diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..190e222 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +elixir 1.12.3-otp-24 +erlang 24.2 diff --git a/.travis.yml b/.travis.yml index 29689e4..1ab6d25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,4 @@ otp_release: - 21.0 - 20.3 - 19.3 - - 18.3 script: rebar3 do compile, eunit diff --git a/include/esaml.hrl b/include/esaml.hrl index 5fb08a1..91d7af3 100644 --- a/include/esaml.hrl +++ b/include/esaml.hrl @@ -107,7 +107,7 @@ idp_signs_envelopes = true :: boolean(), idp_signs_logout_requests = true :: boolean(), sp_sign_metadata = false :: boolean(), - trusted_fingerprints = [] :: [string() | binary()], + trusted_fingerprints = [] :: [string() | binary()] | any, metadata_uri = "" :: string(), consume_uri = "" :: string(), logout_uri :: string() | undefined, diff --git a/rebar b/rebar deleted file mode 100755 index f350b02..0000000 Binary files a/rebar and /dev/null differ diff --git a/rebar.config b/rebar.config index 8e82a6c..2f29659 100644 --- a/rebar.config +++ b/rebar.config @@ -5,7 +5,7 @@ {ct_verbose, true}. {deps, [ - {cowboy, "2.6.0"} + {cowboy, "2.9.0"} ]}. {edoc_opts, [{preprocess, true}]}. diff --git a/rebar3 b/rebar3 new file mode 100755 index 0000000..4dd5eb4 Binary files /dev/null and b/rebar3 differ diff --git a/src/esaml.erl b/src/esaml.erl index e68b981..78ed909 100644 --- a/src/esaml.erl +++ b/src/esaml.erl @@ -401,7 +401,9 @@ validate_assertion(AssertionXml, Recipient, Audience) -> case proplists:get_value(audience, Conds) of undefined -> A; Audience -> A; - _ -> {error, bad_audience} + Other -> + logger:error("ESAML: bad_audience - expected: ~ts, got: ~ts", [Audience, Other]), + {error, bad_audience} end; _ -> A end end, @@ -516,29 +518,29 @@ to_xml(#esaml_logoutresp{version = V, issue_instant = Time, Ns = #xmlNamespace{nodes = [{"md", 'urn:oasis:names:tc:SAML:2.0:metadata'}, {"saml", 'urn:oasis:names:tc:SAML:2.0:assertion'}, - {"dsig", 'http://www.w3.org/2000/09/xmldsig#'}]}, + {"ds", 'http://www.w3.org/2000/09/xmldsig#'}]}, KeyDescriptorElems = case CertBin of undefined -> []; C when is_binary(C) -> [ #xmlElement{name = 'md:KeyDescriptor', attributes = [#xmlAttribute{name = 'use', value = "signing"}], - content = [#xmlElement{name = 'dsig:KeyInfo', - content = [#xmlElement{name = 'dsig:X509Data', + content = [#xmlElement{name = 'ds:KeyInfo', + content = [#xmlElement{name = 'ds:X509Data', content = - [#xmlElement{name = 'dsig:X509Certificate', + [#xmlElement{name = 'ds:X509Certificate', content = [#xmlText{value = base64:encode_to_string(CertBin)}]} | - [#xmlElement{name = 'dsig:X509Certificate', + [#xmlElement{name = 'ds:X509Certificate', content = [#xmlText{value = base64:encode_to_string(CertChainBin)}]} || CertChainBin <- CertChain]]}]}]}, #xmlElement{name = 'md:KeyDescriptor', attributes = [#xmlAttribute{name = 'use', value = "encryption"}], - content = [#xmlElement{name = 'dsig:KeyInfo', - content = [#xmlElement{name = 'dsig:X509Data', + content = [#xmlElement{name = 'ds:KeyInfo', + content = [#xmlElement{name = 'ds:X509Data', content = - [#xmlElement{name = 'dsig:X509Certificate', + [#xmlElement{name = 'ds:X509Certificate', content = [#xmlText{value = base64:encode_to_string(CertBin)}]} | - [#xmlElement{name = 'dsig:X509Certificate', + [#xmlElement{name = 'ds:X509Certificate', content = [#xmlText{value = base64:encode_to_string(CertChainBin)}]} || CertChainBin <- CertChain]]}]}]} ] @@ -547,9 +549,6 @@ to_xml(#esaml_logoutresp{version = V, issue_instant = Time, SingleLogoutServiceElems = case SLOLoc of undefined -> []; _ -> [ - #xmlElement{name = 'md:SingleLogoutService', - attributes = [#xmlAttribute{name = 'Binding', value = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"}, - #xmlAttribute{name = 'Location', value = SLOLoc}]}, #xmlElement{name = 'md:SingleLogoutService', attributes = [#xmlAttribute{name = 'Binding', value = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"}, #xmlAttribute{name = 'Location', value = SLOLoc}]} @@ -561,10 +560,6 @@ to_xml(#esaml_logoutresp{version = V, issue_instant = Time, attributes = [#xmlAttribute{name = 'isDefault', value = "true"}, #xmlAttribute{name = 'index', value = "0"}, #xmlAttribute{name = 'Binding', value = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"}, - #xmlAttribute{name = 'Location', value = ConsumerLoc}]}, - #xmlElement{name = 'md:AssertionConsumerService', - attributes = [#xmlAttribute{name = 'index', value = "1"}, - #xmlAttribute{name = 'Binding', value = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"}, #xmlAttribute{name = 'Location', value = ConsumerLoc}]} ], @@ -592,21 +587,20 @@ to_xml(#esaml_logoutresp{version = V, issue_instant = Time, esaml_util:build_nsinfo(Ns, #xmlElement{ name = 'md:EntityDescriptor', - attributes = [ +attributes = [ #xmlAttribute{name = 'xmlns:md', value = atom_to_list(proplists:get_value("md", Ns#xmlNamespace.nodes))}, #xmlAttribute{name = 'xmlns:saml', value = atom_to_list(proplists:get_value("saml", Ns#xmlNamespace.nodes))}, - #xmlAttribute{name = 'xmlns:dsig', value = atom_to_list(proplists:get_value("dsig", Ns#xmlNamespace.nodes))}, + #xmlAttribute{name = 'xmlns:ds', value = atom_to_list(proplists:get_value("ds", Ns#xmlNamespace.nodes))}, #xmlAttribute{name = 'entityID', value = EntityID} ], content = [ SPSSODescriptorElem, OrganizationElem, ContactElem ] - }); + }); to_xml(_) -> error("unknown record"). - -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). diff --git a/src/esaml_sp.erl b/src/esaml_sp.erl index 3a1abf4..dd85d0a 100644 --- a/src/esaml_sp.erl +++ b/src/esaml_sp.erl @@ -11,9 +11,10 @@ -include("esaml.hrl"). -include_lib("xmerl/include/xmerl.hrl"). +-include_lib("kernel/include/logger.hrl"). -export([setup/1, generate_authn_request/2, generate_authn_request/3, generate_metadata/1]). --export([validate_assertion/2, validate_assertion/3]). +-export([validate_assertion/2, validate_assertion/3, validate_assertion/4]). -export([generate_logout_request/3, generate_logout_request/4, generate_logout_response/3]). -export([validate_logout_request/2, validate_logout_response/2]). @@ -169,7 +170,8 @@ validate_logout_request(Xml, SP = #esaml_sp{}) -> fun(X) -> case xmerl_xpath:string("/samlp:LogoutRequest", X, [{namespace, Ns}]) of [#xmlElement{}] -> X; - _ -> {error, bad_assertion} + Error -> logger:error("ESAML_SP: Failed parsing LogoutRequest XML with: ~ts",[Error]), + {error, bad_assertion} end end, fun(X) -> @@ -239,6 +241,15 @@ validate_assertion(Xml, SP = #esaml_sp{}) -> -spec validate_assertion(xml(), dupe_fun(), esaml:sp()) -> {ok, esaml:assertion()} | {error, Reason :: term()}. validate_assertion(Xml, DuplicateFun, SP = #esaml_sp{}) -> + validate_assertion(Xml, DuplicateFun, SP, nil). + +%% @doc Validate and decode an assertion envelope in parsed XML +%% +%% sign_cert() is x509 cert to be used if SAML response is missing +%% X509Certificate element (Cisco) +-spec validate_assertion(xml(), dupe_fun(), esaml:sp(), SignCert :: binary | any) -> + {ok, esaml:assertion()} | {error, Reason :: term()} | {error, Reason :: term(), Details :: any}. +validate_assertion(Xml, DuplicateFun, SP = #esaml_sp{}, SignCert) -> Ns = [{"samlp", 'urn:oasis:names:tc:SAML:2.0:protocol'}, {"saml", 'urn:oasis:names:tc:SAML:2.0:assertion'}], esaml_util:threaduntil([ @@ -250,19 +261,19 @@ validate_assertion(Xml, DuplicateFun, SP = #esaml_sp{}) -> xmerl_xpath:string("/saml:Assertion", DecryptedAssertion, [{namespace, Ns}]) of [A2] -> A2 catch - _Error:_Reason -> {error, bad_assertion} + Error -> {error, bad_assertion, Error} end; _ -> case xmerl_xpath:string("/samlp:Response/saml:Assertion", X, [{namespace, Ns}]) of [A3] -> A3; - _ -> {error, bad_assertion} + Error -> {error, bad_assertion, Error} end end end, fun(A) -> if SP#esaml_sp.idp_signs_envelopes -> - case xmerl_dsig:verify(Xml, SP#esaml_sp.trusted_fingerprints) of + case xmerl_dsig:verify(Xml, SP#esaml_sp.trusted_fingerprints, SignCert) of ok -> A; OuterError -> {error, {envelope, OuterError}} end; @@ -271,7 +282,7 @@ validate_assertion(Xml, DuplicateFun, SP = #esaml_sp{}) -> end, fun(A) -> if SP#esaml_sp.idp_signs_assertions -> - case xmerl_dsig:verify(A, SP#esaml_sp.trusted_fingerprints) of + case xmerl_dsig:verify(A, SP#esaml_sp.trusted_fingerprints, SignCert) of ok -> A; InnerError -> {error, {assertion, InnerError}} end; @@ -299,19 +310,53 @@ decrypt_assertion(Xml, #esaml_sp{key = PrivateKey}) -> [EncryptedData] = xmerl_xpath:string("./xenc:EncryptedData", Xml, [{namespace, XencNs}]), [#xmlText{value = CipherValue64}] = xmerl_xpath:string("xenc:CipherData/xenc:CipherValue/text()", EncryptedData, [{namespace, XencNs}]), CipherValue = base64:decode(CipherValue64), - SymmetricKey = decrypt_key_info(EncryptedData, PrivateKey), + EncryptedKey = get_encrypted_key(EncryptedData, Xml), + SymmetricKey = decrypt_key(EncryptedKey, PrivateKey), [#xmlAttribute{value = Algorithm}] = xmerl_xpath:string("./xenc:EncryptionMethod/@Algorithm", EncryptedData, [{namespace, XencNs}]), AssertionXml = block_decrypt(Algorithm, SymmetricKey, CipherValue), {Assertion, _} = xmerl_scan:string(AssertionXml, [{namespace_conformant, true}]), Assertion. -decrypt_key_info(EncryptedData, Key) -> - DsNs = [{"ds", 'http://www.w3.org/2000/09/xmldsig#'}], +get_encrypted_key(EncryptedData, Xml) -> + Ns = [{namespace, [ + {"ds", 'http://www.w3.org/2000/09/xmldsig#'}, + {"xenc", 'http://www.w3.org/2001/04/xmlenc#'} + ]}], + [KeyInfo] = xmerl_xpath:string("./ds:KeyInfo", EncryptedData, Ns), + case xmerl_xpath:string("./xenc:EncryptedKey", KeyInfo, Ns) of + [EncryptedKey] -> + EncryptedKey; + [] -> + retrieve_encrypted_key(KeyInfo, Xml, Ns) + end. + + +retrieve_encrypted_key(KeyInfo, Xml, Ns) -> + [#xmlAttribute{value = URI}] = xmerl_xpath:string("./ds:RetrievalMethod/@URI", KeyInfo, Ns), + case URI of + "#" ++ Id -> + [EncryptedKey] = xmerl_xpath:string("//xenc:EncryptedKey[@Id='" ++ Id ++ "']", Xml, Ns), + EncryptedKey; + _ -> + case application:get_env(esaml, retrieve_remote_key, fun default_retrieve_remote_key/1) of + Fun when is_function(Fun, 1) -> + Fun(URI); + + {M, F, A} -> + erlang:apply(M, F, [URI | A]) + end + end. + + +default_retrieve_remote_key(_URI) -> + error("Retrieval of remote encrypted keys is not configured"). + + +decrypt_key(EncryptedKey, Key) -> XencNs = [{"xenc", 'http://www.w3.org/2001/04/xmlenc#'}], - [KeyInfo] = xmerl_xpath:string("./ds:KeyInfo", EncryptedData, [{namespace, DsNs}]), - [#xmlAttribute{value = Algorithm}] = xmerl_xpath:string("./xenc:EncryptedKey/xenc:EncryptionMethod/@Algorithm", KeyInfo, [{namespace, XencNs}]), - [#xmlText{value = CipherValue64}] = xmerl_xpath:string("./xenc:EncryptedKey/xenc:CipherData/xenc:CipherValue/text()", KeyInfo, [{namespace, XencNs}]), + [#xmlAttribute{value = Algorithm}] = xmerl_xpath:string("./xenc:EncryptionMethod/@Algorithm", EncryptedKey, [{namespace, XencNs}]), + [#xmlText{value = CipherValue64}] = xmerl_xpath:string("./xenc:CipherData/xenc:CipherValue/text()", EncryptedKey, [{namespace, XencNs}]), CipherValue = base64:decode(CipherValue64), decrypt(CipherValue, Algorithm, Key). @@ -334,18 +379,18 @@ block_decrypt("http://www.w3.org/2009/xmlenc11#aes128-gcm", SymmetricKey, Cipher %% IV: 12 bytes and Tag data: 16 bytes EncryptedDataSize = byte_size(CipherValue) - 12 - 16, <> = CipherValue, - DecryptedData = crypto:block_decrypt(aes_gcm, SymmetricKey, IV, {<<>>, EncryptedData, Tag}), + DecryptedData = crypto:crypto_one_time_aead(aes_128_gcm, SymmetricKey, IV, EncryptedData, <<>>, Tag, false), binary_to_list(DecryptedData); block_decrypt("http://www.w3.org/2001/04/xmlenc#aes128-cbc", SymmetricKey, CipherValue) -> <> = CipherValue, - DecryptedData = crypto:block_decrypt(aes_cbc128, SymmetricKey, IV, EncryptedData), + DecryptedData = crypto:crypto_one_time(aes_128_cbc, SymmetricKey, IV, EncryptedData, false), IsPadding = fun(X) -> X < 16 end, lists:reverse(lists:dropwhile(IsPadding, lists:reverse(binary_to_list(DecryptedData)))); block_decrypt("http://www.w3.org/2001/04/xmlenc#aes256-cbc", SymmetricKey, CipherValue) -> <> = CipherValue, - DecryptedData = crypto:block_decrypt(aes_cbc256, SymmetricKey, IV, EncryptedData), + DecryptedData = crypto:crypto_one_time(aes_256_cbc, SymmetricKey, IV, EncryptedData, false), IsPadding = fun(X) -> X < 16 end, lists:reverse(lists:dropwhile(IsPadding, lists:reverse(binary_to_list(DecryptedData)))). diff --git a/src/xmerl_dsig.erl b/src/xmerl_dsig.erl index e333a36..e18ccab 100644 --- a/src/xmerl_dsig.erl +++ b/src/xmerl_dsig.erl @@ -20,7 +20,7 @@ %% enveloped mode. -module(xmerl_dsig). --export([verify/1, verify/2, sign/3, sign/4, strip/1, digest/1]). +-export([verify/1, verify/2, verify/3, sign/3, sign/4, strip/1, digest/1]). -include_lib("xmerl/include/xmerl.hrl"). -include_lib("public_key/include/public_key.hrl"). @@ -162,6 +162,15 @@ digest(Element, HashFunction) -> %% than rsa+sha1 or sha256 this will asplode. Don't say I didn't warn you. -spec verify(Element :: #xmlElement{}, Fingerprints :: [fingerprint()] | any) -> ok | {error, bad_digest | bad_signature | cert_not_accepted}. verify(Element, Fingerprints) -> +verify(Element, Fingerprints, nil). + +%% @doc Dubber change with optional x509 certificate as parameter +%% +%% This certificate to be used when X509Certificate child is not found +%% +%% +-spec verify(Element :: #xmlElement{}, Fingerprints :: [fingerprint()] | any, SkipCert :: binary | any) -> ok | {error, bad_digest | bad_signature | cert_not_accepted}. +verify(Element, Fingerprints, SkipCert) -> DsNs = [{"ds", 'http://www.w3.org/2000/09/xmldsig#'}, {"ec", 'http://www.w3.org/2001/10/xml-exc-c14n#'}], @@ -194,8 +203,11 @@ verify(Element, Fingerprints) -> [#xmlText{value = Sig64}] = xmerl_xpath:string("ds:Signature//ds:SignatureValue/text()", Element, [{namespace, DsNs}]), Sig = base64:decode(Sig64), - [#xmlText{value = Cert64}] = xmerl_xpath:string("ds:Signature//ds:X509Certificate/text()", Element, [{namespace, DsNs}]), - CertBin = base64:decode(Cert64), + CertBin = case xmerl_xpath:string("ds:Signature//ds:X509Certificate/text()", Element, [{namespace, DsNs}]) of + [] -> SkipCert; + [#xmlText{value = Cert64}] -> base64:decode(Cert64) + end, +%% CertBin = base64:decode(Cert64), CertHash = crypto:hash(sha, CertBin), CertHash2 = crypto:hash(sha256, CertBin), diff --git a/test/esaml_sp.crt b/test/esaml_sp.crt new file mode 100644 index 0000000..b8fb0f0 --- /dev/null +++ b/test/esaml_sp.crt @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEpDCCAowCCQCSdHd01QFuCDANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwHhcNMjAwMjI1MDA0OTIxWhcNMzAwMjIyMDA0OTIxWjAUMRIwEAYD +VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7 +b8IfFHfFveaO0OWOzt7xCMqIAhtB8RDuesmTlQLP6rIysz3jUXr/1VLjl2y5/YCJ +83Nl3DUSkQLNuksdBnuQyDD6AsOyS9iU6yzrcPCalRSzOeDXthklX5hvkbPykM0v +AvFUvjO7Vbjsp9UsuLhCVn9djSRxyaDCBZsLUXrDamIlpltqG+/3kltUp76gr8S7 ++0Htjnwh1X+oCzfpCkQBjDJlszAilyZChZhHDR3o9QHeAfno7eMy+XT/DaXt4ERS +ypij0m1RZjB55ceKjOqT6CtfPXsFWzPwcC1Kh0kQbdi8YY/pNSxZhiqcA50f+iut +7Pm6+CpntrZ3VWlC6tcU7pVf4XZZpjRU8eb7L9OTsnnaDONT6h4jc6WMiIyrf2cU +7gBCrOlRT0TOeWbuvrtCy9PZg/pZwDUJlgwFhKMFN3XuVkDWrNwxdNIXrwwc04Bf +sQAztqBaAkD1HqMmQZq4GrGGA1+cS4QFZCiyifUo+3T12DdCICSXMtvpgUGMgVDP +u5c7MaSWNVYD4oSJv1kPQQexG1SrP8qymg1lwXf3smcgxmBF01zY+fhapr817kvl +oE+SwVq1hwSFRaPgIG7+8WhTSYilwXoFBK3ZaM5NzOu7T7zp24C/73M43NR8p5AA +rD9Qb5YmeyuQrs0UXhWBkaFDCmE5C/E+kMN3pmt6KQIDAQABMA0GCSqGSIb3DQEB +CwUAA4ICAQBmmqqHl5DwnlcNabYjNQYuCcRE0s9FX5xy1pY/JkG6H85/pWTuxBDa +CWTtYXpXg+LRv6o2Y6mRLFNNZsyo+Ypuis0hvu5j5NmjDHvhuUjLyw3HtMOvlEqu +tcBpdTczLOAXe5ntzL76Tf5IdnvPItqjIjfzbJJfx9pV77SJbtusILIrJEFTHTcO +cC5Yg8nJP1Zhy7J8rAZdSCrKxaDjcEet79QMJfE0wx7gM0yASCHMGb9v/eT2iugb +ZNj0R5CuTQXbILCo3dvd3T0eqmnsjkbRLN/pVYCPEbtQGcA7k3wAMarlHGcIfH1i +DqB3up/cH0W4N1XYpWYSxwDOPR6gURyZarGAlSqBk9b3rc80UTetiZX9D9F4r83z +rwjD4oiIBSKchpPTn2sEv//4DeKLRa/Q1QvLdMHInf5iPmsA12r0VywNLXGw/c55 +M29z/m9QqCfeZ/SvFZhqvHS5lRMuzIbPE+kpNerBOjXI7YHE5+TkTOfjsDhNim8B +o1UDCnpdNJzK5COJ+zJW0AtCVsIWqgCaUA3TeWk7V9o8FGx5OueiGJbVF4rXaUhW +s94wDvnv/fgvGcJtzSrDorLN0lT4AMQvajoSzeaxkNSSykl2Un1J9HmJdiwYAx24 +Mf7cpkaGeVa/zoFDd78YQdheuV8w7kHzmZmYodQ9Va7ASsDMe8chLA== +-----END CERTIFICATE----- diff --git a/test/esaml_sp.key b/test/esaml_sp.key new file mode 100644 index 0000000..0e54e23 --- /dev/null +++ b/test/esaml_sp.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/test/esaml_sp_inline.xml b/test/esaml_sp_inline.xml new file mode 100644 index 0000000..1b3df2f --- /dev/null +++ b/test/esaml_sp_inline.xml @@ -0,0 +1,35 @@ + +https://samltest.id/saml/idpmURbTZO31uJb7DfS3NA6e1p1uvrCX8ciXW9bZ5Ps3Pk=MQinOSz4Xe6IgZsN+7wfn5bSNnc/Gm0hX6HOm6pZG6C7ObmzH2qYdKHZe3D/OvDH7CcdOlCfPthQ/a5+m6em4HTJzhcIAqdFaPDQsfq3rp9eAVjm/Qcp95vkYgEK4TgbFZdZn0aLzX+htG0cUk0G++Ol5HpkGOFPB6HKVAagSS82nZ/4uDxToFgjOXxIpViFLFLTa9PlTvolMTtzlyTTh69tm1o7IzQqK/Bj8gz/wiRLo7Psn3NixJOenqJek/zwok2aDf2aMNb3NUyidIpYrwdV33sbHW7Wc5HKnCSEQSQrc5sacUFlIpxWeyHCm4ttSDkkq2053qvaMaWHSwLDDQ==MIIDEjCCAfqgAwIBAgIVAMECQ1tjghafm5OxWDh9hwZfxthWMA0GCSqGSIb3DQEBCwUAMBYxFDAS +BgNVBAMMC3NhbWx0ZXN0LmlkMB4XDTE4MDgyNDIxMTQwOVoXDTM4MDgyNDIxMTQwOVowFjEUMBIG +A1UEAwwLc2FtbHRlc3QuaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0Z4QX1NFK +s71ufbQwoQoW7qkNAJRIANGA4iM0ThYghul3pC+FwrGv37aTxWXfA1UG9njKbbDreiDAZKngCgyj +xj0uJ4lArgkr4AOEjj5zXA81uGHARfUBctvQcsZpBIxDOvUUImAl+3NqLgMGF2fktxMG7kX3GEVN +c1klbN3dfYsaw5dUrw25DheL9np7G/+28GwHPvLb4aptOiONbCaVvh9UMHEA9F7c0zfF/cL5fOpd +Va54wTI0u12CsFKt78h6lEGG5jUs/qX9clZncJM7EFkN3imPPy+0HC8nspXiH/MZW8o2cqWRkrw3 +MzBZW3Ojk5nQj40V6NUbjb7kfejzAgMBAAGjVzBVMB0GA1UdDgQWBBQT6Y9J3Tw/hOGc8PNV7JEE +4k2ZNTA0BgNVHREELTArggtzYW1sdGVzdC5pZIYcaHR0cHM6Ly9zYW1sdGVzdC5pZC9zYW1sL2lk +cDANBgkqhkiG9w0BAQsFAAOCAQEASk3guKfTkVhEaIVvxEPNR2w3vWt3fwmwJCccW98XXLWgNbu3 +YaMb2RSn7Th4p3h+mfyk2don6au7Uyzc1Jd39RNv80TG5iQoxfCgphy1FYmmdaSfO8wvDtHTTNiL +ArAxOYtzfYbzb5QrNNH/gQEN8RJaEf/g/1GTw9x/103dSMK0RXtl+fRs2nblD1JJKSQ3AdhxK/we +P3aUPtLxVVJ9wMOQOfcy02l+hHMb6uAjsPOpOVKqi3M8XmcUZOpx4swtgGdeoSpeRyrtMvRwdcci +NBp9UZome44qZAYH1iqrpmmjsfI9pJItsgWu3kXPjhSfj1AJGR1l9JGvJrHki1iHTA==MIIEpDCCAowCCQCSdHd01QFuCDANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlsb2NhbGhvc3Qw +HhcNMjAwMjI1MDA0OTIxWhcNMzAwMjIyMDA0OTIxWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7b8IfFHfFveaO0OWOzt7xCMqIAhtB8RDuesmT +lQLP6rIysz3jUXr/1VLjl2y5/YCJ83Nl3DUSkQLNuksdBnuQyDD6AsOyS9iU6yzrcPCalRSzOeDX +thklX5hvkbPykM0vAvFUvjO7Vbjsp9UsuLhCVn9djSRxyaDCBZsLUXrDamIlpltqG+/3kltUp76g +r8S7+0Htjnwh1X+oCzfpCkQBjDJlszAilyZChZhHDR3o9QHeAfno7eMy+XT/DaXt4ERSypij0m1R +ZjB55ceKjOqT6CtfPXsFWzPwcC1Kh0kQbdi8YY/pNSxZhiqcA50f+iut7Pm6+CpntrZ3VWlC6tcU +7pVf4XZZpjRU8eb7L9OTsnnaDONT6h4jc6WMiIyrf2cU7gBCrOlRT0TOeWbuvrtCy9PZg/pZwDUJ +lgwFhKMFN3XuVkDWrNwxdNIXrwwc04BfsQAztqBaAkD1HqMmQZq4GrGGA1+cS4QFZCiyifUo+3T1 +2DdCICSXMtvpgUGMgVDPu5c7MaSWNVYD4oSJv1kPQQexG1SrP8qymg1lwXf3smcgxmBF01zY+fha +pr817kvloE+SwVq1hwSFRaPgIG7+8WhTSYilwXoFBK3ZaM5NzOu7T7zp24C/73M43NR8p5AArD9Q +b5YmeyuQrs0UXhWBkaFDCmE5C/E+kMN3pmt6KQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQBmmqqH +l5DwnlcNabYjNQYuCcRE0s9FX5xy1pY/JkG6H85/pWTuxBDaCWTtYXpXg+LRv6o2Y6mRLFNNZsyo ++Ypuis0hvu5j5NmjDHvhuUjLyw3HtMOvlEqutcBpdTczLOAXe5ntzL76Tf5IdnvPItqjIjfzbJJf +x9pV77SJbtusILIrJEFTHTcOcC5Yg8nJP1Zhy7J8rAZdSCrKxaDjcEet79QMJfE0wx7gM0yASCHM +Gb9v/eT2iugbZNj0R5CuTQXbILCo3dvd3T0eqmnsjkbRLN/pVYCPEbtQGcA7k3wAMarlHGcIfH1i +DqB3up/cH0W4N1XYpWYSxwDOPR6gURyZarGAlSqBk9b3rc80UTetiZX9D9F4r83zrwjD4oiIBSKc +hpPTn2sEv//4DeKLRa/Q1QvLdMHInf5iPmsA12r0VywNLXGw/c55M29z/m9QqCfeZ/SvFZhqvHS5 +lRMuzIbPE+kpNerBOjXI7YHE5+TkTOfjsDhNim8Bo1UDCnpdNJzK5COJ+zJW0AtCVsIWqgCaUA3T +eWk7V9o8FGx5OueiGJbVF4rXaUhWs94wDvnv/fgvGcJtzSrDorLN0lT4AMQvajoSzeaxkNSSykl2 +Un1J9HmJdiwYAx24Mf7cpkaGeVa/zoFDd78YQdheuV8w7kHzmZmYodQ9Va7ASsDMe8chLA==t2+VYQubBDCmjv48EVdnChQT2dfNLHY+yPeBa82gVTd2eVo27N+/JjB8dV0skOMJVnfevx+sJ591CvtQYBx3TuUGnwDoEDh0aP/9uBL0Zm76yvKLL+LCwMUmqZkmHYXBRXqFVIRpwoAjbK2K+EjuJPzTuKaf7KNO3ED9tuLEOI/dMqR2MoMjYjcK7IUnJlIMLj2zWMrS7ENCpkfRuamKde/LPhnpO5rE9msXUoyPj0+zORnCjAw7yJI26C8uMZ41fYVq1zCN+Qd/4Q6UV8vmEUjlggiRPe3WcmHSrhkoLzNGEO55eZ5sFeh9wurcWhXVuaSgV8eVNv5stu2y3k0fQ+CemuZIGpdDUDkYA3mXV4iRAdTiMhpPLYvPMLBmDZ44JOyDH49ZKOyL9UFMpcO2vPHxYgCRnp1J7w6wxcvrkGtXGmPMQi/X1Zaaf+ed/qeFe0kzTQACyAyJTeaFC/jQ4kmxlTyfY/YzNb3sYEsulbRAiIFgEvICAqU3wzc9xKBPDnJ9iv5X/i4lsCLocBGBU1tmwr2JRGUCP4720LRcU+0nyC1FRIFpcNgc0/Nc4eP8NLepNEeLPik2/ralQdozswQCc2FjkHiAwRtrjmkA5VBeebYIZDafgSXTl9rwXVLiiFSLEJCO4PNxj/EO27mw/3WMyjHscn7p4zKTrvfdd7A=ZCru0qp3lXKOIx015VWRaIn9fogaRYOzZOLZ1Clwkyjfk1Q/Gly6FBKDB1blLtI+iQkq7RYBBUY+50ASgKxMjDneHv/CmWURID3UIPlu7SNVPEEmj802BIwgb69TekaXFyVTqXtY/ZPbrYhepartV7erRK2fR5KZO5PvOcqP2csYJiOGWT0Y02o76PH2ga9AsctnVsDTlMy7vptvyKZU4DZ/89fNwure3BYcobMNWF7Mwd8iCwRODkubGKO6UA31wlswuNJ2NCjHIthwAj6j3QStkpCPpuQVE+XbSXcZl4RVuYIpQjyxeww5LLPqV4UUZiwKxT5RppleeodiZcZRrC5DlCDrmSYdquFAE0y4M/StpZDSWrD1QTxG4wJICkYtYa9Z6gd5qRVjdS6g5p9ChueDshC54klDryRbRq5dSaem/iv4vK8zixFKoQENdGK9c8Aw3I0uxQxAuswNlsXN9ht8R8ZyygaaUlfe1xIIpqJb7KgS75IFt7GgpG737uDZwT7MelY2cWu80JtWYb54dvjBwsjlWPFxt9s+5FuXLaMzwC5telotq5q5J16daRLKlwKFZGhHomKEyFu3KJ5wqGhiArPkpkNqm1EPwg1EJdh5Ya9KT1/fKHUEmMrR+Iv9FcUEPOT4TnjmzBR7JAnirqlYEyjRiX5eeoP/DrfIsPudjOdOc+4WYQDNLluBEwZt/ul70IXy4E0WjW/MDwF/lkkSVIoo/UwgjofkyOVvB6vv+qmgv/xTy+G0+Era/g6T3Wb4k8CFaPc9Jy6Q9/xPdaso4m0W2/9X1Tqa/VIDK4Z+m1kz/pbltA+kKM8/8FrNLNhE7VMWMTixZDs3MY1FODPbjoAuT9hdr/DoahC6bXxOz4xOXbL18Coihjtpy2uFDTZdW/3rtkKMnrRIcoxvH22zsBX5rp8w0N8/bEKxRdvWA5MKdU30SrDat3P/uABc2mQO45fw6HIrWvM8VGSLLfdfWCYly/6WzcFUyq9k8E7fBKcLQyxrlhTjwt7hLZMs7fOxabfRymcX3AV+ZhMcYB6uMdR6jEaayPTYMgA64QohVjvHEEr3tKBw0BaMSMUeanSigGrWl9KVP1fbrmQpJ5BHUFi49FMGJsJsEwyHBNyeRlVjERcYXi5xEL4v2snkOXIpkS4I/ZjD8iVwlvM7VXhQM2YFR7Gt3p2TEYGGp5AxwYYjrTeIjsgKCAdJH31IsktDYC1KiVVMNe0krDfJ/3EvomQob0PRqwS13WCbBl0VeUxyJVxeHmOk7qV0+/Gw+HzMzEn8Ogmnn2z1VmTd3EmF4EAZGM5rtYacjACw9fv89UYqJ6kVO+orXDa+1wLh36psclvwUInpP9pRVVM/g+UecQ+dbYCugxpY3zfL3e/lVM0U3P9YdLZ93OWhxAEnByWE8tVwwl5QgD6A6KuzTM8IXHOgC7L5NSrS1lmRFaFp28FjX5C9kdVzNW8UOFCcuy56v7kHIGRU0x2+NYqmDhh6+4Fey+dcBcQ+TAv8uMQpBpmRE8XinPzNNIG5XMOLJ0lOT0jBrIS07+e75vF/DHfdYDrdY6JdQUn61IDdu2Dv4ernwEqR4KXyc5IAbOJT9GdaVoo3Ihz4ZDp822aa6Uss2aKLpAo4hvJXqNGT/9lCbfeDrzG8Ial7s0Hn1jsBZQrvnuUDskRvaTBzn6o3SuYLujeI7fxSXncG41G3ZX5iPFNhh1rt6LT9tLo5+4okBolStkWoJF/4VDvtvgCoJ1iwmzS/0R/9VfalsH50slioqYXTtH3YlzTiDQD9Z9lM0BkKAFDiYsKiMJb/hQoOYMsqZQheasSrsjVrnGhU5IDC8Xkhh7PFyfNpK6Zz1Mu7qWxLkoGTMEyXIdJ+MddroSwroDjsbebcBEzGAGCMJHk8Rfi4lbPsKsmdRm9F6xcEs8Xbkh5ZVjWaVyyrLHgR6Idu6NYTHdMOiE/DY4IwNrf4a+li8HQp3vv8+eZ4GhfcgMkXFmRa6jN2OrE+aOSpMLGbV1yuKWx7QQlsh+cjQmRczw8QAeY6ktEYAsJQcmDx5hU2a6t87qJ/TjQFN7aBO1+NQMdkkTSEmIsu2SgSQTLmSHjd93lgb8NYRwbsW/DaaG034cuEkMkhuvGGBdHZQLXcKS6Zq+m0b+JO+YuZwksx6Ws9yVaaI3KWNB6waSz+62vmPFgAipnqUY1cBlB5lSacBgcHCnPLKFYMe0roAMFEFFvlLwO98NoWSYS9zVUl+rrgKmkkf69XqHYILd/IqrWxpqRtmnEtQRFMqLHt7YXPxVTgYkpeOPQwOh2hWVYIBV9uTqaK3+2/JY9mjrtNAa7eu1vjl2CcZMHo0oqZNGlzGeGd1nZG/kogkl1vAKYDnvQ7lbTaVV2ffYMJ1PB4RArXm7wz6OS3Oez3+Vw3+kx+Kor99QjMzH9SIo8Ojm/yOe/mHpi52XUtc90j39IK6tZ7IRxOP7xh0lvmxzIcn1gZ/ZTui8dCfz3mmPvI6zpfHFaZm8IZdOuqOXyhS8KABXEHv4mh9uLCk643uFTOsSZyKskoUnX2A3cnY4cMSasSc4nxzQ3B50fitaDRu/O7P7uWHwm2ALSc2vEaDOQiCDKTuUIksk5ABxCNoucMD5EGAROurTiyeVDH4weRcuKXjfDceoQnwdLuNOj8x0twz1fy33OE637jy7VVuziYcrvq/A7s8z08kEV87JfcO67KG9IKbfPARuDt3PbC6AbaqV68E2pB6kpZljll4L8Z44H9QZudsirZ3eI5GW87IJ/Mvnjj5lTtFtRTSx/0aqvVM+8VqLfMI6Q7qM/kgtxwhg0fhJBgREeLQ85Hl7VhUnRv24kHd1Gm0NzBmSQ2o84qWqWgvEmxBWtFtR93BQAk9sMnC/e0XYE53ISO3xMOdQ/nrmD+kj8QfU384tgXbEVyH0NNRW4ZcI2JUiTucjbI60C28NpyemAQt/WZW0Km1uPXg40RSMtZ1tPGn7xzXQ0OHRUzW8A+DxfAvRVlS1k7ftJim1oMtJYBJhkme38C5vdRxce/gUBDpUSbnwgylXgDauvSG/yuOVduxK9PH2uFMccDBgflKzKQlaRscjdn7zIabenRJ8F/8eJ75sJ716jDrXVhTNHfEmcmm9nwmZs2DQRHwksjBoW29XPNEaY9tUkQOzG1VskEkUPcgcoByacxctkBh+UTMgF0gbUJLxt4jMO31QiCM8xT+7P7nNaBv961Kg5YIB5kCBcMoS1QJ6J0KPtiTQIMyVF2+kAZMCPMyldIsdb6yaJC+yajEhUTFdmBKdjivQWTnhqFCFfxYA+vzNr9GUC3KEmpBtUmC4XpEB7jB/Bn4ITg+JX914ZB0qLeqchnM1Vmqr+Ct7vcYe6e7tc44tilYytMWLOI9Aq2sE9qqraJZTwI4dbj5V8cBxm+gwL/6eYLh+sBdA7JXMOA4KbycphQSDISM3G1Xm/MlijQx+bLyT+h10nr64fGK3X7/Em9O+njQ1BrYTakcRua7W+Q+z56PAzlZVIzPc5iXCNEfGmqbKQUprP14wgnV9g7SNiL6a5RqRpJOuMF18Ron7XFBd2mwN56pKXEuYrorpkDYLj0eUAMqR+om+XchIyrFtGA5tjuqZZYUdpAkAf6jgr76NmsWn6RUG3+gxA74TTrfIxe17/i33i/3jg0P8dAQlk6BQGmONaofPbqSj31rsPEHGK93ySYAzM7F3LVppUsXytevyutyPSu91SYxBvwIo6CQ6gMQ0MMLRlVhEzLtu1bKFqw+KAvbhGy00vgBGM3ymwJpGE1vaCHSGu9/MGnDe5iOqFBrREFIhQ0RAaz1AwBhQpmun2esPYuPF99I2DjjiZCfxtGfwwSZwerr41SJDA8o48tTadt0jTvbNZnQvYPqvu6+RucaTisCOi6sVemmuyiLt4TwFZD79iOod0+0f0UJSiOvFqV4mM5oYJ8xiSTo5HXGa0rA6Lw+/B/mz1pcfPjVf5hJApj8lU33oVhFHBEVoGz4SB9qhlt52RQzc98Zj7Ni9j7O/+NC1DZDwVqtOyH7ZSrcaIz/XaE4WgYOAeLyjyAl9SnUFCI5AMB9vB+/GR+YBVSLgbjYMw/KIYSsSbg32mObZZkz9NMZXWw4dkPh4gYBhXopmAegWJtE1TQ8veeg6vXhkGlKTAK0XqPqLWul6Tmkk6saz49vWtiDTMp726JGLgH8Mz7c9aRehPhQZNztcEx6gLheci3NKlnemnm2hJ3wSvX4fxP6HVtSXAqsz/xET0lqA3m1I4E5e04XYYNwy+eReJ5SoANTEjIbLgmV643b9Z4cks2TE2hEVFVnpfQ2gQ0s6q252DPCkl64tXq+N04+gBW/y5wBS0MeseaH8k/J7Ch0KwZq5vgkiN/s1XW5s5o+GGSea8JzBLofrkgnTO0WUQGstDsEeSRVlQB5i/94f64XLDFy28a9v4HfEhevqffanGD+0XlGZYJLXcVE0nWNoDvM+P5rzLoj94NySFfD2F1UXrOQYZCfrUlh2tlurgo5FzsiAaUZOs5noJ2+oCWDltKjSB/+UJH85KecuHAbp/Qlouo4RccYaRbBFTB4D9+RlcKaZhFEIPFfqLn3xgKKE9hzsLbnSWyEC9GzBLsusJDF49LvuqgHmSQ6ElSprCPj5eO2+vS458ktrf1rbRJ0yt0fmNyOi3Y0eElsJiSrOCfZozebsASOGul1e1rQgmg2WnuNaJbuiV2pecjP/n2vgdeS3gnMo8J \ No newline at end of file diff --git a/test/esaml_sp_local.xml b/test/esaml_sp_local.xml new file mode 100644 index 0000000..505cbe9 --- /dev/null +++ b/test/esaml_sp_local.xml @@ -0,0 +1,37 @@ +http://www.okta.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 \ No newline at end of file diff --git a/test/esaml_sp_test.erl b/test/esaml_sp_test.erl new file mode 100644 index 0000000..2f33972 --- /dev/null +++ b/test/esaml_sp_test.erl @@ -0,0 +1,73 @@ +-module(esaml_sp_test). + +-include_lib("eunit/include/eunit.hrl"). +-include_lib("xmerl/include/xmerl.hrl"). +-include("esaml.hrl"). + + +path(Name, Ext) -> + "test/esaml_sp_" ++ Name ++ "." ++ Ext. + + +path(Ext) -> + "test/esaml_sp." ++ Ext. + + +validate_assertion_test_() -> + {setup, + fun() -> + {ok, Sup} = esaml:start(permanent, []), + Sup + end, + fun(Sup) -> + gen_server:stop(Sup) + end, + [ + {"inline key", fun() -> + {Xml, SP} = build_sp("inline"), + ?assertMatch({error,stale_assertion}, esaml_sp:validate_assertion(Xml, SP)) + end}, + {"local key", fun() -> + {Xml, SP} = build_sp("local"), + ?assertMatch({error,stale_assertion}, esaml_sp:validate_assertion(Xml, SP)) + end} + ] + }. + +get_xml(Name) -> + case file:read_file(path(Name, "xml")) of + {ok, <<"<", _/binary>> = Text} -> + ok; + {ok, Encoded} -> + Text = base64:decode(Encoded) + end, + {Xml, _} = xmerl_scan:string(binary_to_list(Text), [{namespace_conformant, true}]), + Xml. + +build_sp(Name) -> + Xml = get_xml(Name), + ConsumeUrl = "http://localhost:4000/saml/login", + Recipient = "urn:f5156378-6d88-44b0-a38a-31219f1af162", + PrivKey = esaml_util:load_private_key(path("key")), + Cert = esaml_util:load_certificate(path("crt")), + + SP = esaml_sp:setup(#esaml_sp{ + entity_id = Recipient, + key = PrivKey, + certificate = Cert, + idp_signs_assertions = false, + idp_signs_envelopes = false, + consume_uri = ConsumeUrl, + metadata_uri = ConsumeUrl, + org = #esaml_org{ + name = "Foo Bar", + displayname = "Foo Bar", + url = "http://some.hostname.com" + }, + tech = #esaml_contact{ + name = "Foo Bar", + email = "foo@bar.com" + } + }), + + {Xml, SP#esaml_sp{trusted_fingerprints = any}}.