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.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -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 +97 -0
  8. data/Rakefile +39 -0
  9. data/adal.gemspec +52 -0
  10. data/contributing.md +127 -0
  11. data/lib/adal.rb +24 -0
  12. data/lib/adal/authentication_context.rb +202 -0
  13. data/lib/adal/authentication_parameters.rb +126 -0
  14. data/lib/adal/authority.rb +165 -0
  15. data/lib/adal/cache_driver.rb +171 -0
  16. data/lib/adal/cached_token_response.rb +190 -0
  17. data/lib/adal/client_assertion.rb +63 -0
  18. data/lib/adal/client_assertion_certificate.rb +89 -0
  19. data/lib/adal/client_credential.rb +46 -0
  20. data/lib/adal/core_ext.rb +26 -0
  21. data/lib/adal/core_ext/hash.rb +34 -0
  22. data/lib/adal/jwt_parameters.rb +39 -0
  23. data/lib/adal/logger.rb +90 -0
  24. data/lib/adal/logging.rb +98 -0
  25. data/lib/adal/memory_cache.rb +95 -0
  26. data/lib/adal/mex_request.rb +52 -0
  27. data/lib/adal/mex_response.rb +141 -0
  28. data/lib/adal/noop_cache.rb +38 -0
  29. data/lib/adal/oauth_request.rb +76 -0
  30. data/lib/adal/request_parameters.rb +48 -0
  31. data/lib/adal/self_signed_jwt_factory.rb +96 -0
  32. data/lib/adal/templates/rst.13.xml.erb +35 -0
  33. data/lib/adal/templates/rst.2005.xml.erb +32 -0
  34. data/lib/adal/token_request.rb +231 -0
  35. data/lib/adal/token_response.rb +144 -0
  36. data/lib/adal/user_assertion.rb +57 -0
  37. data/lib/adal/user_credential.rb +152 -0
  38. data/lib/adal/user_identifier.rb +83 -0
  39. data/lib/adal/user_information.rb +49 -0
  40. data/lib/adal/util.rb +49 -0
  41. data/lib/adal/version.rb +36 -0
  42. data/lib/adal/wstrust_request.rb +100 -0
  43. data/lib/adal/wstrust_response.rb +168 -0
  44. data/lib/adal/xml_namespaces.rb +64 -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 +265 -0
