kl-ruby-saml 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +14 -0
  4. data/.travis.yml +17 -0
  5. data/Gemfile +9 -0
  6. data/LICENSE +19 -0
  7. data/README.md +575 -0
  8. data/Rakefile +41 -0
  9. data/changelog.md +75 -0
  10. data/gemfiles/nokogiri-1.5.gemfile +5 -0
  11. data/lib/onelogin/ruby-saml.rb +17 -0
  12. data/lib/onelogin/ruby-saml/attribute_service.rb +57 -0
  13. data/lib/onelogin/ruby-saml/attributes.rb +128 -0
  14. data/lib/onelogin/ruby-saml/authrequest.rb +156 -0
  15. data/lib/onelogin/ruby-saml/http_error.rb +7 -0
  16. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +161 -0
  17. data/lib/onelogin/ruby-saml/logging.rb +30 -0
  18. data/lib/onelogin/ruby-saml/logoutrequest.rb +131 -0
  19. data/lib/onelogin/ruby-saml/logoutresponse.rb +241 -0
  20. data/lib/onelogin/ruby-saml/metadata.rb +123 -0
  21. data/lib/onelogin/ruby-saml/response.rb +722 -0
  22. data/lib/onelogin/ruby-saml/saml_message.rb +158 -0
  23. data/lib/onelogin/ruby-saml/settings.rb +165 -0
  24. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +258 -0
  25. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +136 -0
  26. data/lib/onelogin/ruby-saml/utils.rb +172 -0
  27. data/lib/onelogin/ruby-saml/validation_error.rb +7 -0
  28. data/lib/onelogin/ruby-saml/version.rb +5 -0
  29. data/lib/ruby-saml.rb +1 -0
  30. data/lib/schemas/saml-schema-assertion-2.0.xsd +283 -0
  31. data/lib/schemas/saml-schema-authn-context-2.0.xsd +23 -0
  32. data/lib/schemas/saml-schema-authn-context-types-2.0.xsd +821 -0
  33. data/lib/schemas/saml-schema-metadata-2.0.xsd +337 -0
  34. data/lib/schemas/saml-schema-protocol-2.0.xsd +302 -0
  35. data/lib/schemas/sstc-metadata-attr.xsd +35 -0
  36. data/lib/schemas/sstc-saml-attribute-ext.xsd +25 -0
  37. data/lib/schemas/sstc-saml-metadata-algsupport-v1.0.xsd +41 -0
  38. data/lib/schemas/sstc-saml-metadata-ui-v1.0.xsd +89 -0
  39. data/lib/schemas/xenc-schema.xsd +136 -0
  40. data/lib/schemas/xml.xsd +287 -0
  41. data/lib/schemas/xmldsig-core-schema.xsd +309 -0
  42. data/lib/xml_security.rb +358 -0
  43. data/ruby-saml.gemspec +57 -0
  44. data/test/certificates/certificate1 +12 -0
  45. data/test/certificates/certificate_without_head_foot +1 -0
  46. data/test/certificates/formatted_certificate +14 -0
  47. data/test/certificates/formatted_private_key +12 -0
  48. data/test/certificates/formatted_rsa_private_key +12 -0
  49. data/test/certificates/invalid_certificate1 +1 -0
  50. data/test/certificates/invalid_certificate2 +1 -0
  51. data/test/certificates/invalid_certificate3 +12 -0
  52. data/test/certificates/invalid_private_key1 +1 -0
  53. data/test/certificates/invalid_private_key2 +1 -0
  54. data/test/certificates/invalid_private_key3 +10 -0
  55. data/test/certificates/invalid_rsa_private_key1 +1 -0
  56. data/test/certificates/invalid_rsa_private_key2 +1 -0
  57. data/test/certificates/invalid_rsa_private_key3 +10 -0
  58. data/test/certificates/ruby-saml.crt +14 -0
  59. data/test/certificates/ruby-saml.key +15 -0
  60. data/test/idp_metadata_parser_test.rb +95 -0
  61. data/test/logging_test.rb +62 -0
  62. data/test/logout_requests/invalid_slo_request.xml +6 -0
  63. data/test/logout_requests/slo_request.xml +4 -0
  64. data/test/logout_requests/slo_request.xml.base64 +1 -0
  65. data/test/logout_requests/slo_request_deflated.xml.base64 +1 -0
  66. data/test/logout_requests/slo_request_with_session_index.xml +5 -0
  67. data/test/logout_responses/logoutresponse_fixtures.rb +67 -0
  68. data/test/logoutrequest_test.rb +211 -0
  69. data/test/logoutresponse_test.rb +258 -0
  70. data/test/metadata_test.rb +203 -0
  71. data/test/request_test.rb +282 -0
  72. data/test/response_test.rb +1094 -0
  73. data/test/responses/adfs_response_sha1.xml +46 -0
  74. data/test/responses/adfs_response_sha256.xml +46 -0
  75. data/test/responses/adfs_response_sha384.xml +46 -0
  76. data/test/responses/adfs_response_sha512.xml +46 -0
  77. data/test/responses/adfs_response_xmlns.xml +45 -0
  78. data/test/responses/attackxee.xml +13 -0
  79. data/test/responses/idp_descriptor.xml +3 -0
  80. data/test/responses/invalids/invalid_audience.xml.base64 +1 -0
  81. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +1 -0
  82. data/test/responses/invalids/invalid_issuer_message.xml.base64 +1 -0
  83. data/test/responses/invalids/invalid_signature_position.xml.base64 +1 -0
  84. data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +1 -0
  85. data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +1 -0
  86. data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +1 -0
  87. data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +1 -0
  88. data/test/responses/invalids/multiple_assertions.xml.base64 +2 -0
  89. data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
  90. data/test/responses/invalids/no_id.xml.base64 +1 -0
  91. data/test/responses/invalids/no_saml2.xml.base64 +1 -0
  92. data/test/responses/invalids/no_signature.xml.base64 +1 -0
  93. data/test/responses/invalids/no_status.xml.base64 +1 -0
  94. data/test/responses/invalids/no_status_code.xml.base64 +1 -0
  95. data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +1 -0
  96. data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +1 -0
  97. data/test/responses/invalids/response_encrypted_attrs.xml.base64 +1 -0
  98. data/test/responses/invalids/response_invalid_signed_element.xml.base64 +1 -0
  99. data/test/responses/invalids/status_code_responder.xml.base64 +1 -0
  100. data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +1 -0
  101. data/test/responses/no_signature_ns.xml +48 -0
  102. data/test/responses/open_saml_response.xml +56 -0
  103. data/test/responses/response_assertion_wrapped.xml.base64 +93 -0
  104. data/test/responses/response_encrypted_nameid.xml.base64 +1 -0
  105. data/test/responses/response_eval.xml +7 -0
  106. data/test/responses/response_no_cert_and_encrypted_attrs.xml +29 -0
  107. data/test/responses/response_unsigned_xml_base64 +1 -0
  108. data/test/responses/response_with_ampersands.xml +139 -0
  109. data/test/responses/response_with_ampersands.xml.base64 +93 -0
  110. data/test/responses/response_with_multiple_attribute_values.xml +67 -0
  111. data/test/responses/response_with_saml2_namespace.xml.base64 +102 -0
  112. data/test/responses/response_with_signed_assertion.xml.base64 +66 -0
  113. data/test/responses/response_with_signed_assertion_2.xml.base64 +1 -0
  114. data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
  115. data/test/responses/response_without_attributes.xml.base64 +79 -0
  116. data/test/responses/response_wrapped.xml.base64 +150 -0
  117. data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +1 -0
  118. data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +1 -0
  119. data/test/responses/simple_saml_php.xml +71 -0
  120. data/test/responses/starfield_response.xml.base64 +1 -0
  121. data/test/responses/test_sign.xml +43 -0
  122. data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +1 -0
  123. data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +1 -0
  124. data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +1 -0
  125. data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +1 -0
  126. data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +1 -0
  127. data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +1 -0
  128. data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +1 -0
  129. data/test/responses/valid_response.xml.base64 +1 -0
  130. data/test/saml_message_test.rb +56 -0
  131. data/test/settings_test.rb +218 -0
  132. data/test/slo_logoutrequest_test.rb +275 -0
  133. data/test/slo_logoutresponse_test.rb +185 -0
  134. data/test/test_helper.rb +252 -0
  135. data/test/utils_test.rb +145 -0
  136. data/test/xml_security_test.rb +329 -0
  137. metadata +415 -0
