Merge pull request #804 from patriot1burke/master

idp descriptor
This commit is contained in:
Bill Burke 2014-10-28 12:49:54 -04:00
commit eaaaf91963
5 changed files with 75 additions and 2 deletions

View file

@ -88,10 +88,26 @@
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</para> </para>
<para>
You have to specify an admin URL if you want logout to work. This should be a URL that will except single logout
requests from the Keycloak server. You should also specify a default redirect url. Keycloak will redirect to this
url after single logout is complete.
</para>
<para> <para>
One thing to note is that roles are not treated as a hierarchy. So, any role mappings will just be added One thing to note is that roles are not treated as a hierarchy. So, any role mappings will just be added
to the role attributes in the SAML document using their basic name. So, if you have multiple applicaiton roles to the role attributes in the SAML document using their basic name. So, if you have multiple application roles
you might have name collisions. You can use the Scope Mapping menu item to control which role mappings are set you might have name collisions. You can use the Scope Mapping menu item to control which role mappings are set
in the response. in the response.
</para> </para>
<section>
<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> </chapter>

View file

@ -102,7 +102,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
} }
deploymentContext = new AdapterDeploymentContext(kd); deploymentContext = new AdapterDeploymentContext(kd);
context.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext); context.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer(), getObjectName()); AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer());
setNext(actions); setNext(actions);
nodesRegistrationManagement = new NodesRegistrationManagement(); nodesRegistrationManagement = new NodesRegistrationManagement();

View file

@ -19,7 +19,9 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.OpenIDConnectService; import org.keycloak.protocol.oidc.OpenIDConnectService;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.flows.Flows; import org.keycloak.services.resources.flows.Flows;
import org.keycloak.util.StreamUtil;
import org.picketlink.common.constants.GeneralConstants; import org.picketlink.common.constants.GeneralConstants;
import org.picketlink.identity.federation.core.saml.v2.common.SAMLDocumentHolder; import org.picketlink.identity.federation.core.saml.v2.common.SAMLDocumentHolder;
import org.picketlink.identity.federation.saml.v2.SAML2Object; 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.FormParam;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; 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.UriBuilder;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers; import javax.ws.rs.ext.Providers;
import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.Signature; import java.security.Signature;
@ -379,4 +384,19 @@ public class SamlService {
return new PostBindingProtocol().execute(samlRequest, samlResponse, relayState); 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;
}
} }

View file

@ -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>

View file

@ -77,6 +77,14 @@ public class RealmsResource {
return base.path(RealmsResource.class).path(RealmsResource.class, "getAccountService"); 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") @Path("{realm}/login-status-iframe.html")
@GET @GET
@Produces(MediaType.TEXT_HTML) @Produces(MediaType.TEXT_HTML)