[KEYCLOAK-883] - More SAML configuration. Using SAML builders to create AuthnRequest.
This commit is contained in:
parent
da240b2b36
commit
b9a7594113
14 changed files with 283 additions and 71 deletions
|
@ -54,4 +54,7 @@ public class AuthenticationResponse {
|
|||
return new AuthenticationResponse(Response.temporaryRedirect(url).build());
|
||||
}
|
||||
|
||||
public static AuthenticationResponse fromResponse(Response response) {
|
||||
return new AuthenticationResponse(response);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
<version>${project.version}</version>
|
||||
<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>
|
||||
|
|
|
@ -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);
|
||||
if (getConfig().isPostBindingResponse()) {
|
||||
protocolBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
|
||||
}
|
||||
|
||||
authn.setProtocolBinding(URI.create(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get()));
|
||||
authn.setForceAuthn(getConfig().isForceAuthn());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,20 @@
|
|||
</div>
|
||||
<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">
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
return response(destination, false);
|
||||
}
|
||||
|
||||
public Response response(String redirectUri) throws ProcessingException, ConfigurationException, IOException {
|
||||
URI uri = responseUri(redirectUri);
|
||||
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>");
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue