Проверка подписанного JWT - PullRequest
0 голосов
/ 03 июля 2019

Я подписываю JWT с закрытым ключом (сервер авторизации) и использую открытый ключ (сервер ресурсов), чтобы «проверить» его ... Как я могу узнать, не был ли JWT скомпрометирован? Или как я могу это сделать?

Код с сервера ресурсов

       JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        Resource resource = new ClassPathResource("public.txt");
        String publicKey = null;
        try {
            publicKey = IOUtils.toString(resource.getInputStream());
        } catch (final IOException e) {
            throw new RuntimeException(e);
        }
        converter.setVerifierKey(publicKey);

        return converter;
    }

1 Ответ

0 голосов
/ 03 июля 2019

Spring Security выполнит проверку токена на основе конфигураций на сервере авторизации.

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

  RsaVerifier verifier = new RsaVerifier(RSAPublicKey);
  Jwt tokenDecoded = JwtHelper.decodeAndVerify(token, verifier);
  Map<String, Object> claimsMap = (Map<String, Object>) new 
  ObjectMapper().readValue(tokenDecoded.getClaims(), Map.class);
  //Verify the claims then
  // 1 Verify if the token has not already expired
  // 2 Verify the issuance date ( should be before this date )
  // 3 Verify if the issuer of this token is contained in verified authorities.
  // 4 Verify if the token was issued for this client
  // 5 Verify if the token contained any expected claims...

Но вышеописанное реализованоSpring Security для процесса аутентификации Oauth2, клиентское приложение просто должно предоставить конфигурации.

Триггер OAuth2AuthenticationProcessingFilter в цепочке фильтров безопасности Spring.Этот фильтр добавляется, когда ресурсы защищены защитой Oauth2.

В вашем приложении конфигурация сервера авторизации будет выглядеть так (только соответствующие ориентировочные выдержки конфигурации приведены ниже)

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

...
 @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        RSAPemKeyPairLoader keyPairLoader = new RSAPemKeyPairLoader();
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(...);
        converter.setVerifierKey(...);
        return converter;
    }

 @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(...);
        defaultTokenServices.setAccessTokenValiditySeconds(...);
        defaultTokenServices.setRefreshTokenValiditySeconds(...);
        return defaultTokenServices;
    }
}

В вашем приложенииконфигурация сервера ресурсов будет выглядеть следующим образом:

@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
  public void configure(HttpSecurity http) throws Exception {
   ...
  }
}

Для отслеживания в реализации Spring, где запрашиваемый токен перехватывается и проверяется, посмотрите на реализацию Spring OAUTH2 - подробности потока ниже, где объект Authentication, экземпляр OAuth2Authentication будетпопытаться создать его для успешных запросов.

Все приведенные ниже извлечения кода взяты из реализаций spring-security-oauth2-2.0.8.RELEASE.

public class OAuth2AuthenticationManager implements AuthenticationManager {

                ....
                public Authentication authenticate(Authentication authentication) throws AuthenticationException {

                        if (authentication == null) {
                            throw new InvalidTokenException("Invalid token (token not found)");
                        }
                        String token = (String) authentication.getPrincipal();
                        OAuth2Authentication auth = tokenServices.loadAuthentication(token);
                        ...
         }
}

loadAuthentication будет в основном проверять токен доступа и пытаться преобразовать его в OAuth2Authentication

public class DefaultTokenServices implements AuthorizationServerTokenServices ...{

           public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException, InvalidTokenException {

                   OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
                    ...
            }
}

JwtTokenStore создаст OAuth2AccessToken и в процессе декодирования и проверки токена String.

    public class JwtTokenStore implements TokenStore {

        public OAuth2AccessToken readAccessToken(String tokenValue) {
                OAuth2AccessToken accessToken = convertAccessToken(tokenValue);
                if (jwtTokenEnhancer.isRefreshToken(accessToken)) {
                    throw new InvalidTokenException("Encoded token is a refresh token");
                }
                return accessToken;
            }

        private OAuth2AccessToken convertAccessToken(String tokenValue) {
                return jwtTokenEnhancer.extractAccessToken(tokenValue, jwtTokenEnhancer.decode(tokenValue));
            }

  }

JWTAccessTokenConverter выполняет декодирование и извлечение заявок на токены.

public class JwtAccessTokenConverter implements AccessTokenConverter {

   protected Map<String, Object> decode(String token) {
                    try {
                        Jwt jwt = JwtHelper.decodeAndVerify(token, verifier);
                        String content = jwt.getClaims();
                        Map<String, Object> map = objectMapper.parseMap(content);
                        if (map.containsKey(EXP) && map.get(EXP) instanceof Integer) {
                            Integer intValue = (Integer) map.get(EXP);
                            map.put(EXP, new Long(intValue));
                        }
                        return map;
                    }
                    catch (Exception e) {
                        throw new InvalidTokenException("Cannot convert access token to JSON", e);
                    }
}

JwtHelper выполнит декодирование и запросит подтверждение.

public static Jwt decodeAndVerify(String token, SignatureVerifier verifier) {
     Jwt jwt = decode(token);
     jwt.verifySignature(verifier);
     return jwt;
}

JwttImpl вызывает верификатор.

public void verifySignature(SignatureVerifier verifier) {
    verifier.verify(signingInput(), crypto);
}

Например, верификатор RSA Signature наконец выполнит проверку:

public class RsaVerifier implements SignatureVerifier {

            public void verify(byte[] content, byte[] sig) {
                    try {
                        Signature signature = Signature.getInstance(algorithm);
                        signature.initVerify(key);
                        signature.update(content);

                        if (!signature.verify(sig)) {
                            throw new InvalidSignatureException("RSA Signature did not match content");
                        }
                    }
                    catch (GeneralSecurityException e) {
                        throw new RuntimeException(e);
                    }
                }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...