omniauth-azure_active_directory_b2c 0.2.0
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/omniauth-azure_active_directory_b2c.rb +1 -0
- data/lib/omniauth/strategies/azure_active_directory_b2c.rb +163 -0
- data/lib/omniauth/strategies/azure_active_directory_b2c/authentication_request.rb +48 -0
- data/lib/omniauth/strategies/azure_active_directory_b2c/authentication_response.rb +122 -0
- data/lib/omniauth/strategies/azure_active_directory_b2c/client.rb +14 -0
- data/lib/omniauth/strategies/azure_active_directory_b2c/jwt_validator.rb +93 -0
- data/lib/omniauth/strategies/azure_active_directory_b2c/policy.rb +26 -0
- data/lib/omniauth/strategies/azure_active_directory_b2c/policy_options.rb +97 -0
- data/lib/omniauth/strategies/azure_active_directory_b2c/version.rb +9 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0c0f7094e772b9c4aeeac8eba5ee0e5f8664c863
|
4
|
+
data.tar.gz: d48a92be522a55bb07ebbaca2d279a7fb84e825c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8dd3cdf6e26aec04a21bd50d7030ba583cc1d76a31b5e48dc7f726d1aa792bfacc2ef0dff1535b79a3e29aa52b7d7f8f4cafb28c09f543b308601042807bd567
|
7
|
+
data.tar.gz: 996b5025889be29a5dd93f4964f0aed570be8fe26ca2aef3506b4dcd34b53c82aa66e8c18906117242297f479f69c193bf80a453546ed2c4b87fff6d85c5f6ea
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'omniauth/strategies/azure_active_directory_b2c.rb'
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'omniauth'
|
2
|
+
require 'proc_evaluate'
|
3
|
+
|
4
|
+
require_relative 'azure_active_directory_b2c/authentication_request.rb'
|
5
|
+
require_relative 'azure_active_directory_b2c/authentication_response.rb'
|
6
|
+
require_relative 'azure_active_directory_b2c/client.rb'
|
7
|
+
require_relative 'azure_active_directory_b2c/jwt_validator.rb'
|
8
|
+
require_relative 'azure_active_directory_b2c/policy_options.rb'
|
9
|
+
require_relative 'azure_active_directory_b2c/policy.rb'
|
10
|
+
require_relative 'azure_active_directory_b2c/version.rb'
|
11
|
+
|
12
|
+
module OmniAuth
|
13
|
+
module Strategies
|
14
|
+
class AzureActiveDirectoryB2C
|
15
|
+
|
16
|
+
include OmniAuth::Strategy
|
17
|
+
|
18
|
+
using ProcEvaluate # adds the `evaluate` refinement method to Object and Proc instances
|
19
|
+
|
20
|
+
#########################################
|
21
|
+
# Error definitions
|
22
|
+
#########################################
|
23
|
+
|
24
|
+
GenericError = Class.new(StandardError)
|
25
|
+
|
26
|
+
# Errors raised du to missing options or settings
|
27
|
+
MissingOptionError = Class.new(GenericError)
|
28
|
+
|
29
|
+
# Errors raised during the callback stage
|
30
|
+
CallbackError = Class.new(GenericError) do
|
31
|
+
attr_reader :failure_message_key
|
32
|
+
def self.failure_message_key(key)
|
33
|
+
define_method(:failure_message_key) { key }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
InvalidCredentialsError = Class.new(CallbackError) { failure_message_key :invalid_credentials }
|
37
|
+
UnauthorizedError = Class.new(CallbackError) { failure_message_key :unauthorized }
|
38
|
+
MissingCodeError = Class.new(CallbackError) { failure_message_key :missing_code }
|
39
|
+
IdTokenValidationError = Class.new(CallbackError) { failure_message_key :id_token_validation_failed }
|
40
|
+
|
41
|
+
#########################################
|
42
|
+
# Strategy options
|
43
|
+
#########################################
|
44
|
+
|
45
|
+
option :name, 'azure_active_directory_b2c'
|
46
|
+
option :redirect_uri # the url to return to in the callback phase
|
47
|
+
option :policy_options
|
48
|
+
|
49
|
+
#########################################
|
50
|
+
# Strategy - setup
|
51
|
+
#########################################
|
52
|
+
|
53
|
+
def policy_options
|
54
|
+
@policy_options ||= options.policy_options || (raise MissingOptionError, '`policy_options` not defined')
|
55
|
+
end
|
56
|
+
|
57
|
+
def policy
|
58
|
+
@policy = Policy.new(**policy_options.symbolize_keys)
|
59
|
+
end
|
60
|
+
|
61
|
+
def redirect_uri
|
62
|
+
@redirect_uri ||= options.redirect_uri.evaluate(self) || (raise MissingOptionError, '`redirect_uri` not defined')
|
63
|
+
end
|
64
|
+
|
65
|
+
def setup_phase
|
66
|
+
end
|
67
|
+
|
68
|
+
#########################################
|
69
|
+
# Strategy - request
|
70
|
+
#########################################
|
71
|
+
|
72
|
+
def authentication_request
|
73
|
+
@authentication_request ||= AuthenticationRequest.new(policy, redirect_uri: redirect_uri)
|
74
|
+
end
|
75
|
+
|
76
|
+
def authorization_uri
|
77
|
+
authentication_request.authorization_uri
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_session_variables!
|
81
|
+
# set the session details to check against in the callback_phase
|
82
|
+
session['omniauth.nonce'] = authentication_request.nonce
|
83
|
+
session['omniauth.state'] = authentication_request.state
|
84
|
+
end
|
85
|
+
|
86
|
+
def request_phase
|
87
|
+
# this phase needs to redirect to B2C with the correct params and record the state and nonce in the session to check against in the callback_phase
|
88
|
+
set_session_variables!
|
89
|
+
redirect authentication_request.authorization_uri
|
90
|
+
end
|
91
|
+
|
92
|
+
#########################################
|
93
|
+
# Strategy - callback
|
94
|
+
#########################################
|
95
|
+
|
96
|
+
def authentication_response
|
97
|
+
@authentication_response ||= AuthenticationResponse.new(policy, request.params['code'])
|
98
|
+
end
|
99
|
+
|
100
|
+
def callback_phase
|
101
|
+
validate_callback_response!
|
102
|
+
validate_id_token!
|
103
|
+
super # required to complete the callback phase
|
104
|
+
|
105
|
+
rescue UnauthorizedError => e
|
106
|
+
return Rack::Response.new(['401 Unauthorized'], 401).finish
|
107
|
+
rescue CallbackError => e
|
108
|
+
fail!(e.failure_message_key, e)
|
109
|
+
rescue ::Timeout::Error, ::Errno::ETIMEDOUT => e
|
110
|
+
fail!(:timeout, e)
|
111
|
+
rescue ::SocketError => e
|
112
|
+
fail!(:failed_to_connect, e)
|
113
|
+
end
|
114
|
+
|
115
|
+
def validate_callback_response!
|
116
|
+
state, code, error, error_reason, error_description = request.params.values_at('state', 'code', 'error', 'error_reason', 'error_description')
|
117
|
+
|
118
|
+
if error || error_reason || error_description
|
119
|
+
raise InvalidCredentialsError, [error, error_reason, error_description].compact.join('. ')
|
120
|
+
elsif state.to_s.empty? || state != session.delete('omniauth.state')
|
121
|
+
raise UnauthorizedError
|
122
|
+
elsif !code
|
123
|
+
raise MissingCodeError, 'Code was not returned from OpenID Connect Provider'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def validate_id_token!
|
128
|
+
results = authentication_response.validate_id_token
|
129
|
+
if results.has_errors?
|
130
|
+
raise IdTokenValidationError, results.full_messages.join('. ')
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
#########################################
|
135
|
+
# Auth Hash Schema
|
136
|
+
#########################################
|
137
|
+
|
138
|
+
def user_info
|
139
|
+
authentication_response.user_info
|
140
|
+
end
|
141
|
+
|
142
|
+
def subject_id
|
143
|
+
authentication_response.subject_id
|
144
|
+
end
|
145
|
+
|
146
|
+
def extra_info
|
147
|
+
authentication_response.extra_info
|
148
|
+
end
|
149
|
+
|
150
|
+
def credentials
|
151
|
+
authentication_response.credentials
|
152
|
+
end
|
153
|
+
|
154
|
+
# return the details required by OmniAuth
|
155
|
+
info { user_info }
|
156
|
+
uid { subject_id }
|
157
|
+
extra { extra_info }
|
158
|
+
credentials { credentials }
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
OmniAuth.config.add_camelization('azure_active_directory_b2c', 'AzureActiveDirectoryB2C')
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module OmniAuth
|
2
|
+
module Strategies
|
3
|
+
class AzureActiveDirectoryB2C
|
4
|
+
class AuthenticationRequest
|
5
|
+
|
6
|
+
class ResponseType
|
7
|
+
# TODO: provide constants for each option
|
8
|
+
CODE = 'code'
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :policy, :client
|
12
|
+
|
13
|
+
def initialize(policy, redirect_uri:, **override_options)
|
14
|
+
@policy = policy
|
15
|
+
@client = policy.initialize_client({ redirect_uri: redirect_uri, **override_options })
|
16
|
+
end
|
17
|
+
|
18
|
+
def authorization_uri(**override_options)
|
19
|
+
options = default_authorization_uri_options.merge(override_options)
|
20
|
+
options = options.select {|k, v| v }
|
21
|
+
client.authorization_uri(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def state
|
25
|
+
@state ||= SecureRandom.hex(16)
|
26
|
+
end
|
27
|
+
|
28
|
+
def nonce
|
29
|
+
@nonce ||= SecureRandom.hex(16)
|
30
|
+
end
|
31
|
+
|
32
|
+
def response_type
|
33
|
+
ResponseType::CODE
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_authorization_uri_options
|
37
|
+
{
|
38
|
+
response_type: response_type,
|
39
|
+
scope: policy.scope,
|
40
|
+
state: state,
|
41
|
+
nonce: nonce,
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
end # AuthenticationRequest
|
46
|
+
end # AzureActiveDirectoryB2C
|
47
|
+
end # Strategies
|
48
|
+
end # OmniAuth
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module OmniAuth
|
2
|
+
module Strategies
|
3
|
+
class AzureActiveDirectoryB2C
|
4
|
+
class AuthenticationResponse
|
5
|
+
|
6
|
+
class AuthenticationMethod
|
7
|
+
BASIC = 'basic'
|
8
|
+
BODY = 'body'
|
9
|
+
POST = 'post'
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :policy, :client, :code
|
13
|
+
|
14
|
+
def initialize(policy, code, **override_options)
|
15
|
+
@policy = policy
|
16
|
+
@client = policy.initialize_client({ redirect_uri: nil, **override_options })
|
17
|
+
@client.authorization_code = code
|
18
|
+
@code = code
|
19
|
+
end
|
20
|
+
|
21
|
+
def access_token
|
22
|
+
@access_token ||= get_access_token!
|
23
|
+
end
|
24
|
+
|
25
|
+
def id_token
|
26
|
+
@id_token ||= get_id_token!
|
27
|
+
end
|
28
|
+
|
29
|
+
def refresh_token
|
30
|
+
access_token.refresh_token
|
31
|
+
end
|
32
|
+
|
33
|
+
def expires_in
|
34
|
+
access_token.expires_in
|
35
|
+
end
|
36
|
+
|
37
|
+
def subject_id
|
38
|
+
id_token.sub
|
39
|
+
end
|
40
|
+
|
41
|
+
def user_info
|
42
|
+
{
|
43
|
+
name: id_token.raw_attributes['name'],
|
44
|
+
email: ([*id_token.raw_attributes['emails']].first),
|
45
|
+
nickname: id_token.raw_attributes['preferred_username'],
|
46
|
+
first_name: id_token.raw_attributes['given_name'],
|
47
|
+
last_name: id_token.raw_attributes['family_name'],
|
48
|
+
gender: id_token.raw_attributes['gender'],
|
49
|
+
image: id_token.raw_attributes['picture'],
|
50
|
+
phone: id_token.raw_attributes['phone_number'],
|
51
|
+
urls: { website: id_token.raw_attributes['website'] }
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def extra_info
|
56
|
+
{ raw_info: id_token.raw_attributes }
|
57
|
+
end
|
58
|
+
|
59
|
+
def scope
|
60
|
+
policy.scope
|
61
|
+
end
|
62
|
+
|
63
|
+
def authentication_method
|
64
|
+
AuthenticationMethod::BODY
|
65
|
+
end
|
66
|
+
|
67
|
+
def credentials
|
68
|
+
{
|
69
|
+
id_token: id_token,
|
70
|
+
token: access_token.access_token,
|
71
|
+
refresh_token: refresh_token,
|
72
|
+
expires_in: expires_in,
|
73
|
+
scope: scope,
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def default_access_token_options
|
78
|
+
{
|
79
|
+
scope: scope,
|
80
|
+
client_auth_method: authentication_method,
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def get_access_token!
|
85
|
+
client.access_token!(default_access_token_options)
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_id_token!
|
89
|
+
# TODO: if the id_token is not passed back, we could get the id token from the userinfo endpoint (or fail if no endpoint is defined?)
|
90
|
+
encrypted_id_token = access_token.id_token
|
91
|
+
decoded_id_token = decode_id_token!(encrypted_id_token)
|
92
|
+
end
|
93
|
+
|
94
|
+
def decode_id_token!(id_token)
|
95
|
+
::OpenIDConnect::ResponseObject::IdToken.decode(id_token, public_key)
|
96
|
+
end
|
97
|
+
|
98
|
+
def public_key
|
99
|
+
if policy.jwk_signing_algorithm == :RS256 && policy.jwk_signing_keys
|
100
|
+
jwk_key
|
101
|
+
else
|
102
|
+
raise 'id_token signing algorithm is currently not supported: %s' % policy.jwk_signing_algorithm
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def jwk_key
|
107
|
+
key = policy.jwk_signing_keys
|
108
|
+
if key.has_key?('keys')
|
109
|
+
JSON::JWK::Set.new(key['keys']) # a set of keys
|
110
|
+
else
|
111
|
+
JSON::JWK.new(key) # a single key
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def validate_id_token(seconds_since_epoc = Time.now.to_i)
|
116
|
+
JwtValidator.validate(id_token.raw_attributes, public_key, policy, seconds_since_epoc)
|
117
|
+
end
|
118
|
+
|
119
|
+
end # AuthenticationResponse
|
120
|
+
end # AzureActiveDirectoryB2C
|
121
|
+
end # Strategies
|
122
|
+
end # OmniAuth
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'openid_connect'
|
2
|
+
|
3
|
+
module OmniAuth
|
4
|
+
module Strategies
|
5
|
+
class AzureActiveDirectoryB2C
|
6
|
+
|
7
|
+
class Client < ::OpenIDConnect::Client
|
8
|
+
# developers can override this class as required
|
9
|
+
# Be sure to also override MicrosoftAzureB2C::Policy#initialize_client
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module OmniAuth
|
2
|
+
module Strategies
|
3
|
+
class AzureActiveDirectoryB2C
|
4
|
+
|
5
|
+
class ValidationResult
|
6
|
+
def error_messages
|
7
|
+
@error_messages ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_error(key, message)
|
11
|
+
error_messages << { error: key, message: message }
|
12
|
+
end
|
13
|
+
|
14
|
+
def has_errors?
|
15
|
+
error_messages.any?
|
16
|
+
end
|
17
|
+
|
18
|
+
def okay?
|
19
|
+
error_messages.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def full_messages
|
23
|
+
error_messages.collect {|err| err[:message] }
|
24
|
+
end
|
25
|
+
end # ValidationResult
|
26
|
+
|
27
|
+
class JwtValidator
|
28
|
+
|
29
|
+
EPOC_TIME_LEEWAY_SECONDS = 10
|
30
|
+
|
31
|
+
attr_reader :jwt, :jwt_key, :policy, :seconds_since_epoc
|
32
|
+
|
33
|
+
def self.validate(jwt, jwt_key, policy, seconds_since_epoc = Time.now.to_i)
|
34
|
+
new(jwt, jwt_key, policy, seconds_since_epoc).validate
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(jwt, jwt_key, policy, seconds_since_epoc = Time.now.to_i)
|
38
|
+
@jwt = jwt
|
39
|
+
@jwt_key = jwt_key
|
40
|
+
@policy = policy
|
41
|
+
@seconds_since_epoc = seconds_since_epoc
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate
|
45
|
+
results = ValidationResult.new
|
46
|
+
results.add_error(:algorithm_mismatch, "Signing algorithm mismatch: Expected `#{policy.jwk_signing_algorithm} but got #{jwt.algorithm}`") unless signing_algoritm_matches?
|
47
|
+
results.add_error(:issue_mismatch, "Issue mismatch: Expected `#{policy.issuer}` but got `#{jwt[:iss]}`") unless issuer_matches?
|
48
|
+
results.add_error(:audience_mismatch, "Audience mismatch: Expected `#{policy.aud}` but got `#{jwt[:aud]}`") unless audience_matches?
|
49
|
+
results.add_error(:before_start_time, "Token has not yet commenced: Valid at #{jwt[:nbf]} but currently #{seconds_since_epoc}") unless on_or_after_not_before_time?
|
50
|
+
results.add_error(:after_expiry_time, "Token has expired: Expired at #{jwt[:exp]} but currently #{seconds_since_epoc}") unless before_expiration_time?
|
51
|
+
|
52
|
+
begin
|
53
|
+
verify_signature!
|
54
|
+
rescue JSON::JWS::VerificationFailed
|
55
|
+
results.add_error(:signiture_verification_failed, 'Signture verification failed') unless signature_verified?
|
56
|
+
rescue JSON::JWS::UnexpectedAlgorithm
|
57
|
+
results.add_error(:unexpected_signiture_algorithm, 'Unexpected signature algorithm') unless signature_verified?
|
58
|
+
rescue => e
|
59
|
+
results.add_error(:signiture_verification_failed, e.message || 'Signature verification failed') unless signature_verified?
|
60
|
+
end
|
61
|
+
|
62
|
+
results # return results
|
63
|
+
end
|
64
|
+
|
65
|
+
def signing_algoritm_matches?
|
66
|
+
# An attacker may change the signing algorith to provide a forged signature
|
67
|
+
jwt.algorithm.to_sym == policy.jwk_signing_algorithm
|
68
|
+
end
|
69
|
+
|
70
|
+
def issuer_matches?
|
71
|
+
jwt[:iss] && jwt[:iss] != '' && jwt[:iss] == policy.issuer
|
72
|
+
end
|
73
|
+
|
74
|
+
def audience_matches?
|
75
|
+
jwt[:aud] && jwt[:aud] != '' && jwt[:aud] == policy.application_identifier
|
76
|
+
end
|
77
|
+
|
78
|
+
def on_or_after_not_before_time?
|
79
|
+
(seconds_since_epoc + EPOC_TIME_LEEWAY_SECONDS) >= jwt[:nbf]
|
80
|
+
end
|
81
|
+
|
82
|
+
def before_expiration_time?
|
83
|
+
(seconds_since_epoc - EPOC_TIME_LEEWAY_SECONDS) < jwt[:exp]
|
84
|
+
end
|
85
|
+
|
86
|
+
def verify_signature!
|
87
|
+
jwt.verify!(jwt_key)
|
88
|
+
end
|
89
|
+
|
90
|
+
end # JwtVerifier
|
91
|
+
end # AzureActiveDirectoryB2C
|
92
|
+
end # Strategies
|
93
|
+
end # OmniAuth
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module OmniAuth
|
2
|
+
module Strategies
|
3
|
+
class AzureActiveDirectoryB2C
|
4
|
+
class Policy
|
5
|
+
include AzureActiveDirectoryB2C::PolicyOptions
|
6
|
+
|
7
|
+
attr_reader :application_identifier, :application_secret, :issuer, :tenant_name, :policy_name, :jwk_signing_algorithm, :jwk_signing_keys
|
8
|
+
|
9
|
+
def initialize(application_identifier:, application_secret:, issuer:, tenant_name:, policy_name:, jwk_signing_algorithm:, jwk_signing_keys:, scope: nil)
|
10
|
+
@application_identifier = application_identifier
|
11
|
+
@application_secret = application_secret
|
12
|
+
@issuer = issuer
|
13
|
+
@tenant_name = tenant_name
|
14
|
+
@policy_name = policy_name
|
15
|
+
@jwk_signing_algorithm = jwk_signing_algorithm
|
16
|
+
@jwk_signing_keys = jwk_signing_keys
|
17
|
+
@scope = *scope
|
18
|
+
end
|
19
|
+
|
20
|
+
def scope
|
21
|
+
@scope.any? ? @scope : super
|
22
|
+
end
|
23
|
+
end # Policy
|
24
|
+
end # AzureActiveDirectoryB2C
|
25
|
+
end # Strategies
|
26
|
+
end # OmniAuth
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module OmniAuth
|
2
|
+
module Strategies
|
3
|
+
class AzureActiveDirectoryB2C
|
4
|
+
module PolicyOptions
|
5
|
+
|
6
|
+
def respond_to_missing?(method_name, *args)
|
7
|
+
self.class.instance_methods.include?("policy_#{method_name}".to_sym) || super
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(method_name, *args, &block)
|
11
|
+
policy_method_name = 'policy_%s' % method_name
|
12
|
+
if respond_to?(policy_method_name)
|
13
|
+
send(policy_method_name, *args, &block)
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def policy_application_identifier
|
20
|
+
raise MissingOptionError, '`application_identifier` not defined'
|
21
|
+
end
|
22
|
+
|
23
|
+
def policy_application_secret
|
24
|
+
raise MissingOptionError, '`application_secret` not defined'
|
25
|
+
end
|
26
|
+
|
27
|
+
def policy_issuer
|
28
|
+
raise MissingOptionError, '`issuer` not defined'
|
29
|
+
end
|
30
|
+
|
31
|
+
def policy_tenant_name
|
32
|
+
raise MissingOptionError, '`tenant_name` not defined'
|
33
|
+
end
|
34
|
+
|
35
|
+
def policy_policy_name
|
36
|
+
raise MissingOptionError, '`policy_name` not defined'
|
37
|
+
end
|
38
|
+
|
39
|
+
def policy_host_name
|
40
|
+
'https://login.microsoftonline.com/te/%s/%s' % [tenant_name, policy_name]
|
41
|
+
end
|
42
|
+
|
43
|
+
def policy_authorization_endpoint
|
44
|
+
'%s/oauth2/v2.0/authorize' % host_name
|
45
|
+
end
|
46
|
+
|
47
|
+
def policy_token_endpoint
|
48
|
+
'%s/oauth2/v2.0/token' % host_name
|
49
|
+
end
|
50
|
+
|
51
|
+
def policy_jwks_uri
|
52
|
+
'%s/discovery/v2.0/keys' % host_name
|
53
|
+
end
|
54
|
+
|
55
|
+
def policy_jwk_signing_algorithm
|
56
|
+
# this can be "discovered" from the `jwks_uri` property at .well-known/openid-configuration
|
57
|
+
'RS256'.to_sym
|
58
|
+
end
|
59
|
+
|
60
|
+
def policy_id_token_signing_algorithm
|
61
|
+
policy_jwk_signing_algorithm
|
62
|
+
end
|
63
|
+
|
64
|
+
def policy_scope
|
65
|
+
[
|
66
|
+
:openid, # This requests an ID token
|
67
|
+
# :offline_access, # This requests a refresh token using Auth Code flows. See: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-reference-oauth-code).
|
68
|
+
# Request API permissions. See https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-access-tokens
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
def policy_jwk_signing_keys
|
73
|
+
# public keys are listed at the url specified in the the `jwks_uri` property at .well-known/openid-configuration
|
74
|
+
# eg. https://login.microsoftonline.com/mipwtest.onmicrosoft.com/discovery/v2.0/keys?p=b2c_1_signupin
|
75
|
+
raise MissingOptionError, '`jwk_signing_keys` not defined'
|
76
|
+
end
|
77
|
+
|
78
|
+
def policy_default_client_options
|
79
|
+
{
|
80
|
+
identifier: application_identifier,
|
81
|
+
secret: application_secret,
|
82
|
+
authorization_endpoint: authorization_endpoint,
|
83
|
+
token_endpoint: token_endpoint,
|
84
|
+
jwks_uri: jwks_uri,
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def policy_initialize_client(redirect_uri:, **override_options)
|
89
|
+
options = default_client_options.merge(override_options)
|
90
|
+
options[:redirect_uri] = redirect_uri
|
91
|
+
Client.new(options)
|
92
|
+
end
|
93
|
+
|
94
|
+
end # PolicyOptions
|
95
|
+
end # AzureActiveDirectoryB2C
|
96
|
+
end # Strategies
|
97
|
+
end # OmniAuth
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omniauth-azure_active_directory_b2c
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brent Jacobs
|
8
|
+
- NextFaze
|
9
|
+
- Meeco
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2017-10-27 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: omniauth
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '1.3'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: openid_connect
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '1.1'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1.1'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: proc_evaluate
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.0'
|
50
|
+
type: :runtime
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '1.0'
|
57
|
+
description:
|
58
|
+
email: developers@meeco.me
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- lib/omniauth-azure_active_directory_b2c.rb
|
64
|
+
- lib/omniauth/strategies/azure_active_directory_b2c.rb
|
65
|
+
- lib/omniauth/strategies/azure_active_directory_b2c/authentication_request.rb
|
66
|
+
- lib/omniauth/strategies/azure_active_directory_b2c/authentication_response.rb
|
67
|
+
- lib/omniauth/strategies/azure_active_directory_b2c/client.rb
|
68
|
+
- lib/omniauth/strategies/azure_active_directory_b2c/jwt_validator.rb
|
69
|
+
- lib/omniauth/strategies/azure_active_directory_b2c/policy.rb
|
70
|
+
- lib/omniauth/strategies/azure_active_directory_b2c/policy_options.rb
|
71
|
+
- lib/omniauth/strategies/azure_active_directory_b2c/version.rb
|
72
|
+
homepage: https://github.com/Meeco/omniauth-azure_active_directory_b2c
|
73
|
+
licenses:
|
74
|
+
- MIT
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.6.12
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Azure AD B2C Strategy for OmniAuth.
|
96
|
+
test_files: []
|