keycloak-uncached

Merge pull request #4509 from TeliaSoneraNorge/KEYCLOAK-5032 KEYCLOAK-5032

10/13/2017 7:47:05 PM

Details

diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java
index 4098439..d0b445c 100644
--- a/core/src/main/java/org/keycloak/OAuth2Constants.java
+++ b/core/src/main/java/org/keycloak/OAuth2Constants.java
@@ -79,6 +79,7 @@ public interface OAuth2Constants {
     String UI_LOCALES_PARAM = "ui_locales";
 
     String PROMPT = "prompt";
+    String ACR_VALUES = "acr_values";
 
     String MAX_AGE = "max_age";
 
diff --git a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
index 98d4e34..c549688 100755
--- a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
@@ -306,6 +306,19 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
         if (getConfig().isLoginHint() && loginHint != null) {
             uriBuilder.queryParam(OIDCLoginProtocol.LOGIN_HINT_PARAM, loginHint);
         }
+
+        String prompt = getConfig().getPrompt();
+        if (prompt == null || prompt.isEmpty()) {
+            prompt = request.getAuthenticationSession().getClientNote(OAuth2Constants.PROMPT);
+        }
+        if (prompt != null) {
+            uriBuilder.queryParam(OAuth2Constants.PROMPT, prompt);
+        }
+
+        String acr = request.getAuthenticationSession().getClientNote(OAuth2Constants.ACR_VALUES);
+        if (acr != null) {
+            uriBuilder.queryParam(OAuth2Constants.ACR_VALUES, acr);
+        }
         return uriBuilder;
     }
 
diff --git a/services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java b/services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java
index 13dbcdd..6cc6750 100644
--- a/services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java
@@ -82,4 +82,8 @@ public class OAuth2IdentityProviderConfig extends IdentityProviderModel {
     public void setLoginHint(boolean loginHint) {
         getConfig().put("loginHint", String.valueOf(loginHint));
     }
+
+    public String getPrompt() {
+        return getConfig().get("prompt");
+    }
 }
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
index 014d835..6d5e15c 100755
--- a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java
@@ -71,7 +71,6 @@ import java.security.PublicKey;
 public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIdentityProviderConfig> implements ExchangeExternalToken {
     protected static final Logger logger = Logger.getLogger(OIDCIdentityProvider.class);
 
-    public static final String OAUTH2_PARAMETER_PROMPT = "prompt";
     public static final String SCOPE_OPENID = "openid";
     public static final String FEDERATED_ID_TOKEN = "FEDERATED_ID_TOKEN";
     public static final String USER_INFO = "UserInfo";
@@ -213,18 +212,6 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
         }
     }
 
-    @Override
-    protected UriBuilder createAuthorizationUrl(AuthenticationRequest request) {
-        UriBuilder authorizationUrl = super.createAuthorizationUrl(request);
-        String prompt = getConfig().getPrompt();
-
-        if (prompt != null && !prompt.isEmpty()) {
-            authorizationUrl.queryParam(OAUTH2_PARAMETER_PROMPT, prompt);
-        }
-
-        return authorizationUrl;
-    }
-
     protected void processAccessTokenResponse(BrokeredIdentityContext context, AccessTokenResponse response) {
 
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index 7a1f005..c8064e2 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -434,6 +434,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
         if (request.getIdpHint() != null) authenticationSession.setClientNote(AdapterConstants.KC_IDP_HINT, request.getIdpHint());
         if (request.getResponseMode() != null) authenticationSession.setClientNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM, request.getResponseMode());
         if (request.getClaims()!= null) authenticationSession.setClientNote(OIDCLoginProtocol.CLAIMS_PARAM, request.getClaims());
+        if (request.getAcr() != null) authenticationSession.setClientNote(OIDCLoginProtocol.ACR_PARAM, request.getAcr());
 
         // https://tools.ietf.org/html/rfc7636#section-4
         if (request.getCodeChallenge() != null) authenticationSession.setClientNote(OIDCLoginProtocol.CODE_CHALLENGE_PARAM, request.getCodeChallenge());
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequest.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequest.java
index 29b734f..29edb03 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequest.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthorizationEndpointRequest.java
@@ -43,6 +43,12 @@ public class AuthorizationEndpointRequest {
     String codeChallenge;
     String codeChallengeMethod;
 
+    String acr;
+
+    public String getAcr() {
+        return acr;
+    }
+
     public String getClientId() {
         return clientId;
     }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthzEndpointRequestParser.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthzEndpointRequestParser.java
index 0f9d152..90160ee 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthzEndpointRequestParser.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/request/AuthzEndpointRequestParser.java
@@ -62,6 +62,7 @@ abstract class AuthzEndpointRequestParser {
         KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.REQUEST_PARAM);
         KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.REQUEST_URI_PARAM);
         KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.CLAIMS_PARAM);
+        KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.ACR_PARAM);
 
         // https://tools.ietf.org/html/rfc7636#section-6.1
         KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.CODE_CHALLENGE_PARAM);
@@ -89,6 +90,7 @@ abstract class AuthzEndpointRequestParser {
         request.nonce = replaceIfNotNull(request.nonce, getParameter(OIDCLoginProtocol.NONCE_PARAM));
         request.maxAge = replaceIfNotNull(request.maxAge, getIntParameter(OIDCLoginProtocol.MAX_AGE_PARAM));
         request.claims = replaceIfNotNull(request.claims, getParameter(OIDCLoginProtocol.CLAIMS_PARAM));
+        request.acr = replaceIfNotNull(request.acr, getParameter(OIDCLoginProtocol.ACR_PARAM));
 
         // https://tools.ietf.org/html/rfc7636#section-6.1
         request.codeChallenge = replaceIfNotNull(request.codeChallenge, getParameter(OIDCLoginProtocol.CODE_CHALLENGE_PARAM));
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index 91405d3..22d5313 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -69,6 +69,7 @@ public class OIDCLoginProtocol implements LoginProtocol {
     public static final String REQUEST_URI_PARAM = "request_uri";
     public static final String UI_LOCALES_PARAM = OAuth2Constants.UI_LOCALES_PARAM;
     public static final String CLAIMS_PARAM = "claims";
+    public static final String ACR_PARAM = "acr_values";
 
     public static final String LOGOUT_REDIRECT_URI = "OIDC_LOGOUT_REDIRECT_URI";
     public static final String ISSUER = "iss";
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerAcrParameterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerAcrParameterTest.java
new file mode 100644
index 0000000..d21bd72
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerAcrParameterTest.java
@@ -0,0 +1,94 @@
+package org.keycloak.testsuite.broker;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper;
+import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.Assert;
+
+import java.util.List;
+
+import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
+
+public class KcOidcBrokerAcrParameterTest extends AbstractBrokerTest {
+
+    private static final String ACR_VALUES = "acr_values";
+    private static final String ACR_3 = "3";
+
+    @Override
+    protected BrokerConfiguration getBrokerConfiguration() {
+        return KcOidcBrokerConfiguration.INSTANCE;
+    }
+
+    @Override
+    protected Iterable<IdentityProviderMapperRepresentation> createIdentityProviderMappers() {
+        IdentityProviderMapperRepresentation attrMapper1 = new IdentityProviderMapperRepresentation();
+        attrMapper1.setName("manager-role-mapper");
+        attrMapper1.setIdentityProviderMapper(ExternalKeycloakRoleToRoleMapper.PROVIDER_ID);
+        attrMapper1.setConfig(ImmutableMap.<String,String>builder()
+                .put("external.role", "manager")
+                .put("role", "manager")
+                .build());
+
+        IdentityProviderMapperRepresentation attrMapper2 = new IdentityProviderMapperRepresentation();
+        attrMapper2.setName("user-role-mapper");
+        attrMapper2.setIdentityProviderMapper(ExternalKeycloakRoleToRoleMapper.PROVIDER_ID);
+        attrMapper2.setConfig(ImmutableMap.<String,String>builder()
+                .put("external.role", "user")
+                .put("role", "user")
+                .build());
+
+        return Lists.newArrayList(attrMapper1, attrMapper2);
+    }
+
+    @Override
+    protected void loginUser() {
+        driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
+
+        driver.navigate().to(driver.getCurrentUrl() + "&" + ACR_VALUES + "=" + ACR_3);
+
+        log.debug("Clicking social " + bc.getIDPAlias());
+        accountLoginPage.clickSocial(bc.getIDPAlias());
+
+        waitForPage(driver, "log in to");
+
+        Assert.assertTrue("Driver should be on the provider realm page right now",
+                driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/"));
+
+        Assert.assertTrue(ACR_VALUES + "=" + ACR_3 + " should be part of the url",
+                driver.getCurrentUrl().contains(ACR_VALUES + "=" + ACR_3));
+
+        log.debug("Logging in");
+        accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword());
+
+        waitForPage(driver, "update account information");
+
+        updateAccountInformationPage.assertCurrent();
+        Assert.assertTrue("We must be on correct realm right now",
+                driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/"));
+
+
+        log.debug("Updating info on updateAccount page");
+        updateAccountInformationPage.updateAccountInformation(bc.getUserLogin(), bc.getUserEmail(), "Firstname", "Lastname");
+
+        UsersResource consumerUsers = adminClient.realm(bc.consumerRealmName()).users();
+
+        int userCount = consumerUsers.count();
+        Assert.assertTrue("There must be at least one user", userCount > 0);
+
+        List<UserRepresentation> users = consumerUsers.search("", 0, userCount);
+
+        boolean isUserFound = false;
+        for (UserRepresentation user : users) {
+            if (user.getUsername().equals(bc.getUserLogin()) && user.getEmail().equals(bc.getUserEmail())) {
+                isUserFound = true;
+                break;
+            }
+        }
+
+        Assert.assertTrue("There must be user " + bc.getUserLogin() + " in realm " + bc.consumerRealmName(),
+                isUserFound);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerPromptParameterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerPromptParameterTest.java
new file mode 100644
index 0000000..bf85af8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerPromptParameterTest.java
@@ -0,0 +1,107 @@
+package org.keycloak.testsuite.broker;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.arquillian.SuiteContext;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
+
+public class KcOidcBrokerPromptParameterTest extends AbstractBrokerTest {
+
+    private static final String PROMPT_CONSENT = "consent";
+    private static final String PROMPT_LOGIN = "login";
+
+    @Override
+    protected BrokerConfiguration getBrokerConfiguration() {
+        return new KcOidcBrokerConfiguration2();
+    }
+
+    @Override
+    protected Iterable<IdentityProviderMapperRepresentation> createIdentityProviderMappers() {
+        IdentityProviderMapperRepresentation attrMapper1 = new IdentityProviderMapperRepresentation();
+        attrMapper1.setName("manager-role-mapper");
+        attrMapper1.setIdentityProviderMapper(ExternalKeycloakRoleToRoleMapper.PROVIDER_ID);
+        attrMapper1.setConfig(ImmutableMap.<String,String>builder()
+                .put("external.role", "manager")
+                .put("role", "manager")
+                .build());
+
+        IdentityProviderMapperRepresentation attrMapper2 = new IdentityProviderMapperRepresentation();
+        attrMapper2.setName("user-role-mapper");
+        attrMapper2.setIdentityProviderMapper(ExternalKeycloakRoleToRoleMapper.PROVIDER_ID);
+        attrMapper2.setConfig(ImmutableMap.<String,String>builder()
+                .put("external.role", "user")
+                .put("role", "user")
+                .build());
+
+        return Lists.newArrayList(attrMapper1, attrMapper2);
+    }
+
+    @Override
+    protected void loginUser() {
+        driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
+
+        driver.navigate().to(driver.getCurrentUrl() + "&" + OIDCLoginProtocol.PROMPT_PARAM + "=" + PROMPT_CONSENT);
+
+        log.debug("Clicking social " + bc.getIDPAlias());
+        accountLoginPage.clickSocial(bc.getIDPAlias());
+
+        waitForPage(driver, "log in to");
+
+        Assert.assertTrue("Driver should be on the provider realm page right now",
+                driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/"));
+
+        Assert.assertFalse(OIDCLoginProtocol.PROMPT_PARAM + "=" + PROMPT_LOGIN + " should not be part of the url",
+                driver.getCurrentUrl().contains(OIDCLoginProtocol.PROMPT_PARAM + "=" + PROMPT_LOGIN));
+
+        Assert.assertTrue(OIDCLoginProtocol.PROMPT_PARAM + "=" + PROMPT_CONSENT + " should be part of the url",
+                driver.getCurrentUrl().contains(OIDCLoginProtocol.PROMPT_PARAM + "=" + PROMPT_CONSENT));
+
+        log.debug("Logging in");
+        accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword());
+
+        waitForPage(driver, "update account information");
+
+        updateAccountInformationPage.assertCurrent();
+        Assert.assertTrue("We must be on correct realm right now",
+                driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/"));
+
+
+        log.debug("Updating info on updateAccount page");
+        updateAccountInformationPage.updateAccountInformation(bc.getUserLogin(), bc.getUserEmail(), "Firstname", "Lastname");
+
+        UsersResource consumerUsers = adminClient.realm(bc.consumerRealmName()).users();
+
+        int userCount = consumerUsers.count();
+        Assert.assertTrue("There must be at least one user", userCount > 0);
+
+        List<UserRepresentation> users = consumerUsers.search("", 0, userCount);
+
+        boolean isUserFound = false;
+        for (UserRepresentation user : users) {
+            if (user.getUsername().equals(bc.getUserLogin()) && user.getEmail().equals(bc.getUserEmail())) {
+                isUserFound = true;
+                break;
+            }
+        }
+
+        Assert.assertTrue("There must be user " + bc.getUserLogin() + " in realm " + bc.consumerRealmName(),
+                isUserFound);
+    }
+
+    private class KcOidcBrokerConfiguration2 extends KcOidcBrokerConfiguration {
+        protected void applyDefaultConfiguration(final SuiteContext suiteContext, final Map<String, String> config) {
+            super.applyDefaultConfiguration(suiteContext, config);
+            config.remove("prompt");
+        }
+    }
+}
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
index 91074e3..1dd5f72 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
@@ -558,7 +558,7 @@ public class SamlAdapterTestStrategy  extends ExternalResource {
         Retry.execute(new Runnable() {
             @Override
             public void run() {
-                assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-enc/");
+                assertEquals(APP_SERVER_BASE_URL + "/sales-post-enc/", driver.getCurrentUrl());
             }
         }, 10, 100);
         Assert.assertTrue(driver.getPageSource().contains("bburke"));