ruby-saml 0.9.1 → 0.9.2
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.
Potentially problematic release.
This version of ruby-saml might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +10 -0
- data/Gemfile +1 -1
- data/README.md +31 -7
- data/changelog.md +18 -0
- data/gemfiles/nokogiri-1.5.gemfile +5 -0
- data/lib/onelogin/ruby-saml.rb +16 -0
- data/lib/onelogin/ruby-saml/authrequest.rb +10 -5
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +20 -1
- data/lib/onelogin/ruby-saml/logoutrequest.rb +9 -5
- data/lib/onelogin/ruby-saml/logoutresponse.rb +2 -0
- data/lib/onelogin/ruby-saml/metadata.rb +16 -6
- data/lib/onelogin/ruby-saml/response.rb +17 -15
- data/lib/onelogin/ruby-saml/saml_message.rb +44 -30
- data/lib/onelogin/ruby-saml/settings.rb +17 -7
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +2 -0
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +9 -5
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/ruby-saml.rb +1 -16
- data/lib/xml_security.rb +39 -17
- data/ruby-saml.gemspec +5 -6
- data/test/idp_metadata_parser_test.rb +6 -2
- data/test/logoutrequest_test.rb +50 -22
- data/test/logoutresponse_test.rb +2 -1
- data/test/metadata_test.rb +100 -55
- data/test/request_test.rb +49 -24
- data/test/response_test.rb +41 -8
- data/test/responses/test_sign.xml +43 -0
- data/test/settings_test.rb +16 -0
- data/test/slo_logoutrequest_test.rb +2 -0
- data/test/slo_logoutresponse_test.rb +51 -21
- data/test/test_helper.rb +0 -1
- data/test/xml_security_test.rb +41 -4
- metadata +10 -6
    
        data/test/request_test.rb
    CHANGED
    
    | @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'onelogin/ruby-saml/authrequest'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            class RequestTest < Minitest::Test
         | 
| 4 6 |  | 
| 5 7 | 
             
              describe "Authrequest" do
         | 
| @@ -143,7 +145,7 @@ class RequestTest < Minitest::Test | |
| 143 145 | 
             
                  end
         | 
| 144 146 | 
             
                end
         | 
| 145 147 |  | 
| 146 | 
            -
                describe "when the settings indicate to sign (embebed) the request" do
         | 
| 148 | 
            +
                describe "#create_params when the settings indicate to sign (embebed) the request" do
         | 
| 147 149 | 
             
                  it "create a signed request" do
         | 
| 148 150 | 
             
                    settings = OneLogin::RubySaml::Settings.new
         | 
| 149 151 | 
             
                    settings.compress_request = false
         | 
| @@ -156,8 +158,8 @@ class RequestTest < Minitest::Test | |
| 156 158 | 
             
                    params = OneLogin::RubySaml::Authrequest.new.create_params(settings)
         | 
| 157 159 | 
             
                    request_xml = Base64.decode64(params["SAMLRequest"])
         | 
| 158 160 | 
             
                    assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
         | 
| 159 | 
            -
                     | 
| 160 | 
            -
                     | 
| 161 | 
            +
                    assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], request_xml
         | 
| 162 | 
            +
                    assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], request_xml
         | 
| 161 163 | 
             
                  end
         | 
| 162 164 |  | 
| 163 165 | 
             
                  it "create a signed request with 256 digest and signature methods" do
         | 
| @@ -166,7 +168,7 @@ class RequestTest < Minitest::Test | |
| 166 168 | 
             
                    settings.idp_sso_target_url = "http://example.com?field=value"
         | 
| 167 169 | 
             
                    settings.security[:authn_requests_signed] = true
         | 
| 168 170 | 
             
                    settings.security[:embed_sign] = true
         | 
| 169 | 
            -
                    settings.security[:signature_method] = XMLSecurity::Document:: | 
| 171 | 
            +
                    settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
         | 
| 170 172 | 
             
                    settings.security[:digest_method] = XMLSecurity::Document::SHA512
         | 
| 171 173 | 
             
                    settings.certificate  = ruby_saml_cert_text
         | 
| 172 174 | 
             
                    settings.private_key = ruby_saml_key_text
         | 
| @@ -174,33 +176,56 @@ class RequestTest < Minitest::Test | |
| 174 176 | 
             
                    params = OneLogin::RubySaml::Authrequest.new.create_params(settings)
         | 
| 175 177 | 
             
                    request_xml = Base64.decode64(params["SAMLRequest"])
         | 
| 176 178 | 
             
                    assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
         | 
| 177 | 
            -
                     | 
| 178 | 
            -
                     | 
| 179 | 
            +
                    assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'/>], request_xml
         | 
| 180 | 
            +
                    assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#sha512'/>], request_xml
         | 
| 179 181 | 
             
                  end
         | 
| 180 182 | 
             
                end
         | 
| 181 183 |  | 
| 184 | 
            +
                describe "#create_params when the settings indicate to sign the request" do
         | 
| 185 | 
            +
                  def setup
         | 
| 186 | 
            +
                    @settings = OneLogin::RubySaml::Settings.new
         | 
| 187 | 
            +
                    @settings.compress_request = false
         | 
| 188 | 
            +
                    @settings.idp_sso_target_url = "http://example.com?field=value"
         | 
| 189 | 
            +
                    @settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
         | 
| 190 | 
            +
                    @settings.security[:authn_requests_signed] = true
         | 
| 191 | 
            +
                    @settings.security[:embed_sign] = false
         | 
| 192 | 
            +
                    @settings.certificate  = ruby_saml_cert_text
         | 
| 193 | 
            +
                    @settings.private_key = ruby_saml_key_text
         | 
| 194 | 
            +
                    @cert = OpenSSL::X509::Certificate.new(ruby_saml_cert_text)
         | 
| 195 | 
            +
                  end
         | 
| 196 | 
            +
                  
         | 
| 197 | 
            +
                  it "create a signature parameter with RSA_SHA1 and validate it" do
         | 
| 198 | 
            +
                    @settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
         | 
| 182 199 |  | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 185 | 
            -
                     | 
| 186 | 
            -
                    settings.compress_request = false
         | 
| 187 | 
            -
                    settings.idp_sso_target_url = "http://example.com?field=value"
         | 
| 188 | 
            -
                    settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
         | 
| 189 | 
            -
                    settings.security[:authn_requests_signed] = true
         | 
| 190 | 
            -
                    settings.security[:embed_sign] = false
         | 
| 191 | 
            -
                    settings.security[:signature_method] = XMLSecurity::Document::SHA1
         | 
| 192 | 
            -
                    settings.certificate  = ruby_saml_cert_text
         | 
| 193 | 
            -
                    settings.private_key = ruby_saml_key_text
         | 
| 194 | 
            -
             | 
| 195 | 
            -
                    params = OneLogin::RubySaml::Authrequest.new.create_params(settings)
         | 
| 200 | 
            +
                    params = OneLogin::RubySaml::Authrequest.new.create_params(@settings, :RelayState => 'http://example.com')
         | 
| 201 | 
            +
                    assert params['SAMLRequest']
         | 
| 202 | 
            +
                    assert params[:RelayState]
         | 
| 196 203 | 
             
                    assert params['Signature']
         | 
| 197 | 
            -
                     | 
| 204 | 
            +
                    assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1
         | 
| 198 205 |  | 
| 199 | 
            -
                     | 
| 200 | 
            -
                     | 
| 201 | 
            -
                     | 
| 206 | 
            +
                    query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
         | 
| 207 | 
            +
                    query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
         | 
| 208 | 
            +
                    query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                    signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
         | 
| 211 | 
            +
                    assert_equal signature_algorithm, OpenSSL::Digest::SHA1
         | 
| 212 | 
            +
                    assert @cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
         | 
| 213 | 
            +
                  end
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                  it "create a signature parameter with RSA_SHA256 and validate it" do
         | 
| 216 | 
            +
                    @settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
         | 
| 217 | 
            +
             | 
| 218 | 
            +
                    params = OneLogin::RubySaml::Authrequest.new.create_params(@settings, :RelayState => 'http://example.com')
         | 
