Skip to content

Instantly share code, notes, and snippets.

@jebberjeb
Created September 27, 2016 18:46
Show Gist options
  • Save jebberjeb/4e87cf04dc49321285270e1dda3b4737 to your computer and use it in GitHub Desktop.
Save jebberjeb/4e87cf04dc49321285270e1dda3b4737 to your computer and use it in GitHub Desktop.
Parse SAML metadata with clojure spec
(ns foo.saml
(:require
[clojure.spec :as s]
[clojure.string :as string]
[clojure.xml :as xml])
(:import
(java.io ByteArrayInputStream)))
(s/def :sso/Binding #{"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"})
(s/def :sso/attrs (s/keys :req-un [:sso/Binding ::Location]))
(s/def :sso/tag #{:SingleSignOnService})
(s/def :sso/node (s/keys :req-un [:sso/attrs :sso/tag]))
(s/def :cert/tag #{:ds:X509Certificate})
(s/def :cert/node (s/keys :req-un [:cert/tag]))
(s/fdef parse-metadata
:args (s/cat :xml string?)
:ret (s/keys :req-un [::x509-cert ::sso-http-post-uri]))
(defn first-match
"Find the first match for a spec."
[xs spec]
(first (filter (partial s/valid? spec) xs)))
(defn parse-metadata
"Parses SAML metadata xml. Return data as a map."
[xml]
(let [nodes (xml-seq (xml/parse (ByteArrayInputStream. (.getBytes xml))))]
{:sso-http-post-uri (-> (first-match nodes :sso/node)
:attrs
:Location)
:x509-cert (-> (first-match nodes :cert/node)
:content
first
string/trim
(string/replace " " ""))}))
(comment
;; non-spec, non-zipper version
(let [http-redirect-attr "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
idp-sso-descriptor (->> (xml/parse (java.io.ByteArrayInputStream. (.getBytes s)))
:content
(filter #(= :IDPSSODescriptor (:tag %)))
first
:content)]
{:sso-http-redirect (->> idp-sso-descriptor
(filter #(= :SingleSignOnService (:tag %)))
(map :attrs)
(filter #(= http-redirect-attr (% :Binding)))
first
:Location)
:x509-certificate 'bar}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment