keycloak-aplcache
Changes
services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java 19(+11 -8)
services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java 25(+18 -7)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/x509/X509IdentityConfirmationPage.java 3(+2 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java 7(+4 -3)
Details
diff --git a/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsPages.java b/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsPages.java
index 476e3aa..b09340a 100755
--- a/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsPages.java
+++ b/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsPages.java
@@ -24,6 +24,7 @@ public enum LoginFormsPages {
LOGIN, LOGIN_TOTP, LOGIN_CONFIG_TOTP, LOGIN_VERIFY_EMAIL,
LOGIN_IDP_LINK_CONFIRM, LOGIN_IDP_LINK_EMAIL,
- OAUTH_GRANT, LOGIN_RESET_PASSWORD, LOGIN_UPDATE_PASSWORD, REGISTER, INFO, ERROR, LOGIN_UPDATE_PROFILE, LOGIN_PAGE_EXPIRED, CODE;
+ OAUTH_GRANT, LOGIN_RESET_PASSWORD, LOGIN_UPDATE_PASSWORD, REGISTER, INFO, ERROR, LOGIN_UPDATE_PROFILE,
+ LOGIN_PAGE_EXPIRED, CODE, X509_CONFIRM;
}
diff --git a/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsProvider.java b/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsProvider.java
index eb8013e..011946f 100755
--- a/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsProvider.java
@@ -80,7 +80,9 @@ public interface LoginFormsProvider extends Provider {
Response createOAuthGrant();
Response createCode();
-
+
+ Response createX509ConfirmPage();
+
LoginFormsProvider setAuthenticationSession(AuthenticationSessionModel authenticationSession);
LoginFormsProvider setClientSessionCode(String accessCode);
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java
index 01339f6..5ba4e3c 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java
@@ -22,6 +22,7 @@ import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
+import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@@ -30,11 +31,12 @@ import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
+import org.keycloak.forms.login.LoginFormsPages;
import org.keycloak.forms.login.LoginFormsProvider;
+import org.keycloak.forms.login.freemarker.Templates;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
-import org.keycloak.services.ServicesLogger;
/**
* @author <a href="mailto:pnalyvayko@agi.com">Peter Nalyvayko</a>
@@ -43,8 +45,6 @@ import org.keycloak.services.ServicesLogger;
*/
public class X509ClientCertificateAuthenticator extends AbstractX509ClientCertificateAuthenticator {
- protected static ServicesLogger logger = ServicesLogger.LOGGER;
-
@Override
public void close() {
@@ -216,11 +216,14 @@ public class X509ClientCertificateAuthenticator extends AbstractX509ClientCertif
form.setErrors(errors);
}
- return form
- .setAttribute("username", context.getUser() != null ? context.getUser().getUsername() : "unknown user")
- .setAttribute("subjectDN", subjectDN)
- .setAttribute("isUserEnabled", isUserEnabled)
- .createForm("login-x509-info.ftl");
+ MultivaluedMap<String,String> formData = new MultivaluedHashMap<>();
+ formData.add("username", context.getUser() != null ? context.getUser().getUsername() : "unknown user");
+ formData.add("subjectDN", subjectDN);
+ formData.add("isUserEnabled", String.valueOf(isUserEnabled));
+
+ form.setFormData(formData);
+
+ return form.createX509ConfirmPage();
}
private void dumpContainerAttributes(AuthenticationFlowContext context) {
diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java b/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java
index 8b92110..80cfe53 100755
--- a/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java
+++ b/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java
@@ -35,6 +35,7 @@ import org.keycloak.forms.login.freemarker.model.RegisterBean;
import org.keycloak.forms.login.freemarker.model.RequiredActionUrlFormatterMethod;
import org.keycloak.forms.login.freemarker.model.TotpBean;
import org.keycloak.forms.login.freemarker.model.UrlBean;
+import org.keycloak.forms.login.freemarker.model.X509ConfirmBean;
import org.keycloak.models.*;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.services.Urls;
@@ -62,6 +63,7 @@ import java.net.URI;
import java.text.MessageFormat;
import java.util.*;
+
import static org.keycloak.models.UserModel.RequiredAction.UPDATE_PASSWORD;
/**
@@ -75,7 +77,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
protected Response.Status status;
protected javax.ws.rs.core.MediaType contentType;
protected List<ClientScopeModel> clientScopesRequested;
- protected Map<String, String> httpResponseHeaders = new HashMap<String, String>();
+ protected Map<String, String> httpResponseHeaders = new HashMap<>();
protected URI actionUri;
protected String execution;
@@ -95,12 +97,12 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
protected UserModel user;
- protected final Map<String, Object> attributes = new HashMap<String, Object>();
+ protected final Map<String, Object> attributes = new HashMap<>();
public FreeMarkerLoginFormsProvider(KeycloakSession session, FreeMarkerUtil freeMarker) {
this.session = session;
this.freeMarker = freeMarker;
- this.attributes.put("scripts", new LinkedList<String>());
+ this.attributes.put("scripts", new LinkedList<>());
this.realm = session.getContext().getRealm();
this.client = session.getContext().getClient();
this.uriInfo = session.getContext().getUri();
@@ -204,6 +206,9 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
case CODE:
attributes.put(OAuth2Constants.CODE, new CodeBean(accessCode, messageType == MessageType.ERROR ? getFirstMessageUnformatted() : null));
break;
+ case X509_CONFIRM:
+ attributes.put("x509", new X509ConfirmBean(formData));
+ break;
}
return processTemplate(theme, Templates.getTemplate(page), locale);
@@ -342,7 +347,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
Locale locale = session.getContext().resolveLocale(user);
Properties messagesBundle = handleThemeResources(theme, locale);
- FormMessage msg = new FormMessage(message, parameters);
+ FormMessage msg = new FormMessage(message, (Object[]) parameters);
return formatMessage(msg, messagesBundle, locale);
}
@@ -385,6 +390,9 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
case LOGIN:
b = UriBuilder.fromUri(Urls.realmLoginPage(baseUri, realm.getName()));
break;
+ case X509_CONFIRM:
+ b = UriBuilder.fromUri(Urls.realmLoginPage(baseUri, realm.getName()));
+ break;
case REGISTER:
b = UriBuilder.fromUri(Urls.realmRegisterPage(baseUri, realm.getName()));
break;
@@ -508,6 +516,11 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
return createResponse(LoginFormsPages.CODE);
}
+ @Override
+ public Response createX509ConfirmPage() {
+ return createResponse(LoginFormsPages.X509_CONFIRM);
+ }
+
protected void setMessage(MessageType type, String message, Object... parameters) {
messageType = type;
messages = new ArrayList<>();
@@ -629,15 +642,13 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
this.status = status;
return this;
}
+
@Override
public LoginFormsProvider setMediaType(javax.ws.rs.core.MediaType type) {
this.contentType = type;
return this;
}
-
-
-
@Override
public LoginFormsProvider setActionUri(URI actionUri) {
this.actionUri = actionUri;
diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/model/X509ConfirmBean.java b/services/src/main/java/org/keycloak/forms/login/freemarker/model/X509ConfirmBean.java
new file mode 100644
index 0000000..20d87f4
--- /dev/null
+++ b/services/src/main/java/org/keycloak/forms/login/freemarker/model/X509ConfirmBean.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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.forms.login.freemarker.model;
+
+import javax.ws.rs.core.MultivaluedMap;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author vramik
+ */
+public class X509ConfirmBean {
+
+ private Map<String, String> formData = new HashMap<>();
+
+ public X509ConfirmBean(MultivaluedMap<String, String> formData) {
+ this.formData = new HashMap<>();
+
+ if (formData != null) {
+ formData.keySet().stream().forEach((key) -> this.formData.put(key, formData.getFirst(key)));
+ }
+ }
+
+ public Map<String, String> getFormData() {
+ return formData;
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java b/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java
index f2a9d75..73921a5 100755
--- a/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java
+++ b/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java
@@ -56,6 +56,8 @@ public class Templates {
return "code.ftl";
case LOGIN_PAGE_EXPIRED:
return "login-page-expired.ftl";
+ case X509_CONFIRM:
+ return "login-x509-info.ftl";
default:
throw new IllegalArgumentException();
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/x509/X509IdentityConfirmationPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/x509/X509IdentityConfirmationPage.java
index a656d50..f229ca4 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/x509/X509IdentityConfirmationPage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/x509/X509IdentityConfirmationPage.java
@@ -20,6 +20,7 @@ package org.keycloak.testsuite.pages.x509;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.keycloak.testsuite.pages.AbstractPage;
+import org.keycloak.testsuite.pages.LanguageComboboxAwarePage;
import org.keycloak.testsuite.util.OAuthClient;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
@@ -30,7 +31,7 @@ import org.openqa.selenium.support.FindBy;
* @since 10/24/2016
*/
-public class X509IdentityConfirmationPage extends AbstractPage {
+public class X509IdentityConfirmationPage extends LanguageComboboxAwarePage {
@ArquillianResource
protected OAuthClient oauth;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
index 2218288..4d1b224 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/AbstractX509AuthenticationTest.java
@@ -98,6 +98,7 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
@Rule
public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this);
+ @Override
protected boolean isImportAfterEachMethod() {
return true;
}
@@ -113,9 +114,9 @@ public abstract class AbstractX509AuthenticationTest extends AbstractTestRealmKe
cliArgs.append("--ignore-ssl-errors=true ");
cliArgs.append("--web-security=false ");
- cliArgs.append("--ssl-certificates-path=" + authServerHome + "/ca.crt ");
- cliArgs.append("--ssl-client-certificate-file=" + authServerHome + "/client.crt ");
- cliArgs.append("--ssl-client-key-file=" + authServerHome + "/client.key ");
+ cliArgs.append("--ssl-certificates-path=").append(authServerHome).append("/ca.crt ");
+ cliArgs.append("--ssl-client-certificate-file=").append(authServerHome).append("/client.crt ");
+ cliArgs.append("--ssl-client-key-file=").append(authServerHome).append("/client.key ");
cliArgs.append("--ssl-client-key-passphrase=secret ");
System.setProperty("keycloak.phantomjs.cli.args", cliArgs.toString());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginTest.java
index a714998..51f4453 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509BrowserLoginTest.java
@@ -33,11 +33,16 @@ import org.keycloak.testsuite.pages.x509.X509IdentityConfirmationPage;
import javax.ws.rs.core.Response;
import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.IdentityMapperType.USERNAME_EMAIL;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.IdentityMapperType.USER_ATTRIBUTE;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN;
import static org.keycloak.authentication.authenticators.x509.X509AuthenticatorConfigModel.MappingSourceType.SUBJECTDN_EMAIL;
+import org.keycloak.testsuite.ProfileAssume;
+import org.keycloak.testsuite.util.DroneUtils;
/**
* @author <a href="mailto:brat000012001@gmail.com">Peter Nalyvayko</a>
@@ -483,4 +488,33 @@ public class X509BrowserLoginTest extends AbstractX509AuthenticationTest {
loginAsUserFromCertSubjectEmail();
}
+ // KEYCLOAK-6866
+ @Test
+ public void changeLocaleOnX509InfoPage() {
+ ProfileAssume.assumeCommunity();
+
+ AuthenticatorConfigRepresentation cfg = newConfig("x509-browser-config", createLoginSubjectEmail2UsernameOrEmailConfig().getConfig());
+ String cfgId = createConfig(browserExecution.getId(), cfg);
+ Assert.assertNotNull(cfgId);
+
+ log.debug("Open confirm page");
+ loginConfirmationPage.open();
+
+ log.debug("check if on confirm page");
+ Assert.assertThat(loginConfirmationPage.getSubjectDistinguishedNameText(), startsWith("EMAILADDRESS=test-user@localhost"));
+ log.debug("check if locale is EN");
+ Assert.assertThat(loginConfirmationPage.getLanguageDropdownText(), is(equalTo("English")));
+
+ log.debug("change locale to DE");
+ loginConfirmationPage.openLanguage("Deutsch");
+ log.debug("check if locale is DE");
+ Assert.assertThat(loginConfirmationPage.getLanguageDropdownText(), is(equalTo("Deutsch")));
+ Assert.assertThat(DroneUtils.getCurrentDriver().getPageSource(), containsString("X509 Client Zertifikat:"));
+
+ log.debug("confirm cert");
+ loginConfirmationPage.confirm();
+
+ log.debug("check if logged in");
+ Assert.assertThat(appPage.getRequestType(), is(equalTo(AppPage.RequestType.AUTH_RESPONSE)));
+ }
}
diff --git a/themes/src/main/resources/theme/base/login/login-x509-info.ftl b/themes/src/main/resources/theme/base/login/login-x509-info.ftl
index c3ff2fd..0228b06 100644
--- a/themes/src/main/resources/theme/base/login/login-x509-info.ftl
+++ b/themes/src/main/resources/theme/base/login/login-x509-info.ftl
@@ -10,9 +10,9 @@
<div class="${properties.kcLabelWrapperClass!}">
<label for="certificate_subjectDN" class="${properties.kcLabelClass!}">${msg("clientCertificate")}</label>
</div>
- <#if subjectDN??>
+ <#if x509.formData.subjectDN??>
<div class="${properties.kcLabelWrapperClass!}">
- <label id="certificate_subjectDN" class="${properties.kcLabelClass!}">${(subjectDN!"")}</label>
+ <label id="certificate_subjectDN" class="${properties.kcLabelClass!}">${(x509.formData.subjectDN!"")}</label>
</div>
<#else>
<div class="${properties.kcLabelWrapperClass!}">
@@ -23,12 +23,12 @@
<div class="${properties.kcFormGroupClass!}">
- <#if isUserEnabled>
+ <#if x509.formData.isUserEnabled??>
<div class="${properties.kcLabelWrapperClass!}">
<label for="username" class="${properties.kcLabelClass!}">${msg("doX509Login")}</label>
</div>
<div class="${properties.kcLabelWrapperClass!}">
- <label id="username" class="${properties.kcLabelClass!}">${(username!'')}</label>
+ <label id="username" class="${properties.kcLabelClass!}">${(x509.formData.username!'')}</label>
</div>
</#if>
@@ -43,7 +43,7 @@
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
<div class="${properties.kcFormButtonsWrapperClass!}">
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="login" id="kc-login" type="submit" value="${msg("doContinue")}"/>
- <#if isUserEnabled>
+ <#if x509.formData.isUserEnabled??>
<input class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="cancel" id="kc-cancel" type="submit" value="${msg("doIgnore")}"/>
</#if>
</div>