| 202 219 | 
             
                    assert params['Signature']
         | 
| 203 | 
            -
                     | 
| 220 | 
            +
                    assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA256
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                    query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
         | 
| 223 | 
            +
                    query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
         | 
| 224 | 
            +
                    query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                    signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
         | 
| 227 | 
            +
                    assert_equal signature_algorithm, OpenSSL::Digest::SHA256
         | 
| 228 | 
            +
                    assert @cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)        
         | 
| 204 229 | 
             
                  end
         | 
| 205 230 | 
             
                end
         | 
| 206 231 |  | 
    
        data/test/response_test.rb
    CHANGED
    
    | @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'onelogin/ruby-saml/response'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            class RubySamlTest < Minitest::Test
         | 
| 4 6 |  | 
| 5 7 | 
             
              describe "Response" do
         | 
| @@ -119,7 +121,7 @@ class RubySamlTest < Minitest::Test | |
| 119 121 | 
             
                    settings.idp_cert_fingerprint = signature_fingerprint_1
         | 
| 120 122 | 
             
                    response.settings = settings
         | 
| 121 123 | 
             
                    assert response.is_valid?
         | 
| 122 | 
            -
                     | 
| 124 | 
            +
                    assert_equal response.name_id, "test@onelogin.com"
         | 
| 123 125 | 
             
                  end
         | 
| 124 126 |  | 
| 125 127 | 
             
                  it "support dynamic namespace resolution on signature elements" do
         | 
| @@ -193,15 +195,23 @@ class RubySamlTest < Minitest::Test | |
| 193 195 | 
             
                    assert response.send(:validate_conditions, true)
         | 
| 194 196 | 
             
                  end
         | 
| 195 197 |  | 
| 196 | 
            -
                  it "optionally  | 
| 198 | 
            +
                  it "optionally allows for clock drift" do
         | 
| 197 199 | 
             
                    # The NotBefore condition in the document is 2011-06-14T18:21:01.516Z
         | 
| 198 | 
            -
                     | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 200 | 
            +
                    Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
         | 
| 201 | 
            +
                      response = OneLogin::RubySaml::Response.new(
         | 
| 202 | 
            +
                        response_document_5,
         | 
| 203 | 
            +
                        :allowed_clock_drift => 0.515
         | 
| 204 | 
            +
                      )
         | 
| 205 | 
            +
                      assert !response.send(:validate_conditions, true)
         | 
| 206 | 
            +
                    end
         | 
| 201 207 |  | 
| 202 | 
            -
                     | 
| 203 | 
            -
             | 
| 204 | 
            -
             | 
| 208 | 
            +
                    Timecop.freeze(Time.parse("2011-06-14T18:21:01Z")) do
         | 
| 209 | 
            +
                      response = OneLogin::RubySaml::Response.new(
         | 
| 210 | 
            +
                        response_document_5,
         | 
| 211 | 
            +
                        :allowed_clock_drift => 0.516
         | 
| 212 | 
            +
                      )
         | 
| 213 | 
            +
                      assert response.send(:validate_conditions, true)
         | 
| 214 | 
            +
                    end
         | 
| 205 215 | 
             
                  end
         | 
| 206 216 | 
             
                end
         | 
| 207 217 |  | 
| @@ -376,5 +386,28 @@ class RubySamlTest < Minitest::Test | |
| 376 386 | 
             
                    assert_equal($evalled, nil)
         | 
| 377 387 | 
             
                  end
         | 
| 378 388 | 
             
                end
         | 
| 389 | 
            +
             | 
| 390 | 
            +
                describe '#sign_document' do
         | 
| 391 | 
            +
                  it 'Sign an unsigned SAML Response XML and initiate the SAML object with it' do
         | 
| 392 | 
            +
                    xml = Base64.decode64(fixture("test_sign.xml"))
         | 
| 393 | 
            +
             | 
| 394 | 
            +
                    document = XMLSecurity::Document.new(xml)
         | 
| 395 | 
            +
             | 
| 396 | 
            +
                    formated_cert = OneLogin::RubySaml::Utils.format_cert(ruby_saml_cert_text)
         | 
