├── .gitignore ├── screenshot.png ├── themes └── arenadata │ └── login │ ├── resources │ ├── img │ │ ├── bg.png │ │ ├── favicon.ico │ │ ├── keycloak-logo-text.png │ │ └── ad-logo.svg │ └── css │ │ └── login.css │ ├── theme.properties │ ├── template.ftl │ └── messages │ └── messages_en.properties ├── extensions ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ └── services │ │ │ │ ├── org.keycloak.broker.provider.IdentityProviderMapper │ │ │ │ ├── org.keycloak.broker.social.SocialIdentityProviderFactory │ │ │ │ └── org.keycloak.authentication.AuthenticatorFactory │ │ └── theme-resources │ │ │ └── resources │ │ │ └── partials │ │ │ ├── realm-identity-provider-yandex.html │ │ │ └── realm-identity-provider-yandex-ext.html │ │ └── java │ │ └── io │ │ └── arenadata │ │ └── keycloak │ │ ├── providers │ │ └── yandex │ │ │ ├── YandexUserAttributeMapper.java │ │ │ ├── YandexIdentityProviderConfig.java │ │ │ ├── YandexIdentityProviderFactory.java │ │ │ └── YandexIdentityProvider.java │ │ └── authenticators │ │ ├── MattermostIntegrationAuthenticatorFactory.java │ │ └── MattermostIntegrationAuthenticator.java └── pom.xml ├── Makefile ├── Dockerfile ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | extensions/target 2 | tmp 3 | .vscode 4 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arenadata/keycloak-arenadata/HEAD/screenshot.png -------------------------------------------------------------------------------- /themes/arenadata/login/resources/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arenadata/keycloak-arenadata/HEAD/themes/arenadata/login/resources/img/bg.png -------------------------------------------------------------------------------- /extensions/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper: -------------------------------------------------------------------------------- 1 | io.arenadata.keycloak.providers.yandex.YandexUserAttributeMapper -------------------------------------------------------------------------------- /themes/arenadata/login/resources/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arenadata/keycloak-arenadata/HEAD/themes/arenadata/login/resources/img/favicon.ico -------------------------------------------------------------------------------- /extensions/src/main/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory: -------------------------------------------------------------------------------- 1 | io.arenadata.keycloak.providers.yandex.YandexIdentityProviderFactory -------------------------------------------------------------------------------- /extensions/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory: -------------------------------------------------------------------------------- 1 | io.arenadata.keycloak.authenticators.MattermostIntegrationAuthenticatorFactory -------------------------------------------------------------------------------- /themes/arenadata/login/resources/img/keycloak-logo-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arenadata/keycloak-arenadata/HEAD/themes/arenadata/login/resources/img/keycloak-logo-text.png -------------------------------------------------------------------------------- /extensions/src/main/resources/theme-resources/resources/partials/realm-identity-provider-yandex.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /extensions/src/main/resources/theme-resources/resources/partials/realm-identity-provider-yandex-ext.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | Hosted domain 7 |
-------------------------------------------------------------------------------- /extensions/src/main/java/io/arenadata/keycloak/providers/yandex/YandexUserAttributeMapper.java: -------------------------------------------------------------------------------- 1 | package io.arenadata.keycloak.providers.yandex; 2 | 3 | import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper; 4 | 5 | public class YandexUserAttributeMapper extends AbstractJsonUserAttributeMapper { 6 | 7 | private static final String[] COMPATIBLE_PROVIDERS = new String[]{YandexIdentityProviderFactory.PROVIDER_ID}; 8 | 9 | @Override 10 | public String[] getCompatibleProviders() { 11 | return COMPATIBLE_PROVIDERS; 12 | } 13 | 14 | @Override 15 | public String getId() { 16 | return "yandex-user-attribute-mapper"; 17 | } 18 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build start start-dev 2 | -include .env 3 | VERSION:=0.2.0 4 | KC_DB?=postgres 5 | KC_DB_URL?=jdbc:postgresql://localhost/keycloak 6 | KC_DB_USERNAME?=keycloak 7 | KC_DB_PASSWORD?=keycloak 8 | KC_ARG?="" 9 | IMAGE="hub.adsw.io/library/keycloak-arenadata:17-${VERSION}" 10 | build: 11 | docker build --build-arg VERSION=${VERSION} -t ${IMAGE} . 12 | start start-dev: build 13 | docker run -p 80:8080 \ 14 | -e KC_DB=${KC_DB} \ 15 | -e KC_DB_URL=${KC_DB_URL} \ 16 | -e KC_DB_USERNAME=${KC_DB_USERNAME} \ 17 | -e KC_DB_PASSWORD='${KC_DB_PASSWORD}' \ 18 | -e KEYCLOAK_ADMIN=admin \ 19 | -e KEYCLOAK_ADMIN_PASSWORD=admin \ 20 | ${IMAGE} \ 21 | $@ \ 22 | --http-enabled=true \ 23 | --proxy=edge \ 24 | --hostname-strict=false ${KC_ARGS} 25 | -------------------------------------------------------------------------------- /extensions/src/main/java/io/arenadata/keycloak/providers/yandex/YandexIdentityProviderConfig.java: -------------------------------------------------------------------------------- 1 | package io.arenadata.keycloak.providers.yandex; 2 | 3 | import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; 4 | import org.keycloak.models.IdentityProviderModel; 5 | 6 | public class YandexIdentityProviderConfig extends OAuth2IdentityProviderConfig { 7 | 8 | public YandexIdentityProviderConfig(IdentityProviderModel model) { 9 | super(model); 10 | } 11 | 12 | public YandexIdentityProviderConfig() { 13 | } 14 | 15 | public String getHostedDomain() { 16 | String hostedDomain = getConfig().get("hostedDomain") ; 17 | return hostedDomain == null || hostedDomain.isEmpty() ? null : hostedDomain; 18 | } 19 | 20 | public void setHostedDomain(final String hostedDomain) { 21 | getConfig().put("hostedDomain", hostedDomain); 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VERSION 2 | ARG KEYCLOAK_VERSION=17.0.1 3 | 4 | # Build extensions. 5 | FROM maven:3-openjdk-17 as builder 6 | ARG VERSION 7 | ARG KEYCLOAK_VERSION 8 | COPY extensions /src/extensions 9 | RUN cd /src/extensions && mvn package 10 | 11 | # Configure Keycloak. 12 | FROM quay.io/keycloak/keycloak:${KEYCLOAK_VERSION} as keycloak 13 | ARG VERSION 14 | ARG KEYCLOAK_VERSION 15 | COPY --from=builder \ 16 | /src/extensions/target/keycloak-arenadata-${VERSION}.jar \ 17 | /opt/keycloak/providers/ 18 | COPY themes/arenadata/ /opt/keycloak/themes/arenadata/ 19 | RUN /opt/keycloak/bin/kc.sh build \ 20 | --db=postgres \ 21 | --metrics-enabled=true \ 22 | --features=scripts 23 | 24 | # Build Keycloak. 25 | FROM quay.io/keycloak/keycloak:${KEYCLOAK_VERSION} 26 | ARG VERSION 27 | ARG KEYCLOAK_VERSION 28 | COPY --from=keycloak /opt/keycloak/lib/quarkus/ /opt/keycloak/lib/quarkus/ 29 | COPY --from=keycloak /opt/keycloak/providers/ /opt/keycloak/providers/ 30 | COPY --from=keycloak /opt/keycloak/themes/ /opt/keycloak/themes/ 31 | WORKDIR /opt/keycloak 32 | ENTRYPOINT ["/opt/keycloak/bin/kc.sh"] 33 | -------------------------------------------------------------------------------- /extensions/src/main/java/io/arenadata/keycloak/providers/yandex/YandexIdentityProviderFactory.java: -------------------------------------------------------------------------------- 1 | package io.arenadata.keycloak.providers.yandex; 2 | 3 | import org.keycloak.broker.provider.AbstractIdentityProviderFactory; 4 | import org.keycloak.broker.social.SocialIdentityProviderFactory; 5 | import org.keycloak.models.IdentityProviderModel; 6 | import org.keycloak.models.KeycloakSession; 7 | 8 | public class YandexIdentityProviderFactory 9 | extends AbstractIdentityProviderFactory 10 | implements SocialIdentityProviderFactory { 11 | 12 | public static final String PROVIDER_ID = "yandex"; 13 | 14 | @Override 15 | public String getName() { 16 | return "Yandex"; 17 | } 18 | 19 | @Override 20 | public YandexIdentityProvider create( 21 | KeycloakSession session, IdentityProviderModel model 22 | ) { 23 | return new YandexIdentityProvider(session, new YandexIdentityProviderConfig(model)); 24 | } 25 | 26 | @Override 27 | public YandexIdentityProviderConfig createConfig() { 28 | return new YandexIdentityProviderConfig(); 29 | } 30 | 31 | @Override 32 | public String getId() { 33 | return PROVIDER_ID; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arenadata Keycloak Customization 2 | 3 | ![Arenadata theme screenshot](screenshot.png) 4 | 5 | Includes: 6 | 7 | - Yandex identity provider with `hostedDomain` parameter support; 8 | - corporate login theme; 9 | - Dockerfile to build application image in Quarkus style. 10 | 11 | ## How to build 12 | 13 | Just run `make build`. The `Makefile` contains a set of environment variables 14 | to customize the image. Use can change the values when calling `make` or use 15 | `.env` file (recommended). 16 | 17 | Use the following environment variables to customize build: 18 | 19 | - `KC_DB`: the type of database 20 | - `KC_DB_URL`: database jdbc URL 21 | - `KC_DB_USER`: database user 22 | - `KC_DB_PASSWORD`: database password 23 | - `IMAGE`: Docker image name 24 | - `KC_ARGS`: additional parameters for `start` or `start-dev` command 25 | ## How to run 26 | 27 | When developing, just run `make start` or `make start-dev` with the parameters 28 | you need. 29 | 30 | To run with `docker-compose`, use the following configuration: 31 | 32 | ``` 33 | version: "3" 34 | services: 35 | keycloak: 36 | image: hub.adsw.io/library/keycloak-arenadata:17-0.1.0 37 | environment: 38 | KC_DB_URL: "jdbc:postgresql://hostname:port/database" 39 | KC_DB_USERNAME: user 40 | KC_DB_PASSWORD: password 41 | ports: 42 | - 8080:8080 43 | command: start --http-enabled=true --proxy=edge --hostname-strict=false 44 | ``` 45 | 46 | You can tune some build parameters (e.g. add new plugins or change URI path 47 | prefix) in `--auto-build` mode, for example: 48 | 49 | ``` 50 | command start --auto-build --db=postgres --http-relative-path=/auth 51 | ``` 52 | 53 | Use `--auto-build` only in debug or quick fix mode, for production it's better 54 | to rebuild optimized container using Dockerfile. 55 | 56 | -------------------------------------------------------------------------------- /extensions/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | Keycloak Arenadata 5 | 6 | 4.0.0 7 | 8 | io.arenadata.keycloak 9 | keycloak-arenadata 10 | ${env.VERSION} 11 | jar 12 | 13 | 14 | 17.0.1 15 | UTF-8 16 | UTF-8 17 | 18 | 19 | 20 | 21 | org.keycloak 22 | keycloak-core 23 | provided 24 | ${version.keycloak} 25 | 26 | 27 | org.keycloak 28 | keycloak-server-spi 29 | provided 30 | ${version.keycloak} 31 | 32 | 33 | org.keycloak 34 | keycloak-server-spi-private 35 | provided 36 | ${version.keycloak} 37 | 38 | 39 | org.keycloak 40 | keycloak-services 41 | provided 42 | ${version.keycloak} 43 | 44 | 45 | 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-compiler-plugin 51 | 2.3.2 52 | 53 | 1.8 54 | 1.8 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /extensions/src/main/java/io/arenadata/keycloak/authenticators/MattermostIntegrationAuthenticatorFactory.java: -------------------------------------------------------------------------------- 1 | package io.arenadata.keycloak.authenticators; 2 | 3 | import org.keycloak.Config; 4 | import org.keycloak.OAuth2Constants; 5 | import org.keycloak.authentication.Authenticator; 6 | import org.keycloak.authentication.AuthenticatorFactory; 7 | import org.keycloak.authentication.DisplayTypeAuthenticatorFactory; 8 | import org.keycloak.models.KeycloakSession; 9 | import org.keycloak.models.KeycloakSessionFactory; 10 | import org.keycloak.provider.ProviderConfigProperty; 11 | import org.keycloak.models.AuthenticationExecutionModel; 12 | import org.keycloak.authentication.authenticators.AttemptedAuthenticator; 13 | import static org.keycloak.provider.ProviderConfigProperty.STRING_TYPE; 14 | import static java.util.Arrays.asList; 15 | import java.util.List; 16 | 17 | public class MattermostIntegrationAuthenticatorFactory implements AuthenticatorFactory, DisplayTypeAuthenticatorFactory { 18 | 19 | public static final String PROVIDER_ID = "arenadata-platform"; 20 | public static final String GITLAB_TOKEN = "gitlabToken"; 21 | public static final String GITLAB_URI = "gitlabURI"; 22 | 23 | @Override 24 | public Authenticator create(KeycloakSession session) { 25 | return new MattermostIntegrationAuthenticator(); 26 | } 27 | 28 | @Override 29 | public void init(Config.Scope config) { 30 | } 31 | 32 | @Override 33 | public String getReferenceCategory() { 34 | return null; 35 | } 36 | 37 | @Override 38 | public boolean isConfigurable() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public boolean isUserSetupAllowed() { 44 | return true; 45 | } 46 | 47 | @Override 48 | public String getDisplayType() { 49 | return "Arenadata Platform Integration."; 50 | } 51 | 52 | @Override 53 | public Authenticator createDisplay(KeycloakSession session, String displayType) { 54 | if (displayType == null) return new MattermostIntegrationAuthenticator(); 55 | if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) return null; 56 | return AttemptedAuthenticator.SINGLETON; // ignore this authenticator 57 | } 58 | 59 | 60 | @Override 61 | public String getHelpText() { 62 | return "Arenadata Platform Integration."; 63 | } 64 | 65 | @Override 66 | public List getConfigProperties() { 67 | ProviderConfigProperty gitlab_uri = new ProviderConfigProperty( 68 | GITLAB_URI, 69 | "Gitlab URI", 70 | "Gitlab instance URI (https://gitlab.com)", 71 | STRING_TYPE, 72 | null 73 | ); 74 | ProviderConfigProperty gitlab_token = new ProviderConfigProperty( 75 | GITLAB_TOKEN, 76 | "Gitlab Token", 77 | "Gitlab private token", 78 | STRING_TYPE, 79 | null 80 | ); 81 | return asList(gitlab_uri, gitlab_token); 82 | } 83 | 84 | @Override 85 | public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { 86 | return REQUIREMENT_CHOICES; 87 | } 88 | 89 | @Override 90 | public void postInit(KeycloakSessionFactory factory) { 91 | } 92 | 93 | @Override 94 | public void close() { 95 | } 96 | 97 | @Override 98 | public String getId() { 99 | return PROVIDER_ID; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /extensions/src/main/java/io/arenadata/keycloak/providers/yandex/YandexIdentityProvider.java: -------------------------------------------------------------------------------- 1 | package io.arenadata.keycloak.providers.yandex; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import org.jboss.logging.Logger; 5 | import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; 6 | import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper; 7 | import org.keycloak.broker.provider.BrokeredIdentityContext; 8 | import org.keycloak.broker.provider.IdentityBrokerException; 9 | import org.keycloak.broker.provider.util.SimpleHttp; 10 | import org.keycloak.broker.social.SocialIdentityProvider; 11 | import org.keycloak.events.EventBuilder; 12 | import org.keycloak.models.KeycloakSession; 13 | 14 | public class YandexIdentityProvider extends AbstractOAuth2IdentityProvider 15 | implements SocialIdentityProvider { 16 | 17 | private static final Logger log = Logger.getLogger(YandexIdentityProvider.class); 18 | 19 | public static final String AUTH_URL = "https://oauth.yandex.ru/authorize"; 20 | public static final String TOKEN_URL = "https://oauth.yandex.ru/token"; 21 | public static final String PROFILE_URL = "https://login.yandex.ru/info"; 22 | public static final String DEFAULT_SCOPE = ""; 23 | 24 | public YandexIdentityProvider(KeycloakSession session, YandexIdentityProviderConfig config) { 25 | super(session, config); 26 | config.setAuthorizationUrl(AUTH_URL); 27 | config.setTokenUrl(TOKEN_URL); 28 | config.setUserInfoUrl(PROFILE_URL); 29 | } 30 | 31 | @Override 32 | protected boolean supportsExternalExchange() { 33 | return true; 34 | } 35 | 36 | @Override 37 | protected String getProfileEndpointForValidation(EventBuilder event) { 38 | return PROFILE_URL; 39 | } 40 | 41 | @Override 42 | protected BrokeredIdentityContext extractIdentityFromProfile(EventBuilder event, JsonNode profile) { 43 | BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "id")); 44 | String domain = ((YandexIdentityProviderConfig) getConfig()).getHostedDomain(); 45 | 46 | String email = getJsonProperty(profile, "default_email"); 47 | if (email == null || email.trim().isEmpty()) { 48 | throw new IllegalArgumentException("Can not get user's email."); 49 | } 50 | if (domain != null && !domain.isEmpty() && !email.endsWith("@" + domain)) { 51 | throw new IllegalArgumentException("Hosted domain does not match."); 52 | } 53 | String login = getJsonProperty(profile, "login"); 54 | if (login == null || login.trim().isEmpty()) { 55 | user.setUsername(email); 56 | } else { 57 | user.setUsername(login); 58 | } 59 | user.setEmail(email); 60 | user.setFirstName(getJsonProperty(profile, "first_name")); 61 | user.setLastName(getJsonProperty(profile, "last_name")); 62 | 63 | user.setIdpConfig(getConfig()); 64 | user.setIdp(this); 65 | 66 | AbstractJsonUserAttributeMapper.storeUserProfileForMapper(user, profile, getConfig().getAlias()); 67 | 68 | return user; 69 | } 70 | 71 | @Override 72 | protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) { 73 | log.debug("doGetFederatedIdentity()"); 74 | JsonNode profile = null; 75 | try { 76 | profile = SimpleHttp.doGet(PROFILE_URL + "?oauth_token=" + accessToken, session).asJson(); 77 | return extractIdentityFromProfile(null, profile); 78 | } catch (Exception e) { 79 | throw new IdentityBrokerException("Could not obtain user profile from Yandex: " + e.getMessage(), e); 80 | } 81 | } 82 | 83 | @Override 84 | protected String getDefaultScopes() { 85 | return DEFAULT_SCOPE; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /extensions/src/main/java/io/arenadata/keycloak/authenticators/MattermostIntegrationAuthenticator.java: -------------------------------------------------------------------------------- 1 | package io.arenadata.keycloak.authenticators; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import com.fasterxml.jackson.annotation.JsonProperty; 8 | 9 | import org.jboss.logging.Logger; 10 | import org.keycloak.authentication.AuthenticationFlowContext; 11 | import org.keycloak.authentication.Authenticator; 12 | import org.keycloak.broker.provider.util.SimpleHttp; 13 | import org.keycloak.models.KeycloakSession; 14 | import org.keycloak.models.RealmModel; 15 | import org.keycloak.models.UserModel; 16 | 17 | public class MattermostIntegrationAuthenticator implements Authenticator { 18 | 19 | private static final Logger LOG = Logger.getLogger(MattermostIntegrationAuthenticator.class); 20 | 21 | @Override 22 | public void authenticate(AuthenticationFlowContext context) { 23 | 24 | UserModel user = context.getUser(); 25 | String email = user.getEmail(); 26 | Map config = context.getAuthenticatorConfig().getConfig(); 27 | int mattermostId = 0; 28 | 29 | // Local user without email, e.g. admin, do nothing. 30 | if (email == null || email.trim().isEmpty()) { 31 | context.success(); 32 | return; 33 | } 34 | 35 | String gitlabToken = config.get(MattermostIntegrationAuthenticatorFactory.GITLAB_TOKEN); 36 | String gitlabURI = config.get(MattermostIntegrationAuthenticatorFactory.GITLAB_URI); 37 | 38 | try { 39 | JsonNode searchUserResponse = SimpleHttp.doGet( 40 | gitlabURI + "/api/v4/users?search=" + email, context.getSession()) 41 | .header("PRIVATE-TOKEN", gitlabToken) 42 | .asJson(); 43 | if (searchUserResponse.size() > 0) { 44 | mattermostId = searchUserResponse.get(0) 45 | .get("id").asInt(0); 46 | } else { 47 | GitlabCreateUserRequest createUserRequest = new GitlabCreateUserRequest(); 48 | createUserRequest.setEmail(email); 49 | createUserRequest.setName(user.getFirstName() + " " + user.getLastName()); 50 | createUserRequest.setUsername(user.getUsername()); 51 | JsonNode createUserResponse = SimpleHttp.doPost(gitlabURI + "/api/v4/users", context.getSession()) 52 | .header("PRIVATE-TOKEN", gitlabToken) 53 | .json(createUserRequest) 54 | .asJson(); 55 | if (createUserResponse != null) { 56 | mattermostId = createUserResponse.get("id").asInt(0); 57 | } 58 | } 59 | if (mattermostId > 0) { 60 | user.setSingleAttribute( 61 | "mattermostid", Integer.toString(mattermostId)); 62 | } 63 | } catch (IOException e) { 64 | LOG.error(e.getMessage()); 65 | } 66 | context.success(); 67 | } 68 | 69 | @Override 70 | public void action(AuthenticationFlowContext context) { 71 | } 72 | 73 | @Override 74 | public boolean requiresUser() { 75 | return true; 76 | } 77 | 78 | @Override 79 | public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { 80 | return true; 81 | } 82 | 83 | @Override 84 | public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) { 85 | } 86 | 87 | @Override 88 | public void close() { 89 | } 90 | 91 | static class GitlabCreateUserRequest { 92 | private String email; 93 | private String name; 94 | private String username; 95 | private boolean forceRandomPassword = true; 96 | 97 | public String getEmail() { 98 | return email; 99 | } 100 | 101 | public void setEmail(String email) { 102 | this.email = email; 103 | } 104 | 105 | public String getName() { 106 | return name; 107 | } 108 | 109 | public void setName(String name) { 110 | this.name = name; 111 | } 112 | 113 | public String getUsername() { 114 | return username; 115 | } 116 | 117 | public void setUsername(String username) { 118 | this.username = username; 119 | } 120 | 121 | @JsonProperty("force_random_password") 122 | public boolean getForceRandomPassword() { 123 | return forceRandomPassword; 124 | } 125 | 126 | @JsonProperty("force_random_password") 127 | public void setForceRandomPassword(boolean forceRandomPassword) { 128 | this.forceRandomPassword = forceRandomPassword; 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /themes/arenadata/login/resources/img/ad-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 35 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /themes/arenadata/login/theme.properties: -------------------------------------------------------------------------------- 1 | parent=base 2 | import=common/keycloak 3 | 4 | styles=css/login.css 5 | stylesCommon=web_modules/@patternfly/react-core/dist/styles/base.css web_modules/@patternfly/react-core/dist/styles/app.css node_modules/patternfly/dist/css/patternfly.min.css node_modules/patternfly/dist/css/patternfly-additions.min.css lib/pficon/pficon.css 6 | 7 | meta=viewport==width=device-width,initial-scale=1 8 | 9 | kcHtmlClass=login-pf 10 | kcLoginClass=login-pf-page 11 | 12 | # LINARO: not used 13 | #kcLogoLink=http://www.keycloak.org 14 | 15 | kcLogoClass=login-pf-brand 16 | 17 | kcContainerClass=container-fluid 18 | kcContentClass=col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3 19 | # LINARO: added 20 | kcContentWrapperClass=row 21 | 22 | kcHeaderClass=login-pf-page-header 23 | kcFeedbackAreaClass=col-md-12 24 | kcLocaleClass=col-xs-12 col-sm-1 25 | 26 | ## Locale 27 | kcLocaleMainClass=pf-c-dropdown 28 | kcLocaleListClass=pf-c-dropdown__menu pf-m-align-right 29 | kcLocaleItemClass=pf-c-dropdown__menu-item 30 | 31 | ## Alert 32 | kcAlertClass=pf-c-alert pf-m-inline 33 | kcAlertTitleClass=pf-c-alert__title kc-feedback-text 34 | 35 | kcFormAreaClass=col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2 36 | kcFormCardClass=card-pf 37 | 38 | ### Social providers 39 | kcFormSocialAccountListClass=pf-c-login__main-footer-links kc-social-links 40 | kcFormSocialAccountListGridClass=pf-l-grid kc-social-grid 41 | kcFormSocialAccountListButtonClass=pf-c-button pf-m-control pf-m-block kc-social-item kc-social-gray 42 | kcFormSocialAccountGridItem=pf-l-grid__item 43 | 44 | kcFormSocialAccountNameClass=kc-social-provider-name 45 | kcFormSocialAccountLinkClass=pf-c-login__main-footer-links-item-link 46 | kcFormSocialAccountSectionClass=kc-social-section kc-social-gray 47 | kcFormHeaderClass=login-pf-header 48 | 49 | kcFeedbackErrorIcon=fa fa-fw fa-exclamation-circle 50 | kcFeedbackWarningIcon=fa fa-fw fa-exclamation-triangle 51 | kcFeedbackSuccessIcon=fa fa-fw fa-check-circle 52 | kcFeedbackInfoIcon=fa fa-fw fa-info-circle 53 | 54 | kcResetFlowIcon=pficon pficon-arrow fa 55 | kcWebAuthnKeyIcon=pficon pficon-key 56 | 57 | kcFormClass=form-horizontal 58 | kcFormGroupClass=form-group 59 | kcFormGroupErrorClass=has-error 60 | kcLabelClass=pf-c-form__label pf-c-form__label-text 61 | kcLabelWrapperClass=col-xs-12 col-sm-12 col-md-12 col-lg-12 62 | kcInputClass=pf-c-form-control 63 | kcInputHelperTextBeforeClass=pf-c-form__helper-text pf-c-form__helper-text-before 64 | kcInputHelperTextAfterClass=pf-c-form__helper-text pf-c-form__helper-text-after 65 | kcInputClassRadio=pf-c-radio 66 | kcInputClassRadioInput=pf-c-radio__input 67 | kcInputClassRadioLabel=pf-c-radio__label 68 | kcInputClassCheckbox=pf-c-check 69 | kcInputClassCheckboxInput=pf-c-check__input 70 | kcInputClassCheckboxLabel=pf-c-check__label 71 | kcInputClassRadioCheckboxLabelDisabled=pf-m-disabled 72 | kcInputErrorMessageClass=pf-c-form__helper-text pf-m-error required kc-feedback-text 73 | kcInputWrapperClass=col-xs-12 col-sm-12 col-md-12 col-lg-12 74 | kcFormOptionsClass=col-xs-12 col-sm-12 col-md-12 col-lg-12 75 | kcFormButtonsClass=col-xs-12 col-sm-12 col-md-12 col-lg-12 76 | kcFormSettingClass=login-pf-settings 77 | kcTextareaClass=form-control 78 | kcSignUpClass=login-pf-signup 79 | 80 | 81 | kcInfoAreaClass=col-xs-12 col-sm-4 col-md-4 col-lg-5 details 82 | 83 | ### user-profile grouping 84 | kcFormGroupHeader=pf-c-form__group 85 | 86 | ##### css classes for form buttons 87 | # main class used for all buttons 88 | kcButtonClass=pf-c-button 89 | # classes defining priority of the button - primary or default (there is typically only one priority button for the form) 90 | kcButtonPrimaryClass=pf-m-primary 91 | kcButtonDefaultClass=btn-default 92 | # classes defining size of the button 93 | kcButtonLargeClass=btn-lg 94 | kcButtonBlockClass=pf-m-block 95 | 96 | ##### css classes for input 97 | kcInputLargeClass=input-lg 98 | 99 | ##### css classes for form accessability 100 | kcSrOnlyClass=sr-only 101 | 102 | ##### css classes for select-authenticator form 103 | kcSelectAuthListClass=pf-l-stack select-auth-container 104 | kcSelectAuthListItemClass=pf-l-stack__item select-auth-box-parent pf-l-split 105 | kcSelectAuthListItemIconClass=pf-l-split__item select-auth-box-icon 106 | kcSelectAuthListItemBodyClass=pf-l-split__item pf-l-stack 107 | kcSelectAuthListItemHeadingClass=pf-l-stack__item select-auth-box-headline pf-c-title 108 | kcSelectAuthListItemDescriptionClass=pf-l-stack__item select-auth-box-desc 109 | kcSelectAuthListItemFillClass=pf-l-split__item pf-m-fill 110 | kcSelectAuthListItemArrowClass=pf-l-split__item select-auth-box-arrow 111 | kcSelectAuthListItemArrowIconClass=fa fa-angle-right fa-lg 112 | 113 | ##### css classes for the authenticators 114 | kcAuthenticatorDefaultClass=fa list-view-pf-icon-lg 115 | kcAuthenticatorPasswordClass=fa fa-unlock list-view-pf-icon-lg 116 | kcAuthenticatorOTPClass=fa fa-mobile list-view-pf-icon-lg 117 | kcAuthenticatorWebAuthnClass=fa fa-key list-view-pf-icon-lg 118 | kcAuthenticatorWebAuthnPasswordlessClass=fa fa-key list-view-pf-icon-lg 119 | 120 | ##### css classes for the OTP Login Form 121 | kcLoginOTPListClass=pf-c-tile 122 | kcLoginOTPListInputClass=pf-c-tile__input 123 | kcLoginOTPListItemHeaderClass=pf-c-tile__header 124 | kcLoginOTPListItemIconBodyClass=pf-c-tile__icon 125 | kcLoginOTPListItemIconClass=fa fa-mobile 126 | kcLoginOTPListItemTitleClass=pf-c-tile__title 127 | 128 | ##### css classes for identity providers logos 129 | kcCommonLogoIdP=kc-social-provider-logo kc-social-gray 130 | 131 | ## Social 132 | kcLogoIdP-facebook=fa fa-facebook 133 | kcLogoIdP-google=fa fa-google 134 | kcLogoIdP-github=fa fa-github 135 | kcLogoIdP-linkedin=fa fa-linkedin 136 | kcLogoIdP-instagram=fa fa-instagram 137 | ## windows instead of microsoft - not included in PF4 138 | kcLogoIdP-microsoft=fa fa-windows 139 | kcLogoIdP-bitbucket=fa fa-bitbucket 140 | kcLogoIdP-gitlab=fa fa-gitlab 141 | kcLogoIdP-paypal=fa fa-paypal 142 | kcLogoIdP-stackoverflow=fa fa-stack-overflow 143 | kcLogoIdP-twitter=fa fa-twitter 144 | kcLogoIdP-openshift-v4=pf-icon pf-icon-openshift 145 | kcLogoIdP-openshift-v3=pf-icon pf-icon-openshift 146 | 147 | -------------------------------------------------------------------------------- /themes/arenadata/login/template.ftl: -------------------------------------------------------------------------------- 1 | <#macro registrationLayout bodyClass="" displayInfo=false displayMessage=true displayRequiredFields=false showAnotherWayIfPresent=true> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <#if properties.meta?has_content> 10 | <#list properties.meta?split(' ') as meta> 11 | 12 | 13 | 14 | ${msg("loginTitle",(realm.displayName!''))} 15 | 16 | <#if properties.stylesCommon?has_content> 17 | <#list properties.stylesCommon?split(' ') as style> 18 | 19 | 20 | 21 | <#if properties.styles?has_content> 22 | <#list properties.styles?split(' ') as style> 23 | 24 | 25 | 26 | <#if properties.scripts?has_content> 27 | <#list properties.scripts?split(' ') as script> 28 | 29 | 30 | 31 | <#if scripts??> 32 | <#list scripts as script> 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 |
41 |
42 | <#if realm.internationalizationEnabled && locale.supported?size gt 1> 43 |
44 |
45 |
46 | ${locale.current} 47 |
    48 | <#list locale.supported as l> 49 |
  • 50 | ${l.label} 51 |
  • 52 | 53 |
54 |
55 |
56 |
57 | 58 | <#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())> 59 | <#if displayRequiredFields> 60 |
61 |
62 | * ${msg("requiredFields")} 63 |
64 |
65 | 66 |

<#nested "header">

67 |
68 |
69 | <#else> 70 | 71 |

<#nested "header">

72 | 73 | <#else> 74 | <#if displayRequiredFields> 75 |
76 |
77 | * ${msg("requiredFields")} 78 |
79 |
80 | <#nested "show-username"> 81 |
82 | 83 | 84 | 88 | 89 |
90 |
91 |
92 | <#else> 93 | <#nested "show-username"> 94 |
95 | 96 | 97 | 101 | 102 |
103 | 104 | 105 |
106 |
107 |
108 | 109 | <#-- App-initiated actions should not see warning messages about the need to complete the action --> 110 | <#-- during login. --> 111 | <#if displayMessage && message?has_content && (message.type != 'warning' || !isAppInitiatedAction??)> 112 |
113 |
114 | <#if message.type = 'success'> 115 | <#if message.type = 'warning'> 116 | <#if message.type = 'error'> 117 | <#if message.type = 'info'> 118 |
119 | ${kcSanitize(message.summary)?no_esc} 120 |
121 | 122 | 123 | <#nested "form"> 124 | 125 | <#if auth?has_content && auth.showTryAnotherWayLink() && showAnotherWayIfPresent> 126 |
127 |
128 | 129 | ${msg("doTryAnotherWay")} 131 |
132 |
133 | 134 | 135 | <#if displayInfo> 136 |
137 |
138 | <#nested "info"> 139 |
140 |
141 | 142 |
143 |
144 | 145 |
146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /themes/arenadata/login/messages/messages_en.properties: -------------------------------------------------------------------------------- 1 | doLogIn=Log in 2 | doRegister=Register 3 | doCancel=Cancel 4 | doSubmit=Submit 5 | doBack=Back 6 | doYes=Yes 7 | doNo=No 8 | doContinue=Continue 9 | doIgnore=Ignore 10 | doAccept=Accept 11 | doDecline=Decline 12 | doForgotPassword=Forgot Password? 13 | doClickHere=Click here 14 | doImpersonate=Impersonate 15 | doTryAgain=Try again 16 | doTryAnotherWay=Try Another Way 17 | doConfirmDelete=Confirm deletion 18 | errorDeletingAccount=Error happened while deleting account 19 | deletingAccountForbidden=You do not have enough permissions to delete your own account, contact admin. 20 | kerberosNotConfigured=Kerberos Not Configured 21 | kerberosNotConfiguredTitle=Kerberos Not Configured 22 | bypassKerberosDetail=Either you are not logged in by Kerberos or your browser is not set up for Kerberos login. Please click continue to login in through other means 23 | kerberosNotSetUp=Kerberos is not set up. You cannot login. 24 | registerTitle=Register 25 | loginAccountTitle=Welcome. Please Login. 26 | loginTitle=Welcome. Please Login. 27 | loginTitleHtml={0} 28 | impersonateTitle={0} Impersonate User 29 | impersonateTitleHtml={0} Impersonate User 30 | realmChoice=Realm 31 | unknownUser=Unknown user 32 | loginTotpTitle=Mobile Authenticator Setup 33 | loginProfileTitle=Update Account Information 34 | loginIdpReviewProfileTitle=Update Account Information 35 | loginTimeout=Your login attempt timed out. Login will start from the beginning. 36 | oauthGrantTitle=Grant Access to {0} 37 | oauthGrantTitleHtml={0} 38 | oauthGrantInformation=Make sure you trust {0} by learning how {0} will handle your data. 39 | oauthGrantReview=You could review the 40 | oauthGrantTos=terms of service. 41 | oauthGrantPolicy=privacy policy. 42 | errorTitle=We are sorry... 43 | errorTitleHtml=We are sorry ... 44 | emailVerifyTitle=Email verification 45 | emailForgotTitle=Forgot Your Password? 46 | updatePasswordTitle=Update password 47 | codeSuccessTitle=Success code 48 | codeErrorTitle=Error code\: {0} 49 | displayUnsupported=Requested display type unsupported 50 | browserRequired=Browser required to login 51 | browserContinue=Browser required to complete login 52 | browserContinuePrompt=Open browser and continue login? [y/n]: 53 | browserContinueAnswer=y 54 | 55 | 56 | termsTitle=Terms and Conditions 57 | termsText=

Terms and conditions to be defined

58 | termsPlainText=Terms and conditions to be defined. 59 | 60 | recaptchaFailed=Invalid Recaptcha 61 | recaptchaNotConfigured=Recaptcha is required, but not configured 62 | consentDenied=Consent denied. 63 | 64 | noAccount=New user? 65 | username=Username 66 | usernameOrEmail=Email 67 | firstName=First name 68 | givenName=Given name 69 | fullName=Full name 70 | lastName=Last name 71 | familyName=Family name 72 | email=Email 73 | password=Password 74 | passwordConfirm=Confirm password 75 | passwordNew=New Password 76 | passwordNewConfirm=New Password confirmation 77 | rememberMe=Remember me 78 | authenticatorCode=One-time code 79 | address=Address 80 | street=Street 81 | locality=City or Locality 82 | region=State, Province, or Region 83 | postal_code=Zip or Postal code 84 | country=Country 85 | emailVerified=Email verified 86 | website=Web page 87 | phoneNumber=Phone number 88 | phoneNumberVerified=Phone number verified 89 | gender=Gender 90 | birthday=Birthdate 91 | zoneinfo=Time zone 92 | gssDelegationCredential=GSS Delegation Credential 93 | logoutOtherSessions=Sign out from other devices 94 | 95 | profileScopeConsentText=User profile 96 | emailScopeConsentText=Email address 97 | addressScopeConsentText=Address 98 | phoneScopeConsentText=Phone number 99 | offlineAccessScopeConsentText=Offline Access 100 | samlRoleListScopeConsentText=My Roles 101 | rolesScopeConsentText=User roles 102 | 103 | restartLoginTooltip=Restart login 104 | 105 | loginTotpIntro=You need to set up a One Time Password generator to access this account 106 | loginTotpStep1=Install one of the following applications on your mobile: 107 | loginTotpStep2=Open the application and scan the barcode: 108 | loginTotpStep3=Enter the one-time code provided by the application and click Submit to finish the setup. 109 | loginTotpStep3DeviceName=Provide a Device Name to help you manage your OTP devices. 110 | loginTotpManualStep2=Open the application and enter the key: 111 | loginTotpManualStep3=Use the following configuration values if the application allows setting them: 112 | loginTotpUnableToScan=Unable to scan? 113 | loginTotpScanBarcode=Scan barcode? 114 | loginCredential=Credential 115 | loginOtpOneTime=One-time code 116 | loginTotpType=Type 117 | loginTotpAlgorithm=Algorithm 118 | loginTotpDigits=Digits 119 | loginTotpInterval=Interval 120 | loginTotpCounter=Counter 121 | loginTotpDeviceName=Device Name 122 | 123 | loginTotp.totp=Time-based 124 | loginTotp.hotp=Counter-based 125 | 126 | loginChooseAuthenticator=Select login method 127 | 128 | oauthGrantRequest=Do you grant these access privileges? 129 | inResource=in 130 | 131 | oauth2DeviceVerificationTitle=Device Login 132 | verifyOAuth2DeviceUserCode=Enter the code provided by your device and click Submit 133 | oauth2DeviceInvalidUserCodeMessage=Invalid code, please try again. 134 | oauth2DeviceExpiredUserCodeMessage=The code has expired. Please go back to your device and try connecting again. 135 | oauth2DeviceVerificationCompleteHeader=Device Login Successful 136 | oauth2DeviceVerificationCompleteMessage=You may close this browser window and go back to your device. 137 | oauth2DeviceVerificationFailedHeader=Device Login Failed 138 | oauth2DeviceVerificationFailedMessage=You may close this browser window and go back to your device and try connecting again. 139 | oauth2DeviceConsentDeniedMessage=Consent denied for connecting the device. 140 | oauth2DeviceAuthorizationGrantDisabledMessage=Client is not allowed to initiate OAuth 2.0 Device Authorization Grant. The flow is disabled for the client. 141 | 142 | emailVerifyInstruction1=An email with instructions to verify your email address has been sent to you. 143 | emailVerifyInstruction2=Haven''t received a verification code in your email? 144 | emailVerifyInstruction3=to re-send the email. 145 | 146 | emailLinkIdpTitle=Link {0} 147 | emailLinkIdp1=An email with instructions to link {0} account {1} with your {2} account has been sent to you. 148 | emailLinkIdp2=Haven''t received a verification code in your email? 149 | emailLinkIdp3=to re-send the email. 150 | emailLinkIdp4=If you already verified the email in different browser 151 | emailLinkIdp5=to continue. 152 | 153 | backToLogin=« Back to Login 154 | 155 | emailInstruction=Enter your username or email address and we will send you instructions on how to create a new password. 156 | emailInstructionUsername=Enter your username and we will send you instructions on how to create a new password. 157 | 158 | copyCodeInstruction=Please copy this code and paste it into your application: 159 | 160 | pageExpiredTitle=Page has expired 161 | pageExpiredMsg1=To restart the login process 162 | pageExpiredMsg2=To continue the login process 163 | 164 | personalInfo=Personal Info: 165 | role_admin=Admin 166 | role_realm-admin=Realm Admin 167 | role_create-realm=Create realm 168 | role_create-client=Create client 169 | role_view-realm=View realm 170 | role_view-users=View users 171 | role_view-applications=View applications 172 | role_view-clients=View clients 173 | role_view-events=View events 174 | role_view-identity-providers=View identity providers 175 | role_manage-realm=Manage realm 176 | role_manage-users=Manage users 177 | role_manage-applications=Manage applications 178 | role_manage-identity-providers=Manage identity providers 179 | role_manage-clients=Manage clients 180 | role_manage-events=Manage events 181 | role_view-profile=View profile 182 | role_manage-account=Manage account 183 | role_manage-account-links=Manage account links 184 | role_read-token=Read token 185 | role_offline-access=Offline access 186 | client_account=Account 187 | client_account-console=Account Console 188 | client_security-admin-console=Security Admin Console 189 | client_admin-cli=Admin CLI 190 | client_realm-management=Realm Management 191 | client_broker=Broker 192 | 193 | requiredFields=Required fields 194 | 195 | invalidUserMessage=Invalid username or password. 196 | invalidUsernameMessage=Invalid username. 197 | invalidUsernameOrEmailMessage=Invalid username or email. 198 | invalidPasswordMessage=Invalid password. 199 | invalidEmailMessage=Invalid email address. 200 | accountDisabledMessage=Account is disabled, contact your administrator. 201 | accountTemporarilyDisabledMessage=Account is temporarily disabled; contact your administrator or retry later. 202 | expiredCodeMessage=Login timeout. Please sign in again. 203 | expiredActionMessage=Action expired. Please continue with login now. 204 | expiredActionTokenNoSessionMessage=Action expired. 205 | expiredActionTokenSessionExistsMessage=Action expired. Please start again. 206 | 207 | missingFirstNameMessage=Please specify first name. 208 | missingLastNameMessage=Please specify last name. 209 | missingEmailMessage=Please specify email. 210 | missingUsernameMessage=Please specify username. 211 | missingPasswordMessage=Please specify password. 212 | missingTotpMessage=Please specify authenticator code. 213 | missingTotpDeviceNameMessage=Please specify device name. 214 | notMatchPasswordMessage=Passwords don''t match. 215 | 216 | error-invalid-value=Invalid value. 217 | error-invalid-blank=Please specify value. 218 | error-empty=Please specify value. 219 | error-invalid-length=Length must be between {1} and {2}. 220 | error-invalid-length-too-short=Minimal length is {1}. 221 | error-invalid-length-too-long=Maximal length is {2}. 222 | error-invalid-email=Invalid email address. 223 | error-invalid-number=Invalid number. 224 | error-number-out-of-range=Number must be between {1} and {2}. 225 | error-number-out-of-range-too-small=Number must have minimal value of {1}. 226 | error-number-out-of-range-too-big=Number must have maximal value of {2}. 227 | error-pattern-no-match=Invalid value. 228 | error-invalid-uri=Invalid URL. 229 | error-invalid-uri-scheme=Invalid URL scheme. 230 | error-invalid-uri-fragment=Invalid URL fragment. 231 | error-user-attribute-required=Please specify this field. 232 | error-invalid-date=Invalid date. 233 | error-user-attribute-read-only=This field is read only. 234 | error-username-invalid-character=Value contains invalid character. 235 | error-person-name-invalid-character=Value contains invalid character. 236 | 237 | invalidPasswordExistingMessage=Invalid existing password. 238 | invalidPasswordBlacklistedMessage=Invalid password: password is blacklisted. 239 | invalidPasswordConfirmMessage=Password confirmation doesn''t match. 240 | invalidTotpMessage=Invalid authenticator code. 241 | 242 | usernameExistsMessage=Username already exists. 243 | emailExistsMessage=Email already exists. 244 | 245 | federatedIdentityExistsMessage=User with {0} {1} already exists. Please login to account management to link the account. 246 | federatedIdentityUnavailableMessage=User {0} authenticated with identity provider {1} does not exists. Please contact your administrator. 247 | 248 | confirmLinkIdpTitle=Account already exists 249 | federatedIdentityConfirmLinkMessage=User with {0} {1} already exists. How do you want to continue? 250 | federatedIdentityConfirmReauthenticateMessage=Authenticate to link your account with {0} 251 | nestedFirstBrokerFlowMessage=The {0} user {1} is not linked to any known user. 252 | confirmLinkIdpReviewProfile=Review profile 253 | confirmLinkIdpContinue=Add to existing account 254 | 255 | configureTotpMessage=You need to set up Mobile Authenticator to activate your account. 256 | updateProfileMessage=You need to update your user profile to activate your account. 257 | updatePasswordMessage=You need to change your password to activate your account. 258 | resetPasswordMessage=You need to change your password. 259 | verifyEmailMessage=You need to verify your email address to activate your account. 260 | linkIdpMessage=You need to verify your email address to link your account with {0}. 261 | 262 | emailSentMessage=You should receive an email shortly with further instructions. 263 | emailSendErrorMessage=Failed to send email, please try again later. 264 | 265 | accountUpdatedMessage=Your account has been updated. 266 | accountPasswordUpdatedMessage=Your password has been updated. 267 | 268 | delegationCompleteHeader=Login Successful 269 | delegationCompleteMessage=You may close this browser window and go back to your console application. 270 | delegationFailedHeader=Login Failed 271 | delegationFailedMessage=You may close this browser window and go back to your console application and try logging in again. 272 | 273 | noAccessMessage=No access 274 | 275 | invalidPasswordMinLengthMessage=Invalid password: minimum length {0}. 276 | invalidPasswordMaxLengthMessage=Invalid password: maximum length {0}. 277 | invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits. 278 | invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters. 279 | invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least {0} upper case characters. 280 | invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters. 281 | invalidPasswordNotUsernameMessage=Invalid password: must not be equal to the username. 282 | invalidPasswordNotEmailMessage=Invalid password: must not be equal to the email. 283 | invalidPasswordRegexPatternMessage=Invalid password: fails to match regex pattern(s). 284 | invalidPasswordHistoryMessage=Invalid password: must not be equal to any of last {0} passwords. 285 | invalidPasswordGenericMessage=Invalid password: new password doesn''t match password policies. 286 | 287 | failedToProcessResponseMessage=Failed to process response 288 | httpsRequiredMessage=HTTPS required 289 | realmNotEnabledMessage=Realm not enabled 290 | invalidRequestMessage=Invalid Request 291 | failedLogout=Logout failed 292 | unknownLoginRequesterMessage=Unknown login requester 293 | loginRequesterNotEnabledMessage=Login requester not enabled 294 | bearerOnlyMessage=Bearer-only applications are not allowed to initiate browser login 295 | standardFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client. 296 | implicitFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client. 297 | invalidRedirectUriMessage=Invalid redirect uri 298 | unsupportedNameIdFormatMessage=Unsupported NameIDFormat 299 | invalidRequesterMessage=Invalid requester 300 | registrationNotAllowedMessage=Registration not allowed 301 | resetCredentialNotAllowedMessage=Reset Credential not allowed 302 | 303 | permissionNotApprovedMessage=Permission not approved. 304 | noRelayStateInResponseMessage=No relay state in response from identity provider. 305 | insufficientPermissionMessage=Insufficient permissions to link identities. 306 | couldNotProceedWithAuthenticationRequestMessage=Could not proceed with authentication request to identity provider. 307 | couldNotObtainTokenMessage=Could not obtain token from identity provider. 308 | unexpectedErrorRetrievingTokenMessage=Unexpected error when retrieving token from identity provider. 309 | unexpectedErrorHandlingResponseMessage=Unexpected error when handling response from identity provider. 310 | identityProviderAuthenticationFailedMessage=Authentication failed. Could not authenticate with identity provider. 311 | couldNotSendAuthenticationRequestMessage=Could not send authentication request to identity provider. 312 | unexpectedErrorHandlingRequestMessage=Unexpected error when handling authentication request to identity provider. 313 | invalidAccessCodeMessage=Invalid access code. 314 | sessionNotActiveMessage=Session not active. 315 | invalidCodeMessage=An error occurred, please login again through your application. 316 | cookieNotFoundMessage=Cookie not found. Please make sure cookies are enabled in your browser. 317 | identityProviderUnexpectedErrorMessage=Unexpected error when authenticating with identity provider 318 | identityProviderMissingStateMessage=Missing state parameter in response from identity provider. 319 | identityProviderNotFoundMessage=Could not find an identity provider with the identifier. 320 | identityProviderLinkSuccess=You successfully verified your email. Please go back to your original browser and continue there with the login. 321 | staleCodeMessage=This page is no longer valid, please go back to your application and sign in again 322 | realmSupportsNoCredentialsMessage=Realm does not support any credential type. 323 | credentialSetupRequired=Cannot login, credential setup required. 324 | identityProviderNotUniqueMessage=Realm supports multiple identity providers. Could not determine which identity provider should be used to authenticate with. 325 | emailVerifiedMessage=Your email address has been verified. 326 | staleEmailVerificationLink=The link you clicked is an old stale link and is no longer valid. Maybe you have already verified your email. 327 | identityProviderAlreadyLinkedMessage=Federated identity returned by {0} is already linked to another user. 328 | confirmAccountLinking=Confirm linking the account {0} of identity provider {1} with your account. 329 | confirmEmailAddressVerification=Confirm validity of e-mail address {0}. 330 | confirmExecutionOfActions=Perform the following action(s) 331 | 332 | locale_ca=Catal\u00E0 333 | locale_cs=\u010Ce\u0161tina 334 | locale_da=Dansk 335 | locale_de=Deutsch 336 | locale_en=English 337 | locale_es=Espa\u00F1ol 338 | locale_fr=Fran\u00E7ais 339 | locale_hu=Magyar 340 | locale_it=Italiano 341 | locale_ja=\u65E5\u672C\u8A9E 342 | locale_lt=Lietuvi\u0173 343 | locale_nl=Nederlands 344 | locale_no=Norsk 345 | locale_pl=Polski 346 | locale_pt_BR=Portugu\u00EAs (Brasil) 347 | locale_pt-BR=Portugu\u00EAs (Brasil) 348 | locale_ru=\u0420\u0443\u0441\u0441\u043A\u0438\u0439 349 | locale_sk=Sloven\u010Dina 350 | locale_sv=Svenska 351 | locale_tr=T\u00FCrk\u00E7e 352 | locale_zh-CN=\u4E2D\u6587\u7B80\u4F53 353 | 354 | backToApplication=« Back to Application 355 | missingParameterMessage=Missing parameters\: {0} 356 | clientNotFoundMessage=Client not found. 357 | clientDisabledMessage=Client disabled. 358 | invalidParameterMessage=Invalid parameter\: {0} 359 | alreadyLoggedIn=You are already logged in. 360 | differentUserAuthenticated=You are already authenticated as different user ''{0}'' in this session. Please sign out first. 361 | brokerLinkingSessionExpired=Requested broker account linking, but current session is no longer valid. 362 | proceedWithAction=» Click here to proceed 363 | 364 | requiredAction.CONFIGURE_TOTP=Configure OTP 365 | requiredAction.terms_and_conditions=Terms and Conditions 366 | requiredAction.UPDATE_PASSWORD=Update Password 367 | requiredAction.UPDATE_PROFILE=Update Profile 368 | requiredAction.VERIFY_EMAIL=Verify Email 369 | 370 | doX509Login=You will be logged in as\: 371 | clientCertificate=X509 client certificate\: 372 | noCertificate=[No Certificate] 373 | 374 | 375 | pageNotFound=Page not found 376 | internalServerError=An internal server error has occurred 377 | 378 | console-username=Username: 379 | console-password=Password: 380 | console-otp=One Time Password: 381 | console-new-password=New Password: 382 | console-confirm-password=Confirm Password: 383 | console-update-password=Update of your password is required. 384 | console-verify-email=You need to verify your email address. We sent an email to {0} that contains a verification code. Please enter this code into the input below. 385 | console-email-code=Email Code: 386 | console-accept-terms=Accept Terms? [y/n]: 387 | console-accept=y 388 | 389 | # Openshift messages 390 | openshift.scope.user_info=User information 391 | openshift.scope.user_check-access=User access information 392 | openshift.scope.user_full=Full Access 393 | openshift.scope.list-projects=List projects 394 | 395 | # SAML authentication 396 | saml.post-form.title=Authentication Redirect 397 | saml.post-form.message=Redirecting, please wait. 398 | saml.post-form.js-disabled=JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue. 399 | saml.artifactResolutionServiceInvalidResponse=Unable to resolve artifact. 400 | 401 | #authenticators 402 | otp-display-name=Authenticator Application 403 | otp-help-text=Enter a verification code from authenticator application. 404 | password-display-name=Password 405 | password-help-text=Sign in by entering your password. 406 | auth-username-form-display-name=Username 407 | auth-username-form-help-text=Start sign in by entering your username 408 | auth-username-password-form-display-name=Username and password 409 | auth-username-password-form-help-text=Sign in by entering your username and password. 410 | 411 | # WebAuthn 412 | webauthn-display-name=Security Key 413 | webauthn-help-text=Use your security key to sign in. 414 | webauthn-passwordless-display-name=Security Key 415 | webauthn-passwordless-help-text=Use your security key for passwordless sign in. 416 | webauthn-login-title=Security Key login 417 | webauthn-registration-title=Security Key Registration 418 | webauthn-available-authenticators=Available authenticators 419 | webauthn-unsupported-browser-text=WebAuthn is not supported by this browser. Try another one or contact your administrator. 420 | webauthn-doAuthenticate=Sign in with Security Key 421 | 422 | # WebAuthn Error 423 | webauthn-error-title=Security Key Error 424 | webauthn-error-registration=Failed to register your Security key.
{0} 425 | webauthn-error-api-get=Failed to authenticate by the Security key.
{0} 426 | webauthn-error-different-user=First authenticated user is not the one authenticated by the Security key. 427 | webauthn-error-auth-verification=Security key authentication result is invalid.
{0} 428 | webauthn-error-register-verification=Security key registration result is invalid.
{0} 429 | webauthn-error-user-not-found=Unknown user authenticated by the Security key. 430 | 431 | # Identity provider 432 | identity-provider-redirector=Connect with another Identity Provider 433 | identity-provider-login-label=Or sign in with 434 | 435 | finalDeletionConfirmation=If you delete your account, it cannot be restored. To keep your account, click Cancel. 436 | irreversibleAction=This action is irreversible 437 | deleteAccountConfirm=Delete account confirmation 438 | 439 | deletingImplies=Deleting your account implies: 440 | errasingData=Erasing all your data 441 | loggingOutImmediately=Logging you out immediately 442 | accountUnusable=Any subsequent use of the application will not be possible with this account 443 | userDeletedSuccessfully=User deleted successfully 444 | 445 | access-denied=Access denied 446 | 447 | frontchannel-logout.title=Logging out 448 | frontchannel-logout.message=You are logging out from following apps 449 | -------------------------------------------------------------------------------- /themes/arenadata/login/resources/css/login.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --pf-global--primary-color--100: #00754a; 3 | --pf-global--primary-color--200: #00754a; 4 | --pf-global--link--Color--hover: #00754a; 5 | --pf-global--link--Color: #00754a; 6 | } 7 | 8 | /* Patternfly CSS places a "bg-login.jpg" as the background on this ".login-pf" class. 9 | This clashes with the "keycloak-bg.png' background defined on the body below. 10 | Therefore the Patternfly background must be set to none. */ 11 | .login-pf { 12 | background: none; 13 | } 14 | 15 | .login-pf body { 16 | background: url("../img/bg.png"); 17 | background-color: #999999; 18 | height: 100%; 19 | display: flex; 20 | align-items: center; 21 | justify-content: center; 22 | } 23 | 24 | /*IE compatibility*/ 25 | .pf-c-form-control { 26 | font-size: 14px; 27 | font-size: var(--pf-global--FontSize--sm); 28 | border-width: 1px; 29 | border-width: var(--pf-global--BorderWidth--sm);; 30 | border-color: #EDEDED #EDEDED #8A8D90 #EDEDED; 31 | border-color: var(--pf-global--BorderColor--300) var(--pf-global--BorderColor--300) var(--pf-global--BorderColor--200) var(--pf-global--BorderColor--300); 32 | background-color: #FFFFFF; 33 | background-color: var(--pf-global--BackgroundColor--100); 34 | height: 36px; 35 | height: calc(var(--pf-c-form-control--FontSize) * var(--pf-c-form-control--LineHeight) + var(--pf-c-form-control--BorderWidth) * 2 + var(--pf-c-form-control--PaddingTop) + var(--pf-c-form-control--PaddingBottom)); 36 | padding: 5px 0.5rem; 37 | padding: var(--pf-c-form-control--PaddingTop) var(--pf-c-form-control--PaddingRight) var(--pf-c-form-control--PaddingBottom) var(--pf-c-form-control--PaddingLeft); 38 | } 39 | 40 | textarea.pf-c-form-control { 41 | height: auto; 42 | } 43 | 44 | .pf-c-form-control:hover, .pf-c-form-control:focus { 45 | border-bottom-color: #00754a; 46 | border-bottom-width: 2px; 47 | border-bottom-width: var(--pf-global--BorderWidth--md); 48 | } 49 | 50 | .pf-c-form-control[aria-invalid="true"] { 51 | border-bottom-color: #C9190B; 52 | border-bottom-color: var(--pf-global--danger-color--100); 53 | border-bottom-width: 2px; 54 | border-bottom-width: var(--pf-global--BorderWidth--md); 55 | } 56 | 57 | .pf-c-check__label, .pf-c-radio__label { 58 | font-size: 14px; 59 | font-size: var(--pf-global--FontSize--sm); 60 | } 61 | 62 | .pf-c-alert.pf-m-inline { 63 | margin-bottom: 0.5rem; /* default - IE compatibility */ 64 | margin-bottom: var(--pf-global--spacer--sm); 65 | padding: 0.25rem; 66 | padding: var(--pf-global--spacer--xs); 67 | border: solid #ededed; 68 | border: solid var(--pf-global--BorderColor--300); 69 | border-width: 1px; 70 | border-width: var(--pf-c-alert--m-inline--BorderTopWidth) var(--pf-c-alert--m-inline--BorderRightWidth) var(--pf-c-alert--m-inline--BorderBottomWidth) var(--pf-c-alert--m-inline--BorderLeftWidth); 71 | display: -ms-flexbox; 72 | display: grid; 73 | -ms-grid-columns: max-content 1fr max-content; 74 | grid-template-columns:max-content 1fr max-content; 75 | grid-template-columns: var(--pf-c-alert--grid-template-columns); 76 | grid-template-rows: 1fr auto; 77 | grid-template-rows: var(--pf-c-alert--grid-template-rows); 78 | } 79 | 80 | .pf-c-alert.pf-m-inline::before { 81 | position: absolute; 82 | top: -1px; 83 | top: var(--pf-c-alert--m-inline--before--Top); 84 | bottom: -1px; 85 | bottom: var(--pf-c-alert--m-inline--before--Bottom); 86 | left: 0; 87 | width: 3px; 88 | width: var(--pf-c-alert--m-inline--before--Width); 89 | content: ""; 90 | background-color: #FFFFFF; 91 | background-color: var(--pf-global--BackgroundColor--100); 92 | } 93 | 94 | .pf-c-alert.pf-m-inline.pf-m-success::before { 95 | background-color: #00754a; 96 | background-color: var(--pf-global--success-color--100); 97 | } 98 | 99 | .pf-c-alert.pf-m-inline.pf-m-danger::before { 100 | background-color: #C9190B; 101 | background-color: var(--pf-global--danger-color--100); 102 | } 103 | 104 | .pf-c-alert.pf-m-inline.pf-m-warning::before { 105 | background-color: #F0AB00; 106 | background-color: var(--pf-global--warning-color--100); 107 | } 108 | 109 | .pf-c-alert.pf-m-inline .pf-c-alert__icon { 110 | padding: 1rem 0.5rem 1rem 1rem; 111 | padding: var(--pf-c-alert--m-inline__icon--PaddingTop) var(--pf-c-alert--m-inline__icon--PaddingRight) var(--pf-c-alert--m-inline__icon--PaddingBottom) var(--pf-c-alert--m-inline__icon--PaddingLeft); 112 | font-size: 16px; 113 | font-size: var(--pf-c-alert--m-inline__icon--FontSize); 114 | } 115 | 116 | .pf-c-alert.pf-m-success .pf-c-alert__icon { 117 | color: #00754a; 118 | color: var(--pf-global--success-color--100); 119 | } 120 | 121 | .pf-c-alert.pf-m-success .pf-c-alert__title { 122 | color: #00754a; 123 | color: var(--pf-global--success-color--200); 124 | } 125 | 126 | .pf-c-alert.pf-m-danger .pf-c-alert__icon { 127 | color: #C9190B; 128 | color: var(--pf-global--danger-color--100); 129 | } 130 | 131 | .pf-c-alert.pf-m-danger .pf-c-alert__title { 132 | color: #A30000; 133 | color: var(--pf-global--danger-color--200); 134 | } 135 | 136 | .pf-c-alert.pf-m-warning .pf-c-alert__icon { 137 | color: #F0AB00; 138 | color: var(--pf-global--warning-color--100); 139 | } 140 | 141 | .pf-c-alert.pf-m-warning .pf-c-alert__title { 142 | color: #795600; 143 | color: var(--pf-global--warning-color--200); 144 | } 145 | 146 | .pf-c-alert__title { 147 | font-size: 14px; /* default - IE compatibility */ 148 | font-size: var(--pf-global--FontSize--sm); 149 | padding: 5px 8px; 150 | padding: var(--pf-c-alert__title--PaddingTop) var(--pf-c-alert__title--PaddingRight) var(--pf-c-alert__title--PaddingBottom) var(--pf-c-alert__title--PaddingLeft); 151 | } 152 | 153 | .pf-c-button { 154 | padding:0.375rem 1rem; 155 | padding: var(--pf-global--spacer--form-element) var(--pf-global--spacer--md); 156 | border-color: #00754a; 157 | } 158 | 159 | /* default - IE compatibility */ 160 | .pf-m-primary { 161 | color: #FFFFFF; 162 | background-color: #00754a; 163 | background-color: var(--pf-global--primary-color--100); 164 | } 165 | 166 | /* default - IE compatibility */ 167 | .pf-m-primary:hover { 168 | background-color: #00754a; 169 | background-color: var(--pf-global--primary-color--200); 170 | } 171 | 172 | /* default - IE compatibility */ 173 | .pf-c-button.pf-m-control { 174 | border: solid 1px #00754a !important; 175 | transition: background-color 0.2s; 176 | } 177 | .pf-c-button.pf-m-control:hover { 178 | color: white; 179 | background: #00754a; 180 | } 181 | .pf-c-button.pf-m-control:hover > * { 182 | color: white; 183 | } 184 | .pf-c-button.pf-m-control::after { 185 | display: none !important; 186 | } 187 | /*End of IE compatibility*/ 188 | h1#kc-page-title { 189 | margin-top: 10px; 190 | } 191 | 192 | #kc-locale ul { 193 | background-color: #FFF; 194 | background-color: var(--pf-global--BackgroundColor--100); 195 | display: none; 196 | top: 20px; 197 | min-width: 100px; 198 | padding: 0; 199 | } 200 | 201 | #kc-locale-dropdown{ 202 | display: inline-block; 203 | } 204 | 205 | #kc-locale-dropdown:hover ul { 206 | display:block; 207 | } 208 | 209 | /* IE compatibility */ 210 | #kc-locale-dropdown a { 211 | color: #6A6E73; 212 | color: var(--pf-global--Color--200); 213 | text-align: right; 214 | font-size: 14px; 215 | font-size: var(--pf-global--FontSize--sm); 216 | } 217 | 218 | /* IE compatibility */ 219 | a#kc-current-locale-link::after { 220 | content: "\2c5"; 221 | margin-left: 4px; 222 | margin-left: var(--pf-global--spacer--xs) 223 | } 224 | 225 | .login-pf .container { 226 | padding-top: 40px; 227 | } 228 | 229 | .login-pf a:hover { 230 | color: #00754a; 231 | } 232 | 233 | #kc-logo { 234 | width: 100%; 235 | } 236 | 237 | .ad-logo { 238 | text-align:center; 239 | margin-bottom: 24px; 240 | } 241 | 242 | div.kc-logo-text { 243 | background-image: url(../img/keycloak-logo-text.png); 244 | background-repeat: no-repeat; 245 | background-size: contain; 246 | background-position: center center; 247 | color: #00754a; 248 | height: 63px; 249 | width: 300px; 250 | margin: 0 auto; 251 | } 252 | 253 | div.kc-logo-text span { 254 | display: none; 255 | } 256 | 257 | #kc-header { 258 | color: #ededed; 259 | overflow: visible; 260 | white-space: nowrap; 261 | } 262 | 263 | #kc-header-wrapper { 264 | font-size: 29px; 265 | text-transform: uppercase; 266 | letter-spacing: 3px; 267 | line-height: 1.2em; 268 | padding: 62px 10px 20px; 269 | white-space: normal; 270 | } 271 | 272 | #kc-content { 273 | width: 100%; 274 | } 275 | 276 | #kc-attempted-username { 277 | font-size: 20px; 278 | font-family: inherit; 279 | font-weight: normal; 280 | padding-right: 10px; 281 | } 282 | 283 | #kc-username { 284 | text-align: center; 285 | margin-bottom:-10px; 286 | } 287 | 288 | #kc-webauthn-settings-form { 289 | padding-top: 8px; 290 | } 291 | 292 | #kc-content-wrapper { 293 | margin-top: 20px; 294 | } 295 | 296 | #kc-form-wrapper { 297 | margin-top: 10px; 298 | } 299 | 300 | #kc-info { 301 | margin: 20px -40px -30px; 302 | } 303 | 304 | #kc-info-wrapper { 305 | font-size: 13px; 306 | padding: 15px 35px; 307 | background-color: #F0F0F0; 308 | } 309 | 310 | #kc-form-options span { 311 | display: block; 312 | } 313 | 314 | #kc-form-options .checkbox { 315 | margin-top: 0; 316 | color: #72767b; 317 | } 318 | 319 | #kc-terms-text { 320 | margin-bottom: 20px; 321 | } 322 | 323 | #kc-registration { 324 | margin-bottom: 0; 325 | } 326 | 327 | /* TOTP */ 328 | 329 | .subtitle { 330 | text-align: right; 331 | margin-top: 30px; 332 | color: #909090; 333 | } 334 | 335 | .required { 336 | color: #A30000; /* default - IE compatibility */ 337 | color: var(--pf-global--danger-color--200); 338 | } 339 | 340 | ol#kc-totp-settings { 341 | margin: 0; 342 | padding-left: 20px; 343 | } 344 | 345 | ul#kc-totp-supported-apps { 346 | margin-bottom: 10px; 347 | } 348 | 349 | #kc-totp-secret-qr-code { 350 | max-width:150px; 351 | max-height:150px; 352 | } 353 | 354 | #kc-totp-secret-key { 355 | background-color: #fff; 356 | color: #333333; 357 | font-size: 16px; 358 | padding: 10px 0; 359 | } 360 | 361 | /* OAuth */ 362 | 363 | #kc-oauth h3 { 364 | margin-top: 0; 365 | } 366 | 367 | #kc-oauth ul { 368 | list-style: none; 369 | padding: 0; 370 | margin: 0; 371 | } 372 | 373 | #kc-oauth ul li { 374 | border-top: 1px solid rgba(255, 255, 255, 0.1); 375 | font-size: 12px; 376 | padding: 10px 0; 377 | } 378 | 379 | #kc-oauth ul li:first-of-type { 380 | border-top: 0; 381 | } 382 | 383 | #kc-oauth .kc-role { 384 | display: inline-block; 385 | width: 50%; 386 | } 387 | 388 | /* Code */ 389 | #kc-code textarea { 390 | width: 100%; 391 | height: 8em; 392 | } 393 | 394 | /* Social */ 395 | .kc-social-links { 396 | margin-top: 20px; 397 | } 398 | 399 | .kc-social-provider-logo { 400 | font-size: 23px; 401 | width: 30px; 402 | height: 25px; 403 | float: left; 404 | } 405 | 406 | .kc-social-gray { 407 | color: #737679; /* default - IE compatibility */ 408 | color: var(--pf-global--Color--200); 409 | } 410 | 411 | .kc-social-item { 412 | margin-bottom: 0.5rem; /* default - IE compatibility */ 413 | margin-bottom: var(--pf-global--spacer--sm); 414 | font-size: 15px; 415 | text-align: center; 416 | } 417 | 418 | .kc-social-provider-name { 419 | position: relative; 420 | top: 3px; 421 | } 422 | 423 | .kc-social-icon-text { 424 | left: -15px; 425 | } 426 | 427 | .kc-social-grid { 428 | display:grid; 429 | grid-column-gap: 10px; 430 | grid-row-gap: 5px; 431 | grid-column-end: span 6; 432 | --pf-l-grid__item--GridColumnEnd: span 6; 433 | } 434 | 435 | .kc-social-grid .kc-social-icon-text { 436 | left: -10px; 437 | } 438 | 439 | .kc-login-tooltip { 440 | position: relative; 441 | display: inline-block; 442 | } 443 | 444 | .kc-social-section { 445 | text-align: center; 446 | } 447 | 448 | .kc-social-section hr{ 449 | margin-bottom: 10px 450 | } 451 | 452 | .kc-login-tooltip .kc-tooltip-text{ 453 | top:-3px; 454 | left:160%; 455 | background-color: black; 456 | visibility: hidden; 457 | color: #fff; 458 | 459 | min-width:130px; 460 | text-align: center; 461 | border-radius: 2px; 462 | box-shadow:0 1px 8px rgba(0,0,0,0.6); 463 | padding: 5px; 464 | 465 | position: absolute; 466 | opacity:0; 467 | transition:opacity 0.5s; 468 | } 469 | 470 | /* Show tooltip */ 471 | .kc-login-tooltip:hover .kc-tooltip-text { 472 | visibility: visible; 473 | opacity:0.7; 474 | } 475 | 476 | /* Arrow for tooltip */ 477 | .kc-login-tooltip .kc-tooltip-text::after { 478 | content: " "; 479 | position: absolute; 480 | top: 15px; 481 | right: 100%; 482 | margin-top: -5px; 483 | border-width: 5px; 484 | border-style: solid; 485 | border-color: transparent black transparent transparent; 486 | } 487 | 488 | @media (min-width: 768px) { 489 | #kc-container-wrapper { 490 | position: absolute; 491 | width: 100%; 492 | } 493 | 494 | .login-pf .container { 495 | padding-right: 80px; 496 | } 497 | 498 | #kc-locale { 499 | position: relative; 500 | text-align: right; 501 | z-index: 9999; 502 | } 503 | } 504 | 505 | @media (max-width: 767px) { 506 | #kc-header { 507 | padding-left: 15px; 508 | padding-right: 15px; 509 | float: none; 510 | text-align: left; 511 | } 512 | 513 | #kc-header-wrapper { 514 | font-size: 16px; 515 | font-weight: bold; 516 | padding: 20px 60px 0 0; 517 | color: #72767b; 518 | letter-spacing: 0; 519 | } 520 | 521 | div.kc-logo-text { 522 | margin: 0; 523 | width: 150px; 524 | height: 32px; 525 | background-size: 100%; 526 | } 527 | 528 | #kc-form { 529 | float: none; 530 | } 531 | 532 | #kc-info-wrapper { 533 | border-top: 1px solid rgba(255, 255, 255, 0.1); 534 | background-color: transparent; 535 | } 536 | 537 | .login-pf .container { 538 | padding-top: 15px; 539 | padding-bottom: 15px; 540 | } 541 | 542 | #kc-locale { 543 | position: absolute; 544 | width: 200px; 545 | top: 20px; 546 | right: 20px; 547 | text-align: right; 548 | z-index: 9999; 549 | } 550 | } 551 | 552 | @media (min-height: 646px) { 553 | #kc-container-wrapper { 554 | bottom: 12%; 555 | } 556 | } 557 | 558 | @media (max-height: 645px) { 559 | #kc-container-wrapper { 560 | padding-top: 50px; 561 | top: 20%; 562 | } 563 | } 564 | 565 | .card-pf form.form-actions .pf-c-button { 566 | float: right; 567 | margin-left: 10px; 568 | } 569 | 570 | #kc-form-buttons { 571 | margin-top: 20px; 572 | } 573 | 574 | .login-pf-page .login-pf-brand { 575 | margin-top: 20px; 576 | max-width: 360px; 577 | width: 40%; 578 | } 579 | 580 | /* Internet Explorer 11 compatibility workaround for select-authenticator screen */ 581 | @media all and (-ms-high-contrast: none), 582 | (-ms-high-contrast: active) { 583 | .select-auth-box-parent { 584 | border-top: 1px solid #f0f0f0; 585 | padding-top: 1rem; 586 | padding-bottom: 1rem; 587 | cursor: pointer; 588 | } 589 | 590 | .select-auth-box-headline { 591 | font-size: 16px; 592 | color: #00754a; 593 | font-weight: bold; 594 | } 595 | 596 | .select-auth-box-desc { 597 | font-size: 14px; 598 | } 599 | 600 | .pf-l-stack { 601 | flex-basis: 100%; 602 | } 603 | } 604 | /* End of IE11 workaround for select-authenticator screen */ 605 | 606 | .select-auth-box-arrow{ 607 | display: flex; 608 | align-items: center; 609 | margin-right: 2rem; 610 | } 611 | 612 | .select-auth-box-icon{ 613 | display: flex; 614 | flex: 0 0 2em; 615 | justify-content: center; 616 | margin-right: 1rem; 617 | margin-left: 3rem; 618 | } 619 | 620 | .select-auth-box-parent{ 621 | border-top: 1px solid var(--pf-global--palette--black-200); 622 | padding-top: 1rem; 623 | padding-bottom: 1rem; 624 | cursor: pointer; 625 | } 626 | 627 | .select-auth-box-parent:hover{ 628 | background-color: #f7f8f8; 629 | } 630 | 631 | .select-auth-container { 632 | padding-bottom: 0px !important; 633 | } 634 | 635 | .select-auth-box-headline { 636 | font-size: var(--pf-global--FontSize--md); 637 | color: #00754a; 638 | font-weight: bold; 639 | } 640 | 641 | .select-auth-box-desc { 642 | font-size: var(--pf-global--FontSize--sm); 643 | } 644 | 645 | .card-pf { 646 | margin: 0 auto; 647 | box-shadow: none; 648 | padding: 0 20px; 649 | max-width: 500px; 650 | min-width: 500px; 651 | border-radius: 8px 652 | } 653 | 654 | /*phone*/ 655 | @media (max-width: 767px) { 656 | .login-pf-page .card-pf { 657 | max-width: none; 658 | margin-left: 0; 659 | margin-right: 0; 660 | padding-top: 0; 661 | border-top: 0; 662 | box-shadow: 0 0; 663 | } 664 | 665 | .kc-social-grid { 666 | grid-column-end: 12; 667 | --pf-l-grid__item--GridColumnEnd: span 12; 668 | } 669 | 670 | .kc-social-grid .kc-social-icon-text { 671 | left: -15px; 672 | } 673 | } 674 | 675 | .login-pf-page .login-pf-signup { 676 | font-size: 15px; 677 | color: #72767b; 678 | } 679 | #kc-content-wrapper .row { 680 | margin-left: 0; 681 | margin-right: 0; 682 | } 683 | 684 | .login-pf-page.login-pf-page-accounts { 685 | margin-left: auto; 686 | margin-right: auto; 687 | } 688 | 689 | .login-pf-page .btn-primary { 690 | margin-top: 0; 691 | } 692 | 693 | .login-pf-page .list-view-pf .list-group-item { 694 | border-bottom: 1px solid #ededed; 695 | } 696 | 697 | .login-pf-page .list-view-pf-description { 698 | width: 100%; 699 | } 700 | 701 | #kc-form-login div.form-group:last-of-type, 702 | #kc-register-form div.form-group:last-of-type, 703 | #kc-update-profile-form div.form-group:last-of-type { 704 | margin-bottom: 0px; 705 | } 706 | 707 | .no-bottom-margin { 708 | margin-bottom: 0; 709 | } 710 | 711 | #kc-back { 712 | margin-top: 5px; 713 | } 714 | 715 | /* Stop cancel buttons showing a gradient */ 716 | #kc-content .pf-c-button.btn-default { 717 | background-image: none; 718 | } 719 | /* Stop cancel buttons being full width and pad to same as primary */ 720 | .pf-c-button.btn-default { 721 | width: auto; 722 | padding: 10px 30px; 723 | } 724 | a.pf-c-button.pf-m-primary { 725 | background-color: #00754a; 726 | } 727 | a.pf-c-button.pf-m-primary:hover { 728 | color: #ffffff; 729 | } 730 | 731 | a#reset-login { 732 | color: #00754a; 733 | } 734 | 735 | .login-pf-page { 736 | padding-top: 0; 737 | } 738 | .navbar-left img { 739 | height: 66px; 740 | padding-top: 5px; 741 | padding-bottom: 5px; 742 | } 743 | #footer { 744 | background-color: white !important; 745 | } 746 | @media (min-width: 768px) { 747 | .login-pf footer .container { 748 | bottom: 0; 749 | padding-left: 0; 750 | position: relative; 751 | } 752 | } 753 | 754 | @media (min-width: 768px) { 755 | .login-pf .container { 756 | padding-right: 0; 757 | } 758 | } 759 | #footer .container { 760 | margin-right: auto; 761 | margin-left: auto; 762 | padding-left: 20px; 763 | padding-right: 20px; 764 | color: #333; 765 | background-color: inherit; 766 | } 767 | @media (min-width: 768px) { 768 | #footer .container { 769 | width: 760px !important; 770 | } 771 | } 772 | @media (min-width: 992px) { 773 | #footer .container { 774 | width: 980px !important; 775 | } 776 | } 777 | @media (min-width: 1200px) { 778 | #footer .container { 779 | width: 1180px !important; 780 | } 781 | } 782 | @media (max-width: 999px) { 783 | #wrapper footer h3 { 784 | text-align: left; 785 | } 786 | } 787 | #kc-content .pf-c-button.pf-m-primary { 788 | background-color:#00754a; 789 | background-image: none; 790 | border:#7a7a7a; 791 | color:white; 792 | transition: all 300ms ease; 793 | border-radius: 2px; 794 | width: auto; 795 | padding: 10px 30px; 796 | } 797 | .p-fc-button.pf-m-primary:hover { 798 | color: white; 799 | } 800 | .p-fc-button.pf-m-primary:active { 801 | background-color:#00754a; 802 | background-image: none; 803 | border:#7a7a7a; 804 | color:white; 805 | } 806 | #wrapper footer .block h3 { 807 | color: #3c3b39; 808 | } 809 | #wrapper footer p { 810 | font-size: 16px; 811 | } 812 | #wrapper .card-pf { 813 | text-align: center; 814 | background-color: rgba(255, 255, 255, 0.9); 815 | background: rgba(255, 255, 255, 0.9); 816 | } 817 | nav.navbar.navbar-fixed-top { 818 | background-color: white; 819 | position: relative; 820 | margin-bottom: 0; 821 | } 822 | div#wrapper {margin-top: 67px;} 823 | 824 | .alert-error { 825 | background-color: #fac7c7; 826 | border-radius: 2px; 827 | } 828 | 829 | .block { 830 | background-color: white; 831 | padding: 10px; 832 | border: 1px solid #eee; 833 | margin: 10px; 834 | height: 100%; 835 | } 836 | .row_equal_height { 837 | display: -webkit-box; 838 | display: -webkit-flex; 839 | display: -ms-flexbox; 840 | display: flex; 841 | } 842 | @media (max-width: 768px) { 843 | .row_equal_height { 844 | display: block; 845 | } 846 | } 847 | #kc-page-title { 848 | text-align: left; 849 | font-size: 24px; 850 | } 851 | 852 | .form-control { 853 | max-width: 300px; 854 | } 855 | div#block_row { 856 | background-color: whitesmoke; 857 | } 858 | 859 | #block_row .container { 860 | padding-left: 0px; 861 | padding-right: 0px; 862 | } 863 | #wrapper .btn-lg { 864 | padding: 10px 20px; 865 | text-transform: uppercase; 866 | } 867 | #kc-form a { 868 | color: #00754a; 869 | } 870 | #kc-form a:hover { 871 | color: #00754a; 872 | } 873 | 874 | #wrapper .block a.pf-c-button.pf-m-primary.btn-lg { 875 | background-color: white; 876 | box-shadow: none; 877 | color: #00754a; 878 | font-weight: bolder; 879 | padding-left:0px; 880 | margin-left:0px; 881 | padding: 0px; 882 | margin-bottom:15px; 883 | } 884 | #wrapper .block a.pf-c-button.pf-m-primary.btn-lg:hover { 885 | background-color: white; 886 | box-shadow: none; 887 | color: #3c3b39; 888 | font-weight: bolder; 889 | top:0px; 890 | transform: none; 891 | transition: 0ms all ease; 892 | } 893 | textarea:focus, 894 | input[type="text"]:focus, 895 | input[type="password"]:focus, 896 | input[type="datetime"]:focus, 897 | input[type="datetime-local"]:focus, 898 | input[type="date"]:focus, 899 | input[type="month"]:focus, 900 | input[type="time"]:focus, 901 | input[type="week"]:focus, 902 | input[type="number"]:focus, 903 | input[type="email"]:focus, 904 | input[type="url"]:focus, 905 | input[type="search"]:focus, 906 | input[type="tel"]:focus, 907 | input[type="color"]:focus, 908 | .uneditable-input:focus { 909 | border-color: #00754a; 910 | outline: 0 none; 911 | } 912 | 913 | --------------------------------------------------------------------------------