Home > Software design >  How to get jwt token value in spring webflux? (to exchange it with Minio STS token)
How to get jwt token value in spring webflux? (to exchange it with Minio STS token)

Time:12-22

I have sping-boot application with rest services written using Spring web flux.

For now I access minio using login/password authorizaton and it works fine.

For now I want to exchange application JWT token with STS minio token and I implemented method to test:

@PostMapping
public boolean test(JwtAuthenticationToken token) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
    MinioClient minioClient =
            MinioClient.builder()
                    .region(...)
                    .endpoint(...)              
                    .credentialsProvider(new WebIdentityProvider(
                           
                            () -> new Jwt(token.getToken().getTokenValue(), 1000),
                            String.valueOf(...),
                            null,
                            null,
                            null,
                            null,
                            null))
                    .build();
    return minioClient.bucketExists("mybucket").build());
}

This code successfully works and returns true because mybucket actually exists.

But it is only test and I need to move minioClient to the configuration. The issue here that I have to have credentials provider there.

So I've created folowing configuration:

@Bean
public MinioClient minioClient() {
    return MinioClient.builder()
            .region(...)
            .endpoint(...)
            .credentialsProvider(new WebIdentityProvider(
                   
                    () -> {
                        String block = null;
                        try {
                            block = ReactiveSecurityContextHolder
                                .getContext()
                                .map(context -> {
                                            return context
                                                    .getAuthentication()
                                                    .getPrincipal();

                                        }
                                )
                                .cast(Jwt.class)
                                .map(Jwt::token)
                                .block();
                        } catch (Exception e) {
                            // it fails here     <=======
                            System.out.println(e);
                        }

                        Jwt jwt = new Jwt(String.valueOf(block),
                                1000);
                        return jwt; },
                    String.valueOf(...),
                    null,
                    null,
                    null,
                    null,
                    null))
            .build();
}

But unfortunately method block() fails with exception:

java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-6 

Any ideas how to fix it?

CodePudding user response:

As Numichi stated in the comment you have to stay in the reactor context. One option is to create a bean of type Mono<MinioClient>.

    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public Mono<MinioClient> reactiveMinio() {
        return ReactiveSecurityContextHolder.getContext()
                .map(securityContext ->
                        (Jwt)securityContext.getAuthentication().getPrincipal())
                .map(jwt -> MinioClient.builder()
                        .region("someRegion")
                        .endpoint("someEndpoint")
                        .credentialsProvider(webIdentityProvider(jwt.token()))
                        .build());
    }

    private WebIdentityProvider webIdentityProvider(String token) {
        return new WebIdentityProvider(() -> new Jwt(token, 1000),
                "stsEndpoint",
                null,
                null,
                null,
                null,
                null);
    }

I think bean scope should be prototype since MinioClient is bound to security context.

Here is the sample usage of reactive MinioClient:


@RestController
public class MinioTest {

    private Mono<MinioClient> minioClient;

    public MinioTest(Mono<MinioClient> minioClient) {
        this.minioClient = minioClient;
    }

    @GetMapping("/minio")
    public Mono<Object> client() {
        return minioClient
                .map(minio -> {
                    try {
                        return minio.bucketExists(BucketExistsArgs
                                .builder()
                                .bucket("my-bucketname")
                                .build());
                    } catch (Exception e) {
                        return new Exception(e);
                    }
                });
    }
}


  • Related