keycloak-uncached

KEYCLOAK-2769 Fix NPE during 'Identity Broker cancelled'

4/8/2016 2:06:52 PM

Details

diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index 27d47b5..4a9d993 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -531,7 +531,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
     @Override
     public Response cancelled(String code) {
         ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realmModel);
-        if (clientCode.getClientSession() == null || !clientCode.isValid(AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
+        if (clientCode == null || !clientCode.isValid(AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
             return redirectToErrorPage(Messages.INVALID_CODE);
         }
 
@@ -541,7 +541,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
     @Override
     public Response error(String code, String message) {
         ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, this.realmModel);
-        if (clientCode.getClientSession() == null || !clientCode.isValid(AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
+        if (clientCode == null || !clientCode.isValid(AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
             return redirectToErrorPage(Messages.INVALID_CODE);
         }
         return browserAuthentication(clientCode.getClientSession(), message);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
index b45213a..f5f80f5 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -40,6 +40,7 @@ import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionSt
 import org.keycloak.testsuite.pages.AccountFederatedIdentityPage;
 import org.keycloak.testsuite.pages.AccountPasswordPage;
 import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
+import org.keycloak.testsuite.pages.ErrorPage;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
 import org.keycloak.testsuite.pages.OAuthGrantPage;
@@ -109,6 +110,9 @@ public abstract class AbstractIdentityProviderTest {
     @WebResource
     protected AccountFederatedIdentityPage accountFederatedIdentityPage;
 
+    @WebResource
+    protected ErrorPage errorPage;
+
     protected KeycloakSession session;
 
     protected int logoutTimeOffset = 0;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
index ad3e9ff..68d903c 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
@@ -17,12 +17,16 @@
 
 package org.keycloak.testsuite.broker;
 
+import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.common.util.Time;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.services.Urls;
@@ -30,7 +34,6 @@ import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.Constants;
 import org.keycloak.testsuite.KeycloakServer;
 import org.keycloak.testsuite.pages.AccountApplicationsPage;
-import org.keycloak.testsuite.pages.OAuthGrantPage;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.util.JsonSerialization;
@@ -38,6 +41,7 @@ import org.openqa.selenium.NoSuchElementException;
 
 import javax.ws.rs.core.UriBuilder;
 import java.io.IOException;
+import java.util.List;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
@@ -69,9 +73,6 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityP
     };
 
     @WebResource
-    private OAuthGrantPage grantPage;
-
-    @WebResource
     protected AccountApplicationsPage accountApplicationsPage;
 
     @Override
@@ -139,6 +140,65 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityP
         keycloak.realm("realm-with-broker").identityProviders().get("kc-oidc-idp").update(idp);
     }
 
+
+    @Test
+    public void testAccessDeniedError() throws Exception {
+        // Disable update profile
+        setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF);
+
+        Keycloak keycloak1 = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID);
+        Keycloak keycloak2 = Keycloak.getInstance("http://localhost:8082/auth", "master", "admin", "admin", org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID);
+
+        // Require broker to show consent screen
+        RealmResource brokeredRealm = keycloak2.realm("realm-with-oidc-identity-provider");
+        List<ClientRepresentation> clients = brokeredRealm.clients().findByClientId("broker-app");
+        Assert.assertEquals(1, clients.size());
+        ClientRepresentation brokerApp = clients.get(0);
+        brokerApp.setConsentRequired(true);
+        brokeredRealm.clients().get(brokerApp.getId()).update(brokerApp);
+
+        // Change timeouts on realm-with-broker to lower values
+        RealmResource realmWithBroker = keycloak1.realm("realm-with-broker");
+        RealmRepresentation realmBackup = realmWithBroker.toRepresentation();
+        RealmRepresentation realm = realmWithBroker.toRepresentation();
+        realm.setAccessCodeLifespanLogin(30);;
+        realm.setAccessCodeLifespan(30);
+        realm.setAccessCodeLifespanUserAction(30);
+        realmWithBroker.update(realm);
+
+        // Login to broker
+        loginIDP("test-user");
+
+        // Set time offset and manually enforce removeExpired sessions TODO: Will need custom REST endpoints for that on integration-arquillian
+        Time.setOffset(60);
+        try {
+            brokerServerRule.stopSession(this.session, true);
+            this.session = brokerServerRule.startSession();
+
+            session.sessions().removeExpired(getRealm());
+
+            brokerServerRule.stopSession(this.session, true);
+            this.session = brokerServerRule.startSession();
+
+            // User rejected consent
+            grantPage.assertCurrent();
+            grantPage.cancel();
+
+            // Assert classic error page ( We're sorry ) displayed. TODO: Should be improved? See KEYCLOAK-2740
+            errorPage.assertCurrent();
+
+        } finally {
+            Time.setOffset(0);
+        }
+
+        // Revert consent
+        brokerApp.setConsentRequired(false);
+        brokeredRealm.clients().get(brokerApp.getId()).update(brokerApp);
+
+        // Revert timeouts
+        realmWithBroker.update(realmBackup);
+    }
+
     @Test
     public void testSuccessfulAuthenticationWithoutUpdateProfile() {
         super.testSuccessfulAuthenticationWithoutUpdateProfile();