adal 1.0.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/.gitignore +5 -0
- data/.rubocop.yml +7 -0
- data/.travis.yml +7 -0
- data/Gemfile +25 -0
- data/LICENSE.txt +21 -0
- data/README.md +97 -0
- data/Rakefile +39 -0
- data/adal.gemspec +52 -0
- data/contributing.md +127 -0
- data/lib/adal.rb +24 -0
- data/lib/adal/authentication_context.rb +202 -0
- data/lib/adal/authentication_parameters.rb +126 -0
- data/lib/adal/authority.rb +165 -0
- data/lib/adal/cache_driver.rb +171 -0
- data/lib/adal/cached_token_response.rb +190 -0
- data/lib/adal/client_assertion.rb +63 -0
- data/lib/adal/client_assertion_certificate.rb +89 -0
- data/lib/adal/client_credential.rb +46 -0
- data/lib/adal/core_ext.rb +26 -0
- data/lib/adal/core_ext/hash.rb +34 -0
- data/lib/adal/jwt_parameters.rb +39 -0
- data/lib/adal/logger.rb +90 -0
- data/lib/adal/logging.rb +98 -0
- data/lib/adal/memory_cache.rb +95 -0
- data/lib/adal/mex_request.rb +52 -0
- data/lib/adal/mex_response.rb +141 -0
- data/lib/adal/noop_cache.rb +38 -0
- data/lib/adal/oauth_request.rb +76 -0
- data/lib/adal/request_parameters.rb +48 -0
- data/lib/adal/self_signed_jwt_factory.rb +96 -0
- data/lib/adal/templates/rst.13.xml.erb +35 -0
- data/lib/adal/templates/rst.2005.xml.erb +32 -0
- data/lib/adal/token_request.rb +231 -0
- data/lib/adal/token_response.rb +144 -0
- data/lib/adal/user_assertion.rb +57 -0
- data/lib/adal/user_credential.rb +152 -0
- data/lib/adal/user_identifier.rb +83 -0
- data/lib/adal/user_information.rb +49 -0
- data/lib/adal/util.rb +49 -0
- data/lib/adal/version.rb +36 -0
- data/lib/adal/wstrust_request.rb +100 -0
- data/lib/adal/wstrust_response.rb +168 -0
- data/lib/adal/xml_namespaces.rb +64 -0
- data/samples/authorization_code_example/README.md +10 -0
- data/samples/authorization_code_example/web_app.rb +139 -0
- data/samples/client_assertion_certificate_example/README.md +42 -0
- data/samples/client_assertion_certificate_example/app.rb +55 -0
- data/samples/on_behalf_of_example/README.md +35 -0
- data/samples/on_behalf_of_example/native_app.rb +52 -0
- data/samples/on_behalf_of_example/web_api.rb +71 -0
- data/samples/user_credentials_example/README.md +7 -0
- data/samples/user_credentials_example/app.rb +52 -0
- data/spec/adal/authentication_context_spec.rb +186 -0
- data/spec/adal/authentication_parameters_spec.rb +107 -0
- data/spec/adal/authority_spec.rb +122 -0
- data/spec/adal/cache_driver_spec.rb +191 -0
- data/spec/adal/cached_token_response_spec.rb +148 -0
- data/spec/adal/client_assertion_certificate_spec.rb +113 -0
- data/spec/adal/client_assertion_spec.rb +38 -0
- data/spec/adal/core_ext/hash_spec.rb +47 -0
- data/spec/adal/logging_spec.rb +48 -0
- data/spec/adal/memory_cache_spec.rb +107 -0
- data/spec/adal/mex_request_spec.rb +57 -0
- data/spec/adal/mex_response_spec.rb +143 -0
- data/spec/adal/self_signed_jwt_factory_spec.rb +63 -0
- data/spec/adal/token_request_spec.rb +150 -0
- data/spec/adal/token_response_spec.rb +102 -0
- data/spec/adal/user_credential_spec.rb +125 -0
- data/spec/adal/user_identifier_spec.rb +115 -0
- data/spec/adal/wstrust_request_spec.rb +51 -0
- data/spec/adal/wstrust_response_spec.rb +152 -0
- data/spec/fixtures/mex/insecureaddress.xml +924 -0
- data/spec/fixtures/mex/invalid_namespaces.xml +916 -0
- data/spec/fixtures/mex/malformed.xml +914 -0
- data/spec/fixtures/mex/microsoft.xml +916 -0
- data/spec/fixtures/mex/multiple_endpoints.xml +922 -0
- data/spec/fixtures/mex/no_matching_bindings.xml +916 -0
- data/spec/fixtures/mex/no_username_token_policies.xml +914 -0
- data/spec/fixtures/mex/no_wstrust_endpoints.xml +838 -0
- data/spec/fixtures/mex/only_13.xml +842 -0
- data/spec/fixtures/mex/only_2005.xml +842 -0
- data/spec/fixtures/oauth/error.json +1 -0
- data/spec/fixtures/oauth/success.json +1 -0
- data/spec/fixtures/oauth/success_with_id_token.json +1 -0
- data/spec/fixtures/wstrust/error.xml +24 -0
- data/spec/fixtures/wstrust/invalid_namespaces.xml +136 -0
- data/spec/fixtures/wstrust/missing_security_tokens.xml +90 -0
- data/spec/fixtures/wstrust/success.xml +136 -0
- data/spec/fixtures/wstrust/token.xml +1 -0
- data/spec/fixtures/wstrust/too_many_security_tokens.xml +219 -0
- data/spec/fixtures/wstrust/unrecognized_token_type.xml +136 -0
- data/spec/fixtures/wstrust/wstrust.13.xml +1 -0
- data/spec/fixtures/wstrust/wstrust.2005.xml +89 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/support/fake_data.rb +40 -0
- data/spec/support/fake_token_endpoint.rb +108 -0
- metadata +265 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#-------------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) 2015 Micorosft Corporation
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
# furnished to do so, subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
|
12
|
+
# all copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20
|
+
# THE SOFTWARE.
|
|
21
|
+
#-------------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
module ADAL
|
|
24
|
+
# Proxy object for a token response with metadata.
|
|
25
|
+
class CachedTokenResponse
|
|
26
|
+
attr_reader :authority
|
|
27
|
+
attr_reader :client_id
|
|
28
|
+
attr_reader :token_response
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Constructs a new CachedTokenResponse.
|
|
32
|
+
#
|
|
33
|
+
# @param ClientCredential|ClientAssertion|ClientAssertionCertificate
|
|
34
|
+
# The credentials of the calling client application.
|
|
35
|
+
# @param Authority authority
|
|
36
|
+
# The ADAL::Authority object that the response was retrieved from.
|
|
37
|
+
# @param SuccessResponse token_response
|
|
38
|
+
# The token response to be cached.
|
|
39
|
+
def initialize(client, authority, token_response)
|
|
40
|
+
unless token_response.instance_of? SuccessResponse
|
|
41
|
+
fail ArgumentError, 'Only SuccessResponses can be cached.'
|
|
42
|
+
end
|
|
43
|
+
@authority = authority
|
|
44
|
+
if client.respond_to? :client_id
|
|
45
|
+
@client = client
|
|
46
|
+
@client_id = client.client_id
|
|
47
|
+
else
|
|
48
|
+
@client = ClientCredential.new(client)
|
|
49
|
+
@client_id = client
|
|
50
|
+
end
|
|
51
|
+
@token_response = token_response
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# Converts the fields in this object and its proxied SuccessResponse into
|
|
56
|
+
# a JSON string.
|
|
57
|
+
#
|
|
58
|
+
# @param JSON::Ext::Generator::State
|
|
59
|
+
# We don't care about the state, but JSON::unparse requires this.
|
|
60
|
+
# @return String
|
|
61
|
+
def to_json(_ = nil)
|
|
62
|
+
JSON.unparse(authority: [authority.host, authority.tenant],
|
|
63
|
+
client_id: client_id,
|
|
64
|
+
token_response: token_response)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
##
|
|
68
|
+
# Reconstructs an object from JSON that was serialized with
|
|
69
|
+
# CachedTokenResponse#to_json.
|
|
70
|
+
#
|
|
71
|
+
# @param JSON raw_json
|
|
72
|
+
# @return CachedTokenResponse
|
|
73
|
+
def self.from_json(json)
|
|
74
|
+
json = JSON.parse(json) if json.instance_of? String
|
|
75
|
+
CachedTokenResponse.new(json['client_id'],
|
|
76
|
+
Authority.new(*json['authority']),
|
|
77
|
+
SuccessResponse.new(json['token_response']))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
##
|
|
81
|
+
# Determines if self can be used to refresh other.
|
|
82
|
+
#
|
|
83
|
+
# @param CachedTokenResponse other
|
|
84
|
+
# @return Boolean
|
|
85
|
+
def can_refresh?(other)
|
|
86
|
+
mrrt? && (authority == other.authority) &&
|
|
87
|
+
(user_info == other.user_info) && (client_id == other.client_id)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
# If the access token is within the expiration buffer of expiring, an
|
|
92
|
+
# attempt will be made to retrieve a new token with the refresh token.
|
|
93
|
+
#
|
|
94
|
+
# @param Fixnum expiration_buffer_sec
|
|
95
|
+
# The number of seconds to use as leeway in determining if the token is
|
|
96
|
+
# expired. A positive buffer will refresh the token early while a negative
|
|
97
|
+
# buffer will refresh it late. Used to counter clock skew and network
|
|
98
|
+
# latency.
|
|
99
|
+
# @return Boolean
|
|
100
|
+
# True if the token is still valid (even if it was refreshed). False if
|
|
101
|
+
# the token is expired an unable to be refreshed.
|
|
102
|
+
def validate(expiration_buffer_sec = 0)
|
|
103
|
+
return true if (Time.now + expiration_buffer_sec).to_i < expires_on
|
|
104
|
+
unless refresh_token
|
|
105
|
+
logger.verbose('Cached token is almost expired but no refresh token ' \
|
|
106
|
+
'is available.')
|
|
107
|
+
return false
|
|
108
|
+
end
|
|
109
|
+
logger.verbose('Cached token is almost expired, attempting to refresh ' \
|
|
110
|
+
' with refresh token.')
|
|
111
|
+
refresh_response = refresh
|
|
112
|
+
if refresh_response.instance_of? SuccessResponse
|
|
113
|
+
logger.verbose('Successfully refreshed token in cache.')
|
|
114
|
+
@token_response = refresh_response
|
|
115
|
+
true
|
|
116
|
+
else
|
|
117
|
+
logger.warn('Failed to refresh token in cache with refresh token.')
|
|
118
|
+
false
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
##
|
|
123
|
+
# Attempts to refresh the access token for a given resource. Note that you
|
|
124
|
+
# can call this method with a different resource even if the token is not
|
|
125
|
+
# an MRRT, but it will fail
|
|
126
|
+
#
|
|
127
|
+
# @param String resource
|
|
128
|
+
# The resource that the new access token is beign requested for. Defaults
|
|
129
|
+
# to using the same resource as the original token.
|
|
130
|
+
# @return TokenResponse
|
|
131
|
+
def refresh(new_resource = resource)
|
|
132
|
+
token_response = TokenRequest
|
|
133
|
+
.new(authority, @client)
|
|
134
|
+
.get_with_refresh_token(refresh_token, new_resource)
|
|
135
|
+
if token_response.instance_of? SuccessResponse
|
|
136
|
+
token_response.parse_id_token(id_token)
|
|
137
|
+
end
|
|
138
|
+
token_response
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
##
|
|
142
|
+
# Changes the refresh token of the underlying token response.
|
|
143
|
+
#
|
|
144
|
+
# @param String token
|
|
145
|
+
def refresh_token=(token)
|
|
146
|
+
token_response.instance_variable_set(:@refresh_token, token)
|
|
147
|
+
logger.verbose("Updated the refresh token for #{token_response}.")
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
##
|
|
151
|
+
# Is the token a Multi Resource Refresh Token?
|
|
152
|
+
#
|
|
153
|
+
# @return Boolean
|
|
154
|
+
def mrrt?
|
|
155
|
+
token_response.refresh_token && token_response.resource
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
## Since the token cache may be implemented by the user of this library,
|
|
159
|
+
## all means of checking equality must be consistent.
|
|
160
|
+
|
|
161
|
+
def ==(other)
|
|
162
|
+
[:authority, :client_id, :token_response].all? do |field|
|
|
163
|
+
(other.respond_to? field) && (send(field) == other.send(field))
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def eql?(other)
|
|
168
|
+
self == other
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def hash
|
|
172
|
+
[authority, client_id, token_response].hash
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
private
|
|
176
|
+
|
|
177
|
+
# CachedTokenResponse is just a proxy for TokenResponse.
|
|
178
|
+
def method_missing(method, *args, &block)
|
|
179
|
+
if token_response.respond_to?(method)
|
|
180
|
+
token_response.send(method, *args, &block)
|
|
181
|
+
else
|
|
182
|
+
super(method)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def respond_to_missing?(method, include_private = false)
|
|
187
|
+
token_response.respond_to?(method, include_private) || super
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#-------------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) 2015 Micorosft Corporation
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
# furnished to do so, subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
|
12
|
+
# all copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20
|
+
# THE SOFTWARE.
|
|
21
|
+
#-------------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
require_relative './request_parameters'
|
|
24
|
+
require_relative './token_request'
|
|
25
|
+
require_relative './util'
|
|
26
|
+
|
|
27
|
+
module ADAL
|
|
28
|
+
# A client credential that consists of the client id and a JWT bearer
|
|
29
|
+
# assertion. The type is 'urn:ietf:params:oauth:token-type:jwt'.
|
|
30
|
+
class ClientAssertion
|
|
31
|
+
include TokenRequest::GrantType
|
|
32
|
+
include RequestParameters
|
|
33
|
+
include Util
|
|
34
|
+
|
|
35
|
+
attr_reader :assertion
|
|
36
|
+
attr_reader :assertion_type
|
|
37
|
+
attr_reader :client_id
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# Creates a new ClientAssertion.
|
|
41
|
+
#
|
|
42
|
+
# @param [String] client_id
|
|
43
|
+
# The client id of the calling application.
|
|
44
|
+
# @param [String] assertion
|
|
45
|
+
# The JWT used as a credential.
|
|
46
|
+
def initialize(client_id, assertion, assertion_type = JWT_BEARER)
|
|
47
|
+
fail_if_arguments_nil(client_id, assertion, assertion_type)
|
|
48
|
+
@assertion = assertion
|
|
49
|
+
@assertion_type = assertion_type
|
|
50
|
+
@client_id = client_id
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# The relavent parameters from this credential for OAuth.
|
|
55
|
+
#
|
|
56
|
+
# @return Hash
|
|
57
|
+
def request_params
|
|
58
|
+
{ CLIENT_ID => @client_id,
|
|
59
|
+
CLIENT_ASSERTION_TYPE => @assertion_type,
|
|
60
|
+
CLIENT_ASSERTION => @assertion }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#-------------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) 2015 Micorosft Corporation
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
# furnished to do so, subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
|
12
|
+
# all copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20
|
+
# THE SOFTWARE.
|
|
21
|
+
#-------------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
require 'openssl'
|
|
24
|
+
|
|
25
|
+
module ADAL
|
|
26
|
+
# An assertion made by a client with an X509 certificate. This requires both
|
|
27
|
+
# the public and private keys. Technically it only requires the thumbprint
|
|
28
|
+
# of the public key, however OpenSSL's object model does not include
|
|
29
|
+
# thumbprints.
|
|
30
|
+
class ClientAssertionCertificate
|
|
31
|
+
include RequestParameters
|
|
32
|
+
|
|
33
|
+
MIN_KEY_SIZE_BITS = 2014
|
|
34
|
+
|
|
35
|
+
attr_reader :certificate
|
|
36
|
+
attr_reader :client_id
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# Creates a new ClientAssertionCertificate.
|
|
40
|
+
#
|
|
41
|
+
# @param Authority authority
|
|
42
|
+
# The authority object that will recognize this certificate.
|
|
43
|
+
# @param [String] client_id
|
|
44
|
+
# The client id of the calling application.
|
|
45
|
+
# @param [OpenSSL::PKCS12] pkcs12_file
|
|
46
|
+
# The PKCS12 file containing the certificate and private key.
|
|
47
|
+
def initialize(authority, client_id, pkcs12_file)
|
|
48
|
+
unless pkcs12_file.is_a? OpenSSL::PKCS12
|
|
49
|
+
fail ArgumentError, 'Only PKCS12 file format is supported.'
|
|
50
|
+
end
|
|
51
|
+
@authority = authority
|
|
52
|
+
@certificate = pkcs12_file.certificate
|
|
53
|
+
@client_id = client_id.to_s
|
|
54
|
+
@private_key = pkcs12_file.key
|
|
55
|
+
validate_certificate_and_key(@certificate, @private_key)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The relevant parameters from this credential for OAuth.
|
|
59
|
+
def request_params
|
|
60
|
+
jwt_assertion = SelfSignedJwtFactory
|
|
61
|
+
.new(@client_id, @authority.token_endpoint)
|
|
62
|
+
.create_and_sign_jwt(@certificate, @private_key)
|
|
63
|
+
ClientAssertion.new(client_id, jwt_assertion).request_params
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
# @param [OpenSSL::X509::Certificate] certificate
|
|
69
|
+
# @return [Fixnum] The number of bits in the public key.
|
|
70
|
+
def public_key_size_bits(certificate)
|
|
71
|
+
certificate.public_key.n.num_bytes * 8
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
# In general, Ruby code is very loose about types. However, since we are
|
|
76
|
+
# dealing with sensitive information here, we will be a little bit stricter
|
|
77
|
+
# on type safety.
|
|
78
|
+
def validate_certificate_and_key(certificate, private_key)
|
|
79
|
+
if !certificate.is_a? OpenSSL::X509::Certificate
|
|
80
|
+
fail ArgumentError, 'certificate must be an OpenSSL::X509::Certificate.'
|
|
81
|
+
elsif !private_key.is_a? OpenSSL::PKey::RSA
|
|
82
|
+
fail ArgumentError, 'private_key must be an OpenSSL::PKey::RSA.'
|
|
83
|
+
elsif public_key_size_bits(certificate) < MIN_KEY_SIZE_BITS
|
|
84
|
+
fail ArgumentError, 'certificate must contain a public key of at ' \
|
|
85
|
+
"least #{MIN_KEY_SIZE_BITS} bits."
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#-------------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) 2015 Micorosft Corporation
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
# furnished to do so, subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
|
12
|
+
# all copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20
|
+
# THE SOFTWARE.
|
|
21
|
+
#-------------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
require_relative './request_parameters'
|
|
24
|
+
require_relative './util'
|
|
25
|
+
|
|
26
|
+
module ADAL
|
|
27
|
+
# A wrapper object for a client id and secret.
|
|
28
|
+
class ClientCredential
|
|
29
|
+
include RequestParameters
|
|
30
|
+
include Util
|
|
31
|
+
|
|
32
|
+
attr_reader :client_id
|
|
33
|
+
attr_reader :client_secret
|
|
34
|
+
|
|
35
|
+
def initialize(client_id, client_secret = nil)
|
|
36
|
+
fail_if_arguments_nil(client_id)
|
|
37
|
+
@client_id = client_id
|
|
38
|
+
@client_secret = client_secret
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# The relavent parameters from this credential for OAuth.
|
|
42
|
+
def request_params
|
|
43
|
+
{ CLIENT_ID => @client_id, CLIENT_SECRET => @client_secret }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#-------------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) 2015 Micorosft Corporation
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
# furnished to do so, subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
|
12
|
+
# all copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20
|
+
# THE SOFTWARE.
|
|
21
|
+
#-------------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
# All of the refinements used in ADAL. They are all in the namespace
|
|
24
|
+
# ADAL::CoreExt and will only be applied to files that start with ADAL::CoreExt
|
|
25
|
+
# before opening any module or class.
|
|
26
|
+
require_relative './core_ext/hash'
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#-------------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) 2015 Micorosft Corporation
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
# furnished to do so, subject to the following conditions:
|
|
10
|
+
#
|
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
|
12
|
+
# all copies or substantial portions of the Software.
|
|
13
|
+
#
|
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20
|
+
# THE SOFTWARE.
|
|
21
|
+
#-------------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
module ADAL
|
|
24
|
+
# Adds helper methods to Hash. These are standard in Rails and are
|
|
25
|
+
# commonplace in the Ruby community.
|
|
26
|
+
module CoreExt
|
|
27
|
+
# Same as #merge, but values in other_hash are prioritized over self.
|
|
28
|
+
refine Hash do
|
|
29
|
+
def reverse_merge(other_hash)
|
|
30
|
+
other_hash.merge(self)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|