keycloak-aplcache

Details

diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java
index bc1bd51..a4b3771 100755
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/FreeMarkerAccountProvider.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
 package org.keycloak.account.freemarker;
 
 import java.io.IOException;
@@ -199,9 +215,8 @@ public class FreeMarkerAccountProvider implements AccountProvider {
             BrowserSecurityHeaderSetup.headers(builder, realm);
 
             String keycloakLocaleCookiePath = Urls.localeCookiePath(baseUri, realm.getName());
-            String ngTranslateCookiePath = Urls.ngTranslateLocaleCookiePath(baseUri, realm.getName());
 
-            LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, keycloakLocaleCookiePath, ngTranslateCookiePath);
+            LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, keycloakLocaleCookiePath);
             return builder.build();
         } catch (FreeMarkerException e) {
             logger.error("Failed to process template", e);
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/LocaleHelper.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/LocaleHelper.java
index 4ca78f8..14f7f6c 100644
--- a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/LocaleHelper.java
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/LocaleHelper.java
@@ -1,6 +1,21 @@
+/*
+ * Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
 package org.keycloak.freemarker;
 
-import org.jboss.logging.Logger;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 
@@ -15,7 +30,6 @@ import java.util.*;
  */
 public class LocaleHelper {
     public final static String LOCALE_COOKIE = "KEYCLOAK_LOCALE";
-    public final static String NG_LOCALE_COOKIE = "NG_TRANSLATE_LANG_KEY";
     public static final String UI_LOCALES_PARAM = "ui_locales";
     public static final String KC_LOCALE_PARAM = "kc_locale";
 
@@ -94,14 +108,12 @@ public class LocaleHelper {
                                           Locale locale,
                                           RealmModel realm,
                                           UriInfo uriInfo,
-                                          String keycloakLocaleCookiePath,
-                                          String ngTranslateLocaleCookiePath) {
+                                          String path) {
         if (locale == null) {
             return;
         }
         boolean secure = realm.getSslRequired().isRequired(uriInfo.getRequestUri().getHost());
-        builder.cookie(new NewCookie(LocaleHelper.LOCALE_COOKIE, locale.toLanguageTag(), keycloakLocaleCookiePath, null, null, 31536000, secure),
-                       new NewCookie(LocaleHelper.NG_LOCALE_COOKIE, "%22" + locale.toLanguageTag() + "%22", ngTranslateLocaleCookiePath, null, null, 31536000, secure));
+        builder.cookie(new NewCookie(LocaleHelper.LOCALE_COOKIE, locale.toLanguageTag(), path, null, null, 31536000, secure));
     }
 
     public static Locale findLocale(Set<String> supportedLocales, String ... localeStrings) {
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/index.ftl b/forms/common-themes/src/main/resources/theme/base/admin/index.ftl
index 80736b6..1584d0d 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/index.ftl
+++ b/forms/common-themes/src/main/resources/theme/base/admin/index.ftl
@@ -24,7 +24,6 @@
     <script src="${resourceUrl}/lib/angular/angular-cookies.js"></script>
     <script src="${resourceUrl}/lib/angular/angular-sanitize.js"></script>
     <script src="${resourceUrl}/lib/angular/angular-translate.js"></script>
-    <script src="${resourceUrl}/lib/angular/angular-translate-storage-cookie.js"></script>
     <script src="${resourceUrl}/lib/angular/angular-translate-loader-url.js"></script>
     <script src="${resourceUrl}/lib/angular/ui-bootstrap-tpls-0.11.0.js"></script>
 
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
index 00dab91..8fbf3b0 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -52,12 +52,18 @@ module.factory('authInterceptor', function($q, Auth) {
     };
 });
 
-module.config(function($translateProvider) {
+module.config(['$translateProvider', function($translateProvider) {
     $translateProvider.useSanitizeValueStrategy('sanitizeParameters');
-    $translateProvider.preferredLanguage('en');
-    $translateProvider.useCookieStorage();
+    
+    var locale = auth.authz.idTokenParsed.locale;
+    if (locale !== undefined) {
+        $translateProvider.preferredLanguage(locale);
+    } else {
+        $translateProvider.preferredLanguage('en');
+    }
+    
     $translateProvider.useUrlLoader('messages.json');
-});
+}]);
 
 module.config([ '$routeProvider', function($routeProvider) {
     $routeProvider
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
index 4cf44be..9b9c134 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
 package org.keycloak.login.freemarker;
 
 import org.jboss.logging.Logger;
@@ -277,9 +293,8 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
                 builder.header(entry.getKey(), entry.getValue());
             }
 
-            String keycloakLocaleCookiePath = Urls.localeCookiePath(baseUri, realm.getName());
-            String ngTranslateCookiePath = Urls.ngTranslateLocaleCookiePath(baseUri, realm.getName());
-            LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, keycloakLocaleCookiePath, ngTranslateCookiePath);
+            String cookiePath = Urls.localeCookiePath(baseUri, realm.getName());
+            LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, cookiePath);
 
             return builder.build();
         } catch (FreeMarkerException e) {
@@ -379,10 +394,8 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
                 builder.header(entry.getKey(), entry.getValue());
             }
 
-            String keycloakLocaleCookiePath = Urls.localeCookiePath(baseUri, realm.getName());
-            String ngTranslateCookiePath = Urls.ngTranslateLocaleCookiePath(baseUri, realm.getName());
-
-            LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, keycloakLocaleCookiePath, ngTranslateCookiePath);
+            String cookiePath = Urls.localeCookiePath(baseUri, realm.getName());
+            LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, cookiePath);
             return builder.build();
         } catch (FreeMarkerException e) {
             logger.error("Failed to process template", e);
@@ -391,26 +404,32 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
     }
 
 