| 397 | 
            +
                    cert = OpenSSL::X509::Certificate.new(formated_cert)
         | 
| 398 | 
            +
             | 
| 399 | 
            +
                    formated_private_key = OneLogin::RubySaml::Utils.format_private_key(ruby_saml_key_text)
         | 
| 400 | 
            +
                    private_key = OpenSSL::PKey::RSA.new(formated_private_key)
         | 
| 401 | 
            +
                    document.sign_document(private_key, cert)
         | 
| 402 | 
            +
             | 
| 403 | 
            +
                    saml_response = OneLogin::RubySaml::Response.new(document.to_s)
         | 
| 404 | 
            +
                    settings = OneLogin::RubySaml::Settings.new
         | 
| 405 | 
            +
                    settings.idp_cert = ruby_saml_cert_text
         | 
| 406 | 
            +
                    saml_response.settings = settings
         | 
| 407 | 
            +
                    time = Time.parse("2015-03-18T04:50:24Z")
         | 
| 408 | 
            +
                    Time.stubs(:now).returns(time)
         | 
| 409 | 
            +
                    saml_response.validate!
         | 
| 410 | 
            +
                  end
         | 
| 411 | 
            +
                end
         | 
| 379 412 | 
             
              end
         | 
| 380 413 | 
             
            end
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            <?xml version='1.0' encoding='UTF-8'?>
         | 
| 2 | 
            +
            <samlp:Response Destination='http://recipient' ID='R6fa6c6bfb42798aa6d2893740f1e8d0fc361ac23' InResponseTo='_36387b60-af58-0132-6be9-6c4008ad82d2' IssueInstant='2015-03-18T04:50:24Z' Version='2.0' xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol'>
         | 
| 3 | 
            +
              <saml:Issuer>https://app.onelogin.com/saml/metadata/433789</saml:Issuer>
         | 
| 4 | 
            +
              <samlp:Status>
         | 
| 5 | 
            +
                <samlp:StatusCode Value='urn:oasis:names:tc:SAML:2.0:status:Success'/>
         | 
| 6 | 
            +
              </samlp:Status>
         | 
| 7 | 
            +
              <saml:Assertion ID='pfxcb6907fc-cd01-59eb-a50f-513689085a71' IssueInstant='2015-03-18T04:50:24Z' Version='2.0' xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
         | 
| 8 | 
            +
                <saml:Issuer>https://app.onelogin.com/saml/metadata/433789</saml:Issuer>
         | 
| 9 | 
            +
                <saml:Subject>
         | 
| 10 | 
            +
                  <saml:NameID Format='urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'>jane.doe@example.com</saml:NameID>
         | 
| 11 | 
            +
                  <saml:SubjectConfirmation Method='urn:oasis:names:tc:SAML:2.0:cm:bearer'>
         | 
| 12 | 
            +
                    <saml:SubjectConfirmationData InResponseTo='_36387b60-af58-0132-6be9-6c4008ad82d2' NotOnOrAfter='2015-03-19T17:57:12Z' Recipient='http://recipient'/>
         | 
| 13 | 
            +
                  </saml:SubjectConfirmation>
         | 
| 14 | 
            +
                </saml:Subject>
         | 
| 15 | 
            +
                <saml:Conditions NotBefore='2015-03-18T04:47:24Z' NotOnOrAfter='2015-03-19T17:57:12Z'>
         | 
| 16 | 
            +
                  <saml:AudienceRestriction>
         | 
| 17 | 
            +
                    <saml:Audience>http://audience</saml:Audience>
         | 
| 18 | 
            +
                  </saml:AudienceRestriction>
         | 
| 19 | 
            +
                </saml:Conditions>
         | 
| 20 | 
            +
                <saml:AuthnStatement AuthnInstant='2015-03-18T04:50:23Z' SessionIndex='_f4610090-af35-0132-899e-38ca3a662f1c' SessionNotOnOrAfter='2015-03-19T04:50:24Z'>
         | 
| 21 | 
            +
                  <saml:AuthnContext>
         | 
| 22 | 
            +
                    <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
         | 
| 23 | 
            +
                  </saml:AuthnContext>
         | 
| 24 | 
            +
                </saml:AuthnStatement>
         | 
