oidc 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/.rspec +2 -0
- data/.rubocop.yml +28 -0
- data/CHANGELOG.md +4 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +46 -0
- data/Rakefile +12 -0
- data/lib/oidc/access_token/mtls.rb +9 -0
- data/lib/oidc/access_token.rb +45 -0
- data/lib/oidc/client/registrar.rb +186 -0
- data/lib/oidc/client.rb +43 -0
- data/lib/oidc/connect_object.rb +52 -0
- data/lib/oidc/discovery/provider/config/resource.rb +39 -0
- data/lib/oidc/discovery/provider/config/response.rb +112 -0
- data/lib/oidc/discovery/provider/config.rb +20 -0
- data/lib/oidc/discovery/provider.rb +34 -0
- data/lib/oidc/discovery.rb +8 -0
- data/lib/oidc/exception.rb +39 -0
- data/lib/oidc/jwtnizable.rb +14 -0
- data/lib/oidc/request_object/claimable.rb +54 -0
- data/lib/oidc/request_object/id_token.rb +8 -0
- data/lib/oidc/request_object/user_info.rb +7 -0
- data/lib/oidc/request_object.rb +37 -0
- data/lib/oidc/response_object/id_token.rb +99 -0
- data/lib/oidc/response_object/user_info/address.rb +10 -0
- data/lib/oidc/response_object/user_info.rb +65 -0
- data/lib/oidc/response_object.rb +8 -0
- data/lib/oidc/version.rb +5 -0
- data/lib/oidc.rb +98 -0
- data/lib/rack/oauth2/server/authorize/error_with_connect_ext.rb +34 -0
- data/lib/rack/oauth2/server/authorize/extension/code_and_id_token.rb +40 -0
- data/lib/rack/oauth2/server/authorize/extension/code_and_id_token_and_token.rb +36 -0
- data/lib/rack/oauth2/server/authorize/extension/id_token.rb +40 -0
- data/lib/rack/oauth2/server/authorize/extension/id_token_and_token.rb +36 -0
- data/lib/rack/oauth2/server/authorize/request_with_connect_params.rb +26 -0
- data/lib/rack/oauth2/server/id_token_response.rb +24 -0
- data/oidc.gemspec +46 -0
- data/sig/omniauth_oidc.rbs +4 -0
- metadata +252 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
module Oidc
|
2
|
+
module Discovery
|
3
|
+
module Provider
|
4
|
+
class Config
|
5
|
+
class Response
|
6
|
+
include ActiveModel::Validations, AttrRequired, AttrOptional
|
7
|
+
|
8
|
+
cattr_accessor :metadata_attributes
|
9
|
+
attr_reader :raw
|
10
|
+
attr_accessor :expected_issuer
|
11
|
+
uri_attributes = {
|
12
|
+
required: [
|
13
|
+
:issuer,
|
14
|
+
:authorization_endpoint,
|
15
|
+
:jwks_uri
|
16
|
+
],
|
17
|
+
optional: [
|
18
|
+
:token_endpoint,
|
19
|
+
:userinfo_endpoint,
|
20
|
+
:registration_endpoint,
|
21
|
+
:end_session_endpoint,
|
22
|
+
:service_documentation,
|
23
|
+
:check_session_iframe,
|
24
|
+
:op_policy_uri,
|
25
|
+
:op_tos_uri
|
26
|
+
]
|
27
|
+
}
|
28
|
+
attr_required(*(uri_attributes[:required] + [
|
29
|
+
:response_types_supported,
|
30
|
+
:subject_types_supported,
|
31
|
+
:id_token_signing_alg_values_supported
|
32
|
+
]))
|
33
|
+
attr_optional(*(uri_attributes[:optional] + [
|
34
|
+
:scopes_supported,
|
35
|
+
:response_modes_supported,
|
36
|
+
:grant_types_supported,
|
37
|
+
:acr_values_supported,
|
38
|
+
:id_token_encryption_alg_values_supported,
|
39
|
+
:id_token_encryption_enc_values_supported,
|
40
|
+
:userinfo_signing_alg_values_supported,
|
41
|
+
:userinfo_encryption_alg_values_supported,
|
42
|
+
:userinfo_encryption_enc_values_supported,
|
43
|
+
:request_object_signing_alg_values_supported,
|
44
|
+
:request_object_encryption_alg_values_supported,
|
45
|
+
:request_object_encryption_enc_values_supported,
|
46
|
+
:token_endpoint_auth_methods_supported,
|
47
|
+
:token_endpoint_auth_signing_alg_values_supported,
|
48
|
+
:display_values_supported,
|
49
|
+
:claim_types_supported,
|
50
|
+
:claims_supported,
|
51
|
+
:claims_locales_supported,
|
52
|
+
:ui_locales_supported,
|
53
|
+
:claims_parameter_supported,
|
54
|
+
:request_parameter_supported,
|
55
|
+
:request_uri_parameter_supported,
|
56
|
+
:require_request_uri_registration
|
57
|
+
]))
|
58
|
+
|
59
|
+
validates(*required_attributes, presence: true)
|
60
|
+
validates(*uri_attributes.values.flatten, url: true, allow_nil: true)
|
61
|
+
validates :issuer, with: :validate_issuer_matching
|
62
|
+
|
63
|
+
def initialize(hash)
|
64
|
+
(required_attributes + optional_attributes).each do |key|
|
65
|
+
self.send "#{key}=", hash[key]
|
66
|
+
end
|
67
|
+
@raw = hash
|
68
|
+
end
|
69
|
+
|
70
|
+
def as_json(options = {})
|
71
|
+
validate!
|
72
|
+
(required_attributes + optional_attributes).inject({}) do |hash, _attr_|
|
73
|
+
value = self.send _attr_
|
74
|
+
hash.merge! _attr_ => value unless value.nil?
|
75
|
+
hash
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def validate!
|
80
|
+
valid? or raise ValidationFailed.new(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
def jwks
|
84
|
+
@jwks ||= Oidc.http_client.get(jwks_uri).body.with_indifferent_access
|
85
|
+
JSON::JWK::Set.new @jwks[:keys]
|
86
|
+
end
|
87
|
+
|
88
|
+
def jwk(kid)
|
89
|
+
@jwks ||= {}
|
90
|
+
@jwks[kid] ||= JSON::JWK::Set::Fetcher.fetch(jwks_uri, kid: kid)
|
91
|
+
end
|
92
|
+
|
93
|
+
def public_keys
|
94
|
+
@public_keys ||= jwks.collect(&:to_key)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def validate_issuer_matching
|
100
|
+
if expected_issuer.present? && issuer != expected_issuer
|
101
|
+
if Oidc.validate_discovery_issuer
|
102
|
+
errors.add :issuer, 'mismatch'
|
103
|
+
else
|
104
|
+
Oidc.logger.warn 'ignoring issuer mismach.'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Oidc
|
2
|
+
module Discovery
|
3
|
+
module Provider
|
4
|
+
class Config
|
5
|
+
def self.discover!(identifier, cache_options = {})
|
6
|
+
uri = URI.parse(identifier)
|
7
|
+
Resource.new(uri).discover!(cache_options).tap do |response|
|
8
|
+
response.expected_issuer = identifier
|
9
|
+
response.validate!
|
10
|
+
end
|
11
|
+
rescue SWD::Exception, ValidationFailed => e
|
12
|
+
raise DiscoveryFailed.new(e.message)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'oidc/discovery/provider/config/resource'
|
20
|
+
require 'oidc/discovery/provider/config/response'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Oidc
|
2
|
+
module Discovery
|
3
|
+
module Provider
|
4
|
+
module Issuer
|
5
|
+
REL_VALUE = 'http://openid.net/specs/connect/1.0/issuer'
|
6
|
+
|
7
|
+
def issuer
|
8
|
+
self.link_for(REL_VALUE)[:href]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.discover!(identifier)
|
13
|
+
resource = case identifier
|
14
|
+
when /^acct:/, /https?:\/\//
|
15
|
+
identifier
|
16
|
+
when /@/
|
17
|
+
"acct:#{identifier}"
|
18
|
+
else
|
19
|
+
"https://#{identifier}"
|
20
|
+
end
|
21
|
+
response = WebFinger.discover!(
|
22
|
+
resource,
|
23
|
+
rel: Issuer::REL_VALUE
|
24
|
+
)
|
25
|
+
response.extend Issuer
|
26
|
+
response
|
27
|
+
rescue WebFinger::Exception => e
|
28
|
+
raise DiscoveryFailed.new(e.message)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'oidc/discovery/provider/config'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Oidc
|
2
|
+
class Exception < StandardError; end
|
3
|
+
|
4
|
+
class ValidationFailed < Exception
|
5
|
+
attr_reader :object
|
6
|
+
|
7
|
+
def initialize(object)
|
8
|
+
super object.errors.full_messages.to_sentence
|
9
|
+
@object = object
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class HttpError < Exception
|
14
|
+
attr_accessor :status, :response
|
15
|
+
def initialize(status, message = nil, response = nil)
|
16
|
+
super message
|
17
|
+
@status = status
|
18
|
+
@response = response
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class BadRequest < HttpError
|
23
|
+
def initialize(message = nil, response = nil)
|
24
|
+
super 400, message, response
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Unauthorized < HttpError
|
29
|
+
def initialize(message = nil, response = nil)
|
30
|
+
super 401, message, response
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Forbidden < HttpError
|
35
|
+
def initialize(message = nil, response = nil)
|
36
|
+
super 403, message, response
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Oidc
|
2
|
+
module JWTnizable
|
3
|
+
def to_jwt(key, algorithm = :RS256, &block)
|
4
|
+
as_jwt(key, algorithm, &block).to_s
|
5
|
+
end
|
6
|
+
|
7
|
+
def as_jwt(key, algorithm = :RS256, &block)
|
8
|
+
token = JSON::JWT.new as_json
|
9
|
+
yield token if block_given?
|
10
|
+
token = token.sign key, algorithm if algorithm != :none
|
11
|
+
token
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Oidc
|
2
|
+
class RequestObject
|
3
|
+
module Claimable
|
4
|
+
def self.included(klass)
|
5
|
+
klass.send :attr_optional, :claims
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(attributes = {})
|
9
|
+
super
|
10
|
+
if claims.present?
|
11
|
+
_claims_ = {}
|
12
|
+
claims.each do |key, value|
|
13
|
+
_claims_[key] = case value
|
14
|
+
when :optional, :voluntary
|
15
|
+
{
|
16
|
+
essential: false
|
17
|
+
}
|
18
|
+
when :required, :essential
|
19
|
+
{
|
20
|
+
essential: true
|
21
|
+
}
|
22
|
+
else
|
23
|
+
value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
self.claims = _claims_.with_indifferent_access
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def as_json(options = {})
|
31
|
+
keys = claims.try(:keys)
|
32
|
+
hash = super
|
33
|
+
Array(keys).each do |key|
|
34
|
+
hash[:claims][key] ||= nil
|
35
|
+
end
|
36
|
+
hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def required?(claim)
|
40
|
+
accessible?(claim) && claims[claim].is_a?(Hash) && claims[claim][:essential]
|
41
|
+
end
|
42
|
+
alias_method :essential?, :required?
|
43
|
+
|
44
|
+
def optional?(claim)
|
45
|
+
accessible?(claim) && !required?(claim)
|
46
|
+
end
|
47
|
+
alias_method :voluntary?, :optional?
|
48
|
+
|
49
|
+
def accessible?(claim)
|
50
|
+
claims.try(:include?, claim)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Oidc
|
2
|
+
class RequestObject < ConnectObject
|
3
|
+
include JWTnizable
|
4
|
+
|
5
|
+
attr_optional :client_id, :response_type, :redirect_uri, :scope, :state, :nonce, :display, :prompt, :userinfo, :id_token
|
6
|
+
validate :require_at_least_one_attributes
|
7
|
+
|
8
|
+
undef :id_token=
|
9
|
+
def id_token=(attributes = {})
|
10
|
+
@id_token = IdToken.new(attributes) if attributes.present?
|
11
|
+
end
|
12
|
+
|
13
|
+
undef :userinfo=
|
14
|
+
def userinfo=(attributes = {})
|
15
|
+
@userinfo = UserInfo.new(attributes) if attributes.present?
|
16
|
+
end
|
17
|
+
|
18
|
+
def as_json(options = {})
|
19
|
+
super.with_indifferent_access
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def decode(jwt_string, key = nil)
|
24
|
+
new JSON::JWT.decode(jwt_string, key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch(request_uri, key = nil)
|
28
|
+
jwt_string = Oidc.http_client.get(request_uri).body
|
29
|
+
decode jwt_string, key
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'oidc/request_object/claimable'
|
36
|
+
require 'oidc/request_object/id_token'
|
37
|
+
require 'oidc/request_object/user_info'
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Oidc
|
2
|
+
class ResponseObject
|
3
|
+
class IdToken < ConnectObject
|
4
|
+
class InvalidToken < Exception; end
|
5
|
+
class ExpiredToken < InvalidToken; end
|
6
|
+
class InvalidIssuer < InvalidToken; end
|
7
|
+
class InvalidNonce < InvalidToken; end
|
8
|
+
class InvalidAudience < InvalidToken; end
|
9
|
+
|
10
|
+
attr_required :iss, :sub, :aud, :exp, :iat
|
11
|
+
attr_optional :acr, :amr, :azp, :jti, :sid, :auth_time, :nonce, :sub_jwk, :at_hash, :c_hash, :s_hash
|
12
|
+
attr_accessor :access_token, :code, :state
|
13
|
+
alias_method :subject, :sub
|
14
|
+
alias_method :subject=, :sub=
|
15
|
+
|
16
|
+
def initialize(attributes = {})
|
17
|
+
super
|
18
|
+
(all_attributes - [:aud, :exp, :iat, :auth_time, :sub_jwk]).each do |key|
|
19
|
+
self.send "#{key}=", self.send(key).try(:to_s)
|
20
|
+
end
|
21
|
+
self.auth_time = auth_time.to_i unless auth_time.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
def verify!(expected = {})
|
25
|
+
raise ExpiredToken.new('Invalid ID token: Expired token') unless exp.to_i > Time.now.to_i
|
26
|
+
raise InvalidIssuer.new('Invalid ID token: Issuer does not match') unless iss == expected[:issuer]
|
27
|
+
raise InvalidNonce.new('Invalid ID Token: Nonce does not match') unless nonce == expected[:nonce]
|
28
|
+
|
29
|
+
# aud(ience) can be a string or an array of strings
|
30
|
+
unless Array(aud).include?(expected[:audience] || expected[:client_id])
|
31
|
+
raise InvalidAudience.new('Invalid ID token: Audience does not match')
|
32
|
+
end
|
33
|
+
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
include JWTnizable
|
38
|
+
def to_jwt(key, algorithm = :RS256, &block)
|
39
|
+
hash_length = algorithm.to_s[2, 3].to_i
|
40
|
+
if access_token
|
41
|
+
token = case access_token
|
42
|
+
when Rack::OAuth2::AccessToken
|
43
|
+
access_token.access_token
|
44
|
+
else
|
45
|
+
access_token
|
46
|
+
end
|
47
|
+
self.at_hash = left_half_hash_of token, hash_length
|
48
|
+
end
|
49
|
+
if code
|
50
|
+
self.c_hash = left_half_hash_of code, hash_length
|
51
|
+
end
|
52
|
+
if state
|
53
|
+
self.s_hash = left_half_hash_of state, hash_length
|
54
|
+
end
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def left_half_hash_of(string, hash_length)
|
61
|
+
digest = OpenSSL::Digest.new("SHA#{hash_length}").digest string
|
62
|
+
Base64.urlsafe_encode64 digest[0, hash_length / (2 * 8)], padding: false
|
63
|
+
end
|
64
|
+
|
65
|
+
class << self
|
66
|
+
def decode(jwt_string, key_or_config)
|
67
|
+
case key_or_config
|
68
|
+
when :self_issued
|
69
|
+
decode_self_issued jwt_string
|
70
|
+
when Oidc::Discovery::Provider::Config::Response
|
71
|
+
jwt = JSON::JWT.decode jwt_string, :skip_verification
|
72
|
+
jwt.verify! key_or_config.jwk(jwt.kid)
|
73
|
+
new jwt
|
74
|
+
else
|
75
|
+
new JSON::JWT.decode jwt_string, key_or_config
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def decode_self_issued(jwt_string)
|
80
|
+
jwt = JSON::JWT.decode jwt_string, :skip_verification
|
81
|
+
jwk = JSON::JWK.new jwt[:sub_jwk]
|
82
|
+
raise InvalidToken.new('Missing sub_jwk') if jwk.blank?
|
83
|
+
raise InvalidToken.new('Invalid subject') unless jwt[:sub] == jwk.thumbprint
|
84
|
+
jwt.verify! jwk
|
85
|
+
new jwt
|
86
|
+
end
|
87
|
+
|
88
|
+
def self_issued(attributes = {})
|
89
|
+
attributes[:sub_jwk] ||= JSON::JWK.new attributes.delete(:public_key)
|
90
|
+
_attributes_ = {
|
91
|
+
iss: 'https://self-issued.me',
|
92
|
+
sub: JSON::JWK.new(attributes[:sub_jwk]).thumbprint
|
93
|
+
}.merge(attributes)
|
94
|
+
new _attributes_
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Oidc
|
2
|
+
class ResponseObject
|
3
|
+
class UserInfo < ConnectObject
|
4
|
+
attr_optional(
|
5
|
+
:sub,
|
6
|
+
:name,
|
7
|
+
:given_name,
|
8
|
+
:family_name,
|
9
|
+
:middle_name,
|
10
|
+
:nickname,
|
11
|
+
:preferred_username,
|
12
|
+
:profile,
|
13
|
+
:picture,
|
14
|
+
:website,
|
15
|
+
:email,
|
16
|
+
:email_verified,
|
17
|
+
:gender,
|
18
|
+
:birthdate,
|
19
|
+
:zoneinfo,
|
20
|
+
:locale,
|
21
|
+
:phone_number,
|
22
|
+
:phone_number_verified,
|
23
|
+
:address,
|
24
|
+
:updated_at
|
25
|
+
)
|
26
|
+
alias_method :subject, :sub
|
27
|
+
alias_method :subject=, :sub=
|
28
|
+
|
29
|
+
validates :email_verified, :phone_number_verified, allow_nil: true, inclusion: {in: [true, false]}
|
30
|
+
validates :zoneinfo, allow_nil: true, inclusion: {in: TZInfo::TimezoneProxy.all.collect(&:name)}
|
31
|
+
validates :profile, :picture, :website, allow_nil: true, url: true
|
32
|
+
validates :email, allow_nil: true, email: true
|
33
|
+
validates :updated_at, allow_nil: true, numericality: {only_integer: true}
|
34
|
+
validate :validate_address
|
35
|
+
validate :require_at_least_one_attributes
|
36
|
+
# TODO: validate locale
|
37
|
+
|
38
|
+
def initialize(attributes = {})
|
39
|
+
super
|
40
|
+
(all_attributes - [:email_verified, :phone_number_verified, :address, :updated_at]).each do |key|
|
41
|
+
self.send "#{key}=", self.send(key).try(:to_s)
|
42
|
+
end
|
43
|
+
self.updated_at = updated_at.try(:to_i)
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate_address
|
47
|
+
errors.add :address, address.errors.full_messages.join(', ') if address.present? && !address.valid?
|
48
|
+
end
|
49
|
+
|
50
|
+
undef :address=
|
51
|
+
def address=(hash_or_address)
|
52
|
+
@address = case hash_or_address
|
53
|
+
when Hash
|
54
|
+
Address.new hash_or_address
|
55
|
+
when Address
|
56
|
+
hash_or_address
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Dir[File.dirname(__FILE__) + '/user_info/*.rb'].each do |file|
|
64
|
+
require file
|
65
|
+
end
|
data/lib/oidc/version.rb
ADDED
data/lib/oidc.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'logger'
|
3
|
+
require 'faraday'
|
4
|
+
require 'faraday/follow_redirects'
|
5
|
+
require 'swd'
|
6
|
+
require 'webfinger'
|
7
|
+
require 'active_model'
|
8
|
+
require 'tzinfo'
|
9
|
+
require 'validate_url'
|
10
|
+
require 'email_validator/strict'
|
11
|
+
require 'mail'
|
12
|
+
require 'attr_required'
|
13
|
+
require 'attr_optional'
|
14
|
+
require 'json/jwt'
|
15
|
+
require 'rack/oauth2'
|
16
|
+
require 'rack/oauth2/server/authorize/error_with_connect_ext'
|
17
|
+
require 'rack/oauth2/server/authorize/request_with_connect_params'
|
18
|
+
require 'rack/oauth2/server/id_token_response'
|
19
|
+
|
20
|
+
module Oidc
|
21
|
+
def self.logger
|
22
|
+
@@logger
|
23
|
+
end
|
24
|
+
def self.logger=(logger)
|
25
|
+
@@logger = logger
|
26
|
+
end
|
27
|
+
self.logger = Logger.new(STDOUT)
|
28
|
+
self.logger.progname = 'Oidc'
|
29
|
+
|
30
|
+
@sub_protocols = [
|
31
|
+
SWD,
|
32
|
+
WebFinger,
|
33
|
+
Rack::OAuth2
|
34
|
+
]
|
35
|
+
def self.debugging?
|
36
|
+
@@debugging
|
37
|
+
end
|
38
|
+
def self.debugging=(boolean)
|
39
|
+
@sub_protocols.each do |klass|
|
40
|
+
klass.debugging = boolean
|
41
|
+
end
|
42
|
+
@@debugging = boolean
|
43
|
+
end
|
44
|
+
def self.debug!
|
45
|
+
@sub_protocols.each do |klass|
|
46
|
+
klass.debug!
|
47
|
+
end
|
48
|
+
self.debugging = true
|
49
|
+
end
|
50
|
+
def self.debug(&block)
|
51
|
+
sub_protocol_originals = @sub_protocols.inject({}) do |sub_protocol_originals, klass|
|
52
|
+
sub_protocol_originals.merge!(klass => klass.debugging?)
|
53
|
+
end
|
54
|
+
original = self.debugging?
|
55
|
+
debug!
|
56
|
+
yield
|
57
|
+
ensure
|
58
|
+
@sub_protocols.each do |klass|
|
59
|
+
klass.debugging = sub_protocol_originals[klass]
|
60
|
+
end
|
61
|
+
self.debugging = original
|
62
|
+
end
|
63
|
+
self.debugging = false
|
64
|
+
|
65
|
+
def self.http_client
|
66
|
+
Faraday.new(headers: {user_agent: "Oidc (#{VERSION})"}) do |faraday|
|
67
|
+
faraday.request :url_encoded
|
68
|
+
faraday.request :json
|
69
|
+
faraday.response :json
|
70
|
+
faraday.adapter Faraday.default_adapter
|
71
|
+
http_config&.call(faraday)
|
72
|
+
faraday.response :logger, Oidc.logger, {bodies: true} if debugging?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
def self.http_config(&block)
|
76
|
+
@sub_protocols.each do |klass|
|
77
|
+
klass.http_config(&block) unless klass.http_config
|
78
|
+
end
|
79
|
+
@@http_config ||= block
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.validate_discovery_issuer=(boolean)
|
83
|
+
@@validate_discovery_issuer = boolean
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.validate_discovery_issuer
|
87
|
+
@@validate_discovery_issuer
|
88
|
+
end
|
89
|
+
|
90
|
+
self.validate_discovery_issuer = true
|
91
|
+
end
|
92
|
+
|
93
|
+
require 'oidc/exception'
|
94
|
+
require 'oidc/client'
|
95
|
+
require 'oidc/access_token'
|
96
|
+
require 'oidc/jwtnizable'
|
97
|
+
require 'oidc/connect_object'
|
98
|
+
require 'oidc/discovery'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rack
|
2
|
+
module OAuth2
|
3
|
+
module Server
|
4
|
+
class Authorize
|
5
|
+
module ErrorWithConnectExt
|
6
|
+
DEFAULT_DESCRIPTION = {
|
7
|
+
invalid_redirect_uri: 'The redirect_uri in the request does not match any of pre-registered redirect_uris.',
|
8
|
+
interaction_required: 'End-User interaction required.',
|
9
|
+
login_required: 'End-User authentication required.',
|
10
|
+
session_selection_required: 'The End-User is required to select a session at the Authorization Server.',
|
11
|
+
consent_required: 'End-User consent required.',
|
12
|
+
invalid_request_uri: 'The request_uri in the request returns an error or invalid data.',
|
13
|
+
invalid_openid_request_object: 'The request parameter contains an invalid OpenID Request Object.'
|
14
|
+
}
|
15
|
+
|
16
|
+
def self.included(klass)
|
17
|
+
DEFAULT_DESCRIPTION.each do |error, default_description|
|
18
|
+
# NOTE:
|
19
|
+
# Connect Message spec doesn't say anything about HTTP status code for each error code.
|
20
|
+
# It probably means "use 400".
|
21
|
+
error_method = :bad_request!
|
22
|
+
klass.class_eval <<-ERROR
|
23
|
+
def #{error}!(description = "#{default_description}", options = {})
|
24
|
+
#{error_method} :#{error}, description, options
|
25
|
+
end
|
26
|
+
ERROR
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
Request.send :include, ErrorWithConnectExt
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|