more saml config

This commit is contained in:
Bill Burke 2015-02-11 21:56:16 -05:00
parent 889fe8dd8c
commit 9b053e6918
8 changed files with 119 additions and 18 deletions

View file

@ -96,12 +96,78 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Force Name ID Format</term>
<listitem>
<para>
If the request has a name ID policy, ignore it and used the value configured in the admin console
under Name ID Format
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Name ID Format</term>
<listitem>
<para>
Name ID Format for the subject. If no name ID policy is specified in the request or if the
Force Name ID Format attribute is true, this value is used.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Master SAML Processing URL</term>
<listitem>
<para>
This URL will be used for all SAML requests and responsed directed to the SP. It will be used
as the Assertion Consumer Service URL and the Single Logout Service URL. If a login request
contains the Assertion Consumer Service URL, that will take precedence, but this URL must be valided
by a registered Valid Redirect URI pattern
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Assertion Consumer Service POST Binding URL</term>
<listitem>
<para>
POST Binding URL for the Assertion Consumer Service.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Assertion Consumer Service Redirect Binding URL</term>
<listitem>
<para>
Redirect Binding URL for the Assertion Consumer Service.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Logout Service POST Binding URL</term>
<listitem>
<para>
POST Binding URL for the Logout Service.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Logout Service Redirect Binding URL</term>
<listitem>
<para>
Redirect Binding URL for the Logout Service.
</para>
</listitem>
</varlistentry>
</variablelist>
</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.
For login to work, Keycloak needs to be able to resolve the URL for the Assertion Consumer Service of the SP. If
you are relying on the SP to provide this URL in the login request, then you must register valid redirect uri patterns
so that this URL can be validated. You can set the Master SAML Processing URL as well, or alternatively, you can
specify the Assertion Consumer Service URL per binding.
</para>
<para>
For logout to work, you must specify a Master SAML Processing URL, or the Loging Service URL for the binding
you want Keycloak to use.
</para>
<para>
One thing to note is that roles are not treated as a hierarchy. So, any role mappings will just be added

View file

@ -221,16 +221,16 @@
<fieldset>
<legend collapsed><span class="text">Fine Grain SAML Endpoint Configuration</span> <span tooltip-placement="right" tooltip="Expand this section to configure exact URLs for Assertion Consumer and Single Logout Service." class="fa fa-info-circle"></span></legend>
<div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
<label class="col-sm-2 control-label" for="logoutPostBinding">Assertion Consumer Service POST Binding URL</label>
<label class="col-sm-2 control-label" for="consumerServicePost">Assertion Consumer Service POST Binding URL</label>
<div class="col-sm-6">
<input ng-model="application.attributes.saml_assertion_consumer_service_url_post" class="form-control" type="text" name="logoutPostBinding" id="logoutPostBinding" />
<input ng-model="application.attributes.saml_assertion_consumer_url_post" class="form-control" type="text" name="consumerServicePost" id="consumerServicePost" />
</div>
<span tooltip-placement="right" tooltip="SAML POST Binding URL for the application's assertion consumer service (login responses). You can leave this blank if you do not have a URL for this binding." class="fa fa-info-circle"></span>
</div>
<div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
<label class="col-sm-2 control-label" for="logoutPostBinding">Assertion Consumer Service Redirect Binding URL</label>
<label class="col-sm-2 control-label" for="consumerServiceRedirect">Assertion Consumer Service Redirect Binding URL</label>
<div class="col-sm-6">
<input ng-model="application.attributes.saml_assertion_consumer_service_url_redirect" class="form-control" type="text" name="logoutRedirectBinding" id="logoutRedirectBinding" />
<input ng-model="application.attributes.saml_assertion_consumer_url_redirect" class="form-control" type="text" name="consumerServiceRedirect" id="consumerServiceRedirect" />
</div>
<span tooltip-placement="right" tooltip="SAML Redirect Binding URL for the application's assertion consumer service (login responses). You can leave this blank if you do not have a URL for this binding." class="fa fa-info-circle"></span>
</div>

View file

