Как я тестирую сервер ресурсов OAuth2 с помощью макета - PullRequest
1 голос
/ 16 марта 2019

У меня есть сервер OAUTH2, которому другие службы должны запрашивать токен jwt для доступа к конечным точкам.

Пока все хорошо, все идет хорошо.

Но сейчас я пишу тесты, и все они возвращают ошибку 401 без авторизации. Я уже понял, что это потому, что тесты не делают никаких запросов для сервера OAuth2.

То, что я хотел знать, это как сделать Mock с JWT или с сервера oauth2.

Ответы [ 3 ]

2 голосов
/ 16 марта 2019

Самый простой способ - напрямую смоделировать токен JWT, для тестов можно использовать другой ключ подписи, чтобы не создавать бреши в системе безопасности для своего бэкэнда.

1 голос
/ 16 марта 2019

Если вам нужно смоделировать JWT, лучшим решением будет использование генератора JWT, нацеленного на ваши тесты с использованием библиотеки Nimbus JWT + JOSE

Например, ниже приведен код, непосредственно извлеченный из JSON Web Token (JWT) с подписью RSA , который показывает генерацию JWT, а также утверждение, которое очень похоже на тестовое задание.

import java.util.Date;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jose.jwk.*;
import com.nimbusds.jose.jwk.gen.*;
import com.nimbusds.jwt.*;


// RSA signatures require a public and private RSA key pair, the public key 
// must be made known to the JWS recipient in order to verify the signatures
RSAKey rsaJWK = new RSAKeyGenerator(2048)
    .keyID("123")
    .generate();
RSAKey rsaPublicJWK = rsaJWK.toPublicJWK();

// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(rsaJWK);

// Prepare JWT with claims set
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
    .subject("alice")
    .issuer("https://c2id.com")
    .expirationTime(new Date(new Date().getTime() + 60 * 1000))
    .build();

SignedJWT signedJWT = new SignedJWT(
    new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(rsaJWK.getKeyID()).build(),
    claimsSet);

// Compute the RSA signature
signedJWT.sign(signer);

// To serialize to compact form, produces something like
// eyJhbGciOiJSUzI1NiJ9.SW4gUlNBIHdlIHRydXN0IQ.IRMQENi4nJyp4er2L
// mZq3ivwoAjqa1uUkSBKFIX7ATndFF5ivnt-m8uApHO4kfIFOrW7w2Ezmlg3Qd
// maXlS9DhN0nUk_hGI3amEjkKd0BWYCB8vfUbUv0XGjQip78AI4z1PrFRNidm7
// -jPDm5Iq0SZnjKjCNS5Q15fokXZc8u0A
String s = signedJWT.serialize();

// On the consumer side, parse the JWS and verify its RSA signature
signedJWT = SignedJWT.parse(s);

JWSVerifier verifier = new RSASSAVerifier(rsaPublicJWK);
assertTrue(signedJWT.verify(verifier));

// Retrieve / verify the JWT claims according to the app requirements
assertEquals("alice", signedJWT.getJWTClaimsSet().getSubject());
assertEquals("https://c2id.com", signedJWT.getJWTClaimsSet().getIssuer());
assertTrue(new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime()));

То, что я хотел бы сделать, это извлечь аналогичные функции генерации JWT для выделенного класса. Добавьте к этому несколько параметров конструктора (или используйте шаблон компоновщика) и используйте его для всех моих ложных результатов. Таким образом, вы можете проверить правильные, неправильные и неожиданные сценарии.

0 голосов
/ 17 марта 2019

Я испробовал оба совета, но безуспешно.

Моя конфигурация сервера ресурсов:

@Configuration
@EnableResourceServer
public class ServidorDeRecursos extends ResourceServerConfigurerAdapter {

    @Autowired
    private ConfiguracaoDeToken configuracaoDeToken;

    @Override
    public void configure(final HttpSecurity http) throws Exception {
        // @formatter:off
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .and()
                .authorizeRequests().anyRequest().permitAll();
        // @formatter:on
    }

    @Override
    public void configure(final ResourceServerSecurityConfigurer config) {
        config.tokenServices(configuracaoDeToken.tokenServices());
    }
}

Моя конфигурация токена

@Configuration
public class ConfiguracaoDeToken {

    @Autowired
    private ConversorDeTokenDeAcessoPersonalizado conversorDeTokenDeAcessoPersonalizado;

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public DefaultTokenServices tokenServices() {
        final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setAccessTokenConverter(conversorDeTokenDeAcessoPersonalizado);

        final 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;
    }
}

@Component
public class ConversorDeTokenDeAcessoPersonalizado extends DefaultAccessTokenConverter {

    @Override
    public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {
        OAuth2Authentication authentication = super.extractAuthentication(claims);
        authentication.setDetails(claims);
        return authentication;
    }
}

@Component
public class TokenPayload {

    private Map<String, Object> getExtraInfo() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        OAuth2AuthenticationDetails oauthDetails = (OAuth2AuthenticationDetails) auth.getDetails();
        @SuppressWarnings("unchecked")
        var details = (Map<String, Object>) oauthDetails.getDecodedDetails();
        return details;
    }

    public String payloadLogin() {
        return getExtraInfo().get("user_name").toString();
    }

    public Long payloadIdEmpresa() {
        return Long.parseLong(getExtraInfo().get("idEmpresa").toString());
    }

    public Long payloadIdFuncionario() {
        return Long.parseLong(getExtraInfo().get("idFuncionario").toString());
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...