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,144 @@
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
+
25
+ require 'digest'
26
+ require 'json'
27
+ require 'jwt'
28
+ require 'securerandom'
29
+
30
+ module ADAL
31
+ # The return type of all of the instance methods that return tokens.
32
+ class TokenResponse
33
+ extend Logging
34
+
35
+ ##
36
+ # Constructs a TokenResponse from a raw hash. It will return either a
37
+ # SuccessResponse or an ErrorResponse depending on the fields of the hash.
38
+ #
39
+ # @param Hash raw_response
40
+ # The body of the HTTP response expressed as a raw hash.
41
+ # @return TokenResponse
42
+ def self.parse(raw_response)
43
+ logger.verbose('Attempting to create a TokenResponse from raw response.')
44
+ if raw_response.nil?
45
+ ErrorResponse.new
46
+ elsif raw_response['error']
47
+ ErrorResponse.new(JSON.parse(raw_response))
48
+ else
49
+ SuccessResponse.new(JSON.parse(raw_response))
50
+ end
51
+ end
52
+
53
+ public
54
+
55
+ ##
56
+ # Shorthand for checking if a token response is successful or failed.
57
+ #
58
+ # @return Boolean
59
+ def error?
60
+ self.respond_to? :error
61
+ end
62
+ end
63
+
64
+ # A token response that contains an access token. All fields are read only
65
+ # and may be nil. Some fields are only populated in certain flows.
66
+ class SuccessResponse < TokenResponse
67
+ include Logging
68
+
69
+ # These fields may or may not be included in the response from the token
70
+ # endpoint.
71
+ OAUTH_FIELDS = [:access_token, :expires_in, :expires_on, :id_token,
72
+ :not_before, :refresh_token, :resource, :scope, :token_type]
73
+ OAUTH_FIELDS.each { |field| attr_reader field }
74
+ attr_reader :user_info
75
+ attr_reader :fields
76
+
77
+ ##
78
+ # Constructs a SuccessResponse from a collection of fields returned from a
79
+ # token endpoint.
80
+ #
81
+ # @param Hash
82
+ def initialize(fields = {})
83
+ @fields = fields
84
+ fields.each { |k, v| instance_variable_set("@#{k}", v) }
85
+ parse_id_token(id_token)
86
+ @expires_on = @expires_in.to_i + Time.now.to_i
87
+ logger.info('Parsed a SuccessResponse with access token digest ' \
88
+ "#{Digest::SHA256.hexdigest @access_token.to_s} and " \
89
+ 'refresh token digest ' \
90
+ "#{Digest::SHA256.hexdigest @refresh_token.to_s}.")
91
+ end
92
+
93
+ ##
94
+ # Converts the fields that were used to create this token response into
95
+ # a JSON string. This is helpful for storing then in a database.
96
+ #
97
+ # @param JSON::Ext::Generator::State
98
+ # We don't care about this, because the JSON representation of this
99
+ # object does not depend on the fields before it.
100
+ # @return String
101
+ def to_json(_ = nil)
102
+ JSON.unparse(fields)
103
+ end
104
+
105
+ ##
106
+ # Parses the raw id token into an ADAL::UserInformation.
107
+ # If the id token is missing, an ADAL::UserInformation will still be
108
+ # generated, it just won't contain any displayable information.
109
+ #
110
+ # @param String id_token
111
+ # The id token to parse
112
+ # Adds an id token to the token response if one is not present
113
+ def parse_id_token(id_token)
114
+ if id_token.nil?
115
+ logger.warn('No id token found.')
116
+ @user_info ||= ADAL::UserInformation.new(unique_id: SecureRandom.uuid)
117
+ return
118
+ end
119
+ logger.verbose('Attempting to decode id token in token response.')
120
+ claims = JWT.decode(id_token.to_s, nil, false).first
121
+ @id_token = id_token
122
+ @user_info = ADAL::UserInformation.new(claims)
123
+ end
124
+ end
125
+
126
+ # A token response that contains an error code.
127
+ class ErrorResponse < TokenResponse
128
+ include Logging
129
+
130
+ OAUTH_FIELDS = [:error, :error_description, :error_codes, :timestamp,
131
+ :trace_id, :correlation_id, :submit_url, :context]
132
+ OAUTH_FIELDS.each { |field| attr_reader field }
133
+
134
+ # Constructs a Error from a collection of fields returned from a
135
+ # token endpoint.
136
+ #
137
+ # @param Hash
138
+ def initialize(fields = {})
139
+ fields.each { |k, v| instance_variable_set("@#{k}", v) }
140
+ logger.error("Parsed an ErrorResponse with error: #{@error} and error " \
141
+ "description: #{@error_description}.")
142
+ end
143
+ end
144
+ 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 './token_request'
24
+
25
+ module ADAL
26
+ # An assertion and its representation type, stored as a JWT for
27
+ # the on-behalf-of flow.
28
+ class UserAssertion
29
+ attr_reader :assertion
30
+ attr_reader :assertion_type
31
+
32
+ ##
33
+ # Creates a new UserAssertion.
34
+ #
35
+ # @param String assertion
36
+ # An OAuth assertion representing the user.
37
+ # @optional AssertionType assertion_type
38
+ # The type of the assertion being made. Currently only JWT_BEARER is
39
+ # supported.
40
+ def initialize(
41
+ assertion, assertion_type = ADAL::TokenRequest::GrantType::JWT_BEARER)
42
+ @assertion = assertion
43
+ @assertion_type = assertion_type
44
+ end
45
+
46
+ ##
47
+ # The relevant OAuth access token request parameters for this object.
48
+ #
49
+ # @return Hash
50
+ def request_params
51
+ { grant_type: assertion_type,
52
+ assertion: assertion,
53
+ requested_token_use: :on_behalf_of,
54
+ scope: :openid }
55
+ end
56
+ end
57
+ 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 './authority'
24
+ require_relative './logger'
25
+ require_relative './mex_request'
26
+ require_relative './token_request'
27
+ require_relative './wstrust_request'
28
+
29
+ require 'base64'
30
+ require 'json'
31
+ require 'net/http'
32
+ require 'uri'
33
+
34
+ module ADAL
35
+ # A convenience class for username and password credentials.
36
+ class UserCredential
37
+ include Logging
38
+
39
+ # Federation response type from the userrealm endpoint.
40
+ module AccountType
41
+ FEDERATED = 'Federated'
42
+ MANAGED = 'Managed'
43
+ UNKNOWN = 'Unknown'
44
+ end
45
+
46
+ # ADAL only supports flows for managed and federated users.
47
+ class UnsupportedAccountTypeError < StandardError
48
+ def initialize(account_type)
49
+ super("Unsupported account type for authentication: #{account_type}.")
50
+ end
51
+ end
52
+
53
+ attr_reader :username
54
+ attr_reader :password
55
+
56
+ ##
57
+ # Constructs a new UserCredential.
58
+ #
59
+ # @param String username
60
+ # @param String password
61
+ # @optional String authority_host
62
+ # The host name of the authority to verify the user against.
63
+ def initialize(
64
+ username, password, authority_host = Authority::WORLD_WIDE_AUTHORITY)
65
+ @username = username
66
+ @password = password
67
+ @authority_host = authority_host
68
+ @discovery_path = "/common/userrealm/#{URI.escape @username}"
69
+ end
70
+
71
+ ##
72
+ # Determines the account type based on a Home Realm Discovery request.
73
+ #
74
+ # @return UserCredential::AccountType
75
+ def account_type
76
+ realm_discovery_response['account_type']
77
+ end
78
+
79
+ ##
80
+ # The OAuth parameters that respresent this UserCredential.
81
+ #
82
+ # @return Hash
83
+ def request_params
84
+ case account_type
85
+ when AccountType::MANAGED
86
+ managed_request_params
87
+ when AccountType::FEDERATED
88
+ federated_request_params
89
+ else
90
+ fail UnsupportedAccountTypeError, account_type
91
+ end
92
+ end
93
+
94
+ # :nocov:
95
+ def to_s
96
+ "UserCredential[Username: #{@username}, AccountType: #{account_type}]"
97
+ end
98
+ # :nocov:
99
+
100
+ private
101
+
102
+ # Memoized response from the discovery endpoint. Since a UserCredential is
103
+ # read only, this should only ever need to be called once.
104
+ # @return Hash
105
+ def realm_discovery_response
106
+ @realm_discovery_response ||=
107
+ JSON.parse(Net::HTTP.get(realm_discovery_uri))
108
+ end
109
+
110
+ # @return URI
111
+ def realm_discovery_uri
112
+ URI::HTTPS.build(
113
+ host: @authority_host,
114
+ path: @discovery_path,
115
+ query: URI.encode_www_form('api-version' => '1.0'))
116
+ end
117
+
118
+ # @return Hash
119
+ def federated_request_params
120
+ logger.verbose("Getting OAuth parameters for Federated #{@username}.")
121
+ wstrust_response = wstrust_request.execute(@username, @password)
122
+ { assertion: Base64.encode64(wstrust_response.token).strip,
123
+ grant_type: wstrust_response.grant_type,
124
+ scope: :openid }
125
+ end
126
+
127
+ # @return URI
128
+ def federation_metadata_url
129
+ URI.parse(realm_discovery_response['federation_metadata_url'])
130
+ end
131
+
132
+ # @return Hash
133
+ def managed_request_params
134
+ logger.verbose("Getting OAuth parameters for Managed #{@username}.")
135
+ { username: @username,
136
+ password: @password,
137
+ grant_type: TokenRequest::GrantType::PASSWORD,
138
+ scope: :openid }
139
+ end
140
+
141
+ # @return MexResponse
142
+ def mex_response
143
+ @mex_response ||= MexRequest.new(federation_metadata_url).execute
144
+ end
145
+
146
+ # @return WSTrustRequest
147
+ def wstrust_request
148
+ @wstrust_request ||=
149
+ WSTrustRequest.new(mex_response.wstrust_url, mex_response.action)
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,83 @@
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
+ # Identifier for users in the cache.
25
+ #
26
+ # Ideally, the application will first use a different OAuth flow, such as the
27
+ # Authorization Code flow, to acquire an ADAL::SuccessResponse. Then, it can
28
+ # create ADAL::UserIdentifier to query the cache which will refresh tokens as
29
+ # necessary.
30
+ class UserIdentifier
31
+ attr_reader :id
32
+ attr_reader :type
33
+
34
+ # Displayable IDs are human readable (eg email addresses) while Unique Ids
35
+ # are generally random UUIDs.
36
+ module Type
37
+ UNIQUE_ID = :UNIQUE_ID
38
+ DISPLAYABLE_ID = :DISPLAYABLE_ID
39
+ end
40
+ include Type
41
+
42
+ ##
43
+ # Creates a UserIdentifier with a specific type. Used for cache lookups.
44
+ # Matches .NET ADAL implementation.
45
+ #
46
+ # @param String id
47
+ # @param UserIdentifier::Type
48
+ # @return ADAL::UserIdentifier
49
+ def initialize(id, type)
50
+ unless [UNIQUE_ID, DISPLAYABLE_ID].include? type
51
+ fail ArgumentError, 'type must be an ADAL::UserIdentifier::Type.'
52
+ end
53
+ @id = id
54
+ @type = type
55
+ end
56
+
57
+ ##
58
+ # These parameters should only be used for cache lookup. This is enforced
59
+ # by ADAL::TokenRequest.
60
+ #
61
+ # @return Hash
62
+ def request_params
63
+ { user_info: self }
64
+ end
65
+
66
+ ##
67
+ # Overrides comparison operator for cache lookups
68
+ #
69
+ # @param UserIdentifier other
70
+ # @return Boolean
71
+ def ==(other)
72
+ case other
73
+ when UserIdentifier
74
+ self.equal? other
75
+ when UserInformation
76
+ (type == UNIQUE_ID && id == other.unique_id) ||
77
+ (type == DISPLAYABLE_ID && id == other.displayable_id)
78
+ when String
79
+ @id == other
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,49 @@
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
+ # Basically just a holder for the id token.
25
+ class UserInformation
26
+ ID_TOKEN_FIELDS = [:aud, :iss, :iat, :nbf, :exp, :ver, :tid, :oid, :upn,
27
+ :sub, :given_name, :family_name, :name, :amr,
28
+ :unique_name, :nonce, :email]
29
+ ID_TOKEN_FIELDS.each { |field| attr_reader field }
30
+ attr_reader :unique_id
31
+ attr_reader :displayable_id
32
+
33
+ ##
34
+ # Constructs a new UserInformation.
35
+ #
36
+ # @param Hash claims
37
+ # Claims from an id token. The exact claims will vary, so whatever is not
38
+ # found in the claims will be nil.
39
+ def initialize(claims)
40
+ claims.each { |k, v| instance_variable_set("@#{k}", v) }
41
+ @unique_id = oid || sub || unique_id
42
+ @displayable_id = upn || email
43
+ end
44
+
45
+ def ==(other)
46
+ unique_id == other.unique_id && displayable_id == other.displayable_id
47
+ end
48
+ end
49
+ end