How to locally validate JWT using JwtDecoder? - java

Rule: I must use the JwtDecoder implementation. We're using different jwt validations. Mostly external. This is the first time we're doing internal JWT creation encoding and then decoding with validation.
private JwtDecoder sampleDecoder(String issuerUri, String jwkUri) {
OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefaultWithIssuer(issueUri);
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkUri).build();
jwtDecoder.setJwtValidator(jwtValidator);
return jwtDecoder;
}
So previously, it was login via the external API, they give a token, then per request we validate that token using the JwtDecoder created with the JwkSetUri.
The problem I'm having now is I need to create a JwtDecoder for our internally made token. Here's how I made the token.
public String createToken(String mobileNumber) throws JOSEException {
JWTClaimsSet jwtClaimsSet = new JWTClaimsSet.Builder()
.issuer(securityProperties.getConciergeIssuer())
.claim("mobileNumber", mobileNumber)
.claim("roles", "ADMIN")
.build();
ECKey ecKey = new ECKeyGenerator(Curve.P_256)
.keyID("123")
.generate();
JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.ES256)
.type(JOSEObjectType.JWT)
.keyID(ecKey.getKeyID())
.build();
SignedJWT jwt = new SignedJWT(jwsHeader, jwtClaimsSet);
jwt.sign(new ECDSASigner(ecKey.toECPrivateKey()));
String token = jwt.serialize();
return token;
}
And as for it's JwtDecoder implementation, this is how I did it:
private JwtDecoder customDecoder(String issuer) {
OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefaultWithIssuer(issuer);
byte[] decoded = Base64.getDecoder().decode(securityProperties.getConciergeSecret());
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder
.withSecretKey(new SecretKeySpec(decoded, 0, decoded.length, "AES"))
.build();
jwtDecoder.setJwtValidator(jwtValidator);
return jwtDecoder;
}
Now I know it does not add up. I'm not sure where to use the secret key in token creation, and i'm having trouble creating the decoder. Is there a more proper way for this?

Problem solved. I basically created my own implementation of JwtDecoder (literally just implemented JwtDecoder into my own class), overrode the decode method, and made my own implementation of how to validate the token (e.g. get the claims and check expiry)

Related

how to auto-refresh AWS STS Temporary security credentials when it expires while accessing Amazon SQS?

I've spring boot app with QueueMessagingTemplate as client to access Amazon SQS using temporary security credentials(STS). Getting temp token using STS-AssumeRole . Can you help me how to refresh/auto-refresh session token when it expires?
Error:
com.amazonaws.services.sqs.model.AmazonSQSException: The security token included in the request is expired
Here is the code:
#Configuration
#Slf4j
public class QueueConfig {
#Bean
public QueueMessagingTemplate queueMessagingTemplate(#Autowired BasicSessionCredentials sessionCredentials) {
log.info("queueMessagingTemplate refresh");
return new QueueMessagingTemplate(amazonSQSAsync(sessionCredentials));
}
#Bean
#Primary
public AmazonSQSAsync amazonSQSAsync(BasicSessionCredentials sessionCredentials) {
return AmazonSQSAsyncClientBuilder
.standard()
.withRegion(Regions.US_WEST_1)
.withCredentials(new AWSStaticCredentialsProvider(sessionCredentials))
.build();
}
}
Here is the code for AWS STS cred
#Configuration
#Slf4j
public class AwsRoleCredentials {
#Bean(name = "sessionCredentials")
public BasicSessionCredentials sessionCredentials(){
try {
String roleArn = "XXXX";
String roleSessionName = "XXX";
Region region = Region.US_WEST_1;
StsClient stsClient = StsClient.builder()
.region(region)
.build();
AssumeRoleRequest roleRequest = AssumeRoleRequest.builder()
.roleArn(roleArn)
.roleSessionName(roleSessionName)
.build();
AssumeRoleResponse roleResponse = stsClient.assumeRole(roleRequest);
Credentials myCreds = roleResponse.credentials();
BasicSessionCredentials sessionCred = new BasicSessionCredentials(
myCreds.accessKeyId(),
myCreds.secretAccessKey(),
myCreds.sessionToken());
return sessionCred;
} catch (StsException e) {
log.error("ERROR while get token:"+ e.getMessage());
}
return null;
}
}
I was just about to implement it myself and then i found that in version 2 of the sdk its already there, you can use StsAssumeRoleCredentialsProvider which takes care of refreshing the token when it is about to expire. I don't know if there is something equivalent in the old SDK.
But you can implement it pretty easily for the older SDK as well, just store the expiry and make another assumeRole request when it's about to expire
Edit- I was confused because you use the v1 sdk for SQS but you do use the V2 SDK for STS, so you can simply use StsAssumeRoleCredentialsProvider instead. Also, I suggest using either V1 or V2, but not both

How to perform a refresh with spring-boot-starter-oauth2-client

I'm using spring-boot-starter-oauth2-client to authenticate my user with Google. This works well and I can sign in and get valid access and refresh token as expected.
I'm creating the access token as such:
public class TokenServiceImpl implements TokenService {
private final OAuth2AuthorizedClientService clientService;
#Override
public GoogleCredentials credentials() {
final var accessToken = getAccessToken();
return getGoogleCredentials(accessToken);
}
private GoogleCredentials getGoogleCredentials(String accessToken) {
return GoogleCredentials
.newBuilder()
.setAccessToken(new AccessToken(accessToken, null))
.build();
}
private String getAccessToken() {
final var oauthToken = (OAuth2AuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
return clientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(),
oauthToken.getName()).getAccessToken().getTokenValue();
}
}
The token is ultimately being used in the Google Photo API client as such
private PhotosLibraryClient getClient() {
final var settings =
PhotosLibrarySettings
.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(tokenService.credentials()))
.build();
return PhotosLibraryClient.initialize(settings);
}
The problem is that the token will expire after a short period and I'd like to refresh it to keep it active.
I'm unsure what pattern of methods I can use to do this, without having to write the entire OAuth flow (defeating the purpose of something like the Spring oauth2-client).
So far I have no other token/security/filter logic in my application.
Do I just need to write it all out manually, or is there another way I can do this?
The OAuth2AuthorizedClientManager will take care of refreshing your access token for you, assuming you get a refresh token along with your access token. The doco for OAuth2AuthorizedClientManager is at
https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2client
When configuring your OAuth2AuthorizedClientManager, make sure you have included refreshToken in the OAuth2AuthorizedClientProvider...
#Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
return authorizedClientManager;
}
You then use the OAuth2AuthorizedClientManager to get the access token. The sample from the spring doco is below...
#Controller
public class OAuth2ClientController {
#Autowired
private OAuth2AuthorizedClientManager authorizedClientManager;
#GetMapping("/")
public String index(Authentication authentication,
HttpServletRequest servletRequest,
HttpServletResponse servletResponse) {
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(authentication)
.attributes(attrs -> {
attrs.put(HttpServletRequest.class.getName(), servletRequest);
attrs.put(HttpServletResponse.class.getName(), servletResponse);
})
.build();
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
...
return "index";
}
}
If the current accessToken has expired, this will automatically request a new accessToken using the previously obtained refreshToken.

How to set any attribute in ClientRegistration in spring oauth2

Since I cannot keep client secret in application.yml , so it's kept in vault and from there it gets resolved. However, I can see that ClientRegistration is a final class , hence it's client secret can't be set later once the bean is already initialized.
In such case how can I set secret & use new object of ClientRegistration in all the referred beans.
Something like below I am trying to achieve but don't how to set enrichedClientRegistration in webclient or other referred places.
#Slf4j
#Configuration
public class WebClientConfig {
#Bean
WebClient authWebClient(ClientRegistrationRepository clientRegistrations,
OAuth2AuthorizedClientRepository authorizedClients,
PasswordResolver passwordResolver) {
var clientRegistration = clientRegistrations.findByRegistrationId("myApp");
log.info("Before client secret is {}",clientRegistration.getClientSecret());
var clientSecret = passwordResolver.resolve(clientRegistration.getClientSecret());
log.info("Resolved client secret is {}", clientSecret);
var enrichedClientRegistration=ClientRegistration.withClientRegistration(clientRegistration)
.clientSecret(clientSecret)
.build();
log.info("After client secret is {}",clientRegistrations.findByRegistrationId("myApp").getClientSecret());
var oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
oauth.setDefaultClientRegistrationId("myApp");
return WebClient.builder()
.apply(oauth.oauth2Configuration())
.build();
}
}
Since ClientRegistration is a final class which in injected into ClientRegistrationRepository, so you need completely override ClientRegistrationRepository as per example given in spring documentation.
https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/jc.html#jc-oauth2login-completely-override-autoconfiguration

Why does the JdbcClientTokenServices not save refresh tokens?

