Keycloak - настройка «под» формата в токене JWT - PullRequest
0 голосов
/ 14 января 2020

Я пытаюсь найти способ изменить формат «sub» в токене JWT, предоставленном Keycloak, я знаю, что он получен из идентификатора пользователя Keycloak, но я не уверен, что мы не можем его изменить.

Например, сейчас у меня есть что-то вроде этого:

"sub": "f: 39989175-b393-4fad-8f84-628b9712f93b: testldap",

Я бы хотел, чтобы он был меньше ? .

1 Ответ

0 голосов
/ 15 января 2020

Я не уверен, что изменение 'sub' является хорошей идеей, но если вы уверены, вы можете использовать что-то вроде этого:

/**
 * Class for signing JWT (when you get tokens in base64 actually they are
 * signed by issuer server see https://jwt.io)
 */
public static class JwtSigner {

    private final KeyPair keyPair;
    private final String kid;

    public JwtSigner(String privateKeyPem) {
        PrivateKey privateKey = PemUtils.decodePrivateKey(privateKeyPem);
        PublicKey publicKey = KeyUtils.extractPublicKey(privateKey);
        keyPair = new KeyPair(publicKey, privateKey);
        kid = KeyUtils.createKeyId(keyPair.getPublic());
    }

    public String encodeToken(AccessToken accessToken) {
        return new JWSBuilder()
                .type("JWT")
                .kid(kid)
                .jsonContent(accessToken)
                .sign(Algorithm.RS256, keyPair.getPrivate());
    }
}


/**
 * This class allows you to update several token fields and re-encode token
 */
public static class JwtTransformer<T extends AccessToken> {

    private T token;

    public JwtTransformer(String tokenString, Class<T> tokenType) throws JWSInputException {
        try {
            token = JsonSerialization.readValue(new JWSInput(tokenString).getContent(), tokenType);
        } catch (IOException e) {
            throw new JWSInputException(e);
        }
    }

    public static <T extends AccessToken> T decode(String tokenString, Class<T> tokenType) throws JWSInputException {
        return new JwtTransformer<>(tokenString, tokenType).decode();
    }

    public static JwtTransformer<AccessToken> forAccessToken(String tokenString) throws JWSInputException {
        return new JwtTransformer<>(tokenString, AccessToken.class);
    }

    public static JwtTransformer<RefreshToken> forRefreshToken(String tokenString) throws JWSInputException {
        return new JwtTransformer<>(tokenString, RefreshToken.class);
    }

    public T decode() {
        return token;
    }

    public JwtTransformer transform(Consumer<T> consumer) {
        consumer.accept(token);
        return this;
    }

    public String encode(JwtSigner jwtSigner) {
        return jwtSigner.encodeToken(token);
    }

}

Я использовал эти классы для тестов, но вы можете принять их для ваших нужд. Обратите внимание, что закрытый ключ, необходимый для инициализации JwtSigner, хранится в базе данных Keycloak и не может быть легко извлечен через интерфейс консоли администратора. Проверьте результат

select VALUE
from KEYCLOAK.COMPONENT
         inner join KEYCLOAK.COMPONENT_CONFIG
                    on KEYCLOAK.COMPONENT.ID = KEYCLOAK.COMPONENT_CONFIG.COMPONENT_ID
where PARENT_ID = '%YOUR_REALM_NAME%'
  and PROVIDER_ID = 'rsa-generated'
  and COMPONENT_CONFIG.NAME = 'privateKey';

Итак, наконец, вы можете сделать что-то вроде

String new AccessToken = JwtTransformer.forAccessToken(accessTokenString)
        .transform(token -> {
            token.subject(subModificationFunction(token.getSubject()))
        })
        .encode();
...