| 25 | 
            +
                <saml:AttributeStatement>
         | 
| 26 | 
            +
                  <saml:Attribute Name='User.email' NameFormat='urn:oasis:names:tc:SAML:2.0:attrname-format:basic'>
         | 
| 27 | 
            +
                    <saml:AttributeValue xsi:type='xs:string' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>jane.doe@example.com</saml:AttributeValue>
         | 
| 28 | 
            +
                  </saml:Attribute>
         | 
| 29 | 
            +
                  <saml:Attribute Name='User.FirstName' NameFormat='urn:oasis:names:tc:SAML:2.0:attrname-format:basic'>
         | 
| 30 | 
            +
                    <saml:AttributeValue xsi:type='xs:string' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>Jane</saml:AttributeValue>
         | 
| 31 | 
            +
                  </saml:Attribute>
         | 
| 32 | 
            +
                  <saml:Attribute Name='User.LastName' NameFormat='urn:oasis:names:tc:SAML:2.0:attrname-format:basic'>
         | 
| 33 | 
            +
                    <saml:AttributeValue xsi:type='xs:string' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>Doe</saml:AttributeValue>
         | 
| 34 | 
            +
                  </saml:Attribute>
         | 
| 35 | 
            +
                  <saml:Attribute Name='PersonImmutableID' NameFormat='urn:oasis:names:tc:SAML:2.0:attrname-format:basic'>
         | 
| 36 | 
            +
                    <saml:AttributeValue xsi:type='xs:string' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'/>
         | 
| 37 | 
            +
                  </saml:Attribute>
         | 
| 38 | 
            +
                  <saml:Attribute Name='memberOf' NameFormat='urn:oasis:names:tc:SAML:2.0:attrname-format:basic'>
         | 
| 39 | 
            +
                    <saml:AttributeValue xsi:type='xs:string' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'/>
         | 
| 40 | 
            +
                  </saml:Attribute>
         | 
| 41 | 
            +
                </saml:AttributeStatement>
         | 
| 42 | 
            +
              </saml:Assertion>
         | 
| 43 | 
            +
            </samlp:Response>
         | 
    
        data/test/settings_test.rb
    CHANGED
    
    | @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'onelogin/ruby-saml/settings'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            class SettingsTest < Minitest::Test
         | 
| 4 6 |  | 
| 5 7 | 
             
              describe "Settings" do
         | 
| @@ -61,5 +63,19 @@ class SettingsTest < Minitest::Test | |
| 61 63 | 
             
                  assert_equal @settings.attribute_consuming_service.name, "Test Service"
         | 
| 62 64 | 
             
                  assert_equal @settings.attribute_consuming_service.attributes, [{:name => "Name", :name_format => "Name Format", :friendly_name => "Friendly Name" }]
         | 
| 63 65 | 
             
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                it "does not modify default security settings" do
         | 
| 68 | 
            +
                  settings = OneLogin::RubySaml::Settings.new
         | 
| 69 | 
            +
                  settings.security[:authn_requests_signed] = true
         | 
| 70 | 
            +
                  settings.security[:embed_sign] = true
         | 
| 71 | 
            +
                  settings.security[:digest_method] = XMLSecurity::Document::SHA256
         | 
| 72 | 
            +
                  settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  new_settings = OneLogin::RubySaml::Settings.new
         | 
| 75 | 
            +
                  assert_equal new_settings.security[:authn_requests_signed], false
         | 
| 76 | 
            +
                  assert_equal new_settings.security[:embed_sign], false
         | 
| 77 | 
            +
                  assert_equal new_settings.security[:digest_method], XMLSecurity::Document::SHA1
         | 
| 78 | 
            +
                  assert_equal new_settings.security[:signature_method], XMLSecurity::Document::RSA_SHA1
         | 
| 79 | 
            +
                end
         | 
| 64 80 | 
             
              end
         | 
| 65 81 | 
             
            end
         | 
| @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'onelogin/ruby-saml/slo_logoutresponse'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            class SloLogoutresponseTest < Minitest::Test
         | 
| 4 6 |  | 
| 5 7 | 
             
              describe "SloLogoutresponse" do
         | 
