keycloak-uncached

KEYCLOAK-8152: Allow passing the current locale to OAuth2

8/26/2018 5:15:38 PM

Details

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 790fd99..ee8de08 100755
--- a/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java
@@ -313,6 +313,10 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
             uriBuilder.queryParam(OIDCLoginProtocol.LOGIN_HINT_PARAM, loginHint);
         }
 
+        if (getConfig().isUiLocales()) {
+            uriBuilder.queryParam(OIDCLoginProtocol.UI_LOCALES_PARAM, session.getContext().resolveLocale(null).toLanguageTag());
+        }
+
         String prompt = getConfig().getPrompt();
         if (prompt == null || prompt.isEmpty()) {
             prompt = request.getAuthenticationSession().getClientNote(OAuth2Constants.PROMPT);
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 6c84340..b3a204b 100644
--- a/services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java
@@ -83,6 +83,14 @@ public class OAuth2IdentityProviderConfig extends IdentityProviderModel {
         getConfig().put("loginHint", String.valueOf(loginHint));
     }
 
+    public boolean isUiLocales() {
+        return Boolean.valueOf(getConfig().get("uiLocales"));
+    }
+
+    public void setUiLocales(boolean uiLocales) {
+        getConfig().put("uiLocales", String.valueOf(uiLocales));
+    }
+
     public String getPrompt() {
         return getConfig().get("prompt");
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerUiLocalesDisabledTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerUiLocalesDisabledTest.java
new file mode 100644
index 0000000..45da7e9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerUiLocalesDisabledTest.java
@@ -0,0 +1,87 @@
+package org.keycloak.testsuite.broker;
+
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+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 java.util.Locale.ENGLISH;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.keycloak.OAuth2Constants.UI_LOCALES_PARAM;
+import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_ALIAS;
+import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_PROVIDER_ID;
+import static org.keycloak.testsuite.broker.BrokerTestTools.createIdentityProvider;
+import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
+
+public class KcOidcBrokerUiLocalesDisabledTest extends KcOidcBrokerTest {
+
+    @Override
+    protected BrokerConfiguration getBrokerConfiguration() {
+        return new KcOidcBrokerConfigurationWithUiLocalesDisabled();
+    }
+
+    private class KcOidcBrokerConfigurationWithUiLocalesDisabled extends KcOidcBrokerConfiguration {
+
+        @Override
+        public IdentityProviderRepresentation setUpIdentityProvider(SuiteContext suiteContext) {
+            IdentityProviderRepresentation idp = createIdentityProvider(IDP_OIDC_ALIAS, IDP_OIDC_PROVIDER_ID);
+            Map<String, String> config = idp.getConfig();
+            applyDefaultConfiguration(suiteContext, config);
+            config.put("uiLocales", "false");
+            return idp;
+        }
+    }
+
+    @Override
+    protected void loginUser() {
+        driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
+
+        driver.navigate().to(driver.getCurrentUrl());
+
+
+        log.debug("Clicking social " + bc.getIDPAlias());
+        accountLoginPage.clickSocial(bc.getIDPAlias());
+
+        waitForPage(driver, "log in to", true);
+
+        Assert.assertThat("Driver should be on the provider realm page right now",
+                driver.getCurrentUrl(), containsString("/auth/realms/" + bc.providerRealmName() + "/"));
+
+        Assert.assertThat(UI_LOCALES_PARAM + "=" + ENGLISH.toLanguageTag() + " should be part of the url",
+                driver.getCurrentUrl(), not(containsString(UI_LOCALES_PARAM + "=" + ENGLISH.toLanguageTag())));
+
+        accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword());
+        waitForPage(driver, "update account information", false);
+
+        updateAccountInformationPage.assertCurrent();
+
+        Assert.assertThat("We must be on correct realm right now",
+                driver.getCurrentUrl(), containsString("/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/KcOidcBrokerUiLocalesEnabledTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerUiLocalesEnabledTest.java
new file mode 100644
index 0000000..0bf4116
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerUiLocalesEnabledTest.java
@@ -0,0 +1,87 @@
+package org.keycloak.testsuite.broker;
+
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+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 java.util.Locale.ENGLISH;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.keycloak.OAuth2Constants.UI_LOCALES_PARAM;
+import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_ALIAS;
+import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_PROVIDER_ID;
+import static org.keycloak.testsuite.broker.BrokerTestTools.createIdentityProvider;
+import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
+
+public class KcOidcBrokerUiLocalesEnabledTest extends KcOidcBrokerTest {
+
+    @Override
+    protected BrokerConfiguration getBrokerConfiguration() {
+        return new KcOidcBrokerConfigurationWithUiLocalesEnabled();
+    }
+
+    private class KcOidcBrokerConfigurationWithUiLocalesEnabled extends KcOidcBrokerConfiguration {
+
+        @Override
+        public IdentityProviderRepresentation setUpIdentityProvider(SuiteContext suiteContext) {
+            IdentityProviderRepresentation idp = createIdentityProvider(IDP_OIDC_ALIAS, IDP_OIDC_PROVIDER_ID);
+            Map<String, String> config = idp.getConfig();
+            applyDefaultConfiguration(suiteContext, config);
+            config.put("uiLocales", "true");
+            return idp;
+        }
+    }
+
+    @Override
+    protected void loginUser() {
+        driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
+
+        driver.navigate().to(driver.getCurrentUrl());
+
+
+        log.debug("Clicking social " + bc.getIDPAlias());
+        accountLoginPage.clickSocial(bc.getIDPAlias());
+
+        waitForPage(driver, "log in to", true);
+
+        Assert.assertThat("Driver should be on the provider realm page right now",
+                driver.getCurrentUrl(), containsString("/auth/realms/" + bc.providerRealmName() + "/"));
+
+        Assert.assertThat(UI_LOCALES_PARAM + "=" + ENGLISH.toLanguageTag() + " should be part of the url",
+                driver.getCurrentUrl(), containsString(UI_LOCALES_PARAM + "=" + ENGLISH.toLanguageTag()));
+
+        accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword());
+        waitForPage(driver, "update account information", false);
+
+        updateAccountInformationPage.assertCurrent();
+
+        Assert.assertThat("We must be on correct realm right now",
+                driver.getCurrentUrl(), containsString("/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/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index d9fb412..ea78b5e 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -544,6 +544,8 @@ token-url=Token URL
 token-url.tooltip=The Token URL.
 loginHint=Pass login_hint
 loginHint.tooltip=Pass login_hint to identity provider.
+uiLocales=Pass current locale
+uiLocales.tooltip=Pass the current locale to the identity provider as an ui_locales parameter.
 logout-url=Logout URL
 identity-provider.logout-url.tooltip=End session endpoint to use to logout user from external IDP.
 backchannel-logout=Backchannel Logout
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
index 825ed15..9a351ee 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
@@ -124,6 +124,13 @@
                 </div>
                 <kc-tooltip>{{:: 'loginHint.tooltip' | translate}}</kc-tooltip>
             </div>
+            <div class="form-group">
+                <label class="col-sm-2 control-label" for="uiLocales">{{:: 'uiLocales' | translate}}</label>
+                <div class="col-sm-4">
+                    <input ng-model="identityProvider.config.uiLocales" id="uiLocales" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
+                </div>
+                <kc-tooltip>{{:: 'uiLocales.tooltip' | translate}}</kc-tooltip>
+            </div>
             <div class="form-group clearfix">
                 <label class="col-md-2 control-label" for="tokenUrl"><span class="required">*</span> {{:: 'token-url' | translate}}</label>
                 <div class="col-md-6">