Skip to content
Snippets Groups Projects
Verified Commit d419e173 authored by Ira ¯\_(ツ)_/¯'s avatar Ira ¯\_(ツ)_/¯
Browse files

Add custom REST endpoint MailPassResourceProvider and factory

parent b184d31a
No related branches found
No related tags found
No related merge requests found
package org.archlinux.keycloak.mailpass.rest;
import java.security.SecureRandom;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.bouncycastle.crypto.generators.OpenBSDBCrypt;
import org.keycloak.models.KeycloakSession;
import org.keycloak.services.resource.RealmResourceProvider;
/**
* A custom REST endpoint to trigger functionality on the Keycloak server, which is not available
* through the default set of built-in Keycloak REST endpoints. This is to be used during the
* storage of a custom attribute on the Account Management Console for the mail password. The data
* stored will be a Bcrypt hash instead of the plain text password.
*/
public class MailPassResourceProvider implements RealmResourceProvider {
private static final int SALT_LENGTH = 16;
private static final int COST = 12;
private static final String VARIANT = "2b";
@SuppressWarnings("unused")
private KeycloakSession session;
private byte[] generateSalt() {
// https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#secure-random-number-generation
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
return salt;
}
public MailPassResourceProvider(KeycloakSession session) {
this.session = session;
}
@Override
public Object getResource() {
return this;
}
@Override
public void close() {
}
/**
* The custom REST endpoint reachable at {{ base_url }}/realms/{{ realm }}/mailpass/hashify.
*
* @param data The JSON property including the password entry.
* @return Response instance including the hashed password string.
*/
@POST
@Path("hashify")
@Consumes(MediaType.APPLICATION_JSON)
public Response generateBcryptHash(String data) {
byte[] salt = generateSalt();
String hash = OpenBSDBCrypt.generate(VARIANT, data.toCharArray(), salt, COST);
return Response.status(201).entity(hash).build();
}
}
package org.archlinux.keycloak.mailpass.rest;
import org.keycloak.Config.Scope;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.services.resource.RealmResourceProvider;
import org.keycloak.services.resource.RealmResourceProviderFactory;
/**
* A factory that extends RealmResourceProviderFactory instance to create the custom mail pass
* resource for a path relative to Realm's RESTful API that cannot be resolved by the Keycloak
* server. This is a requirement for custom REST endpoints.
*/
public class MailPassResourceProviderFactory implements RealmResourceProviderFactory {
public static final String ID = "mailpass";
@Override
public String getId() {
return ID;
}
@Override
public RealmResourceProvider create(KeycloakSession session) {
return new MailPassResourceProvider(session);
}
@Override
public void init(Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment