Как декодировать и проверить 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.

Другие вопросы по тегам