keycloak-aplcache

Merge pull request #1961 from pedroigor/KEYCLOAK-2202 [KEYCLOAK-2202]

12/22/2015 1:48:54 PM

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