adal 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,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 '../spec_helper'
|
24
|
+
|
25
|
+
require 'jwt'
|
26
|
+
|
27
|
+
include FakeData
|
28
|
+
|
29
|
+
describe ADAL::SelfSignedJwtFactory do
|
30
|
+
describe '#create_and_sign_jwt' do
|
31
|
+
before(:each) do
|
32
|
+
key = OpenSSL::PKey::RSA.new 2048
|
33
|
+
@cert = OpenSSL::X509::Certificate.new
|
34
|
+
@cert.public_key = key.public_key
|
35
|
+
@jwt = ADAL::SelfSignedJwtFactory
|
36
|
+
.new(CLIENT_ID, 'some_token_endpoint')
|
37
|
+
.create_and_sign_jwt(@cert, key)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should be decodable with the public key' do
|
41
|
+
expect do
|
42
|
+
JWT.decode(@jwt, @cert.public_key)
|
43
|
+
end.to_not raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should contain the correct keys in the payload' do
|
47
|
+
payload, = JWT.decode(@jwt, @cert.public_key)
|
48
|
+
expect(payload.keys).to contain_exactly(
|
49
|
+
'aud', 'iss', 'sub', 'nbf', 'exp', 'jti')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should containt the correct keys in the header' do
|
53
|
+
_, header = JWT.decode(@jwt, @cert.public_key)
|
54
|
+
expect(header.keys).to contain_exactly('x5t', 'alg', 'typ')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should contain the correct thumbprint from the certificate' do
|
58
|
+
thumbprint = OpenSSL::Digest::SHA1.new(@cert.to_der).base64digest
|
59
|
+
_, header = JWT.decode(@jwt, @cert.public_key)
|
60
|
+
expect(header['x5t']).to eq(thumbprint)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,150 @@
|
|
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 '../support/fake_data'
|
24
|
+
|
25
|
+
require 'spec_helper'
|
26
|
+
|
27
|
+
include FakeData
|
28
|
+
|
29
|
+
describe ADAL::TokenRequest do
|
30
|
+
let(:authority) { ADAL::Authority.new(AUTHORITY, TENANT) }
|
31
|
+
let(:cache) { ADAL::MemoryCache.new }
|
32
|
+
let(:client) { ADAL::ClientCredential.new(CLIENT_ID, CLIENT_SECRET) }
|
33
|
+
let(:token_request) { ADAL::TokenRequest.new(authority, client, cache) }
|
34
|
+
let(:token_response) do
|
35
|
+
ADAL::SuccessResponse.new(expires_in: 100, resource: RESOURCE)
|
36
|
+
end
|
37
|
+
|
38
|
+
# The mocking seam is the OAuthRequest class.
|
39
|
+
def mock_oauth_request(result = nil)
|
40
|
+
instance_double('oauth_request', execute: result)
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#get_with_authorization_code' do
|
44
|
+
context 'with a matching token in the cache' do
|
45
|
+
before(:each) do
|
46
|
+
ADAL::CacheDriver.new(authority, client, cache).add(token_response)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should not make an OAuthRequest' do
|
50
|
+
expect(ADAL::OAuthRequest).to_not receive(:new)
|
51
|
+
token_request.get_with_authorization_code(
|
52
|
+
AUTH_CODE, REDIRECT_URI, RESOURCE)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should retrieve the token response from the cache' do
|
56
|
+
expect(
|
57
|
+
token_request.get_with_authorization_code(
|
58
|
+
AUTH_CODE, REDIRECT_URI, RESOURCE)
|
59
|
+
).to eq(token_response)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'without a matching token in the cache' do
|
64
|
+
before(:each) do
|
65
|
+
allow(ADAL::OAuthRequest).to receive(:new)
|
66
|
+
.and_return(mock_oauth_request(token_response))
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should make an OAuthRequest' do
|
70
|
+
expect(ADAL::OAuthRequest).to receive(:new).once
|
71
|
+
token_request.get_with_authorization_code(AUTH_CODE, REDIRECT_URI)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should return the token response from the OAuth flow' do
|
75
|
+
expect(
|
76
|
+
token_request.get_with_authorization_code(AUTH_CODE, REDIRECT_URI)
|
77
|
+
).to eq(token_response)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#get_for_client' do
|
83
|
+
context 'with a matching token in the cache' do
|
84
|
+
before(:each) do
|
85
|
+
ADAL::CacheDriver.new(authority, client, cache).add(token_response)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should not make an OAuthRequest' do
|
89
|
+
expect(ADAL::OAuthRequest).to_not receive(:new)
|
90
|
+
token_request.get_for_client(RESOURCE)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should retrieve the token response from the cache' do
|
94
|
+
expect(token_request.get_for_client(RESOURCE)).to eq(token_response)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'without a matching token in the cache' do
|
99
|
+
before(:each) do
|
100
|
+
allow(ADAL::OAuthRequest).to receive(:new)
|
101
|
+
.and_return(mock_oauth_request(token_response))
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should make an OAuthRequest' do
|
105
|
+
expect(ADAL::OAuthRequest).to receive(:new).once
|
106
|
+
token_request.get_for_client(RESOURCE)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should return the token response from the OAuth flow' do
|
110
|
+
expect(token_request.get_for_client(RESOURCE)).to eq(token_response)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#get_with_refresh_token' do
|
116
|
+
let(:refresh_token_response) { ADAL::SuccessResponse.new }
|
117
|
+
before(:each) do
|
118
|
+
allow(ADAL::OAuthRequest).to receive(:new)
|
119
|
+
.and_return(mock_oauth_request(refresh_token_response))
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'with a matching token in the cache' do
|
123
|
+
before(:each) do
|
124
|
+
ADAL::CacheDriver.new(authority, client, cache).add(token_response)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should make an OAuth request' do
|
128
|
+
expect(ADAL::OAuthRequest).to receive(:new).once
|
129
|
+
token_request.get_with_refresh_token(REFRESH_TOKEN, RESOURCE)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should return the refreshed token response' do
|
133
|
+
expect(token_request.get_with_refresh_token(REFRESH_TOKEN, RESOURCE))
|
134
|
+
.to eq(refresh_token_response)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'without a matching token in the cache' do
|
139
|
+
it 'should make an OAuth request' do
|
140
|
+
expect(ADAL::OAuthRequest).to receive(:new).once
|
141
|
+
token_request.get_with_refresh_token(REFRESH_TOKEN, RESOURCE)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should return the refreshed token response' do
|
145
|
+
expect(token_request.get_with_refresh_token(REFRESH_TOKEN, RESOURCE))
|
146
|
+
.to eq(refresh_token_response)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,102 @@
|
|
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 '../spec_helper'
|
24
|
+
|
25
|
+
OAUTH_FIXTURES = File.expand_path('../../fixtures/oauth', __FILE__)
|
26
|
+
|
27
|
+
describe ADAL::TokenResponse do
|
28
|
+
let(:response) { File.read(File.expand_path(file_name, OAUTH_FIXTURES)) }
|
29
|
+
|
30
|
+
describe '::parse' do
|
31
|
+
context 'with a successful response' do
|
32
|
+
context 'with an id token' do
|
33
|
+
let(:file_name) { 'success_with_id_token.json' }
|
34
|
+
|
35
|
+
it 'should not raise any errors' do
|
36
|
+
expect { ADAL::TokenResponse.parse(response) }.to_not raise_error
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'response' do
|
40
|
+
subject { ADAL::TokenResponse.parse(response) }
|
41
|
+
|
42
|
+
it { is_expected.to be_instance_of ADAL::SuccessResponse }
|
43
|
+
|
44
|
+
describe '#error?' do
|
45
|
+
# RSpec does some metaprogramming voodoo; this calls subject.error?.
|
46
|
+
it { is_expected.to_not be_error }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'without an id token' do
|
52
|
+
let(:file_name) { 'success.json' }
|
53
|
+
|
54
|
+
it 'should not raise any errors' do
|
55
|
+
expect { ADAL::TokenResponse.parse(response) }.to_not raise_error
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'response' do
|
59
|
+
subject { ADAL::TokenResponse.parse(response) }
|
60
|
+
|
61
|
+
it { is_expected.to be_instance_of ADAL::SuccessResponse }
|
62
|
+
|
63
|
+
describe '#error?' do
|
64
|
+
it { is_expected.to_not be_error }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'with an error response' do
|
71
|
+
let(:file_name) { 'error.json' }
|
72
|
+
|
73
|
+
it 'should not raise any errors' do
|
74
|
+
expect { ADAL::TokenResponse.parse(response) }.to_not raise_error
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'response' do
|
78
|
+
subject { ADAL::TokenResponse.parse(response) }
|
79
|
+
|
80
|
+
it { is_expected.to be_instance_of ADAL::ErrorResponse }
|
81
|
+
|
82
|
+
describe '#error?' do
|
83
|
+
it { is_expected.to be_error }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with a successful response' do
|
90
|
+
let(:file_name) { 'success.json' }
|
91
|
+
|
92
|
+
describe '::parse' do
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'with an error response' do
|
97
|
+
let(:file_name) { 'error.json' }
|
98
|
+
|
99
|
+
describe '::parse' do
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,125 @@
|
|
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 '../spec_helper'
|
24
|
+
|
25
|
+
include FakeData
|
26
|
+
|
27
|
+
describe ADAL::UserCredential do
|
28
|
+
let(:user_cred) { ADAL::UserCredential.new(USERNAME, PASSWORD) }
|
29
|
+
let(:fed_url) { 'https://abc.def/' }
|
30
|
+
|
31
|
+
before(:each) do
|
32
|
+
expect(Net::HTTP).to receive(:get).once.and_return(
|
33
|
+
"{\"account_type\": \"#{account_type}\", " \
|
34
|
+
"\"federation_metadata_url\": \"#{fed_url}\"}")
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with a federated user' do
|
38
|
+
let(:account_type) { 'Federated' }
|
39
|
+
|
40
|
+
describe '#account_type' do
|
41
|
+
subject { user_cred.account_type }
|
42
|
+
|
43
|
+
it { is_expected.to eq ADAL::UserCredential::AccountType::FEDERATED }
|
44
|
+
|
45
|
+
it 'should cache the response instead of making multiple HTTP requests' do
|
46
|
+
# Note the .once in the before block.
|
47
|
+
user_cred.account_type
|
48
|
+
user_cred.account_type
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#request_params' do
|
53
|
+
subject { user_cred.request_params }
|
54
|
+
let(:action) do
|
55
|
+
'http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal'
|
56
|
+
end
|
57
|
+
let(:grant_type) { 'grant_type' }
|
58
|
+
let(:token) { 'token' }
|
59
|
+
let(:wstrust_url) { 'https://ghi.jkl/' }
|
60
|
+
|
61
|
+
before(:each) do
|
62
|
+
expect_any_instance_of(ADAL::MexRequest).to receive(:execute)
|
63
|
+
.and_return(double(wstrust_url: wstrust_url, action: action))
|
64
|
+
expect_any_instance_of(ADAL::WSTrustRequest).to receive(:execute)
|
65
|
+
.and_return(double(token: token, grant_type: grant_type))
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'contains assertion, grant_type and scope' do
|
69
|
+
expect(subject.keys).to contain_exactly(:assertion, :grant_type, :scope)
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'assertion' do
|
73
|
+
subject { user_cred.request_params[:assertion] }
|
74
|
+
|
75
|
+
it 'contains the base64 encoded token' do
|
76
|
+
expect(Base64.decode64(subject)).to eq token
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'scope' do
|
81
|
+
subject { user_cred.request_params[:scope] }
|
82
|
+
|
83
|
+
it { is_expected.to eq :openid }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'with a managed user' do
|
89
|
+
let(:account_type) { 'Managed' }
|
90
|
+
|
91
|
+
describe '#account_type' do
|
92
|
+
subject { user_cred.account_type }
|
93
|
+
it { is_expected.to eq ADAL::UserCredential::AccountType::MANAGED }
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#request_params' do
|
97
|
+
it 'should contain username, password and grant type' do
|
98
|
+
expect(user_cred.request_params.keys).to contain_exactly(
|
99
|
+
:username, :password, :grant_type, :scope)
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'grant_type' do
|
103
|
+
subject { user_cred.request_params[:grant_type] }
|
104
|
+
|
105
|
+
it { is_expected.to eq 'password' }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with an unknown account type user' do
|
111
|
+
let(:account_type) { 'Unknown' }
|
112
|
+
|
113
|
+
describe '#account_type' do
|
114
|
+
subject { user_cred.account_type }
|
115
|
+
it { is_expected.to eq ADAL::UserCredential::AccountType::UNKNOWN }
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#request_params' do
|
119
|
+
it 'should throw an error' do
|
120
|
+
expect { user_cred.request_params }.to raise_error(
|
121
|
+
ADAL::UserCredential::UnsupportedAccountTypeError)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,115 @@
|
|
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
|
+
require_relative '../spec_helper'
|
23
|
+
|
24
|
+
describe ADAL::UserIdentifier do
|
25
|
+
describe '#initialize' do
|
26
|
+
context 'with a valid type' do
|
27
|
+
subject { -> { ADAL::UserIdentifier.new('a@io', :DISPLAYABLE_ID) } }
|
28
|
+
it { is_expected.to_not raise_error }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with an invalid type' do
|
32
|
+
subject { -> { ADAL::UserIdentifier.new('a@io', :NEW_ID) } }
|
33
|
+
it { is_expected.to raise_error ArgumentError }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'request_parameters' do
|
38
|
+
let(:id) { 'my id' }
|
39
|
+
let(:type) { ADAL::UserIdentifier::UNIQUE_ID }
|
40
|
+
let(:user_id) { ADAL::UserIdentifier.new(id, type) }
|
41
|
+
subject { user_id.request_params }
|
42
|
+
it { is_expected.to eq(user_info: user_id) }
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '==' do
|
46
|
+
let(:id) { 'my id' }
|
47
|
+
subject { ADAL::UserIdentifier.new(id, type) }
|
48
|
+
|
49
|
+
context 'with another UserIdentifier' do
|
50
|
+
let(:type) { ADAL::UserIdentifier::Type::UNIQUE_ID }
|
51
|
+
it 'uses object equality' do
|
52
|
+
expect(subject == subject).to be_truthy
|
53
|
+
expect(subject == ADAL::UserIdentifier.new(id, type)).to be_falsey
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'with a string username' do
|
58
|
+
let(:type) { ADAL::UserIdentifier::Type::UNIQUE_ID }
|
59
|
+
it 'matches strings to the id' do
|
60
|
+
expect(subject == id).to be_truthy
|
61
|
+
expect(subject == '5').to be_falsey
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with a UserInformation' do
|
66
|
+
context 'with type UNIQUE_ID' do
|
67
|
+
let(:type) { ADAL::UserIdentifier::Type::UNIQUE_ID }
|
68
|
+
|
69
|
+
it 'matches oid' do
|
70
|
+
user_info = ADAL::UserInformation.new(oid: id)
|
71
|
+
expect(subject == user_info).to be_truthy
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'matches sub' do
|
75
|
+
user_info = ADAL::UserInformation.new(sub: id)
|
76
|
+
expect(subject == user_info).to be_truthy
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'does not match upn' do
|
80
|
+
user_info = ADAL::UserInformation.new(upn: id)
|
81
|
+
expect(subject == user_info).to be_falsey
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'does not match email' do
|
85
|
+
user_info = ADAL::UserInformation.new(email: id)
|
86
|
+
expect(subject == user_info).to be_falsey
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'with type DISPLAYABLE_ID' do
|
91
|
+
let(:type) { ADAL::UserIdentifier::Type::DISPLAYABLE_ID }
|
92
|
+
|
93
|
+
it 'does not match oid' do
|
94
|
+
user_info = ADAL::UserInformation.new(oid: id)
|
95
|
+
expect(subject == user_info).to be_falsey
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'does not match sub' do
|
99
|
+
user_info = ADAL::UserInformation.new(sub: id)
|
100
|
+
expect(subject == user_info).to be_falsey
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'matches upn' do
|
104
|
+
user_info = ADAL::UserInformation.new(upn: id)
|
105
|
+
expect(subject == user_info).to be_truthy
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'matches email' do
|
109
|
+
user_info = ADAL::UserInformation.new(email: id)
|
110
|
+
expect(subject == user_info).to be_truthy
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|