custom-adal 1.0.1

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 +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,63 @@
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 './request_parameters'
24
+ require_relative './token_request'
25
+ require_relative './util'
26
+
27
+ module ADAL
28
+ # A client credential that consists of the client id and a JWT bearer
29
+ # assertion. The type is 'urn:ietf:params:oauth:token-type:jwt'.
30
+ class ClientAssertion
31
+ include TokenRequest::GrantType
32
+ include RequestParameters
33
+ include Util
34
+
35
+ attr_reader :assertion
36
+ attr_reader :assertion_type
37
+ attr_reader :client_id
38
+
39
+ ##
40
+ # Creates a new ClientAssertion.
41
+ #
42
+ # @param [String] client_id
43
+ # The client id of the calling application.
44
+ # @param [String] assertion
45
+ # The JWT used as a credential.
46
+ def initialize(client_id, assertion, assertion_type = JWT_BEARER)
47
+ fail_if_arguments_nil(client_id, assertion, assertion_type)
48
+ @assertion = assertion
49
+ @assertion_type = assertion_type
50
+ @client_id = client_id
51
+ end
52
+
53
+ ##
54
+ # The relavent parameters from this credential for OAuth.
55
+ #
56
+ # @return Hash
57
+ def request_params
58
+ { CLIENT_ID => @client_id,
59
+ CLIENT_ASSERTION_TYPE => @assertion_type,
60
+ CLIENT_ASSERTION => @assertion }
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,89 @@
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 'openssl'
24
+
25
+ module ADAL
26
+ # An assertion made by a client with an X509 certificate. This requires both
27
+ # the public and private keys. Technically it only requires the thumbprint
28
+ # of the public key, however OpenSSL's object model does not include
29
+ # thumbprints.
30
+ class ClientAssertionCertificate
31
+ include RequestParameters
32
+
33
+ MIN_KEY_SIZE_BITS = 2014
34
+
35
+ attr_reader :certificate
36
+ attr_reader :client_id
37
+
38
+ ##
39
+ # Creates a new ClientAssertionCertificate.
40
+ #
41
+ # @param Authority authority
42
+ # The authority object that will recognize this certificate.
43
+ # @param [String] client_id
44
+ # The client id of the calling application.
45
+ # @param [OpenSSL::PKCS12] pkcs12_file
46
+ # The PKCS12 file containing the certificate and private key.
47
+ def initialize(authority, client_id, pkcs12_file)
48
+ unless pkcs12_file.is_a? OpenSSL::PKCS12
49
+ fail ArgumentError, 'Only PKCS12 file format is supported.'
50
+ end
51
+ @authority = authority
52
+ @certificate = pkcs12_file.certificate
53
+ @client_id = client_id.to_s
54
+ @private_key = pkcs12_file.key
55
+ validate_certificate_and_key(@certificate, @private_key)
56
+ end
57
+
58
+ # The relevant parameters from this credential for OAuth.
59
+ def request_params
60
+ jwt_assertion = SelfSignedJwtFactory
61
+ .new(@client_id, @authority.token_endpoint)
62
+ .create_and_sign_jwt(@certificate, @private_key)
63
+ ClientAssertion.new(client_id, jwt_assertion).request_params
64
+ end
65
+
66
+ private
67
+
68
+ # @param [OpenSSL::X509::Certificate] certificate
69
+ # @return [Fixnum] The number of bits in the public key.
70
+ def public_key_size_bits(certificate)
71
+ certificate.public_key.n.num_bytes * 8
72
+ end
73
+
74
+ ##
75
+ # In general, Ruby code is very loose about types. However, since we are
76
+ # dealing with sensitive information here, we will be a little bit stricter
77
+ # on type safety.
78
+ def validate_certificate_and_key(certificate, private_key)
79
+ if !certificate.is_a? OpenSSL::X509::Certificate
80
+ fail ArgumentError, 'certificate must be an OpenSSL::X509::Certificate.'
81
+ elsif !private_key.is_a? OpenSSL::PKey::RSA
82
+ fail ArgumentError, 'private_key must be an OpenSSL::PKey::RSA.'
83
+ elsif public_key_size_bits(certificate) < MIN_KEY_SIZE_BITS
84
+ fail ArgumentError, 'certificate must contain a public key of at ' \
85
+ "least #{MIN_KEY_SIZE_BITS} bits."
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,46 @@
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 './request_parameters'
24
+ require_relative './util'
25
+
26
+ module ADAL
27
+ # A wrapper object for a client id and secret.
28
+ class ClientCredential
29
+ include RequestParameters
30
+ include Util
31
+
32
+ attr_reader :client_id
33
+ attr_reader :client_secret
34
+
35
+ def initialize(client_id, client_secret = nil)
36
+ fail_if_arguments_nil(client_id)
37
+ @client_id = client_id
38
+ @client_secret = client_secret
39
+ end
40
+
41
+ # The relavent parameters from this credential for OAuth.
42
+ def request_params
43
+ { CLIENT_ID => @client_id, CLIENT_SECRET => @client_secret }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,34 @@
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
+ # Adds helper methods to Hash. These are standard in Rails and are
25
+ # commonplace in the Ruby community.
26
+ module CoreExt
27
+ # Same as #merge, but values in other_hash are prioritized over self.
28
+ refine Hash do
29
+ def reverse_merge(other_hash)
30
+ other_hash.merge(self)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,26 @@
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
+ # All of the refinements used in ADAL. They are all in the namespace
24
+ # ADAL::CoreExt and will only be applied to files that start with ADAL::CoreExt
25
+ # before opening any module or class.
26
+ require_relative './core_ext/hash'
@@ -0,0 +1,39 @@
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
+ # Literals used in JWT header and payload.
25
+ module JwtParameters
26
+ ALGORITHM = 'alg'
27
+ AUDIENCE = 'aud'
28
+ EXPIRES_ON = 'exp'
29
+ ISSUER = 'iss'
30
+ JWT_ID = 'jti'
31
+ NOT_BEFORE = 'nbf'
32
+ RS256 = 'RS256'
33
+ SELF_SIGNED_JWT_LIFETIME = 10
34
+ SUBJECT = 'sub'
35
+ THUMBPRINT = 'x5t'
36
+ TYPE = 'typ'
37
+ TYPE_JWT = 'JWT'
38
+ end
39
+ end
@@ -0,0 +1,90 @@
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 'logger'
24
+
25
+ module ADAL
26
+ # Extended version of Ruby's base logger class to support VERBOSE logging.
27
+ # This is consistent with ADAL logging across platforms.
28
+ #
29
+ # The format of a log message is described in the Ruby docs at
30
+ # http://ruby-doc.org/stdlib-2.2.2/libdoc/logger/rdoc/Logger.html as
31
+ # SeverityID, [DateTime #pid] SeverityLabel -- ProgName: message.
32
+ # SeverityID is the first letter of the severity. In the case of ADAL::Logger
33
+ # that means one of {V, I, W, E, F}. The DateTime object uses the to_s method
34
+ # of DateTime from stdlib which is ISO-8601. The ProgName will be the
35
+ # correlation id if one is sent or absent otherwise.
36
+ class Logger < Logger
37
+ SEVS = %w(VERBOSE INFO WARN ERROR FATAL)
38
+ VERBOSE = SEVS.index('VERBOSE')
39
+
40
+ ##
41
+ # Constructs a new Logger.
42
+ #
43
+ # @param String|IO logdev
44
+ # A filename (String) or IO object (STDOUT, STDERR).
45
+ # @param String correlation_id
46
+ # The UUID of the request context.
47
+ def initialize(logdev, correlation_id)
48
+ super(logdev)
49
+ @correlation_id = correlation_id
50
+ end
51
+
52
+ def format_severity(severity)
53
+ SEVS[severity] || 'ANY'
54
+ end
55
+
56
+ ##
57
+ # For some reason, the default logger implementations of #error, #fatal,
58
+ # etc. pass message = nil and progname = <the message> to #add, which
59
+ # interprets that as using the progname as the message. Instead, we will
60
+ # use the message as the message and the progname as the correlation_id.
61
+ #
62
+ # This is purely an internal change, the calling mechanism is exactly the
63
+ # same and it only affects ADAL::Logger, not Logger.
64
+
65
+ # These methods are skipped by the SimpleCov, because it is not our
66
+ # responsibility to test the standard library's logging framework.
67
+
68
+ #:nocov:
69
+ def error(message = nil, &block)
70
+ add(ERROR, message, @correlation_id, &block)
71
+ end
72
+
73
+ def fatal(message = nil, &block)
74
+ add(FATAL, message, @correlation_id, &block)
75
+ end
76
+
77
+ def info(message = nil, &block)
78
+ add(INFO, message, @correlation_id, &block)
79
+ end
80
+
81
+ def verbose(message = nil, &block)
82
+ add(VERBOSE, message, @correlation_id, &block)
83
+ end
84
+
85
+ def warn(message = nil, &block)
86
+ add(WARN, message, @correlation_id, &block)
87
+ end
88
+ #:nocov:
89
+ end
90
+ end
@@ -0,0 +1,98 @@
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 './logger'
24
+
25
+ require 'securerandom'
26
+
27
+ module ADAL
28
+ # Mix-in module for the ADAL logger. To obtain a logger in class methods the
29
+ # calling class will need to extend this module. To obtain a logger in
30
+ # instance methods the calling will need to include this Module.
31
+ module Logging
32
+ DEFAULT_LOG_LEVEL = Logger::ERROR
33
+ DEFAULT_LOG_OUTPUT = STDOUT
34
+
35
+ @correlation_id = SecureRandom.uuid
36
+ @log_level = DEFAULT_LOG_LEVEL
37
+ @log_output = DEFAULT_LOG_OUTPUT
38
+
39
+ # According to the style guide, class instance variables are preferable to
40
+ # class variables.
41
+ class << self
42
+ attr_accessor :correlation_id
43
+ attr_accessor :log_level
44
+ attr_accessor :log_output
45
+ end
46
+
47
+ ##
48
+ # Sets the ADAL log level.
49
+ #
50
+ # Example usage:
51
+ #
52
+ # ADAL::Logging.log_level = ADAL::Logger::VERBOSE
53
+ #
54
+ def self.log_level=(level)
55
+ unless Logger::SEVS.map.with_index { |_, i| i }.include? level
56
+ fail ArgumentError, "Invalid log level: #{level}."
57
+ end
58
+ @log_level = level
59
+ end
60
+
61
+ ##
62
+ # Sets the ADAL log output. All future logs generated by ADAL will be sent
63
+ # to this location. It is not retroactive.
64
+ #
65
+ # @param IO|String output
66
+ # This can either be STDERR, STDOUT or a String containing a file path.
67
+ def self.log_output=(output)
68
+ output = output.to_s unless output.is_a? IO
69
+ @log_output = output
70
+ end
71
+
72
+ ##
73
+ # Creates one ADAL logger per calling class/module with a specified output.
74
+ # This is to be used within ADAL. Clients will have no use for it.
75
+ #
76
+ # Examples usage:
77
+ #
78
+ # require_relative './logging'
79
+ #
80
+ # module ADAL
81
+ # module SomeModule
82
+ # include Logging
83
+ #
84
+ # def something_bad
85
+ # logger.error('An error message')
86
+ # end
87
+ # end
88
+ # end
89
+ #
90
+ # @param output
91
+ # STDERR, STDOUT or the file name as a string.
92
+ def logger
93
+ @logger ||= ADAL::Logger.new(Logging.log_output, Logging.correlation_id)
94
+ @logger.level = Logging.log_level || DEFAULT_LOG_LEVEL
95
+ @logger
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,95 @@
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
+ module ADAL
26
+ # A simple cache implementation that is not persisted across application runs.
27
+ class MemoryCache
28
+ include Logging
29
+
30
+ def initialize
31
+ @entries = []
32
+ end
33
+
34
+ attr_accessor :entries
35
+
36
+ ##
37
+ # Adds an array of objects to the cache.
38
+ #
39
+ # @param Array
40
+ # The entries to add.
41
+ # @return Array
42
+ # The entries after the addition.
43
+ def add(entries)
44
+ entries = Array(entries) # If entries is an array, this is a no-op.
45
+ old_size = @entries.size
46
+ @entries |= entries
47
+ logger.verbose("Added #{entries.size - old_size} new entries to cache.")
48
+ end
49
+
50
+ ##
51
+ # By default, matches all entries.
52
+ #
53
+ # @param Block
54
+ # A matcher on the token list.
55
+ # @return Array
56
+ # The matching tokens.
57
+ def find(&query)
58
+ query ||= proc { true }
59
+ @entries.select(&query)
60
+ end
61
+
62
+ ##
63
+ # Removes an array of objects from the cache.
64
+ #
65
+ # @param Array
66
+ # The entries to remove.
67
+ # @return Array
68
+ # The remaining entries.
69
+ def remove(entries)
70
+ @entries -= Array(entries)
71
+ end
72
+
73
+ ##
74
+ # Converts the cache entries into one JSON string.
75
+ #
76
+ # @param JSON::Ext::Generator::State
77
+ # @return String
78
+ def to_json(_ = nil)
79
+ JSON.unparse(entries)
80
+ end
81
+
82
+ ##
83
+ # Reconstructs the cache from JSON that was previously serialized.
84
+ #
85
+ # @param JSON json
86
+ # @return MemoryCache
87
+ def self.from_json(json)
88
+ cache = MemoryCache.new
89
+ cache.entries = JSON.parse(json).map do |e|
90
+ CachedTokenResponse.from_json(e)
91
+ end
92
+ cache
93
+ end
94
+ end
95
+ end
@@ -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_relative './mex_response'
24
+ require_relative './util'
25
+
26
+ require 'net/http'
27
+ require 'uri'
28
+
29
+ module ADAL
30
+ # A request to a Metadata Exchange endpoint of an ADFS server. Used to obtain
31
+ # the WSTrust endpoint for username and password authentication of federated
32
+ # users.
33
+ class MexRequest
34
+ include Util
35
+
36
+ ##
37
+ # Constructs a MexRequest object for a specific URL endpoint.
38
+ #
39
+ # @param String|URI endpoint
40
+ # The Metadata Exchange endpoint.
41
+ def initialize(endpoint)
42
+ @endpoint = URI.parse(endpoint.to_s)
43
+ end
44
+
45
+ # @return MexResponse
46
+ def execute
47
+ request = Net::HTTP::Get.new(@endpoint.path)
48
+ request.add_field('Content-Type', 'application/soap+xml')
49
+ MexResponse.parse(http(@endpoint).request(request).body)
50
+ end
51
+ end
52
+ end