Repsect permissions configured to firstName and lastName when configured in user profile
Resolves #12109
This commit is contained in:
parent
c4001ba198
commit
3c19ad627f
3 changed files with 140 additions and 51 deletions
|
@ -27,7 +27,9 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -146,23 +148,35 @@ public class AccountRestService {
|
|||
|
||||
UserRepresentation rep = new UserRepresentation();
|
||||
rep.setId(user.getId());
|
||||
rep.setUsername(user.getUsername());
|
||||
rep.setFirstName(user.getFirstName());
|
||||
rep.setLastName(user.getLastName());
|
||||
rep.setEmail(user.getEmail());
|
||||
rep.setEmailVerified(user.isEmailVerified());
|
||||
|
||||
UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
|
||||
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user);
|
||||
|
||||
rep.setAttributes(profile.getAttributes().getReadable(false));
|
||||
|
||||
addReadableBuiltinAttributes(user, rep, profile.getAttributes().getReadable(true).keySet());
|
||||
|
||||
if(userProfileMetadata == null || userProfileMetadata.booleanValue())
|
||||
rep.setUserProfileMetadata(createUserProfileMetadata(profile));
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
private void addReadableBuiltinAttributes(UserModel user, UserRepresentation rep, Set<String> readableAttributes) {
|
||||
setIfReadable(UserModel.USERNAME, readableAttributes, rep::setUsername, user::getUsername);
|
||||
setIfReadable(UserModel.FIRST_NAME, readableAttributes, rep::setFirstName, user::getFirstName);
|
||||
setIfReadable(UserModel.LAST_NAME, readableAttributes, rep::setLastName, user::getLastName);
|
||||
setIfReadable(UserModel.EMAIL, readableAttributes, rep::setEmail, user::getEmail);
|
||||
// emailVerified is readable when email is readable
|
||||
setIfReadable(UserModel.EMAIL, readableAttributes, rep::setEmailVerified, user::isEmailVerified);
|
||||
}
|
||||
|
||||
private <T> void setIfReadable(String attributeName, Set<String> readableAttributes, Consumer<T> setter, Supplier<T> getter) {
|
||||
if (readableAttributes.contains(attributeName)) {
|
||||
setter.accept(getter.get());
|
||||
}
|
||||
}
|
||||
|
||||
private UserProfileMetadata createUserProfileMetadata(final UserProfile profile) {
|
||||
Map<String, List<String>> am = profile.getAttributes().getReadable();
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
|||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.forms.VerifyProfileTest;
|
||||
import org.keycloak.userprofile.UserProfileContext;
|
||||
import org.keycloak.userprofile.EventAuditingAttributeChangeListener;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -79,6 +78,21 @@ public class AccountRestServiceWithUserProfileTest extends AccountRestServiceTes
|
|||
+ "{\"name\": \"attr_no_permission\"," + PERMISSIONS_ADMIN_ONLY + "}"
|
||||
+ "]}";
|
||||
|
||||
private static String UP_CONFIG_NO_ACCESS_TO_NAME_FIELDS = "{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ADMIN_ONLY + ", \"required\": {}, \"displayName\": \"${profile.firstName}\", \"validations\": {\"length\": { \"max\": 255 }}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ADMIN_ONLY + ", \"required\": {}, \"displayName\": \"Last name\", \"annotations\": {\"formHintKey\" : \"userEmailFormFieldHint\", \"anotherKey\" : 10, \"yetAnotherKey\" : \"some value\"}},"
|
||||
+ "{\"name\": \"attr_readonly\"," + PERMISSIONS_ADMIN_EDITABLE + "},"
|
||||
+ "{\"name\": \"attr_no_permission\"," + PERMISSIONS_ADMIN_ONLY + "}"
|
||||
+ "]}";
|
||||
|
||||
private static String UP_CONFIG_RO_ACCESS_TO_NAME_FIELDS = "{\"attributes\": ["
|
||||
+ "{\"name\": \"firstName\"," + PERMISSIONS_ADMIN_EDITABLE + ", \"required\": {}, \"displayName\": \"${profile.firstName}\", \"validations\": {\"length\": { \"max\": 255 }}},"
|
||||
+ "{\"name\": \"lastName\"," + PERMISSIONS_ADMIN_EDITABLE + ", \"required\": {}, \"displayName\": \"Last name\", \"annotations\": {\"formHintKey\" : \"userEmailFormFieldHint\", \"anotherKey\" : 10, \"yetAnotherKey\" : \"some value\"}},"
|
||||
+ "{\"name\": \"attr_readonly\"," + PERMISSIONS_ADMIN_EDITABLE + "},"
|
||||
+ "{\"name\": \"attr_no_permission\"," + PERMISSIONS_ADMIN_ONLY + "}"
|
||||
+ "]}";
|
||||
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testGetUserProfileMetadata_EditUsernameAllowed() throws IOException {
|
||||
|
@ -115,6 +129,65 @@ public class AccountRestServiceWithUserProfileTest extends AccountRestServiceTes
|
|||
assertNull(getUserProfileAttributeMetadata(user, "attr_no_permission"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserProfileMetadata_NoAccessToNameFields() throws IOException {
|
||||
|
||||
try {
|
||||
RealmRepresentation realmRep = adminClient.realm("test").toRepresentation();
|
||||
realmRep.setEditUsernameAllowed(false);
|
||||
adminClient.realm("test").update(realmRep);
|
||||
|
||||
setUserProfileConfiguration(UP_CONFIG_NO_ACCESS_TO_NAME_FIELDS);
|
||||
|
||||
UserRepresentation user = getUser();
|
||||
assertNotNull(user.getUserProfileMetadata());
|
||||
|
||||
assertUserProfileAttributeMetadata(user, "username", "${username}", true, true);
|
||||
assertUserProfileAttributeMetadata(user, "email", "${email}", true, false);
|
||||
|
||||
assertNull(getUserProfileAttributeMetadata(user, "firstName"));
|
||||
assertNull(getUserProfileAttributeMetadata(user, "lastName"));
|
||||
assertUserProfileAttributeMetadata(user, "attr_readonly", "attr_readonly", false, true);
|
||||
|
||||
assertNull(getUserProfileAttributeMetadata(user, "attr_no_permission"));
|
||||
|
||||
} finally {
|
||||
RealmRepresentation realmRep = testRealm().toRepresentation();
|
||||
realmRep.setEditUsernameAllowed(true);
|
||||
testRealm().update(realmRep);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUserProfileMetadata_RoAccessToNameFields() throws IOException {
|
||||
|
||||
try {
|
||||
RealmRepresentation realmRep = adminClient.realm("test").toRepresentation();
|
||||
realmRep.setEditUsernameAllowed(false);
|
||||
adminClient.realm("test").update(realmRep);
|
||||
|
||||
setUserProfileConfiguration(UP_CONFIG_RO_ACCESS_TO_NAME_FIELDS);
|
||||
|
||||
UserRepresentation user = getUser();
|
||||
assertNotNull(user.getUserProfileMetadata());
|
||||
|
||||
assertUserProfileAttributeMetadata(user, "username", "${username}", true, true);
|
||||
assertUserProfileAttributeMetadata(user, "email", "${email}", true, false);
|
||||
|
||||
assertUserProfileAttributeMetadata(user, "firstName", "${profile.firstName}", true, true);
|
||||
assertUserProfileAttributeMetadata(user, "lastName", "Last name", true, true);
|
||||
assertUserProfileAttributeMetadata(user, "attr_readonly", "attr_readonly", false, true);
|
||||
|
||||
assertNull(getUserProfileAttributeMetadata(user, "attr_no_permission"));
|
||||
|
||||
} finally {
|
||||
RealmRepresentation realmRep = testRealm().toRepresentation();
|
||||
realmRep.setEditUsernameAllowed(true);
|
||||
testRealm().update(realmRep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Override
|
||||
public void testGetUserProfileMetadata_EditUsernameDisallowed() throws IOException {
|
||||
|
|
|
@ -197,7 +197,7 @@ export class AccountPage extends React.Component<AccountPageProps, AccountPageSt
|
|||
)}
|
||||
</FormGroup>
|
||||
)}
|
||||
{!this.isUpdateEmailFeatureEnabled && <FormGroup
|
||||
{!this.isUpdateEmailFeatureEnabled && fields.email != undefined && <FormGroup
|
||||
label={Msg.localize('email')}
|
||||
fieldId="email-address"
|
||||
helperTextInvalid={this.state.errors.email}
|
||||
|
@ -250,7 +250,7 @@ export class AccountPage extends React.Component<AccountPageProps, AccountPageSt
|
|||
}
|
||||
</InputGroup>
|
||||
</FormGroup> }
|
||||
<FormGroup
|
||||
{ fields.firstName != undefined && <FormGroup
|
||||
label={Msg.localize("firstName")}
|
||||
fieldId="first-name"
|
||||
helperTextInvalid={this.state.errors.firstName}
|
||||
|
@ -275,7 +275,8 @@ export class AccountPage extends React.Component<AccountPageProps, AccountPageSt
|
|||
}
|
||||
></TextInput>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
}
|
||||
{fields.lastName != undefined && <FormGroup
|
||||
label={Msg.localize("lastName")}
|
||||
fieldId="last-name"
|
||||
helperTextInvalid={this.state.errors.lastName}
|
||||
|
@ -300,6 +301,7 @@ export class AccountPage extends React.Component<AccountPageProps, AccountPageSt
|
|||
}
|
||||
></TextInput>
|
||||
</FormGroup>
|
||||
}
|
||||
{features.isInternationalizationEnabled && (
|
||||
<FormGroup
|
||||
label={Msg.localize("selectLocale")}
|
||||
|
|
Loading…
Reference in a new issue