keycloak-aplcache
Changes
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileProtocolFactory.java 109(+0 -109)
saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java 74(+72 -2)
Details
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
index c16b997..52b8557 100644
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
@@ -6,13 +6,24 @@ import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows;
+import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
import org.keycloak.protocol.saml.SamlProtocol;
import org.keycloak.protocol.saml.SamlService;
import org.keycloak.protocol.saml.profile.ecp.util.Soap;
+import org.keycloak.saml.SAML2LogoutResponseBuilder;
+import org.keycloak.saml.common.constants.JBossSAMLConstants;
+import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.common.exceptions.ConfigurationException;
+import org.keycloak.saml.common.exceptions.ProcessingException;
import org.keycloak.services.managers.AuthenticationManager;
+import org.w3c.dom.Document;
import javax.ws.rs.core.Response;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPHeaderElement;
+import java.io.IOException;
import java.io.InputStream;
/**
@@ -20,6 +31,10 @@ import java.io.InputStream;
*/
public class SamlEcpProfileService extends SamlService {
+ private static final String NS_PREFIX_PROFILE_ECP = "ecp";
+ private static final String NS_PREFIX_SAML_PROTOCOL = "samlp";
+ private static final String NS_PREFIX_SAML_ASSERTION = "saml";
+
public SamlEcpProfileService(RealmModel realm, EventBuilder event, AuthenticationManager authManager) {
super(realm, event, authManager);
}
@@ -53,8 +68,63 @@ public class SamlEcpProfileService extends SamlService {
}
@Override
- protected String getLoginProtocol() {
- return SamlEcpProfileProtocolFactory.ID;
+ protected Response newBrowserAuthentication(ClientSessionModel clientSession, boolean isPassive, SamlProtocol samlProtocol) {
+ return super.newBrowserAuthentication(clientSession, isPassive, createEcpSamlProtocol());
+ }
+
+ private SamlProtocol createEcpSamlProtocol() {
+ return new SamlProtocol() {
+ // method created to send a SOAP Binding response instead of a HTTP POST response
+ @Override
+ protected Response buildAuthenticatedResponse(ClientSessionModel clientSession, String redirectUri, Document samlDocument, JaxrsSAML2BindingBuilder bindingBuilder) throws ConfigurationException, ProcessingException, IOException {
+ Document document = bindingBuilder.postBinding(samlDocument).getDocument();
+
+ try {
+ Soap.SoapMessageBuilder messageBuilder = Soap.createMessage()
+ .addNamespace(NS_PREFIX_SAML_ASSERTION, JBossSAMLURIConstants.ASSERTION_NSURI.get())
+ .addNamespace(NS_PREFIX_SAML_PROTOCOL, JBossSAMLURIConstants.PROTOCOL_NSURI.get())
+ .addNamespace(NS_PREFIX_PROFILE_ECP, JBossSAMLURIConstants.ECP_PROFILE.get());
+
+ createEcpResponseHeader(redirectUri, messageBuilder);
+ createRequestAuthenticatedHeader(clientSession, messageBuilder);
+
+ messageBuilder.addToBody(document);
+
+ return messageBuilder.build();
+ } catch (Exception e) {
+ throw new RuntimeException("Error while creating SAML response.", e);
+ }
+ }
+
+ private void createRequestAuthenticatedHeader(ClientSessionModel clientSession, Soap.SoapMessageBuilder messageBuilder) {
+ ClientModel client = clientSession.getClient();
+
+ if ("true".equals(client.getAttribute(SamlProtocol.SAML_CLIENT_SIGNATURE_ATTRIBUTE))) {
+ SOAPHeaderElement ecpRequestAuthenticated = messageBuilder.addHeader(JBossSAMLConstants.REQUEST_AUTHENTICATED.get(), NS_PREFIX_PROFILE_ECP);
+
+ ecpRequestAuthenticated.setMustUnderstand(true);
+ ecpRequestAuthenticated.setActor("http://schemas.xmlsoap.org/soap/actor/next");
+ }
+ }
+
+ private void createEcpResponseHeader(String redirectUri, Soap.SoapMessageBuilder messageBuilder) throws SOAPException {
+ SOAPHeaderElement ecpResponseHeader = messageBuilder.addHeader(JBossSAMLConstants.RESPONSE.get(), NS_PREFIX_PROFILE_ECP);
+
+ ecpResponseHeader.setMustUnderstand(true);
+ ecpResponseHeader.setActor("http://schemas.xmlsoap.org/soap/actor/next");
+ ecpResponseHeader.addAttribute(messageBuilder.createName(JBossSAMLConstants.ASSERTION_CONSUMER_SERVICE_URL.get()), redirectUri);
+ }
+
+ @Override
+ protected Response buildErrorResponse(ClientSessionModel clientSession, JaxrsSAML2BindingBuilder binding, Document document) throws ConfigurationException, ProcessingException, IOException {
+ return Soap.createMessage().addToBody(document).build();
+ }
+
+ @Override
+ protected Response buildLogoutResponse(UserSessionModel userSession, String logoutBindingUri, SAML2LogoutResponseBuilder builder, JaxrsSAML2BindingBuilder binding) throws ConfigurationException, ProcessingException, IOException {
+ return Soap.createFault().reason("Logout not supported.").build();
+ }
+ }.setEventBuilder(event).setHttpHeaders(headers).setRealm(realm).setSession(session).setUriInfo(uriInfo);
}
@Override
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index f9aa30b..67edd49 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -35,7 +35,6 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.AuthorizationEndpointBase;
-import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.oidc.utils.RedirectUtils;
import org.keycloak.protocol.saml.profile.ecp.SamlEcpProfileService;
import org.keycloak.saml.SAML2LogoutResponseBuilder;
@@ -224,7 +223,7 @@ public class SamlService extends AuthorizationEndpointBase {
}
ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
- clientSession.setAuthMethod(getLoginProtocol());
+ clientSession.setAuthMethod(SamlProtocol.LOGIN_PROTOCOL);
clientSession.setRedirectUri(redirect);
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
@@ -373,7 +372,7 @@ public class SamlService extends AuthorizationEndpointBase {
}
}
- public class PostBindingProtocol extends BindingProtocol {
+ protected class PostBindingProtocol extends BindingProtocol {
@Override
protected void verifySignature(SAMLDocumentHolder documentHolder, ClientModel client) throws VerificationException {
@@ -446,12 +445,12 @@ public class SamlService extends AuthorizationEndpointBase {
}
protected Response newBrowserAuthentication(ClientSessionModel clientSession, boolean isPassive) {
- LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
- protocol.setRealm(realm)
- .setHttpHeaders(request.getHttpHeaders())
- .setUriInfo(uriInfo)
- .setEventBuilder(event);
- return handleBrowserAuthenticationRequest(clientSession, protocol, isPassive);
+ SamlProtocol samlProtocol = new SamlProtocol().setEventBuilder(event).setHttpHeaders(headers).setRealm(realm).setSession(session).setUriInfo(uriInfo);
+ return newBrowserAuthentication(clientSession, isPassive, samlProtocol);
+ }
+
+ protected Response newBrowserAuthentication(ClientSessionModel clientSession, boolean isPassive, SamlProtocol samlProtocol) {
+ return handleBrowserAuthenticationRequest(clientSession, samlProtocol, isPassive);
}
/**
@@ -471,16 +470,6 @@ public class SamlService extends AuthorizationEndpointBase {
return new PostBindingProtocol().execute(samlRequest, samlResponse, relayState);
}
- @POST
- @Consumes("application/soap+xml")
- public Response soapBinding(InputStream inputStream) {
- SamlEcpProfileService bindingService = new SamlEcpProfileService(realm, event, authManager);
-
- ResteasyProviderFactory.getInstance().injectProperties(bindingService);
-
- return bindingService.authenticate(inputStream);
- }
-
@GET
@Path("descriptor")
@Produces(MediaType.APPLICATION_XML)
@@ -537,7 +526,7 @@ public class SamlService extends AuthorizationEndpointBase {
}
ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
- clientSession.setAuthMethod(getLoginProtocol());
+ clientSession.setAuthMethod(SamlProtocol.LOGIN_PROTOCOL);
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
clientSession.setNote(SamlProtocol.SAML_BINDING, SamlProtocol.SAML_POST_BINDING);
@@ -555,8 +544,14 @@ public class SamlService extends AuthorizationEndpointBase {
}
- protected String getLoginProtocol() {
- return SamlProtocol.LOGIN_PROTOCOL;
+ @POST
+ @Consumes("application/soap+xml")
+ public Response soapBinding(InputStream inputStream) {
+ SamlEcpProfileService bindingService = new SamlEcpProfileService(realm, event, authManager);
+
+ ResteasyProviderFactory.getInstance().injectProperties(bindingService);
+
+ return bindingService.authenticate(inputStream);
}
}
diff --git a/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.LoginProtocolFactory b/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.LoginProtocolFactory
index ae434f6..d0a2dd0 100755
--- a/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.LoginProtocolFactory
+++ b/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.LoginProtocolFactory
@@ -1,2 +1 @@
-org.keycloak.protocol.saml.SamlProtocolFactory
-org.keycloak.protocol.saml.profile.ecp.SamlEcpProfileProtocolFactory
\ No newline at end of file
+org.keycloak.protocol.saml.SamlProtocolFactory
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index 75803f1..17c02af 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -810,10 +810,10 @@ public class AuthenticationProcessor {
AuthenticationManager.evaluateRequiredActionTriggers(session, userSession, clientSession, connection, request, uriInfo, event, realm, clientSession.getAuthenticatedUser());
}
- public Response finishAuthentication() {
+ public Response finishAuthentication(LoginProtocol protocol) {
event.success();
RealmModel realm = clientSession.getRealm();
- return AuthenticationManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, connection, event);
+ return AuthenticationManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, connection, event, protocol);
}
diff --git a/services/src/main/java/org/keycloak/protocol/AuthorizationEndpointBase.java b/services/src/main/java/org/keycloak/protocol/AuthorizationEndpointBase.java
index 9dc5548..befd364 100644
--- a/services/src/main/java/org/keycloak/protocol/AuthorizationEndpointBase.java
+++ b/services/src/main/java/org/keycloak/protocol/AuthorizationEndpointBase.java
@@ -115,7 +115,7 @@ public abstract class AuthorizationEndpointBase {
else
return protocol.sendError(clientSession, Error.PASSIVE_INTERACTION_REQUIRED);
} else {
- return processor.finishAuthentication();
+ return processor.finishAuthentication(protocol);
}
} else {
try {
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 0131b6d..d034d75 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -382,6 +382,19 @@ public class AuthenticationManager {
ClientSessionModel clientSession,
HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection,
EventBuilder event) {
+ LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
+ protocol.setRealm(realm)
+ .setHttpHeaders(request.getHttpHeaders())
+ .setUriInfo(uriInfo)
+ .setEventBuilder(event);
+ return redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, clientConnection, event, protocol);
+
+ }
+
+ public static Response redirectAfterSuccessfulFlow(KeycloakSession session, RealmModel realm, UserSessionModel userSession,
+ ClientSessionModel clientSession,
+ HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection,
+ EventBuilder event, LoginProtocol protocol) {
Cookie sessionCookie = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_SESSION_COOKIE);
if (sessionCookie != null) {
@@ -405,12 +418,6 @@ public class AuthenticationManager {
createLoginCookie(realm, userSession.getUser(), userSession, uriInfo, clientConnection);
if (userSession.getState() != UserSessionModel.State.LOGGED_IN) userSession.setState(UserSessionModel.State.LOGGED_IN);
if (userSession.isRememberMe()) createRememberMeCookie(realm, userSession.getUser().getUsername(), uriInfo, clientConnection);
- LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
- protocol.setRealm(realm)
- .setHttpHeaders(request.getHttpHeaders())
- .setUriInfo(uriInfo)
- .setEventBuilder(event);
- RestartLoginCookie.expireRestartCookie(realm, clientConnection, uriInfo);
return protocol.authenticated(userSession, new ClientSessionCode(realm, clientSession));
}