keycloak-aplcache
Changes
saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java 73(+52 -21)
saml/client-adapter/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/JettySamlSessionStore.java 23(+23 -0)
saml/client-adapter/servlet-filter/src/main/java/org/keycloak/adapters/saml/servlet/FilterSamlSessionStore.java 23(+23 -0)
saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java 24(+24 -0)
saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlSessionStore.java 40(+38 -2)
testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java 4(+4 -0)
Details
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java
index a34fb1b..bd78fd2 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/InitiateLogin.java
@@ -87,6 +87,7 @@ public class InitiateLogin implements AuthChallenge {
Document document = authnRequestBuilder.toDocument();
SamlDeployment.Binding samlBinding = deployment.getIDP().getSingleSignOnService().getRequestBinding();
SamlUtil.sendSaml(true, httpFacade, actionUrl, binding, document, samlBinding);
+ sessionStore.setCurrentAction(SamlSessionStore.CurrentAction.LOGGING_IN);
} catch (Exception e) {
throw new RuntimeException("Could not create authentication request.", e);
}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java
index 39f026a..5478edf 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlAuthenticator.java
@@ -1,10 +1,12 @@
package org.keycloak.adapters.saml;
import org.jboss.logging.Logger;
-import org.keycloak.common.VerificationException;
import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.HttpFacade;
+import org.keycloak.common.VerificationException;
+import org.keycloak.common.util.KeycloakUriBuilder;
+import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.dom.saml.v2.assertion.AssertionType;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
import org.keycloak.dom.saml.v2.assertion.AttributeType;
@@ -29,8 +31,6 @@ import org.keycloak.saml.processing.api.saml.v2.sig.SAML2Signature;
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil;
import org.keycloak.saml.processing.web.util.PostBindingUtil;
-import org.keycloak.common.util.KeycloakUriBuilder;
-import org.keycloak.common.util.MultivaluedHashMap;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
@@ -74,7 +74,7 @@ public abstract class SamlAuthenticator {
return handleSamlRequest(samlRequest, relayState);
} else if (samlResponse != null) {
return handleSamlResponse(samlResponse, relayState);
- } else if (sessionStore.isLoggedIn()) {
+ } else if (sessionStore.isLoggedIn()) {
if (globalLogout) {
return globalLogout();
}
@@ -106,6 +106,7 @@ public abstract class SamlAuthenticator {
try {
SamlUtil.sendSaml(true, facade, deployment.getIDP().getSingleLogoutService().getRequestBindingUrl(), binding, logoutBuilder.buildDocument(), deployment.getIDP().getSingleLogoutService().getRequestBinding());
+ sessionStore.setCurrentAction(SamlSessionStore.CurrentAction.LOGGING_OUT);
} catch (Exception e) {
log.error("Could not send global logout SAML request", e);
return AuthOutcome.FAILED;
@@ -155,7 +156,7 @@ public abstract class SamlAuthenticator {
protected AuthOutcome logoutRequest(LogoutRequestType request, String relayState) {
if (request.getSessionIndex() == null || request.getSessionIndex().isEmpty()) {
sessionStore.logoutByPrincipal(request.getNameID().getValue());
- } else {
+ } else {
sessionStore.logoutBySsoId(request.getSessionIndex());
}
@@ -169,7 +170,8 @@ public abstract class SamlAuthenticator {
binding.signatureAlgorithm(deployment.getSignatureAlgorithm())
.signWith(deployment.getSigningKeyPair())
.signDocument();
- if (deployment.getSignatureCanonicalizationMethod() != null) binding.canonicalizationMethod(deployment.getSignatureCanonicalizationMethod());
+ if (deployment.getSignatureCanonicalizationMethod() != null)
+ binding.canonicalizationMethod(deployment.getSignatureCanonicalizationMethod());
}
@@ -199,7 +201,7 @@ public abstract class SamlAuthenticator {
postBinding = true;
holder = extractPostBindingResponse(samlResponse);
}
- StatusResponseType statusResponse = (StatusResponseType)holder.getSamlObject();
+ final StatusResponseType statusResponse = (StatusResponseType) holder.getSamlObject();
// validate destination
if (!requestUri.equals(statusResponse.getDestination())) {
log.error("Request URI does not match SAML request destination");
@@ -214,19 +216,49 @@ public abstract class SamlAuthenticator {
return AuthOutcome.FAILED;
}
}
- return handleLoginResponse((ResponseType)statusResponse);
+ return handleLoginResponse((ResponseType) statusResponse);
} else {
- if (deployment.getIDP().getSingleLogoutService().validateResponseSignature()) {
+ if (sessionStore.isLoggingOut()) {
try {
- validateSamlSignature(holder, postBinding, GeneralConstants.SAML_RESPONSE_KEY);
- } catch (VerificationException e) {
- log.error("Failed to verify saml response signature", e);
+ if (deployment.getIDP().getSingleLogoutService().validateResponseSignature()) {
+ try {
+ validateSamlSignature(holder, postBinding, GeneralConstants.SAML_RESPONSE_KEY);
+ } catch (VerificationException e) {
+ log.error("Failed to verify saml response signature", e);
+ return AuthOutcome.FAILED;
+ }
+ }
+ return handleLogoutResponse(holder, statusResponse, relayState);
+ } finally {
+ sessionStore.setCurrentAction(SamlSessionStore.CurrentAction.NONE);
+ }
+
+ } else if (sessionStore.isLoggingIn()) {
+ try {
+ challenge = new AuthChallenge() {
+ @Override
+ public boolean challenge(HttpFacade exchange) {
+ exchange.getResponse().sendError(500, statusResponse.getStatus().getStatusCode().getValue().toString());
+ return true;
+ }
+
+ @Override
+ public boolean errorPage() {
+ return true;
+ }
+
+ @Override
+ public int getResponseCode() {
+ return 500;
+ }
+ };
return AuthOutcome.FAILED;
+ } finally {
+ sessionStore.setCurrentAction(SamlSessionStore.CurrentAction.NONE);
}
}
- // todo need to check that it is actually a LogoutResponse
- return handleLogoutResponse(holder, statusResponse, relayState);
+ return AuthOutcome.NOT_ATTEMPTED;
}
}
@@ -239,7 +271,7 @@ public abstract class SamlAuthenticator {
}
}
- protected AuthOutcome handleLoginResponse(ResponseType responseType) {
+ protected AuthOutcome handleLoginResponse(ResponseType responseType) {
AssertionType assertion = null;
try {
assertion = AssertionUtil.getAssertion(responseType, deployment.getDecryptionKey());
@@ -308,14 +340,14 @@ public abstract class SamlAuthenticator {
AuthnStatementType authn = null;
for (Object statement : assertion.getStatements()) {
if (statement instanceof AuthnStatementType) {
- authn = (AuthnStatementType)statement;
+ authn = (AuthnStatementType) statement;
break;
}
}
URI nameFormat = subjectNameID.getFormat();
- String nameFormatString = nameFormat == null ? JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get() : nameFormat.toString();
+ String nameFormatString = nameFormat == null ? JBossSAMLURIConstants.NAMEID_FORMAT_UNSPECIFIED.get() : nameFormat.toString();
final SamlPrincipal principal = new SamlPrincipal(principalName, principalName, nameFormatString, attributes, friendlyAttributes);
String index = authn == null ? null : authn.getSessionIndex();
final String sessionIndex = index;
@@ -341,9 +373,9 @@ public abstract class SamlAuthenticator {
protected abstract void completeAuthentication(SamlSession account);
private String getAttributeValue(Object attrValue) {
- String value = null;
+ String value = null;
if (attrValue instanceof String) {
- value = (String)attrValue;
+ value = (String) attrValue;
} else if (attrValue instanceof Node) {
Node roleNode = (Node) attrValue;
value = roleNode.getFirstChild().getNodeValue();
@@ -372,6 +404,7 @@ public abstract class SamlAuthenticator {
protected SAMLDocumentHolder extractRedirectBindingResponse(String response) {
return SAMLRequestParser.parseRequestRedirectBinding(response);
}
+
protected SAMLDocumentHolder extractPostBindingResponse(String response) {
byte[] samlBytes = PostBindingUtil.base64Decode(response);
String xml = new String(samlBytes);
@@ -379,7 +412,6 @@ public abstract class SamlAuthenticator {
}
-
protected AuthOutcome initiateLogin() {
challenge = new InitiateLogin(deployment, sessionStore);
return AuthOutcome.NOT_ATTEMPTED;
@@ -445,5 +477,4 @@ public abstract class SamlAuthenticator {
}
-
}
diff --git a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlSessionStore.java b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlSessionStore.java
index da20026..1a19464 100755
--- a/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlSessionStore.java
+++ b/saml/client-adapter/core/src/main/java/org/keycloak/adapters/saml/SamlSessionStore.java
@@ -1,6 +1,8 @@
package org.keycloak.adapters.saml;
import org.keycloak.adapters.spi.AdapterSessionStore;
+import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
+import org.keycloak.dom.saml.v2.protocol.StatusType;
import java.util.List;
@@ -9,6 +11,19 @@ import java.util.List;
* @version $Revision: 1 $
*/
public interface SamlSessionStore extends AdapterSessionStore {
+ public static final String CURRENT_ACTION = "SAML_CURRENT_ACTION";
+ public static final String SAML_LOGIN_ERROR_STATUS = "SAML_LOGIN_ERROR_STATUS";
+ public static final String SAML_LOGOUT_ERROR_STATUS = "SAML_LOGOUT_ERROR_STATUS";
+
+ enum CurrentAction {
+ NONE,
+ LOGGING_IN,
+ LOGGING_OUT
+ }
+ void setCurrentAction(CurrentAction action);
+ boolean isLoggingIn();
+ boolean isLoggingOut();
+
boolean isLoggedIn();
SamlSession getAccount();
void saveAccount(SamlSession account);
diff --git a/saml/client-adapter/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/JettySamlSessionStore.java b/saml/client-adapter/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/JettySamlSessionStore.java
index d86184b..6e51f11 100755
--- a/saml/client-adapter/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/JettySamlSessionStore.java
+++ b/saml/client-adapter/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/JettySamlSessionStore.java
@@ -8,6 +8,7 @@ import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
import org.keycloak.adapters.saml.SamlSession;
import org.keycloak.adapters.saml.SamlSessionStore;
+import org.keycloak.dom.saml.v2.protocol.StatusType;
import javax.servlet.http.HttpSession;
@@ -38,6 +39,28 @@ public class JettySamlSessionStore implements SamlSessionStore {
}
@Override
+ public void setCurrentAction(CurrentAction action) {
+ if (action == CurrentAction.NONE && request.getSession(false) == null) return;
+ request.getSession().setAttribute(CURRENT_ACTION, action);
+ }
+
+ @Override
+ public boolean isLoggingIn() {
+ HttpSession session = request.getSession(false);
+ if (session == null) return false;
+ CurrentAction action = (CurrentAction)session.getAttribute(CURRENT_ACTION);
+ return action == CurrentAction.LOGGING_IN;
+ }
+
+ @Override
+ public boolean isLoggingOut() {
+ HttpSession session = request.getSession(false);
+ if (session == null) return false;
+ CurrentAction action = (CurrentAction)session.getAttribute(CURRENT_ACTION);
+ return action == CurrentAction.LOGGING_OUT;
+ }
+
+ @Override
public void logoutAccount() {
HttpSession session = request.getSession(false);
if (session != null) {
diff --git a/saml/client-adapter/servlet-filter/src/main/java/org/keycloak/adapters/saml/servlet/FilterSamlSessionStore.java b/saml/client-adapter/servlet-filter/src/main/java/org/keycloak/adapters/saml/servlet/FilterSamlSessionStore.java
index cbd036e..e690db5 100755
--- a/saml/client-adapter/servlet-filter/src/main/java/org/keycloak/adapters/saml/servlet/FilterSamlSessionStore.java
+++ b/saml/client-adapter/servlet-filter/src/main/java/org/keycloak/adapters/saml/servlet/FilterSamlSessionStore.java
@@ -7,6 +7,7 @@ import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.saml.SamlSession;
import org.keycloak.adapters.saml.SamlSessionStore;
import org.keycloak.adapters.servlet.FilterSessionStore;
+import org.keycloak.dom.saml.v2.protocol.StatusType;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
@@ -30,6 +31,28 @@ public class FilterSamlSessionStore extends FilterSessionStore implements SamlSe
}
@Override
+ public void setCurrentAction(CurrentAction action) {
+ if (action == CurrentAction.NONE && request.getSession(false) == null) return;
+ request.getSession().setAttribute(CURRENT_ACTION, action);
+ }
+
+ @Override
+ public boolean isLoggingIn() {
+ HttpSession session = request.getSession(false);
+ if (session == null) return false;
+ CurrentAction action = (CurrentAction)session.getAttribute(CURRENT_ACTION);
+ return action == CurrentAction.LOGGING_IN;
+ }
+
+ @Override
+ public boolean isLoggingOut() {
+ HttpSession session = request.getSession(false);
+ if (session == null) return false;
+ CurrentAction action = (CurrentAction)session.getAttribute(CURRENT_ACTION);
+ return action == CurrentAction.LOGGING_OUT;
+ }
+
+ @Override
public void logoutAccount() {
HttpSession session = request.getSession(false);
if (session == null) return;
diff --git a/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java
index adbc441..804acf3 100755
--- a/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java
+++ b/saml/client-adapter/tomcat/tomcat-core/src/main/java/org/keycloak/adapters/saml/CatalinaSamlSessionStore.java
@@ -9,6 +9,8 @@ import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.tomcat.CatalinaUserSessionManagement;
import org.keycloak.adapters.tomcat.GenericPrincipalFactory;
+import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
+import org.keycloak.dom.saml.v2.protocol.StatusType;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@@ -42,6 +44,28 @@ public class CatalinaSamlSessionStore implements SamlSessionStore {
}
@Override
+ public void setCurrentAction(CurrentAction action) {
+ if (action == CurrentAction.NONE && request.getSession(false) == null) return;
+ request.getSession().setAttribute(CURRENT_ACTION, action);
+ }
+
+ @Override
+ public boolean isLoggingIn() {
+ HttpSession session = request.getSession(false);
+ if (session == null) return false;
+ CurrentAction action = (CurrentAction)session.getAttribute(CURRENT_ACTION);
+ return action == CurrentAction.LOGGING_IN;
+ }
+
+ @Override
+ public boolean isLoggingOut() {
+ HttpSession session = request.getSession(false);
+ if (session == null) return false;
+ CurrentAction action = (CurrentAction)session.getAttribute(CURRENT_ACTION);
+ return action == CurrentAction.LOGGING_OUT;
+ }
+
+ @Override
public void logoutAccount() {
Session sessionInternal = request.getSessionInternal(false);
if (sessionInternal == null) return;
diff --git a/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlSessionStore.java b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlSessionStore.java
index 8afcc1f..34d718b 100755
--- a/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlSessionStore.java
+++ b/saml/client-adapter/undertow/src/main/java/org/keycloak/adapters/saml/undertow/ServletSamlSessionStore.java
@@ -13,9 +13,12 @@ import org.keycloak.adapters.saml.SamlSession;
import org.keycloak.adapters.saml.SamlSessionStore;
import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
import org.keycloak.common.util.KeycloakUriBuilder;
+import org.keycloak.dom.saml.v2.protocol.StatusType;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
+import java.io.IOException;
import java.security.Principal;
import java.util.LinkedList;
import java.util.List;
@@ -34,6 +37,7 @@ public class ServletSamlSessionStore implements SamlSessionStore {
private final SecurityContext securityContext;
private final SessionIdMapper idMapper;
+
public ServletSamlSessionStore(HttpServerExchange exchange, UndertowUserSessionManagement sessionManagement,
SecurityContext securityContext,
SessionIdMapper idMapper) {
@@ -44,6 +48,28 @@ public class ServletSamlSessionStore implements SamlSessionStore {
}
@Override
+ public void setCurrentAction(CurrentAction action) {
+ if (action == CurrentAction.NONE && getRequest().getSession(false) == null) return;
+ getRequest().getSession().setAttribute(CURRENT_ACTION, action);
+ }
+
+ @Override
+ public boolean isLoggingIn() {
+ HttpSession session = getRequest().getSession(false);
+ if (session == null) return false;
+ CurrentAction action = (CurrentAction)session.getAttribute(CURRENT_ACTION);
+ return action == CurrentAction.LOGGING_IN;
+ }
+
+ @Override
+ public boolean isLoggingOut() {
+ HttpSession session = getRequest().getSession(false);
+ if (session == null) return false;
+ CurrentAction action = (CurrentAction)session.getAttribute(CURRENT_ACTION);
+ return action == CurrentAction.LOGGING_OUT;
+ }
+
+ @Override
public void logoutAccount() {
HttpSession session = getSession(false);
if (session != null) {
@@ -170,8 +196,18 @@ public class ServletSamlSessionStore implements SamlSessionStore {
}
protected HttpSession getSession(boolean create) {
- final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
- HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest();
+ HttpServletRequest req = getRequest();
return req.getSession(create);
}
+
+ private HttpServletResponse getResponse() {
+ final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
+ return (HttpServletResponse)servletRequestContext.getServletResponse();
+
+ }
+
+ private HttpServletRequest getRequest() {
+ final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
+ return (HttpServletRequest) servletRequestContext.getServletRequest();
+ }
}
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusCodeType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusCodeType.java
index 2ce85eb..482834b 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusCodeType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusCodeType.java
@@ -17,6 +17,7 @@
*/
package org.keycloak.dom.saml.v2.protocol;
+import java.io.Serializable;
import java.net.URI;
/**
@@ -39,7 +40,7 @@ import java.net.URI;
* </complexType>
* </pre>
*/
-public class StatusCodeType {
+public class StatusCodeType implements Serializable {
protected StatusCodeType statusCode;
protected URI value;
diff --git a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusType.java b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusType.java
index 9918879..2e2eab9 100755
--- a/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusType.java
+++ b/saml/saml-core/src/main/java/org/keycloak/dom/saml/v2/protocol/StatusType.java
@@ -17,6 +17,8 @@
*/
package org.keycloak.dom.saml.v2.protocol;
+import java.io.Serializable;
+
/**
* <p>
* Java class for StatusType complex type.
@@ -38,7 +40,7 @@ package org.keycloak.dom.saml.v2.protocol;
* </complexType>
* </pre>
*/
-public class StatusType {
+public class StatusType implements Serializable {
protected String statusMessage;
protected StatusCodeType statusCode;
diff --git a/saml/saml-core/src/main/java/org/keycloak/saml/SAML2ErrorResponseBuilder.java b/saml/saml-core/src/main/java/org/keycloak/saml/SAML2ErrorResponseBuilder.java
index db7ac7e..2373656 100755
--- a/saml/saml-core/src/main/java/org/keycloak/saml/SAML2ErrorResponseBuilder.java
+++ b/saml/saml-core/src/main/java/org/keycloak/saml/SAML2ErrorResponseBuilder.java
@@ -1,6 +1,12 @@
package org.keycloak.saml;
+import org.keycloak.dom.saml.v2.assertion.NameIDType;
+import org.keycloak.dom.saml.v2.protocol.StatusCodeType;
+import org.keycloak.dom.saml.v2.protocol.StatusResponseType;
+import org.keycloak.dom.saml.v2.protocol.StatusType;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.common.exceptions.ConfigurationException;
+import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.exceptions.ProcessingException;
import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
import org.keycloak.saml.processing.core.saml.v2.common.IDGenerator;
@@ -9,8 +15,11 @@ import org.keycloak.saml.processing.core.saml.v2.holders.IDPInfoHolder;
import org.keycloak.saml.processing.core.saml.v2.holders.IssuerInfoHolder;
import org.keycloak.saml.processing.core.saml.v2.holders.SPInfoHolder;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
+import org.keycloak.saml.processing.core.saml.v2.util.XMLTimeUtil;
import org.w3c.dom.Document;
+import java.net.URI;
+
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@@ -38,29 +47,25 @@ public class SAML2ErrorResponseBuilder {
public Document buildDocument() throws ProcessingException {
- Document samlResponse = null;
- ResponseType responseType = null;
-
- SAML2Response saml2Response = new SAML2Response();
-
- // Create a response type
- String id = IDGenerator.create("ID_");
- IssuerInfoHolder issuerHolder = new IssuerInfoHolder(issuer);
- issuerHolder.setStatusCode(status);
+ try {
+ StatusResponseType statusResponse = new StatusResponseType(IDGenerator.create("ID_"), XMLTimeUtil.getIssueInstant());
- IDPInfoHolder idp = new IDPInfoHolder();
- idp.setNameIDFormatValue(null);
- idp.setNameIDFormat(JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get());
+ statusResponse.setStatus(JBossSAMLAuthnResponseFactory.createStatusTypeForResponder(status));
+ NameIDType issuer = new NameIDType();
+ issuer.setValue(this.issuer);
- SPInfoHolder sp = new SPInfoHolder();
- sp.setResponseDestinationURI(destination);
+ statusResponse.setIssuer(issuer);
+ statusResponse.setDestination(destination);
- responseType = saml2Response.createResponseType(id);
- responseType.setStatus(JBossSAMLAuthnResponseFactory.createStatusTypeForResponder(status));
- responseType.setDestination(destination);
+ SAML2Response saml2Response = new SAML2Response();
+ return saml2Response.convert(statusResponse);
+ } catch (ConfigurationException e) {
+ throw new ProcessingException(e);
+ } catch (ParsingException e) {
+ throw new ProcessingException(e);
+ }
- return samlResponse;
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java
index f97a05e..84fa65c 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java
@@ -67,6 +67,10 @@ public class SamlAdapterTest {
}
@Test
+ public void testErrorHandling() throws Exception {
+ testStrategy.testErrorHandling();
+ }
+ @Test
public void testMetadataPostSignedLoginLogout() throws Exception {
testStrategy.testMetadataPostSignedLoginLogout();
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
index fbced9f..abe108a 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
@@ -1,27 +1,16 @@
package org.keycloak.testsuite.keycloaksaml;
-import com.mongodb.util.Hash;
import org.apache.commons.io.IOUtils;
-import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
import org.junit.rules.ExternalResource;
-import org.keycloak.Config;
import org.keycloak.adapters.saml.SamlPrincipal;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserModel;
-import org.keycloak.models.UserSessionModel;
-import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
import org.keycloak.protocol.saml.mappers.GroupMembershipMapper;
import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
@@ -29,33 +18,27 @@ import org.keycloak.protocol.saml.mappers.HardcodedRole;
import org.keycloak.protocol.saml.mappers.RoleListMapper;
import org.keycloak.protocol.saml.mappers.RoleNameMapper;
import org.keycloak.protocol.saml.mappers.UserAttributeStatementMapper;
-import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.saml.BaseSAML2BindingBuilder;
+import org.keycloak.saml.SAML2ErrorResponseBuilder;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
import org.keycloak.services.managers.RealmManager;
-import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.testsuite.KeycloakServer;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
-import org.keycloak.util.JsonSerialization;
import org.openqa.selenium.WebDriver;
+import org.w3c.dom.Document;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.client.ClientRequestContext;
-import javax.ws.rs.client.ClientRequestFilter;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
-import java.io.InputStream;
+import java.net.URI;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -116,6 +99,27 @@ public class SamlAdapterTestStrategy extends ExternalResource {
Assert.assertTrue(driver.getCurrentUrl().startsWith(AUTH_SERVER_URL + "/realms/demo/protocol/saml"));
}
+ public void testErrorHandling() throws Exception {
+ Client client = ClientBuilder.newClient();
+ // make sure
+ Response response = client.target(APP_SERVER_BASE_URL + "/employee-sig/").request().get();
+ response.close();
+ SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder()
+ .destination(APP_SERVER_BASE_URL + "/employee-sig/")
+ .issuer(AUTH_SERVER_URL + "/realms/demo")
+ .status(JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
+ BaseSAML2BindingBuilder binding = new BaseSAML2BindingBuilder()
+ .relayState(null);
+ Document document = builder.buildDocument();
+ URI uri = binding.redirectBinding(document).generateURI(APP_SERVER_BASE_URL + "/employee-sig/", false);
+ response = client.target(uri).request().get();
+ String errorPage = response.readEntity(String.class);
+ response.close();
+ Assert.assertTrue(errorPage.contains(JBossSAMLURIConstants.STATUS_RESPONDER.get()));
+ client.close();
+
+ }
+
public void testPostSimpleLoginLogout() {
driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post/");
assertEquals(driver.getCurrentUrl(), AUTH_SERVER_URL + "/realms/demo/protocol/saml");
diff --git a/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index 1506b0c..3eb9a80 100755
--- a/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty81/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -105,6 +105,11 @@ public class JettySamlTest {
}
@Test
+ public void testErrorHandling() throws Exception {
+ testStrategy.testErrorHandling();
+ }
+
+ @Test
public void testPostSimpleLoginLogout() {
testStrategy.testPostSimpleLoginLogout();
}
diff --git a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index e71887e..25cf046 100755
--- a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -104,6 +104,11 @@ public class JettySamlTest {
}
@Test
+ public void testErrorHandling() throws Exception {
+ testStrategy.testErrorHandling();
+ }
+
+ @Test
public void testPostSimpleLoginLogout() {
testStrategy.testPostSimpleLoginLogout();
}
diff --git a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java
index e71887e..25cf046 100755
--- a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java
+++ b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -104,6 +104,11 @@ public class JettySamlTest {
}
@Test
+ public void testErrorHandling() throws Exception {
+ testStrategy.testErrorHandling();
+ }
+
+ @Test
public void testPostSimpleLoginLogout() {
testStrategy.testPostSimpleLoginLogout();
}
diff --git a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
index c72ab01..ecda388 100755
--- a/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
+++ b/testsuite/tomcat6/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
@@ -113,6 +113,11 @@ public class TomcatSamlTest {
}
@Test
+ public void testErrorHandling() throws Exception {
+ testStrategy.testErrorHandling();
+ }
+
+ @Test
public void testPostSignedLoginLogoutEmailNameID() {
testStrategy.testPostSignedLoginLogoutEmailNameID();
}
diff --git a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
index f9cb853..9653f31 100755
--- a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
+++ b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
@@ -93,6 +93,11 @@ public class TomcatSamlTest {
@Test
+ public void testErrorHandling() throws Exception {
+ testStrategy.testErrorHandling();
+ }
+
+ @Test
public void testPostSimpleLoginLogout() {
testStrategy.testPostSimpleLoginLogout();
}
diff --git a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
index 405c6ee..88d9316 100755
--- a/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
+++ b/testsuite/tomcat8/src/test/java/org/keycloak/testsuite/TomcatSamlTest.java
@@ -93,6 +93,11 @@ public class TomcatSamlTest {
public SamlAdapterTestStrategy testStrategy = new SamlAdapterTestStrategy("http://localhost:8081/auth", "http://localhost:8082", keycloakRule);
@Test
+ public void testErrorHandling() throws Exception {
+ testStrategy.testErrorHandling();
+ }
+
+ @Test
public void testPostSimpleLoginLogout() {
testStrategy.testPostSimpleLoginLogout();
}