I have a Spring application that acts as an OAuth2 client. I implemented a JdbcClientTokenServices to persist the tokens for each user that succesfully authenticates.
#Bean
public OAuth2RestTemplate restTemplate(OAuth2ClientContext clientContext) {
OAuth2RestTemplate template = new OAuth2RestTemplate(resource(), clientContext);
AccessTokenProviderChain accessTokenProvider = new AccessTokenProviderChain(
Collections.<AccessTokenProvider>singletonList(
new AuthorizationCodeAccessTokenProvider()
));
accessTokenProvider.setClientTokenServices(clientTokenServices());
accessTokenProvider.supportsRefresh(resource());
template.setAccessTokenProvider(accessTokenProvider);
return template;
}
#Bean
public JdbcClientTokenServices clientTokenServices() {
return new JdbcClientTokenServices(dataSource);
}
This code makes use of a oauth_client_token table. When I looked for the content in this table, I noticed it only saves the access token? I was wondering why the refresh token does not get saved aswell since the refresh token should be longer lived than the access token anyway.

Store access token in OAuth2.0 application and use it repeatedly until it expires?

I'm developing an OAuth2.0 "CLIENT" application which call some APIs(secured by oauth2.0).
I'm using OAuth2.0RestTemplate which contains CLIENT_ID, CLIENT_SECRET, username and password. The code for calling OAuth2.0 secured APIs looks like this:
#Bean
OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
List<String> Scopes = new ArrayList<String>(2);
Scopes.add("read");
Scopes.add("write");
resource.setClientAuthenticationScheme(AuthenticationScheme.header);
resource.setId("*****");
resource.setAccessTokenUri(tokenUrl);
resource.setClientId("*****");
resource.setClientSecret("*****");
resource.setGrantType("password");
resource.setScope(Scopes);
resource.setUsername("*****");
resource.setPassword("*****");
return resource;
}
#Autowired
private OAuth2RestTemplate restTemplate;
Map<String, String> allCredentials = new HashMap<>();
allCredentials.put("username", "***");
allCredentials.put("password", "***");
restTemplate.getOAuth2ClientContext().getAccessTokenRequest().setAll(allCredentials);
ParameterizedTypeReference<List<MyObject>> responseType = new ParameterizedTypeReference<List<MyObject>>() { };
ResponseEntity<List<MyObject>> response = restTemplate.exchange("https://***.*****.com/api/*****/*****",
HttpMethod.GET,
null,
responseType);
AllCities all = new AllCities();
all.setAllCities(response.getBody());
As you can see everytime I want to call a service the code get a new ACCESS TOKEN which is wildly wrong!!! My question is how can I automatically receive and store the issued token in my application an use it until it expires and then automatically get a new one?
On the other hand my token only contains access token and doesn't contain refresh token(I don't know why!!! this is so weird!!!)
Hello you can design like google client library.
First step you need to create the datastore for store the token in your directory like C:/User/soyphea/.token/datastore.
Before you load your function retrieve access_token_store. Your access token should have expired_in.
if(access_token_store from your datastore !=null && !expired){
access_token = access_token_store.
} else {
access_token = Your RestTemplate function for retrieve access_token.
}
finally you can retrieve access_token.
In spring security oauth2 if you want to support refresh_token you need to set,
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("resource-serv")
.scopes("read")
.resourceIds("my-resource")
.secret("secret123")
.and()
.withClient("app")
.authorizedGrantTypes("client_credentials", "password", "refresh_token")
.scopes("read")
.resourceIds("my-resource")
.secret("appclientsecret");
}
First of all you have define that your app is a Oaut2App for this in Spring boot you can use the annotation #EnableOAuth2Client in your code and configure the client application metadata in your applicaition.yml. A skeleton client app can be like below:
#EnableOAuth2Client
#SpringBootApplication
public class HelloOauthServiceApplication {
public static void main(String[] args) {
SpringApplication.run(HelloOauthServiceApplication.class, args);
}
#Bean
public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ProtectedResourceDetails resource){
return new OAuth2RestTemplate(resource);
}
}
application.yml
security:
oauth2:
client:
clientId: client
clientSecret: secret
accessTokenUri: http://localhost:9090/oauth/token
userAuthorizationUri: http://localhost:9090/oauth/authorize
auto-approve-scopes: '.*'
registered-redirect-uri: http://localhost:9090/login
clientAuthenticationScheme: form
grant-type: passwordR
resource:
token-info-uri: http://localhost:9090/oauth/check_token
in this way you have guarantee that the OAuth2RestTemplate of spring will use and upgrade the token

Categories