Merge pull request #1618 from ssilvert/i18n
KEYCLOAK-1152: i18n using angular-translate
This commit is contained in:
commit
4bd1d899db
31 changed files with 3742 additions and 202 deletions
|
@ -181,6 +181,12 @@ import=common/keycloak
|
|||
<literal>messages/messages.properties</literal> inside your theme folder and add the following content:
|
||||
</para>
|
||||
<programlisting>username=Your Username</programlisting>
|
||||
<para>
|
||||
For the admin console, there is a second resource bundle named <literal>admin-messages.properties</literal>.
|
||||
This resource bundle is converted to JSON and shipped to the console to be processed by
|
||||
angular-translate. It is found in the same directory as messages.properties and can be overridden
|
||||
in the same way as described above.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Modifying HTML</title>
|
||||
|
|
|
@ -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;
|
||||
|
@ -197,7 +213,10 @@ public class FreeMarkerAccountProvider implements AccountProvider {
|
|||
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
||||
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML).entity(result);
|
||||
BrowserSecurityHeaderSetup.headers(builder, realm);
|
||||
LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, Urls.localeCookiePath(baseUri,realm.getName()));
|
||||
|
||||
String keycloakLocaleCookiePath = Urls.localeCookiePath(baseUri, realm.getName());
|
||||
|
||||
LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, keycloakLocaleCookiePath);
|
||||
return builder.build();
|
||||
} catch (FreeMarkerException e) {
|
||||
logger.error("Failed to process template", e);
|
||||
|
|
|
@ -224,10 +224,15 @@ public class ExtendingThemeManager implements ThemeProvider {
|
|||
|
||||
@Override
|
||||
public Properties getMessages(Locale locale) throws IOException {
|
||||
return getMessages("messages", locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getMessages(String baseBundlename, Locale locale) throws IOException {
|
||||
Properties messages = new Properties();
|
||||
ListIterator<Theme> itr = themes.listIterator(themes.size());
|
||||
while (itr.hasPrevious()) {
|
||||
Properties m = itr.previous().getMessages(locale);
|
||||
Properties m = itr.previous().getMessages(baseBundlename, locale);
|
||||
if (m != null) {
|
||||
messages.putAll(m);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -89,7 +104,11 @@ public class LocaleHelper {
|
|||
return Locale.ENGLISH;
|
||||
}
|
||||
|
||||
public static void updateLocaleCookie(Response.ResponseBuilder builder, Locale locale, RealmModel realm, UriInfo uriInfo, String path) {
|
||||
public static void updateLocaleCookie(Response.ResponseBuilder builder,
|
||||
Locale locale,
|
||||
RealmModel realm,
|
||||
UriInfo uriInfo,
|
||||
String path) {
|
||||
if (locale == null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,27 @@ public interface Theme {
|
|||
|
||||
public InputStream getResourceAsStream(String path) throws IOException;
|
||||
|
||||
/**
|
||||
* Same as getMessages(baseBundlename, locale), but uses a default baseBundlename
|
||||
* such as "messages".
|
||||
*
|
||||
* @param locale The locale of the desired message bundle.
|
||||
* @return The localized messages from the bundle.
|
||||
* @throws IOException If bundle can not be read.
|
||||
*/
|
||||
public Properties getMessages(Locale locale) throws IOException;
|
||||
|
||||
/**
|
||||
* Retrieve localized messages from a message bundle.
|
||||
*
|
||||
* @param baseBundlename The base name of the bundle, such as "messages" in
|
||||
* messages_en.properties.
|
||||
* @param locale The locale of the desired message bundle.
|
||||
* @return The localized messages from the bundle.
|
||||
* @throws IOException If bundle can not be read.
|
||||
*/
|
||||
public Properties getMessages(String baseBundlename, Locale locale) throws IOException;
|
||||
|
||||
public Properties getProperties() throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -100,12 +100,17 @@ public class ClassLoaderTheme implements Theme {
|
|||
|
||||
@Override
|
||||
public Properties getMessages(Locale locale) throws IOException {
|
||||
return getMessages("messages", locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getMessages(String baseBundlename, Locale locale) throws IOException {
|
||||
if(locale == null){
|
||||
return null;
|
||||
}
|
||||
Properties m = new Properties();
|
||||
|
||||
URL url = classLoader.getResource(this.messageRoot + "messages_" + locale.toString() + ".properties");
|
||||
URL url = classLoader.getResource(this.messageRoot + baseBundlename + "_" + locale.toString() + ".properties");
|
||||
if (url != null) {
|
||||
m.load(url.openStream());
|
||||
}
|
||||
|
|
|
@ -93,13 +93,18 @@ public class FolderTheme implements Theme {
|
|||
|
||||
@Override
|
||||
public Properties getMessages(Locale locale) throws IOException {
|
||||
return getMessages("messages", locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getMessages(String baseBundlename, Locale locale) throws IOException {
|
||||
if(locale == null){
|
||||
return null;
|
||||
}
|
||||
|
||||
Properties m = new Properties();
|
||||
|
||||
File file = new File(themeDir, "messages" + File.separator + "messages_" + locale.toString() + ".properties");
|
||||
File file = new File(themeDir, "messages" + File.separator + baseBundlename + "_" + locale.toString() + ".properties");
|
||||
if (file.isFile()) {
|
||||
m.load(new FileInputStream(file));
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
<script src="${resourceUrl}/lib/angular/angular.js"></script>
|
||||
<script src="${resourceUrl}/lib/angular/angular-resource.js"></script>
|
||||
<script src="${resourceUrl}/lib/angular/angular-route.js"></script>
|
||||
<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-loader-url.js"></script>
|
||||
<script src="${resourceUrl}/lib/angular/ui-bootstrap-tpls-0.11.0.js"></script>
|
||||
|
||||
<script src="${resourceUrl}/lib/angular/select2.js" type="text/javascript"></script>
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
# Common messages
|
||||
enabled=de Enabled
|
||||
name=de Name
|
||||
save=de Save
|
||||
cancel=de Cancel
|
||||
onText=AN
|
||||
offText=AUS
|
||||
client=de Client
|
||||
clear=de Clear
|
||||
|
||||
# Realm settings
|
||||
realm-detail.enabled.tooltip=de Users and clients can only access a realm if it's enabled
|
||||
registrationAllowed=de User registration
|
||||
registrationAllowed.tooltip=de Enable/disable the registration page. A link for registration will show on login page too.
|
||||
registrationEmailAsUsername=de Email as username
|
||||
registrationEmailAsUsername.tooltip=de If enabled then username field is hidden from registration form and email is used as username for new user.
|
||||
editUsernameAllowed=de Edit username
|
||||
editUsernameAllowed.tooltip=de If enabled, the username field is editable, readonly otherwise.
|
||||
resetPasswordAllowed=de Forget password
|
||||
resetPasswordAllowed.tooltip=de Show a link on login page for user to click on when they have forgotten their credentials.
|
||||
rememberMe=de Remember Me
|
||||
rememberMe.tooltip=de Show checkbox on login page to allow user to remain logged in between browser restarts until session expires.
|
||||
verifyEmail=de Verify email
|
||||
verifyEmail.tooltip=de Require the user to verify their email address the first time they login.
|
||||
sslRequired=de Require SSL
|
||||
sslRequired.option.all=de all requests
|
||||
sslRequired.option.external=de external requests
|
||||
sslRequired.option.none=de none
|
||||
sslRequired.tooltip=de Is HTTPS required? 'None' means HTTPS is not required for any client IP address. 'External requests' means localhost and private IP addresses can access without HTTPS. 'All requests' means HTTPS is required for all IP addresses.
|
||||
publicKey=de Public key
|
||||
gen-new-keys=de Generate new keys
|
||||
certificate=de Certificate
|
||||
host=de Host
|
||||
smtp-host=de SMTP Host
|
||||
port=de Port
|
||||
smtp-port=de SMTP Port (defaults to 25)
|
||||
from=de From
|
||||
sender-email-addr=de Sender Email Address
|
||||
enable-ssl=de Enable SSL
|
||||
enable-start-tls=de Enable StartTLS
|
||||
enable-auth=de Enable Authentication
|
||||
username=de Username
|
||||
login-username=de Login Username
|
||||
password=de Password
|
||||
login-password=de Login Password
|
||||
login-theme=de Login Theme
|
||||
select-one=de Select one...
|
||||
login-theme.tooltip=de Select theme for login, TOTP, grant, registration, and forgot password pages.
|
||||
account-theme=de Account Theme
|
||||
account-theme.tooltip=de Select theme for user account management pages.
|
||||
admin-console-theme=de Admin Console Theme
|
||||
select-theme-admin-console=de Select theme for admin console.
|
||||
email-theme=de Email Theme
|
||||
select-theme-email=de Select theme for emails that are sent by the server.
|
||||
i18n-enabled=de Internationalization Enabled
|
||||
supported-locales=de Supported Locales
|
||||
supported-locales.placeholder=de Type a locale and enter
|
||||
default-locale=de Default Locale
|
||||
realm-cache-enabled=de Realm Cache Enabled
|
||||
realm-cache-enabled.tooltip=de Enable/disable cache for realm, client and role data.
|
||||
user-cache-enabled=de User Cache Enabled
|
||||
user-cache-enabled.tooltip=de Enable/disable user and user role mapping cache.
|
||||
sso-session-idle=de SSO Session Idle
|
||||
seconds=de Seconds
|
||||
minutes=de Minutes
|
||||
hours=de Hours
|
||||
days=de Days
|
||||
sso-session-max=de SSO Session Max
|
||||
sso-session-idle.tooltip=de Time a session is allowed to be idle before it expires. Tokens and browser sessions are invalidated when a session is expired.
|
||||
sso-session-max.tooltip=de Max time before a session is expired. Tokens and browser sessions are invalidated when a session is expired.
|
||||
access-token-lifespan=de Access Token Lifespan
|
||||
access-token-lifespan.tooltip=de Max time before an access token is expired. This value is recommended to be short relative to the SSO timeout.
|
||||
client-login-timeout=de Client login timeout
|
||||
client-login-timeout.tooltip=de Max time an client has to finish the access token protocol. This should normally be 1 minute.
|
||||
login-timeout=de Login timeout
|
||||
login-timeout.tooltip=de Max time a user has to complete a login. This is recommended to be relatively long. 30 minutes or more.
|
||||
login-action-timeout=de Login action timeout
|
||||
login-action-timeout.tooltip=de Max time a user has to complete login related actions like update password or configure totp. This is recommended to be relatively long. 5 minutes or more.
|
||||
headers=de Headers
|
||||
brute-force-detection=de Brute Force Detection
|
||||
x-frame-options=de X-Frame-Options
|
||||
click-label-for-info=de Click on label link for more information. The default value prevents pages from being included via non-origin iframes.
|
||||
content-sec-policy=de Content-Security-Policy
|
||||
max-login-failures=de Max Login Failures
|
||||
max-login-failures.tooltip=de How many failures before wait is triggered.
|
||||
wait-increment=de Wait Increment
|
||||
wait-increment.tooltip=de When failure threshold has been met, how much time should the user be locked out?
|
||||
quick-login-check-millis=de Quick Login Check Milli Seconds
|
||||
quick-login-check-millis.tooltip=de If a failure happens concurrently too quickly, lock out the user.
|
||||
min-quick-login-wait=de Minimum Quick Login Wait
|
||||
min-quick-login-wait.tooltip=de How long to wait after a quick login failure.
|
||||
max-wait=de Max Wait
|
||||
max-wait.tooltip=de Max time a user will be locked out.
|
||||
failure-reset-time=de Failure Reset Time
|
||||
failure-reset-time.tooltip=de When will failure count be reset?
|
||||
realm-tab-login=de Login
|
||||
realm-tab-keys=de Keys
|
||||
realm-tab-email=de Email
|
||||
realm-tab-themes=de Themes
|
||||
realm-tab-cache=de Cache
|
||||
realm-tab-tokens=de Tokens
|
||||
realm-tab-security-defenses=de Security Defenses
|
||||
realm-tab-general=de General
|
||||
add-realm=de Add Realm
|
||||
|
||||
#Session settings
|
||||
realm-sessions=de Realm Sessions
|
||||
revocation=de Revocation
|
||||
logout-all=de Logout All
|
||||
active-sessions=de Active Sessions
|
||||
sessions=de Sessions
|
||||
not-before=de Not Before
|
||||
not-before.tooltip=de Revoke any tokens issued before this date.
|
||||
set-to-now=de Set To Now
|
||||
push=de Push
|
||||
push.tooltip=de For every client that has an admin URL, notify them of the new revocation policy.
|
|
@ -0,0 +1,116 @@
|
|||
# Common messages
|
||||
enabled=Enabled
|
||||
name=Name
|
||||
save=Save
|
||||
cancel=Cancel
|
||||
onText=ON
|
||||
offText=OFF
|
||||
client=Client
|
||||
clear=Clear
|
||||
|
||||
# Realm settings
|
||||
realm-detail.enabled.tooltip=Users and clients can only access a realm if it's enabled
|
||||
registrationAllowed=User registration
|
||||
registrationAllowed.tooltip=Enable/disable the registration page. A link for registration will show on login page too.
|
||||
registrationEmailAsUsername=Email as username
|
||||
registrationEmailAsUsername.tooltip=If enabled then username field is hidden from registration form and email is used as username for new user.
|
||||
editUsernameAllowed=Edit username
|
||||
editUsernameAllowed.tooltip=If enabled, the username field is editable, readonly otherwise.
|
||||
resetPasswordAllowed=Forget password
|
||||
resetPasswordAllowed.tooltip=Show a link on login page for user to click on when they have forgotten their credentials.
|
||||
rememberMe=Remember Me
|
||||
rememberMe.tooltip=Show checkbox on login page to allow user to remain logged in between browser restarts until session expires.
|
||||
verifyEmail=Verify email
|
||||
verifyEmail.tooltip=Require the user to verify their email address the first time they login.
|
||||
sslRequired=Require SSL
|
||||
sslRequired.option.all=all requests
|
||||
sslRequired.option.external=external requests
|
||||
sslRequired.option.none=none
|
||||
sslRequired.tooltip=Is HTTPS required? 'None' means HTTPS is not required for any client IP address. 'External requests' means localhost and private IP addresses can access without HTTPS. 'All requests' means HTTPS is required for all IP addresses.
|
||||
publicKey=Public key
|
||||
gen-new-keys=Generate new keys
|
||||
certificate=Certificate
|
||||
host=Host
|
||||
smtp-host=SMTP Host
|
||||
port=Port
|
||||
smtp-port=SMTP Port (defaults to 25)
|
||||
from=From
|
||||
sender-email-addr=Sender Email Address
|
||||
enable-ssl=Enable SSL
|
||||
enable-start-tls=Enable StartTLS
|
||||
enable-auth=Enable Authentication
|
||||
username=Username
|
||||
login-username=Login Username
|
||||
password=Password
|
||||
login-password=Login Password
|
||||
login-theme=Login Theme
|
||||
select-one=Select one...
|
||||
login-theme.tooltip=Select theme for login, TOTP, grant, registration, and forgot password pages.
|
||||
account-theme=Account Theme
|
||||
account-theme.tooltip=Select theme for user account management pages.
|
||||
admin-console-theme=Admin Console Theme
|
||||
select-theme-admin-console=Select theme for admin console.
|
||||
email-theme=Email Theme
|
||||
select-theme-email=Select theme for emails that are sent by the server.
|
||||
i18n-enabled=Internationalization Enabled
|
||||
supported-locales=Supported Locales
|
||||
supported-locales.placeholder=Type a locale and enter
|
||||
default-locale=Default Locale
|
||||
realm-cache-enabled=Realm Cache Enabled
|
||||
realm-cache-enabled.tooltip=Enable/disable cache for realm, client and role data.
|
||||
user-cache-enabled=User Cache Enabled
|
||||
user-cache-enabled.tooltip=Enable/disable user and user role mapping cache.
|
||||
sso-session-idle=SSO Session Idle
|
||||
seconds=Seconds
|
||||
minutes=Minutes
|
||||
hours=Hours
|
||||
days=Days
|
||||
sso-session-max=SSO Session Max
|
||||
sso-session-idle.tooltip=Time a session is allowed to be idle before it expires. Tokens and browser sessions are invalidated when a session is expired.
|
||||
sso-session-max.tooltip=Max time before a session is expired. Tokens and browser sessions are invalidated when a session is expired.
|
||||
access-token-lifespan=Access Token Lifespan
|
||||
access-token-lifespan.tooltip=Max time before an access token is expired. This value is recommended to be short relative to the SSO timeout.
|
||||
client-login-timeout=Client login timeout
|
||||
client-login-timeout.tooltip=Max time an client has to finish the access token protocol. This should normally be 1 minute.
|
||||
login-timeout=Login timeout
|
||||
login-timeout.tooltip=Max time a user has to complete a login. This is recommended to be relatively long. 30 minutes or more.
|
||||
login-action-timeout=Login action timeout
|
||||
login-action-timeout.tooltip=Max time a user has to complete login related actions like update password or configure totp. This is recommended to be relatively long. 5 minutes or more.
|
||||
headers=Headers
|
||||
brute-force-detection=Brute Force Detection
|
||||
x-frame-options=X-Frame-Options
|
||||
click-label-for-info=Click on label link for more information. The default value prevents pages from being included via non-origin iframes.
|
||||
content-sec-policy=Content-Security-Policy
|
||||
max-login-failures=Max Login Failures
|
||||
max-login-failures.tooltip=How many failures before wait is triggered.
|
||||
wait-increment=Wait Increment
|
||||
wait-increment.tooltip=When failure threshold has been met, how much time should the user be locked out?
|
||||
quick-login-check-millis=Quick Login Check Milli Seconds
|
||||
quick-login-check-millis.tooltip=If a failure happens concurrently too quickly, lock out the user.
|
||||
min-quick-login-wait=Minimum Quick Login Wait
|
||||
min-quick-login-wait.tooltip=How long to wait after a quick login failure.
|
||||
max-wait=Max Wait
|
||||
max-wait.tooltip=Max time a user will be locked out.
|
||||
failure-reset-time=Failure Reset Time
|
||||
failure-reset-time.tooltip=When will failure count be reset?
|
||||
realm-tab-login=Login
|
||||
realm-tab-keys=Keys
|
||||
realm-tab-email=Email
|
||||
realm-tab-themes=Themes
|
||||
realm-tab-cache=Cache
|
||||
realm-tab-tokens=Tokens
|
||||
realm-tab-security-defenses=Security Defenses
|
||||
realm-tab-general=General
|
||||
add-realm=Add Realm
|
||||
|
||||
#Session settings
|
||||
realm-sessions=Realm Sessions
|
||||
revocation=Revocation
|
||||
logout-all=Logout All
|
||||
active-sessions=Active Sessions
|
||||
sessions=Sessions
|
||||
not-before=Not Before
|
||||
not-before.tooltip=Revoke any tokens issued before this date.
|
||||
set-to-now=Set To Now
|
||||
push=Push
|
||||
push.tooltip=For every client that has an admin URL, notify them of the new revocation policy.
|
|
@ -7,7 +7,7 @@ var configUrl = consoleBaseUrl + "/config";
|
|||
|
||||
var auth = {};
|
||||
|
||||
var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload' ]);
|
||||
var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload', 'pascalprecht.translate', 'ngCookies', 'ngSanitize']);
|
||||
var resourceRequests = 0;
|
||||
var loadingTimer = -1;
|
||||
|
||||
|
@ -52,8 +52,18 @@ module.factory('authInterceptor', function($q, Auth) {
|
|||
};
|
||||
});
|
||||
|
||||
module.config(['$translateProvider', function($translateProvider) {
|
||||
$translateProvider.useSanitizeValueStrategy('sanitizeParameters');
|
||||
|
||||
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
|
||||
|
|
|
@ -2,102 +2,102 @@
|
|||
<kc-tabs-realm></kc-tabs-realm>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li><a href="#/realms/{{realm.realm}}/defense/headers">Headers</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/defense/brute-force">Brute Force Detection</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/defense/headers">{{:: 'headers' | translate}}</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/defense/brute-force">{{:: 'brute-force-detection' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="bruteForceProtected">Enabled</label>
|
||||
<label class="col-md-2 control-label" for="bruteForceProtected">{{:: 'enabled' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.bruteForceProtected" name="bruteForceProtected" id="bruteForceProtected" onoffswitch />
|
||||
<input ng-model="realm.bruteForceProtected" name="bruteForceProtected" id="bruteForceProtected" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.bruteForceProtected">
|
||||
<label class="col-md-2 control-label" for="failureFactor">Max Login Failures</label>
|
||||
<label class="col-md-2 control-label" for="failureFactor">{{:: 'max-login-failures' | translate}}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" type="number" min="1" max="31536000" id="failureFactor" name="failureFactor" data-ng-model="realm.failureFactor" autofocus
|
||||
required>
|
||||
</div>
|
||||
<kc-tooltip>How many failures before wait is triggered.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'max-login-failures.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.bruteForceProtected">
|
||||
<label class="col-md-2 control-label" for="waitIncrement">Wait Increment</label>
|
||||
<label class="col-md-2 control-label" for="waitIncrement">{{:: 'wait-increment' | translate}}</label>
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.waitIncrement"
|
||||
id="waitIncrement" name="waitIncrement"/>
|
||||
<select class="form-control" name="waitIncrementUnit" data-ng-model="realm.waitIncrementUnit" >
|
||||
<option data-ng-selected="!realm.waitIncrementUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.waitIncrementUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>When failure threshold has been met, how much time should the user be locked out?</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'wait-increment.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.bruteForceProtected">
|
||||
<label class="col-md-2 control-label" for="quickLoginCheckMilliSeconds">Quick Login Check Milli Seconds</label>
|
||||
<label class="col-md-2 control-label" for="quickLoginCheckMilliSeconds">{{:: 'quick-login-check-millis' | translate}}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" type="number" min="1" max="31536000" id="quickLoginCheckMilliSeconds" name="quickLoginCheckMilliSeconds" data-ng-model="realm.quickLoginCheckMilliSeconds" autofocus
|
||||
required>
|
||||
</div>
|
||||
<kc-tooltip>If a failure happens concurrently too quickly, lock out the user.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'quick-login-check-millis.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.bruteForceProtected">
|
||||
<label class="col-md-2 control-label" for="minimumQuickLoginWait">Minimum Quick Login Wait</label>
|
||||
<label class="col-md-2 control-label" for="minimumQuickLoginWait">{{:: 'min-quick-login-wait' | translate}}</label>
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.minimumQuickLoginWait"
|
||||
id="minimumQuickLoginWait" name="minimumQuickLoginWait"/>
|
||||
<select class="form-control" name="minimumQuickLoginWaitUnit" data-ng-model="realm.minimumQuickLoginWaitUnit" >
|
||||
<option data-ng-selected="!realm.minimumQuickLoginWaitUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.minimumQuickLoginWaitUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>How long to wait after a quick login failure.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'min-quick-login-wait.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.bruteForceProtected">
|
||||
<label class="col-md-2 control-label" for="maxFailureWait">Max Wait</label>
|
||||
<label class="col-md-2 control-label" for="maxFailureWait">{{:: 'max-wait' | translate}}</label>
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.maxFailureWait"
|
||||
id="maxFailureWait" name="maxFailureWait"/>
|
||||
<select class="form-control" name="maxFailureWaitUnit" data-ng-model="realm.maxFailureWaitUnit" >
|
||||
<option data-ng-selected="!realm.maxFailureWaitUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.maxFailureWaitUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>Max time a user will be locked out.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'max-wait.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.bruteForceProtected">
|
||||
<label class="col-md-2 control-label" for="maxDeltaTime">Failure Reset Time</label>
|
||||
<label class="col-md-2 control-label" for="maxDeltaTime">{{:: 'failure-reset-time' | translate}}</label>
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.maxDeltaTime"
|
||||
id="maxDeltaTime" name="maxDeltaTime"/>
|
||||
<select class="form-control" name="maxDeltaTimeUnit" data-ng-model="realm.maxDeltaTimeUnit" >
|
||||
<option data-ng-selected="!realm.maxDeltaTimeUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.maxDeltaTimeUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>When will failure count be reset?</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'failure-reset-time.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="form-group" data-ng-show="access.manageRealm">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button kc-save data-ng-disabled="!changed">Save</button>
|
||||
<button kc-reset data-ng-disabled="!changed">Cancel</button>
|
||||
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -2,31 +2,31 @@
|
|||
<kc-tabs-realm></kc-tabs-realm>
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/defense/headers">Headers</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/defense/brute-force">Brute Force Detection</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/defense/headers">{{:: 'headers' | translate}}</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/defense/brute-force">{{:: 'brute-force-detection' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="xFrameOptions"><a href="http://tools.ietf.org/html/rfc7034">X-Frame-Options</a></label>
|
||||
<label class="col-md-2 control-label" for="xFrameOptions"><a href="http://tools.ietf.org/html/rfc7034">{{:: 'x-frame-options' | translate}}</a></label>
|
||||
<div class="col-sm-6">
|
||||
<input class="form-control" id="xFrameOptions" type="text" ng-model="realm.browserSecurityHeaders.xFrameOptions">
|
||||
</div>
|
||||
<kc-tooltip>Click on label link for more information. The default value prevents pages from being included via non-origin iframes.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'click-label-for-info' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="contentSecurityPolicy"><a href="http://www.w3.org/TR/CSP/">Content-Security-Policy</a></label>
|
||||
<label class="col-md-2 control-label" for="contentSecurityPolicy"><a href="http://www.w3.org/TR/CSP/">{{:: 'content-sec-policy' | translate}}</a></label>
|
||||
<div class="col-sm-6">
|
||||
<input class="form-control" id="contentSecurityPolicy" type="text" ng-model="realm.browserSecurityHeaders.contentSecurityPolicy">
|
||||
</div>
|
||||
<kc-tooltip>Click on label link for more information. The default value prevents pages from being included via non-origin iframes.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'click-label-for-info' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="form-group" data-ng-show="access.manageRealm">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button kc-save data-ng-disabled="!changed">Save</button>
|
||||
<button kc-reset data-ng-disabled="!changed">Cancel</button>
|
||||
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -3,24 +3,24 @@
|
|||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="realmCacheEnabled">Realm Cache Enabled</label>
|
||||
<label class="col-md-2 control-label" for="realmCacheEnabled">{{:: 'realm-cache-enabled' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.realmCacheEnabled" name="realmCacheEnabled" id="realmCacheEnabled" onoffswitch />
|
||||
<input ng-model="realm.realmCacheEnabled" name="realmCacheEnabled" id="realmCacheEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||
</div>
|
||||
<kc-tooltip>Enable/disable cache for realm, client and role data.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'realm-cache-enabled.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="userCacheEnabled">User Cache Enabled</label>
|
||||
<label class="col-md-2 control-label" for="userCacheEnabled">{{:: 'user-cache-enabled' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.userCacheEnabled" name="userCacheEnabled" id="userCacheEnabled" onoffswitch />
|
||||
<input ng-model="realm.userCacheEnabled" name="userCacheEnabled" id="userCacheEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||
</div>
|
||||
<kc-tooltip>Enable/disable user and user role mapping cache.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'user-cache-enabled.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group" data-ng-show="access.manageRealm">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button kc-save data-ng-disabled="!changed">Save</button>
|
||||
<button kc-reset data-ng-disabled="!changed">Cancel</button>
|
||||
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -3,29 +3,29 @@
|
|||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="name"><span class="required">*</span> Name</label>
|
||||
<label class="col-md-2 control-label" for="name"><span class="required">*</span> {{:: 'name' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" type="text" id="name" name="name" data-ng-model="realm.realm" autofocus required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="enabled">Enabled</label>
|
||||
<label class="col-md-2 control-label" for="enabled">{{:: 'enabled' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.enabled" name="enabled" id="enabled" onoffswitch />
|
||||
<input ng-model="realm.enabled" name="enabled" id="enabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>Users and clients can only access a realm if it's enabled</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'realm-detail.enabled.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-10 col-md-offset-2" data-ng-show="createRealm && access.manageRealm">
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">{{:: 'save' | translate}}</button>
|
||||
<button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
|
||||
<div class="col-md-10 col-md-offset-2" data-ng-show="!createRealm && access.manageRealm">
|
||||
<button kc-save data-ng-disabled="!changed">Save</button>
|
||||
<button kc-reset data-ng-disabled="!changed">Cancel</button>
|
||||
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="publicKey">Public key</label>
|
||||
<label class="col-md-2 control-label" for="publicKey">{{:: 'publicKey' | translate}}</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<textarea type="text" id="publicKey" name="publicKey" class="form-control" rows="4"
|
||||
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="certificate">Certificate</label>
|
||||
<label class="col-md-2 control-label" for="certificate">{{:: 'certificate' | translate}}</label>
|
||||
|
||||
<div class="col-md-10">
|
||||
<textarea type="text" id="certificate" name="certificate" class="form-control" rows="8" kc-select-action="click" readonly>{{realm.certificate}}</textarea>
|
||||
|
@ -22,7 +22,7 @@
|
|||
|
||||
<div class="form-group" data-ng-show="access.manageRealm">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button class="btn btn-danger" type="submit" data-ng-click="generate()">Generate new keys</button>
|
||||
<button class="btn btn-danger" type="submit" data-ng-click="generate()">{{:: 'gen-new-keys' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -4,66 +4,66 @@
|
|||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label for="registrationAllowed" class="col-md-2 control-label">User registration</label>
|
||||
<label for="registrationAllowed" class="col-md-2 control-label">{{:: 'registrationAllowed' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.registrationAllowed" name="registrationAllowed" id="registrationAllowed" onoffswitch />
|
||||
<input ng-model="realm.registrationAllowed" name="registrationAllowed" id="registrationAllowed" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>Enable/disable the registration page. A link for registration will show on login page too.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'registrationAllowed.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group" ng-show="realm.registrationAllowed">
|
||||
<label for="registrationEmailAsUsername" class="col-md-2 control-label">Email as username</label>
|
||||
<label for="registrationEmailAsUsername" class="col-md-2 control-label">{{:: 'registrationEmailAsUsername' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.registrationEmailAsUsername" name="registrationEmailAsUsername" id="registrationEmailAsUsername" onoffswitch />
|
||||
<input ng-model="realm.registrationEmailAsUsername" name="registrationEmailAsUsername" id="registrationEmailAsUsername" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>If enabled then username field is hidden from registration form and email is used as username for new user.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'registrationEmailAsUsername.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="editUsernameAllowed" class="col-md-2 control-label">Edit username</label>
|
||||
<label for="editUsernameAllowed" class="col-md-2 control-label">{{:: 'editUsernameAllowed' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.editUsernameAllowed" name="editUsernameAllowed" id="editUsernameAllowed" onoffswitch />
|
||||
<input ng-model="realm.editUsernameAllowed" name="editUsernameAllowed" id="editUsernameAllowed" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>If enabled, the username field is editable, readonly otherwise.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'editUsernameAllowed.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="resetPasswordAllowed" class="col-md-2 control-label">Forget password</label>
|
||||
<label for="resetPasswordAllowed" class="col-md-2 control-label">{{:: 'resetPasswordAllowed' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.resetPasswordAllowed" name="resetPasswordAllowed" id="resetPasswordAllowed" onoffswitch />
|
||||
<input ng-model="realm.resetPasswordAllowed" name="resetPasswordAllowed" id="resetPasswordAllowed" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>Show a link on login page for user to click on when they have forgotten their credentials.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'resetPasswordAllowed.tooltip' |translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="rememberMe">Remember Me</label>
|
||||
<label class="col-md-2 control-label" for="rememberMe">{{:: 'rememberMe' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.rememberMe" name="rememberMe" id="rememberMe" onoffswitch />
|
||||
<input ng-model="realm.rememberMe" name="rememberMe" id="rememberMe" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>Show checkbox on login page to allow user to remain logged in between browser restarts until session expires.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'rememberMe.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="verifyEmail" class="col-md-2 control-label">Verify email</label>
|
||||
<label for="verifyEmail" class="col-md-2 control-label">{{:: 'verifyEmail' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.verifyEmail" name="verifyEmail" id="verifyEmail" onoffswitch />
|
||||
<input ng-model="realm.verifyEmail" name="verifyEmail" id="verifyEmail" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>Require the user to verify their email address the first time they login.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'verifyEmail.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="sslRequired" class="col-md-2 control-label">Require SSL</label>
|
||||
<label for="sslRequired" class="col-md-2 control-label">{{:: 'sslRequired' | translate}}</label>
|
||||
<div class="col-md-2">
|
||||
<div>
|
||||
<select id="sslRequired" ng-model="realm.sslRequired" class="form-control">
|
||||
<option value="all">all requests</option>
|
||||
<option value="external">external requests</option>
|
||||
<option value="none">none</option>
|
||||
<option value="all">{{:: 'sslRequired.option.all' | translate}}</option>
|
||||
<option value="external">{{:: 'sslRequired.option.external' | translate}}</option>
|
||||
<option value="none">{{:: 'sslRequired.option.none' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>Is HTTPS required? 'None' means HTTPS is not required for any client IP address. 'External requests' means localhost and private IP addresses can access without HTTPS. 'All requests' means HTTPS is required for all IP addresses.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'sslRequired.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="form-group" data-ng-show="access.manageRealm">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button kc-save data-ng-disabled="!changed">Save</button>
|
||||
<button kc-reset data-ng-disabled="!changed">Cancel</button>
|
||||
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -3,59 +3,59 @@
|
|||
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpHost"><span class="required">*</span> Host</label>
|
||||
<label class="col-md-2 control-label" for="smtpHost"><span class="required">*</span> {{:: 'host' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpHost" type="text" ng-model="realm.smtpServer.host" placeholder="SMTP Host" required>
|
||||
<input class="form-control" id="smtpHost" type="text" ng-model="realm.smtpServer.host" placeholder="{{:: 'smtp-host' | translate}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpPort">Port</label>
|
||||
<label class="col-md-2 control-label" for="smtpPort">{{:: 'port' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpPort" type="number" ng-model="realm.smtpServer.port" placeholder="SMTP Port (defaults to 25)">
|
||||
<input class="form-control" id="smtpPort" type="number" ng-model="realm.smtpServer.port" placeholder="{{:: 'smtp-port' | translate}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpFrom"><span class="required">*</span> From</label>
|
||||
<label class="col-md-2 control-label" for="smtpFrom"><span class="required">*</span> {{:: 'from' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpFrom" type="email" ng-model="realm.smtpServer.from" placeholder="Sender Email Address" required>
|
||||
<input class="form-control" id="smtpFrom" type="email" ng-model="realm.smtpServer.from" placeholder="{{:: 'sender-email-addr' | translate}}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpSSL">Enable SSL</label>
|
||||
<label class="col-md-2 control-label" for="smtpSSL">{{:: 'enable-ssl' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.smtpServer.ssl" name="smtpSSL" id="smtpSSL" onoffswitch />
|
||||
<input ng-model="realm.smtpServer.ssl" name="smtpSSL" id="smtpSSL" onoffswitch onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpStartTLS">Enable StartTLS</label>
|
||||
<label class="col-md-2 control-label" for="smtpStartTLS">{{:: 'enable-start-tls' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.smtpServer.starttls" name="smtpStartTLS" id="smtpStartTLS" onoffswitch />
|
||||
<input ng-model="realm.smtpServer.starttls" name="smtpStartTLS" id="smtpStartTLS" onoffswitch onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="smtpAuth">Enable Authentication</label>
|
||||
<label class="col-md-2 control-label" for="smtpAuth">{{:: 'enable-auth' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="realm.smtpServer.auth" name="smtpAuth" id="smtpAuth" onoffswitch />
|
||||
<input ng-model="realm.smtpServer.auth" name="smtpAuth" id="smtpAuth" onoffswitch onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="realm.smtpServer.auth">
|
||||
<label class="col-md-2 control-label" for="smtpUsername"><span class="required">*</span> Username</span></label>
|
||||
<label class="col-md-2 control-label" for="smtpUsername"><span class="required">*</span> {{:: 'username' | translate}}</span></label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpUsername" type="text" ng-model="realm.smtpServer.user" placeholder="Login Username" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
|
||||
<input class="form-control" id="smtpUsername" type="text" ng-model="realm.smtpServer.user" placeholder="{{:: 'login-username' | translate}}" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix" data-ng-show="realm.smtpServer.auth">
|
||||
<label class="col-md-2 control-label" for="smtpPassword"><span class="required">*</span> Password</label>
|
||||
<label class="col-md-2 control-label" for="smtpPassword"><span class="required">*</span> {{:: 'password' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input class="form-control" id="smtpPassword" type="password" ng-model="realm.smtpServer.password" placeholder="Login Password" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
|
||||
<input class="form-control" id="smtpPassword" type="password" ng-model="realm.smtpServer.password" placeholder="{{:: 'login-password' | translate}}" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" data-ng-show="access.manageRealm">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button data-kc-save data-ng-disabled="!changed">Save</button>
|
||||
<button data-kc-reset data-ng-disabled="!changed">Cancel</button>
|
||||
<button data-kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||
<button data-kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -4,72 +4,72 @@
|
|||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="loginTheme">Login Theme</label>
|
||||
<label class="col-md-2 control-label" for="loginTheme">{{:: 'login-theme' | translate}}</label>
|
||||
<div class="col-md-3">
|
||||
<div>
|
||||
<select class="form-control" id="loginTheme"
|
||||
ng-model="realm.loginTheme"
|
||||
ng-options="o as o for o in serverInfo.themes.login">
|
||||
<option value="" disabled selected>Select one...</option>
|
||||
<option value="" disabled selected>{{:: 'select-one' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>Select theme for login, TOTP, grant, registration, and forgot password pages.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'login-theme.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="accountTheme">Account Theme</label>
|
||||
<label class="col-md-2 control-label" for="accountTheme">{{:: 'account-theme' | translate}}</label>
|
||||
<div class="col-md-3">
|
||||
<div>
|
||||
<select class="form-control" id="accountTheme"
|
||||
ng-model="realm.accountTheme"
|
||||
ng-options="o as o for o in serverInfo.themes.account">
|
||||
<option value="" disabled selected>Select one...</option>
|
||||
<option value="" disabled selected>{{:: 'select-one' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>Select theme for user account management pages.</kc-tooltip>
|
||||
<kc-tooltip>{{ 'account-theme.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="adminTheme">Admin Console Theme</label>
|
||||
<label class="col-md-2 control-label" for="adminTheme">{{:: 'admin-console-theme' | translate}}</label>
|
||||
<div class="col-md-3">
|
||||
<div>
|
||||
<select class="form-control" id="adminTheme"
|
||||
ng-model="realm.adminTheme"
|
||||
ng-options="o as o for o in serverInfo.themes.admin">
|
||||
<option value="" disabled selected>Select one...</option>
|
||||
<option value="" disabled selected>{{:: 'select-one' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>Select theme for admin console.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'select-theme-admin-console' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="emailTheme">Email Theme</label>
|
||||
<label class="col-md-2 control-label" for="emailTheme">{{:: 'email-theme' | translate}}</label>
|
||||
<div class="col-md-3">
|
||||
<div>
|
||||
<select class="form-control" id="emailTheme"
|
||||
ng-model="realm.emailTheme"
|
||||
ng-options="o as o for o in serverInfo.themes.email">
|
||||
<option value="" disabled selected>Select one...</option>
|
||||
<option value="" disabled selected>{{:: 'select-one' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<kc-tooltip>Select theme for emails that are sent by the server.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'select-theme-email' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="internationalizationEnabled">Internationalization Enabled</label>
|
||||
<label class="col-md-2 control-label" for="internationalizationEnabled">{{:: 'i18n-enabled' | translate}}</label>
|
||||
<div class="col-md-3">
|
||||
<input ng-model="realm.internationalizationEnabled" name="internationalizationEnabled" id="internationalizationEnabled" onoffswitch />
|
||||
<input ng-model="realm.internationalizationEnabled" name="internationalizationEnabled" id="internationalizationEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.internationalizationEnabled">
|
||||
<label class="col-md-2 control-label" for="supportedLocales" class="control-label two-lines">Supported Locales</label>
|
||||
<label class="col-md-2 control-label" for="supportedLocales" class="control-label two-lines">{{:: 'supported-locales' | translate}}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="supportedLocales" type="text" ui-select2="supportedLocalesOptions" ng-model="realm.supportedLocales" placeholder="Type a locale and enter" ng-required="realm.internationalizationEnabled" ng-disabled="!realm.internationalizationEnabled">
|
||||
<input id="supportedLocales" type="text" ui-select2="supportedLocalesOptions" ng-model="realm.supportedLocales" placeholder="{{:: 'supported-locales.placeholder' | translate}}" ng-required="realm.internationalizationEnabled" ng-disabled="!realm.internationalizationEnabled">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.internationalizationEnabled">
|
||||
<label class="col-md-2 control-label" for="defaultLocale">Default Locale</label>
|
||||
<label class="col-md-2 control-label" for="defaultLocale">{{:: 'default-locale' | translate}}</label>
|
||||
<div class="col-md-3">
|
||||
<div>
|
||||
<select class="form-control" id="defaultLocale"
|
||||
|
@ -77,7 +77,7 @@
|
|||
ng-options="o as o for o in realm.supportedLocales"
|
||||
ng-required="realm.internationalizationEnabled"
|
||||
ng-disabled="!realm.internationalizationEnabled">
|
||||
<option value="" disabled selected>Select one...</option>
|
||||
<option value="" disabled selected>{{:: 'select-one' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -86,8 +86,8 @@
|
|||
|
||||
<div class="form-group" data-ng-show="access.manageRealm">
|
||||
<div class="col-md-10 col-md-offset-2">
|
||||
<button kc-save data-ng-disabled="!changed">Save</button>
|
||||
<button kc-reset data-ng-disabled="!changed">Cancel</button>
|
||||
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -4,110 +4,110 @@
|
|||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="ssoSessionIdleTimeout">SSO Session Idle</label>
|
||||
<label class="col-md-2 control-label" for="ssoSessionIdleTimeout">{{:: 'sso-session-idle' | translate}}</label>
|
||||
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1" max="31536000" data-ng-model="realm.ssoSessionIdleTimeout" id="ssoSessionIdleTimeout"
|
||||
name="ssoSessionIdleTimeout"/>
|
||||
<select class="form-control" name="ssoSessionIdleTimeoutUnit" data-ng-model="realm.ssoSessionIdleTimeoutUnit">
|
||||
<option data-ng-selected="!realm.ssoSessionIdleTimeoutUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.ssoSessionIdleTimeoutUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>Time a session is allowed to be idle before it expires. Tokens and browser sessions are invalidated when a session is expired.
|
||||
<kc-tooltip>{{:: 'sso-session-idle.tooltip' | translate}}
|
||||
</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="ssoSessionMaxLifespan">SSO Session Max</label>
|
||||
<label class="col-md-2 control-label" for="ssoSessionMaxLifespan">{{:: 'sso-session-max' | translate}}</label>
|
||||
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.ssoSessionMaxLifespan"
|
||||
id="ssoSessionMaxLifespan" name="ssoSessionMaxLifespan"/>
|
||||
<select class="form-control" name="ssoSessionMaxLifespanUnit" data-ng-model="realm.ssoSessionMaxLifespanUnit">
|
||||
<option data-ng-selected="!realm.ssoSessionMaxLifespanUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.ssoSessionMaxLifespanUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>Max time before a session is expired. Tokens and browser sessions are invalidated when a session is expired.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'sso-session-max.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="accessTokenLifespan">Access Token Lifespan</label>
|
||||
<label class="col-md-2 control-label" for="accessTokenLifespan">{{:: 'access-token-lifespan' | translate}}</label>
|
||||
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.accessTokenLifespan"
|
||||
id="accessTokenLifespan" name="accessTokenLifespan"/>
|
||||
<select class="form-control" name="accessTokenLifespanUnit" data-ng-model="realm.accessTokenLifespanUnit">
|
||||
<option data-ng-selected="!realm.accessTokenLifespanUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.accessTokenLifespanUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>Max time before an access token is expired. This value is recommended to be short relative to the SSO timeout.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'access-token-lifespan.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="accessCodeLifespan">Client login timeout</label>
|
||||
<label class="col-md-2 control-label" for="accessCodeLifespan">{{:: 'client-login-timeout' | translate}}</label>
|
||||
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1" max="31536000" data-ng-model="realm.accessCodeLifespan" id="accessCodeLifespan"
|
||||
name="accessCodeLifespan">
|
||||
<select class="form-control" name="accessCodeLifespanUnit" data-ng-model="realm.accessCodeLifespanUnit">
|
||||
<option data-ng-selected="!realm.accessCodeLifespanUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.accessCodeLifespanUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>Max time an client has to finish the access token protocol. This should normally be 1 minute.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'client-login-timeout.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="accessCodeLifespanLogin" class="two-lines">Login timeout</label>
|
||||
<label class="col-md-2 control-label" for="accessCodeLifespanLogin" class="two-lines">{{:: 'login-timeout' | translate}}</label>
|
||||
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1" max="31536000" data-ng-model="realm.accessCodeLifespanLogin"
|
||||
id="accessCodeLifespanLogin" name="accessCodeLifespanLogin">
|
||||
<select class="form-control" name="accessCodeLifespanLoginUnit" data-ng-model="realm.accessCodeLifespanLoginUnit">
|
||||
<option data-ng-selected="!realm.accessCodeLifespanLoginUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.accessCodeLifespanLoginUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>Max time a user has to complete a login. This is recommended to be relatively long. 30 minutes or more.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'login-timeout' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="accessCodeLifespanUserAction" class="two-lines">Login action timeout</label>
|
||||
<label class="col-md-2 control-label" for="accessCodeLifespanUserAction" class="two-lines">{{:: 'login-action-timeout' | translate}}</label>
|
||||
|
||||
<div class="col-md-6 time-selector">
|
||||
<input class="form-control" type="number" required min="1" max="31536000" data-ng-model="realm.accessCodeLifespanUserAction"
|
||||
id="accessCodeLifespanUserAction" name="accessCodeLifespanUserAction">
|
||||
<select class="form-control" name="accessCodeLifespanUserActionUnit" data-ng-model="realm.accessCodeLifespanUserActionUnit">
|
||||
<option data-ng-selected="!realm.accessCodeLifespanUserActionUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
<option data-ng-selected="!realm.accessCodeLifespanUserActionUnit" value="Seconds">{{:: 'seconds' | translate}}</option>
|
||||
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||
<option value="Days">{{:: 'days' | translate}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<kc-tooltip>
|
||||
Max time a user has to complete login related actions like update password or configure totp. This is recommended to be relatively long. 5 minutes or more.
|
||||
{{:: 'login-action-timeout.tooltip' | translate}}
|
||||
</kc-tooltip>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
|
||||
<button kc-save data-ng-disabled="!changed">Save</button>
|
||||
<button kc-reset data-ng-disabled="!changed">Cancel</button>
|
||||
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
<h1>Sessions</h1>
|
||||
<h1>{{:: 'sessions' | translate}}</h1>
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/sessions/realm">Realm Sessions</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/sessions/revocation">Revocation</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/sessions/realm">{{:: 'realm-sessions' | translate}}</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/sessions/revocation">{{:: 'revocation' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<table class="table table-striped table-bordered">
|
||||
|
@ -11,13 +11,13 @@
|
|||
<tr>
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="pull-right">
|
||||
<a id="logoutAllSessions" class="btn btn-default" ng-click="logoutAll()">Logout All</a>
|
||||
<a id="logoutAllSessions" class="btn btn-default" ng-click="logoutAll()">{{:: 'logout-all' | translate}}</a>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Client</th>
|
||||
<th>Active Sessions</th>
|
||||
<th>{{:: 'client' | translate}}</th>
|
||||
<th>{{:: 'active-sessions' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||
<h1>Sessions</h1>
|
||||
<h1>{{:: 'sessions' | translate}}</h1>
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<li><a href="#/realms/{{realm.realm}}/sessions/realm">Realm Sessions</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/sessions/revocation">Revocation</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/sessions/realm">{{:: 'realm-sessions' | translate}}</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/sessions/revocation">{{:: 'revocation' | translate}}</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="notBefore">Not Before</label>
|
||||
<label class="col-md-2 control-label" for="notBefore">{{:: 'not-before' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-disabled="true" class="form-control" type="text" id="notBefore" name="notBefore" data-ng-model="notBefore" autofocus>
|
||||
</div>
|
||||
<kc-tooltip>Revoke any tokens issued before this date.</kc-tooltip>
|
||||
<kc-tooltip>{{:: 'not-before.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-10 col-md-offset-2" data-ng-show="access.manageClients">
|
||||
<button type="submit" data-ng-click="setNotBeforeNow()" class="btn btn-default">Set To Now</button>
|
||||
<button type="submit" data-ng-click="clear()" class="btn btn-default">Clear</button>
|
||||
<button type="submit" data-ng-click="pushRevocation()" class="btn btn-primary" tooltip-trigger="mouseover mouseout" tooltip="For every client that has an admin URL, notify them of the new revocation policy." tooltip-placement="bottom">Push</button>
|
||||
<button type="submit" data-ng-click="setNotBeforeNow()" class="btn btn-default">{{:: 'set-to-now' | translate}}</button>
|
||||
<button type="submit" data-ng-click="clear()" class="btn btn-default">{{:: 'clear' | translate}}</button>
|
||||
<button type="submit" data-ng-click="pushRevocation()" class="btn btn-primary" tooltip-trigger="mouseover mouseout" tooltip="{{:: 'push.tooltip' | translate}}" tooltip-placement="bottom">{{:: 'push' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
{{realm.realm|capitalize}}
|
||||
<i id="removeRealm" class="pficon pficon-delete clickable" data-ng-show="access.manageRealm" data-ng-click="removeRealm()"></i>
|
||||
</h1>
|
||||
<h1 data-ng-show="createRealm">Add Realm</h1>
|
||||
<h1 data-ng-show="createRealm">{{:: 'add-realm' | translate}}</h1>
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<li ng-class="{active: !path[2]}"><a href="#/realms/{{realm.realm}}">General</a></li>
|
||||
<li ng-class="{active: path[2] == 'login-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/login-settings">Login</a></li>
|
||||
<li ng-class="{active: path[2] == 'keys-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
|
||||
<li ng-class="{active: path[2] == 'smtp-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
|
||||
<li ng-class="{active: path[2] == 'theme-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/theme-settings">Themes</a></li>
|
||||
<li ng-class="{active: path[2] == 'cache-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/cache-settings">Cache</a></li>
|
||||
<li ng-class="{active: path[2] == 'token-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/token-settings">Tokens</a></li>
|
||||
<li ng-class="{active: path[2] == 'defense'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/defense/headers">Security Defenses</a></li>
|
||||
<li ng-class="{active: !path[2]}"><a href="#/realms/{{realm.realm}}">{{:: 'realm-tab-general' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'login-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/login-settings">{{:: 'realm-tab-login' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'keys-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/keys-settings">{{:: 'realm-tab-keys' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'smtp-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/smtp-settings">{{:: 'realm-tab-email' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'theme-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/theme-settings">{{:: 'realm-tab-themes' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'cache-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/cache-settings">{{:: 'realm-tab-cache' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'token-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/token-settings">{{:: 'realm-tab-tokens' | translate}}</a></li>
|
||||
<li ng-class="{active: path[2] == 'defense'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/defense/headers">{{:: 'realm-tab-security-defenses' | translate}}</a></li>
|
||||
</ul>
|
||||
</div>
|
|
@ -0,0 +1,75 @@
|
|||
/*!
|
||||
* angular-translate - v2.7.2 - 2015-06-01
|
||||
* http://github.com/angular-translate/angular-translate
|
||||
* Copyright (c) 2015 ; Licensed MIT
|
||||
*/
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module unless amdModuleId is set
|
||||
define([], function () {
|
||||
return (factory());
|
||||
});
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node. Does not work with strict CommonJS, but
|
||||
// only CommonJS-like environments that support module.exports,
|
||||
// like Node.
|
||||
module.exports = factory();
|
||||
} else {
|
||||
factory();
|
||||
}
|
||||
}(this, function () {
|
||||
|
||||
angular.module('pascalprecht.translate')
|
||||
/**
|
||||
* @ngdoc object
|
||||
* @name pascalprecht.translate.$translateUrlLoader
|
||||
* @requires $q
|
||||
* @requires $http
|
||||
*
|
||||
* @description
|
||||
* Creates a loading function for a typical dynamic url pattern:
|
||||
* "locale.php?lang=en_US", "locale.php?lang=de_DE", "locale.php?language=nl_NL" etc.
|
||||
* Prefixing the specified url, the current requested, language id will be applied
|
||||
* with "?{queryParameter}={key}".
|
||||
* Using this service, the response of these urls must be an object of
|
||||
* key-value pairs.
|
||||
*
|
||||
* @param {object} options Options object, which gets the url, key and
|
||||
* optional queryParameter ('lang' is used by default).
|
||||
*/
|
||||
.factory('$translateUrlLoader', $translateUrlLoader);
|
||||
|
||||
function $translateUrlLoader($q, $http) {
|
||||
|
||||
'use strict';
|
||||
|
||||
return function (options) {
|
||||
|
||||
if (!options || !options.url) {
|
||||
throw new Error('Couldn\'t use urlLoader since no url is given!');
|
||||
}
|
||||
|
||||
var deferred = $q.defer(),
|
||||
requestParams = {};
|
||||
|
||||
requestParams[options.queryParameter || 'lang'] = options.key;
|
||||
|
||||
$http(angular.extend({
|
||||
url: options.url,
|
||||
params: requestParams,
|
||||
method: 'GET'
|
||||
}, options.$http)).success(function (data) {
|
||||
deferred.resolve(data);
|
||||
}).error(function () {
|
||||
deferred.reject(options.key);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
}
|
||||
$translateUrlLoader.$inject = ['$q', '$http'];
|
||||
|
||||
$translateUrlLoader.displayName = '$translateUrlLoader';
|
||||
return 'pascalprecht.translate';
|
||||
|
||||
}));
|
|
@ -0,0 +1,71 @@
|
|||
/*!
|
||||
* angular-translate - v2.6.1 - 2015-03-01
|
||||
* http://github.com/angular-translate/angular-translate
|
||||
* Copyright (c) 2015 ; Licensed MIT
|
||||
*/
|
||||
angular.module('pascalprecht.translate')
|
||||
|
||||
/**
|
||||
* @ngdoc object
|
||||
* @name pascalprecht.translate.$translateCookieStorage
|
||||
* @requires $cookieStore
|
||||
*
|
||||
* @description
|
||||
* Abstraction layer for cookieStore. This service is used when telling angular-translate
|
||||
* to use cookieStore as storage.
|
||||
*
|
||||
*/
|
||||
.factory('$translateCookieStorage', ['$cookieStore', function ($cookieStore) {
|
||||
|
||||
var $translateCookieStorage = {
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name pascalprecht.translate.$translateCookieStorage#get
|
||||
* @methodOf pascalprecht.translate.$translateCookieStorage
|
||||
*
|
||||
* @description
|
||||
* Returns an item from cookieStorage by given name.
|
||||
*
|
||||
* @param {string} name Item name
|
||||
* @return {string} Value of item name
|
||||
*/
|
||||
get: function (name) {
|
||||
return $cookieStore.get(name);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name pascalprecht.translate.$translateCookieStorage#set
|
||||
* @methodOf pascalprecht.translate.$translateCookieStorage
|
||||
*
|
||||
* @description
|
||||
* Sets an item in cookieStorage by given name.
|
||||
*
|
||||
* @deprecated use #put
|
||||
*
|
||||
* @param {string} name Item name
|
||||
* @param {string} value Item value
|
||||
*/
|
||||
set: function (name, value) {
|
||||
$cookieStore.put(name, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name pascalprecht.translate.$translateCookieStorage#put
|
||||
* @methodOf pascalprecht.translate.$translateCookieStorage
|
||||
*
|
||||
* @description
|
||||
* Sets an item in cookieStorage by given name.
|
||||
*
|
||||
* @param {string} name Item name
|
||||
* @param {string} value Item value
|
||||
*/
|
||||
put: function (name, value) {
|
||||
$cookieStore.put(name, value);
|
||||
}
|
||||
};
|
||||
|
||||
return $translateCookieStorage;
|
||||
}]);
|
2904
forms/common-themes/src/main/resources/theme/keycloak/common/resources/lib/angular/angular-translate.js
vendored
Normal file
2904
forms/common-themes/src/main/resources/theme/keycloak/common/resources/lib/angular/angular-translate.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
@ -276,7 +292,10 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
|||
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
|
||||
builder.header(entry.getKey(), entry.getValue());
|
||||
}
|
||||
LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, Urls.localeCookiePath(baseUri, realm.getName()));
|
||||
|
||||
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);
|
||||
|
@ -374,7 +393,9 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
|||
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
|
||||
builder.header(entry.getKey(), entry.getValue());
|
||||
}
|
||||
LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, Urls.localeCookiePath(baseUri, realm.getName()));
|
||||
|
||||
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);
|
||||
|
@ -383,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;
|
||||
|
@ -410,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);
|
||||
|
@ -494,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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -44,7 +44,9 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import javax.ws.rs.QueryParam;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -283,8 +285,7 @@ public class AdminConsole {
|
|||
map.put("resourceUrl", Urls.themeRoot(baseUri) + "/admin/" + adminTheme);
|
||||
map.put("resourceVersion", Version.RESOURCES_VERSION);
|
||||
|
||||
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
|
||||
Theme theme = themeProvider.getTheme(realm.getAdminTheme(), Theme.Type.ADMIN);
|
||||
Theme theme = getTheme();
|
||||
|
||||
map.put("properties", theme.getProperties());
|
||||
|
||||
|
@ -296,10 +297,38 @@ public class AdminConsole {
|
|||
}
|
||||
}
|
||||
|
||||
private Theme getTheme() throws IOException {
|
||||
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
|
||||
return themeProvider.getTheme(realm.getAdminTheme(), Theme.Type.ADMIN);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{indexhtml: index.html}") // this expression is a hack to get around jaxdoclet generation bug. Doesn't like index.html
|
||||
public Response getIndexHtmlRedirect() {
|
||||
return Response.status(302).location(uriInfo.getRequestUriBuilder().path("../").build()).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("messages.json")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Properties getMessages(@QueryParam("lang") String lang) {
|
||||
if (lang == null) {
|
||||
logger.warn("Locale not specified for messages.json");
|
||||
lang = "en";
|
||||
}
|
||||
|
||||
try {
|
||||
Properties msgs = AdminMessagesLoader.getMessages(getTheme(), lang);
|
||||
if (msgs.isEmpty()) {
|
||||
logger.warn("Message bundle not found for language code '" + lang + "'");
|
||||
msgs = AdminMessagesLoader.getMessages(getTheme(), "en"); // fall back to en
|
||||
}
|
||||
|
||||
if (msgs.isEmpty()) logger.fatal("Message bundle not found for language code 'en'");
|
||||
|
||||
return msgs;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.resources.admin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import org.keycloak.freemarker.Theme;
|
||||
|
||||
/**
|
||||
* Simple loader and cache for message bundles consumed by angular-translate.
|
||||
*
|
||||
* Note that these bundles are converted to JSON before being shipped to the UI.
|
||||
* Also, the content should be formatted such that it can be interpolated by
|
||||
* angular-translate. This is somewhat different from an ordinary Java bundle.
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2015 Red Hat Inc.
|
||||
*/
|
||||
public class AdminMessagesLoader {
|
||||
private static final Map<String, Properties> allMessages = new HashMap<String, Properties>();
|
||||
|
||||
static Properties getMessages(Theme theme, String strLocale) throws IOException {
|
||||
String allMessagesKey = theme.getName() + "_" + strLocale;
|
||||
Properties messages = allMessages.get(allMessagesKey);
|
||||
if (messages != null) return messages;
|
||||
|
||||
Locale locale = Locale.forLanguageTag(strLocale);
|
||||
messages = theme.getMessages("admin-messages", locale);
|
||||
if (messages == null) return new Properties();
|
||||
|
||||
allMessages.put(allMessagesKey, messages);
|
||||
return messages;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue