KEYCLOAK-14904 Fix AccountRestService

- custom attributes in UserModel are removed during update
- this can break caching (doesn't break if user is written
  to database)
- also ensure that we don't accidentally change username
  and/or firstName/lastName through attributes
This commit is contained in:
Martin Idel 2020-06-26 14:23:47 +02:00 committed by Marek Posolda
parent bf411d7567
commit 330a3d8ff5
2 changed files with 41 additions and 1 deletions

View file

@ -214,12 +214,26 @@ public class AccountRestService {
user.setLastName(userRep.getLastName());
if (userRep.getAttributes() != null) {
for (String k : user.getAttributes().keySet()) {
Set<String> attributeKeys = new HashSet<>(user.getAttributes().keySet());
// We store username and other attributes as attributes (for future UserProfile)
// but don't propagate them to the UserRepresentation, so userRep will never contain them
// if the user did not explicitly add them
attributeKeys.remove(UserModel.FIRST_NAME);
attributeKeys.remove(UserModel.LAST_NAME);
attributeKeys.remove(UserModel.EMAIL);
attributeKeys.remove(UserModel.USERNAME);
for (String k : attributeKeys) {
if (!userRep.getAttributes().containsKey(k)) {
user.removeAttribute(k);
}
}
Map<String, List<String>> attributes = userRep.getAttributes();
// Make sure we don't accidentally update any of the fields through attributes
attributes.remove(UserModel.FIRST_NAME);
attributes.remove(UserModel.LAST_NAME);
attributes.remove(UserModel.EMAIL);
attributes.remove(UserModel.USERNAME);
for (Map.Entry<String, List<String>> e : userRep.getAttributes().entrySet()) {
user.setAttribute(e.getKey(), e.getValue());
}

View file

@ -180,6 +180,32 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
}
@Test
public void testUpdateProfileCannotChangeThroughAttributes() throws IOException {
UserRepresentation user = SimpleHttp.doGet(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).asJson(UserRepresentation.class);
String originalUsername = user.getUsername();
Map<String, List<String>> originalAttributes = new HashMap<>(user.getAttributes());
try {
user.getAttributes().put("username", Collections.singletonList("Username"));
user.getAttributes().put("attr2", Collections.singletonList("val2"));
user = updateAndGet(user);
assertEquals(user.getUsername(), originalUsername);
} finally {
RealmRepresentation realmRep = adminClient.realm("test").toRepresentation();
realmRep.setEditUsernameAllowed(true);
adminClient.realm("test").update(realmRep);
user.setUsername(originalUsername);
user.setAttributes(originalAttributes);
SimpleHttp.Response response = SimpleHttp.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user).asResponse();
System.out.println(response.asString());
assertEquals(204, response.getStatus());
}
}
// KEYCLOAK-7572
@Test
public void testUpdateProfileWithRegistrationEmailAsUsername() throws IOException {