msidp-endpoint 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/msidp/access_token.rb +82 -0
- data/lib/msidp/endpoint/version.rb +7 -0
- data/lib/msidp/endpoint.rb +105 -0
- data/lib/msidp/error.rb +38 -0
- data/sig/msidp/access_token.rbs +14 -0
- data/sig/msidp/endpoint.rbs +15 -0
- data/sig/msidp/error.rbs +9 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: da9217f4c3e53be7d57aea0a021671939445d7abe2aeac645948935900b8a289
|
4
|
+
data.tar.gz: 01f12f461ef866dbd079c15fc504973d0aa83795e9ecf4d763bf5d3d758d4866
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 42f07a9e6127d52203e646df3fc071e9e88ee9be8436eb04118762cc0756678a9d1918f56bb179dbd73a5d23c724a9139d27a1bf6b681cefe8633cbc791b88cf
|
7
|
+
data.tar.gz: 7a5e4fd84a032765c5bf05556e08e43d3f63a29cce450d09343cb64aaeb11b2bbcc412f221541f55944a09a69e11be27d2c47086bc62b425398367e69bca3933
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
require 'uri'
|
5
|
+
require 'net/http'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
module MSIDP
|
9
|
+
# Access token issued by Microsoft identity platform.
|
10
|
+
class AccessToken
|
11
|
+
# @return [String] the token string
|
12
|
+
attr_reader :value
|
13
|
+
# @return [Date] the expiration date
|
14
|
+
attr_reader :expire
|
15
|
+
# @return [Array] the scope, a list of permissions.
|
16
|
+
attr_reader :scope
|
17
|
+
# @return [String] the refresh token (optional)
|
18
|
+
attr_reader :refresh_token
|
19
|
+
# @return [String] the id token (optional)
|
20
|
+
attr_reader :id_token
|
21
|
+
# @return [String] the type
|
22
|
+
attr_reader :type
|
23
|
+
|
24
|
+
# Creates a new access token.
|
25
|
+
#
|
26
|
+
# @param [String] value the access token string.
|
27
|
+
# @param [Date] expire the expiration date.
|
28
|
+
# @param [Array] scope the list of permissions.
|
29
|
+
# @param [String] refresh_token the refresh token.
|
30
|
+
# @param [String] id_token the id token.
|
31
|
+
# @param [String] type the token type.
|
32
|
+
def initialize( # rubocop:disable Metrics/ParameterLists
|
33
|
+
value, expire, scope,
|
34
|
+
refresh_token = nil, id_token = nil, type = 'Bearer'
|
35
|
+
)
|
36
|
+
@value = value
|
37
|
+
@scope = scope
|
38
|
+
@expire = expire
|
39
|
+
@refresh_token = refresh_token
|
40
|
+
@id_token = id_token
|
41
|
+
@type = type
|
42
|
+
end
|
43
|
+
|
44
|
+
# Parses a response from the endpoint and creates an access token object.
|
45
|
+
#
|
46
|
+
# @param [String,Net::HTTPResponse] res a query string or a HTTP respone.
|
47
|
+
# @param [Hash] supplement attributes supplementary to the response.
|
48
|
+
def self.parse(res, supplement = {}) # rubocop:disable Metrics/AbcSize
|
49
|
+
case res
|
50
|
+
when String
|
51
|
+
hash = Hash[URI.decode_www_form(res)]
|
52
|
+
date = Time.now - 1
|
53
|
+
when Net::HTTPResponse
|
54
|
+
hash = JSON.parse(res.body)
|
55
|
+
date = res.key?('date') ? Time.parse(res['date']) : (Time.now - 1)
|
56
|
+
else
|
57
|
+
raise TypeError, 'expected String or Net::HTTPResponse'
|
58
|
+
end
|
59
|
+
hash = supplement.transform_keys(&:to_s).merge(hash)
|
60
|
+
AccessToken.new(
|
61
|
+
hash['access_token'], date + hash['expires_in'].to_i,
|
62
|
+
hash['scope'].split(' '),
|
63
|
+
hash['refresh_token'], hash['id_token'],
|
64
|
+
hash['token_type']
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Checks if the token is not expired.
|
69
|
+
#
|
70
|
+
# @option kwd [Integer] :in the number of seconds to offset.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# token.valid? in: 5
|
74
|
+
def valid?(**kwd)
|
75
|
+
@expire > Time.now + kwd.fetch(:in, 0)
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_s
|
79
|
+
@value
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'net/http'
|
5
|
+
require 'msidp/error'
|
6
|
+
require 'msidp/access_token'
|
7
|
+
|
8
|
+
module MSIDP
|
9
|
+
# Utility methods for Microsoft identity platform endpoints.
|
10
|
+
module Endpoint
|
11
|
+
# Returns the authorize endpoint URI object.
|
12
|
+
#
|
13
|
+
# @param [String] tenant a directory tenant in GUID or domain-name format.
|
14
|
+
def authorize_uri(tenant)
|
15
|
+
uri(tenant, 'authorize')
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the token endpoint URI object.
|
19
|
+
#
|
20
|
+
# @param [String] tenant a directory tenant in GUID or domain-name format.
|
21
|
+
def token_uri(tenant)
|
22
|
+
uri(tenant, 'token')
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns an endpoint URI object.
|
26
|
+
#
|
27
|
+
# @param [String] tenant a directory tenant in GUID or domain-name format.
|
28
|
+
# @param [String] endpoint an endpoint.
|
29
|
+
def uri(tenant, endpoint)
|
30
|
+
URI.parse(
|
31
|
+
"https://login.microsoftonline.com/#{tenant}/oauth2/v2.0/#{endpoint}"
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Call the authorize endpoint and returns the response.
|
36
|
+
#
|
37
|
+
# @param [URI::Generic] uri the endpoint URI.
|
38
|
+
# @param [Hash] params parameters to the endpoint.
|
39
|
+
# @return [Net::HTTPResponse] the endpoint response.
|
40
|
+
def authorize(uri, params)
|
41
|
+
get(uri, params)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Call the token endpoint and returns an issued access token.
|
45
|
+
#
|
46
|
+
# @param [URI::Generic] uri the endpoint URI.
|
47
|
+
# @param [Hash] params parameters to the endpoint.
|
48
|
+
# @param [Hash] supplement supplemental attributres for the access token.
|
49
|
+
# @return [AccessToken] the issued access token.
|
50
|
+
def token(uri, params, supplement = {})
|
51
|
+
res = validate_json_response post(uri, params)
|
52
|
+
suppl = params.select { |k| k.intern == :scope }.merge(supplement)
|
53
|
+
AccessToken.parse(res, suppl)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get with parameters from an endpoint and returns the response.
|
57
|
+
#
|
58
|
+
# @param [URI::Generic] uri the endpoint URI.
|
59
|
+
# @param [Hash] params parameters to the endpoint.
|
60
|
+
# @param [Hash] headers additional headers.
|
61
|
+
# @return [Net::HTTPResponse] the endpoint response.
|
62
|
+
def get(uri, params, headers = nil)
|
63
|
+
req_uri = URI.parse(uri.request_uri)
|
64
|
+
req_uri.query = URI.encode_www_form(params) if params
|
65
|
+
req = Net::HTTP::Get.new(req_uri.to_s, headers)
|
66
|
+
https_request(uri, req)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Post parameters to an endpoint and returns the response.
|
70
|
+
#
|
71
|
+
# @param [URI::Generic] uri the endpoint URI.
|
72
|
+
# @param [Hash] params parameters to the endpoint.
|
73
|
+
# @param [Hash] headers additional headers.
|
74
|
+
# @return [Net::HTTPResponse] the endpoint response.
|
75
|
+
def post(uri, params, headers = nil)
|
76
|
+
req = Net::HTTP::Post.new(uri.request_uri, headers)
|
77
|
+
req.form_data = params if params
|
78
|
+
https_request(uri, req)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Validate a HTTP response supposed to have the JSON body.
|
82
|
+
def validate_json_response(res)
|
83
|
+
raise Error, res unless res.is_a? Net::HTTPSuccess
|
84
|
+
raise Error, res unless res.content_type&.start_with? 'application/json'
|
85
|
+
|
86
|
+
res
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def https_request(uri, req)
|
92
|
+
Net::HTTP.start(uri.host, uri.port,
|
93
|
+
use_ssl: true,
|
94
|
+
min_version: OpenSSL::SSL::TLS1_2_VERSION) do |http|
|
95
|
+
res = http.request(req)
|
96
|
+
case res
|
97
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
98
|
+
res
|
99
|
+
else
|
100
|
+
raise Error, res
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/msidp/error.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MSIDP
|
4
|
+
# Error from Microsoft identity platform.
|
5
|
+
class Error < StandardError
|
6
|
+
# @return [Net::HTTPResponse] the HTTP response
|
7
|
+
attr_reader :response
|
8
|
+
# @return [String, Hash] the parsed body of the HTTP response in JSON case,
|
9
|
+
# otherwise the raw body.
|
10
|
+
attr_reader :body
|
11
|
+
# @return [String] the error code
|
12
|
+
attr_reader :error
|
13
|
+
# @return [String] the error description
|
14
|
+
attr_reader :description
|
15
|
+
|
16
|
+
# @param [Net::HTTPResponse] response the HTTP response
|
17
|
+
def initialize(response)
|
18
|
+
@response = response
|
19
|
+
if response.content_type&.start_with? 'application/json'
|
20
|
+
@body = JSON.parse(response.body, symbolize_names: true)
|
21
|
+
@error = @body[:error]
|
22
|
+
@description = @body[:error_description]
|
23
|
+
super(<<-"MSG"
|
24
|
+
#{response.code}: #{response.message}
|
25
|
+
#{@error}: #{@description}
|
26
|
+
MSG
|
27
|
+
)
|
28
|
+
else
|
29
|
+
@body = response.body
|
30
|
+
super(<<-"MSG"
|
31
|
+
#{response.code}: #{response.message}
|
32
|
+
#{@body}
|
33
|
+
MSG
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Msidp
|
2
|
+
class AccessToken
|
3
|
+
attr_reader value: String
|
4
|
+
attr_reader expire: Time
|
5
|
+
attr_reader scope: Array[String]
|
6
|
+
attr_reader refresh_token: String?
|
7
|
+
attr_reader id_token: String?
|
8
|
+
attr_reader type: String
|
9
|
+
def initialize: (String value, Time expire, Array[String] scope, ?String refresh_token, ?String id_token, ?String `type`) -> void
|
10
|
+
def self.parse: (String | Net::HTTPResponse res, ?Hash[untyped, untyped] supplement) -> AccessToken
|
11
|
+
def valid?: (?in: Integer) -> bool
|
12
|
+
def to_s: -> String
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Msidp
|
2
|
+
module Endpoint
|
3
|
+
def authorize_uri: (String tenant) -> URI::Generic
|
4
|
+
def token_uri: (String tenant) -> URI::Generic
|
5
|
+
def uri: (String tenant, String endpoint) -> URI::Generic
|
6
|
+
def authorize: (URI::Generic uri, Hash[untyped, untyped] params) -> Net::HTTPResponse
|
7
|
+
def token: (URI::Generic uri, Hash[untyped, untyped] params, ?Hash[untyped, untyped] supplement) -> AccessToken
|
8
|
+
def get: (URI::Generic uri, Hash[untyped, untyped] params, ?Hash[String, untyped] headers) -> Net::HTTPResponse
|
9
|
+
def post: (URI::Generic uri, Hash[untyped, untyped] params, ?Hash[String, untyped] headers) -> Net::HTTPResponse
|
10
|
+
def validate_json_response: (Net::HTTPResponse res) -> Net::HTTPResponse
|
11
|
+
|
12
|
+
private
|
13
|
+
def https_request: (URI::Generic uri, Net::HTTPRequest req) -> Net::HTTPResponse
|
14
|
+
end
|
15
|
+
end
|
data/sig/msidp/error.rbs
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
module Msidp
|
2
|
+
class Error < StandardError
|
3
|
+
attr_reader response: Net::HTTPResponse
|
4
|
+
attr_reader body: String | Hash[Symbol, untyped]
|
5
|
+
attr_reader error: String?
|
6
|
+
attr_reader description: String?
|
7
|
+
def initialize: (Net::HTTPResponse response) -> void
|
8
|
+
end
|
9
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: msidp-endpoint
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- SHIMAYOSHI, Takao
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-01-18 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Simple class library for Microsoft Identity Platform endpoints.
|
14
|
+
email:
|
15
|
+
- simayosi@cc.kyushu-u.ac.jp
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/msidp/access_token.rb
|
21
|
+
- lib/msidp/endpoint.rb
|
22
|
+
- lib/msidp/endpoint/version.rb
|
23
|
+
- lib/msidp/error.rb
|
24
|
+
- sig/msidp/access_token.rbs
|
25
|
+
- sig/msidp/endpoint.rbs
|
26
|
+
- sig/msidp/error.rbs
|
27
|
+
homepage: https://github.com/simayosi/rb-msidp-endpoint
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata:
|
31
|
+
homepage_uri: https://github.com/simayosi/rb-msidp-endpoint
|
32
|
+
source_code_uri: https://github.com/simayosi/rb-msidp-endpoint
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 2.6.0
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubygems_version: 3.0.3.1
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: MSIDP::Endpoint
|
52
|
+
test_files: []
|