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,141 @@
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 './logging'
24
+ require_relative './xml_namespaces'
25
+
26
+ require 'nokogiri'
27
+ require 'uri'
28
+
29
+ module ADAL
30
+ # Relevant fields from a Mex response.
31
+ class MexResponse
32
+ include XmlNamespaces
33
+
34
+ class << self
35
+ include Logging
36
+ end
37
+
38
+ class MexError < StandardError; end
39
+
40
+ POLICY_ID_XPATH =
41
+ '//wsdl:definitions/wsp:Policy[./wsp:ExactlyOne/wsp:All/sp:SignedSuppor' \
42
+ 'tingTokens/wsp:Policy/sp:UsernameToken/wsp:Policy/sp:WssUsernameToken1' \
43
+ '0]/@u:Id|//wsdl:definitions/wsp:Policy[./wsp:ExactlyOne/wsp:All/ssp:Si' \
44
+ 'gnedEncryptedSupportingTokens/wsp:Policy/ssp:UsernameToken/wsp:Policy/' \
45
+ 'ssp:WssUsernameToken10]/@u:Id'
46
+ BINDING_XPATH = '//wsdl:definitions/wsdl:binding[./wsp:PolicyReference]'
47
+ PORT_XPATH = '//wsdl:definitions/wsdl:service/wsdl:port'
48
+ ADDRESS_XPATH = './soap12:address/@location'
49
+
50
+ ##
51
+ # Parses the XML string response from the Metadata Exchange endpoint into
52
+ # a MexResponse object.
53
+ #
54
+ # @param String response
55
+ # @return MexResponse
56
+ def self.parse(response)
57
+ xml = Nokogiri::XML(response)
58
+ policy_ids = parse_policy_ids(xml)
59
+ bindings = parse_bindings(xml, policy_ids)
60
+ endpoint, binding = parse_endpoint_and_binding(xml, bindings)
61
+ MexResponse.new(endpoint, binding)
62
+ end
63
+
64
+ # @param Nokogiri::XML::Document xml
65
+ # @param Array[String] policy_ids
66
+ # @return Array[String]
67
+ def self.parse_bindings(xml, policy_ids)
68
+ matching_bindings = xml.xpath(BINDING_XPATH, NAMESPACES).map do |node|
69
+ reference_uri = node.xpath('./wsp:PolicyReference/@URI', NAMESPACES)
70
+ node.xpath('./@name').to_s if policy_ids.include? reference_uri.to_s
71
+ end.compact
72
+ fail MexError, 'No matching bindings found.' if matching_bindings.empty?
73
+ matching_bindings
74
+ end
75
+ private_class_method :parse_bindings
76
+
77
+ # @param Nokogiri::XML::Document xml
78
+ # @param Array[String] bindings
79
+ # @return Array[[String, String]]
80
+ def self.parse_all_endpoints(xml, bindings)
81
+ endpoints = xml.xpath(PORT_XPATH, NAMESPACES).map do |node|
82
+ binding = node.attr('binding').split(':').last
83
+ if bindings.include? binding
84
+ [node.xpath(ADDRESS_XPATH, NAMESPACES).to_s, binding]
85
+ end
86
+ end.compact
87
+ endpoints
88
+ end
89
+ private_class_method :parse_all_endpoints
90
+
91
+ # @param Nokogiri::XML::Document xml
92
+ # @param Array[String] bindings
93
+ # @return [String, String]
94
+ def self.parse_endpoint_and_binding(xml, bindings)
95
+ endpoints = parse_all_endpoints(xml, bindings)
96
+ case endpoints.size
97
+ when 0
98
+ fail MexError, 'No valid WS-Trust endpoints found.'
99
+ when 1
100
+ else
101
+ logger.info('Multiple WS-Trust endpoints were found in the mex ' \
102
+ 'response. Only one was used.')
103
+ end
104
+ prefer_13(endpoints).first
105
+ end
106
+ private_class_method :parse_endpoint_and_binding
107
+
108
+ # @param Nokogiri::XML::Document xml
109
+ # @return Array[String]
110
+ def self.parse_policy_ids(xml)
111
+ policy_ids = xml.xpath(POLICY_ID_XPATH, NAMESPACES)
112
+ .map { |attr| "\##{attr.value}" }
113
+ fail MexError, 'No username token policy nodes.' if policy_ids.empty?
114
+ policy_ids
115
+ end
116
+ private_class_method :parse_policy_ids
117
+
118
+ # @param Array[String, String] endpoints
119
+ # @return Array[String, String] endpoints
120
+ def self.prefer_13(endpoints)
121
+ only13 = endpoints.select { |_, b| BINDING_TO_ACTION[b] == WSTRUST_13 }
122
+ only13.empty? ? endpoints : only13
123
+ end
124
+ private_class_method :prefer_13
125
+
126
+ attr_reader :action
127
+ attr_reader :wstrust_url
128
+
129
+ ##
130
+ # Constructs a new MexResponse.
131
+ #
132
+ # @param String|URI wstrust_url
133
+ # @param String action
134
+ def initialize(wstrust_url, binding)
135
+ @action = BINDING_TO_ACTION[binding]
136
+ @wstrust_url = URI.parse(wstrust_url.to_s)
137
+ return if @wstrust_url.instance_of? URI::HTTPS
138
+ fail ArgumentError, 'Mex is only done over HTTPS.'
139
+ end
140
+ end
141
+ 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
+ module ADAL
24
+ # A cache implementation that holds no values and ignores all method calls.
25
+ class NoopCache
26
+ # Swallows any number of parameters and returns nil.
27
+ def noop(*); end
28
+
29
+ alias_method :add, :noop
30
+ alias_method :add_many, :noop
31
+ alias_method :remove, :noop
32
+ alias_method :remove_many, :noop
33
+
34
+ def find(*)
35
+ []
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,76 @@
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 './logging'
24
+ require_relative './request_parameters'
25
+ require_relative './util'
26
+
27
+ require 'net/http'
28
+ require 'uri'
29
+
30
+ module ADAL
31
+ # A request that can be made to an authentication or token server.
32
+ class OAuthRequest
33
+ include RequestParameters
34
+ include Util
35
+
36
+ DEFAULT_CONTENT_TYPE = 'application/x-www-form-urlencoded'
37
+ DEFAULT_ENCODING = 'utf8'
38
+ SSL_SCHEME = 'https'
39
+
40
+ def initialize(endpoint, params)
41
+ @endpoint_uri = URI.parse(endpoint.to_s)
42
+ @params = params
43
+ end
44
+
45
+ def params
46
+ default_parameters.merge(@params)
47
+ end
48
+
49
+ ##
50
+ # Requests and waits for a token from the endpoint.
51
+ # @return TokenResponse
52
+ def execute
53
+ request = Net::HTTP::Post.new(@endpoint_uri.path)
54
+ add_headers(request)
55
+ request.body = URI.encode_www_form(string_hash(params))
56
+ TokenResponse.parse(http(@endpoint_uri).request(request).body)
57
+ end
58
+
59
+ private
60
+
61
+ ##
62
+ # Adds the necessary OAuth headers.
63
+ #
64
+ # @param Net::HTTPGenericRequest
65
+ def add_headers(request)
66
+ return if Logging.correlation_id.nil?
67
+ request.add_field(CLIENT_REQUEST_ID.to_s, Logging.correlation_id)
68
+ request.add_field(CLIENT_RETURN_CLIENT_REQUEST_ID.to_s, true)
69
+ end
70
+
71
+ def default_parameters
72
+ { encoding: DEFAULT_ENCODING,
73
+ AAD_API_VERSION => '1.0' }
74
+ end
75
+ end
76
+ 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
+ module ADAL
24
+ # Names of parameters in OAuth requests. This module can be included in any
25
+ # class to reference the parameters instead of referring to them as strings
26
+ # or symbols
27
+ module RequestParameters
28
+ AAD_API_VERSION = 'api-version'.to_sym
29
+ ASSERTION = 'assertion'.to_sym
30
+ CLIENT_ASSERTION = 'client_assertion'.to_sym
31
+ CLIENT_ASSERTION_TYPE = 'client_assertion_type'.to_sym
32
+ CLIENT_ID = 'client_id'.to_sym
33
+ CLIENT_REQUEST_ID = 'client-request-id'.to_sym
34
+ CLIENT_RETURN_CLIENT_REQUEST_ID = 'client-return-client-request-id'.to_sym
35
+ CLIENT_SECRET = 'client_secret'.to_sym
36
+ CODE = 'code'.to_sym
37
+ FORM_POST = 'form_post'.to_sym
38
+ GRANT_TYPE = 'grant_type'.to_sym
39
+ PASSWORD = 'password'.to_sym
40
+ REDIRECT_URI = 'redirect_uri'.to_sym
41
+ REFRESH_TOKEN = 'refresh_token'.to_sym
42
+ RESOURCE = 'resource'.to_sym
43
+ SCOPE = 'scope'.to_sym
44
+ UNIQUE_ID = 'unique_id'.to_sym
45
+ USER_INFO = 'user_info'.to_sym
46
+ USERNAME = 'username'.to_sym
47
+ end
48
+ end
@@ -0,0 +1,96 @@
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 './jwt_parameters'
24
+ require_relative './logging'
25
+
26
+ require 'jwt'
27
+ require 'openssl'
28
+ require 'securerandom'
29
+
30
+ module ADAL
31
+ # Converts client certificates into self signed JWTs.
32
+ class SelfSignedJwtFactory
33
+ include JwtParameters
34
+ include Logging
35
+
36
+ ##
37
+ # Constructs a new SelfSignedJwtFactory.
38
+ #
39
+ # @param String client_id
40
+ # The client id of the calling application.
41
+ # @param String token_endpoint
42
+ # The token endpoint that will accept the certificate.
43
+ def initialize(client_id, token_endpoint)
44
+ @client_id = client_id
45
+ @token_endpoint = token_endpoint
46
+ end
47
+
48
+ ##
49
+ # Creates a JWT from a client certificate and signs it with a private key.
50
+ #
51
+ # @param OpenSSL::X509::Certificate certificate
52
+ # The certifcate object to be converted to a JWT and signed for use
53
+ # in an authentication flow.
54
+ # @param OpenSSL::PKey::RSA private_key
55
+ # The private key used to sign the certificate.
56
+ # @return String
57
+ def create_and_sign_jwt(certificate, private_key)
58
+ JWT.encode(payload, private_key, RS256, header(certificate))
59
+ end
60
+
61
+ private
62
+
63
+ # The JWT header for a certificate to be encoded.
64
+ def header(certificate)
65
+ x5t = thumbprint(certificate)
66
+ logger.verbose("Creating self signed JWT header with thumbprint: #{x5t}.")
67
+ { TYPE => TYPE_JWT,
68
+ ALGORITHM => RS256,
69
+ THUMBPRINT => x5t }
70
+ end
71
+
72
+ # The JWT payload.
73
+ def payload
74
+ now = Time.now - 1
75
+ expires = now + 60 * SELF_SIGNED_JWT_LIFETIME
76
+ logger.verbose("Creating self signed JWT payload. Expires: #{expires}. " \
77
+ "NotBefore: #{now}.")
78
+ { AUDIENCE => @token_endpoint,
79
+ ISSUER => @client_id,
80
+ SUBJECT => @client_id,
81
+ NOT_BEFORE => now.to_i,
82
+ EXPIRES_ON => expires.to_i,
83
+ JWT_ID => SecureRandom.uuid }
84
+ end
85
+
86
+ ##
87
+ # Base 64 encoded thumbprint AKA fingerprint AKA SHA1 hash of the
88
+ # DER representation of the cert.
89
+ #
90
+ # @param OpenSSL::X509::Certificate certificate
91
+ # @return String
92
+ def thumbprint(certificate)
93
+ OpenSSL::Digest::SHA1.new(certificate.to_der).base64digest
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0"?>
2
+ <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
3
+ <s:Header>
4
+ <a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
5
+ <a:messageID>urn:uuid:<%= message_id %></a:messageID>
6
+ <a:ReplyTo>
7
+ <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
8
+ </a:ReplyTo>
9
+ <a:To s:mustUnderstand="1"><%= @endpoint %></a:To>
10
+ <o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
11
+ <u:Timestamp u:Id="_0">
12
+ <u:Created><%= created.utc.iso8601 %></u:Created>
13
+ <u:Expires><%= expires.utc.iso8601 %></u:Expires>
14
+ </u:Timestamp>
15
+ <o:UsernameToken u:Id="ADALUsernameToken">
16
+ <o:Username><%= username.encode(xml: :text) %></o:Username>
17
+ <o:Password><%= password.encode(xml: :text) %></o:Password>
18
+ </o:UsernameToken>
19
+ </o:Security>
20
+ </s:Header>
21
+ <s:Body>
22
+ <trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
23
+ <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
24
+ <a:EndpointReference>
25
+ <a:Address><%= @applies_to %></a:Address>
26
+ </a:EndpointReference>
27
+ </wsp:AppliesTo>
28
+ <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
29
+ <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
30
+ </trust:RequestSecurityToken>
31
+ </s:Body>
32
+ </s:Envelope>
33
+
34
+
35
+
@@ -0,0 +1,32 @@
1
+ <?xml version="1.0"?>
2
+ <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
3
+ <s:Header>
4
+ <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
5
+ <a:messageID>urn:uuid:<%= message_id %></a:messageID>
6
+ <a:ReplyTo>
7
+ <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
8
+ </a:ReplyTo>
9
+ <a:To s:mustUnderstand="1"><%= @endpoint %></a:To>
10
+ <o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
11
+ <u:Timestamp u:Id="_0">
12
+ <u:Created><%= created.utc.iso8601 %></u:Created>
13
+ <u:Expires><%= expires.utc.iso8601 %></u:Expires>
14
+ </u:Timestamp>
15
+ <o:UsernameToken u:Id="ADALUsernameToken">
16
+ <o:Username><%= username.encode(xml: :text) %></o:Username>
17
+ <o:Password><%= password.encode(xml: :text) %></o:Password>
18
+ </o:UsernameToken>
19
+ </o:Security>
20
+ </s:Header>
21
+ <s:Body>
22
+ <trust:RequestSecurityToken xmlns:trust="http://schemas.xmlsoap.org/ws/2005/02/trust">
23
+ <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
24
+ <a:EndpointReference>
25
+ <a:Address><%= @applies_to %></a:Address>
26
+ </a:EndpointReference>
27
+ </wsp:AppliesTo>
28
+ <trust:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</trust:KeyType>
29
+ <trust:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</trust:RequestType>
30
+ </trust:RequestSecurityToken>
31
+ </s:Body>
32
+ </s:Envelope>