[KEYCLOAK-883] - More SAML configuration. Using SAML builders to create AuthnRequest.

This commit is contained in:
pedroigor 2015-01-21 23:40:20 -02:00
parent da240b2b36
commit b9a7594113
14 changed files with 283 additions and 71 deletions

View file

@ -54,4 +54,7 @@ public class AuthenticationResponse {
return new AuthenticationResponse(Response.temporaryRedirect(url).build()); return new AuthenticationResponse(Response.temporaryRedirect(url).build());
} }
public static AuthenticationResponse fromResponse(Response response) {
return new AuthenticationResponse(response);
}
} }

View file

@ -21,6 +21,12 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-protocol</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.picketlink</groupId> <groupId>org.picketlink</groupId>
<artifactId>picketlink-federation</artifactId> <artifactId>picketlink-federation</artifactId>

View file

@ -22,6 +22,8 @@ import org.keycloak.broker.provider.AbstractIdentityProvider;
import org.keycloak.broker.provider.AuthenticationRequest; import org.keycloak.broker.provider.AuthenticationRequest;
import org.keycloak.broker.provider.AuthenticationResponse; import org.keycloak.broker.provider.AuthenticationResponse;
import org.keycloak.broker.provider.FederatedIdentity; 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.JBossSAMLConstants;
import org.picketlink.common.constants.JBossSAMLURIConstants; import org.picketlink.common.constants.JBossSAMLURIConstants;
import org.picketlink.common.exceptions.ProcessingException; 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.response.SAML2Response;
import org.picketlink.identity.federation.api.saml.v2.sig.SAML2Signature; 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.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.saml.v2.common.SAMLDocumentHolder;
import org.picketlink.identity.federation.core.util.JAXPValidationUtil; import org.picketlink.identity.federation.core.util.JAXPValidationUtil;
import org.picketlink.identity.federation.core.util.XMLEncryptionUtil; 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.NameIDType;
import org.picketlink.identity.federation.saml.v2.assertion.SubjectType; 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.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;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType.RTChoiceType; import org.picketlink.identity.federation.saml.v2.protocol.ResponseType.RTChoiceType;
import org.picketlink.identity.federation.saml.v2.protocol.StatusCodeType; 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.Element;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import javax.ws.rs.core.MultivaluedMap;
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.xml.namespace.QName; import javax.xml.namespace.QName;
import java.net.URI;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.PrivateKey; import java.security.PrivateKey;
@ -85,22 +85,26 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
UriInfo uriInfo = request.getUriInfo(); UriInfo uriInfo = request.getUriInfo();
String issuerURL = UriBuilder.fromUri(uriInfo.getBaseUri()).build().toString(); String issuerURL = UriBuilder.fromUri(uriInfo.getBaseUri()).build().toString();
String destinationUrl = getConfig().getSingleSignOnServiceUrl(); String destinationUrl = getConfig().getSingleSignOnServiceUrl();
SAML2Request samlRequest = new SAML2Request();
String nameIDPolicyFormat = getConfig().getNameIDPolicyFormat(); String nameIDPolicyFormat = getConfig().getNameIDPolicyFormat();
if (nameIDPolicyFormat == null) { if (nameIDPolicyFormat == null) {
nameIDPolicyFormat = JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get(); nameIDPolicyFormat = JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get();
} }
samlRequest.setNameIDFormat(nameIDPolicyFormat); String protocolBinding = JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get();
AuthnRequestType authn = samlRequest if (getConfig().isPostBindingResponse()) {
.createAuthnRequestType(IDGenerator.create("ID_"), request.getRedirectUri(), destinationUrl, issuerURL); protocolBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
}
authn.setProtocolBinding(URI.create(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())); SAML2AuthnRequestBuilder authnRequestBuilder = new SAML2AuthnRequestBuilder()
authn.setForceAuthn(getConfig().isForceAuthn()); .assertionConsumerUrl(request.getRedirectUri())
.destination(destinationUrl)
Document authnDoc = samlRequest.convert(authn); .issuer(issuerURL)
.forceAuthn(getConfig().isForceAuthn())
.protocolBinding(protocolBinding)
.nameIdPolicy(SAML2NameIDPolicyBuilder.format(nameIDPolicyFormat))
.relayState(request.getState());
if (getConfig().isWantAuthnRequestsSigned()) { if (getConfig().isWantAuthnRequestsSigned()) {
PrivateKey privateKey = request.getRealm().getPrivateKey(); PrivateKey privateKey = request.getRealm().getPrivateKey();
@ -116,16 +120,14 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
KeyPair keypair = new KeyPair(publicKey, privateKey); KeyPair keypair = new KeyPair(publicKey, privateKey);
this.saml2Signature.signSAMLDocument(authnDoc, keypair); authnRequestBuilder.signWith(keypair);
} }
byte[] responseBytes = DocumentUtil.getDocumentAsString(authnDoc).getBytes("UTF-8"); if (getConfig().isPostBindingAuthnRequest()) {
String urlEncodedResponse = RedirectBindingUtil.deflateBase64URLEncode(responseBytes); return AuthenticationResponse.fromResponse(authnRequestBuilder.postBinding().request());
URI redirectUri = UriBuilder.fromPath(destinationUrl) } else {
.queryParam(SAML_REQUEST_PARAMETER, urlEncodedResponse) return AuthenticationResponse.fromResponse(authnRequestBuilder.redirectBinding().request());
.queryParam(RELAY_STATE_PARAMETER, request.getState()).build(); }
return AuthenticationResponse.temporaryRedirect(redirectUri);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Could not create authentication request.", e); throw new RuntimeException("Could not create authentication request.", e);
} }
@ -133,44 +135,48 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
@Override @Override
public String getRelayState(AuthenticationRequest request) { public String getRelayState(AuthenticationRequest request) {
HttpRequest httpRequest = request.getHttpRequest(); return getRequestParameter(request, RELAY_STATE_PARAMETER);
return httpRequest.getFormParameters().getFirst(RELAY_STATE_PARAMETER);
} }
@Override @Override
public AuthenticationResponse handleResponse(AuthenticationRequest request) { 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 { try {
SAML2Request saml2Request = new SAML2Request(); AssertionType assertion = getAssertion(request);
ResponseType responseType = (ResponseType) saml2Request
.getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(samlResponse, "UTF-8")));
AssertionType assertion = getAssertion(request, saml2Request, responseType);
SubjectType subject = assertion.getSubject(); SubjectType subject = assertion.getSubject();
STSubType subType = subject.getSubType(); STSubType subType = subject.getSubType();
NameIDType subjectNameID = (NameIDType) subType.getBaseID(); NameIDType subjectNameID = (NameIDType) subType.getBaseID();
FederatedIdentity identity = new FederatedIdentity(subjectNameID.getValue());
FederatedIdentity user = new FederatedIdentity(subjectNameID.getValue()); identity.setUsername(subjectNameID.getValue());
user.setUsername(subjectNameID.getValue());
if (subjectNameID.getFormat().toString().equals(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get())) { 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) { } catch (Exception e) {
throw new RuntimeException("Could not process response from SAML identity provider.", 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); validateStatusResponse(responseType);
validateSignature(saml2Request); 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);
}
} }