@ -89,15 +89,20 @@ public class EntityDescriptorImporterService {
if (spDescriptorType.isWantAssertionsSigned()) {
app.setAttribute(SamlProtocol.SAML_ASSERTION_SIGNATURE, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
}
String adminUrl = getLogoutLocation(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
if (adminUrl != null) app.setManagementUrl(adminUrl);
String logoutPost = getLogoutLocation(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
if (logoutPost != null) app.setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE, logoutPost);
String logoutRedirect = getLogoutLocation(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
if (logoutPost != null) app.setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, logoutRedirect);
String urlPattern = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
if (urlPattern == null) {
urlPattern = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
String assertionConsumerServicePostBinding = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
if (assertionConsumerServicePostBinding != null) {
app.setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE, assertionConsumerServicePostBinding);
app.addRedirectUri(assertionConsumerServicePostBinding);
}
if (urlPattern != null) {
app.addRedirectUri(urlPattern);
String assertionConsumerServiceRedirectBinding = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
if (assertionConsumerServiceRedirectBinding != null) {
app.setAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE, assertionConsumerServiceRedirectBinding);
app.addRedirectUri(assertionConsumerServiceRedirectBinding);
}
for (KeyDescriptorType keyDescriptor : spDescriptorType.getKeyDescriptor()) {

View file

@ -51,6 +51,8 @@ public class SamlProtocol implements LoginProtocol {
public static final String SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE = "saml_assertion_consumer_url_redirect";
public static final String SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE = "saml_single_logout_service_url_post";
public static final String SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE = "saml_single_logout_service_url_redirect";
public static final String SAML_FORCE_NAME_ID_FORMAT_ATTRIBUTE = "saml_force_name_id_format";
public static final String SAML_NAME_ID_FORMAT_ATTRIBUTE = "saml_name_id_format";
public static final String LOGIN_PROTOCOL = "saml";
public static final String SAML_BINDING = "saml_binding";
public static final String SAML_POST_BINDING = "post";
@ -175,10 +177,30 @@ public class SamlProtocol implements LoginProtocol {
protected String getNameIdFormat(ClientSessionModel clientSession) {
String nameIdFormat = clientSession.getNote(GeneralConstants.NAMEID_FORMAT);
ClientModel client = clientSession.getClient();
boolean forceFormat = forceNameIdFormat(client);
String configuredNameIdFormat = client.getAttribute(SAML_NAME_ID_FORMAT_ATTRIBUTE);
if ((nameIdFormat == null || forceFormat) && configuredNameIdFormat != null) {
if (configuredNameIdFormat.equals("email")) {
nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get();
} else if (configuredNameIdFormat.equals("persistent")) {
nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get();
} else if (configuredNameIdFormat.equals("transient")) {
nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_TRANSIENT.get();
} else if (configuredNameIdFormat.equals("username")) {
nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get();
} else {
nameIdFormat = JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get();
}
}
if(nameIdFormat == null) return SAML_DEFAULT_NAMEID_FORMAT;
return nameIdFormat;
}
public static boolean forceNameIdFormat(ClientModel client) {
return "true".equals(client.getAttribute(SAML_FORCE_NAME_ID_FORMAT_ATTRIBUTE));
}
protected String getNameId(String nameIdFormat, ClientSessionModel clientSession, UserSessionModel userSession) {
if (nameIdFormat.equals(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get())) {
return userSession.getUser().getEmail();

View file

@ -245,7 +245,7 @@ public class SamlService {
// Handle NameIDPolicy from SP
NameIDPolicyType nameIdPolicy = requestAbstractType.getNameIDPolicy();
if(nameIdPolicy != null) {
if(nameIdPolicy != null && !SamlProtocol.forceNameIdFormat(client)) {
String nameIdFormat = nameIdPolicy.getFormat().toString();
// TODO: Handle AllowCreate too, relevant for persistent NameID.
if(isSupportedNameIdFormat(nameIdFormat)) {
@ -254,8 +254,6 @@ public class SamlService {
event.error(Errors.INVALID_TOKEN);
return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unsupported NameIDFormat.");
}
} else {
clientSession.setNote(GeneralConstants.NAMEID_FORMAT, JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get());
}
Response response = authManager.checkNonFormAuthentication(session, clientSession, realm, uriInfo, request, clientConnection, headers, event);

View file

@ -24,6 +24,14 @@
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-dependencies-server-all</artifactId>

View file

@ -21,7 +21,7 @@
class="org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler"/>
<Handler
class="org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler">
<Option Key="NAMEID_FORMAT" Value="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
<!-- <Option Key="NAMEID_FORMAT" Value="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/> -->
</Handler>
<Handler
class="org.picketlink.identity.federation.web.handlers.saml2.RolesGenerationHandler"/>

View file

@ -123,6 +123,8 @@
"http://localhost:8081/sales-post-sig-email/*"
],
"attributes": {
"saml_force_name_id_format": "true",
"saml_name_id_format": "email",
"saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-sig-email",
"saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-sig-email",
"saml_single_logout_service_url_post": "http://localhost:8081/sales-post-sig-email",