+    @Override
     public Response createLogin() {
         return createResponse(LoginFormsPages.LOGIN);
     }
 
+    @Override
     public Response createPasswordReset() {
         return createResponse(LoginFormsPages.LOGIN_RESET_PASSWORD);
     }
 
+    @Override
     public Response createLoginTotp() {
         return createResponse(LoginFormsPages.LOGIN_TOTP);
     }
 
+    @Override
     public Response createRegistration() {
         return createResponse(LoginFormsPages.REGISTER);
     }
 
+    @Override
     public Response createInfoPage() {
         return createResponse(LoginFormsPages.INFO);
     }
 
+    @Override
     public Response createErrorPage() {
         if (status == null) {
             status = Response.Status.INTERNAL_SERVER_ERROR;
@@ -418,7 +437,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
         return createResponse(LoginFormsPages.ERROR);
     }
 
-
+    @Override
     public Response createOAuthGrant(ClientSessionModel clientSession) {
         this.clientSession = clientSession;
         return createResponse(LoginFormsPages.OAUTH_GRANT);
@@ -502,11 +521,13 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
         return this;
     }
 
+    @Override
     public FreeMarkerLoginFormsProvider setUser(UserModel user) {
         this.user = user;
         return this;
     }
 
+    @Override
     public FreeMarkerLoginFormsProvider setFormData(MultivaluedMap<String, String> formData) {
         this.formData = formData;
         return this;
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
index 8f62a52..c600322 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
 package org.keycloak.protocol.oidc;
 
 import org.keycloak.constants.KerberosConstants;
@@ -19,6 +35,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import org.keycloak.protocol.oidc.mappers.UserAttributeMapper;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -32,12 +49,14 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
     public static final String GIVEN_NAME = "given name";
     public static final String FAMILY_NAME = "family name";
     public static final String FULL_NAME = "full name";
+    public static final String LOCALE = "locale";
     public static final String USERNAME_CONSENT_TEXT = "${username}";
     public static final String EMAIL_CONSENT_TEXT = "${email}";
     public static final String EMAIL_VERIFIED_CONSENT_TEXT = "${emailVerified}";
     public static final String GIVEN_NAME_CONSENT_TEXT = "${givenName}";
     public static final String FAMILY_NAME_CONSENT_TEXT = "${familyName}";
     public static final String FULL_NAME_CONSENT_TEXT = "${fullName}";
+    public static final String LOCALE_CONSENT_TEXT = "${locale}";
 
 
     @Override
@@ -95,6 +114,12 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
                 false, EMAIL_VERIFIED_CONSENT_TEXT,
                 true, true);
         builtins.add(model);
+        model = UserAttributeMapper.createClaimMapper(LOCALE,
+                "locale",
+                "locale", "String",
+                false, LOCALE_CONSENT_TEXT,
+                true, true, false);
+        builtins.add(model);
 
         ProtocolMapperModel fullName = new ProtocolMapperModel();
         fullName.setName(FULL_NAME);
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 3790d5a..5f1f9bf 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
 package org.keycloak.services.managers;
 
 import org.jboss.logging.Logger;
@@ -49,7 +65,9 @@ import javax.ws.rs.core.UriInfo;
 import java.net.URI;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
+import org.keycloak.freemarker.LocaleHelper;
 
 /**
  * Stateless object that manages authentication
@@ -393,6 +411,9 @@ public class AuthenticationManager {
                 }
             }
         }
+
+        handleLoginLocale(realm, userSession, request, uriInfo);
+
         // refresh the cookies!
         createLoginCookie(realm, userSession.getUser(), userSession, uriInfo, clientConnection);
         if (userSession.getState() != UserSessionModel.State.LOGGED_IN) userSession.setState(UserSessionModel.State.LOGGED_IN);
@@ -406,6 +427,17 @@ public class AuthenticationManager {
 
     }
 
+    // If a locale has been set on the login screen, associate that locale with the user
+    private static void handleLoginLocale(RealmModel realm, UserSessionModel userSession,
+                                          HttpRequest request, UriInfo uriInfo) {
+        Cookie localeCookie = request.getHttpHeaders().getCookies().get(LocaleHelper.LOCALE_COOKIE);
+        if (localeCookie == null) return;
+
+        UserModel user = userSession.getUser();
+        Locale locale = LocaleHelper.getLocale(realm, user, uriInfo, request.getHttpHeaders());
+        user.setSingleAttribute(UserModel.LOCALE, locale.toLanguageTag());
+    }
+
     public static Response nextActionAfterAuthentication(KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession,
                                                   ClientConnection clientConnection,
                                                   HttpRequest request, UriInfo uriInfo, EventBuilder event) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminMessagesLoader.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminMessagesLoader.java
index df0ce27..43dfc3e 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminMessagesLoader.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminMessagesLoader.java
@@ -17,9 +17,6 @@
 
 package org.keycloak.services.resources.admin;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FilenameFilter;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Locale;
@@ -44,7 +41,7 @@ public class AdminMessagesLoader {
         Properties messages = allMessages.get(allMessagesKey);
         if (messages != null) return messages;
 
-        Locale locale = new Locale(strLocale);
+        Locale locale = Locale.forLanguageTag(strLocale);
         messages = theme.getMessages("admin-messages", locale);
         if (messages == null) return new Properties();
 
diff --git a/services/src/main/java/org/keycloak/services/Urls.java b/services/src/main/java/org/keycloak/services/Urls.java
index 33bdd57..cb7292b 100755
--- a/services/src/main/java/org/keycloak/services/Urls.java
+++ b/services/src/main/java/org/keycloak/services/Urls.java
@@ -208,15 +208,6 @@ public class Urls {
         return realmBase(baseUri).path(realmName).build().getRawPath();
     }
 
-    public static String ngTranslateLocaleCookiePath(URI baseUri, String realmName) {
-        // I'm only using using localeCookiePath to get the /auth part of the path.
-        // I can't assume the URL starts with "/auth".  Keycloak could be installed
-        // as root context.  Typically, the angular-translate cookie path needs to be
-        //  /auth/admin/{realmName}/console/
-        String basePath = localeCookiePath(baseUri, realmName);
-        return basePath.substring(0, basePath.indexOf("realms")) + "admin/" + realmName + "/console/";
-    }
-
     public static URI themeRoot(URI baseUri) {
         return themeBase(baseUri).path(Version.RESOURCES_VERSION).build();
     }