Автономная проверка Java токена доступа JWT из Keycloak

#java #validation #jwt #keycloak

#java #проверка #jwt #keycloak

Вопрос:

Я получаю подписанный токен JWT из Keycloak http://localhost:8080/auth/realms/MyRealm/protocol/openid-connect/token :

 {
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJqQThGdzdhRk1rTGhGc2......",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIzMWRjZTBjNS01MGU0LTQxZjMtODAxNC1kMTcyMjdk....",
"token_type": "bearer",
"not-before-policy": 0,
"session_state": "bd1728eb-ceda-43cf-a6e6-d637ba0da5e3",
"scope": "email profile"
}
  

Таким образом, токен доступа:

 eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJqQThGdzdhRk1rTGhGc2......
  

Я запрашиваю Keycloak для http://localhost:8080/auth/realms/Myrealm/ :

 {
"realm": "MyRealm",
"public_key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKQF8ewcJ/pDzhgzbTfFCoS1FLjZyO5z7CbmeWl.......",
"token-service": "http://localhost:8080/auth/realms/Myrealm/protocol/openid-connect",
"account-service": "http://localhost:8080/auth/realms/Myrealm/account",
"tokens-not-before": 0
}
  

Таким образом, открытый ключ:

 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKQF8ewcJ/pDzhgzbTfFCoS1FLjZyO5z7CbmeWl.......
  

Теперь я пытаюсь выполнить автономную проверку следующим образом:

 import java.security.KeyFactory;
import java.security.spec.X509EncodedKeySpec;
import java.security.PublicKey;

String keyFromKeycloak = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKQF8ewcJ/pDzhgzbTfFCoS1FLjZyO5z7CbmeWl.......";
byte[] bytes = keyFromKeycloak.getBytes();
KeyFactory factory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(bytes);
PublicKey pk = factory.generatePublic(encodedKeySpec);
  

Но я получаю исключение для недопустимого ключа:

 java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
    at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:239)
    at java.base/java.security.KeyFactory.generatePublic(KeyFactory.java:352)
Caused by: java.security.InvalidKeyException: invalid key format
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:386)
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:401)
    at java.base/sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:122)
    at java.base/sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:330)
    at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:235)
    ... 3 more
  

Мне нужен объект PublicKey для проверки токена доступа следующим образом:

 Algorithm algorithm = Algorithm.RSA256(
    (RSAPublicKey) pk,
    null);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
  

Что не так? Я вижу много примеров с этим кодом, поэтому я подозреваю, что проблема связана с самим ключом.

Комментарии:

1. Используйте Base64.getDecoder().decode(keyFromKeycloak) и передайте этот массив байтов в спецификацию x509.

2. Мне этого не хватало. Спасибо! Отправьте ответ, чтобы я мог его принять.

3. Не могли бы вы поделиться именами библиотек / пакетов, которые вы используете для второго фрагмента кода: Algorithm , JWT , JWTVerifier и DecodedJWT ?

4. @xbmono Это com.auth0.java-jwt

Ответ №1:

Ваша keyFromKeycloak строка представляет собой кодированный на Base64 DER SubjectPublicKeyInfo. Вы должны сначала декодировать его, а затем передать X509EncodedKeySpec конструктору :

 String keyFromKeycloak = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKQF8ewcJ/pDzhgzbTfFCoS1FLjZyO5z7CbmeWl.......";
byte[] keyBytes = Base64.getDecoder().decode(keyFromKeycloak);
X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(keyBytes);