adal 1.0.0

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 +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