View file

@ -89,4 +89,20 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
public void setEncryptionPublicKey(String encryptionPublicKey) { public void setEncryptionPublicKey(String encryptionPublicKey) {
getConfig().put("encryptionPublicKey", 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));
}
} }

View file

@ -72,6 +72,20 @@
</div> </div>
<span tooltip-placement="right" tooltip="Enable/disable signature validation of SAML responses." class="fa fa-info-circle"></span> <span tooltip-placement="right" tooltip="Enable/disable signature validation of SAML responses." class="fa fa-info-circle"></span>
</div> </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"> <div class="form-group">
<label class="col-sm-2 control-label" for="enabled">Enabled</label> <label class="col-sm-2 control-label" for="enabled">Enabled</label>
<div class="col-sm-4"> <div class="col-sm-4">

View file

@ -127,7 +127,7 @@ public class SALM2LoginResponseBuilder extends SAML2BindingBuilder<SALM2LoginRes
// Create a response type // Create a response type
String id = IDGenerator.create("ID_"); String id = IDGenerator.create("ID_");
IssuerInfoHolder issuerHolder = new IssuerInfoHolder(responseIssuer); IssuerInfoHolder issuerHolder = new IssuerInfoHolder(issuer);
issuerHolder.setStatusCode(JBossSAMLURIConstants.STATUS_SUCCESS.get()); issuerHolder.setStatusCode(JBossSAMLURIConstants.STATUS_SUCCESS.get());
IDPInfoHolder idp = new IDPInfoHolder(); IDPInfoHolder idp = new IDPInfoHolder();

View file

@ -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);
}
}
}

View file

