keycloak-developers
Changes
broker/saml/pom.xml 6(+6 -0)
forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html 14(+14 -0)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2AuthnRequestBuilder.java 98(+98 -0)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutResponseBuilder.java 7(+1 -6)
Details
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/AuthenticationResponse.java b/broker/core/src/main/java/org/keycloak/broker/provider/AuthenticationResponse.java
index 641c7da..5e54093 100644
--- a/broker/core/src/main/java/org/keycloak/broker/provider/AuthenticationResponse.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/AuthenticationResponse.java
@@ -54,4 +54,7 @@ public class AuthenticationResponse {
return new AuthenticationResponse(Response.temporaryRedirect(url).build());
}
+ public static AuthenticationResponse fromResponse(Response response) {
+ return new AuthenticationResponse(response);
+ }
}
broker/saml/pom.xml 6(+6 -0)
diff --git a/broker/saml/pom.xml b/broker/saml/pom.xml
index a0e6706..f518b3c 100755
--- a/broker/saml/pom.xml
+++ b/broker/saml/pom.xml
@@ -22,6 +22,12 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-saml-protocol</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-federation</artifactId>
</dependency>
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 59863f8..05db2c2 100644
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -22,6 +22,8 @@ import org.keycloak.broker.provider.AbstractIdentityProvider;
import org.keycloak.broker.provider.AuthenticationRequest;
import org.keycloak.broker.provider.AuthenticationResponse;
import org.keycloak.broker.provider.FederatedIdentity;
+import org.keycloak.protocol.saml.SAML2AuthnRequestBuilder;
+import org.keycloak.protocol.saml.SAML2NameIDPolicyBuilder;
import org.picketlink.common.constants.JBossSAMLConstants;
import org.picketlink.common.constants.JBossSAMLURIConstants;
import org.picketlink.common.exceptions.ProcessingException;
@@ -31,7 +33,6 @@ import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request;
import org.picketlink.identity.federation.api.saml.v2.response.SAML2Response;
import org.picketlink.identity.federation.api.saml.v2.sig.SAML2Signature;
import org.picketlink.identity.federation.core.parsers.saml.SAMLParser;
-import org.picketlink.identity.federation.core.saml.v2.common.IDGenerator;
import org.picketlink.identity.federation.core.saml.v2.common.SAMLDocumentHolder;
import org.picketlink.identity.federation.core.util.JAXPValidationUtil;
import org.picketlink.identity.federation.core.util.XMLEncryptionUtil;
@@ -41,7 +42,6 @@ import org.picketlink.identity.federation.saml.v2.assertion.EncryptedAssertionTy
import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
import org.picketlink.identity.federation.saml.v2.assertion.SubjectType;
import org.picketlink.identity.federation.saml.v2.assertion.SubjectType.STSubType;
-import org.picketlink.identity.federation.saml.v2.protocol.AuthnRequestType;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType.RTChoiceType;
import org.picketlink.identity.federation.saml.v2.protocol.StatusCodeType;
@@ -53,10 +53,10 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
+import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.xml.namespace.QName;
-import java.net.URI;
import java.net.URLDecoder;
import java.security.KeyPair;
import java.security.PrivateKey;
@@ -85,22 +85,26 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
UriInfo uriInfo = request.getUriInfo();
String issuerURL = UriBuilder.fromUri(uriInfo.getBaseUri()).build().toString();
String destinationUrl = getConfig().getSingleSignOnServiceUrl();
- SAML2Request samlRequest = new SAML2Request();
String nameIDPolicyFormat = getConfig().getNameIDPolicyFormat();
if (nameIDPolicyFormat == null) {
nameIDPolicyFormat = JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get();
}
- samlRequest.setNameIDFormat(nameIDPolicyFormat);
+ String protocolBinding = JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get();
- AuthnRequestType authn = samlRequest
- .createAuthnRequestType(IDGenerator.create("ID_"), request.getRedirectUri(), destinationUrl, issuerURL);
-
- authn.setProtocolBinding(URI.create(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get()));
- authn.setForceAuthn(getConfig().isForceAuthn());
+ if (getConfig().isPostBindingResponse()) {
+ protocolBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
+ }
- Document authnDoc = samlRequest.convert(authn);
+ SAML2AuthnRequestBuilder authnRequestBuilder = new SAML2AuthnRequestBuilder()
+ .assertionConsumerUrl(request.getRedirectUri())
+ .destination(destinationUrl)
+ .issuer(issuerURL)
+ .forceAuthn(getConfig().isForceAuthn())
+ .protocolBinding(protocolBinding)
+ .nameIdPolicy(SAML2NameIDPolicyBuilder.format(nameIDPolicyFormat))
+ .relayState(request.getState());
if (getConfig().isWantAuthnRequestsSigned()) {
PrivateKey privateKey = request.getRealm().getPrivateKey();
@@ -116,16 +120,14 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
KeyPair keypair = new KeyPair(publicKey, privateKey);
- this.saml2Signature.signSAMLDocument(authnDoc, keypair);
+ authnRequestBuilder.signWith(keypair);
}
- byte[] responseBytes = DocumentUtil.getDocumentAsString(authnDoc).getBytes("UTF-8");
- String urlEncodedResponse = RedirectBindingUtil.deflateBase64URLEncode(responseBytes);
- URI redirectUri = UriBuilder.fromPath(destinationUrl)
- .queryParam(SAML_REQUEST_PARAMETER, urlEncodedResponse)
- .queryParam(RELAY_STATE_PARAMETER, request.getState()).build();
-
- return AuthenticationResponse.temporaryRedirect(redirectUri);
+ if (getConfig().isPostBindingAuthnRequest()) {
+ return AuthenticationResponse.fromResponse(authnRequestBuilder.postBinding().request());
+ } else {
+ return AuthenticationResponse.fromResponse(authnRequestBuilder.redirectBinding().request());
+ }
} catch (Exception e) {
throw new RuntimeException("Could not create authentication request.", e);
}
@@ -133,44 +135,48 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
@Override
public String getRelayState(AuthenticationRequest request) {
- HttpRequest httpRequest = request.getHttpRequest();
- return httpRequest.getFormParameters().getFirst(RELAY_STATE_PARAMETER);
+ return getRequestParameter(request, RELAY_STATE_PARAMETER);
}
@Override
public AuthenticationResponse handleResponse(AuthenticationRequest request) {
- HttpRequest httpRequest = request.getHttpRequest();
- String samlResponse = httpRequest.getFormParameters().getFirst(SAML_RESPONSE_PARAMETER);
-
- if (samlResponse == null) {
- throw new RuntimeException("No response from SAML identity provider.");
- }
-
try {
- SAML2Request saml2Request = new SAML2Request();
- ResponseType responseType = (ResponseType) saml2Request
- .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(samlResponse, "UTF-8")));
- AssertionType assertion = getAssertion(request, saml2Request, responseType);
-
+ AssertionType assertion = getAssertion(request);
SubjectType subject = assertion.getSubject();
STSubType subType = subject.getSubType();
NameIDType subjectNameID = (NameIDType) subType.getBaseID();
+ FederatedIdentity identity = new FederatedIdentity(subjectNameID.getValue());
- FederatedIdentity user = new FederatedIdentity(subjectNameID.getValue());
-
- user.setUsername(subjectNameID.getValue());
+ identity.setUsername(subjectNameID.getValue());
if (subjectNameID.getFormat().toString().equals(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get())) {
- user.setEmail(subjectNameID.getValue());
+ identity.setEmail(subjectNameID.getValue());
}
- return AuthenticationResponse.end(user);
+ return AuthenticationResponse.end(identity);
} catch (Exception e) {
throw new RuntimeException("Could not process response from SAML identity provider.", e);
}
}
- private AssertionType getAssertion(AuthenticationRequest request, SAML2Request saml2Request, ResponseType responseType) throws ProcessingException {
+ private AssertionType getAssertion(AuthenticationRequest request) throws Exception {
+ String samlResponse = getRequestParameter(request, SAML_RESPONSE_PARAMETER);
+
+ if (samlResponse == null) {
+ throw new RuntimeException("No response from SAML identity provider.");
+ }
+
+ SAML2Request saml2Request = new SAML2Request();
+ ResponseType responseType;
+
+ if (getConfig().isPostBindingResponse()) {
+ responseType = (ResponseType) saml2Request
+ .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(samlResponse, "UTF-8")));
+ } else {
+ responseType = (ResponseType) saml2Request
+ .getSAML2ObjectFromStream(RedirectBindingUtil.base64DeflateDecode((samlResponse)));
+ }
+
validateStatusResponse(responseType);
validateSignature(saml2Request);
@@ -252,4 +258,17 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
}
}
+ private String getRequestParameter(AuthenticationRequest request, String parameterName) {
+ MultivaluedMap<String, String> requestParameters;
+
+ if (getConfig().isPostBindingResponse()) {
+ HttpRequest httpRequest = request.getHttpRequest();
+ requestParameters = httpRequest.getFormParameters();
+ } else {
+ UriInfo uriInfo = request.getUriInfo();
+ requestParameters = uriInfo.getQueryParameters();
+ }
+
+ return requestParameters.getFirst(parameterName);
+ }
}
diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
index b0b8724..e6efe16 100644
--- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
+++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
@@ -89,4 +89,20 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
public void setEncryptionPublicKey(String encryptionPublicKey) {
getConfig().put("encryptionPublicKey", encryptionPublicKey);
}
+
+ public boolean isPostBindingAuthnRequest() {
+ return Boolean.valueOf(getConfig().get("postBindingAuthnRequest"));
+ }
+
+ public void setPostBindingAuthnRequest(boolean postBindingAuthnRequest) {
+ getConfig().put("postBindingAuthnRequest", String.valueOf(postBindingAuthnRequest));
+ }
+
+ public boolean isPostBindingResponse() {
+ return Boolean.valueOf(getConfig().get("postBindingResponse"));
+ }
+
+ public void setPostBindingResponse(boolean postBindingResponse) {
+ getConfig().put("postBindingResponse", String.valueOf(postBindingResponse));
+ }
}
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html
index 6d4ea91..5624e54 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-saml.html
@@ -73,6 +73,20 @@
<span tooltip-placement="right" tooltip="Enable/disable signature validation of SAML responses." class="fa fa-info-circle"></span>
</div>
<div class="form-group">
+ <label class="col-sm-2 control-label" for="postBindingResponse">HTTP-POST Binding Response</label>
+ <div class="col-sm-4">
+ <input ng-model="identityProvider.config.postBindingResponse" id="postBindingResponse" onoffswitch />
+ </div>
+ <span tooltip-placement="right" tooltip="Indicates whether the identity provider must respond to the AuthnRequest using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used." class="fa fa-info-circle"></span>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="postBindingAuthnRequest">HTTP-POST Binding for AuthnRequest</label>
+ <div class="col-sm-4">
+ <input ng-model="identityProvider.config.postBindingAuthnRequest" id="postBindingAuthnRequest" onoffswitch />
+ </div>
+ <span tooltip-placement="right" tooltip="Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used." class="fa fa-info-circle"></span>
+ </div>
+ <div class="form-group">
<label class="col-sm-2 control-label" for="enabled">Enabled</label>
<div class="col-sm-4">
<input ng-model="identityProvider.enabled" id="enabled" onoffswitch />
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java
index 2bf82ae..288e2bd 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SALM2LoginResponseBuilder.java
@@ -127,7 +127,7 @@ public class SALM2LoginResponseBuilder extends SAML2BindingBuilder<SALM2LoginRes
// Create a response type
String id = IDGenerator.create("ID_");
- IssuerInfoHolder issuerHolder = new IssuerInfoHolder(responseIssuer);
+ IssuerInfoHolder issuerHolder = new IssuerInfoHolder(issuer);
issuerHolder.setStatusCode(JBossSAMLURIConstants.STATUS_SUCCESS.get());
IDPInfoHolder idp = new IDPInfoHolder();
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2AuthnRequestBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2AuthnRequestBuilder.java
new file mode 100644
index 0000000..4dedd01
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2AuthnRequestBuilder.java
@@ -0,0 +1,98 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.protocol.saml;
+
+import org.picketlink.common.exceptions.ConfigurationException;
+import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request;
+import org.picketlink.identity.federation.core.saml.v2.common.IDGenerator;
+import org.picketlink.identity.federation.core.saml.v2.util.XMLTimeUtil;
+import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
+import org.picketlink.identity.federation.saml.v2.protocol.AuthnRequestType;
+import org.w3c.dom.Document;
+
+import java.net.URI;
+
+/**
+ * @author pedroigor
+ */
+public class SAML2AuthnRequestBuilder extends SAML2BindingBuilder<SAML2AuthnRequestBuilder> {
+
+ private final AuthnRequestType authnRequestType;
+
+ public SAML2AuthnRequestBuilder() {
+ try {
+ this.authnRequestType = new AuthnRequestType(IDGenerator.create("ID_"), XMLTimeUtil.getIssueInstant());
+ } catch (ConfigurationException e) {
+ throw new RuntimeException("Could not create SAML AuthnRequest builder.", e);
+ }
+ }
+
+ public SAML2AuthnRequestBuilder assertionConsumerUrl(String assertionConsumerUrl) {
+ this.authnRequestType.setAssertionConsumerServiceURL(URI.create(assertionConsumerUrl));
+ return this;
+ }
+
+ public SAML2AuthnRequestBuilder forceAuthn(boolean forceAuthn) {
+ this.authnRequestType.setForceAuthn(forceAuthn);
+ return this;
+ }
+
+ public SAML2AuthnRequestBuilder nameIdPolicy(SAML2NameIDPolicyBuilder nameIDPolicy) {
+ this.authnRequestType.setNameIDPolicy(nameIDPolicy.build());
+ return this;
+ }
+
+ public SAML2AuthnRequestBuilder protocolBinding(String protocolBinding) {
+ this.authnRequestType.setProtocolBinding(URI.create(protocolBinding));
+ return this;
+ }
+
+ public RedirectBindingBuilder redirectBinding() {
+ try {
+ return new RedirectBindingBuilder(toDocument());
+ } catch (Exception e) {
+ throw new RuntimeException("Could not build authn request for post binding.", e);
+ }
+ }
+
+ public PostBindingBuilder postBinding() {
+ try {
+ return new PostBindingBuilder(toDocument());
+ } catch (Exception e) {
+ throw new RuntimeException("Could not build authn request for post binding.", e);
+ }
+ }
+
+ private Document toDocument() {
+ try {
+ AuthnRequestType authnRequestType = this.authnRequestType;
+
+ NameIDType nameIDType = new NameIDType();
+
+ nameIDType.setValue(this.issuer);
+
+ authnRequestType.setIssuer(nameIDType);
+
+ authnRequestType.setDestination(URI.create(this.destination));
+
+ return new SAML2Request().convert(authnRequestType);
+ } catch (Exception e) {
+ throw new RuntimeException("Could not convert " + authnRequestType + " to a document.", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java
index 294f210..dfefa05 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2BindingBuilder.java
@@ -44,7 +44,7 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
protected SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RSA_SHA1;
protected String relayState;
protected String destination;
- protected String responseIssuer;
+ protected String issuer;
protected int encryptionKeySize = 128;
protected PublicKey encryptionPublicKey;
protected String encryptionAlgorithm = "AES";
@@ -108,8 +108,8 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
return (T)this;
}
- public T responseIssuer(String issuer) {
- this.responseIssuer = issuer;
+ public T issuer(String issuer) {
+ this.issuer = issuer;
return (T)this;
}
@@ -140,14 +140,17 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
}
public String htmlResponse() throws ProcessingException, ConfigurationException, IOException {
- return buildHtml(encoded(), destination);
+ return buildHtml(encoded(), destination, false);
}
+ public Response request() throws ConfigurationException, ProcessingException, IOException {
+ return buildResponse(document, destination, true);
+ }
public Response response() throws ConfigurationException, ProcessingException, IOException {
- return buildResponse(document, destination);
+ return buildResponse(document, destination, false);
}
public Response response(String actionUrl) throws ConfigurationException, ProcessingException, IOException {
- return buildResponse(document, actionUrl);
+ return buildResponse(document, actionUrl, false);
}
}
@@ -165,15 +168,28 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
public Document getDocument() {
return document;
}
- public URI responseUri(String redirectUri) throws ConfigurationException, ProcessingException, IOException {
- return generateRedirectUri("SAMLResponse", redirectUri, document);
+ public URI responseUri(String redirectUri, boolean asRequest) throws ConfigurationException, ProcessingException, IOException {
+ String samlParameterName = GeneralConstants.SAML_RESPONSE_KEY;
+
+ if (asRequest) {
+ samlParameterName = GeneralConstants.SAML_REQUEST_KEY;
+ }
+
+ return generateRedirectUri(samlParameterName, redirectUri, document);
}
public Response response() throws ProcessingException, ConfigurationException, IOException {
- return response(destination);
+ return response(destination, false);
}
-
public Response response(String redirectUri) throws ProcessingException, ConfigurationException, IOException {
- URI uri = responseUri(redirectUri);
+ return response(destination, false);
+ }
+
+ public Response request() throws ProcessingException, ConfigurationException, IOException {
+ return response(destination, true);
+ }
+
+ private Response response(String redirectUri, boolean asRequest) throws ProcessingException, ConfigurationException, IOException {
+ URI uri = responseUri(redirectUri, asRequest);
CacheControl cacheControl = new CacheControl();
cacheControl.setNoCache(true);
@@ -266,8 +282,8 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
}
- protected Response buildResponse(Document responseDoc, String actionUrl) throws ProcessingException, ConfigurationException, IOException {
- String str = buildHtmlPostResponse(responseDoc, actionUrl);
+ protected Response buildResponse(Document responseDoc, String actionUrl, boolean asRequest) throws ProcessingException, ConfigurationException, IOException {
+ String str = buildHtmlPostResponse(responseDoc, actionUrl, asRequest);
CacheControl cacheControl = new CacheControl();
cacheControl.setNoCache(true);
@@ -276,14 +292,14 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
.header("Cache-Control", "no-cache, no-store").build();
}
- protected String buildHtmlPostResponse(Document responseDoc, String actionUrl) throws ProcessingException, ConfigurationException, IOException {
+ protected String buildHtmlPostResponse(Document responseDoc, String actionUrl, boolean asRequest) throws ProcessingException, ConfigurationException, IOException {
byte[] responseBytes = DocumentUtil.getDocumentAsString(responseDoc).getBytes("UTF-8");
String samlResponse = PostBindingUtil.base64Encode(new String(responseBytes));
- return buildHtml(samlResponse, actionUrl);
+ return buildHtml(samlResponse, actionUrl, asRequest);
}
- protected String buildHtml(String samlResponse, String actionUrl) {
+ protected String buildHtml(String samlResponse, String actionUrl, boolean asRequest) {
if (destination == null) {
throw SALM2LoginResponseBuilder.logger.nullValueError("Destination is null");
}
@@ -291,6 +307,11 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
StringBuilder builder = new StringBuilder();
String key = GeneralConstants.SAML_RESPONSE_KEY;
+
+ if (asRequest) {
+ key = GeneralConstants.SAML_REQUEST_KEY;
+ }
+
builder.append("<HTML>");
builder.append("<HEAD>");
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2ErrorResponseBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2ErrorResponseBuilder.java
index c4a2c2b..7059d68 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2ErrorResponseBuilder.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2ErrorResponseBuilder.java
@@ -47,7 +47,7 @@ public class SAML2ErrorResponseBuilder extends SAML2BindingBuilder<SAML2ErrorRes
// Create a response type
String id = IDGenerator.create("ID_");
- IssuerInfoHolder issuerHolder = new IssuerInfoHolder(responseIssuer);
+ IssuerInfoHolder issuerHolder = new IssuerInfoHolder(issuer);
issuerHolder.setStatusCode(status);
IDPInfoHolder idp = new IDPInfoHolder();
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java
index 9e885ea..65c902c 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutRequestBuilder.java
@@ -1,19 +1,15 @@
package org.keycloak.protocol.saml;
-import org.picketlink.common.constants.JBossSAMLURIConstants;
import org.picketlink.common.exceptions.ConfigurationException;
import org.picketlink.common.exceptions.ParsingException;
import org.picketlink.common.exceptions.ProcessingException;
import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request;
-import org.picketlink.identity.federation.core.saml.v2.util.DocumentUtil;
import org.picketlink.identity.federation.core.saml.v2.util.XMLTimeUtil;
import org.picketlink.identity.federation.core.sts.PicketLinkCoreSTS;
import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
import org.picketlink.identity.federation.saml.v2.protocol.LogoutRequestType;
-import org.picketlink.identity.federation.web.util.PostBindingUtil;
import org.w3c.dom.Document;
-import java.io.IOException;
import java.net.URI;
/**
@@ -48,7 +44,7 @@ public class SAML2LogoutRequestBuilder extends SAML2BindingBuilder<SAML2LogoutRe
}
private LogoutRequestType createLogoutRequest() throws ConfigurationException {
- LogoutRequestType lort = new SAML2Request().createLogoutRequest(responseIssuer);
+ LogoutRequestType lort = new SAML2Request().createLogoutRequest(issuer);
NameIDType nameID = new NameIDType();
nameID.setValue(userPrincipal);
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutResponseBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutResponseBuilder.java
index 9815e61..c9c63b2 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutResponseBuilder.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2LogoutResponseBuilder.java
@@ -6,13 +6,8 @@ import org.picketlink.common.exceptions.ParsingException;
import org.picketlink.common.exceptions.ProcessingException;
import org.picketlink.identity.federation.api.saml.v2.response.SAML2Response;
import org.picketlink.identity.federation.core.saml.v2.common.IDGenerator;
-import org.picketlink.identity.federation.core.saml.v2.factories.JBossSAMLAuthnResponseFactory;
-import org.picketlink.identity.federation.core.saml.v2.holders.IDPInfoHolder;
-import org.picketlink.identity.federation.core.saml.v2.holders.IssuerInfoHolder;
-import org.picketlink.identity.federation.core.saml.v2.holders.SPInfoHolder;
import org.picketlink.identity.federation.core.saml.v2.util.XMLTimeUtil;
import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
-import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
import org.picketlink.identity.federation.saml.v2.protocol.StatusCodeType;
import org.picketlink.identity.federation.saml.v2.protocol.StatusResponseType;
import org.picketlink.identity.federation.saml.v2.protocol.StatusType;
@@ -60,7 +55,7 @@ public class SAML2LogoutResponseBuilder extends SAML2BindingBuilder<SAML2LogoutR
statusResponse.setStatus(statusType);
statusResponse.setInResponseTo(logoutRequestID);
NameIDType issuer = new NameIDType();
- issuer.setValue(responseIssuer);
+ issuer.setValue(this.issuer);
statusResponse.setIssuer(issuer);
statusResponse.setDestination(destination);
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2NameIDPolicyBuilder.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2NameIDPolicyBuilder.java
new file mode 100644
index 0000000..71f4186
--- /dev/null
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SAML2NameIDPolicyBuilder.java
@@ -0,0 +1,44 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.protocol.saml;
+
+import org.picketlink.identity.federation.saml.v2.protocol.NameIDPolicyType;
+
+import java.net.URI;
+
+/**
+ * @author pedroigor
+ */
+public class SAML2NameIDPolicyBuilder {
+
+ private final NameIDPolicyType policyType;
+
+ private SAML2NameIDPolicyBuilder(String format) {
+ this.policyType = new NameIDPolicyType();
+ this.policyType.setFormat(URI.create(format));
+ }
+
+ public static SAML2NameIDPolicyBuilder format(String format) {
+ return new SAML2NameIDPolicyBuilder(format);
+ }
+
+ public NameIDPolicyType build() {
+ this.policyType.setAllowCreate(Boolean.TRUE);
+ return this.policyType;
+ }
+}
\ No newline at end of file
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index 0e68eb3..f3bc382 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -114,7 +114,7 @@ public class SamlProtocol implements LoginProtocol {
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
.relayState(clientSession.getNote(GeneralConstants.RELAY_STATE))
.destination(clientSession.getRedirectUri())
- .responseIssuer(getResponseIssuer(realm))
+ .issuer(getResponseIssuer(realm))
.status(status);
try {
if (isPostBinding(clientSession)) {
@@ -191,7 +191,7 @@ public class SamlProtocol implements LoginProtocol {
builder.requestID(requestID)
.relayState(relayState)
.destination(redirectUri)
- .responseIssuer(responseIssuer)
+ .issuer(responseIssuer)
.requestIssuer(clientSession.getClient().getClientId())
.nameIdentifier(nameIdFormat, nameId)
.authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get());
diff --git a/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java b/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java
index 550deda..19ff363 100644
--- a/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java
@@ -156,7 +156,7 @@ public class AuthenticationBrokerResource {
String relayState = provider.getRelayState(createAuthenticationRequest(providerId, null, realm, null));
if (relayState == null) {
- return redirectToErrorPage(realm, "No authorization code provided.");
+ return redirectToErrorPage(realm, "No relay state from identity provider.");
}
ClientSessionCode clientCode = isValidAuthorizationCode(relayState, realm);