@@ -0,0 +1,136 @@
1
+ require "uuid"
2
+
3
+ require "onelogin/ruby-saml/logging"
4
+ require "onelogin/ruby-saml/saml_message"
5
+
6
+ # Only supports SAML 2.0
7
+ module OneLogin
8
+ module RubySaml
9
+
10
+ # SAML2 Logout Response (SLO SP initiated, Parser)
11
+ #
12
+ class SloLogoutresponse < SamlMessage
13
+
14
+ # Logout Response ID
15
+ attr_reader :uuid
16
+
17
+ # Initializes the Logout Response. A SloLogoutresponse Object that is an extension of the SamlMessage class.
18
+ # Asigns an ID, a random uuid.
19
+ #
20
+ def initialize
21
+ @uuid = "_" + UUID.new.generate
22
+ end
23
+
24
+ # Creates the Logout Response string.
25
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
26
+ # @param request_id [String] The ID of the LogoutRequest sent by this SP to the IdP. That ID will be placed as the InResponseTo in the logout response
27
+ # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
28
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
29
+ # @return [String] Logout Request string that includes the SAMLRequest
30
+ #
31
+ def create(settings, request_id = nil, logout_message = nil, params = {})
32
+ params = create_params(settings, request_id, logout_message, params)
33
+ params_prefix = (settings.idp_slo_target_url =~ /\?/) ? '&' : '?'
34
+ saml_response = CGI.escape(params.delete("SAMLResponse"))
35
+ response_params = "#{params_prefix}SAMLResponse=#{saml_response}"
36
+ params.each_pair do |key, value|
37
+ response_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
38
+ end
39
+
40
+ @logout_url = settings.idp_slo_target_url + response_params
41
+ end
42
+
43
+ # Creates the Get parameters for the logout response.
44
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
45
+ # @param request_id [String] The ID of the LogoutRequest sent by this SP to the IdP. That ID will be placed as the InResponseTo in the logout response
46
+ # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
47
+ # @param params [Hash] Some extra parameters to be added in the GET for example the RelayState
48
+ # @return [Hash] Parameters
49
+ #
50
+ def create_params(settings, request_id = nil, logout_message = nil, params = {})
51
+ # The method expects :RelayState but sometimes we get 'RelayState' instead.
52
+ # Based on the HashWithIndifferentAccess value in Rails we could experience
53
+ # conflicts so this line will solve them.
54
+ relay_state = params[:RelayState] || params['RelayState']
55
+
56
+ response_doc = create_logout_response_xml_doc(settings, request_id, logout_message)
57
+ response_doc.context[:attribute_quote] = :quote if settings.double_quote_xml_attribute_values
58
+
59
+ response = ""
60
+ response_doc.write(response)
61
+
62
+ Logging.debug "Created SLO Logout Response: #{response}"
63
+
64
+ response = deflate(response) if settings.compress_response
65
+ base64_response = encode(response)
66
+ response_params = {"SAMLResponse" => base64_response}
67
+
68
+ if settings.security[:logout_responses_signed] && !settings.security[:embed_sign] && settings.private_key
69
+ params['SigAlg'] = settings.security[:signature_method]
70
+ url_string = OneLogin::RubySaml::Utils.build_query(
71
+ :type => 'SAMLResponse',
72
+ :data => base64_response,
73
+ :relay_state => relay_state,
74
+ :sig_alg => params['SigAlg']
75
+ )
76
+ sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
77
+ signature = settings.get_sp_key.sign(sign_algorithm.new, url_string)
78
+ params['Signature'] = encode(signature)
79
+ end
80
+
81
+ params.each_pair do |key, value|
82
+ response_params[key] = value.to_s
83
+ end
84
+
85
+ response_params
86
+ end
87
+
88
+ # Creates the SAMLResponse String.
89
+ # @param settings [OneLogin::RubySaml::Settings|nil] Toolkit settings
90
+ # @param request_id [String] The ID of the LogoutRequest sent by this SP to the IdP. That ID will be placed as the InResponseTo in the logout response
91
+ # @param logout_message [String] The Message to be placed as StatusMessage in the logout response
92
+ # @return [String] The SAMLResponse String.
93
+ #
94
+ def create_logout_response_xml_doc(settings, request_id = nil, logout_message = nil)
95
+ time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
96
+
97
+ response_doc = XMLSecurity::Document.new
98
+ response_doc.uuid = uuid
99
+
100
+ root = response_doc.add_element 'samlp:LogoutResponse', { 'xmlns:samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol', "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion" }
101
+ root.attributes['ID'] = uuid
102
+ root.attributes['IssueInstant'] = time
103
+ root.attributes['Version'] = '2.0'
104
+ root.attributes['InResponseTo'] = request_id unless request_id.nil?
105
+ root.attributes['Destination'] = settings.idp_slo_target_url unless settings.idp_slo_target_url.nil?
106
+
107
+ if settings.issuer != nil
108
+ issuer = root.add_element "saml:Issuer"
109
+ issuer.text = settings.issuer
110
+ end
111
+
112
+ # add success message
113
+ status = root.add_element 'samlp:Status'
114
+
115
+ # success status code
116
+ status_code = status.add_element 'samlp:StatusCode'
117
+ status_code.attributes['Value'] = 'urn:oasis:names:tc:SAML:2.0:status:Success'
118
+
119
+ # success status message
120
+ logout_message ||= 'Successfully Signed Out'
121
+ status_message = status.add_element 'samlp:StatusMessage'
122
+ status_message.text = logout_message
123
+
124
+ # embed signature
125
+ if settings.security[:logout_responses_signed] && settings.private_key && settings.certificate && settings.security[:embed_sign]
126
+ private_key = settings.get_sp_key
127
+ cert = settings.get_sp_cert
128
+ response_doc.sign_document(private_key, cert, settings.security[:signature_method], settings.security[:digest_method])
129
+ end
130
+
131
+ response_doc
132
+ end
133
+
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,172 @@
1
+ module OneLogin
2
+ module RubySaml
3
+
4
+ # SAML2 Auxiliary class
5
+ #
6
+ class Utils
7
+
8
+ DSIG = "http://www.w3.org/2000/09/xmldsig#"
9
+ XENC = "http://www.w3.org/2001/04/xmlenc#"
10
+
11
+ # Return a properly formatted x509 certificate
12
+ #
13
+ # @param cert [String] The original certificate
14
+ # @return [String] The formatted certificate
15
+ #
16
+ def self.format_cert(cert)
17
+ # don't try to format an encoded certificate or if is empty or nil
18
+ return cert if cert.nil? || cert.empty? || cert.match(/\x0d/)
19
+
20
+ cert = cert.gsub(/\-{5}\s?(BEGIN|END) CERTIFICATE\s?\-{5}/, "")
21
+ cert = cert.gsub(/[\n\r\s]/, "")
22
+ cert = cert.scan(/.{1,64}/)
23
+ cert = cert.join("\n")
24
+ "-----BEGIN CERTIFICATE-----\n#{cert}\n-----END CERTIFICATE-----"
25
+ end
26
+
27
+ # Return a properly formatted private key
28
+ #
29
+ # @param key [String] The original private key
30
+ # @return [String] The formatted private key
31
+ #
32
+ def self.format_private_key(key)
33
+ # don't try to format an encoded private key or if is empty
34
+ return key if key.nil? || key.empty? || key.match(/\x0d/)
35
+
36
+ # is this an rsa key?
37
+ rsa_key = key.match("RSA PRIVATE KEY")
38
+ key = key.gsub(/\-{5}\s?(BEGIN|END)( RSA)? PRIVATE KEY\s?\-{5}/, "")
39
+ key = key.gsub(/[\n\r\s]/, "")
40
+ key = key.scan(/.{1,64}/)
41
+ key = key.join("\n")
42
+ key_label = rsa_key ? "RSA PRIVATE KEY" : "PRIVATE KEY"
43
+ "-----BEGIN #{key_label}-----\n#{key}\n-----END #{key_label}-----"
44
+ end
45
+
46
+ # Build the Query String signature that will be used in the HTTP-Redirect binding
47
+ # to generate the Signature
48
+ # @param params [Hash] Parameters to build the Query String
49
+ # @option params [String] :type 'SAMLRequest' or 'SAMLResponse'
50
+ # @option params [String] :data Base64 encoded SAMLRequest or SAMLResponse
51
+ # @option params [String] :relay_state The RelayState parameter
52
+ # @option params [String] :sig_alg The SigAlg parameter
53
+ # @return [String] The Query String
54
+ #
55
+ def self.build_query(params)
56
+ type, data, relay_state, sig_alg = [:type, :data, :relay_state, :sig_alg].map { |k| params[k]}
57
+
58
+ url_string = "#{type}=#{CGI.escape(data)}"
59
+ url_string << "&RelayState=#{CGI.escape(relay_state)}" if relay_state
60
+ url_string << "&SigAlg=#{CGI.escape(sig_alg)}"
61
+ end
62
+
63
+ # Validate the Signature parameter sent on the HTTP-Redirect binding
64
+ # @param params [Hash] Parameters to be used in the validation process
65
+ # @option params [OpenSSL::X509::Certificate] cert The Identity provider public certtificate
66
+ # @option params [String] sig_alg The SigAlg parameter
67
+ # @option params [String] signature The Signature parameter (base64 encoded)
68
+ # @option params [String] query_string The SigAlg parameter
69
+ # @return [Boolean] True if the Signature is valid, False otherwise
70
+ #
71
+ def self.verify_signature(params)
72
+ cert, sig_alg, signature, query_string = [:cert, :sig_alg, :signature, :query_string].map { |k| params[k]}
73
+ signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(sig_alg)
74
+ return cert.public_key.verify(signature_algorithm.new, Base64.decode64(signature), query_string)
75
+ end
76
+
77
+ # Build the status error message
78
+ # @param status_code [String] StatusCode value
79
+ # @param status_message [Strig] StatusMessage value
80
+ # @return [String] The status error message
81
+ def self.status_error_msg(error_msg, status_code = nil, status_message = nil)
82
+ unless status_code.nil?
83
+ printable_code = status_code.split(':').last
84
+ error_msg << ', was ' + printable_code
85
+ end
86
+
87
+ unless status_message.nil?
88
+ error_msg << ' -> ' + status_message
89
+ end
90
+
91
+ error_msg
92
+ end
93
+
94
+ # Obtains the decrypted string from an Encrypted node element in XML
95
+ # @param encrypted_node [REXML::Element] The Encrypted element
96
+ # @param private_key [OpenSSL::PKey::RSA] The Service provider private key
97
+ # @return [String] The decrypted data
98
+ def self.decrypt_data(encrypted_node, private_key)
99
+ encrypt_data = REXML::XPath.first(
100
+ encrypted_node,
101
+ "./xenc:EncryptedData",
102
+ { 'xenc' => XENC }
103
+ )
104
+ symmetric_key = retrieve_symmetric_key(encrypt_data, private_key)
105
+ cipher_value = REXML::XPath.first(
106
+ encrypt_data,
107
+ "//xenc:EncryptedData/xenc:CipherData/xenc:CipherValue",
108
+ { 'xenc' => XENC }
109
+ )
110
+ node = Base64.decode64(cipher_value.text)
111
+ encrypt_method = REXML::XPath.first(
112
+ encrypt_data,
113
+ "//xenc:EncryptedData/xenc:EncryptionMethod",
114
+ { 'xenc' => XENC }
115
+ )
116
+ algorithm = encrypt_method.attributes['Algorithm']
117
+ retrieve_plaintext(node, symmetric_key, algorithm)
118
+ end
119
+
120
+ # Obtains the symmetric key from the EncryptedData element
121
+ # @param encrypt_data [REXML::Element] The EncryptedData element
122
+ # @param private_key [OpenSSL::PKey::RSA] The Service provider private key
123
+ # @return [String] The symmetric key
124
+ def self.retrieve_symmetric_key(encrypt_data, private_key)
125
+ encrypted_symmetric_key_element = REXML::XPath.first(
126
+ encrypt_data,
127
+ "//xenc:EncryptedData/ds:KeyInfo/xenc:EncryptedKey/xenc:CipherData/xenc:CipherValue",
128
+ { "ds" => DSIG, "xenc" => XENC }
129
+ )
130
+ cipher_text = Base64.decode64(encrypted_symmetric_key_element.text)
131
+ encrypt_method = REXML::XPath.first(
132
+ encrypt_data,
133
+ "//xenc:EncryptedData/ds:KeyInfo/xenc:EncryptedKey/xenc:EncryptionMethod",
134
+ {"ds" => DSIG, "xenc" => XENC }
135
+ )
136
+ algorithm = encrypt_method.attributes['Algorithm']
137
+ retrieve_plaintext(cipher_text, private_key, algorithm)
138
+ end
139
+
140
+ # Obtains the deciphered text
141
+ # @param cipher_text [String] The ciphered text
142
+ # @param symmetric_key [String] The symetric key used to encrypt the text
143
+ # @param algorithm [String] The encrypted algorithm
144
+ # @return [String] The deciphered text
145
+ def self.retrieve_plaintext(cipher_text, symmetric_key, algorithm)
146
+ case algorithm
147
+ when 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc' then cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').decrypt
148
+ when 'http://www.w3.org/2001/04/xmlenc#aes128-cbc' then cipher = OpenSSL::Cipher.new('AES-128-CBC').decrypt
149
+ when 'http://www.w3.org/2001/04/xmlenc#aes192-cbc' then cipher = OpenSSL::Cipher.new('AES-192-CBC').decrypt
150
+ when 'http://www.w3.org/2001/04/xmlenc#aes256-cbc' then cipher = OpenSSL::Cipher.new('AES-256-CBC').decrypt
151
+ when 'http://www.w3.org/2001/04/xmlenc#rsa-1_5' then rsa = symmetric_key
152
+ when 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p' then oaep = symmetric_key
153
+ end
154
+
155
+ if cipher
156
+ iv_len = cipher.iv_len
157
+ data = cipher_text[iv_len..-1]
158
+ cipher.padding, cipher.key, cipher.iv = 0, symmetric_key, cipher_text[0..iv_len-1]
159
+ assertion_plaintext = cipher.update(data)
160
+ assertion_plaintext << cipher.final
161
+ elsif rsa
162
+ rsa.private_decrypt(cipher_text)
163
+ elsif oaep
164
+ oaep.private_decrypt(cipher_text, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
165
+ else
166
+ cipher_text
167
+ end
168
+ end
169
+
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,7 @@
1
+ module OneLogin
2
+ module RubySaml
3
+ class ValidationError < StandardError
4
+ end
5
+ end
6
+ end
7
+
@@ -0,0 +1,5 @@
1
+ module OneLogin
2
+ module RubySaml
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
data/lib/ruby-saml.rb ADDED
@@ -0,0 +1 @@
1
+ require 'onelogin/ruby-saml'
@@ -0,0 +1,283 @@
1
+ <?xml version="1.0" encoding="US-ASCII"?>
2
+ <schema
3
+ targetNamespace="urn:oasis:names:tc:SAML:2.0:assertion"
4
+ xmlns="http://www.w3.org/2001/XMLSchema"
5
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
6
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
7
+ xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"
8
+ elementFormDefault="unqualified"
9
+ attributeFormDefault="unqualified"
10
+ blockDefault="substitution"
11
+ version="2.0">
12
+ <import namespace="http://www.w3.org/2000/09/xmldsig#"
13
+ schemaLocation="xmldsig-core-schema.xsd"/>
14
+ <import namespace="http://www.w3.org/2001/04/xmlenc#"
15
+ schemaLocation="xenc-schema.xsd"/>
16
+ <annotation>
17
+ <documentation>
18
+ Document identifier: saml-schema-assertion-2.0
19
+ Location: http://docs.oasis-open.org/security/saml/v2.0/
20
+ Revision history:
21
+ V1.0 (November, 2002):
22
+ Initial Standard Schema.
23
+ V1.1 (September, 2003):
24
+ Updates within the same V1.0 namespace.
25
+ V2.0 (March, 2005):
26
+ New assertion schema for SAML V2.0 namespace.
27
+ </documentation>
28
+ </annotation>
29
+ <attributeGroup name="IDNameQualifiers">
30
+ <attribute name="NameQualifier" type="string" use="optional"/>
31
+ <attribute name="SPNameQualifier" type="string" use="optional"/>
32
+ </attributeGroup>
33
+ <element name="BaseID" type="saml:BaseIDAbstractType"/>
34
+ <complexType name="BaseIDAbstractType" abstract="true">
35
+ <attributeGroup ref="saml:IDNameQualifiers"/>
36
+ </complexType>
37
+ <element name="NameID" type="saml:NameIDType"/>
38
+ <complexType name="NameIDType">
39
+ <simpleContent>
40
+ <extension base="string">
41
+ <attributeGroup ref="saml:IDNameQualifiers"/>
42
+ <attribute name="Format" type="anyURI" use="optional"/>
43
+ <attribute name="SPProvidedID" type="string" use="optional"/>
44
+ </extension>
45
+ </simpleContent>
46
+ </complexType>
47
+ <complexType name="EncryptedElementType">
48
+ <sequence>
49
+ <element ref="xenc:EncryptedData"/>
50
+ <element ref="xenc:EncryptedKey" minOccurs="0" maxOccurs="unbounded"/>
51
+ </sequence>
52
+ </complexType>
53
+ <element name="EncryptedID" type="saml:EncryptedElementType"/>
54
+ <element name="Issuer" type="saml:NameIDType"/>
55
+ <element name="AssertionIDRef" type="NCName"/>
56
+ <element name="AssertionURIRef" type="anyURI"/>
57
+ <element name="Assertion" type="saml:AssertionType"/>
58
+ <complexType name="AssertionType">
59
+ <sequence>
60
+ <element ref="saml:Issuer"/>
61
+ <element ref="ds:Signature" minOccurs="0"/>
62
+ <element ref="saml:Subject" minOccurs="0"/>
63
+ <element ref="saml:Conditions" minOccurs="0"/>
64
+ <element ref="saml:Advice" minOccurs="0"/>
65
+ <choice minOccurs="0" maxOccurs="unbounded">
66
+ <element ref="saml:Statement"/>
67
+ <element ref="saml:AuthnStatement"/>
68
+ <element ref="saml:AuthzDecisionStatement"/>
69
+ <element ref="saml:AttributeStatement"/>
70
+ </choice>
71
+ </sequence>
72
+ <attribute name="Version" type="string" use="required"/>
73
+ <attribute name="ID" type="ID" use="required"/>
74
+ <attribute name="IssueInstant" type="dateTime" use="required"/>
75
+ </complexType>
76
+ <element name="Subject" type="saml:SubjectType"/>
77
+ <complexType name="SubjectType">
78
+ <choice>
79
+ <sequence>
80
+ <choice>
81
+ <element ref="saml:BaseID"/>
82
+ <element ref="saml:NameID"/>
83
+ <element ref="saml:EncryptedID"/>
84
+ </choice>
85
+ <element ref="saml:SubjectConfirmation" minOccurs="0" maxOccurs="unbounded"/>
86
+ </sequence>
87
+ <element ref="saml:SubjectConfirmation" maxOccurs="unbounded"/>
88
+ </choice>
89
+ </complexType>
90
+ <element name="SubjectConfirmation" type="saml:SubjectConfirmationType"/>
91
+ <complexType name="SubjectConfirmationType">
92
+ <sequence>
93
+ <choice minOccurs="0">
94
+ <element ref="saml:BaseID"/>
95
+ <element ref="saml:NameID"/>
96
+ <element ref="saml:EncryptedID"/>
97
+ </choice>
98
+ <element ref="saml:SubjectConfirmationData" minOccurs="0"/>
99
+ </sequence>
100
+ <attribute name="Method" type="anyURI" use="required"/>
101
+ </complexType>
102
+ <element name="SubjectConfirmationData" type="saml:SubjectConfirmationDataType"/>
103
+ <complexType name="SubjectConfirmationDataType" mixed="true">
104
+ <complexContent>
105
+ <restriction base="anyType">
106
+ <sequence>
107
+ <any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
108
+ </sequence>
109
+ <attribute name="NotBefore" type="dateTime" use="optional"/>
110
+ <attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
111
+ <attribute name="Recipient" type="anyURI" use="optional"/>
112
+ <attribute name="InResponseTo" type="NCName" use="optional"/>
113
+ <attribute name="Address" type="string" use="optional"/>
114
+ <anyAttribute namespace="##other" processContents="lax"/>
115
+ </restriction>
116
+ </complexContent>
117
+ </complexType>
118
+ <complexType name="KeyInfoConfirmationDataType" mixed="false">
119
+ <complexContent>
120
+ <restriction base="saml:SubjectConfirmationDataType">
121
+ <sequence>
122
+ <element ref="ds:KeyInfo" maxOccurs="unbounded"/>
123
+ </sequence>
124
+ </restriction>
125
+ </complexContent>
126
+ </complexType>
127
+ <element name="Conditions" type="saml:ConditionsType"/>
128
+ <complexType name="ConditionsType">
129
+ <choice minOccurs="0" maxOccurs="unbounded">
130
+ <element ref="saml:Condition"/>
131
+ <element ref="saml:AudienceRestriction"/>
132
+ <element ref="saml:OneTimeUse"/>
133
+ <element ref="saml:ProxyRestriction"/>
134
+ </choice>
135
+ <attribute name="NotBefore" type="dateTime" use="optional"/>
136
+ <attribute name="NotOnOrAfter" type="dateTime" use="optional"/>
137
+ </complexType>
138
+ <element name="Condition" type="saml:ConditionAbstractType"/>
139
+ <complexType name="ConditionAbstractType" abstract="true"/>
140
+ <element name="AudienceRestriction" type="saml:AudienceRestrictionType"/>
141
+ <complexType name="AudienceRestrictionType">
142
+ <complexContent>
143
+ <extension base="saml:ConditionAbstractType">
144
+ <sequence>
145
+ <element ref="saml:Audience" maxOccurs="unbounded"/>
146
+ </sequence>
147
+ </extension>
148
+ </complexContent>
149
+ </complexType>
150
+ <element name="Audience" type="anyURI"/>
151
+ <element name="OneTimeUse" type="saml:OneTimeUseType" />
152
+ <complexType name="OneTimeUseType">
153
+ <complexContent>
154
+ <extension base="saml:ConditionAbstractType"/>
155
+ </complexContent>
156
+ </complexType>
157
+ <element name="ProxyRestriction" type="saml:ProxyRestrictionType"/>
158
+ <complexType name="ProxyRestrictionType">
159
+ <complexContent>
160
+ <extension base="saml:ConditionAbstractType">
161
+ <sequence>
162
+ <element ref="saml:Audience" minOccurs="0" maxOccurs="unbounded"/>
163
+ </sequence>
164
+ <attribute name="Count" type="nonNegativeInteger" use="optional"/>
165
+ </extension>
166
+ </complexContent>
167
+ </complexType>
168
+ <element name="Advice" type="saml:AdviceType"/>
169
+ <complexType name="AdviceType">
170
+ <choice minOccurs="0" maxOccurs="unbounded">
171
+ <element ref="saml:AssertionIDRef"/>
172
+ <element ref="saml:AssertionURIRef"/>
173
+ <element ref="saml:Assertion"/>
174
+ <element ref="saml:EncryptedAssertion"/>
175
+ <any namespace="##other" processContents="lax"/>
176
+ </choice>
177
+ </complexType>
178
+ <element name="EncryptedAssertion" type="saml:EncryptedElementType"/>
179
+ <element name="Statement" type="saml:StatementAbstractType"/>
180
+ <complexType name="StatementAbstractType" abstract="true"/>
181
+ <element name="AuthnStatement" type="saml:AuthnStatementType"/>
182
+ <complexType name="AuthnStatementType">
183
+ <complexContent>
184
+ <extension base="saml:StatementAbstractType">
185
+ <sequence>
186
+ <element ref="saml:SubjectLocality" minOccurs="0"/>
187
+ <element ref="saml:AuthnContext"/>
188
+ </sequence>
189
+ <attribute name="AuthnInstant" type="dateTime" use="required"/>
190
+ <attribute name="SessionIndex" type="string" use="optional"/>
191
+ <attribute name="SessionNotOnOrAfter" type="dateTime" use="optional"/>
192
+ </extension>
193
+ </complexContent>
194
+ </complexType>
195
+ <element name="SubjectLocality" type="saml:SubjectLocalityType"/>
196
+ <complexType name="SubjectLocalityType">
197
+ <attribute name="Address" type="string" use="optional"/>
198
+ <attribute name="DNSName" type="string" use="optional"/>
199
+ </complexType>
200
+ <element name="AuthnContext" type="saml:AuthnContextType"/>
201
+ <complexType name="AuthnContextType">
202
+ <sequence>
203
+ <choice>
204
+ <sequence>
205
+ <element ref="saml:AuthnContextClassRef"/>
206
+ <choice minOccurs="0">
207
+ <element ref="saml:AuthnContextDecl"/>
208
+ <element ref="saml:AuthnContextDeclRef"/>
209
+ </choice>
210
+ </sequence>
211
+ <choice>
212
+ <element ref="saml:AuthnContextDecl"/>
213
+ <element ref="saml:AuthnContextDeclRef"/>
214
+ </choice>
215
+ </choice>
216
+ <element ref="saml:AuthenticatingAuthority" minOccurs="0" maxOccurs="unbounded"/>
217
+ </sequence>
218
+ </complexType>
219
+ <element name="AuthnContextClassRef" type="anyURI"/>
220
+ <element name="AuthnContextDeclRef" type="anyURI"/>
221
+ <element name="AuthnContextDecl" type="anyType"/>
222
+ <element name="AuthenticatingAuthority" type="anyURI"/>
223
+ <element name="AuthzDecisionStatement" type="saml:AuthzDecisionStatementType"/>
224
+ <complexType name="AuthzDecisionStatementType">
225
+ <complexContent>
226
+ <extension base="saml:StatementAbstractType">
227
+ <sequence>
228
+ <element ref="saml:Action" maxOccurs="unbounded"/>
229
+ <element ref="saml:Evidence" minOccurs="0"/>
230
+ </sequence>
231
+ <attribute name="Resource" type="anyURI" use="required"/>
232
+ <attribute name="Decision" type="saml:DecisionType" use="required"/>
233
+ </extension>
234
+ </complexContent>
235
+ </complexType>
236
+ <simpleType name="DecisionType">
237
+ <restriction base="string">
238
+ <enumeration value="Permit"/>
239
+ <enumeration value="Deny"/>
240
+ <enumeration value="Indeterminate"/>
241
+ </restriction>
242
+ </simpleType>
243
+ <element name="Action" type="saml:ActionType"/>
244
+ <complexType name="ActionType">
245
+ <simpleContent>
246
+ <extension base="string">
247
+ <attribute name="Namespace" type="anyURI" use="required"/>
248
+ </extension>
249
+ </simpleContent>
250
+ </complexType>
251
+ <element name="Evidence" type="saml:EvidenceType"/>
252
+ <complexType name="EvidenceType">
253
+ <choice maxOccurs="unbounded">
254
+ <element ref="saml:AssertionIDRef"/>
255
+ <element ref="saml:AssertionURIRef"/>
256
+ <element ref="saml:Assertion"/>
257
+ <element ref="saml:EncryptedAssertion"/>
258
+ </choice>
259
+ </complexType>
260
+ <element name="AttributeStatement" type="saml:AttributeStatementType"/>
261
+ <complexType name="AttributeStatementType">
262
+ <complexContent>
263
+ <extension base="saml:StatementAbstractType">
264
+ <choice maxOccurs="unbounded">
265
+ <element ref="saml:Attribute"/>
266
+ <element ref="saml:EncryptedAttribute"/>
267
+ </choice>
268
+ </extension>
269
+ </complexContent>
270
+ </complexType>
271
+ <element name="Attribute" type="saml:AttributeType"/>
272
+ <complexType name="AttributeType">
273
+ <sequence>
274
+ <element ref="saml:AttributeValue" minOccurs="0" maxOccurs="unbounded"/>
275
+ </sequence>
276
+ <attribute name="Name" type="string" use="required"/>
277
+ <attribute name="NameFormat" type="anyURI" use="optional"/>
278
+ <attribute name="FriendlyName" type="string" use="optional"/>
279
+ <anyAttribute namespace="##other" processContents="lax"/>
280
+ </complexType>
281
+ <element name="AttributeValue" type="anyType" nillable="true"/>
282
+ <element name="EncryptedAttribute" type="saml:EncryptedElementType"/>
283
+ </schema>