@@ -0,0 +1,42 @@
1
+ ## Authenticating with a Certificate and Private Key
2
+
3
+ ### Set-Up
4
+ 1. Register a web application in the Azure portal. Note it's client id.
5
+ 2. Generate a self-issued certificate with key length >= 2048. Using the Windows makecert.exe utility, this can be done with:
6
+
7
+ ```
8
+ makecert -r -pe -n "CN=Name of Certificate" -b 07/01/2015 -e 07/01/2017 -ss my -len 2048
9
+ ```
10
+ 3. Export the certificate from Certificate Manager to a file.
11
+ 4. Get the base 64 thumbprint, base 64 value and key id from the certificate. With Windows powershell, this can be done with:
12
+
13
+ ```
14
+ $cer = New-Object System.Security.Cryptograph.X509Certificates.X509Certificate2
15
+ $cer.Import(".\path\to\cert\from\step3.cer")
16
+ $base64thumbprint = [System.Convert]::ToBase64String($cer.GetRawCertData())
17
+ $base64value = [System.Convert]::ToBase64String($cer.GetRawCertData())
18
+ $keyId = [System.Guid]::NewGuid().ToString()
19
+ ```
20
+ 5. Download the manifest for the registered web application, add the following entry to the keyCredentials array and reupload it:
21
+
22
+ ```
23
+ {
24
+ "customKeyIdentifier": "[base 64 thumbprint]",
25
+ "keyId": "[key id]",
26
+ "type": "AsymmetricX509Cert",
27
+ "usage": "Verify",
28
+ "value": "[base 64 value]"
29
+ }
30
+ ```
31
+ 6. Export the certificate as a PFX (PKCS12). This can be done via the Windows Certificate Manager GUI.
32
+ 7. Fill in your tenant, client id of the web application and path and password to your .pfx file in app.rb.
33
+
34
+ ### Run
35
+ Run the app as ```ruby app.rb```.
36
+
37
+ ## Common problems
38
+ ### I get an error that looks like:
39
+ ```
40
+ ...net/http.rb:xxx: in connect SSL_connect returned=1 errno=0 state=SSLv3 read server certificate verify failed (OpenSSL::SSL::SSLError)
41
+ ```
42
+ This is likely because you are on a Windows system and installed a Ruby installation that ships OpenSSL with no certificate authorities. The most common offender is RailsInstaller. [Solution](https://gist.github.com/fnichol/867550).
@@ -0,0 +1,55 @@
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
+ # See the accompanying README.md for instructions on how to set-up an
24
+ # application to run this sample.
25
+
26
+ require 'adal'
27
+ require 'openssl'
28
+
29
+ # This will make ADAL log the various steps of JWT creation from certificates.
30
+ ADAL::Logging.log_level = ADAL::Logger::VERBOSE
31
+
32
+ AUTHORITY_HOST = ADAL::Authority::WORLD_WIDE_AUTHORITY
33
+ CLIENT_ID = 'your client id here'
34
+ RESOURCE = 'https://outlook.office365.com'
35
+ TENANT = 'your tenant here.onmicrosoft.com'
36
+
37
+ PFX_PATH = './path/to/your/cert.pfx'
38
+ PFX_PASSWORD = 'password'
39
+
40
+ pfx = OpenSSL::PKCS12.new(File.read(PFX_PATH), PFX_PASSWORD)
41
+
42
+ authority = ADAL::Authority.new(AUTHORITY_HOST, TENANT)
43
+ client_cred = ADAL::ClientAssertionCertificate.new(authority, CLIENT_ID, pfx)
44
+ result = ADAL::AuthenticationContext
45
+ .new(AUTHORITY_HOST, TENANT)
46
+ .acquire_token_for_client(RESOURCE, client_cred)
47
+
48
+ case result
49
+ when ADAL::SuccessResponse
50
+ puts 'Successfully authenticated with client credentials. Received access ' \
51
+ "token: #{result.access_token}."
52
+ when ADAL::FailureResponse
53
+ puts 'Failed to authenticate with client credentials. Received error: ' \
54
+ "#{result.error} and error description: #{result.error_description}."
55
+ end
@@ -0,0 +1,35 @@
1
+ # Authenticating On Behalf of a User
2
+
3
+ This sample consists of two applications that each use ADAL.
4
+
5
+ The native application uses a username and password flow to obtain an access
6
+ token and then uses that access token to access a resource: the web api.
7
+
8
+ The web api takes the access token and exchanges it for an access token for
9
+ the graph.windows.net resource and uses it to retrieve graph data, which it
10
+ then sends back to the native app.
11
+
12
+ Before running these applications, follow the instructions below to configure
13
+ them to your tenant.
14
+
15
+
16
+ ## Configuring the Native Application
17
+ 1. In the Azure portal, register a new Web Application. Take note of the client
18
+ id and client secret. The application identifier can be anything, but take
19
+ note of what you choose for a future step.
20
+ 2. Give this application permission to use the web application that you create
21
+ in the next step. (You can't do this step until you've configured the Web
22
+ Application.)
23
+ 3. In `web_app.rb`, fill in the tenant, client id and client secret fields.
24
+
25
+ ## Configuring the Web Application
26
+ 1. In the Azure portal, register a new Native Application. Take note of the
27
+ client id.
28
+ 2. Give this application permission to `Read directory data.`.
29
+ 3. In `native_app.rb`, fill in the tenant and client id field. Fiell in the
30
+ `WEB_API_RESOURCE` field with the application identifier that you used
31
+ previously.
32
+
33
+ ## Running the application
34
+ 1. Start the web application with `ruby web_api.rb`.
35
+ 2. Run the native application with `ruby native_app.rb`.
@@ -0,0 +1,52 @@
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 'adal'
24
+ require 'json'
25
+
26
+ def prompt(*args)
27
+ print(*args)
28
+ gets.strip
29
+ end
30
+
31
+ # Uncomment this if you want to trace ADAL's execution.
32
+ # ADAL::Logging.log_level = ADAL::Logger::VERBOSE
33
+
34
+ AUTHORITY_HOST = ADAL::Authority::WORLD_WIDE_AUTHORITY
35
+ TENANT = 'your tenant here.onmicrosoft.com'
36
+ CLIENT_ID = 'your client id here'
37
+ WEB_API_RESOURCE = 'https://your tenant here.onmicrosoft.com/MyWebService'
38
+ WEB_API_ENDPOINT = 'http://localhost:44321/api/graph'
39
+
40
+ user_cred = ADAL::UserCredential.new(prompt('Username: '), prompt('Password: '))
41
+ ctx = ADAL::AuthenticationContext.new(AUTHORITY_HOST, TENANT)
42
+
43
+ token_response =
44
+ ctx.acquire_token_for_user(WEB_API_RESOURCE, CLIENT_ID, user_cred)
45
+
46
+ web_api_uri = URI(WEB_API_ENDPOINT)
47
+ headers = { 'Bearer' => token_response.access_token }
48
+ http = Net::HTTP.new(web_api_uri.hostname, web_api_uri.port)
49
+ web_api_response = http.get(web_api_uri, headers)
50
+
51
+ puts 'Here is your directory user graph:'
52
+ puts JSON.pretty_generate(JSON.parse(web_api_response.body))
@@ -0,0 +1,71 @@
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 '../../lib/adal'
24
+ require 'sinatra'
25
+
26
+ # Uncomment this if you want to trace ADAL's execution.
27
+ # ADAL::Logging.log_level = ADAL::Logger::VERBOSE
28
+
29
+ AUTHORITY_HOST = ADAL::Authority::WORLD_WIDE_AUTHORITY
30
+ TENANT = 'your tenant here.onmicrosoft.com'
31
+ RESOURCE = 'https://graph.windows.net'
32
+ CLIENT_ID = 'your client id here'
33
+ CLIENT_SECRET = 'your client secret here'
34
+
35
+ set :client_cred, ADAL::ClientCredential.new(CLIENT_ID, CLIENT_SECRET)
36
+ set :ctx, ADAL::AuthenticationContext.new(AUTHORITY_HOST, TENANT)
37
+ set :port, 44_321
38
+
39
+ before do
40
+ # If the client does not send an access token, then he is unauthorized.
41
+ halt 401 unless env['HTTP_BEARER']
42
+
43
+ token = exchange_tokens(env['HTTP_BEARER'])
44
+ env[:access_token] = token.access_token
45
+
46
+ # If we cannot exchange the clients access token for a new one, then he is
47
+ # unauthorized.
48
+ halt 401 unless env[:access_token]
49
+ end
50
+
51
+ # Fetches the contents of the /users graph endpoint.
52
+ get '/api/graph' do
53
+ graph_uri = URI(RESOURCE + '/' + TENANT + '/users?api-version=2013-04-05')
54
+ headers = { 'authorization' => env[:access_token] }
55
+ http = Net::HTTP.new(graph_uri.hostname, graph_uri.port)
56
+ http.use_ssl = true
57
+ http.get(graph_uri, headers).body
58
+ end
59
+
60
+ ##
61
+ # Exchanges an access token for this web api for an access token for another
62
+ # resource.
63
+ #
64
+ # @param String access_token
65
+ # The token for this web service, from the client.
66
+ # @return String
67
+ # An access token for the designated resource.
68
+ def exchange_tokens(access_token)
69
+ settings.ctx.acquire_token_for_user(
70
+ RESOURCE, settings.client_cred, ADAL::UserAssertion.new(access_token))
71
+ end
@@ -0,0 +1,7 @@
1
+ This simple application demonstrates how to use ADAL to acquire access tokens
2
+ with the username/password flow.
3
+
4
+ To run the application:
5
+
6
+ 1. Replace the `CLIENT_ID` and `TENANT` fields with your client id and tenant.
7
+ 2. Run `ruby app.rb`.
@@ -0,0 +1,52 @@
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 'adal'
24
+
25
+ # This will make ADAL log the various steps of obtaining an access token.
26
+ ADAL::Logging.log_level = ADAL::Logger::VERBOSE
27
+
28
+ AUTHORITY_HOST = ADAL::Authority::WORLD_WIDE_AUTHORITY
29
+ CLIENT_ID = 'your clientid here'
30
+ RESOURCE = 'https://graph.windows.net'
31
+ TENANT = 'your tenant here.onmicrosoft.com'
32
+
33
+ def prompt(*args)
34
+ print(*args)
35
+ gets.strip
36
+ end
37
+
38
+ username = prompt 'Username: '
39
+ password = prompt 'Password: '
40
+
41
+ user_cred = ADAL::UserCredential.new(username, password)
42
+ ctx = ADAL::AuthenticationContext.new(AUTHORITY_HOST, TENANT)
43
+ result = ctx.acquire_token_for_user(RESOURCE, CLIENT_ID, user_cred)
44
+
45
+ case result
46
+ when ADAL::SuccessResponse
47
+ puts 'Successfully authenticated with user credentials. Received access ' \
48
+ "token: #{result.access_token}."
49
+ when ADAL::FailureResponse
50
+ puts 'Failed to authenticate with client credentials. Received error: ' \
51
+ "#{result.error} and error description: #{result.error_description}."
52
+ end
@@ -0,0 +1,186 @@
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
+ # Load constants used by the fake token endpoint.
28
+ include FakeData
29
+
30
+ describe ADAL::AuthenticationContext do
31
+ let(:auth_ctx) { ADAL::AuthenticationContext.new(AUTHORITY, TENANT) }
32
+ let(:client_cred) { ADAL::ClientCredential.new(CLIENT_ID, CLIENT_SECRET) }
33
+
34
+ describe '#authorization_request_url' do
35
+ let(:resource) { 'http://graph.windows.net' }
36
+ let(:client_id) { 'some-client-id' }
37
+ let(:redirect_uri) { 'http://contoso.com/login' }
38
+
39
+ context 'with no extra params' do
40
+ it 'should produce the correct request url' do
41
+ authorization_url =
42
+ auth_ctx.authorization_request_url(resource, client_id, redirect_uri)
43
+ expect(authorization_url.to_s.strip)
44
+ .to eq "https://#{AUTHORITY}/#{TENANT}/oauth2/authorize?client_id=" \
45
+ "#{client_id}&response_mode=form_post&redirect_uri=http%3A%2" \
46
+ 'F%2Fcontoso.com%2Flogin&resource=http%3A%2F%2Fgraph.windows' \
47
+ '.net&response_type=code'
48
+ end
49
+ end
50
+
51
+ context 'with extra params' do
52
+ it 'should produce the correct request url' do
53
+ params = { foo: :bar }
54
+ authorization_url = auth_ctx.authorization_request_url(
55
+ resource, client_id, redirect_uri, params)
56
+ expect(authorization_url.to_s.strip)
57
+ .to eq "https://#{AUTHORITY}/#{TENANT}/oauth2/authorize?client_id=" \
58
+ "#{client_id}&response_mode=form_post&redirect_uri=http%3A%2" \
59
+ 'F%2Fcontoso.com%2Flogin&resource=http%3A%2F%2Fgraph.windows' \
60
+ '.net&response_type=code&foo=bar'
61
+ end
62
+ end
63
+ end
64
+
65
+ describe '#correlation_id=' do
66
+ let(:correlation_id) { 'correlation_id_1' }
67
+ let(:user) { ADAL::UserAssertion.new(USER_ASSERTION) }
68
+
69
+ it 'should put the correlation id on all request headers' do
70
+ auth_ctx.correlation_id = correlation_id
71
+ stub_request(:post, %r{.*#{TENANT}\/oauth2\/token})
72
+ .with(headers: { 'client-request-id' => correlation_id })
73
+ .and_return(body: '{"access_token":"my access token"}')
74
+ result = auth_ctx.acquire_token_for_user(RESOURCE, CLIENT_ID, user)
75
+ expect(result.access_token).to eq('my access token')
76
+ end
77
+ end
78
+
79
+ describe '#acquire_token_with_authorization_code' do
80
+ it 'should return a SuccessResponse when successful' do
81
+ token_response = auth_ctx.acquire_token_with_authorization_code(
82
+ AUTH_CODE, REDIRECT_URI, client_cred, RESOURCE)
83
+ expect(token_response).to be_a(ADAL::SuccessResponse)
84
+ end
85
+
86
+ it 'should return an ErrorResponse when unauthorized' do
87
+ token_response = auth_ctx.acquire_token_with_authorization_code(
88
+ AUTH_CODE, 'bad', client_cred, RESOURCE)
89
+ expect(token_response).to be_a(ADAL::ErrorResponse)
90
+ end
91
+
92
+ it 'should fail if any of the required parameters are nil' do
93
+ expect do
94
+ auth_ctx.acquire_token_with_authorization_code(
95
+ nil, REDIRECT_URI, client_cred, RESOURCE)
96
+ end.to raise_error(ArgumentError)
97
+ end
98
+ end
99
+
100
+ describe '#acquire_token_for_client' do
101
+ it 'should return a SuccessResponse when successful' do
102
+ response = auth_ctx.acquire_token_for_client(RESOURCE, client_cred)
103
+ expect(response).to be_a(ADAL::SuccessResponse)
104
+ end
105
+
106
+ it 'should return an ErrorResponse when unauthorized' do
107
+ token_response = auth_ctx.acquire_token_for_client(RESOURCE, 'bad')
108
+ expect(token_response).to be_a(ADAL::ErrorResponse)
109
+ end
110
+
111
+ it 'should fail if any of the parameters are nil' do
112
+ expect do
113
+ auth_ctx.acquire_token_for_client(RESOURCE, nil)
114
+ end.to raise_error(ArgumentError)
115
+ end
116
+ end
117
+
118
+ describe '#acquire_token_with_refresh_token' do
119
+ it 'should return a SuccessResponse when successful' do
120
+ token_response = auth_ctx.acquire_token_with_refresh_token(
121
+ REFRESH_TOKEN, client_cred, RESOURCE)
122
+ expect(token_response).to be_a(ADAL::SuccessResponse)
123
+ end
124
+
125
+ it 'should return an ErrorResponse when unauthorized' do
126
+ token_response = auth_ctx.acquire_token_with_refresh_token(
127
+ REFRESH_TOKEN, 'bad', RESOURCE)
128
+ expect(token_response).to be_a(ADAL::ErrorResponse)
129
+ end
130
+
131
+ it 'should return an ErrorResponse when the refresh token is invalid' do
132
+ token_response = auth_ctx.acquire_token_with_refresh_token(
133
+ 'bad', client_cred, RESOURCE)
134
+ expect(token_response).to be_a(ADAL::ErrorResponse)
135
+ end
136
+
137
+ it 'should fail if any of the required parameters are nil' do
138
+ expect do
139
+ auth_ctx.acquire_token_with_refresh_token(
140
+ nil, client_cred, RESOURCE)
141
+ end.to raise_error(ArgumentError)
142
+ end
143
+ end
144
+
145
+ describe '#acquire_token_for_user' do
146
+ context 'with valid parameters' do
147
+ let(:user) { ADAL::UserAssertion.new(USER_ASSERTION) }
148
+ subject { auth_ctx.acquire_token_for_user(RESOURCE, client_cred, user) }
149
+
150
+ it { is_expected.to be_a(ADAL::SuccessResponse) }
151
+ end
152
+
153
+ context 'with invalid parameters' do
154
+ it 'should fail' do
155
+ expect { auth_ctx.acquire_token_for_user(nil, nil) }
156
+ .to raise_error(ArgumentError)
157
+ end
158
+ end
159
+
160
+ context 'with a UserIdentifier' do
161
+ let(:user) { ADAL::UserIdentifier.new(USERNAME, :DISPLAYABLE_ID) }
162
+ context 'with a matching token in the cache' do
163
+ subject { auth_ctx.acquire_token_for_user(RESOURCE, client_cred, user) }
164
+ before(:each) do
165
+ @first_response = auth_ctx.acquire_token_with_authorization_code(
166
+ AUTH_CODE, REDIRECT_URI, client_cred, RESOURCE)
167
+ end
168
+
169
+ it { is_expected.to_not be nil }
170
+
171
+ it 'should return the token from the cache' do
172
+ expect(subject).to eq @first_response
173
+ end
174
+ end
175
+
176
+ context 'with no matching token in the cache' do
177
+ subject do
178
+ -> { auth_ctx.acquire_token_for_user(RESOURCE, client_cred, user) }
179
+ end
180
+ it do
181
+ is_expected.to raise_error ADAL::TokenRequest::UserCredentialError
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end