keycloak-aplcache

idp descriptor

10/28/2014 2:49:31 PM

Details

diff --git a/docbook/reference/en/en-US/modules/saml.xml b/docbook/reference/en/en-US/modules/saml.xml
index 8521907..5ba2e00 100755
--- a/docbook/reference/en/en-US/modules/saml.xml
+++ b/docbook/reference/en/en-US/modules/saml.xml
@@ -100,11 +100,14 @@
         in the response.
     </para>
     <section>
-        <title>SAML Entity Descriptor Import</title>
+        <title>SAML Entity Descriptor</title>
         <para>
             If you go into the admin console in the application list menu page you will see an <literal>Import</literal>
             button.  If you click on that you can import SAML Service Provider definitions using the <ulink url="http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf">Entity Descriptor</ulink>
             format described in SAML 2.0.  You should review all the information there to make sure everything is set up correctly.
         </para>
+        <para>
+            Each realm has a URL where you can view the XML entity descriptor for the IDP.  <literal>root/realms/{realm}/protocol/saml/descriptor</literal>
+        </para>
     </section>
 </chapter>
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index 8f51234..1c8c317 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -19,7 +19,9 @@ import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.oidc.OpenIDConnectService;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
+import org.keycloak.services.resources.RealmsResource;
 import org.keycloak.services.resources.flows.Flows;
+import org.keycloak.util.StreamUtil;
 import org.picketlink.common.constants.GeneralConstants;
 import org.picketlink.identity.federation.core.saml.v2.common.SAMLDocumentHolder;
 import org.picketlink.identity.federation.saml.v2.SAML2Object;
@@ -32,6 +34,8 @@ import javax.ws.rs.Consumes;
 import javax.ws.rs.FormParam;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
@@ -42,6 +46,7 @@ import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.ext.Providers;
+import java.io.InputStream;
 import java.net.URI;
 import java.security.PublicKey;
 import java.security.Signature;
@@ -379,4 +384,19 @@ public class SamlService {
         return new PostBindingProtocol().execute(samlRequest, samlResponse, relayState);
     }
 
+    @GET
+    @Path("descriptor")
+    @Produces(MediaType.APPLICATION_XML)
+    public String getDescriptor() throws Exception {
+        InputStream is = getClass().getResourceAsStream("/idp-metadata-template.xml");
+        String template = StreamUtil.readString(is);
+        template = template.replace("${idp.entityID}", RealmsResource.realmBaseUrl(uriInfo).build(realm.getName()).toString());
+        template = template.replace("${idp.sso.HTTP-POST}", RealmsResource.protocolUrl(uriInfo).build(realm.getName(), SamlProtocol.LOGIN_PROTOCOL).toString());
+        template = template.replace("${idp.sso.HTTP-Redirect}", RealmsResource.protocolUrl(uriInfo).build(realm.getName(), SamlProtocol.LOGIN_PROTOCOL).toString());
+        template = template.replace("${idp.sls.HTTP-POST}", RealmsResource.protocolUrl(uriInfo).build(realm.getName(), SamlProtocol.LOGIN_PROTOCOL).toString());
+        template = template.replace("${idp.signing.certificate}", realm.getCertificatePem());
+        return template;
+
+    }
+
 }
diff --git a/saml/saml-protocol/src/main/resources/idp-metadata-template.xml b/saml/saml-protocol/src/main/resources/idp-metadata-template.xml
new file mode 100755
index 0000000..5468cfc
--- /dev/null
+++ b/saml/saml-protocol/src/main/resources/idp-metadata-template.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<EntitiesDescriptor Name="urn:keycloak"
+	xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+	xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<EntityDescriptor entityID="${idp.entityID}">
+		<IDPSSODescriptor WantAuthnRequestsSigned="true"
+			protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+			<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+			</NameIDFormat>
+			<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+				Location="${idp.sso.HTTP-POST}" />
+			<SingleSignOnService
+				Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+				Location="${idp.sso.HTTP-Redirect}" />
+			<SingleLogoutService
+				Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+				Location="${idp.sls.HTTP-POST}" />
+            <KeyDescriptor use="signing">
+                <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
+                    <dsig:X509Data>
+                        <dsig:X509Certificate>
+                            ${idp.signing.certificate}
+                        </dsig:X509Certificate>
+                    </dsig:X509Data>
+                </dsig:KeyInfo>
+            </KeyDescriptor>
+		</IDPSSODescriptor>
+	</EntityDescriptor>
+</EntitiesDescriptor>
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index 2feeaaa..a7fe6c4 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -77,6 +77,14 @@ public class RealmsResource {
         return base.path(RealmsResource.class).path(RealmsResource.class, "getAccountService");
     }
 
+    public static UriBuilder protocolUrl(UriBuilder base) {
+        return base.path(RealmsResource.class).path(RealmsResource.class, "getProtocol");
+    }
+
+    public static UriBuilder protocolUrl(UriInfo uriInfo) {
+        return uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(RealmsResource.class, "getProtocol");
+    }
+
     @Path("{realm}/login-status-iframe.html")
     @GET
     @Produces(MediaType.TEXT_HTML)