Configure Extension with UiPageProvider #1
2 changed files with 75 additions and 22 deletions
validate configuration before saving it
commit
88ffb9b9f4
|
|
@ -1,15 +1,23 @@
|
|||
package de.ccc.hamburg.keycloak.attribute_endpoints;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.component.ComponentValidationException;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.services.ui.extend.UiPageProvider;
|
||||
import org.keycloak.services.ui.extend.UiPageProviderFactory;
|
||||
import org.keycloak.userprofile.UserProfileProvider;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.auto.service.AutoService;
|
||||
|
||||
/**
|
||||
* Implements UiPageProvider to show a config page in the admin
|
||||
|
|
@ -29,55 +37,108 @@ public class AdminUiPage implements UiPageProvider, UiPageProviderFactory<Compon
|
|||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Configure endpoints of the Attribute Endpoint Provider.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel model) {
|
||||
String errorString = "\n";
|
||||
Boolean hasError = false;
|
||||
|
||||
Pattern slugPattern = Pattern.compile("^[a-zA-Z0-9_-]*$");
|
||||
String configAttributeSlug = model.getConfig().getFirst("slug");
|
||||
|
||||
if (!slugPattern.matcher(configAttributeSlug).matches()) {
|
||||
hasError = true;
|
||||
errorString += " • [Slug] can only contain anlphanumeric characters, dash and underscore (a-z A-Z 0-9 _ - )\n";
|
||||
}
|
||||
|
||||
String configAuthRole = model.getConfig().getFirst("auth-role");
|
||||
RoleModel authRole = realm.getRole(configAuthRole);
|
||||
if (authRole == null) {
|
||||
hasError = true;
|
||||
errorString += " • [Auth Role] does not exist\n";
|
||||
}
|
||||
|
||||
String configMatchRole = model.getConfig().getFirst("match-role");
|
||||
RoleModel matchRole = realm.getRole(configMatchRole);
|
||||
if (matchRole == null) {
|
||||
hasError = true;
|
||||
errorString += " • [Match Role] does not exist\n";
|
||||
}
|
||||
|
||||
UserProfileProvider profileProvider = session.getProvider(UserProfileProvider.class);
|
||||
UPConfig upconfig = profileProvider.getConfiguration();
|
||||
String configAttributeGroup = model.getConfig().getFirst("attribute-group");
|
||||
if (!upconfig.getGroups().stream().anyMatch(g -> g.getName().equals(configAttributeGroup))) {
|
||||
hasError = true;
|
||||
errorString += " • [Attribute Group] does not exist\n";
|
||||
}
|
||||
|
||||
String configAttributeRegex = model.getConfig().getFirst("attribute-regex");
|
||||
Boolean regexIsBlank = configAttributeRegex == null;
|
||||
|
||||
if (!regexIsBlank) {
|
||||
try {
|
||||
Pattern.compile(configAttributeRegex);
|
||||
} catch (Exception e) {
|
||||
hasError = true;
|
||||
errorString += " • [Attribute RegEx] is not a valid regex pattern\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
throw new ComponentValidationException(errorString);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return ProviderConfigurationBuilder.create()
|
||||
.property()
|
||||
.name("slug")
|
||||
.label("Slug")
|
||||
.helpText("The slug in the path of the API endpoint (e.g. /realms/:realm/attribute-endpoint-provider/export/:slug)")
|
||||
.helpText(
|
||||
"The slug in the path of the API endpoint (e.g. /realms/:realm/attribute-endpoint-provider/export/:slug)")
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
|
||||
|
||||
.property()
|
||||
.name("attribute-group")
|
||||
.label("Attribute Group")
|
||||
.helpText("The attribute group to export.")
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
|
||||
|
||||
.property()
|
||||
.name("match-role")
|
||||
.label("Match Role")
|
||||
.helpText("Export only attributes of users with this role.")
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
|
||||
|
||||
.property()
|
||||
.name("auth-role")
|
||||
.label("Auth Role")
|
||||
.helpText("Role needeed by the authenticated account to be able to use this endpoint.")
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
|
||||
|
||||
.property()
|
||||
.name("attribute-regex")
|
||||
.label("Attribute RegEx")
|
||||
.helpText("A RegEx Rule used to verify each attribute value. Only matching values are returned.")
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.add()
|
||||
|
||||
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package de.ccc.hamburg.keycloak.attribute_endpoints;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
|
@ -23,7 +22,7 @@ import org.keycloak.services.managers.AuthenticationManager.AuthResult;
|
|||
import org.keycloak.services.resource.RealmResourceProvider;
|
||||
import org.keycloak.userprofile.UserProfileProvider;
|
||||
|
||||
import io.quarkus.security.UnauthorizedException;
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.NotAuthorizedException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
|
|
@ -102,16 +101,9 @@ public class AttributeEndpointsResourceProvider implements RealmResourceProvider
|
|||
}
|
||||
}
|
||||
|
||||
try
|
||||
|
||||
{
|
||||
UserModel user = auth.getUser();
|
||||
if (!user.hasRole(authRole)) {
|
||||
throw new UnauthorizedException("User does not have required auth role.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
return Response.status(403, e.getMessage()).build();
|
||||
UserModel authUser = auth.getUser();
|
||||
if (!authUser.hasRole(authRole)) {
|
||||
throw new ForbiddenException("User does not have required auth role.");
|
||||
}
|
||||
|
||||
if (componentList.size() > 1) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue