forked from k2n/saml20-clj
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: port metadata generation off of hiccup
Allows us to fully remove hiccup XML generation for just using the opensaml library and clean up other dead code and tests from using the library directly. Adds tests for metadata generation.
- Loading branch information
Showing
11 changed files
with
142 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,61 @@ | ||
(ns saml20-clj.sp.metadata | ||
(:require [clojure.string :as str] | ||
[saml20-clj.coerce :as coerce] | ||
[saml20-clj.encode-decode :as encode])) | ||
[saml20-clj.coerce :as coerce]) | ||
(:import org.opensaml.core.xml.util.XMLObjectSupport | ||
org.opensaml.saml.common.xml.SAMLConstants | ||
org.opensaml.saml.saml2.core.NameIDType | ||
[org.opensaml.saml.saml2.metadata.impl AssertionConsumerServiceBuilder EntityDescriptorBuilder KeyDescriptorBuilder NameIDFormatBuilder SingleLogoutServiceBuilder SPSSODescriptorBuilder] | ||
org.opensaml.security.credential.UsageType | ||
org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory)) | ||
|
||
(def ^:private name-id-formats | ||
[NameIDType/EMAIL NameIDType/TRANSIENT NameIDType/PERSISTENT NameIDType/UNSPECIFIED NameIDType/X509_SUBJECT]) | ||
|
||
(def ^:private cert-uses | ||
[UsageType/SIGNING UsageType/ENCRYPTION]) | ||
|
||
(defn metadata [{:keys [app-name acs-url slo-url sp-cert | ||
requests-signed | ||
want-assertions-signed] | ||
^Boolean requests-signed | ||
^Boolean want-assertions-signed] | ||
:or {want-assertions-signed true | ||
requests-signed true}}] | ||
(let [encoded-cert (some-> ^java.security.cert.X509Certificate sp-cert | ||
.getEncoded | ||
encode/encode-base64 | ||
encode/bytes->str)] | ||
(coerce/->xml-string | ||
[:md:EntityDescriptor {:xmlns:md "urn:oasis:names:tc:SAML:2.0:metadata" | ||
:ID (str/replace acs-url #"[:/]" "_") | ||
:entityID app-name} | ||
[:md:SPSSODescriptor {:AuthnRequestsSigned (str requests-signed) | ||
:WantAssertionsSigned (str want-assertions-signed) | ||
:protocolSupportEnumeration "urn:oasis:names:tc:SAML:2.0:protocol"} | ||
(when encoded-cert | ||
[:md:KeyDescriptor {:use "signing"} | ||
[:ds:KeyInfo {:xmlns:ds "http://www.w3.org/2000/09/xmldsig#"} | ||
[:ds:X509Data | ||
[:ds:X509Certificate encoded-cert]]]]) | ||
(when encoded-cert | ||
[:md:KeyDescriptor {:use "encryption"} | ||
[:ds:KeyInfo {:xmlns:ds "http://www.w3.org/2000/09/xmldsig#"} | ||
[:ds:X509Data | ||
[:ds:X509Certificate encoded-cert]]]]) | ||
(when slo-url | ||
[:md:SingleLogoutService {:Binding "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" :Location slo-url}]) | ||
[:md:NameIDFormat "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"] | ||
[:md:NameIDFormat "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"] | ||
[:md:NameIDFormat "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"] | ||
[:md:NameIDFormat "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"] | ||
[:md:NameIDFormat "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName"] | ||
[:md:AssertionConsumerService {:Binding "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" | ||
:Location acs-url | ||
:index "0" | ||
:isDefault "true"}]]]))) | ||
(let [entity-descriptor (doto (.buildObject (EntityDescriptorBuilder.)) | ||
(.setID (str/replace acs-url #"[:/]" "_")) | ||
(.setEntityID app-name)) | ||
sp-sso-descriptor (doto (.buildObject (SPSSODescriptorBuilder.)) | ||
(.setAuthnRequestsSigned requests-signed) | ||
(.setWantAssertionsSigned want-assertions-signed) | ||
(.addSupportedProtocol SAMLConstants/SAML20P_NS))] | ||
|
||
(.. sp-sso-descriptor | ||
(getAssertionConsumerServices) | ||
(add (doto (.buildObject (AssertionConsumerServiceBuilder.)) | ||
(.setIndex (Integer. 0)) | ||
(.setIsDefault true) | ||
(.setLocation acs-url) | ||
(.setBinding SAMLConstants/SAML2_POST_BINDING_URI)))) | ||
(doseq [name-id-format name-id-formats] | ||
(.. sp-sso-descriptor | ||
(getNameIDFormats) | ||
(add (doto (.buildObject (NameIDFormatBuilder.)) | ||
(.setURI name-id-format))))) | ||
(when sp-cert | ||
(let [key-info-generator (.newInstance (doto (X509KeyInfoGeneratorFactory.) | ||
(.setEmitEntityCertificate true)))] | ||
(doseq [cert-use cert-uses] | ||
(.. sp-sso-descriptor | ||
(getKeyDescriptors) | ||
(add (doto (.buildObject (KeyDescriptorBuilder.)) | ||
(.setUse cert-use) | ||
(.setKeyInfo (.generate key-info-generator sp-cert)))))))) | ||
(when slo-url | ||
(.. sp-sso-descriptor | ||
(getSingleLogoutServices) | ||
(add (doto (.buildObject (SingleLogoutServiceBuilder.)) | ||
(.setBinding SAMLConstants/SAML2_POST_BINDING_URI) | ||
(.setLocation slo-url))))) | ||
|
||
(.. entity-descriptor | ||
(getRoleDescriptors) | ||
(add sp-sso-descriptor)) | ||
(coerce/->xml-string (XMLObjectSupport/marshall entity-descriptor)))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
(ns saml20-clj.sp.metadata-test | ||
(:require [clojure.test :as t] | ||
[saml20-clj.coerce :as coerce] | ||
[saml20-clj.sp.metadata :as sut] | ||
[saml20-clj.test :as test])) | ||
|
||
(t/deftest metadata-generation | ||
(t/testing "generates metadata with keyinfo" | ||
(t/is (= test/metadata-with-key-info | ||
(saml20-clj.sp.metadata/metadata {:app-name "metabase" | ||
:acs-url "http://acs.example.com" | ||
:slo-url "http://slo.example.com" | ||
:sp-cert (coerce/->Credential test/sp-cert)})))) | ||
(t/testing "generates metadata with-out keyinfo" | ||
(t/is (= test/metadata-without-key-info | ||
(saml20-clj.sp.metadata/metadata {:app-name "metabase" | ||
:acs-url "http://acs.example.com" | ||
:slo-url "http://slo.example.com"}))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="http___acs.example.com" entityID="metabase"> | ||
<md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> | ||
<md:KeyDescriptor use="signing"> | ||
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> | ||
<ds:X509Data> | ||
<ds:X509Certificate>MIICZjCCAc+gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBQMQswCQYDVQQGEwJ1czETMBEGA1UECAwK | ||
Q2FsaWZvcm5pYTETMBEGA1UECgwKRXhhbXBsZSBTUDEXMBUGA1UEAwwOc3AuZXhhbXBsZS5jb20w | ||
HhcNMjAwOTIzMTc0MzA2WhcNMzAwOTIxMTc0MzA2WjBQMQswCQYDVQQGEwJ1czETMBEGA1UECAwK | ||
Q2FsaWZvcm5pYTETMBEGA1UECgwKRXhhbXBsZSBTUDEXMBUGA1UEAwwOc3AuZXhhbXBsZS5jb20w | ||
gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMCOR6lM1raadHr3MnDU7ydGHUmMhZ5ZImwSHcxY | ||
rY6/F3TW+S6CPMuAfHJsNQZ57nG4wUhNCbfXdumfVxzoPMzD7oivKKVxeMK6HaUuGsGg9OK4ON++ | ||
EVxomWdmPyJdHpiUaGveGU0BQgzI7aqNibncPYPxJgK9DZEIfDjp05lDAgMBAAGjUDBOMB0GA1Ud | ||
DgQWBBStKfCHxILkLbv2tAEK54+Wn/xF+zAfBgNVHSMEGDAWgBStKfCHxILkLbv2tAEK54+Wn/xF | ||
+zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBAIRA7mJdPPmTWc3wsPLDv+nMeR0nr5a6 | ||
r8dZU5lOTqGfC43YvJ1NEysO3AB6YuiG1KKXERxtlISyYvU9wNrna2IPDU0njcU/a3dEBqa32lD3 | ||
GxfUvbpzIcZovBYqQ7Jhfa86GvNKxRoyUEExVqyHh6i44S4NCJvr8IdnRilYBksl</ds:X509Certificate> | ||
</ds:X509Data> | ||
</ds:KeyInfo> | ||
</md:KeyDescriptor> | ||
<md:KeyDescriptor use="encryption"> | ||
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> | ||
<ds:X509Data> | ||
<ds:X509Certificate>MIICZjCCAc+gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBQMQswCQYDVQQGEwJ1czETMBEGA1UECAwK | ||
Q2FsaWZvcm5pYTETMBEGA1UECgwKRXhhbXBsZSBTUDEXMBUGA1UEAwwOc3AuZXhhbXBsZS5jb20w | ||
HhcNMjAwOTIzMTc0MzA2WhcNMzAwOTIxMTc0MzA2WjBQMQswCQYDVQQGEwJ1czETMBEGA1UECAwK | ||
Q2FsaWZvcm5pYTETMBEGA1UECgwKRXhhbXBsZSBTUDEXMBUGA1UEAwwOc3AuZXhhbXBsZS5jb20w | ||
gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMCOR6lM1raadHr3MnDU7ydGHUmMhZ5ZImwSHcxY | ||
rY6/F3TW+S6CPMuAfHJsNQZ57nG4wUhNCbfXdumfVxzoPMzD7oivKKVxeMK6HaUuGsGg9OK4ON++ | ||
EVxomWdmPyJdHpiUaGveGU0BQgzI7aqNibncPYPxJgK9DZEIfDjp05lDAgMBAAGjUDBOMB0GA1Ud | ||
DgQWBBStKfCHxILkLbv2tAEK54+Wn/xF+zAfBgNVHSMEGDAWgBStKfCHxILkLbv2tAEK54+Wn/xF | ||
+zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBAIRA7mJdPPmTWc3wsPLDv+nMeR0nr5a6 | ||
r8dZU5lOTqGfC43YvJ1NEysO3AB6YuiG1KKXERxtlISyYvU9wNrna2IPDU0njcU/a3dEBqa32lD3 | ||
GxfUvbpzIcZovBYqQ7Jhfa86GvNKxRoyUEExVqyHh6i44S4NCJvr8IdnRilYBksl</ds:X509Certificate> | ||
</ds:X509Data> | ||
</ds:KeyInfo> | ||
</md:KeyDescriptor> | ||
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://slo.example.com"/> | ||
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat> | ||
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat> | ||
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat> | ||
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat> | ||
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</md:NameIDFormat> | ||
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://acs.example.com" index="0" isDefault="true"/> | ||
</md:SPSSODescriptor> | ||
</md:EntityDescriptor> |
Oops, something went wrong.