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)