[KEYCLOAK-18429] Support a dynamic update profile form
This commit is contained in:
parent
f32447bcc1
commit
04ff2c327b
25 changed files with 1004 additions and 387 deletions
|
@ -26,6 +26,6 @@ public enum LoginFormsPages {
|
|||
LOGIN_IDP_LINK_CONFIRM, LOGIN_IDP_LINK_EMAIL,
|
||||
OAUTH_GRANT, LOGIN_RESET_PASSWORD, LOGIN_UPDATE_PASSWORD, LOGIN_SELECT_AUTHENTICATOR, REGISTER, REGISTER_USER_PROFILE, INFO, ERROR, ERROR_WEBAUTHN, LOGIN_UPDATE_PROFILE,
|
||||
LOGIN_PAGE_EXPIRED, CODE, X509_CONFIRM, SAML_POST_FORM,
|
||||
LOGIN_OAUTH2_DEVICE_VERIFY_USER_CODE, VERIFY_PROFILE;
|
||||
LOGIN_OAUTH2_DEVICE_VERIFY_USER_CODE, UPDATE_USER_PROFILE;
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.resources.IdentityBrokerService;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
import org.keycloak.userprofile.UserProfileContext;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -66,6 +67,12 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext {
|
|||
return !emailAsUsername;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public UserProfileContext getUserProfileContext() {
|
||||
return UserProfileContext.IDP_REVIEW;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.keycloak.authentication.RequiredActionProvider;
|
|||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.forms.login.LoginFormsProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
@ -57,9 +58,7 @@ public class UpdateProfile implements RequiredActionProvider, RequiredActionFact
|
|||
|
||||
@Override
|
||||
public void requiredActionChallenge(RequiredActionContext context) {
|
||||
Response challenge = context.form()
|
||||
.createResponse(UserModel.RequiredAction.UPDATE_PROFILE);
|
||||
context.challenge(challenge);
|
||||
context.challenge(createResponse(context, null, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,14 +93,28 @@ public class UpdateProfile implements RequiredActionProvider, RequiredActionFact
|
|||
} catch (ValidationException pve) {
|
||||
List<FormMessage> errors = Validation.getFormErrorsFromValidation(pve.getErrors());
|
||||
|
||||
Response challenge = context.form()
|
||||
.setErrors(errors)
|
||||
.setFormData(formData)
|
||||
.createResponse(UserModel.RequiredAction.UPDATE_PROFILE);
|
||||
context.challenge(challenge);
|
||||
context.challenge(createResponse(context, formData, errors));
|
||||
}
|
||||
}
|
||||
|
||||
protected UserModel.RequiredAction getResponseAction(){
|
||||
return UserModel.RequiredAction.UPDATE_PROFILE;
|
||||
}
|
||||
|
||||
protected Response createResponse(RequiredActionContext context, MultivaluedMap<String, String> formData, List<FormMessage> errors) {
|
||||
LoginFormsProvider form = context.form();
|
||||
|
||||
if (errors != null && !errors.isEmpty()) {
|
||||
form.setErrors(errors);
|
||||
}
|
||||
|
||||
if(formData != null) {
|
||||
form = form.setFormData(formData);
|
||||
}
|
||||
|
||||
return form.createResponse(getResponseAction());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
|
|
@ -17,24 +17,19 @@
|
|||
|
||||
package org.keycloak.authentication.requiredactions;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.core.MultivaluedHashMap;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.authentication.DisplayTypeRequiredActionFactory;
|
||||
import org.keycloak.authentication.InitiatedActionSupport;
|
||||
import org.keycloak.authentication.RequiredActionContext;
|
||||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.forms.login.LoginFormsProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.FormMessage;
|
||||
import org.keycloak.services.validation.Validation;
|
||||
|
@ -46,11 +41,16 @@ import org.keycloak.userprofile.ValidationException;
|
|||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class VerifyUserProfile implements RequiredActionProvider, RequiredActionFactory, DisplayTypeRequiredActionFactory {
|
||||
public class VerifyUserProfile extends UpdateProfile {
|
||||
|
||||
@Override
|
||||
public InitiatedActionSupport initiatedActionSupport() {
|
||||
return InitiatedActionSupport.SUPPORTED;
|
||||
return InitiatedActionSupport.NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UserModel.RequiredAction getResponseAction(){
|
||||
return UserModel.RequiredAction.VERIFY_PROFILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -72,7 +72,7 @@ public class VerifyUserProfile implements RequiredActionProvider, RequiredAction
|
|||
public void requiredActionChallenge(RequiredActionContext context) {
|
||||
UserProfileProvider provider = context.getSession().getProvider(UserProfileProvider.class);
|
||||
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, context.getUser());
|
||||
|
||||
|
||||
try {
|
||||
profile.validate();
|
||||
context.success();
|
||||
|
@ -86,31 +86,17 @@ public class VerifyUserProfile implements RequiredActionProvider, RequiredAction
|
|||
parameters = context.getHttpRequest().getDecodedFormParameters();
|
||||
}
|
||||
|
||||
context.challenge(createResponse(context, profile, parameters, errors));
|
||||
context.challenge(createResponse(context, parameters, errors));
|
||||
|
||||
EventBuilder event = context.getEvent().clone();
|
||||
event.event(EventType.VERIFY_PROFILE);
|
||||
event.detail("fields_to_update", collectFields(errors));
|
||||
event.success();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAction(RequiredActionContext context) {
|
||||
EventBuilder event = context.getEvent();
|
||||
event.event(EventType.VERIFY_PROFILE);
|
||||
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
|
||||
UserProfileProvider provider = context.getSession().getProvider(UserProfileProvider.class);
|
||||
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, formData, context.getUser());
|
||||
|
||||
try {
|
||||
profile.update();
|
||||
context.success();
|
||||
} catch (ValidationException ve) {
|
||||
List<FormMessage> errors = Validation.getFormErrorsFromValidation(ve.getErrors());
|
||||
context.challenge(createResponse(context, profile, formData, errors));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
private String collectFields(List<FormMessage> errors) {
|
||||
return errors.stream().map(FormMessage::getField).distinct().collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,23 +104,6 @@ public class VerifyUserProfile implements RequiredActionProvider, RequiredAction
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequiredActionProvider createDisplay(KeycloakSession session, String displayType) {
|
||||
if (displayType == null) return this;
|
||||
if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) return null;
|
||||
return ConsoleUpdateProfile.SINGLETON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayText() {
|
||||
return "Verify Profile";
|
||||
|
@ -146,15 +115,4 @@ public class VerifyUserProfile implements RequiredActionProvider, RequiredAction
|
|||
return UserModel.RequiredAction.VERIFY_PROFILE.name();
|
||||
}
|
||||
|
||||
private Response createResponse(RequiredActionContext context, UserProfile profile,
|
||||
MultivaluedMap<String, String> formData, List<FormMessage> errors) {
|
||||
LoginFormsProvider form = context.form();
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
form.setErrors(errors);
|
||||
}
|
||||
|
||||
return form.setFormData(formData)
|
||||
.createResponse(UserModel.RequiredAction.VERIFY_PROFILE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import java.util.Map;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.keycloak.userprofile.UserProfileContext;
|
||||
|
||||
/**
|
||||
* Abstraction, which allows to display updateProfile page in various contexts (Required action of already existing user, or first identity provider
|
||||
* login when user doesn't yet exists in Keycloak DB)
|
||||
|
@ -29,6 +31,8 @@ import java.util.stream.Stream;
|
|||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface UpdateProfileContext {
|
||||
|
||||
UserProfileContext getUserProfileContext();
|
||||
|
||||
boolean isEditUsernameAllowed();
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@ package org.keycloak.authentication.requiredactions.util;
|
|||
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.userprofile.UserProfileContext;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
|
@ -37,11 +37,16 @@ public class UserUpdateProfileContext implements UpdateProfileContext {
|
|||
this.realm = realm;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isEditUsernameAllowed() {
|
||||
return realm.isEditUsernameAllowed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserProfileContext getUserProfileContext() {
|
||||
return UserProfileContext.UPDATE_PROFILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
|
|
|
@ -150,7 +150,11 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
|||
this.attributes.put(UPDATE_PROFILE_CONTEXT_ATTR, userBasedContext);
|
||||
|
||||
actionMessage = Messages.UPDATE_PROFILE;
|
||||
page = LoginFormsPages.LOGIN_UPDATE_PROFILE;
|
||||
if(isDynamicUserProfile()) {
|
||||
page = LoginFormsPages.UPDATE_USER_PROFILE;
|
||||
} else {
|
||||
page = LoginFormsPages.LOGIN_UPDATE_PROFILE;
|
||||
}
|
||||
break;
|
||||
case UPDATE_PASSWORD:
|
||||
boolean isRequestedByAdmin = user.getRequiredActionsStream().filter(Objects::nonNull).anyMatch(UPDATE_PASSWORD.toString()::contains);
|
||||
|
@ -166,7 +170,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
|||
this.attributes.put(UPDATE_PROFILE_CONTEXT_ATTR, verifyProfile);
|
||||
|
||||
actionMessage = Messages.UPDATE_PROFILE;
|
||||
page = LoginFormsPages.VERIFY_PROFILE;
|
||||
page = LoginFormsPages.UPDATE_USER_PROFILE;
|
||||
break;
|
||||
default:
|
||||
return Response.serverError().build();
|
||||
|
@ -254,7 +258,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
|||
case SAML_POST_FORM:
|
||||
attributes.put("samlPost", new SAMLPostFormBean(formData));
|
||||
break;
|
||||
case VERIFY_PROFILE:
|
||||
case UPDATE_USER_PROFILE:
|
||||
attributes.put("profile", new VerifyProfileBean(user, formData, session));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -74,8 +74,8 @@ public class Templates {
|
|||
return "login-x509-info.ftl";
|
||||
case SAML_POST_FORM:
|
||||
return "saml-post-form.ftl";
|
||||
case VERIFY_PROFILE:
|
||||
return "verify-profile.ftl";
|
||||
case UPDATE_USER_PROFILE:
|
||||
return "update-user-profile.ftl";
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
|
|
@ -55,9 +55,9 @@ public abstract class AbstractUserProfileBean {
|
|||
* Get attribute default value to be pre-filled into the form on first show.
|
||||
*
|
||||
* @param name of the attribute
|
||||
* @return attribute default value (can be null or empty list)
|
||||
* @return attribute default value (can be null)
|
||||
*/
|
||||
protected abstract List<String> getAttributeDefaultValue(String name);
|
||||
protected abstract String getAttributeDefaultValue(String name);
|
||||
|
||||
/**
|
||||
* Get context the template is used for, so view can be customized for distinct contexts.
|
||||
|
@ -110,11 +110,12 @@ public abstract class AbstractUserProfileBean {
|
|||
}
|
||||
|
||||
public String getValue() {
|
||||
List<String> v = formData!=null ? formData.getOrDefault(getName(), getAttributeDefaultValue(getName())): getAttributeDefaultValue(getName());
|
||||
List<String> v = formData != null ? formData.get(getName()) : null;
|
||||
if (v == null || v.isEmpty()) {
|
||||
return null;
|
||||
return getAttributeDefaultValue(getName());
|
||||
} else {
|
||||
return v.get(0);
|
||||
}
|
||||
return v.get(0);
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
|
@ -143,7 +144,7 @@ public abstract class AbstractUserProfileBean {
|
|||
|
||||
return annotations;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get info about validators applied to attribute.
|
||||
*
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.keycloak.forms.login.freemarker.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
@ -53,7 +52,7 @@ public class RegisterBean extends AbstractUserProfileBean {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getAttributeDefaultValue(String name) {
|
||||
protected String getAttributeDefaultValue(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package org.keycloak.forms.login.freemarker.model;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -31,8 +27,8 @@ public class VerifyProfileBean extends AbstractUserProfileBean {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getAttributeDefaultValue(String name) {
|
||||
return singletonList(user.getFirstAttribute(name));
|
||||
protected String getAttributeDefaultValue(String name) {
|
||||
return user.getFirstAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -138,6 +138,7 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
|
|||
decoratedMetadata.addAttribute(UserModel.LAST_NAME, 2, new AttributeValidatorMetadata(BlankAttributeValidator.ID, BlankAttributeValidator.createConfig(Messages.MISSING_LAST_NAME))).setAttributeDisplayName("${lastName}");
|
||||
return decoratedMetadata;
|
||||
}
|
||||
return decoratedMetadata;
|
||||
}
|
||||
|
||||
ComponentModel model = getComponentModelOrCreate(session);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.pages;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
|
@ -30,6 +32,12 @@ public class LoginUpdateProfileEditUsernameAllowedPage extends LoginUpdateProfil
|
|||
update(firstName, lastName, email);
|
||||
}
|
||||
|
||||
public void updateWithDepartment(String firstName, String lastName, String department, String email, String username) {
|
||||
usernameInput.clear();
|
||||
usernameInput.sendKeys(username);
|
||||
super.updateWithDepartment(firstName, lastName, department, email);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return usernameInput.getAttribute("value");
|
||||
}
|
||||
|
@ -37,6 +45,14 @@ public class LoginUpdateProfileEditUsernameAllowedPage extends LoginUpdateProfil
|
|||
public boolean isCurrent() {
|
||||
return PageUtils.getPageTitle(driver).equals("Update Account Information");
|
||||
}
|
||||
|
||||
public boolean isUsernamePresent() {
|
||||
try {
|
||||
return driver.findElement(By.id("username")).isDisplayed();
|
||||
} catch (NoSuchElementException nse) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.testsuite.pages;
|
|||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.keycloak.testsuite.util.UIUtils;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
@ -42,6 +43,9 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
|
||||
@FindBy(id = "email")
|
||||
private WebElement emailInput;
|
||||
|
||||
@FindBy(id = "department")
|
||||
private WebElement departmentInput;
|
||||
|
||||
@FindBy(css = "input[type=\"submit\"]")
|
||||
private WebElement submitButton;
|
||||
|
@ -53,6 +57,10 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
private WebElement loginAlertErrorMessage;
|
||||
|
||||
public void update(String firstName, String lastName, String email) {
|
||||
updateWithDepartment(firstName, lastName, null, email);
|
||||
}
|
||||
|
||||
public void updateWithDepartment(String firstName, String lastName, String department, String email) {
|
||||
if (firstName != null) {
|
||||
firstNameInput.clear();
|
||||
firstNameInput.sendKeys(firstName);
|
||||
|
@ -66,6 +74,11 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
emailInput.sendKeys(email);
|
||||
}
|
||||
|
||||
if(department != null) {
|
||||
departmentInput.clear();
|
||||
departmentInput.sendKeys(department);
|
||||
}
|
||||
|
||||
clickLink(submitButton);
|
||||
}
|
||||
|
||||
|
@ -92,6 +105,14 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
public String getEmail() {
|
||||
return emailInput.getAttribute("value");
|
||||
}
|
||||
|
||||
public String getDepartment() {
|
||||
return departmentInput.getAttribute("value");
|
||||
}
|
||||
|
||||
public boolean isDepartmentEnabled() {
|
||||
return departmentInput.isEnabled();
|
||||
}
|
||||
|
||||
public boolean isCurrent() {
|
||||
return PageUtils.getPageTitle(driver).equals("Update Account Information");
|
||||
|
@ -100,6 +121,19 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
public UpdateProfileErrors getInputErrors() {
|
||||
return errorsPage;
|
||||
}
|
||||
|
||||
public String getLabelForField(String fieldId) {
|
||||
return driver.findElement(By.cssSelector("label[for="+fieldId+"]")).getText();
|
||||
}
|
||||
|
||||
public boolean isDepartmentPresent() {
|
||||
try {
|
||||
isDepartmentEnabled();
|
||||
return true;
|
||||
} catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
|
@ -120,8 +154,14 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
@FindBy(id = "input-error-firstname")
|
||||
private WebElement inputErrorFirstName;
|
||||
|
||||
@FindBy(id = "input-error-firstName")
|
||||
private WebElement inputErrorFirstNameDynamic;
|
||||
|
||||
@FindBy(id = "input-error-lastname")
|
||||
private WebElement inputErrorLastName;
|
||||
|
||||
@FindBy(id = "input-error-lastName")
|
||||
private WebElement inputErrorLastNameDynamic;
|
||||
|
||||
@FindBy(id = "input-error-email")
|
||||
private WebElement inputErrorEmail;
|
||||
|
@ -133,7 +173,11 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
try {
|
||||
return getTextFromElement(inputErrorFirstName);
|
||||
} catch (NoSuchElementException e) {
|
||||
return null;
|
||||
try {
|
||||
return getTextFromElement(inputErrorFirstNameDynamic);
|
||||
} catch (NoSuchElementException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +185,11 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
try {
|
||||
return getTextFromElement(inputErrorLastName);
|
||||
} catch (NoSuchElementException e) {
|
||||
return null;
|
||||
try {
|
||||
return getTextFromElement(inputErrorLastNameDynamic);
|
||||
} catch (NoSuchElementException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@ public class AppInitiatedActionUpdateProfileTest extends AbstractAppInitiatedAct
|
|||
@Page
|
||||
protected ErrorPage errorPage;
|
||||
|
||||
protected boolean isDynamicForm() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
}
|
||||
|
@ -203,7 +207,10 @@ public class AppInitiatedActionUpdateProfileTest extends AbstractAppInitiatedAct
|
|||
Assert.assertEquals("New last", updateProfilePage.getLastName());
|
||||
Assert.assertEquals("new@email.com", updateProfilePage.getEmail());
|
||||
|
||||
Assert.assertEquals("Please specify first name.", updateProfilePage.getInputErrors().getFirstNameError());
|
||||
if(isDynamicForm())
|
||||
Assert.assertEquals("Please specify this field.", updateProfilePage.getInputErrors().getFirstNameError());
|
||||
else
|
||||
Assert.assertEquals("Please specify first name.", updateProfilePage.getInputErrors().getFirstNameError());
|
||||
|
||||
events.assertEmpty();
|
||||
}
|
||||
|
@ -225,7 +232,10 @@ public class AppInitiatedActionUpdateProfileTest extends AbstractAppInitiatedAct
|
|||
Assert.assertEquals("", updateProfilePage.getLastName());
|
||||
Assert.assertEquals("new@email.com", updateProfilePage.getEmail());
|
||||
|
||||
Assert.assertEquals("Please specify last name.", updateProfilePage.getInputErrors().getLastNameError());
|
||||
if(isDynamicForm())
|
||||
Assert.assertEquals("Please specify this field.", updateProfilePage.getInputErrors().getLastNameError());
|
||||
else
|
||||
Assert.assertEquals("Please specify last name.", updateProfilePage.getInputErrors().getLastNameError());
|
||||
|
||||
events.assertEmpty();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2021 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.testsuite.actions;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.forms.VerifyProfileTest;
|
||||
|
||||
/**
|
||||
* Only covers basic use cases for App Initialized actions. Complete dynamic user profile behavior is tested in {@link RequiredActionUpdateProfileWithUserProfileTest} as it shares same code as the App initialized action.
|
||||
*
|
||||
* @author Vlastimil Elias <velias@redhat.com>
|
||||
*
|
||||
*/
|
||||
public class AppInitiatedActionUpdateProfileWithUserProfileTest extends AppInitiatedActionUpdateProfileTest {
|
||||
|
||||
@Override
|
||||
protected boolean isDynamicForm() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
super.configureTestRealm(testRealm);
|
||||
VerifyProfileTest.enableDynamicUserProfile(testRealm);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeTest() {
|
||||
VerifyProfileTest.setUserProfileConfiguration(testRealm(),null);
|
||||
super.beforeTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -63,6 +63,10 @@ public class RequiredActionUpdateProfileTest extends AbstractTestRealmKeycloakTe
|
|||
|
||||
@Page
|
||||
protected ErrorPage errorPage;
|
||||
|
||||
protected boolean isDynamicForm() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
|
@ -166,7 +170,10 @@ public class RequiredActionUpdateProfileTest extends AbstractTestRealmKeycloakTe
|
|||
Assert.assertEquals("New last", updateProfilePage.getLastName());
|
||||
Assert.assertEquals("new@email.com", updateProfilePage.getEmail());
|
||||
|
||||
Assert.assertEquals("Please specify first name.", updateProfilePage.getInputErrors().getFirstNameError());
|
||||
if(isDynamicForm())
|
||||
Assert.assertEquals("Please specify this field.", updateProfilePage.getInputErrors().getFirstNameError());
|
||||
else
|
||||
Assert.assertEquals("Please specify first name.", updateProfilePage.getInputErrors().getFirstNameError());
|
||||
|
||||
events.assertEmpty();
|
||||
}
|
||||
|
@ -188,7 +195,10 @@ public class RequiredActionUpdateProfileTest extends AbstractTestRealmKeycloakTe
|
|||
Assert.assertEquals("", updateProfilePage.getLastName());
|
||||
Assert.assertEquals("new@email.com", updateProfilePage.getEmail());
|
||||
|
||||
Assert.assertEquals("Please specify last name.", updateProfilePage.getInputErrors().getLastNameError());
|
||||
if(isDynamicForm())
|
||||
Assert.assertEquals("Please specify this field.", updateProfilePage.getInputErrors().getLastNameError());
|
||||
else
|
||||
Assert.assertEquals("Please specify last name.", updateProfilePage.getInputErrors().getLastNameError());
|
||||
|
||||
events.assertEmpty();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* Copyright 2021 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.testsuite.actions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.PERMISSIONS_ALL;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.PERMISSIONS_ADMIN_EDITABLE;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.PERMISSIONS_ADMIN_ONLY;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.SCOPE_DEPARTMENT;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.VALIDATIONS_LENGTH;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.ATTRIBUTE_DEPARTMENT;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.CONFIGURATION_FOR_USER_EDIT;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.forms.VerifyProfileTest;
|
||||
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
||||
import org.keycloak.testsuite.util.ClientScopeBuilder;
|
||||
import org.keycloak.testsuite.util.KeycloakModelUtils;
|
||||
import org.openqa.selenium.By;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Vlastimil Elias <velias@redhat.com>
|
||||
*
|
||||
*/
|
||||
public class RequiredActionUpdateProfileWithUserProfileTest extends RequiredActionUpdateProfileTest {
|
||||
|
||||
protected static final String PASSWORD = "password";
|
||||
protected static final String USERNAME1 = "test-user@localhost";
|
||||
|
||||
private static ClientRepresentation client_scope_default;
|
||||
private static ClientRepresentation client_scope_optional;
|
||||
|
||||
@Override
|
||||
protected boolean isDynamicForm() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
super.configureTestRealm(testRealm);
|
||||
|
||||
VerifyProfileTest.enableDynamicUserProfile(testRealm);
|
||||
|
||||
testRealm.setClientScopes(new ArrayList<>());
|
||||
testRealm.getClientScopes().add(ClientScopeBuilder.create().name(SCOPE_DEPARTMENT).protocol("openid-connect").build());
|
||||
testRealm.getClientScopes().add(ClientScopeBuilder.create().name("profile").protocol("openid-connect").build());
|
||||
|
||||
client_scope_default = KeycloakModelUtils.createClient(testRealm, "client-a");
|
||||
client_scope_default.setDefaultClientScopes(Collections.singletonList(SCOPE_DEPARTMENT));
|
||||
client_scope_default.setRedirectUris(Collections.singletonList("*"));
|
||||
client_scope_optional = KeycloakModelUtils.createClient(testRealm, "client-b");
|
||||
client_scope_optional.setOptionalClientScopes(Collections.singletonList(SCOPE_DEPARTMENT));
|
||||
client_scope_optional.setRedirectUris(Collections.singletonList("*"));
|
||||
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeTest() {
|
||||
VerifyProfileTest.setUserProfileConfiguration(testRealm(),null);
|
||||
super.beforeTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisplayName() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\",\"displayName\":\"${firstName}\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\", \"displayName\" : \"Department\", " + PERMISSIONS_ALL + ", \"required\":{}}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//assert field names
|
||||
// i18n replaced
|
||||
Assert.assertEquals("First name",updateProfilePage.getLabelForField("firstName"));
|
||||
// attribute name used if no display name set
|
||||
Assert.assertEquals("lastName",updateProfilePage.getLabelForField("lastName"));
|
||||
// direct value in display name
|
||||
Assert.assertEquals("Department",updateProfilePage.getLabelForField("department"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeGuiOrder() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\", " + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}},"
|
||||
+ "{\"name\": \"username\", " + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"email\", " + VerifyProfileTest.PERMISSIONS_ALL + "}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//assert fields location in form
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(1) > div:nth-child(2) > input#lastName")
|
||||
).isDisplayed()
|
||||
);
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(2) > div:nth-child(2) > input#department")
|
||||
).isDisplayed()
|
||||
);
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(3) > div:nth-child(2) > input#username")
|
||||
).isDisplayed()
|
||||
);
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(4) > div:nth-child(2) > input#firstName")
|
||||
).isDisplayed()
|
||||
);
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(5) > div:nth-child(2) > input#email")
|
||||
).isDisplayed()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernameOnlyIfEditAllowed() {
|
||||
RealmRepresentation realm = testRealm().toRepresentation();
|
||||
|
||||
boolean r = realm.isEditUsernameAllowed();
|
||||
try {
|
||||
realm.setEditUsernameAllowed(false);
|
||||
testRealm().update(realm);
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
assertFalse(updateProfilePage.isUsernamePresent());
|
||||
|
||||
realm.setEditUsernameAllowed(true);
|
||||
testRealm().update(realm);
|
||||
|
||||
driver.navigate().refresh();
|
||||
assertTrue(updateProfilePage.isUsernamePresent());
|
||||
} finally {
|
||||
realm.setEditUsernameAllowed(r);
|
||||
testRealm().update(realm);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalAttribute() {
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
assertFalse(updateProfilePage.isCancelDisplayed());
|
||||
|
||||
updateProfilePage.update("New first", "", "new@email.com", USERNAME1);
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PROFILE).detail(Details.PREVIOUS_FIRST_NAME, "Tom").detail(Details.UPDATED_FIRST_NAME, "New first")
|
||||
.detail(Details.PREVIOUS_LAST_NAME, "Brady")
|
||||
.detail(Details.PREVIOUS_EMAIL, USERNAME1).detail(Details.UPDATED_EMAIL, "new@email.com")
|
||||
.assertEvent();
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
events.expectLogin().assertEvent();
|
||||
|
||||
// assert user is really updated in persistent store
|
||||
UserRepresentation user = ActionUtil.findUserWithAdminClient(adminClient, USERNAME1);
|
||||
Assert.assertEquals("New first", user.getFirstName());
|
||||
Assert.assertEquals("", user.getLastName());
|
||||
Assert.assertEquals("new@email.com", user.getEmail());
|
||||
Assert.assertEquals(USERNAME1, user.getUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomValidationLastName() {
|
||||
|
||||
setUserProfileConfiguration(CONFIGURATION_FOR_USER_EDIT);
|
||||
updateUserByUsername(USERNAME1, "ExistingFirst", "La", "Department");
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL +","+VALIDATIONS_LENGTH + "},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ADMIN_ONLY + "}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
//submit with error
|
||||
updateProfilePage.update("First", "L", USERNAME1, USERNAME1);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
//submit OK
|
||||
updateProfilePage.update("First", "Last", USERNAME1, USERNAME1);
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername(USERNAME1);
|
||||
assertEquals("First", user.getFirstName());
|
||||
assertEquals("Last", user.getLastName());
|
||||
//check that not configured attribute is unchanged
|
||||
assertEquals("Department", user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredReadOnlyAttribute() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ADMIN_EDITABLE + ", \"required\":{}}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
Assert.assertEquals("Brady", updateProfilePage.getLastName());
|
||||
Assert.assertFalse(updateProfilePage.isDepartmentEnabled());
|
||||
|
||||
//update of the other attributes must be successful in this case
|
||||
updateProfilePage.update("First", "Last", USERNAME1, USERNAME1);
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername(USERNAME1);
|
||||
assertEquals("First", user.getFirstName());
|
||||
assertEquals("Last", user.getLastName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeNotVisible() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ADMIN_ONLY + ", \"required\":{}}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
Assert.assertEquals("Brady", updateProfilePage.getLastName());
|
||||
Assert.assertFalse("'department' field is visible" , updateProfilePage.isDepartmentPresent());
|
||||
|
||||
//update of the other attributes must be successful in this case
|
||||
updateProfilePage.update("First", "Last", USERNAME1, USERNAME1);
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername(USERNAME1);
|
||||
assertEquals("First", user.getFirstName());
|
||||
assertEquals("Last", user.getLastName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredAttribute() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{}}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//submit with error
|
||||
updateProfilePage.updateWithDepartment("FirstCC", "LastCC", "", USERNAME1, USERNAME1);
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//submit OK
|
||||
updateProfilePage.updateWithDepartment("FirstCC", "LastCC", "DepartmentCC", USERNAME1, USERNAME1);
|
||||
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername(USERNAME1);
|
||||
assertEquals("FirstCC", user.getFirstName());
|
||||
assertEquals("LastCC", user.getLastName());
|
||||
assertEquals("DepartmentCC", user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeRequiredForScope() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.scope(SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
|
||||
loginPage.assertCurrent();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//submit with error
|
||||
updateProfilePage.updateWithDepartment("FirstCC", "LastCC", "", USERNAME1, USERNAME1);
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//submit OK
|
||||
updateProfilePage.updateWithDepartment("FirstCC", "LastCC", "DepartmentCC", USERNAME1, USERNAME1);
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername(USERNAME1);
|
||||
assertEquals("FirstCC", user.getFirstName());
|
||||
assertEquals("LastCC", user.getLastName());
|
||||
assertEquals("DepartmentCC", user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeRequiredForDefaultScope() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.clientId(client_scope_default.getClientId()).openLoginForm();
|
||||
|
||||
loginPage.assertCurrent();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//submit with error
|
||||
updateProfilePage.updateWithDepartment("FirstCC", "LastCC", "", USERNAME1, USERNAME1);
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//submit OK
|
||||
updateProfilePage.updateWithDepartment("FirstCC", "LastCC", "DepartmentCC", USERNAME1, USERNAME1);
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername(USERNAME1);
|
||||
assertEquals("FirstCC", user.getFirstName());
|
||||
assertEquals("LastCC", user.getLastName());
|
||||
assertEquals("DepartmentCC", user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeRequiredAndSelectedByScope() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.scope(SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
|
||||
loginPage.assertCurrent();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//submit with error
|
||||
updateProfilePage.updateWithDepartment("FirstCC", "LastCC", "", USERNAME1, USERNAME1);
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
//submit OK
|
||||
updateProfilePage.updateWithDepartment("FirstCC", "LastCC", "DepartmentCC", USERNAME1, USERNAME1);
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername(USERNAME1);
|
||||
assertEquals("FirstCC", user.getFirstName());
|
||||
assertEquals("LastCC", user.getLastName());
|
||||
assertEquals("DepartmentCC", user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeNotRequiredAndSelectedByScopeCanBeUpdated() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.scope(SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
|
||||
loginPage.assertCurrent();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
Assert.assertTrue(updateProfilePage.isDepartmentPresent());
|
||||
updateProfilePage.updateWithDepartment("FirstCC", "LastCC", "DepartmentCC", USERNAME1, USERNAME1);
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername(USERNAME1);
|
||||
assertEquals("FirstCC", user.getFirstName());
|
||||
assertEquals("LastCC", user.getLastName());
|
||||
assertEquals("DepartmentCC", user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeRequiredButNotSelectedByScopeIsNotRendered() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
|
||||
loginPage.assertCurrent();
|
||||
loginPage.login(USERNAME1, PASSWORD);
|
||||
|
||||
updateProfilePage.assertCurrent();
|
||||
|
||||
Assert.assertFalse(updateProfilePage.isDepartmentPresent());
|
||||
updateProfilePage.update("FirstCC", "LastCC", USERNAME1, USERNAME1);
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername(USERNAME1);
|
||||
assertEquals("FirstCC", user.getFirstName());
|
||||
assertEquals("LastCC", user.getLastName());
|
||||
}
|
||||
|
||||
protected void setUserProfileConfiguration(String configuration) {
|
||||
VerifyProfileTest.setUserProfileConfiguration(testRealm(), configuration);
|
||||
}
|
||||
|
||||
protected UserRepresentation getUserByUsername(String username) {
|
||||
return VerifyProfileTest.getUserByUsername(testRealm(), username);
|
||||
}
|
||||
|
||||
protected void updateUserByUsername(String username, String firstName, String lastName, String department) {
|
||||
UserRepresentation ur = getUserByUsername(username);
|
||||
ur.setFirstName(firstName);
|
||||
ur.setLastName(lastName);
|
||||
ur.singleAttribute(ATTRIBUTE_DEPARTMENT, department);
|
||||
testRealm().users().get(ur.getId()).update(ur);
|
||||
}
|
||||
|
||||
}
|
|
@ -17,104 +17,76 @@
|
|||
package org.keycloak.testsuite.forms;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER_PROFILE_ENABLED;
|
||||
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.PERMISSIONS_ALL;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.PERMISSIONS_ADMIN_EDITABLE;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.SCOPE_DEPARTMENT;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.VALIDATIONS_LENGTH;
|
||||
import static org.keycloak.testsuite.forms.VerifyProfileTest.ATTRIBUTE_DEPARTMENT;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.RegisterPage;
|
||||
import org.keycloak.testsuite.pages.VerifyEmailPage;
|
||||
import org.keycloak.testsuite.util.ClientScopeBuilder;
|
||||
import org.keycloak.testsuite.util.GreenMailRule;
|
||||
import org.keycloak.testsuite.util.KeycloakModelUtils;
|
||||
import org.openqa.selenium.By;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
|
||||
* @author Vlastimil Elias <velias@redhat.com>
|
||||
*/
|
||||
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
||||
public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
@Page
|
||||
protected AppPage appPage;
|
||||
|
||||
@Page
|
||||
protected LoginPage loginPage;
|
||||
|
||||
@Page
|
||||
protected RegisterPage registerPage;
|
||||
|
||||
@Page
|
||||
protected VerifyEmailPage verifyEmailPage;
|
||||
|
||||
@Page
|
||||
protected AccountUpdateProfilePage accountPage;
|
||||
|
||||
@Rule
|
||||
public GreenMailRule greenMail = new GreenMailRule();
|
||||
|
||||
public class RegisterWithUserProfileTest extends RegisterTest {
|
||||
|
||||
private static final String SCOPE_LAST_NAME = "lastName";
|
||||
|
||||
private static ClientRepresentation client_scope_default;
|
||||
private static ClientRepresentation client_scope_optional;
|
||||
|
||||
public static String UP_CONFIG_BASIC_ATTRIBUTES = "{\"name\": \"username\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"email\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},";
|
||||
public static String UP_CONFIG_BASIC_ATTRIBUTES = "{\"name\": \"username\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"email\"," + PERMISSIONS_ALL + ", \"required\": {}},";
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
|
||||
super.configureTestRealm(testRealm);
|
||||
|
||||
VerifyProfileTest.enableDynamicUserProfile(testRealm);
|
||||
|
||||
testRealm.setClientScopes(new ArrayList<>());
|
||||
testRealm.getClientScopes().add(ClientScopeBuilder.create().name(SCOPE_LAST_NAME).protocol("openid-connect").build());
|
||||
testRealm.getClientScopes().add(ClientScopeBuilder.create().name(VerifyProfileTest.SCOPE_DEPARTMENT).protocol("openid-connect").build());
|
||||
testRealm.getClientScopes().add(ClientScopeBuilder.create().name(SCOPE_DEPARTMENT).protocol("openid-connect").build());
|
||||
|
||||
List<String> scopes = new ArrayList<>();
|
||||
scopes.add(SCOPE_LAST_NAME);
|
||||
scopes.add(VerifyProfileTest.SCOPE_DEPARTMENT);
|
||||
|
||||
scopes.add(SCOPE_DEPARTMENT);
|
||||
|
||||
client_scope_default = KeycloakModelUtils.createClient(testRealm, "client-a");
|
||||
client_scope_default.setDefaultClientScopes(scopes);
|
||||
client_scope_default.setRedirectUris(Collections.singletonList("*"));
|
||||
client_scope_optional = KeycloakModelUtils.createClient(testRealm, "client-b");
|
||||
client_scope_optional.setOptionalClientScopes(scopes);
|
||||
client_scope_optional.setRedirectUris(Collections.singletonList("*"));
|
||||
if (testRealm.getAttributes() == null) {
|
||||
testRealm.setAttributes(new HashMap<>());
|
||||
}
|
||||
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
|
||||
client_scope_optional.setRedirectUris(Collections.singletonList("*"));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeTest() {
|
||||
VerifyProfileTest.setUserProfileConfiguration(testRealm(),null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterUserSuccess_lastNameOptional() {
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ UP_CONFIG_BASIC_ATTRIBUTES
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "}"
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
|
@ -134,8 +106,8 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
public void testRegisterUserSuccess_lastNameRequiredForScope_notRequested() {
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ UP_CONFIG_BASIC_ATTRIBUTES
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_LAST_NAME+"\"]}}"
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_LAST_NAME+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
|
@ -155,8 +127,8 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
public void testRegisterUserSuccess_lastNameRequiredForScope_requested() {
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ UP_CONFIG_BASIC_ATTRIBUTES
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_LAST_NAME+"\"]}}"
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_LAST_NAME+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.scope(SCOPE_LAST_NAME).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
|
@ -181,8 +153,8 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
public void testRegisterUserSuccess_lastNameRequiredForScope_clientDefault() {
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ UP_CONFIG_BASIC_ATTRIBUTES
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_LAST_NAME+"\"]}}"
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\":{\"scopes\":[\""+SCOPE_LAST_NAME+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.clientId(client_scope_default.getClientId()).openLoginForm();
|
||||
|
@ -207,8 +179,8 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
public void testRegisterUserSuccess_lastNameLengthValidation() {
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ UP_CONFIG_BASIC_ATTRIBUTES
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", " + VerifyProfileTest.VALIDATIONS_LENGTH + "}"
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", " + VALIDATIONS_LENGTH + "}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
|
@ -228,8 +200,8 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
public void testRegisterUserInvalidLastNameLength() {
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ UP_CONFIG_BASIC_ATTRIBUTES
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", " + VerifyProfileTest.VALIDATIONS_LENGTH + "}"
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", " + VALIDATIONS_LENGTH + "}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
|
@ -248,10 +220,10 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
@Test
|
||||
public void testAttributeDisplayName() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\",\"displayName\":\"${firstName}\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\", \"displayName\" : \"Department\", " + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}}"
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\",\"displayName\":\"${firstName}\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\", \"displayName\" : \"Department\", " + PERMISSIONS_ALL + ", \"required\":{}}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
|
@ -325,10 +297,10 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
@Test
|
||||
public void testRegisterUserSuccess_requiredReadOnlyAttributeNotRenderedAndNotBlockingRegistration() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\",\"displayName\":\"${firstName}\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\", \"displayName\" : \"Department\", " + VerifyProfileTest.PERMISSIONS_ADMIN_EDITABLE + ", \"required\":{}}"
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\",\"displayName\":\"${firstName}\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\", \"displayName\" : \"Department\", " + PERMISSIONS_ADMIN_EDITABLE + ", \"required\":{}}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
|
@ -349,13 +321,13 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
@Test
|
||||
public void testRegisterUserSuccess_attributeRequiredAndSelectedByScopeMustBeSet() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.scope(VerifyProfileTest.SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
oauth.scope(SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
loginPage.clickRegister();
|
||||
registerPage.assertCurrent();
|
||||
|
||||
|
@ -368,22 +340,22 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
UserRepresentation user = getUserByUsername("attributeRequiredAndSelectedByScopeMustBeSet");
|
||||
UserRepresentation user = VerifyProfileTest.getUserByUsername(testRealm(),"attributeRequiredAndSelectedByScopeMustBeSet");
|
||||
assertEquals("FirstAA", user.getFirstName());
|
||||
assertEquals("LastAA", user.getLastName());
|
||||
assertEquals("DepartmentAA", user.firstAttribute(VerifyProfileTest.ATTRIBUTE_DEPARTMENT));
|
||||
assertEquals("DepartmentAA", user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterUserSuccess_attributeNotRequiredAndSelectedByScopeCanBeIgnored() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.scope(VerifyProfileTest.SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
oauth.scope(SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
loginPage.clickRegister();
|
||||
registerPage.assertCurrent();
|
||||
|
||||
|
@ -397,16 +369,16 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
UserRepresentation user = getUser(userId);
|
||||
assertEquals("FirstAA", user.getFirstName());
|
||||
assertEquals("LastAA", user.getLastName());
|
||||
assertEquals("", user.firstAttribute(VerifyProfileTest.ATTRIBUTE_DEPARTMENT));
|
||||
assertEquals("", user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterUserSuccess_attributeNotRequiredAndSelectedByScopeCanBeSet() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.clientId(client_scope_default.getClientId()).openLoginForm();
|
||||
|
@ -423,16 +395,16 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
UserRepresentation user = getUser(userId);
|
||||
assertEquals("FirstAA", user.getFirstName());
|
||||
assertEquals("LastAA", user.getLastName());
|
||||
assertEquals("Department AA", user.firstAttribute(VerifyProfileTest.ATTRIBUTE_DEPARTMENT));
|
||||
assertEquals("Department AA", user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterUserSuccess_attributeRequiredButNotSelectedByScopeIsNotRenderedAndNotBlockingRegistration() {
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+SCOPE_DEPARTMENT+"\"]}}"
|
||||
+ "]}");
|
||||
|
||||
oauth.clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||
|
@ -449,7 +421,7 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
UserRepresentation user = getUser(userId);
|
||||
assertEquals("FirstAA", user.getFirstName());
|
||||
assertEquals("LastAA", user.getLastName());
|
||||
assertEquals(null, user.firstAttribute(VerifyProfileTest.ATTRIBUTE_DEPARTMENT));
|
||||
assertEquals(null, user.firstAttribute(ATTRIBUTE_DEPARTMENT));
|
||||
}
|
||||
|
||||
|
||||
|
@ -468,21 +440,7 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
assertEquals(lastName, user.getLastName());
|
||||
}
|
||||
|
||||
protected UserRepresentation getUser(String userId) {
|
||||
return testRealm().users().get(userId).toRepresentation();
|
||||
}
|
||||
|
||||
protected UserRepresentation getUserByUsername(String username) {
|
||||
List<UserRepresentation> users = testRealm().users().search(username);
|
||||
if(users!=null && !users.isEmpty())
|
||||
return users.get(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setUserProfileConfiguration(String configuration) {
|
||||
Response r = testRealm().users().userProfile().update(configuration);
|
||||
if (r.getStatus() != 200) {
|
||||
Assert.fail("Configuration not set due to error: " + r.readEntity(String.class));
|
||||
}
|
||||
protected void setUserProfileConfiguration(String configuration) {
|
||||
VerifyProfileTest.setUserProfileConfiguration(testRealm(), configuration);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package org.keycloak.testsuite.forms;
|
||||
|
||||
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER_PROFILE_ENABLED;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class UserProfileRegisterTest extends RegisterTest {
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
super.configureTestRealm(testRealm);
|
||||
|
||||
if (testRealm.getAttributes() == null) {
|
||||
testRealm.setAttributes(new HashMap<>());
|
||||
}
|
||||
|
||||
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import org.junit.Rule;
|
|||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
|
@ -44,7 +45,6 @@ import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
|||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
|
@ -54,11 +54,11 @@ import org.keycloak.testsuite.util.KeycloakModelUtils;
|
|||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
import org.keycloak.testsuite.util.RealmBuilder;
|
||||
import org.keycloak.testsuite.util.UserBuilder;
|
||||
import org.openqa.selenium.By;
|
||||
|
||||
/**
|
||||
* @author Vlastimil Elias <velias@redhat.com>
|
||||
*/
|
||||
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
||||
public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
public static final String SCOPE_DEPARTMENT = "department";
|
||||
|
@ -70,7 +70,7 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
public static String VALIDATIONS_LENGTH = "\"validations\": {\"length\": { \"min\": 3, \"max\": 255 }}";
|
||||
|
||||
private static final String CONFIGURATION_FOR_USER_EDIT = "{\"attributes\": ["
|
||||
public static final String CONFIGURATION_FOR_USER_EDIT = "{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + "}"
|
||||
|
@ -94,6 +94,9 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
|
||||
enableDynamicUserProfile(testRealm);
|
||||
|
||||
UserRepresentation user = UserBuilder.create().id(UUID.randomUUID().toString()).username("login-test").email("login@test.com").enabled(true).password("password").build();
|
||||
userId = user.getId();
|
||||
|
||||
|
@ -134,10 +137,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
client_scope_optional = KeycloakModelUtils.createClient(testRealm, "client-b");
|
||||
client_scope_optional.setOptionalClientScopes(Collections.singletonList(SCOPE_DEPARTMENT));
|
||||
client_scope_optional.setRedirectUris(Collections.singletonList("*"));
|
||||
if (testRealm.getAttributes() == null) {
|
||||
testRealm.setAttributes(new HashMap<>());
|
||||
}
|
||||
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
|
||||
}
|
||||
|
||||
@Rule
|
||||
|
@ -179,9 +178,82 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
Assert.assertEquals("lastName",verifyProfilePage.getLabelForField("lastName"));
|
||||
// direct value in display name
|
||||
Assert.assertEquals("Department",verifyProfilePage.getLabelForField("department"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttributeGuiOrder() {
|
||||
|
||||
setUserProfileConfiguration(CONFIGURATION_FOR_USER_EDIT);
|
||||
updateUser(user5Id, "ExistingFirst", "ExistingLast", null);
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\", " + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}},"
|
||||
+ "{\"name\": \"username\", " + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"email\", " + VerifyProfileTest.PERMISSIONS_ALL + "}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login("login-test5", "password");
|
||||
|
||||
verifyProfilePage.assertCurrent();
|
||||
|
||||
//assert fields location in form
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(1) > div:nth-child(2) > input#lastName")
|
||||
).isDisplayed()
|
||||
);
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(2) > div:nth-child(2) > input#department")
|
||||
).isDisplayed()
|
||||
);
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(3) > div:nth-child(2) > input#username")
|
||||
).isDisplayed()
|
||||
);
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(4) > div:nth-child(2) > input#firstName")
|
||||
).isDisplayed()
|
||||
);
|
||||
Assert.assertTrue(
|
||||
driver.findElement(
|
||||
By.cssSelector("form#kc-update-profile-form > div:nth-child(5) > div:nth-child(2) > input#email")
|
||||
).isDisplayed()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEvents() {
|
||||
|
||||
setUserProfileConfiguration(CONFIGURATION_FOR_USER_EDIT);
|
||||
updateUser(user5Id, "ExistingFirst", "ExistingLast", null);
|
||||
|
||||
setUserProfileConfiguration("{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ALL + ", \"required\": {}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ALL + "},"
|
||||
+ "{\"name\": \"department\", " + PERMISSIONS_ALL + ", \"required\":{}}"
|
||||
+ "]}");
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login("login-test5", "password");
|
||||
|
||||
verifyProfilePage.assertCurrent();
|
||||
//event when form is shown
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).user(user5Id).detail("fields_to_update", "department").assertEvent();
|
||||
|
||||
verifyProfilePage.update("First", "Last", "Department");
|
||||
//event after profile is updated
|
||||
events.expectRequiredAction(EventType.UPDATE_PROFILE).user(user5Id)
|
||||
.detail(Details.PREVIOUS_FIRST_NAME, "ExistingFirst").detail(Details.UPDATED_FIRST_NAME, "First")
|
||||
.detail(Details.PREVIOUS_LAST_NAME, "ExistingLast").detail(Details.UPDATED_LAST_NAME, "Last")
|
||||
.assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultProfile() {
|
||||
setUserProfileConfiguration(null);
|
||||
|
@ -203,8 +275,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).user(userId).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(userId);
|
||||
assertEquals("First", user.getFirstName());
|
||||
assertEquals("Last", user.getLastName());
|
||||
|
@ -214,6 +284,7 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
public void testUsernameOnlyIfEditAllowed() {
|
||||
RealmRepresentation realm = testRealm().toRepresentation();
|
||||
|
||||
boolean r = realm.isEditUsernameAllowed();
|
||||
try {
|
||||
setUserProfileConfiguration(null);
|
||||
|
||||
|
@ -231,7 +302,7 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
driver.navigate().refresh();
|
||||
assertTrue(verifyProfilePage.isUsernamePresent());
|
||||
} finally {
|
||||
realm.setEditUsernameAllowed(false);
|
||||
realm.setEditUsernameAllowed(r);
|
||||
testRealm().update(realm);
|
||||
}
|
||||
}
|
||||
|
@ -252,8 +323,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).user(user2Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user2Id);
|
||||
assertEquals("First", user.getFirstName());
|
||||
assertEquals("", user.getLastName());
|
||||
|
@ -285,8 +354,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).user(user5Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user5Id);
|
||||
assertEquals("First", user.getFirstName());
|
||||
assertEquals("Last", user.getLastName());
|
||||
|
@ -363,8 +430,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).user(user3Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user3Id);
|
||||
assertEquals("First", user.getFirstName());
|
||||
assertEquals("Last", user.getLastName());
|
||||
|
@ -392,8 +457,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).user(user4Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user4Id);
|
||||
assertEquals("First", user.getFirstName());
|
||||
assertEquals("Last", user.getLastName());
|
||||
|
@ -423,12 +486,9 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
//submit OK
|
||||
verifyProfilePage.update("FirstCC", "LastCC", "DepartmentCC");
|
||||
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).user(user5Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user5Id);
|
||||
assertEquals("FirstCC", user.getFirstName());
|
||||
assertEquals("LastCC", user.getLastName());
|
||||
|
@ -463,8 +523,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).user(user5Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user5Id);
|
||||
assertEquals("FirstCC", user.getFirstName());
|
||||
assertEquals("LastCC", user.getLastName());
|
||||
|
@ -516,8 +574,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).client(client_scope_optional).user(user5Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user5Id);
|
||||
assertEquals("FirstAA", user.getFirstName());
|
||||
|
@ -552,8 +608,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).client(client_scope_default).user(user5Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user5Id);
|
||||
assertEquals("FirstBB", user.getFirstName());
|
||||
|
@ -630,8 +684,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).client(client_scope_optional).user(user5Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user5Id);
|
||||
assertEquals("FirstAA", user.getFirstName());
|
||||
|
@ -663,8 +715,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).client(client_scope_optional).user(user5Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user5Id);
|
||||
assertEquals("FirstAA", user.getFirstName());
|
||||
|
@ -696,8 +746,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).client(client_scope_optional).user(user5Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user5Id);
|
||||
assertEquals("FirstAA", user.getFirstName());
|
||||
|
@ -732,8 +780,6 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
|
||||
events.expectRequiredAction(EventType.VERIFY_PROFILE).user(user5Id).assertEvent();
|
||||
|
||||
UserRepresentation user = getUser(user5Id);
|
||||
assertEquals("FirstCC", user.getFirstName());
|
||||
|
@ -761,22 +807,48 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
|||
}
|
||||
|
||||
protected UserRepresentation getUser(String userId) {
|
||||
return testRealm().users().get(userId).toRepresentation();
|
||||
return getUser(testRealm(), userId);
|
||||
}
|
||||
|
||||
protected void updateUser(String userId, String firstName, String lastName, String department) {
|
||||
UserRepresentation ur = testRealm().users().get(userId).toRepresentation();
|
||||
updateUser(testRealm(), userId, firstName, lastName, department);
|
||||
}
|
||||
|
||||
protected void setUserProfileConfiguration(String configuration) {
|
||||
setUserProfileConfiguration(testRealm(), configuration);
|
||||
}
|
||||
|
||||
public static void enableDynamicUserProfile(RealmRepresentation testRealm) {
|
||||
if (testRealm.getAttributes() == null) {
|
||||
testRealm.setAttributes(new HashMap<>());
|
||||
}
|
||||
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
|
||||
}
|
||||
|
||||
public static void setUserProfileConfiguration(RealmResource testRealm, String configuration) {
|
||||
Response r = testRealm.users().userProfile().update(configuration);
|
||||
if (r.getStatus() != 200) {
|
||||
Assert.fail("UserProfile Configuration not set due to error: " + r.readEntity(String.class));
|
||||
}
|
||||
}
|
||||
|
||||
public static UserRepresentation getUser(RealmResource testRealm, String userId) {
|
||||
return testRealm.users().get(userId).toRepresentation();
|
||||
}
|
||||
|
||||
public static UserRepresentation getUserByUsername(RealmResource testRealm, String username) {
|
||||
List<UserRepresentation> users = testRealm.users().search(username);
|
||||
if(users!=null && !users.isEmpty())
|
||||
return users.get(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void updateUser(RealmResource testRealm, String userId, String firstName, String lastName, String department) {
|
||||
UserRepresentation ur = getUser(testRealm, userId);
|
||||
ur.setFirstName(firstName);
|
||||
ur.setLastName(lastName);
|
||||
ur.singleAttribute(ATTRIBUTE_DEPARTMENT, department);
|
||||
testRealm().users().get(userId).update(ur);
|
||||
testRealm.users().get(userId).update(ur);
|
||||
}
|
||||
|
||||
protected void setUserProfileConfiguration(String configuration) {
|
||||
Response r = testRealm().users().userProfile().update(configuration);
|
||||
if (r.getStatus() != 200) {
|
||||
Assert.fail("Configuration not set due to error: " + r.readEntity(String.class));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,72 +1,54 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<#import "user-profile-commons.ftl" as userProfileCommons>
|
||||
<@layout.registrationLayout displayMessage=messagesPerField.exists('global') displayRequiredFields=true; section>
|
||||
<#if section = "header">
|
||||
${msg("registerTitle")}
|
||||
<#elseif section = "form">
|
||||
<form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.registrationAction}" method="post">
|
||||
|
||||
<#list profile.attributes as attribute>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="${attribute.name}" class="${properties.kcLabelClass!}">${advancedMsg(attribute.displayName!'')}</label>
|
||||
<#if attribute.required>*</#if>
|
||||
</div>
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input type="text" id="${attribute.name}" name="${attribute.name}" value="${(attribute.value!'')}"
|
||||
class="${properties.kcInputClass!}"
|
||||
aria-invalid="<#if messagesPerField.existsError('${attribute.name}')>true</#if>"
|
||||
<#if attribute.readOnly>disabled</#if>
|
||||
<#if attribute.autocomplete??>autocomplete="${attribute.autocomplete}"</#if>
|
||||
/>
|
||||
|
||||
<#if messagesPerField.existsError('${attribute.name}')>
|
||||
<span id="input-error-${attribute.name}" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('${attribute.name}'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
<#-- render password fields just under the username or email (if used as username) -->
|
||||
<#if passwordRequired?? && (attribute.name == 'username' || (attribute.name == 'email' && realm.registrationEmailAsUsername))>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label> *
|
||||
</div>
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input type="password" id="password" class="${properties.kcInputClass!}" name="password"
|
||||
autocomplete="new-password"
|
||||
aria-invalid="<#if messagesPerField.existsError('password','password-confirm')>true</#if>"
|
||||
/>
|
||||
|
||||
<#if messagesPerField.existsError('password')>
|
||||
<span id="input-error-password" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('password'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="password-confirm"
|
||||
class="${properties.kcLabelClass!}">${msg("passwordConfirm")}</label> *
|
||||
</div>
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input type="password" id="password-confirm" class="${properties.kcInputClass!}"
|
||||
name="password-confirm"
|
||||
aria-invalid="<#if messagesPerField.existsError('password-confirm')>true</#if>"
|
||||
/>
|
||||
|
||||
<#if messagesPerField.existsError('password-confirm')>
|
||||
<span id="input-error-password-confirm" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('password-confirm'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
</#list>
|
||||
<@userProfileCommons.userProfileFormFields; callback, attribute>
|
||||
<#if callback = "afterField">
|
||||
<#-- render password fields just under the username or email (if used as username) -->
|
||||
<#if passwordRequired?? && (attribute.name == 'username' || (attribute.name == 'email' && realm.registrationEmailAsUsername))>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label> *
|
||||
</div>
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input type="password" id="password" class="${properties.kcInputClass!}" name="password"
|
||||
autocomplete="new-password"
|
||||
aria-invalid="<#if messagesPerField.existsError('password','password-confirm')>true</#if>"
|
||||
/>
|
||||
|
||||
<#if messagesPerField.existsError('password')>
|
||||
<span id="input-error-password" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('password'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="password-confirm"
|
||||
class="${properties.kcLabelClass!}">${msg("passwordConfirm")}</label> *
|
||||
</div>
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input type="password" id="password-confirm" class="${properties.kcInputClass!}"
|
||||
name="password-confirm"
|
||||
aria-invalid="<#if messagesPerField.existsError('password-confirm')>true</#if>"
|
||||
/>
|
||||
|
||||
<#if messagesPerField.existsError('password-confirm')>
|
||||
<span id="input-error-password-confirm" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('password-confirm'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
</#if>
|
||||
</#if>
|
||||
</@userProfileCommons.userProfileFormFields>
|
||||
|
||||
<#if recaptchaRequired??>
|
||||
<div class="form-group">
|
||||
|
|
28
themes/src/main/resources/theme/base/login/update-user-profile.ftl
Executable file
28
themes/src/main/resources/theme/base/login/update-user-profile.ftl
Executable file
|
@ -0,0 +1,28 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<#import "user-profile-commons.ftl" as userProfileCommons>
|
||||
<@layout.registrationLayout displayMessage=messagesPerField.exists('global') displayRequiredFields=true; section>
|
||||
<#if section = "header">
|
||||
${msg("loginProfileTitle")}
|
||||
<#elseif section = "form">
|
||||
<form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
|
||||
|
||||
<@userProfileCommons.userProfileFormFields/>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<#if isAppInitiatedAction??>
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
|
||||
<button class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" type="submit" name="cancel-aia" value="true" />${msg("doCancel")}</button>
|
||||
<#else>
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
|
@ -0,0 +1,26 @@
|
|||
<#macro userProfileFormFields>
|
||||
<#list profile.attributes as attribute>
|
||||
<#nested "beforeField" attribute>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="${attribute.name}" class="${properties.kcLabelClass!}">${advancedMsg(attribute.displayName!'')}</label>
|
||||
<#if attribute.required>*</#if>
|
||||
</div>
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input type="text" id="${attribute.name}" name="${attribute.name}" value="${(attribute.value!'')}"
|
||||
class="${properties.kcInputClass!}"
|
||||
aria-invalid="<#if messagesPerField.existsError('${attribute.name}')>true</#if>"
|
||||
<#if attribute.readOnly>disabled</#if>
|
||||
<#if attribute.autocomplete??>autocomplete="${attribute.autocomplete}"</#if>
|
||||
/>
|
||||
|
||||
<#if messagesPerField.existsError('${attribute.name}')>
|
||||
<span id="input-error-${attribute.name}" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('${attribute.name}'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
<#nested "afterField" attribute>
|
||||
</#list>
|
||||
</#macro>
|
|
@ -1,47 +0,0 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout displayMessage=!messagesPerField.existsError('username','email','firstName','lastName'); section>
|
||||
<#if section = "header">
|
||||
${msg("loginProfileTitle")}
|
||||
<#elseif section = "form">
|
||||
<form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
|
||||
|
||||
<#list profile.attributes as attribute>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="${attribute.name}" class="${properties.kcLabelClass!}">${advancedMsg(attribute.displayName!'')}</label>
|
||||
<#if attribute.required>*</#if>
|
||||
</div>
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input type="text" id="${attribute.name}" name="${attribute.name}" value="${(attribute.value!'')}"
|
||||
class="${properties.kcInputClass!}"
|
||||
aria-invalid="<#if messagesPerField.existsError('${attribute.name}')>true</#if>"
|
||||
<#if attribute.readOnly>disabled</#if>
|
||||
/>
|
||||
|
||||
<#if messagesPerField.existsError('${attribute.name}')>
|
||||
<span id="input-error-${attribute.name}" class="${properties.kcInputErrorMessageClass!}" aria-live="polite">
|
||||
${kcSanitize(messagesPerField.get('${attribute.name}'))?no_esc}
|
||||
</span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
</#list>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<#if isAppInitiatedAction??>
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
|
||||
<button class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" type="submit" name="cancel-aia" value="true" />${msg("doCancel")}</button>
|
||||
<#else>
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}" type="submit" value="${msg("doSubmit")}" />
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
Loading…
Reference in a new issue