cf-java-client icon indicating copy to clipboard operation
cf-java-client copied to clipboard

Authentication issues from Cloud foundry V2

Open petyorusanov opened this issue 2 years ago • 1 comments
trafficstars

Hello everyone, we are using the cloud foundry V2 client for creating/updating Hana Cloud service instances.

The error is

unauthorized: {"error":"invalid_grant","error_description":"User authentication failed: Unauthorized"}

We have a spring boot app and they way we initialize our CF client is with a @Configuration class on application start.

  @Bean
  public DefaultConnectionContext connectionContext() {
    String cfApi = CfToolsHelper.getCfApi();
    String host = cfApi.substring(cfApi.lastIndexOf("/") + 1);
    return DefaultConnectionContext.builder().apiHost(host).build();

  }

  @Bean
  CloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
    return ReactorCloudFoundryClient.builder()
                                    .connectionContext(connectionContext)
                                    .tokenProvider(tokenProvider)
                                    .build();
  }

  @Bean
  ReactorDopplerClient dopplerClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
    return ReactorDopplerClient.builder().connectionContext(connectionContext).tokenProvider(tokenProvider).build();
  }

  @Bean
  ReactorUaaClient uaaClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
    return ReactorUaaClient.builder().connectionContext(connectionContext).tokenProvider(tokenProvider).build();
  }

We have a technical user and for the authentication we user username and x509 certificate. With it we create a one-time, 5 minute-living passcode with which we create initialize a bean of PasswordGrantTokenProvider:

return PasswordGrantTokenProvider.builder().password(passcode).username(username).build();

which is used for the init of the client above. After that we do not re-initialize PasswordGrantTokenProvider during the lifetime of the app.

We haven't seen any concrete dependency on why and when the error is thrown. E.g. after application start there can be multiple successful executions in the timespan of several hours, but after that it start failing(here I cannot say if from this point on it fails every time or if there can still be successful executions after the first failure, but for sure it fails more than not).

petyorusanov avatar Jun 28 '23 13:06 petyorusanov

Once the TokenProvider is set in ReactorUaaClient it can not be changed. Similarly, once the password is set in PasswordGrantTokenProvider, it can not be changed.

As you are using "a one-time, 5 minute-living passcode", I would guess that you're able to authenticate successfully at initialization time. The ReactorUaaClient is able to get an authentication token that it uses to refresh the access token but at some point the authentication token expires and it tries to get a new one with the original "a one-time, 5 minute-living passcode" which is now out of date.

I would need more information (like debug logs) to verify this.

For your use case, I don't believe that PasswordGrantTokenProvider is the right token provider. Extending PasswordGrantTokenProvider with your own token provider that generates a new "one-time, 5 minute-living passcode" every time the password is requested would be more suitable.

mheath avatar Jun 28 '23 21:06 mheath