custom-adal 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rubocop.yml +7 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +25 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +106 -0
  8. data/Rakefile +39 -0
  9. data/adal.gemspec +52 -0
  10. data/contributing.md +127 -0
  11. data/lib/adal/authentication_context.rb +202 -0
  12. data/lib/adal/authentication_parameters.rb +126 -0
  13. data/lib/adal/authority.rb +165 -0
  14. data/lib/adal/cache_driver.rb +171 -0
  15. data/lib/adal/cached_token_response.rb +190 -0
  16. data/lib/adal/client_assertion.rb +63 -0
  17. data/lib/adal/client_assertion_certificate.rb +89 -0
  18. data/lib/adal/client_credential.rb +46 -0
  19. data/lib/adal/core_ext/hash.rb +34 -0
  20. data/lib/adal/core_ext.rb +26 -0
  21. data/lib/adal/jwt_parameters.rb +39 -0
  22. data/lib/adal/logger.rb +90 -0
  23. data/lib/adal/logging.rb +98 -0
  24. data/lib/adal/memory_cache.rb +95 -0
  25. data/lib/adal/mex_request.rb +52 -0
  26. data/lib/adal/mex_response.rb +141 -0
  27. data/lib/adal/noop_cache.rb +38 -0
  28. data/lib/adal/oauth_request.rb +76 -0
  29. data/lib/adal/request_parameters.rb +48 -0
  30. data/lib/adal/self_signed_jwt_factory.rb +96 -0
  31. data/lib/adal/templates/rst.13.xml.erb +35 -0
  32. data/lib/adal/templates/rst.2005.xml.erb +32 -0
  33. data/lib/adal/token_request.rb +231 -0
  34. data/lib/adal/token_response.rb +144 -0
  35. data/lib/adal/user_assertion.rb +57 -0
  36. data/lib/adal/user_credential.rb +152 -0
  37. data/lib/adal/user_identifier.rb +83 -0
  38. data/lib/adal/user_information.rb +49 -0
  39. data/lib/adal/util.rb +49 -0
  40. data/lib/adal/version.rb +36 -0
  41. data/lib/adal/wstrust_request.rb +100 -0
  42. data/lib/adal/wstrust_response.rb +168 -0
  43. data/lib/adal/xml_namespaces.rb +64 -0
  44. data/lib/adal.rb +24 -0
  45. data/samples/authorization_code_example/README.md +10 -0
  46. data/samples/authorization_code_example/web_app.rb +139 -0
  47. data/samples/client_assertion_certificate_example/README.md +42 -0
  48. data/samples/client_assertion_certificate_example/app.rb +55 -0
  49. data/samples/on_behalf_of_example/README.md +35 -0
  50. data/samples/on_behalf_of_example/native_app.rb +52 -0
  51. data/samples/on_behalf_of_example/web_api.rb +71 -0
  52. data/samples/user_credentials_example/README.md +7 -0
  53. data/samples/user_credentials_example/app.rb +52 -0
  54. data/spec/adal/authentication_context_spec.rb +186 -0
  55. data/spec/adal/authentication_parameters_spec.rb +107 -0
  56. data/spec/adal/authority_spec.rb +122 -0
  57. data/spec/adal/cache_driver_spec.rb +191 -0
  58. data/spec/adal/cached_token_response_spec.rb +148 -0
  59. data/spec/adal/client_assertion_certificate_spec.rb +113 -0
  60. data/spec/adal/client_assertion_spec.rb +38 -0
  61. data/spec/adal/core_ext/hash_spec.rb +47 -0
  62. data/spec/adal/logging_spec.rb +48 -0
  63. data/spec/adal/memory_cache_spec.rb +107 -0
  64. data/spec/adal/mex_request_spec.rb +57 -0
  65. data/spec/adal/mex_response_spec.rb +143 -0
  66. data/spec/adal/self_signed_jwt_factory_spec.rb +63 -0
  67. data/spec/adal/token_request_spec.rb +150 -0
  68. data/spec/adal/token_response_spec.rb +102 -0
  69. data/spec/adal/user_credential_spec.rb +125 -0
  70. data/spec/adal/user_identifier_spec.rb +115 -0
  71. data/spec/adal/wstrust_request_spec.rb +51 -0
  72. data/spec/adal/wstrust_response_spec.rb +152 -0
  73. data/spec/fixtures/mex/insecureaddress.xml +924 -0
  74. data/spec/fixtures/mex/invalid_namespaces.xml +916 -0
  75. data/spec/fixtures/mex/malformed.xml +914 -0
  76. data/spec/fixtures/mex/microsoft.xml +916 -0
  77. data/spec/fixtures/mex/multiple_endpoints.xml +922 -0
  78. data/spec/fixtures/mex/no_matching_bindings.xml +916 -0
  79. data/spec/fixtures/mex/no_username_token_policies.xml +914 -0
  80. data/spec/fixtures/mex/no_wstrust_endpoints.xml +838 -0
  81. data/spec/fixtures/mex/only_13.xml +842 -0
  82. data/spec/fixtures/mex/only_2005.xml +842 -0
  83. data/spec/fixtures/oauth/error.json +1 -0
  84. data/spec/fixtures/oauth/success.json +1 -0
  85. data/spec/fixtures/oauth/success_with_id_token.json +1 -0
  86. data/spec/fixtures/wstrust/error.xml +24 -0
  87. data/spec/fixtures/wstrust/invalid_namespaces.xml +136 -0
  88. data/spec/fixtures/wstrust/missing_security_tokens.xml +90 -0
  89. data/spec/fixtures/wstrust/success.xml +136 -0
  90. data/spec/fixtures/wstrust/token.xml +1 -0
  91. data/spec/fixtures/wstrust/too_many_security_tokens.xml +219 -0
  92. data/spec/fixtures/wstrust/unrecognized_token_type.xml +136 -0
  93. data/spec/fixtures/wstrust/wstrust.13.xml +1 -0
  94. data/spec/fixtures/wstrust/wstrust.2005.xml +89 -0
  95. data/spec/spec_helper.rb +53 -0
  96. data/spec/support/fake_data.rb +40 -0
  97. data/spec/support/fake_token_endpoint.rb +108 -0
  98. metadata +264 -0
@@ -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
@@ -0,0 +1,51 @@
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::WSTrustRequest do
26
+ subject { ADAL::WSTrustRequest.new(uri) }
27
+
28
+ describe '#initialize' do
29
+ context 'with an invalid URI' do
30
+ let(:uri) { 'not a uri' }
31
+
32
+ it 'should raise InvalidURIError' do
33
+ expect do
34
+ ADAL::WSTrustRequest.new(uri)
35
+ end.to raise_error(URI::InvalidURIError)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe '#execute' do
41
+ let(:uri) { 'https://microsoft.com/' }
42
+
43
+ it 'parses the body as an ADAL::WSTrustResponse' do
44
+ mex_response_body = 'mex body'
45
+ expect_any_instance_of(Net::HTTP).to receive(:request).once
46
+ .and_return(double(body: mex_response_body, code: '200'))
47
+ expect(ADAL::WSTrustResponse).to receive(:parse).with(mex_response_body)
48
+ subject.execute('some user', 'some password')
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,152 @@
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
+ WSTRUST_FIXTURES = File.expand_path('../../fixtures/wstrust', __FILE__)
26
+
27
+ describe ADAL::WSTrustResponse do
28
+ describe '::parse' do
29
+ let(:response) { File.read(File.expand_path(file_name, WSTRUST_FIXTURES)) }
30
+
31
+ context 'with a successful response' do
32
+ let(:file_name) { 'success.xml' }
33
+
34
+ let(:token) do
35
+ File.read(File.expand_path('token.xml', WSTRUST_FIXTURES))
36
+ end
37
+
38
+ it 'correctly extracts the token' do
39
+ wstrust_response = ADAL::WSTrustResponse.parse(response)
40
+ expect(wstrust_response.token.strip).to eq(token.strip)
41
+ end
42
+
43
+ it 'has the correct grant type' do
44
+ wstrust_response = ADAL::WSTrustResponse.parse(response)
45
+ expect(wstrust_response.grant_type).to eq(
46
+ ADAL::TokenRequest::GrantType::SAML1)
47
+ end
48
+ end
49
+
50
+ context 'with an unrecognized token type' do
51
+ let(:file_name) { 'unrecognized_token_type.xml' }
52
+
53
+ it 'throws the appropriate error' do
54
+ expect { ADAL::WSTrustResponse.parse(response) }
55
+ .to raise_error(ADAL::WSTrustResponse::UnrecognizedTokenTypeError)
56
+ end
57
+ end
58
+
59
+ context 'with a WS-Trust 1.3 response' do
60
+ let(:file_name) { 'wstrust.13.xml' }
61
+
62
+ it 'extracts the token' do
63
+ wstrust_response = ADAL::WSTrustResponse.parse(response)
64
+ expect(wstrust_response.token.strip).to_not be nil
65
+ end
66
+ end
67
+
68
+ context 'with a WS-Trust 2005 response' do
69
+ let(:file_name) { 'wstrust.2005.xml' }
70
+
71
+ it 'extracts the token' do
72
+ wstrust_response = ADAL::WSTrustResponse.parse(response)
73
+ expect(wstrust_response.token.strip).to_not be nil
74
+ end
75
+ end
76
+
77
+ context 'with an error response' do
78
+ let(:file_name) { 'error.xml' }
79
+
80
+ it 'throws the appropriate error' do
81
+ expect do
82
+ ADAL::WSTrustResponse.parse(response)
83
+ end.to raise_error(ADAL::WSTrustResponse::WSTrustError, /MSIS3127/)
84
+ end
85
+ end
86
+
87
+ context 'with invalid namespaces' do
88
+ let(:file_name) { 'invalid_namespaces.xml' }
89
+
90
+ it 'throws the appropriate error' do
91
+ expect { ADAL::WSTrustResponse.parse(response) }
92
+ .to raise_error(
93
+ ADAL::WSTrustResponse::WSTrustError, /Unable to parse token/)
94
+ end
95
+ end
96
+
97
+ context 'with an invalid abundance of security tokens' do
98
+ let(:file_name) { 'too_many_security_tokens.xml' }
99
+
100
+ it 'throws the appropriate error' do
101
+ expect { ADAL::WSTrustResponse.parse(response) }
102
+ .to raise_error(
103
+ ADAL::WSTrustResponse::WSTrustError,
104
+ /too many RequestedSecurityTokens/)
105
+ end
106
+ end
107
+
108
+ context 'with no security tokens on the first token response node' do
109
+ let(:file_name) { 'missing_security_tokens.xml' }
110
+ let(:expected_token) { '<foo:Assertion xmlns:foo="bar"/>' }
111
+ subject { ADAL::WSTrustResponse.parse(response) }
112
+
113
+ it { expect { subject }.to_not raise_error }
114
+
115
+ it 'should use the backup' do
116
+ expect(subject.token.to_s).to eq(expected_token)
117
+ end
118
+ end
119
+ end
120
+
121
+ describe '#grant_type' do
122
+ context 'with a SAML1 token type' do
123
+ subject do
124
+ response = ADAL::WSTrustResponse.new(
125
+ 'irrelevant', ADAL::WSTrustResponse::TokenType::V1)
126
+ response.grant_type
127
+ end
128
+ it { is_expected.to eq(ADAL::TokenRequest::GrantType::SAML1) }
129
+ end
130
+
131
+ context 'with a SAML2 token type' do
132
+ subject do
133
+ response = ADAL::WSTrustResponse.new(
134
+ 'irrelevant', ADAL::WSTrustResponse::TokenType::V2)
135
+ response.grant_type
136
+ end
137
+ it { is_expected.to eq(ADAL::TokenRequest::GrantType::SAML2) }
138
+ end
139
+
140
+ # This case should not happen unless the developer is being intentionally
141
+ # hacky. The constructor ensures that the token type is valid.
142
+ context 'with an unrecognized token type' do
143
+ subject do
144
+ response = ADAL::WSTrustResponse.new(
145
+ 'irrelevant', ADAL::WSTrustResponse::TokenType::V1)
146
+ response.instance_variable_set(:@token_type, 'not a token type')
147
+ response.grant_type
148
+ end
149
+ it { is_expected.to be_nil }
150
+ end
151
+ end
152
+ end