Custom REST Endpoints
Le RealmResourceProvider SPI permet d'ajouter des endpoints REST custom a Keycloak, utiles pour integrer des logiques metier specifiques.
Creer un endpoint REST custom
public class CustomResourceProvider
implements RealmResourceProvider {
private final KeycloakSession session;
public CustomResourceProvider(KeycloakSession session) {
this.session = session;
}
@Override
public Object getResource() {
return new CustomResource(session);
}
@Override
public void close() {}
}
public class CustomResource {
private final KeycloakSession session;
public CustomResource(KeycloakSession session) {
this.session = session;
}
@GET
@Path("/user-stats")
@Produces(MediaType.APPLICATION_JSON)
public Response getUserStats() {
RealmModel realm = session.getContext().getRealm();
long userCount = session.users()
.getUsersCount(realm);
long activeCount = session.sessions()
.getActiveUserSessions(realm,
session.getContext().getClient());
Map<String, Long> stats = Map.of(
"totalUsers", userCount,
"activeSessions", activeCount
);
return Response.ok(stats).build();
}
@POST
@Path("/bulk-assign-role")
@Consumes(MediaType.APPLICATION_JSON)
public Response bulkAssignRole(BulkRoleRequest req) {
RealmModel realm = session.getContext().getRealm();
RoleModel role = realm.getRole(req.getRoleName());
for (String userId : req.getUserIds()) {
UserModel user = session.users()
.getUserById(realm, userId);
if (user != null) {
user.grantRole(role);
}
}
return Response.ok().build();
}
}
Custom Protocol Mapper
Les Protocol Mappers ajoutent des claims personnalises aux tokens.
public class DepartmentMapper
extends AbstractOIDCProtocolMapper
implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
public static final String PROVIDER_ID = "department-mapper";
@Override
protected void setClaim(
IDToken token,
ProtocolMapperModel model,
UserSessionModel userSession,
KeycloakSession session,
ClientSessionContext ctx
) {
UserModel user = userSession.getUser();
String dept = user.getFirstAttribute("department");
if (dept != null) {
token.getOtherClaims().put("department", dept);
}
// Ajouter des claims complexes
Map<String, Object> orgInfo = Map.of(
"department", dept != null ? dept : "unknown",
"manager", user.getFirstAttribute("manager"),
"costCenter", user.getFirstAttribute("cost_center")
);
token.getOtherClaims().put("org_info", orgInfo);
}
@Override
public String getDisplayType() {
return "Department Mapper";
}
@Override
public String getId() { return PROVIDER_ID; }
}
Compilation et deploiement
# pom.xml (Maven)
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
# Compiler et deployer
mvn clean package
cp target/mon-extension.jar /opt/keycloak/providers/
/opt/keycloak/bin/kc.sh build
Important : Toutes les dependances Keycloak doivent etre en scope
provided car elles sont deja presentes dans le serveur. N'incluez que vos dependances specifiques.