Compare commits

..

2 commits

5 changed files with 5212 additions and 29 deletions

View file

@ -5,10 +5,10 @@ For this it will provide API endpoints for every configured attribute-group.
The configuration of the provider is possible via an admin page. The configuration of the provider is possible via an admin page.
Every endpoint responds with a list of all attribute values, that: Every endpoint responds with a list of all attribute values, that:
- are in the attribute group matching `attribute-group` - is in the attribute group matching `attribute-group`
- match an optional RegEx Pattern `attribute-regex` - matches an optional RegEx Pattern `attribute-regex`
- belong to a user with a role matching `match-role` - belongs to a user with a role matching `match-role`
- are non-empty - is non-empty
Multivalue attributes are flattened in the response. Multivalue attributes are flattened in the response.
@ -61,7 +61,7 @@ We assume an unconfigured, fresh Keycloak installation running under `http://loc
- After creating: - After creating:
- give it the role `myattribute-export` - give it the role `myattribute-export`
- set a password in the users settings `Creadentials > Set password`. For Example `"password"` - set a password in the users settings `Creadentials > Set password`. For Example `"password"`
8. Under `Attribute Endpoints > Create item`, add a new endpoint to the provider 8. Under `🪪 Attribute Endpoints 🚀 > Create item`, add a new endpoint to the provider
Example: Example:
- `Slug` = `"ssh_keys"` - `Slug` = `"ssh_keys"`
- `Attribute Group` = `"my-attributes-group"` - `Attribute Group` = `"my-attributes-group"`

View file

@ -24,7 +24,7 @@ import com.google.auto.service.AutoService;
*/ */
@AutoService(UiPageProviderFactory.class) @AutoService(UiPageProviderFactory.class)
public class AdminUiPage implements UiPageProvider, UiPageProviderFactory<ComponentModel> { public class AdminUiPage implements UiPageProvider, UiPageProviderFactory<ComponentModel> {
public static final String PROVIDER_ID = "Attribute Endpoints"; public static final String PROVIDER_ID = "🪪 Attribute Endpoints 🚀";
@Override @Override
public void init(Config.Scope config) { public void init(Config.Scope config) {
@ -54,28 +54,22 @@ public class AdminUiPage implements UiPageProvider, UiPageProviderFactory<Compon
Pattern slugPattern = Pattern.compile("^[a-zA-Z0-9_-]*$"); Pattern slugPattern = Pattern.compile("^[a-zA-Z0-9_-]*$");
String configAttributeSlug = model.getConfig().getFirst("slug"); String configAttributeSlug = model.getConfig().getFirst("slug");
if (configAttributeSlug == null) {
hasError = true; if (!slugPattern.matcher(configAttributeSlug).matches()) {
errorString += " • [Slug] can not be empty\n";
} else if (!slugPattern.matcher(configAttributeSlug).matches()) {
hasError = true; hasError = true;
errorString += " • [Slug] can only contain anlphanumeric characters, dash and underscore (a-z A-Z 0-9 _ - )\n"; errorString += " • [Slug] can only contain anlphanumeric characters, dash and underscore (a-z A-Z 0-9 _ - )\n";
} }
String configAuthRole = model.getConfig().getFirst("auth-role"); String configAuthRole = model.getConfig().getFirst("auth-role");
if (configAuthRole == null) { RoleModel authRole = realm.getRole(configAuthRole);
hasError = true; if (authRole == null) {
errorString += " • [Auth Role] can not be empty\n";
} else if (realm.getRole(configAuthRole) == null) {
hasError = true; hasError = true;
errorString += " • [Auth Role] does not exist\n"; errorString += " • [Auth Role] does not exist\n";
} }
String configMatchRole = model.getConfig().getFirst("match-role"); String configMatchRole = model.getConfig().getFirst("match-role");
if (configMatchRole == null) { RoleModel matchRole = realm.getRole(configMatchRole);
hasError = true; if (matchRole == null) {
errorString += " • [Match Role] can not be empty\n";
} else if (realm.getRole(configMatchRole) == null) {
hasError = true; hasError = true;
errorString += " • [Match Role] does not exist\n"; errorString += " • [Match Role] does not exist\n";
} }
@ -83,10 +77,7 @@ public class AdminUiPage implements UiPageProvider, UiPageProviderFactory<Compon
UserProfileProvider profileProvider = session.getProvider(UserProfileProvider.class); UserProfileProvider profileProvider = session.getProvider(UserProfileProvider.class);
UPConfig upconfig = profileProvider.getConfiguration(); UPConfig upconfig = profileProvider.getConfiguration();
String configAttributeGroup = model.getConfig().getFirst("attribute-group"); String configAttributeGroup = model.getConfig().getFirst("attribute-group");
if (configAttributeGroup == null) { if (!upconfig.getGroups().stream().anyMatch(g -> g.getName().equals(configAttributeGroup))) {
hasError = true;
errorString += " • [Attribute Group] can not be empty\n";
} else if (!upconfig.getGroups().stream().anyMatch(g -> g.getName().equals(configAttributeGroup))) {
hasError = true; hasError = true;
errorString += " • [Attribute Group] does not exist\n"; errorString += " • [Attribute Group] does not exist\n";
} }

View file

@ -53,7 +53,7 @@ public class AttributeEndpointsResourceProvider implements RealmResourceProvider
@GET @GET
@Path("export/{slug}") @Path("export/{slug}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response exportAttributeValues(@PathParam("slug") String slug) { public Response exportKeys(@PathParam("slug") String slug) {
KeycloakContext context = session.getContext(); KeycloakContext context = session.getContext();
RealmModel realm = context.getRealm(); RealmModel realm = context.getRealm();
@ -62,16 +62,11 @@ public class AttributeEndpointsResourceProvider implements RealmResourceProvider
.filter(c -> c.getConfig().getFirst("slug").equals(slug)) .filter(c -> c.getConfig().getFirst("slug").equals(slug))
.toList(); .toList();
Auth auth = AttributeEndpointsResourceProvider.getAuth(session);
if (componentList.isEmpty()) { if (componentList.isEmpty()) {
throw new NotFoundException("Endpoint not found."); throw new NotFoundException("Endpoint not found.");
} }
if (componentList.size() > 1) { Auth auth = AttributeEndpointsResourceProvider.getAuth(session);
throw new NotFoundException(
"Endpoint Configuration Error - Multiple configurations exist for this endpoint.");
}
ComponentModel component = componentList.get(0); ComponentModel component = componentList.get(0);
@ -111,6 +106,11 @@ public class AttributeEndpointsResourceProvider implements RealmResourceProvider
throw new ForbiddenException("User does not have required auth role."); throw new ForbiddenException("User does not have required auth role.");
} }
if (componentList.size() > 1) {
throw new NotFoundException(
"Endpoint Configuration Error - Multiple configurations exist for this endpoint.");
}
List<String> attributeNames = upconfig.getAttributes() List<String> attributeNames = upconfig.getAttributes()
.stream() .stream()
.filter(a -> a.getGroup() != null && a.getGroup().equals(configAttributeGroup)) .filter(a -> a.getGroup() != null && a.getGroup().equals(configAttributeGroup))

2667
realm-export.json Normal file

File diff suppressed because it is too large Load diff

2525
test.json Normal file

File diff suppressed because it is too large Load diff