| @@ -65,7 +67,7 @@ class SloLogoutresponseTest < Minitest::Test | |
| 65 67 | 
             
                  assert_match /<samlp:StatusMessage>Custom Logout Message<\/samlp:StatusMessage>/, inflated
         | 
| 66 68 | 
             
                end
         | 
| 67 69 |  | 
| 68 | 
            -
                describe "when the settings indicate to sign ( | 
| 70 | 
            +
                describe "when the settings indicate to sign (embedded) logout response" do
         | 
| 69 71 | 
             
                  it "create a signed logout response" do
         | 
| 70 72 | 
             
                    settings = OneLogin::RubySaml::Settings.new
         | 
| 71 73 | 
             
                    settings.compress_response = false
         | 
| @@ -81,7 +83,7 @@ class SloLogoutresponseTest < Minitest::Test | |
| 81 83 | 
             
                    response_xml = Base64.decode64(params["SAMLResponse"])
         | 
| 82 84 | 
             
                    assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], response_xml
         | 
| 83 85 | 
             
                    response_xml =~ /<ds:SignatureMethod Algorithm='http:\/\/www.w3.org\/2000\/09\/xmldsig#rsa-sha1'\/>/
         | 
| 84 | 
            -
                    response_xml =~ /<ds:DigestMethod Algorithm='http:\/\/www.w3.org\/2000\/09\/xmldsig# | 
| 86 | 
            +
                    response_xml =~ /<ds:DigestMethod Algorithm='http:\/\/www.w3.org\/2000\/09\/xmldsig#sha1'\/>/
         | 
| 85 87 | 
             
                  end
         | 
| 86 88 |  | 
| 87 89 | 
             
                  it "create a signed logout response with 256 digest and signature methods" do
         | 
| @@ -90,7 +92,7 @@ class SloLogoutresponseTest < Minitest::Test | |
| 90 92 | 
             
                    settings.idp_slo_target_url = "http://example.com?field=value"
         | 
| 91 93 | 
             
                    settings.security[:logout_responses_signed] = true
         | 
| 92 94 | 
             
                    settings.security[:embed_sign] = true
         | 
| 93 | 
            -
                    settings.security[:signature_method] = XMLSecurity::Document:: | 
| 95 | 
            +
                    settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
         | 
| 94 96 | 
             
                    settings.security[:digest_method] = XMLSecurity::Document::SHA512
         | 
| 95 97 | 
             
                    settings.certificate  = ruby_saml_cert_text
         | 
| 96 98 | 
             
                    settings.private_key = ruby_saml_key_text
         | 
| @@ -105,29 +107,57 @@ class SloLogoutresponseTest < Minitest::Test | |
| 105 107 | 
             
                  end
         | 
| 106 108 | 
             
                end
         | 
| 107 109 |  | 
| 108 | 
            -
                describe "when the settings indicate to sign the logout response" do
         | 
| 109 | 
            -
                   | 
| 110 | 
            -
                    settings = OneLogin::RubySaml::Settings.new
         | 
| 111 | 
            -
                    settings.compress_response = false
         | 
| 112 | 
            -
                    settings.idp_slo_target_url = "http://example.com?field=value"
         | 
| 113 | 
            -
                    settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
         | 
| 114 | 
            -
                    settings.security[:logout_responses_signed] = true
         | 
| 115 | 
            -
                    settings.security[:embed_sign] = false
         | 
| 116 | 
            -
                    settings. | 
| 117 | 
            -
                    settings. | 
| 118 | 
            -
                     | 
| 110 | 
            +
                describe "#create_params when the settings indicate to sign the logout response" do
         | 
| 111 | 
            +
                  def setup
         | 
| 112 | 
            +
                    @settings = OneLogin::RubySaml::Settings.new
         | 
| 113 | 
            +
                    @settings.compress_response = false
         | 
| 114 | 
            +
                    @settings.idp_slo_target_url = "http://example.com?field=value"
         | 
| 115 | 
            +
                    @settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
         | 
| 116 | 
            +
                    @settings.security[:logout_responses_signed] = true
         | 
