diff --git a/lib/saml2.coffee b/lib/saml2.coffee index 2e1e9b6..179d662 100644 --- a/lib/saml2.coffee +++ b/lib/saml2.coffee @@ -160,12 +160,17 @@ certificate_to_keyinfo = (use, certificate) -> check_saml_signature = (xml, certificate, cb) -> doc = (new xmldom.DOMParser()).parseFromString(xml) - signature = xmlcrypto.xpath(doc, ".//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']") - return false unless signature.length is 1 + signatures = xmlcrypto.xpath(doc, ".//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']") + return false unless signatures.length + sig = new xmlcrypto.SignedXml() sig.keyInfoProvider = getKey: -> format_pem(certificate, 'CERTIFICATE') - sig.loadSignature signature[0].toString() - return sig.checkSignature xml + + for signature in signatures + sig.loadSignature signature.toString() + return false unless sig.checkSignature(xml) + + return true # Takes in an xml @dom containing a SAML Status and returns true if at least one status is Success. check_status_success = (dom) -> @@ -541,4 +546,3 @@ if process.env.NODE_ENV is "test" module.exports.get_session_index = get_session_index module.exports.parse_assertion_attributes = parse_assertion_attributes module.exports.set_option_defaults = set_option_defaults - diff --git a/test/data/good_assertion_multiple.xml b/test/data/good_assertion_multiple.xml new file mode 100644 index 0000000..8375447 --- /dev/null +++ b/test/data/good_assertion_multiple.xml @@ -0,0 +1 @@ +Harry PottervfIC/QjiDGknywC9PImPk1nEbr4=gv0nnrEvrQg8P8apOJGGwkANWyCnkbIID0Ds8pUNMayP1Jh23VLRli+J983RpXa8haPfHpPJB72ByXp/ElpFdFaHL5wh2GmsIKgMpWPshFi9Xu/S7zTTZ87I/ax1eo0hA07dS4GGZGrWXKjNEQrllYsYyhxGm3V11F0gYruNgwGwUoFSpL59KbpbQi4yfKjqesS8jRTAREzEhalyUvy2IgrZ9chFIxtqyylhaRSxWY2NbdsmC+cbMf2BQb52FEYQmQmtS6stRrRpJUIlFAHUz0lHTWgzGibqWwc5AHLuN1fyVr0CyqTZs2/jxeYt/czn/pxZQLOXIfI9OsRbHIgqXA==22zQy/Rr+zKlp9CcZvPmWaskedAMM=dazQQsLS8kyLAl30KL/ntwJ0Cg59w9rL2V4iXypAsecJ33AsCiN+5KEZTgb/+aj04/R3Y/HXjKw8qq9zQUTiXs6uJYI+cMBNrm3hNNSVF7yZ6QbeIe6WRREyQM0xNa2q6GMBqhgcF35Chwtf8Y93pYKYFQ301QZXCiM0WqnFXMA7UrwsuNTgWkC2u89fKk3kVDjDUenwHCAsplvt5q7MwnMd9+vOJGWyQMme0pBZ6liTxsVUwcLa7ximhYXtWCqdPrkqy7XZB60MoOAYBlmxqT+ZFb+cxWVRp0K+LjLlXpAS39lrVhZZ75rgjFYIyUuZTQ2PLC/ILBod4LgICUGzLg== diff --git a/test/saml2.coffee b/test/saml2.coffee index 444bc41..d35d504 100644 --- a/test/saml2.coffee +++ b/test/saml2.coffee @@ -112,6 +112,9 @@ describe 'saml2', -> it 'rejects xml with an invalid signature', -> assert.equal false, saml2.check_saml_signature(get_test_file("good_assertion.xml"), get_test_file("test2.crt")) + it 'validates all signatures if more than one exist', -> + assert saml2.check_saml_signature(get_test_file("good_assertion_multiple.xml"), get_test_file("test.crt")) + describe 'check_status_success', => it 'accepts a valid success status', => assert saml2.check_status_success(@good_response_dom), "Did not get 'true' for valid response." @@ -344,7 +347,7 @@ describe 'saml2', -> 'http://schemas.xmlsoap.org/claims/CommonName': [ 'Test Student' ] assert.deepEqual response, expected_response # make sure response can be deflated, since redirect requests need to be inflated - zlib.deflateRaw new Buffer(response, 'base64'), (err, deflated) => + zlib.deflateRaw new Buffer(JSON.stringify(response), 'base64'), (err, deflated) => assert not err?, "Got error: #{err}" done() @@ -412,7 +415,7 @@ describe 'saml2', -> sso_login_url: 'https://idp.example.com/login' sso_logout_url: 'https://idp.example.com/logout' certificates: 'other_service_cert' - request_options = + request_options = assert_endpoint: 'https://sp.example.com/assert' relay_state: 'Some Relay State!' nameid_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" @@ -438,7 +441,7 @@ describe 'saml2', -> sso_login_url: 'https://idp.example.com/login' sso_logout_url: 'https://idp.example.com/logout' certificates: 'other_service_cert' - request_options = + request_options = assert_endpoint: 'https://sp.example.com/assert' relay_state: 'Some Relay State!' @@ -492,7 +495,7 @@ describe 'saml2', -> name_id: 'name_id' session_index: 'session_index' sign_get_request: true - + sp = new saml2.ServiceProvider sp_options idp = new saml2.IdentityProvider idp_options