keycloak-aplcache

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 bf3bc9f..f9efe19 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -815,52 +815,58 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
         return browserAuthentication(clientCode.getClientSession(), message);
     }
 
-    private Response performAccountLinking(ClientSessionModel clientSession, BrokeredIdentityContext context, FederatedIdentityModel federatedIdentityModel, UserModel federatedUser) {
+    private Response performAccountLinking(ClientSessionModel clientSession, BrokeredIdentityContext context, FederatedIdentityModel newModel, UserModel federatedUser) {
         this.event.event(EventType.FEDERATED_IDENTITY_LINK);
 
-        UserModel authenticatedUser = clientSession.getUserSession().getUser();
 
-        if (federatedUser != null) {
-            if (authenticatedUser.getId().equals(federatedUser.getId())) {
-                // refresh the token
-                if (context.getIdpConfig().isStoreToken()) {
-                    federatedIdentityModel = this.session.users().getFederatedIdentity(federatedUser, context.getIdpConfig().getAlias(), this.realmModel);
-                    if (!ObjectUtil.isEqualOrBothNull(context.getToken(), federatedIdentityModel.getToken())) {
 
-                        this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
+        UserModel authenticatedUser = clientSession.getUserSession().getUser();
 
-                        if (isDebugEnabled()) {
-                            logger.debugf("Identity [%s] update with response from identity provider [%s].", federatedUser, context.getIdpConfig().getAlias());
-                        }
-                    }
-                }
-                return Response.status(302).location(UriBuilder.fromUri(clientSession.getRedirectUri()).build()).build();
-            } else {
-                return redirectToAccountErrorPage(clientSession, Messages.IDENTITY_PROVIDER_ALREADY_LINKED, context.getIdpConfig().getAlias());
-            }
+        if (federatedUser != null && !authenticatedUser.getId().equals(federatedUser.getId())) {
+            return redirectToAccountErrorPage(clientSession, Messages.IDENTITY_PROVIDER_ALREADY_LINKED, context.getIdpConfig().getAlias());
         }
 
-
-        if (isDebugEnabled()) {
-            logger.debugf("Linking account [%s] from identity provider [%s] to user [%s].", federatedIdentityModel, context.getIdpConfig().getAlias(), authenticatedUser);
+        if (!authenticatedUser.hasRole(this.realmModel.getClientByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(MANAGE_ACCOUNT))) {
+            return redirectToErrorPage(Messages.INSUFFICIENT_PERMISSION);
         }
 
         if (!authenticatedUser.isEnabled()) {
             return redirectToAccountErrorPage(clientSession, Messages.ACCOUNT_DISABLED);
         }
 
-        if (!authenticatedUser.hasRole(this.realmModel.getClientByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(MANAGE_ACCOUNT))) {
-            return redirectToErrorPage(Messages.INSUFFICIENT_PERMISSION);
-        }
 
-        this.session.users().addFederatedIdentity(this.realmModel, authenticatedUser, federatedIdentityModel);
+
+        if (federatedUser != null) {
+            if (context.getIdpConfig().isStoreToken()) {
+                FederatedIdentityModel oldModel = this.session.users().getFederatedIdentity(federatedUser, context.getIdpConfig().getAlias(), this.realmModel);
+                if (!ObjectUtil.isEqualOrBothNull(context.getToken(), oldModel.getToken())) {
+                    this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, newModel);
+                    if (isDebugEnabled()) {
+                        logger.debugf("Identity [%s] update with response from identity provider [%s].", federatedUser, context.getIdpConfig().getAlias());
+                    }
+                }
+            }
+        } else {
+            this.session.users().addFederatedIdentity(this.realmModel, authenticatedUser, newModel);
+        }
         context.getIdp().attachUserSession(clientSession.getUserSession(), clientSession, context);
 
+
+        if (isDebugEnabled()) {
+            logger.debugf("Linking account [%s] from identity provider [%s] to user [%s].", newModel, context.getIdpConfig().getAlias(), authenticatedUser);
+        }
+
         this.event.user(authenticatedUser)
                 .detail(Details.USERNAME, authenticatedUser.getUsername())
-                .detail(Details.IDENTITY_PROVIDER, federatedIdentityModel.getIdentityProvider())
-                .detail(Details.IDENTITY_PROVIDER_USERNAME, federatedIdentityModel.getUserName())
+                .detail(Details.IDENTITY_PROVIDER, newModel.getIdentityProvider())
+                .detail(Details.IDENTITY_PROVIDER_USERNAME, newModel.getUserName())
                 .success();
+
+        // we do this to make sure that the parent IDP is logged out when this user session is complete.
+
+        clientSession.getUserSession().setNote(Details.IDENTITY_PROVIDER, context.getIdpConfig().getAlias());
+        clientSession.getUserSession().setNote(Details.IDENTITY_PROVIDER_USERNAME, context.getUsername());
+
         return Response.status(302).location(UriBuilder.fromUri(clientSession.getRedirectUri()).build()).build();
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
index 0977d2d..b047595 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
@@ -433,6 +433,7 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
 
         // Assert I am logged immediately to account management due to previously linked "test-user" identity
         loginPage.clickSocial(identityProviderModel.getAlias());
+        this.loginPage.login("test-user", "password");
         doAfterProviderAuthentication();
         assertTrue(accountFederatedIdentityPage.isCurrent());
         assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getAlias() + "\""));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerTestTools.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerTestTools.java
index 40c1f70..a43d842 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerTestTools.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/BrokerTestTools.java
@@ -93,12 +93,12 @@ public class BrokerTestTools {
     public static void createKcOidcBroker(Keycloak adminClient, String childRealm, String idpRealm, SuiteContext suiteContext, String alias, boolean linkOnly) {
         IdentityProviderRepresentation idp = createIdentityProvider(alias, IDP_OIDC_PROVIDER_ID);
         idp.setLinkOnly(linkOnly);
+        idp.setStoreToken(true);
 
         Map<String, String> config = idp.getConfig();
 
         config.put("clientId", childRealm);
         config.put("clientSecret", childRealm);
-        config.put("prompt", "login");
         config.put("authorizationUrl", getAuthRoot(suiteContext) + "/auth/realms/" + idpRealm + "/protocol/openid-connect/auth");
         config.put("tokenUrl", getAuthRoot(suiteContext) + "/auth/realms/" + idpRealm + "/protocol/openid-connect/token");
         config.put("logoutUrl", getAuthRoot(suiteContext) + "/auth/realms/" + idpRealm + "/protocol/openid-connect/logout");
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/ClientInitiatedAccountLinkTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/ClientInitiatedAccountLinkTest.java
index e639127..487e878 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/ClientInitiatedAccountLinkTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/ClientInitiatedAccountLinkTest.java
@@ -29,8 +29,10 @@ import org.keycloak.OAuth2Constants;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.common.util.Base64Url;
+import org.keycloak.models.Constants;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
@@ -48,7 +50,12 @@ import org.keycloak.testsuite.pages.AccountFederatedIdentityPage;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
 import org.keycloak.testsuite.util.AdapterServletDeployment;
+import org.keycloak.testsuite.util.OAuthClient;
+import org.keycloak.util.JsonSerialization;
 
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import java.net.URL;
 import java.util.LinkedList;
@@ -82,6 +89,10 @@ public class ClientInitiatedAccountLinkTest extends AbstractKeycloakTest {
     @Page
     protected AppServerContextRoot appServerContextRootPage;
 
+    @ArquillianResource
+    protected OAuthClient oauth;
+
+
     public boolean isRelative() {
         return testContext.isRelativeAdapterTest();
     }
@@ -122,6 +133,7 @@ public class ClientInitiatedAccountLinkTest extends AbstractKeycloakTest {
             uri = appServerContextRootPage.toString() + uri;
         }
         servlet.setAdminUrl(uri);
+        servlet.setDirectAccessGrantsEnabled(true);
         servlet.setBaseUrl(uri);
         servlet.setRedirectUris(new LinkedList<>());
         servlet.getRedirectUris().add(uri + "/*");
@@ -172,6 +184,11 @@ public class ClientInitiatedAccountLinkTest extends AbstractKeycloakTest {
         List<RoleRepresentation> roles = new LinkedList<>();
         roles.add(role);
         realm.users().get(childUserId).roles().realmLevel().add(roles);
+        ClientRepresentation brokerService = realm.clients().findByClientId(Constants.BROKER_SERVICE_CLIENT_ID).get(0);
+        role = realm.clients().get(brokerService.getId()).roles().get(Constants.READ_TOKEN_ROLE).toRepresentation();
+        roles.clear();
+        roles.add(role);
+        realm.users().get(childUserId).roles().clientLevel(brokerService.getId()).add(roles);
 
     }
 
@@ -391,6 +408,25 @@ public class ClientInitiatedAccountLinkTest extends AbstractKeycloakTest {
         Assert.assertTrue(driver.getCurrentUrl().startsWith(linkBuilder.toTemplate()));
         Assert.assertTrue(driver.getPageSource().contains("Account Linked"));
 
+        OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest(CHILD_IDP, "child", "password", null, "client-linking", "password");
+        Assert.assertNotNull(response.getAccessToken());
+        Assert.assertNull(response.getError());
+        Client httpClient = ClientBuilder.newClient();
+        String firstToken = getToken(response, httpClient);
+        Assert.assertNotNull(firstToken);
+
+
+        driver.navigate().to(linkUrl);
+        Assert.assertTrue(driver.getPageSource().contains("Account Linked"));
+        String nextToken = getToken(response, httpClient);
+        Assert.assertNotNull(nextToken);
+        Assert.assertNotEquals(firstToken, nextToken);
+
+
+
+
+
+
         links = realm.users().get(childUserId).getFederatedIdentity();
         Assert.assertFalse(links.isEmpty());
 
@@ -403,6 +439,19 @@ public class ClientInitiatedAccountLinkTest extends AbstractKeycloakTest {
 
     }
 
+    private String getToken(OAuthClient.AccessTokenResponse response, Client httpClient) throws Exception {
+        String idpToken =  httpClient.target(oauth.AUTH_SERVER_ROOT)
+                .path("realms")
+                .path("child/broker")
+                .path(PARENT_IDP)
+                .path("token")
+                .request()
+                .header("Authorization", "Bearer " + response.getAccessToken())
+                .get(String.class);
+        AccessTokenResponse res = JsonSerialization.readValue(idpToken, AccessTokenResponse.class);
+        return res.getToken();
+    }
+
     public void logoutAll() {
         String logoutUri = OIDCLoginProtocolService.logoutUrl(authServerPage.createUriBuilder()).build(CHILD_IDP).toString();
         driver.navigate().to(logoutUri);