@ -44,7 +44,7 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
protected SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RSA_SHA1; protected SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RSA_SHA1;
protected String relayState; protected String relayState;
protected String destination; protected String destination;
protected String responseIssuer; protected String issuer;
protected int encryptionKeySize = 128; protected int encryptionKeySize = 128;
protected PublicKey encryptionPublicKey; protected PublicKey encryptionPublicKey;
protected String encryptionAlgorithm = "AES"; protected String encryptionAlgorithm = "AES";
@ -108,8 +108,8 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
return (T)this; return (T)this;
} }
public T responseIssuer(String issuer) { public T issuer(String issuer) {
this.responseIssuer = issuer; this.issuer = issuer;
return (T)this; return (T)this;
} }
@ -140,14 +140,17 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
} }
public String htmlResponse() throws ProcessingException, ConfigurationException, IOException { 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 { 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 { 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() { public Document getDocument() {
return document; return document;
} }
public URI responseUri(String redirectUri) throws ConfigurationException, ProcessingException, IOException { public URI responseUri(String redirectUri, boolean asRequest) throws ConfigurationException, ProcessingException, IOException {
return generateRedirectUri("SAMLResponse", redirectUri, document); 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 { public Response response() throws ProcessingException, ConfigurationException, IOException {
return response(destination); return response(destination, false);
}
public Response response(String redirectUri) throws ProcessingException, ConfigurationException, IOException {
return response(destination, false);
} }
public Response response(String redirectUri) throws ProcessingException, ConfigurationException, IOException { public Response request() throws ProcessingException, ConfigurationException, IOException {
URI uri = responseUri(redirectUri); 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 cacheControl = new CacheControl();
cacheControl.setNoCache(true); cacheControl.setNoCache(true);
@ -266,8 +282,8 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
} }
protected Response buildResponse(Document responseDoc, String actionUrl) throws ProcessingException, ConfigurationException, IOException { protected Response buildResponse(Document responseDoc, String actionUrl, boolean asRequest) throws ProcessingException, ConfigurationException, IOException {
String str = buildHtmlPostResponse(responseDoc, actionUrl); String str = buildHtmlPostResponse(responseDoc, actionUrl, asRequest);
CacheControl cacheControl = new CacheControl(); CacheControl cacheControl = new CacheControl();
cacheControl.setNoCache(true); cacheControl.setNoCache(true);
@ -276,14 +292,14 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
.header("Cache-Control", "no-cache, no-store").build(); .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"); byte[] responseBytes = DocumentUtil.getDocumentAsString(responseDoc).getBytes("UTF-8");
String samlResponse = PostBindingUtil.base64Encode(new String(responseBytes)); 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) { if (destination == null) {
throw SALM2LoginResponseBuilder.logger.nullValueError("Destination is null"); throw SALM2LoginResponseBuilder.logger.nullValueError("Destination is null");
} }
@ -291,6 +307,11 @@ public class SAML2BindingBuilder<T extends SAML2BindingBuilder> {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
String key = GeneralConstants.SAML_RESPONSE_KEY; String key = GeneralConstants.SAML_RESPONSE_KEY;
if (asRequest) {
key = GeneralConstants.SAML_REQUEST_KEY;
}
builder.append("<HTML>"); builder.append("<HTML>");
builder.append("<HEAD>"); builder.append("<HEAD>");

View file

@ -47,7 +47,7 @@ public class SAML2ErrorResponseBuilder extends SAML2BindingBuilder<SAML2ErrorRes
// Create a response type // Create a response type
String id = IDGenerator.create("ID_"); String id = IDGenerator.create("ID_");
IssuerInfoHolder issuerHolder = new IssuerInfoHolder(responseIssuer); IssuerInfoHolder issuerHolder = new IssuerInfoHolder(issuer);
issuerHolder.setStatusCode(status); issuerHolder.setStatusCode(status);
IDPInfoHolder idp = new IDPInfoHolder(); IDPInfoHolder idp = new IDPInfoHolder();

View file

@ -1,19 +1,15 @@
package org.keycloak.protocol.saml; package org.keycloak.protocol.saml;
import org.picketlink.common.constants.JBossSAMLURIConstants;
import org.picketlink.common.exceptions.ConfigurationException; import org.picketlink.common.exceptions.ConfigurationException;
import org.picketlink.common.exceptions.ParsingException; import org.picketlink.common.exceptions.ParsingException;
import org.picketlink.common.exceptions.ProcessingException; import org.picketlink.common.exceptions.ProcessingException;
import org.picketlink.identity.federation.api.saml.v2.request.SAML2Request; 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.saml.v2.util.XMLTimeUtil;
import org.picketlink.identity.federation.core.sts.PicketLinkCoreSTS; import org.picketlink.identity.federation.core.sts.PicketLinkCoreSTS;
import org.picketlink.identity.federation.saml.v2.assertion.NameIDType; import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
import org.picketlink.identity.federation.saml.v2.protocol.LogoutRequestType; import org.picketlink.identity.federation.saml.v2.protocol.LogoutRequestType;
import org.picketlink.identity.federation.web.util.PostBindingUtil;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import java.io.IOException;
import java.net.URI; import java.net.URI;
/** /**
@ -48,7 +44,7 @@ public class SAML2LogoutRequestBuilder extends SAML2BindingBuilder<SAML2LogoutRe
} }
private LogoutRequestType createLogoutRequest() throws ConfigurationException { private LogoutRequestType createLogoutRequest() throws ConfigurationException {
LogoutRequestType lort = new SAML2Request().createLogoutRequest(responseIssuer); LogoutRequestType lort = new SAML2Request().createLogoutRequest(issuer);
NameIDType nameID = new NameIDType(); NameIDType nameID = new NameIDType();
nameID.setValue(userPrincipal); nameID.setValue(userPrincipal);

View file

@ -6,13 +6,8 @@ import org.picketlink.common.exceptions.ParsingException;
import org.picketlink.common.exceptions.ProcessingException; import org.picketlink.common.exceptions.ProcessingException;
import org.picketlink.identity.federation.api.saml.v2.response.SAML2Response; 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.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.core.saml.v2.util.XMLTimeUtil;
import org.picketlink.identity.federation.saml.v2.assertion.NameIDType; 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.StatusCodeType;
import org.picketlink.identity.federation.saml.v2.protocol.StatusResponseType; import org.picketlink.identity.federation.saml.v2.protocol.StatusResponseType;
import org.picketlink.identity.federation.saml.v2.protocol.StatusType; import org.picketlink.identity.federation.saml.v2.protocol.StatusType;
@ -60,7 +55,7 @@ public class SAML2LogoutResponseBuilder extends SAML2BindingBuilder<SAML2LogoutR
statusResponse.setStatus(statusType); statusResponse.setStatus(statusType);
statusResponse.setInResponseTo(logoutRequestID); statusResponse.setInResponseTo(logoutRequestID);
NameIDType issuer = new NameIDType(); NameIDType issuer = new NameIDType();
issuer.setValue(responseIssuer); issuer.setValue(this.issuer);
statusResponse.setIssuer(issuer); statusResponse.setIssuer(issuer);
statusResponse.setDestination(destination); statusResponse.setDestination(destination);

View file

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

View file

@ -114,7 +114,7 @@ public class SamlProtocol implements LoginProtocol {
SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder() SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
.relayState(clientSession.getNote(GeneralConstants.RELAY_STATE)) .relayState(clientSession.getNote(GeneralConstants.RELAY_STATE))
.destination(clientSession.getRedirectUri()) .destination(clientSession.getRedirectUri())
.responseIssuer(getResponseIssuer(realm)) .issuer(getResponseIssuer(realm))
.status(status); .status(status);
try { try {
if (isPostBinding(clientSession)) { if (isPostBinding(clientSession)) {
@ -191,7 +191,7 @@ public class SamlProtocol implements LoginProtocol {
builder.requestID(requestID) builder.requestID(requestID)
.relayState(relayState) .relayState(relayState)
.destination(redirectUri) .destination(redirectUri)
.responseIssuer(responseIssuer) .issuer(responseIssuer)
.requestIssuer(clientSession.getClient().getClientId()) .requestIssuer(clientSession.getClient().getClientId())
.nameIdentifier(nameIdFormat, nameId) .nameIdentifier(nameIdFormat, nameId)
.authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get()); .authMethod(JBossSAMLURIConstants.AC_UNSPECIFIED.get());

View file

@ -156,7 +156,7 @@ public class AuthenticationBrokerResource {
String relayState = provider.getRelayState(createAuthenticationRequest(providerId, null, realm, null)); String relayState = provider.getRelayState(createAuthenticationRequest(providerId, null, realm, null));
if (relayState == 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); ClientSessionCode clientCode = isValidAuthorizationCode(relayState, realm);