Add UP decorator to SSSD provider
Closes https://github.com/keycloak/keycloak/issues/25075 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
dc0455b73c
commit
31b7c9d2c3
6 changed files with 536 additions and 84 deletions
|
@ -33,9 +33,17 @@ import org.keycloak.storage.UserStorageProvider;
|
|||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
import org.keycloak.storage.user.ImportedUserValidation;
|
||||
import org.keycloak.storage.user.UserLookupProvider;
|
||||
import org.keycloak.userprofile.AttributeContext;
|
||||
import org.keycloak.userprofile.AttributeMetadata;
|
||||
import org.keycloak.userprofile.UserProfileContext;
|
||||
import org.keycloak.userprofile.UserProfileDecorator;
|
||||
import org.keycloak.userprofile.UserProfileMetadata;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
|
@ -49,7 +57,8 @@ public class SSSDFederationProvider implements UserStorageProvider,
|
|||
UserLookupProvider,
|
||||
CredentialInputUpdater,
|
||||
CredentialInputValidator,
|
||||
ImportedUserValidation {
|
||||
ImportedUserValidation,
|
||||
UserProfileDecorator {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SSSDFederationProvider.class);
|
||||
|
||||
|
@ -211,4 +220,40 @@ public class SSSDFederationProvider implements UserStorageProvider,
|
|||
public Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decorateUserProfile(RealmModel realm, UserProfileMetadata metadata) {
|
||||
// selector by sssd
|
||||
Predicate<AttributeContext> sssdUsersSelector = attributeContext ->
|
||||
attributeContext.getUser() != null && model.getId().equals(attributeContext.getUser().getFederationLink());
|
||||
|
||||
// condition to view only by admin
|
||||
Predicate<AttributeContext> onlyAdminCondition = context -> metadata.getContext() == UserProfileContext.USER_API;
|
||||
|
||||
// guiOrder if new attributes are needed
|
||||
int guiOrder = (int) metadata.getAttributes().stream()
|
||||
.map(AttributeMetadata::getName)
|
||||
.distinct()
|
||||
.count();
|
||||
|
||||
// firstName, lastName, username and email should be read-only
|
||||
for (String attrName : List.of(UserModel.FIRST_NAME, UserModel.LAST_NAME, UserModel.EMAIL, UserModel.USERNAME)) {
|
||||
List<AttributeMetadata> attrMetadatas = metadata.getAttribute(attrName);
|
||||
if (attrMetadatas.isEmpty()) {
|
||||
logger.debugf("Adding user profile attribute '%s' for sssd provider and context '%s'.", attrName, metadata.getContext());
|
||||
AttributeMetadata sssdAttrMetadata = metadata.addAttribute(attrName, guiOrder++, Collections.emptyList())
|
||||
.addWriteCondition(AttributeMetadata.ALWAYS_FALSE)
|
||||
.addReadCondition(onlyAdminCondition)
|
||||
.setRequired(AttributeMetadata.ALWAYS_FALSE);
|
||||
sssdAttrMetadata.setSelector(sssdUsersSelector);
|
||||
} else {
|
||||
for (AttributeMetadata attrMetadata : attrMetadatas) {
|
||||
logger.debugf("Cloning attribute '%s' as read-only for sssd provider and context '%s'.", attrName, metadata.getContext());
|
||||
AttributeMetadata sssdAttrMetadata = metadata.addAttribute(attrMetadata.clone())
|
||||
.addWriteCondition(AttributeMetadata.ALWAYS_FALSE);
|
||||
sssdAttrMetadata.setSelector(sssdUsersSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.keycloak.testsuite.pages;
|
|||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
import static org.keycloak.testsuite.util.UIUtils.getTextFromElement;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.keycloak.testsuite.util.UIUtils;
|
||||
import org.openqa.selenium.By;
|
||||
|
@ -148,6 +150,7 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
private String lastName;
|
||||
private String department;
|
||||
private String email;
|
||||
private final Map<String, String> other = new LinkedHashMap<>();
|
||||
|
||||
protected Update(LoginUpdateProfilePage page) {
|
||||
this.page = page;
|
||||
|
@ -173,6 +176,11 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Update otherProfileAttribute(String name, String value) {
|
||||
other.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void submit() {
|
||||
if (firstName != null) {
|
||||
page.firstNameInput.clear();
|
||||
|
@ -193,6 +201,14 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
|||
page.emailInput.sendKeys(email);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : other.entrySet()) {
|
||||
WebElement el = page.driver.findElement(By.id(entry.getKey()));
|
||||
if (el != null) {
|
||||
el.clear();
|
||||
el.sendKeys(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
clickLink(page.submitButton);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
<properties>
|
||||
<exclude.sssd>**/sssd/**/*Test.java</exclude.sssd>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright 2023 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.sssd;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.apache.commons.configuration.ConfigurationException;
|
||||
import org.apache.commons.configuration.PropertiesConfiguration;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
||||
/**
|
||||
* <p>Abstract base class for SSSD tests.</p>
|
||||
*
|
||||
* @author rmartinc
|
||||
*/
|
||||
public abstract class AbstractBaseSSSDTest extends AbstractTestRealmKeycloakTest {
|
||||
|
||||
@Page
|
||||
protected LoginPage loginPage;
|
||||
|
||||
@Page
|
||||
protected AppPage appPage;
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
@Page
|
||||
protected LoginUpdateProfilePage updateProfilePage;
|
||||
|
||||
// vars for the configuration of the SSSD installation
|
||||
protected static final String PROVIDER_NAME = "sssd";
|
||||
private static final String sssdConfigPath = "sssd/sssd.properties";
|
||||
private static PropertiesConfiguration sssdConfig;
|
||||
protected static final String DISABLED_USER = "disabled";
|
||||
protected static final String NO_EMAIL_USER = "noemail";
|
||||
protected static final String ADMIN_USER = "admin";
|
||||
|
||||
@BeforeClass
|
||||
public static void loadSSSDConfiguration() throws ConfigurationException {
|
||||
InputStream is = SSSDTest.class.getClassLoader().getResourceAsStream(sssdConfigPath);
|
||||
sssdConfig = new PropertiesConfiguration();
|
||||
sssdConfig.load(is);
|
||||
sssdConfig.setListDelimiter(',');
|
||||
}
|
||||
|
||||
protected void testLoginFailure(String username, String password) {
|
||||
loginPage.open();
|
||||
loginPage.login(username, password);
|
||||
loginPage.assertCurrent();
|
||||
Assert.assertEquals("Invalid username or password.", loginPage.getInputError());
|
||||
events.expect(EventType.LOGIN_ERROR).user(Matchers.any(String.class)).error(Errors.INVALID_USER_CREDENTIALS).assertEvent();
|
||||
}
|
||||
|
||||
protected void testLoginSuccess(String username) {
|
||||
loginPage.open();
|
||||
loginPage.login(username, getPassword(username));
|
||||
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
EventRepresentation loginEvent = events.expectLogin().user(Matchers.any(String.class))
|
||||
.detail(Details.USERNAME, username).assertEvent();
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
appPage.logout(tokenResponse.getIdToken());
|
||||
events.expectLogout(loginEvent.getSessionId()).user(loginEvent.getUserId()).assertEvent();
|
||||
}
|
||||
|
||||
protected String getUsername() {
|
||||
return sssdConfig.getStringArray("usernames")[0];
|
||||
}
|
||||
|
||||
protected String getFirstName(String username) {
|
||||
return sssdConfig.getString("user." + username + ".firstname");
|
||||
}
|
||||
|
||||
protected String getLastName(String username) {
|
||||
return sssdConfig.getString("user." + username + ".lastname");
|
||||
}
|
||||
|
||||
protected String getEmail(String username) {
|
||||
return sssdConfig.getString("user." + username + ".mail");
|
||||
}
|
||||
|
||||
protected String getUser(String type) {
|
||||
return sssdConfig.getString("user." + type);
|
||||
}
|
||||
|
||||
protected List<String> getUsernames() {
|
||||
return Arrays.asList(sssdConfig.getStringArray("usernames"));
|
||||
}
|
||||
|
||||
protected String getPassword(String username) {
|
||||
return sssdConfig.getString("user." + username + ".password");
|
||||
}
|
||||
|
||||
protected List<String> getGroups(String username) {
|
||||
return Arrays.asList(sssdConfig.getStringArray("user." + username + ".groups"));
|
||||
}
|
||||
}
|
|
@ -1,44 +1,43 @@
|
|||
/*
|
||||
* Copyright 2023 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.sssd;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.configuration.ConfigurationException;
|
||||
import org.apache.commons.configuration.PropertiesConfiguration;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.ErrorRepresentation;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -61,45 +60,19 @@ import static org.hamcrest.Matchers.greaterThan;
|
|||
*
|
||||
* @author rmartinc
|
||||
*/
|
||||
public class SSSDTest extends AbstractTestRealmKeycloakTest {
|
||||
public class SSSDTest extends AbstractBaseSSSDTest {
|
||||
|
||||
private static final Logger log = Logger.getLogger(SSSDTest.class);
|
||||
|
||||
private static final String DISPLAY_NAME = "Test user federation";
|
||||
private static final String PROVIDER_NAME = "sssd";
|
||||
private static final String REALM_NAME = "test";
|
||||
|
||||
private static final String sssdConfigPath = "sssd/sssd.properties";
|
||||
|
||||
private static final String DISABLED_USER = "disabled";
|
||||
private static final String NO_EMAIL_USER = "noemail";
|
||||
private static final String ADMIN_USER = "admin";
|
||||
private static PropertiesConfiguration sssdConfig;
|
||||
|
||||
@Page
|
||||
protected LoginPage loginPage;
|
||||
|
||||
@Page
|
||||
protected AppPage appPage;
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
private String SSSDFederationID;
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void loadSSSDConfiguration() throws ConfigurationException {
|
||||
log.info("Reading SSSD configuration from classpath from: " + sssdConfigPath);
|
||||
InputStream is = SSSDTest.class.getClassLoader().getResourceAsStream(sssdConfigPath);
|
||||
sssdConfig = new PropertiesConfiguration();
|
||||
sssdConfig.load(is);
|
||||
sssdConfig.setListDelimiter(',');
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createUserFederation() {
|
||||
ComponentRepresentation userFederation = new ComponentRepresentation();
|
||||
|
@ -117,25 +90,6 @@ public class SSSDTest extends AbstractTestRealmKeycloakTest {
|
|||
}
|
||||
}
|
||||
|
||||
private void testLoginFailure(String username, String password) {
|
||||
loginPage.open();
|
||||
loginPage.login(username, password);
|
||||
loginPage.assertCurrent();
|
||||
Assert.assertEquals("Invalid username or password.", loginPage.getInputError());
|
||||
events.expect(EventType.LOGIN_ERROR).user(Matchers.any(String.class)).error(Errors.INVALID_USER_CREDENTIALS).assertEvent();
|
||||
}
|
||||
|
||||
private void testLoginSuccess(String username) {
|
||||
loginPage.open();
|
||||
loginPage.login(username, getPassword(username));
|
||||
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
EventRepresentation loginEvent = events.expectLogin().user(Matchers.any(String.class))
|
||||
.detail(Details.USERNAME, username).assertEvent();
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
appPage.logout(tokenResponse.getIdToken());
|
||||
events.expectLogout(loginEvent.getSessionId()).user(loginEvent.getUserId()).assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidPassword() {
|
||||
String username = getUsername();
|
||||
|
@ -238,24 +192,4 @@ public class SSSDTest extends AbstractTestRealmKeycloakTest {
|
|||
List<String> assignedGroupNames = assignedGroups.stream().map(GroupRepresentation::getName).collect(Collectors.toList());
|
||||
MatcherAssert.assertThat(assignedGroupNames, Matchers.hasItems(groups.toArray(new String[0])));
|
||||
}
|
||||
|
||||
private String getUsername() {
|
||||
return sssdConfig.getStringArray("usernames")[0];
|
||||
}
|
||||
|
||||
private String getUser(String type) {
|
||||
return sssdConfig.getString("user." + type);
|
||||
}
|
||||
|
||||
private List<String> getUsernames() {
|
||||
return Arrays.asList(sssdConfig.getStringArray("usernames"));
|
||||
}
|
||||
|
||||
private String getPassword(String username) {
|
||||
return sssdConfig.getString("user." + username + ".password");
|
||||
}
|
||||
|
||||
private List<String> getGroups(String username) {
|
||||
return Arrays.asList(sssdConfig.getStringArray("user." + username + ".groups"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* Copyright 2023 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.sssd;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.ComponentExportRepresentation;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserProfileAttributeMetadata;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.userprofile.config.UPAttribute;
|
||||
import org.keycloak.representations.userprofile.config.UPAttributePermissions;
|
||||
import org.keycloak.representations.userprofile.config.UPAttributeRequired;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.forms.VerifyProfileTest;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
import org.keycloak.userprofile.config.UPConfigUtils;
|
||||
|
||||
/**
|
||||
* <p>Test for the User profile integration in the SSSD provider.</p>
|
||||
*
|
||||
* @author rmartinc
|
||||
*/
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
@EnableFeature(value = Profile.Feature.DECLARATIVE_USER_PROFILE)
|
||||
public class SSSDUserProfileTest extends AbstractBaseSSSDTest {
|
||||
|
||||
@Override
|
||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||
// enable user profile and add sssd provider in the realm
|
||||
VerifyProfileTest.enableDynamicUserProfile(testRealm);
|
||||
ComponentExportRepresentation sssdComp = new ComponentExportRepresentation();
|
||||
sssdComp.setName(PROVIDER_NAME);
|
||||
sssdComp.setProviderId(PROVIDER_NAME);
|
||||
MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
|
||||
config.putSingle("cachePolicy", "DEFAULT");
|
||||
config.putSingle("enabled", "true");
|
||||
sssdComp.setConfig(config);
|
||||
|
||||
MultivaluedHashMap<String, ComponentExportRepresentation> components = testRealm.getComponents();
|
||||
if (components == null) {
|
||||
components = new MultivaluedHashMap<>();
|
||||
testRealm.setComponents(components);
|
||||
}
|
||||
|
||||
components.add(UserStorageProvider.class.getName(), sssdComp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test01LoginSuccess() throws Exception {
|
||||
// do a login to create the first sssd user in the configuration
|
||||
testLoginSuccess(getUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test02DefaultSSSDUserProfile() throws Exception {
|
||||
// default configuration adds all sssd attributes
|
||||
// check they are read-only in both admin and user for a SSSD user
|
||||
String username = getUsername();
|
||||
UserResource userResource = ApiUtil.findUserByUsernameId(testRealm(), username);
|
||||
UserRepresentation user = userResource.toRepresentation(true);
|
||||
|
||||
// for admin the four should be read-only
|
||||
String sssdId = getSssdProviderId();
|
||||
assertUser(user, username, getEmail(username), getFirstName(username), getLastName(username), sssdId);
|
||||
assertProfileAttributes(user, null, true, UserModel.USERNAME, UserModel.EMAIL, UserModel.FIRST_NAME, UserModel.LAST_NAME);
|
||||
user.getRequiredActions().add(UserModel.RequiredAction.UPDATE_PROFILE.toString());
|
||||
userResource.update(user);
|
||||
|
||||
// for user the same, the four attrs should be read-only
|
||||
loginPage.open();
|
||||
loginPage.login(username, getPassword(username));
|
||||
WaitUtils.waitForPageToLoad();
|
||||
updateProfilePage.assertCurrent();
|
||||
Assert.assertEquals(getFirstName(username), updateProfilePage.getFirstName());
|
||||
Assert.assertEquals(getLastName(username), updateProfilePage.getLastName());
|
||||
Assert.assertEquals(getEmail(username), updateProfilePage.getEmail());
|
||||
Assert.assertFalse(updateProfilePage.getFieldById(UserModel.FIRST_NAME).isEnabled());
|
||||
Assert.assertFalse(updateProfilePage.getFieldById(UserModel.LAST_NAME).isEnabled());
|
||||
Assert.assertFalse(updateProfilePage.getFieldById(UserModel.EMAIL).isEnabled());
|
||||
Assert.assertFalse(updateProfilePage.getFieldById(UserModel.USERNAME).isEnabled());
|
||||
updateProfilePage.prepareUpdate().submit();
|
||||
|
||||
// check events
|
||||
WaitUtils.waitForPageToLoad();
|
||||
appPage.assertCurrent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PROFILE)
|
||||
.user(user.getId())
|
||||
.assertEvent();
|
||||
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
EventRepresentation loginEvent = events.expectLogin()
|
||||
.user(Matchers.any(String.class))
|
||||
.detail(Details.USERNAME, username)
|
||||
.assertEvent();
|
||||
|
||||
// logout
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
appPage.logout(tokenResponse.getIdToken());
|
||||
events.expectLogout(loginEvent.getSessionId()).user(loginEvent.getUserId()).assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test03DefaultInternalDBUserProfile() throws Exception {
|
||||
// check non sssd user has normal atttributes enabled
|
||||
UserResource testResource = ApiUtil.findUserByUsernameId(testRealm(), "test-user@localhost");
|
||||
UserRepresentation test = testResource.toRepresentation(true);
|
||||
|
||||
// for admin the four should be editable
|
||||
assertUser(test, "test-user@localhost", "test-user@localhost", "Tom", "Brady", null);
|
||||
assertProfileAttributes(test, null, false, UserModel.USERNAME, UserModel.EMAIL, UserModel.FIRST_NAME, UserModel.LAST_NAME);
|
||||
test.getRequiredActions().add(UserModel.RequiredAction.UPDATE_PROFILE.toString());
|
||||
testResource.update(test);
|
||||
|
||||
// for user the same, the four attrs should be editable
|
||||
loginPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
WaitUtils.waitForPageToLoad();
|
||||
updateProfilePage.assertCurrent();
|
||||
Assert.assertEquals("Tom", updateProfilePage.getFirstName());
|
||||
Assert.assertEquals("Brady", updateProfilePage.getLastName());
|
||||
Assert.assertEquals("test-user@localhost", updateProfilePage.getEmail());
|
||||
Assert.assertTrue(updateProfilePage.getFieldById(UserModel.FIRST_NAME).isEnabled());
|
||||
Assert.assertTrue(updateProfilePage.getFieldById(UserModel.LAST_NAME).isEnabled());
|
||||
Assert.assertTrue(updateProfilePage.getFieldById(UserModel.EMAIL).isEnabled());
|
||||
Assert.assertTrue(updateProfilePage.getFieldById(UserModel.USERNAME).isEnabled());
|
||||
updateProfilePage.prepareUpdate().submit();
|
||||
|
||||
// check events
|
||||
WaitUtils.waitForPageToLoad();
|
||||
appPage.assertCurrent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PROFILE)
|
||||
.user(test.getId())
|
||||
.assertEvent();
|
||||
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
EventRepresentation loginEvent = events.expectLogin()
|
||||
.user(Matchers.any(String.class))
|
||||
.detail(Details.USERNAME, "test-user@localhost")
|
||||
.assertEvent();
|
||||
|
||||
// logout
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
appPage.logout(tokenResponse.getIdToken());
|
||||
events.expectLogout(loginEvent.getSessionId()).user(loginEvent.getUserId()).assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test04MixedSSSDUserProfile() throws Exception {
|
||||
RealmResource realm = testRealm();
|
||||
UPConfig origConfig = realm.users().userProfile().getConfiguration();
|
||||
try {
|
||||
createMixedUPConfiguration();
|
||||
|
||||
// for admin all attributes are added as read-only and postal_code remains editable
|
||||
String username = getUsername();
|
||||
String sssdId = getSssdProviderId();
|
||||
UserResource userResource = ApiUtil.findUserByUsernameId(testRealm(), username);
|
||||
UserRepresentation user = userResource.toRepresentation(true);
|
||||
assertUser(user, username, getEmail(username), getFirstName(username), getLastName(username), sssdId);
|
||||
assertProfileAttributes(user, null, true, UserModel.USERNAME, UserModel.EMAIL, UserModel.FIRST_NAME, UserModel.LAST_NAME);
|
||||
assertProfileAttributes(user, null, false, "postal_code");
|
||||
|
||||
// for user, firstName and lastName are not visible, username and email read-only, postal_code editable
|
||||
user.getRequiredActions().add(UserModel.RequiredAction.UPDATE_PROFILE.toString());
|
||||
userResource.update(user);
|
||||
loginPage.open();
|
||||
loginPage.login(username, getPassword(username));
|
||||
WaitUtils.waitForPageToLoad();
|
||||
updateProfilePage.assertCurrent();
|
||||
Assert.assertEquals(getEmail(username), updateProfilePage.getEmail());
|
||||
Assert.assertNull(updateProfilePage.getFieldById(UserModel.FIRST_NAME));
|
||||
Assert.assertNull(updateProfilePage.getFieldById(UserModel.LAST_NAME));
|
||||
Assert.assertFalse(updateProfilePage.getFieldById(UserModel.EMAIL).isEnabled());
|
||||
Assert.assertFalse(updateProfilePage.getFieldById(UserModel.USERNAME).isEnabled());
|
||||
Assert.assertTrue(updateProfilePage.getFieldById("postal_code").isEnabled());
|
||||
updateProfilePage.prepareUpdate().otherProfileAttribute("postal_code", "123456").submit();
|
||||
WaitUtils.waitForPageToLoad();
|
||||
appPage.assertCurrent();
|
||||
|
||||
// check events
|
||||
events.expectRequiredAction(EventType.UPDATE_PROFILE)
|
||||
.user(user.getId())
|
||||
.detail("updated_postal_code", "123456")
|
||||
.assertEvent();
|
||||
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
EventRepresentation loginEvent = events.expectLogin()
|
||||
.user(Matchers.any(String.class))
|
||||
.detail(Details.USERNAME, username)
|
||||
.assertEvent();
|
||||
|
||||
// logout
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
appPage.logout(tokenResponse.getIdToken());
|
||||
events.expectLogout(loginEvent.getSessionId()).user(loginEvent.getUserId()).assertEvent();
|
||||
} finally {
|
||||
realm.users().userProfile().update(origConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test05MixedInternalDBUserProfile() throws Exception {
|
||||
RealmResource realm = testRealm();
|
||||
UPConfig origConfig = realm.users().userProfile().getConfiguration();
|
||||
try {
|
||||
createMixedUPConfiguration();
|
||||
|
||||
// for admin firstName and lastName remains removed, the rest editable
|
||||
UserResource testResource = ApiUtil.findUserByUsernameId(testRealm(), "test-user@localhost");
|
||||
UserRepresentation test = testResource.toRepresentation(true);
|
||||
assertUser(test, "test-user@localhost", "test-user@localhost", "Tom", "Brady", null);
|
||||
assertProfileAttributes(test, null, false, "username", "email", "postal_code");
|
||||
Assert.assertNull(test.getUserProfileMetadata().getAttributeMetadata(UserModel.FIRST_NAME));
|
||||
Assert.assertNull(test.getUserProfileMetadata().getAttributeMetadata(UserModel.LAST_NAME));
|
||||
|
||||
// for user, firstName and lastName are not visible, username, email read-only and postal_code editable
|
||||
test.getRequiredActions().add(UserModel.RequiredAction.UPDATE_PROFILE.toString());
|
||||
testResource.update(test);
|
||||
loginPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
WaitUtils.waitForPageToLoad();
|
||||
updateProfilePage.assertCurrent();
|
||||
Assert.assertEquals("test-user@localhost", updateProfilePage.getEmail());
|
||||
Assert.assertNull(updateProfilePage.getFieldById(UserModel.FIRST_NAME));
|
||||
Assert.assertNull(updateProfilePage.getFieldById(UserModel.LAST_NAME));
|
||||
Assert.assertTrue(updateProfilePage.getFieldById(UserModel.EMAIL).isEnabled());
|
||||
Assert.assertTrue(updateProfilePage.getFieldById(UserModel.USERNAME).isEnabled());
|
||||
Assert.assertTrue(updateProfilePage.getFieldById("postal_code").isEnabled());
|
||||
updateProfilePage.prepareUpdate().otherProfileAttribute("postal_code", "123456").submit();
|
||||
WaitUtils.waitForPageToLoad();
|
||||
appPage.assertCurrent();
|
||||
|
||||
// check events
|
||||
events.expectRequiredAction(EventType.UPDATE_PROFILE)
|
||||
.user(test.getId())
|
||||
.detail("updated_postal_code", "123456")
|
||||
.assertEvent();
|
||||
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
EventRepresentation loginEvent = events.expectLogin()
|
||||
.user(Matchers.any(String.class))
|
||||
.detail(Details.USERNAME, "test-user@localhost")
|
||||
.assertEvent();
|
||||
|
||||
// logout
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
appPage.logout(tokenResponse.getIdToken());
|
||||
events.expectLogout(loginEvent.getSessionId()).user(loginEvent.getUserId()).assertEvent();
|
||||
} finally {
|
||||
realm.users().userProfile().update(origConfig);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertUser(UserRepresentation user, String expectedUsername, String expectedEmail,
|
||||
String expectedFirstName, String expectedLastname, String sssdId) {
|
||||
Assert.assertNotNull(user);
|
||||
Assert.assertEquals(expectedUsername, user.getUsername());
|
||||
Assert.assertEquals(expectedFirstName, user.getFirstName());
|
||||
Assert.assertEquals(expectedLastname, user.getLastName());
|
||||
Assert.assertEquals(expectedEmail, user.getEmail());
|
||||
Assert.assertEquals(sssdId, user.getFederationLink());
|
||||
}
|
||||
|
||||
private void assertProfileAttributes(UserRepresentation user, String expectedGroup, boolean expectReadOnly, String... attributes) {
|
||||
for (String attrName : attributes) {
|
||||
UserProfileAttributeMetadata attrMetadata = user.getUserProfileMetadata().getAttributeMetadata(attrName);
|
||||
Assert.assertNotNull("Attribute " + attrName + " was not present for user " + user.getUsername(), attrMetadata);
|
||||
Assert.assertEquals("Attribute " + attrName + " for user " + user.getUsername() + ". Expected read-only: " + expectReadOnly + " but was not", expectReadOnly, attrMetadata.isReadOnly());
|
||||
Assert.assertEquals("Attribute " + attrName + " for user " + user.getUsername() + ". Expected group: " + expectedGroup + " but was " + attrMetadata.getGroup(), expectedGroup, attrMetadata.getGroup());
|
||||
}
|
||||
}
|
||||
|
||||
private String getSssdProviderId() {
|
||||
List<ComponentRepresentation> comps = testRealm().components()
|
||||
.query(TEST_REALM_NAME, UserStorageProvider.class.getName(), PROVIDER_NAME);
|
||||
Assert.assertEquals(1, comps.size());
|
||||
return comps.iterator().next().getId();
|
||||
}
|
||||
|
||||
private void createMixedUPConfiguration() {
|
||||
// removes firstName and lastName, adds a custom postal_code
|
||||
RealmResource realm = testRealm();
|
||||
UPConfig config = realm.users().userProfile().getConfiguration();
|
||||
config.getAttributes().remove(config.getAttribute(UserModel.FIRST_NAME));
|
||||
config.getAttributes().remove(config.getAttribute(UserModel.LAST_NAME));
|
||||
UPAttribute postalCode = new UPAttribute();
|
||||
postalCode.setName("postal_code");
|
||||
postalCode.setDisplayName("Postal Code");
|
||||
UPAttributePermissions permissions = new UPAttributePermissions();
|
||||
permissions.setView(Set.of(UPConfigUtils.ROLE_USER, UPConfigUtils.ROLE_ADMIN));
|
||||
permissions.setEdit(Set.of(UPConfigUtils.ROLE_USER, UPConfigUtils.ROLE_ADMIN));
|
||||
postalCode.setPermissions(permissions);
|
||||
UPAttributeRequired required = new UPAttributeRequired();
|
||||
required.setRoles(Set.of(UPConfigUtils.ROLE_USER));
|
||||
postalCode.setRequired(required);
|
||||
config.getAttributes().add(postalCode);
|
||||
realm.users().userProfile().update(config);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue