Skip to content

Commit

Permalink
Update UserProfileProvider.setConfiguration. Tuning of UserProfilePro…
Browse files Browse the repository at this point in the history
…vider.getConfiguration

closes keycloak#25416

Signed-off-by: mposolda <mposolda@gmail.com>
  • Loading branch information
mposolda committed Dec 14, 2023
1 parent 26342d8 commit c81b533
Show file tree
Hide file tree
Showing 14 changed files with 201 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.keycloak.representations.userprofile.config;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
Expand All @@ -27,7 +28,7 @@
* @author Vlastimil Elias <velias@redhat.com>
*
*/
public class UPAttribute {
public class UPAttribute implements Cloneable {

private String name;
private String displayName;
Expand Down Expand Up @@ -144,4 +145,29 @@ public void setGroup(String group) {
public String toString() {
return "UPAttribute [name=" + name + ", displayName=" + displayName + ", permissions=" + permissions + ", selector=" + selector + ", required=" + required + ", validations=" + validations + ", annotations=" + annotations + ", group=" + group + "]";
}

@Override
protected UPAttribute clone() {
UPAttribute attr = new UPAttribute(this.name);
attr.setDisplayName(this.displayName);

Map<String, Map<String, Object>> validations;
if (this.validations == null) {
validations = null;
} else {
validations = new LinkedHashMap<>();
for (Map.Entry<String, Map<String, Object>> entry : this.validations.entrySet()) {
Map<String, Object> newVal = entry.getValue() == null ? null : new LinkedHashMap<>(entry.getValue());
validations.put(entry.getKey(), newVal);
}
}
attr.setValidations(validations);

attr.setAnnotations(this.annotations == null ? null : new HashMap<>(this.annotations));
attr.setRequired(this.required == null ? null : this.required.clone());
attr.setPermissions(this.permissions == null ? null : this.permissions.clone());
attr.setSelector(this.selector == null ? null : this.selector.clone());
attr.setGroup(this.group);
return attr;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.keycloak.representations.userprofile.config;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnore;

Expand All @@ -28,7 +29,7 @@
* @author Vlastimil Elias <velias@redhat.com>
*
*/
public class UPAttributePermissions {
public class UPAttributePermissions implements Cloneable {

private Set<String> view = Collections.emptySet();
private Set<String> edit = Collections.emptySet();
Expand Down Expand Up @@ -67,4 +68,11 @@ public String toString() {
public boolean isEmpty() {
return getEdit().isEmpty() && getView().isEmpty();
}

@Override
protected UPAttributePermissions clone() {
Set<String> view = this.view == null ? null : new HashSet<>(this.view);
Set<String> edit = this.edit == null ? null : new HashSet<>(this.edit);
return new UPAttributePermissions(view, edit);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.keycloak.representations.userprofile.config;

import java.util.HashSet;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonIgnore;
Expand All @@ -28,7 +29,7 @@
* @author Vlastimil Elias <velias@redhat.com>
*
*/
public class UPAttributeRequired {
public class UPAttributeRequired implements Cloneable {

private Set<String> roles;
private Set<String> scopes;
Expand Down Expand Up @@ -74,4 +75,11 @@ public String toString() {
return "UPAttributeRequired [isAlways=" + isAlways() + ", roles=" + roles + ", scopes=" + scopes + "]";
}

@Override
protected UPAttributeRequired clone() {
Set<String> scopes = this.scopes == null ? null : new HashSet<>(this.scopes);
Set<String> roles = this.roles == null ? null : new HashSet<>(this.roles);
return new UPAttributeRequired(roles, scopes);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.keycloak.representations.userprofile.config;

import java.util.HashSet;
import java.util.Set;

/**
Expand All @@ -26,7 +27,7 @@
* @author Vlastimil Elias <velias@redhat.com>
*
*/
public class UPAttributeSelector {
public class UPAttributeSelector implements Cloneable {

private Set<String> scopes;

Expand All @@ -51,4 +52,8 @@ public String toString() {
return "UPAttributeSelector [scopes=" + scopes + "]";
}

@Override
protected UPAttributeSelector clone() {
return new UPAttributeSelector(scopes == null ? null : new HashSet<>(scopes));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
Expand All @@ -29,7 +31,7 @@
* @author Vlastimil Elias <velias@redhat.com>
*
*/
public class UPConfig {
public class UPConfig implements Cloneable {

public enum UnmanagedAttributePolicy {

Expand Down Expand Up @@ -120,4 +122,19 @@ public void setUnmanagedAttributePolicy(UnmanagedAttributePolicy unmanagedAttrib
public String toString() {
return "UPConfig [attributes=" + attributes + ", groups=" + groups + "]";
}

@Override
public UPConfig clone() {
UPConfig cfg = new UPConfig();

cfg.setUnmanagedAttributePolicy(this.unmanagedAttributePolicy);
if (attributes != null) {
cfg.setAttributes(attributes.stream().map(UPAttribute::clone).collect(Collectors.toList()));
}
if (groups != null) {
cfg.setGroups(groups.stream().map(UPGroup::clone).collect(Collectors.toList()));
}

return cfg;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@

package org.keycloak.representations.userprofile.config;

import java.util.HashMap;
import java.util.Map;

/**
* Configuration of the attribute group.
*
* @author <a href="joerg.matysiak@bosch.io">Jörg Matysiak</a>
*/
public class UPGroup {
public class UPGroup implements Cloneable {

private String name;
private String displayHeader;
Expand Down Expand Up @@ -72,4 +73,13 @@ public Map<String, Object> getAnnotations() {
public void setAnnotations(Map<String, Object> annotations) {
this.annotations = annotations;
}

@Override
protected UPGroup clone() {
UPGroup group = new UPGroup(this.name);
group.setDisplayHeader(displayHeader);
group.setDisplayDescription(displayDescription);
group.setAnnotations(this.annotations == null ? null : new HashMap<>(this.annotations));
return group;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,7 @@ private void updateUserProfileConfiguration(UIRealmRepresentation rep) {
return;
}

String rawUpConfig;

try {
rawUpConfig = JsonSerialization.writeValueAsString(upConfig);
} catch (IOException e) {
throw new InternalServerErrorException("Failed to parse user profile config", e);
}

Response response = new UserProfileResource(session, auth).update(rawUpConfig);
Response response = new UserProfileResource(session, auth).update(upConfig);

if (isSuccessful(response)) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,20 @@ public interface UserProfileProvider extends Provider {
* Get current UserProfile configuration.
*
* @return current UserProfile configuration
* @see #setConfiguration(String)
* @see #setConfiguration(UPConfig)
*/
UPConfig getConfiguration();

/**
* Set new UserProfile configuration. It is persisted inside of the provider.
*
* @param configuration to be set
* @param configuration to be set. It can be null and in this case, userProfile implementation will switch to use the default configuration
* @throws RuntimeException if configuration is invalid (exact exception class
* depends on the implementation) or configuration
* can't be persisted.
* @see #getConfiguration()
*/
void setConfiguration(String configuration);
void setConfiguration(UPConfig configuration);

/**
* Returns whether the declarative provider is enabled to a realm
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,20 @@
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;

import org.keycloak.component.ComponentValidationException;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.provider.ConfiguredProvider;
import org.keycloak.representations.idm.UserProfileAttributeGroupMetadata;
import org.keycloak.representations.idm.UserProfileAttributeMetadata;
import org.keycloak.representations.idm.UserProfileMetadata;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.KeycloakOpenAPI;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.userprofile.AttributeMetadata;
import org.keycloak.userprofile.AttributeValidatorMetadata;
import org.keycloak.userprofile.Attributes;
import org.keycloak.userprofile.UserProfile;
import org.keycloak.userprofile.UserProfileContext;
import org.keycloak.userprofile.UserProfileProvider;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.representations.userprofile.config.UPGroup;
import org.keycloak.validate.Validators;

/**
* @author Vlastimil Elias <velias@redhat.com>
Expand Down Expand Up @@ -99,13 +90,12 @@ public UserProfileMetadata getMetadata() {
@Tag(name = KeycloakOpenAPI.Admin.Tags.USERS)
@Operation(description = "Set the configuration for the user profile")
@APIResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = UPConfig.class)))
public Response update(
@RequestBody(content = @Content(schema = @Schema(implementation = UPConfig.class))) String text) {
public Response update(UPConfig config) {
auth.realm().requireManageRealm();
UserProfileProvider t = session.getProvider(UserProfileProvider.class);

try {
t.setConfiguration(text);
t.setConfiguration(config);
} catch (ComponentValidationException e) {
//show validation result containing details about error
throw ErrorResponse.error(e.getMessage(), Response.Status.BAD_REQUEST);
Expand Down
Loading

0 comments on commit c81b533

Please sign in to comment.