Как декодировать и проверить EdDSA JWT в Spring Security
Я пытаюсь декодировать и проверить JWT EdDSA, используя Spring Security в роли сервера ресурсов. Spring, похоже, не хочет поддерживать EdDSA, поэтому я начал писать свой собственный JwtDecoder, который выглядит вот так
class CustomJwtDecoder : JwtDecoder {
override fun decode(token: String): Jwt {
val signedJwt = SignedJWT.parse(token)
try {
val claimsSet = signedJwt.jwtClaimsSet
val headers = signedJwt.header
return Jwt(
token,
claimsSet.issueTime.toInstant(),
claimsSet.expirationTime.toInstant(),
headers.toJSONObject(),
claimsSet.claims,
)
} catch (ex: JOSEException) {
throw RuntimeException("Failed to decode JWT: ${ex.message}", ex)
}
}
}
Для проверки этих JWT я начал использовать Tink через эту зависимость.
<dependency>
<groupId>com.google.crypto.tink</groupId>
<artifactId>tink</artifactId>
<version>1.6.1</version>
</dependency>
Однако при попытке проверить токен с помощью этой библиотеки рекомендуется сделать что-то вроде этого
val verifier: JWSVerifier = Ed25519Verifier(publicJWK)
Но в этом случаеpublicJwk
здесь должно быть получено из jwks uri на сервере аутентификации путем сопоставленияkid
искsignedJwt
к открытому ключу jwks uri. Итак, вопрос в том, могу ли я получить publicJwk из jwks uri, используя стандартные механизмы Spring, или мне придется полностью разветвить библиотеку nimbus-jose, чтобы добавить поддержку EdDSA, а затем вставить ее в свой проект, чтобы переопределить зависимость Spring Security?
Кроме того, должна ли проверка токена проходить в JwtDecoder или проверка выполняется на другом этапе процесса Spring authN/authZ? И как в этом контексте должен выглядеть этот этап проверки?
Если есть лучший/более простой способ декодирования/проверки JWT EdDSA в контексте Spring Security, я бы тоже хотел это услышать.
1 ответ
Чтобы декодировать и проверять JWTEdDSA в SpringSecurity, вам потребуется интегрировать библиотеку, поддерживающую подписи EdDSA, например Nimbus JOSE+JWT или Google Tink (скоро будет в Tink-crypto ), как вы упомянули.
Вам потребуется:
получить открытый ключ, соответствующий закрытому ключу, который использовался для подписи JWT (для проверки подписи). Обычно это доступно через конечную точку JWKS (набор веб-ключей JSON) . Вы можете использоватьили любой HTTP-клиент для получения JWKS и его анализа для получения открытого ключа.
проверьте подпись JWT (используя открытый ключ). Поскольку вы используете Tink, вы можете использоватькак вы упомянули. В качестве альтернативы, если вы решите использовать Nimbus JOSE+JWT, вы можете использовать
Ed25519Verifier
из этой библиотеки .
Ваш пользователь должен отвечать как за декодирование токена, так и за проверку его подписи.
Как только ваша настройка будет реализована, вам необходимо будет интегрировать ее с SpringSecurity. Вы можете сделать это, настроив его как компонент и используя его в своей конфигурации безопасности.
Например:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PublicKey publicKey; // Inject the public key
@Override
protected void configure(HttpSecurity http) throws Exception {
http.oauth2ResourceServer()
.jwt()
.decoder(customJwtDecoder(publicKey));
}
@Bean
public JwtDecoder customJwtDecoder(PublicKey publicKey) {
return token -> {
try {
SignedJWT signedJwt = SignedJWT.parse(token);
JWSVerifier verifier = new Ed25519Verifier(publicKey);
if (!signedJwt.verify(verifier)) {
throw new JOSEException("Failed to verify JWT signature");
}
JWTClaimsSet claimsSet = signedJwt.getJWTClaimsSet();
return Jwt.withTokenValue(token)
.header(signedJwt.getHeader().toJSONObject())
.claims(claimsSet::getClaims)
.build();
} catch (JOSEException | ParseException ex) {
throw new RuntimeException("Failed to decode JWT: " + ex.getMessage(), ex);
}
};
}
@Bean
public PublicKey getPublicKey() {
// Logic to fetch the public key from JWKS endpoint
// ...
}
}
Это покажет, как вы можете создать собственныйJwtDecoder
который проверяет подпись JWT с использованием алгоритма EdDSA и интегрирует ее в SpringSecurity. getPublicKey
Метод должен содержать логику получения открытого ключа из конечной точки JWKS. Вы можете использовать SpringRestTemplate
для этой цели.
Это должно позволить вам интегрировать JWTEdDSA в SpringSecurity без необходимости разветвлять библиотеку Nimbus JOSE+JWT или заменять зависимости SpringSecurity.