Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for logout responses #97

Open
wants to merge 1 commit into
base: ep-remove-dead-code
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 65 additions & 12 deletions src/saml20_clj/coerce.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
[clojure.string :as str]
[saml20-clj.encode-decode :as encode-decode]
[saml20-clj.xml :as saml.xml])
(:import org.opensaml.core.xml.util.XMLObjectSupport))
(:import org.opensaml.core.xml.util.XMLObjectSupport
org.opensaml.saml.saml2.binding.decoding.impl.HTTPPostDecoder))

;; these have to be initialized before using.
;;
Expand Down Expand Up @@ -31,17 +32,21 @@
(defprotocol CoerceToX509Certificate
(->X509Certificate ^java.security.cert.X509Certificate [this]
"Coerce something such as a base-64-encoded string or byte array to a `java.security.cert.X509Certificate`. This
class isn't used directly by OpenSAML; instead, certificate must be coerced to an OpenSAML `Credential`. See
class isn't used directly by OpenSAML; instead
certificate must be coerced to an OpenSAML `Credential`. See
`->Credential`."))

(defprotocol CoerceToCredential
(->Credential
^org.opensaml.security.credential.Credential [this]
^org.opensaml.security.credential.Credential [public-key private-key]
"Coerce something such as a byte array or base-64-encoded String to an OpenSAML `Credential`. Typically, you'd use
the credential with just the public key for the IdP's credentials, for encrypting requests (in combination with SP
"Coerce something such as a byte array or base-64-encoded String to an OpenSAML `Credential`. Typically
you'd use
the credential with just the public key for the IdP's credentials
for encrypting requests (in combination with SP
credentails) or verifying signature(s) in the response. A credential with both public and private keys would
typically contain *your* public and private keys, for encrypting requests (in combination with IdP credentials) or
typically contain *your* public and private keys
for encrypting requests (in combination with IdP credentials) or
for decrypting encrypted assertions in the response."))

(defprotocol CoerceToElement
Expand All @@ -53,10 +58,12 @@
(defprotocol CoerceToResponse
(->Response ^org.opensaml.saml.saml2.core.Response [this]))

(defprotocol CoerceToLogoutResponse
(->LogoutResponse ^org.opensaml.saml.saml2.core.LogoutResponse [this]))

(defprotocol SerializeXMLString
(->xml-string ^String [this]))


;;; ------------------------------------------------------ Impl ------------------------------------------------------

(defn keystore
Expand All @@ -77,7 +84,8 @@

(defmethod bytes->PrivateKey :default
[^bytes key-bytes algorithm]
(.generatePrivate (java.security.KeyFactory/getInstance (str/upper-case (name algorithm)), "BC")
(.generatePrivate (java.security.KeyFactory/getInstance (str/upper-case (name algorithm))
"BC")
(java.security.spec.PKCS8EncodedKeySpec. key-bytes)))

(defmethod bytes->PrivateKey :aes
Expand Down Expand Up @@ -122,7 +130,9 @@

clojure.lang.IPersistentMap
(->PrivateKey
([{^String key-alias :alias, ^String password :password, :as m}]
([{^String key-alias :alias
^String password :password
:as m}]
(when-let [keystore (keystore m)]
(when-let [key (.getKey keystore key-alias (.toCharArray password))]
(assert (instance? java.security.PrivateKey key))
Expand Down Expand Up @@ -163,7 +173,9 @@

clojure.lang.IPersistentMap
(->X509Certificate
[{^String key-alias :alias, ^String password :password, :as m}]
[{^String key-alias :alias
^String password :password
:as m}]
(when (and key-alias password)
(when-let [keystore (keystore m)]
(.getCertificate keystore key-alias)))))
Expand All @@ -186,7 +198,9 @@

clojure.lang.IPersistentMap
(->Credential
([{^String key-alias :alias, ^String password :password, :as m}]
([{^String key-alias :alias
^String password :password
:as m}]
(when (and key-alias password)
(when-let [keystore (keystore m)]
(org.opensaml.security.x509.impl.KeyStoreX509CredentialAdapter. keystore key-alias (.toCharArray password)))))
Expand Down Expand Up @@ -268,6 +282,46 @@
(->SAMLObject [this]
(->SAMLObject (->Element this))))

(extend-protocol CoerceToLogoutResponse
nil
(->LogoutResponse [_] nil)

org.opensaml.saml.saml2.core.LogoutResponse
(->LogoutResponse [this] this)

org.opensaml.saml.common.SignableSAMLObject
(->LogoutResponse [this]
(throw (ex-info (format "Don't know how to coerce a %s to a Response" (.getCanonicalName (class this)))
{:object this})))

org.opensaml.messaging.context.MessageContext
(->LogoutResponse [this]
(->LogoutResponse (.getMessage this)))

clojure.lang.IPersistentMap
(->LogoutResponse [this]
(let [http-request (reify jakarta.servlet.http.HttpServletRequest
(getMethod [_]
(condp = (:request-method this)
:post "POST" ;; the HTTPPostDecoder only cares about seeing exactly POST in the request
"UNKNOWN"))
(getContentType [_]
(:content-type this))
(getParameter [_ param]
(get-in this [:params (keyword param)])))
http-request-supplier (reify net.shibboleth.shared.primitive.NonnullSupplier
(get [_] http-request))
http-decoder (HTTPPostDecoder.)]
(doto http-decoder
(.setHttpServletRequestSupplier http-request-supplier)
(.initialize)
(.decode))
(->LogoutResponse (.getMessageContext http-decoder))))

Object
(->LogoutResponse [this]
(->LogoutResponse (->SAMLObject this))))

(extend-protocol CoerceToResponse
nil
(->Response [_] nil)
Expand Down Expand Up @@ -310,5 +364,4 @@

org.opensaml.messaging.context.MessageContext
(->xml-string [this]
(->xml-string (XMLObjectSupport/marshall (.getMessage this))))
)
(->xml-string (XMLObjectSupport/marshall (.getMessage this)))))
7 changes: 6 additions & 1 deletion src/saml20_clj/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[saml20-clj.coerce :as coerce]
[saml20-clj.crypto :as crypto]
[saml20-clj.encode-decode :as encode]
[saml20-clj.sp.logout-response :as logout-response]
[saml20-clj.sp.metadata :as metadata]
[saml20-clj.sp.request :as request]
[saml20-clj.sp.response :as response]
Expand All @@ -18,7 +19,8 @@
metadata/keep-me
request/keep-me
response/keep-me
state/keep-me)
state/keep-me
logout-response/keep-me)

(p/import-vars
[coerce
Expand Down Expand Up @@ -48,6 +50,9 @@
default-validation-options
validate]

[logout-response
validate-logout]

[state
record-request!
accept-response!
Expand Down
40 changes: 40 additions & 0 deletions src/saml20_clj/sp/logout_response.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
(ns saml20-clj.sp.logout-response
"Handles parsing, validating and querying a LogoutResponse SAML message"
(:require [saml20-clj.coerce :as coerce]
[saml20-clj.sp.response :as response])
(:import [org.opensaml.saml.saml2.core LogoutResponse StatusCode]))

(defmulti validate-logout-response
"Peform a validation operation on a LogoutResponse."
(fn [validation _ _ _]
(keyword validation)))

(defmethod validate-logout-response :default
[& args]
(apply response/validate-response args))

(defmethod validate-logout-response :success
[_ _ ^LogoutResponse decrypted-response _]
(let [status-value (.. decrypted-response getStatus getStatusCode getValue)]
(when-not (= status-value StatusCode/SUCCESS)
(throw (ex-info "LogoutResponse <Status> was not Success" {:status-value status-value})))))

(def default-logout-validation-options
{:response-validators [:signature
:require-signature
:issuer
:success]})


(defn validate-logout
"Decode a ring request into a LogoutResponse SAML object and validate it."
([req idp-cert]
(validate-logout req idp-cert nil))
([req idp-cert options]
(let [options (-> (merge default-logout-validation-options options)
(assoc :idp-cert (coerce/->Credential idp-cert)))
{:keys [response-validators]} options]
(when-let [response (coerce/->LogoutResponse req)]
(doseq [validator response-validators]
(validate-logout-response validator response response options))
response))))
9 changes: 9 additions & 0 deletions test/saml20_clj/coerce_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,12 @@ c7tL1QjbfAUHAQYwmHkWgPP+T2wAv0pOt36GgMCM
(x509-credential-fingerprints (coerce/->Credential {:filename test/keystore-filename
:password test/keystore-password
:alias "sp"}))))))))

(deftest ->LogoutResponse
(let [logout-response-ring {:params {:SAMLResponse "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOkxvZ291dFJlc3BvbnNlIERlc3RpbmF0aW9uPSJodHRwOi8vbG9jYWxob3N0OjMwMDAvYXV0aC9zc28vaGFuZGxlX3NsbyIgSUQ9ImlkODYyMTQxMDMzODM0ODEzMDA4NTY4NzAiIEluUmVzcG9uc2VUbz0iaWQ2NjFiYWM5ZC0xYWMyLTQxNjctOTY0Ni05ZjEyMmY3ODhkMmYiIElzc3VlSW5zdGFudD0iMjAyNS0wMi0yNFQxNzoxOTo1Ny42MTBaIiBWZXJzaW9uPSIyLjAiIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIj48c2FtbDI6SXNzdWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5IiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI+aHR0cDovL3d3dy5va3RhLmNvbS9leGtuZnpoMXA1TlhBTm96MTVkNzwvc2FtbDI6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI2lkODYyMTQxMDMzODM0ODEzMDA4NTY4NzAiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT5yeGt3RVJSRkNVVklyTXdBZDBoMnJ3bE5PeDVaK1UvZzZiWkUrVHpSVlNVPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5jeXdMRW5kdVF6b3VSa3k4K2hNVXkrMUtBVS9Xb2pRcDJDcTZmMmVrNlFyM2hvbGYvcUt6dkpjNVBOTzBSSjh3UTdvdVlGYmR4V0s0Q0VobzQ0Qy9sOTJSZTl6V3djcXdUWjA5WWdKRFNYUjU2NXRsT2VjQ2pqNS9kd05hRUkrNUEzdGVIbC9GMk5qMDdrUGRtSThhWlMyQ2tJOTk4aXoxclV4bVRqSTJIQm9td3QxZ04vQ1NaNys4d2lWZkRmOGVycmZ0SFhGUmhkMzdRTzBob0NmeVlUY2R0b0RGQitTZmxsSCtpRHVyeE8vV2NkMTZoUEJRQ0Z6bW9tdHAwZHkxMW80NlZmMVFwNUlhMEt4allKOU1tNmxkVUE2dHVYUW40aTYzZXI0MkVNZjAzRTFDYUZrZlowRXROU2ZmY1A3UUhZeTk0OHpIcG1vcEprU3UwV0NsNVE9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJRHFEQ0NBcENnQXdJQkFnSUdBWlVhd0VSWE1BMEdDU3FHU0liM0RRRUJDd1VBTUlHVU1Rc3dDUVlEVlFRR0V3SlZVekVUTUJFRwpBMVVFQ0F3S1EyRnNhV1p2Y201cFlURVdNQlFHQTFVRUJ3d05VMkZ1SUVaeVlXNWphWE5qYnpFTk1Bc0dBMVVFQ2d3RVQydDBZVEVVCk1CSUdBMVVFQ3d3TFUxTlBVSEp2ZG1sa1pYSXhGVEFUQmdOVkJBTU1ER1JsZGkwd09EVTBPREl5TlRFY01Cb0dDU3FHU0liM0RRRUoKQVJZTmFXNW1iMEJ2YTNSaExtTnZiVEFlRncweU5UQXlNVGd5TURJNE1qSmFGdzB6TlRBeU1UZ3lNREk1TWpKYU1JR1VNUXN3Q1FZRApWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVXTUJRR0ExVUVCd3dOVTJGdUlFWnlZVzVqYVhOamJ6RU5NQXNHCkExVUVDZ3dFVDJ0MFlURVVNQklHQTFVRUN3d0xVMU5QVUhKdmRtbGtaWEl4RlRBVEJnTlZCQU1NREdSbGRpMHdPRFUwT0RJeU5URWMKTUJvR0NTcUdTSWIzRFFFSkFSWU5hVzVtYjBCdmEzUmhMbU52YlRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQwpnZ0VCQU8zbkhxZUMraXRINmdyUytvSEdMMEVvNXZUR2EycWQ5VzFyWkplcW1BcWJwZXk0WnY2c0VhSEVqL1FJTEVVbGVNOEl5YTJvClErdkxiWTFJU05Fb0R2TCt1MmZDM0NGWjE1VlRnb0hmdEhZOFF5K21vdW1pWjZyQWU2MzdSY1BQT0RmRXlSUzRhY2FZa29TQ0g1UDQKbEtkVnVOQTc2UXN6KzQrelNnbGNmMURmT0JhQ3FuRHJWWXUrbGVaTWxSSVJaL3ZZRW8zT012ejZXTGJnUy9KMXAra2xkZDJGanpFdQp5ZzdRYiszOGZCZ3pkREhSYmZUeGQzRVptTThFblpxQ0tIWklna3ZVZXBaWUp3TlVXM3FVR3dlR0Y0c0JQaWNnQnI2RU0rR2RJeWVmCnFZNzlEV2h4RVhIOEdhMzA2Yzk4L29KajBiUHBlRFVwb001OWZEN3QyekVDQXdFQUFUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUEKQ3VmRnN5NHNGSkhvNk5XMFpSUy9RT0lFWTFVYjNZNGlHQytIM0tXemdsRDJqNTA1N0tqb3U1ZDNvSmIwSDB0OEpJK0tLOUhIMGk5YwpkRldyQXQ2OTZ1MFpmUEk2TVNWV2x5bVQ5WWY4ZkV1VW9xTmlqQ0RtcW96TlhINUpLQUM2TVZTNzdWZXY0amMxdHJFQmVxd0o5ZE5YCnpFMXBCUDh4YnpWSzBET0NQRW5EL0p4eHQyWmR4d1hiZjlCOWUyeGRTNWYrUG8vZjdCbDkrTVoxeWUyR1ZGV1J0cEJmZzUwU2pFdWYKMThMT2NsRjdibGhZZ1g0SnA4TFJVaGp4cVdUb0Qxc1B3QUxwTmw5SkJ5bGJNb2w2QUlLNkxURG8rMitScUNlQzdjU0FZcjY3SXY0cwppQ0RpbU9DMWlkR01vcU1QT1pOTXBmYXZUemxNeFptalAxQmhiUT09PC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWwycDpTdGF0dXMgeG1sbnM6c2FtbDJwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiPjxzYW1sMnA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+PC9zYW1sMnA6U3RhdHVzPjwvc2FtbDJwOkxvZ291dFJlc3BvbnNlPg=="
:RelayState "aHR0cDovL2xvY2FsaG9zdDozMDAwL2F1dGgvc3NvL2hhbmRsZV9zbG8="}
:content-type "application/x-www-form-urlencoded"
:request-method :post}]
(testing "converts ring response into logout response object"
(is (instance? org.opensaml.saml.saml2.core.LogoutResponse
(coerce/->LogoutResponse logout-response-ring))))))
20 changes: 20 additions & 0 deletions test/saml20_clj/sp/logout_response_test.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(ns saml20-clj.sp.logout-response-test
(:require [clojure.test :as t]
[saml20-clj.sp.logout-response :as sut]
[saml20-clj.test :as test]))

(t/deftest validate-response
(t/testing "returns a logout-response without raising"
(let [response (test/ring-logout-response :success "relay-state")]
(t/is (instance? org.opensaml.saml.saml2.core.LogoutResponse
(sut/validate-logout response test/idp-cert)))))
(t/testing "raises when the logout-response is not successful"
(let [response (test/ring-logout-response :authnfailed "relay-state")
exception (try (sut/validate-logout response test/idp-cert)
(catch clojure.lang.ExceptionInfo e
{:msg (ex-message e) :data (ex-data e)}))]
(t/is (not (instance? org.opensaml.saml.saml2.core.LogoutResponse
exception)))
(t/is (= {:msg "LogoutResponse <Status> was not Success"
:data {:status-value org.opensaml.saml.saml2.core.StatusCode/AUTHN_FAILED}}
exception)))))
17 changes: 16 additions & 1 deletion test/saml20_clj/test.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(ns saml20-clj.test
"Test utils.")
"Test utils."
(:require
[saml20-clj.encode-decode :as encode-decode]))

(def idp-entity-id "idp.example.com")
(def idp-uri "https://idp.example.com")
Expand Down Expand Up @@ -40,6 +42,19 @@
(def metadata-with-key-info (sample-file "metadata-with-keyinfo.xml"))
(def metadata-without-key-info (sample-file "metadata-without-keyinfo.xml"))

;; Logout Response

(defn ring-logout-response
"Return a ring map of the logout response"
[status relay-state]
(let [response (sample-file (condp = status
:success "logout-response-success-with-signature.xml"
:authnfailed "logout-response-authnfailure-with-signature.xml"))]
{:params {:SAMLResponse (encode-decode/str->base64 response)
:RelayState (encode-decode/str->base64 relay-state)}
:request-method :post
:content-type "application/x-www-form-urlencoded"}))

;;
;; Confirmation Data
;;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfxac405874-7b3c-fcfb-084c-e3405b28faa4" Version="2.0" IssueInstant="2014-07-18T01:13:06Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_21df91a89767879fc0f7df6a1490c6000c81644d">
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#pfxac405874-7b3c-fcfb-084c-e3405b28faa4"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>MupMW1Xq3fa+tSg21WjYf0AiNDo=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>RmIKpmDUheMJY2KG4XaZ4siD+dIYhiMqMNcHkl8jVrB+DcRqyNCHvNtYyV3Da4tMQVS0nAOAczGJnojD9EsZXiJkvEZmMDIJup/yaX2VZ4p1Wu0hXvVvucUObL6wEquKsYwWyXPwDXfgb1kqY2hgmUMImT5WwDyFfSwdT5E+GTg=</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICZjCCAc+gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBQMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTETMBEGA1UECgwKRXhhbXBsZSBTUDEXMBUGA1UEAwwOc3AuZXhhbXBsZS5jb20wHhcNMjAwOTIzMTc0MzA2WhcNMzAwOTIxMTc0MzA2WjBQMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTETMBEGA1UECgwKRXhhbXBsZSBTUDEXMBUGA1UEAwwOc3AuZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMCOR6lM1raadHr3MnDU7ydGHUmMhZ5ZImwSHcxYrY6/F3TW+S6CPMuAfHJsNQZ57nG4wUhNCbfXdumfVxzoPMzD7oivKKVxeMK6HaUuGsGg9OK4ON++EVxomWdmPyJdHpiUaGveGU0BQgzI7aqNibncPYPxJgK9DZEIfDjp05lDAgMBAAGjUDBOMB0GA1UdDgQWBBStKfCHxILkLbv2tAEK54+Wn/xF+zAfBgNVHSMEGDAWgBStKfCHxILkLbv2tAEK54+Wn/xF+zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBAIRA7mJdPPmTWc3wsPLDv+nMeR0nr5a6r8dZU5lOTqGfC43YvJ1NEysO3AB6YuiG1KKXERxtlISyYvU9wNrna2IPDU0njcU/a3dEBqa32lD3GxfUvbpzIcZovBYqQ7Jhfa86GvNKxRoyUEExVqyHh6i44S4NCJvr8IdnRilYBksl</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"/>
</samlp:Status>
</samlp:LogoutResponse>
11 changes: 11 additions & 0 deletions test/saml20_clj/test/logout-response-success-with-signature.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfx9566981a-9a4e-9ec8-bcc1-cbef81faeae0" Version="2.0" IssueInstant="2014-07-18T01:13:06Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_21df91a89767879fc0f7df6a1490c6000c81644d">
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#pfx9566981a-9a4e-9ec8-bcc1-cbef81faeae0"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>m7XJQJUS2sYpvSii5girw9RHnMw=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>vz90lqoqtksqLgpxxt7pn29kykHZRONYoHcapZvp0Nc12k/jx+oZ4OpXOEf6YvktOup3BaB+t05VNFpuJckAa//HunwLkZvdfWt2eSyn+Bq5b0+5fnAVWjK2cqh1X0mfZFOXi7DvV1wLtXr8Tgb5QT4tD73YuTI29nT9Gs+ggkE=</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICZjCCAc+gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBQMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTETMBEGA1UECgwKRXhhbXBsZSBTUDEXMBUGA1UEAwwOc3AuZXhhbXBsZS5jb20wHhcNMjAwOTIzMTc0MzA2WhcNMzAwOTIxMTc0MzA2WjBQMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTETMBEGA1UECgwKRXhhbXBsZSBTUDEXMBUGA1UEAwwOc3AuZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMCOR6lM1raadHr3MnDU7ydGHUmMhZ5ZImwSHcxYrY6/F3TW+S6CPMuAfHJsNQZ57nG4wUhNCbfXdumfVxzoPMzD7oivKKVxeMK6HaUuGsGg9OK4ON++EVxomWdmPyJdHpiUaGveGU0BQgzI7aqNibncPYPxJgK9DZEIfDjp05lDAgMBAAGjUDBOMB0GA1UdDgQWBBStKfCHxILkLbv2tAEK54+Wn/xF+zAfBgNVHSMEGDAWgBStKfCHxILkLbv2tAEK54+Wn/xF+zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBAIRA7mJdPPmTWc3wsPLDv+nMeR0nr5a6r8dZU5lOTqGfC43YvJ1NEysO3AB6YuiG1KKXERxtlISyYvU9wNrna2IPDU0njcU/a3dEBqa32lD3GxfUvbpzIcZovBYqQ7Jhfa86GvNKxRoyUEExVqyHh6i44S4NCJvr8IdnRilYBksl</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
</samlp:LogoutResponse>
Loading