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,113 @@
|
|
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::ClientAssertionCertificate do
|
30
|
+
describe '#initialize' do
|
31
|
+
let(:auth) { ADAL::Authority.new(AUTHORITY, TENANT) }
|
32
|
+
let(:cert) { OpenSSL::X509::Certificate.new }
|
33
|
+
|
34
|
+
it "should fail if the public key isn't large enough" do
|
35
|
+
# The key is an integer number of bytes so we have to subtract at least 8.
|
36
|
+
too_few_bits = ADAL::ClientAssertionCertificate::MIN_KEY_SIZE_BITS - 8
|
37
|
+
key = OpenSSL::PKey::RSA.new(too_few_bits)
|
38
|
+
cert.public_key = key.public_key
|
39
|
+
pfx = OpenSSL::PKCS12.create('', '', key, cert)
|
40
|
+
expect do
|
41
|
+
ADAL::ClientAssertionCertificate.new(auth, CLIENT_ID, pfx)
|
42
|
+
end.to raise_error(ArgumentError)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should succeed if the public key is the minimum size' do
|
46
|
+
just_enough_bits = ADAL::ClientAssertionCertificate::MIN_KEY_SIZE_BITS
|
47
|
+
key = OpenSSL::PKey::RSA.new(just_enough_bits)
|
48
|
+
cert.public_key = key.public_key
|
49
|
+
pfx = OpenSSL::PKCS12.create('', '', key, cert)
|
50
|
+
expect do
|
51
|
+
ADAL::ClientAssertionCertificate.new(auth, CLIENT_ID, pfx)
|
52
|
+
end.to_not raise_error
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should fail if the certificate is not PKCS12' do
|
56
|
+
pfx = 'Not an OpenSSL::PKCS12'
|
57
|
+
expect { ADAL::ClientAssertionCertificate.new(auth, CLIENT_ID, pfx) }
|
58
|
+
.to raise_error ArgumentError
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should fail if the pkcs12 does not use valid rsa' do
|
62
|
+
key = OpenSSL::PKey::DSA.new 2048
|
63
|
+
cert.public_key = key.public_key
|
64
|
+
pfx = OpenSSL::PKCS12.create('', '', key, cert)
|
65
|
+
expect { ADAL::ClientAssertionCertificate.new(auth, CLIENT_ID, pfx) }
|
66
|
+
.to raise_error ArgumentError
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should fail if the pkcs12 does not use valid x509' do
|
70
|
+
key = OpenSSL::PKey::RSA.new 2048
|
71
|
+
cert.public_key = key.public_key
|
72
|
+
pfx = OpenSSL::PKCS12.create('', '', key, cert)
|
73
|
+
|
74
|
+
# In practice, no one would ever do this. But we do check for it just in
|
75
|
+
# case.
|
76
|
+
pfx.instance_variable_set(:@certificate, 'Not an x509 certificate')
|
77
|
+
expect { ADAL::ClientAssertionCertificate.new(auth, CLIENT_ID, pfx) }
|
78
|
+
.to raise_error ArgumentError
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#request_params' do
|
83
|
+
ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365
|
84
|
+
let(:cert) { OpenSSL::X509::Certificate.new }
|
85
|
+
before(:each) do
|
86
|
+
key = OpenSSL::PKey::RSA.new 2048
|
87
|
+
cert.public_key = key.public_key
|
88
|
+
@pfx = OpenSSL::PKCS12.create('', '', key, cert)
|
89
|
+
@assertion_cert = ADAL::ClientAssertionCertificate.new(
|
90
|
+
ADAL::Authority.new(AUTHORITY, TENANT), CLIENT_ID, @pfx)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should contain client id, client assertion and client assertion type' do
|
94
|
+
params = @assertion_cert.request_params
|
95
|
+
expect(params.keys).to contain_exactly(
|
96
|
+
:client_id, :client_assertion, :client_assertion_type)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should have client assertion type be JWT_BEARER' do
|
100
|
+
expect(
|
101
|
+
@assertion_cert.request_params[:client_assertion_type]
|
102
|
+
).to eq('urn:ietf:params:oauth:grant-type:jwt-bearer')
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should have an assertion that is a decodable JWT' do
|
106
|
+
expect do
|
107
|
+
JWT.decode(@assertion_cert.request_params[:client_assertion],
|
108
|
+
cert.public_key,
|
109
|
+
options: { verify_not_before: false })
|
110
|
+
end.to_not raise_error
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,38 @@
|
|
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::ClientAssertion do
|
28
|
+
describe '#initialize' do
|
29
|
+
it 'should fail if any parameters are nil' do
|
30
|
+
expect do
|
31
|
+
ADAL::ClientAssertion.new(nil, ASSERTION)
|
32
|
+
end.to raise_error(ArgumentError)
|
33
|
+
expect do
|
34
|
+
ADAL::ClientAssertion.new(CLIENT_ID, nil)
|
35
|
+
end.to raise_error(ArgumentError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,47 @@
|
|
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 'spec_helper'
|
24
|
+
|
25
|
+
using ADAL::CoreExt
|
26
|
+
|
27
|
+
describe Hash do
|
28
|
+
describe '#reverse_merge' do
|
29
|
+
it 'should work on empty hashes' do
|
30
|
+
expect({}.reverse_merge({})).to eq({})
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should work just like merge if the keys do not conflict' do
|
34
|
+
hash1 = { a: 5, b: 10 }
|
35
|
+
hash2 = { c: 8, d: 12 }
|
36
|
+
expect(hash1.reverse_merge(hash2)).to eq(hash1.merge(hash2))
|
37
|
+
expect(hash2.reverse_merge(hash1)).to eq(hash2.merge(hash1))
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should prefer self's values to other_hash's values" do
|
41
|
+
hash1 = { a: 5, c: 10 }
|
42
|
+
hash2 = { a: 6, b: 15 }
|
43
|
+
expect(hash1.reverse_merge(hash2)).to eq(a: 5, b: 15, c: 10)
|
44
|
+
expect(hash2.reverse_merge(hash1)).to eq(a: 6, b: 15, c: 10)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,48 @@
|
|
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
|
+
describe ADAL::Logging do
|
26
|
+
describe '::log_level=' do
|
27
|
+
context 'with an invalid log level' do
|
28
|
+
it 'should throw an error' do
|
29
|
+
expect { ADAL::Logging.log_level = 'abc' }.to raise_error(ArgumentError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with a valid log level' do
|
34
|
+
it 'should not throw an error' do
|
35
|
+
expect { ADAL::Logging.log_level = ADAL::Logger::VERBOSE }
|
36
|
+
.to_not raise_error
|
37
|
+
expect { ADAL::Logging.log_level = ADAL::Logger::INFO }
|
38
|
+
.to_not raise_error
|
39
|
+
expect { ADAL::Logging.log_level = ADAL::Logger::WARN }
|
40
|
+
.to_not raise_error
|
41
|
+
expect { ADAL::Logging.log_level = ADAL::Logger::ERROR }
|
42
|
+
.to_not raise_error
|
43
|
+
expect { ADAL::Logging.log_level = ADAL::Logger::FATAL }
|
44
|
+
.to_not raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,107 @@
|
|
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
|
+
describe ADAL::MemoryCache do
|
26
|
+
let(:authority) { ADAL::Authority.new('login.windows.net', 'contoso.org') }
|
27
|
+
let(:client) { ADAL::ClientCredential.new('my client id', 'client secret') }
|
28
|
+
let(:cache) { ADAL::MemoryCache.new }
|
29
|
+
|
30
|
+
# Note that this test also relies on the correctness of TokenResponse#to_json
|
31
|
+
# and CachedTokenResponse#to_json.
|
32
|
+
describe '#to_json' do
|
33
|
+
subject { cache.to_json }
|
34
|
+
|
35
|
+
context 'when empty' do
|
36
|
+
it { is_expected.to eq '[]' }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with many tokens' do
|
40
|
+
let(:expected_json) do
|
41
|
+
"[{\"access_token\":\"abc\",\"token_type\":\"JWT\"},{\"access_token\"" \
|
42
|
+
":\"abc\",\"scope\":\"openid\"},{\"access_token\":\"abc\",\"resource" \
|
43
|
+
"\":\"http://graph.windows.net\"}]"
|
44
|
+
end
|
45
|
+
let(:expected_json) do
|
46
|
+
"[{\"authority\":[\"login.windows.net\",\"contoso.org\"],\"client_id" \
|
47
|
+
"\":\"my client id\",\"token_response\":{\"access_token\":\"abc\",\"t" \
|
48
|
+
"oken_type\":\"JWT\"}},{\"authority\":[\"login.windows.net\",\"contos" \
|
49
|
+
"o.org\"],\"client_id\":\"my client id\",\"token_response\":{\"access" \
|
50
|
+
"_token\":\"abc\",\"scope\":\"openid\"}},{\"authority\":[\"login.wind" \
|
51
|
+
"ows.net\",\"contoso.org\"],\"client_id\":\"my client id\",\"token_re" \
|
52
|
+
"sponse\":{\"access_token\":\"abc\",\"resource\":\"http://graph.windo" \
|
53
|
+
"ws.net\"}}]"
|
54
|
+
end
|
55
|
+
before(:each) do
|
56
|
+
cache_driver = ADAL::CacheDriver.new(authority, client, cache)
|
57
|
+
cache_driver.add(
|
58
|
+
ADAL::SuccessResponse.new(access_token: 'abc', token_type: 'JWT'))
|
59
|
+
cache_driver.add(
|
60
|
+
ADAL::SuccessResponse.new(access_token: 'abc', scope: 'openid'))
|
61
|
+
cache_driver.add(
|
62
|
+
ADAL::SuccessResponse.new(access_token: 'abc',
|
63
|
+
resource: 'http://graph.windows.net'))
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'properly serializes the cache' do
|
67
|
+
expect(subject).to eq expected_json
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#from_json' do
|
73
|
+
subject { ADAL::MemoryCache.from_json(json) }
|
74
|
+
|
75
|
+
context 'when empty' do
|
76
|
+
let(:json) { '[]' }
|
77
|
+
it 'should contain no entries' do
|
78
|
+
expect(subject.entries.length).to eq 0
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'with many tokens' do
|
83
|
+
let(:json) { cache.to_json }
|
84
|
+
before(:each) do
|
85
|
+
cache_driver = ADAL::CacheDriver.new(authority, client, cache)
|
86
|
+
cache_driver.add(
|
87
|
+
ADAL::SuccessResponse.new(access_token: 'abc', token_type: 'JWT'))
|
88
|
+
cache_driver.add(
|
89
|
+
ADAL::SuccessResponse.new(access_token: 'abc', scope: 'openid'))
|
90
|
+
cache_driver.add(
|
91
|
+
ADAL::SuccessResponse.new(access_token: 'abc',
|
92
|
+
resource: 'http://graph.windows.net'))
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'has the correct number of entries' do
|
96
|
+
expect(subject.entries.length).to eq 3
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'reconstructs the entries' do
|
100
|
+
subject.entries.each do |cache_entry|
|
101
|
+
expect(cache_entry.authority.host).to eq authority.host
|
102
|
+
expect(cache_entry.authority.tenant).to eq authority.tenant
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,57 @@
|
|
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
|
+
describe ADAL::MexRequest do
|
26
|
+
describe '#initialize' do
|
27
|
+
context 'with an invalid endpoint' do
|
28
|
+
let(:uri) { 'not a uri' }
|
29
|
+
|
30
|
+
it 'should raise an error' do
|
31
|
+
expect { ADAL::MexRequest.new(uri) }.to raise_error(
|
32
|
+
URI::InvalidURIError)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#execute' do
|
38
|
+
let(:response_body) { 'response body' }
|
39
|
+
let(:uri) { 'https://abc.def/' }
|
40
|
+
|
41
|
+
before(:each) do
|
42
|
+
@http_request = nil
|
43
|
+
expect_any_instance_of(Net::HTTP).to receive(:request) do |_, req|
|
44
|
+
@http_request = req
|
45
|
+
end.and_return(double(body: response_body))
|
46
|
+
expect(ADAL::MexResponse).to receive(:parse)
|
47
|
+
ADAL::MexRequest.new(uri).execute
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'http request' do
|
51
|
+
subject { @http_request }
|
52
|
+
|
53
|
+
it { expect(subject['Content-Type']).to eq 'application/soap+xml' }
|
54
|
+
it { expect(subject.path).to eq '/' }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,143 @@
|
|
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
|
+
MEX_FIXTURES = File.expand_path('../../fixtures/mex', __FILE__)
|
26
|
+
|
27
|
+
describe ADAL::MexResponse do
|
28
|
+
describe '::parse' do
|
29
|
+
let(:response) { File.read(File.expand_path(file_name, MEX_FIXTURES)) }
|
30
|
+
|
31
|
+
context 'with both 1.3 and 2005 endpoints' do
|
32
|
+
let(:file_name) { 'microsoft.xml' }
|
33
|
+
let(:wstrust_url_13) do
|
34
|
+
'https://corp.sts.microsoft.com/adfs/services/trust/13/usernamemixed'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should not raise an error' do
|
38
|
+
expect { ADAL::MexResponse.parse(response) }.to_not raise_error
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should prefer the 1.3 endpoint' do
|
42
|
+
expect(ADAL::MexResponse.parse(response).wstrust_url.to_s)
|
43
|
+
.to eq(wstrust_url_13)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with only 1.3 wstrust endpoint' do
|
48
|
+
let(:file_name) { 'only_13.xml' }
|
49
|
+
let(:wstrust_13_url) do
|
50
|
+
'https://fs.ajmichael.net/adfs/services/trust/13/usernamemixed'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should parse the 1.3 wstrust endpoint' do
|
54
|
+
expect(ADAL::MexResponse.parse(response).wstrust_url.to_s)
|
55
|
+
.to eq(wstrust_13_url)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with only 2005 wstrust endpoint' do
|
60
|
+
let(:file_name) { 'only_2005.xml' }
|
61
|
+
let(:wstrust_2005_url) do
|
62
|
+
'https://fs.ajmichael.net/adfs/services/trust/2005/usernamemixed'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should parse the 2005 wstrust endpoint' do
|
66
|
+
expect(ADAL::MexResponse.parse(response).wstrust_url.to_s)
|
67
|
+
.to eq(wstrust_2005_url)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with a malformed response' do
|
72
|
+
let(:file_name) { 'malformed.xml' }
|
73
|
+
|
74
|
+
it 'should throw an error' do
|
75
|
+
expect { ADAL::MexResponse.parse(response) }
|
76
|
+
.to raise_error(
|
77
|
+
ADAL::MexResponse::MexError, /No username token policy nodes/)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'with insecure address' do
|
82
|
+
let(:file_name) { 'insecureaddress.xml' }
|
83
|
+
|
84
|
+
it 'should throw an error' do
|
85
|
+
expect { ADAL::MexResponse.parse(response) }
|
86
|
+
.to raise_error(ArgumentError)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'with invalid namespaces' do
|
91
|
+
let(:file_name) { 'invalid_namespaces.xml' }
|
92
|
+
|
93
|
+
it 'should throw an error' do
|
94
|
+
expect { ADAL::MexResponse.parse(response) }
|
95
|
+
.to raise_error(
|
96
|
+
ADAL::MexResponse::MexError, /No username token policy nodes/)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'with no policy nodes' do
|
101
|
+
let(:file_name) { 'no_username_token_policies.xml' }
|
102
|
+
|
103
|
+
it 'should throw an error' do
|
104
|
+
expect { ADAL::MexResponse.parse(response) }
|
105
|
+
.to raise_error(
|
106
|
+
ADAL::MexResponse::MexError, /No username token policy nodes/)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with no wstrust endpoints' do
|
111
|
+
let(:file_name) { 'no_wstrust_endpoints.xml' }
|
112
|
+
|
113
|
+
it 'should throw an error' do
|
114
|
+
expect { ADAL::MexResponse.parse(response) }
|
115
|
+
.to raise_error(
|
116
|
+
ADAL::MexResponse::MexError, /No valid WS-Trust endpoints/)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'with no matching bindings' do
|
121
|
+
let(:file_name) { 'no_matching_bindings.xml' }
|
122
|
+
|
123
|
+
it 'should throw an error' do
|
124
|
+
expect { ADAL::MexResponse.parse(response) }
|
125
|
+
.to raise_error(ADAL::MexResponse::MexError, /No matching bindings/)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'with multiple valid endpoints' do
|
130
|
+
let(:file_name) { 'multiple_endpoints.xml' }
|
131
|
+
let(:first_wstrust_url) do
|
132
|
+
'https://this.is.first.com/adfs/services/trust/13/usernamemixed'
|
133
|
+
end
|
134
|
+
subject { ADAL::MexResponse.parse(response) }
|
135
|
+
|
136
|
+
it { expect { subject }.to_not raise_error }
|
137
|
+
|
138
|
+
it 'should use the first endpoint' do
|
139
|
+
expect(subject.wstrust_url.to_s).to eq(first_wstrust_url)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|