| 117 | 
            +
                    @settings.security[:embed_sign] = false
         | 
| 118 | 
            +
                    @settings.certificate  = ruby_saml_cert_text
         | 
| 119 | 
            +
                    @settings.private_key = ruby_saml_key_text
         | 
| 120 | 
            +
                    @cert = OpenSSL::X509::Certificate.new(ruby_saml_cert_text)
         | 
| 121 | 
            +
                    @request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
         | 
| 122 | 
            +
                  end
         | 
| 119 123 |  | 
| 120 | 
            -
             | 
| 121 | 
            -
                     | 
| 124 | 
            +
                  it "create a signature parameter with RSA_SHA1 and validate it" do
         | 
| 125 | 
            +
                    settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                    params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(@settings, @request.id, "Custom Logout Message", :RelayState => 'http://example.com')
         | 
| 128 | 
            +
                    assert params['SAMLResponse']
         | 
| 129 | 
            +
                    assert params[:RelayState]
         | 
| 122 130 | 
             
                    assert params['Signature']
         | 
| 123 | 
            -
                     | 
| 131 | 
            +
                    assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1
         | 
| 124 132 |  | 
| 125 | 
            -
                     | 
| 126 | 
            -
                     | 
| 127 | 
            -
                     | 
| 133 | 
            +
                    query_string = "SAMLResponse=#{CGI.escape(params['SAMLResponse'])}"
         | 
| 134 | 
            +
                    query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
         | 
| 135 | 
            +
                    query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                    signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
         | 
| 138 | 
            +
                    assert_equal signature_algorithm, OpenSSL::Digest::SHA1
         | 
| 139 | 
            +
                    assert @cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                  it "create a signature parameter with RSA_SHA256 and validate it" do
         | 
| 143 | 
            +
                    @settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                    params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(@settings, @request.id, "Custom Logout Message", :RelayState => 'http://example.com')
         | 
| 146 | 
            +
                    assert params['SAMLResponse']
         | 
| 147 | 
            +
                    assert params[:RelayState]
         | 
| 128 148 | 
             
                    assert params['Signature']
         | 
| 129 | 
            -
             | 
| 149 | 
            +
             | 
| 150 | 
            +
                    assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA256
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                    query_string = "SAMLResponse=#{CGI.escape(params['SAMLResponse'])}"
         | 
| 153 | 
            +
                    query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
         | 
| 154 | 
            +
                    query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                    signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
         | 
| 157 | 
            +
                    assert_equal signature_algorithm, OpenSSL::Digest::SHA256
         | 
| 158 | 
            +
                    assert @cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
         | 
| 130 159 | 
             
                  end
         | 
| 160 | 
            +
             | 
| 131 161 | 
             
                end
         | 
| 132 162 | 
             
              end
         | 
| 133 163 | 
             
            end
         | 
    
        data/test/test_helper.rb
    CHANGED
    
    
    
        data/test/xml_security_test.rb
    CHANGED
    
    | @@ -78,7 +78,44 @@ class XmlSecurityTest < Minitest::Test | |
| 78 78 | 
             
                end
         | 
| 79 79 | 
             
              end
         | 
| 80 80 |  | 
| 81 | 
            -
              describe "Algorithms" do
         | 
| 81 | 
            +
              describe "Fingerprint Algorithms" do
         | 
| 82 | 
            +
                let(:response_fingerprint_test) { OneLogin::RubySaml::Response.new(fixture(:adfs_response_sha1, false)) }
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                it "validate using SHA1" do
         | 
| 85 | 
            +
                  sha1_fingerprint = "F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72"
         | 
| 86 | 
            +
                  sha1_fingerprint_downcase = "f13c6b80905a030e6c913e5d15faddb016454872"
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  assert response_fingerprint_test.document.validate_document(sha1_fingerprint)
         | 
| 89 | 
            +
                  assert response_fingerprint_test.document.validate_document(sha1_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA1)
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  assert response_fingerprint_test.document.validate_document(sha1_fingerprint_downcase)
         | 
| 92 | 
            +
                  assert response_fingerprint_test.document.validate_document(sha1_fingerprint_downcase, true, :fingerprint_alg => XMLSecurity::Document::SHA1)
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                it "validate using SHA256" do
         | 
| 96 | 
            +
                  sha256_fingerprint = "C4:C6:BD:41:EC:AD:57:97:CE:7B:7D:80:06:C3:E4:30:53:29:02:0B:DD:2D:47:02:9E:BD:85:AD:93:02:45:21"
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  assert !response_fingerprint_test.document.validate_document(sha256_fingerprint)
         | 
| 99 | 
            +
                  assert response_fingerprint_test.document.validate_document(sha256_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA256)
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                it "validate using SHA384" do
         | 
| 103 | 
            +
                  sha384_fingerprint = "98:FE:17:90:31:E7:68:18:8A:65:4D:DA:F5:76:E2:09:97:BE:8B:E3:7E:AA:8D:63:64:7C:0C:38:23:9A:AC:A2:EC:CE:48:A6:74:4D:E0:4C:50:80:40:B4:8D:55:14:14"
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  assert !response_fingerprint_test.document.validate_document(sha384_fingerprint)
         | 
| 106 | 
            +
                  assert response_fingerprint_test.document.validate_document(sha384_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA384)
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                it "validate using SHA512" do
         | 
| 110 | 
            +
                  sha512_fingerprint = "5A:AE:BA:D0:BA:9D:1E:25:05:01:1E:1A:C9:E9:FF:DB:ED:FA:6E:F7:52:EB:45:49:BD:DB:06:D8:A3:7E:CC:63:3A:04:A2:DD:DF:EE:61:05:D9:58:95:2A:77:17:30:4B:EB:4A:9F:48:4A:44:1C:D0:9E:0B:1E:04:77:FD:A3:D2"
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  assert !response_fingerprint_test.document.validate_document(sha512_fingerprint)
         | 
| 113 | 
            +
                  assert response_fingerprint_test.document.validate_document(sha512_fingerprint, true, :fingerprint_alg => XMLSecurity::Document::SHA512)
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
              end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
              describe "Signature Algorithms" do
         | 
| 82 119 | 
             
                it "validate using SHA1" do
         | 
| 83 120 | 
             
                  @document = XMLSecurity::SignedDocument.new(fixture(:adfs_response_sha1, false))
         | 
| 84 121 | 
             
                  assert @document.validate_document("F1:3C:6B:80:90:5A:03:0E:6C:91:3E:5D:15:FA:DD:B0:16:45:48:72")
         | 
| @@ -157,7 +194,7 @@ class XmlSecurityTest < Minitest::Test | |
| 157 194 |  | 
| 158 195 | 
             
                    # verify our signature
         | 
| 159 196 | 
             
                    signed_doc = XMLSecurity::SignedDocument.new(request.to_s)
         | 
| 160 | 
            -
                    signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
         | 
| 197 | 
            +
                    assert signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
         | 
| 161 198 | 
             
                  end
         | 
| 162 199 |  | 
| 163 200 | 
             
                  it "sign a LogoutRequest" do
         | 
| @@ -173,7 +210,7 @@ class XmlSecurityTest < Minitest::Test | |
| 173 210 |  | 
| 174 211 | 
             
                    # verify our signature
         | 
| 175 212 | 
             
                    signed_doc = XMLSecurity::SignedDocument.new(request.to_s)
         | 
| 176 | 
            -
                    signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
         | 
| 213 | 
            +
                    assert signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
         | 
| 177 214 | 
             
                  end
         | 
| 178 215 |  | 
| 179 216 | 
             
                  it "sign a LogoutResponse" do
         | 
| @@ -189,7 +226,7 @@ class XmlSecurityTest < Minitest::Test | |
| 189 226 |  | 
| 190 227 | 
             
                    # verify our signature
         | 
| 191 228 | 
             
                    signed_doc = XMLSecurity::SignedDocument.new(response.to_s)
         | 
| 192 | 
            -
                    signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
         | 
| 229 | 
            +
                    assert signed_doc.validate_document(ruby_saml_cert_fingerprint, false)
         | 
| 193 230 | 
             
                  end
         | 
| 194 231 | 
             
                end
         | 
| 195 232 |  |