MongoOperation Override the Audit Information - spring-boot

I am using #CreatedBy and #LastModifiedBy for saving Audit information and i am getting the author from JWT Token which is working perfectly fine.
But when i save the some data using MongoOperation.save() it will override the the audit information and not getting the information from JWT token.

Related

Oauth2 flow to issue tokens for registered users automatically

I have an endpoint, which I want to protect using Oauth2 and spring boot. The users register on the website and after the successful payment, a token with specific expiry should be issued automatically and delivered to the user. The User can revoke the token in their panel and get a new token manually.
I don't want to use password grant type as it requires sending the username and password for each request. the authorization code grant type, requires the user to enter their credentials which doesn't fit my need for automatic generation of tokens after successful payment. I'm not sure if using client credentials grant type is a good idea for my need. I could use a new client for each new user. But this seems not right to me. But correct me if I'm wrong. any idea which oauth flow I should use?
You want to authenticate end-users with OAuth2? Use authorization-code (with PKCE).
In your statements, there seem to be a confusion between authorization-server (issues tokens) and resource-server (subscriptions are resources too in my opinion). Have a look at this article for OAuth2 refresher and spring resource-server security conf.
Also, it seems to be a one-to-one relation between access-token and payed subscription. This is probably a mistake: access-token should be short lived (like a few minutes). Are your subscriptions that short?
I see two options here:
have your authorization-server add a private claim with subscription status to JWT access-token (or introspection details) and check this claim value in spring-security expressions (#PreAuthorize("..."))
configure a custom authentication converter in spring security which calls a #Repository to read subscription status in database, based on identity contained in access-token
First solution is way more efficient (persisted subscription status is retrieved from DB only when a new access-token is issued) but requires your authorization-server to be flexible enough for you to add private claim with values from a web-service or a DB. I have a tutorial to do so in Keycloak. read it AFTER the article above.

How to store the user uuid and role after authentication in spring security JWT

Hello I want to store the userUUID and role extracted from the JWT for all database queries.
Right now Im passing the useruuid and role as request param for each request.
Thanks
You should store these in the JWT payload itself.
Parse JWT and verify signature if present, on each request and then use them accordingly.
These details should never come from user input or a place where user can modify them.

Update fields of the principal at the runtime

I use OAuth2 authentication with my own authorization and resource server in Spring Boot. I want to change some fields in my User implements UserDetails(it's my Principal) object at runtime on behalf of the same user or on behalf of another user(administrator/moderator). E.g. user1 with id=1 want to change his country, so he calls this method:
#PostMapping("/setMyCountry")
public void setMyCountry(#CurrentUser User user, #RequestParam String newCountry){
user.setCountry(newCountry);
userRepository.save(user);
}
But when I want to check his country using this:
#GetMapping("/getMyCountry")
public String getMyCountry(#CurrentUser User user){
return user.getCountry();
}
I get the same old country.
Similarly, with the changes as administrator:
#PostMapping("/setUserCountry")
public void setUserCountry(#CurrentUser Moderator moderator, #RequestParam String newCountry){
User user = userRepository.findById(1L).get();
user.setCountry(newCountry);
userRepository.save(user);
}
#GetMapping("/getUserCountry")
public String getUserCountry(#CurrentUser Moderator moderator){
User user = userRepository.findById(1L).get();
return user.getCountry();
}
It returns the same country. But, of course, the DB shows new value.
I already saw question about the similar issues, but if I use this in setMyCountry():
Authentication newAuth = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(newAuth);
then this still doesn't work. Please note, that I use my custom tokens, token providers and token granters, but they all return UsernamePasswordAuthenticationToken at the end.
So, how can I change field of the User and update current principal without log out and log in?
Common practice when using oauth2 is that the Authentication server knows nothing about the users, more than user name, password, what roles, and an some sort of key so it can look up the user object. This can be a unique UUID, or the username (subject) as in an email address.
The resource server gets a token from a client, it takes this token and then calls the authorization server to verify the token, the authorization server verifies it and if verified then sends back information to the resource server so that the resource server can populate its UserDetails object.
If the resource server needs to know say what country this user lives in, it gets the id from the Principal/UserDetails object and then calls maybe a user service, or another database, or another table, or even back to the authorization server that maybe has a /user endpoint and presents the token to the authorization server (that in turn gets the principal info, gets the subject and then looks up in a database for the user info) and then send the user object back.
What my point is that you should always separate Authentication and Authorization (roles etc) information, from the actual User information.
What if you change from say using facebook authentication to github authentication. Do you need to redo all the users? no, because you have all user information separated from the authorization information.

Adding security to spring webservice for password

i am new to spring. i need to make a user registration form where user will provide their basic details and password which i am directly saving to database.password is as string datatype in registration bean and varchar in database.
Now my approach is that i will do the service call from mobile or website to that web service and send password as plain text.
But i think this is not a good way as there is no security while sending data through webservice or in server code or in database, password is just a string with few validations.
Is there a good approach to do this task according to industry standards.
Thank you in advance.
Also i want that my password should not be intercepted by hackers or in server. The password should go in encrypted form from client and should save in database.Nobody managing server/DB should see that password.
Use BCryptPasswordEncoder provided by Spring Security to encrypt your user's password and store hashed password string to the database.
Example:
#Transactional
#Override
public User create(UserCreateForm form) {
User user = new User();
user.setEmail(form.getEmail());
user.setPasswordHash(new BCryptPasswordEncoder().encode(form.getPassword()));
user.setRole(form.getRole());
return userRepository.save(user);
}

Azure B2C Access Token NULL Spring OAuth 2.0

I am trying to get a custom web application to work with Azure B2C OAuth and the Spring OAuth2.0 framework.
The authentication leg comes back fine and I receive a JWT token. When the request for a token occurs afterwards I get the following error:
java.lang.IllegalStateException: Access token provider returned a null access token, which is illegal according to the contract.
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:223) ~[spring-security-oauth2-2.0.8.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.0.8.RELEASE.jar:na]
...
From some debugging of the spring code I can see the token is expected to be called access_token as seen in the OAuth2AccessToken class. From looking at the B2C tutorials their token is called token_id. Furthermore the applications.yml config I have for my spring application has a field called tokenName. Surely this should be used to pick up the token name field instead of the hardcoded static variable as above.
Am I missing something and is there a solution to my problem. Can I override the token name field used by the spring OAuth framework?
I'm going to go ahead and post this as the answer.
I started with the Spring tutorial, and made some modifications to it. For a working example, see the public github repo: https://github.com/Pytry/azure-b2c-oauth2.git
To properly parse the token received you will need:
A custom implementation of an AccessToken that will parse the JWT, pulling and setting variables as required by spring security. I extended DefaultOAuth2AccessToken and added this parsing to a private method called by the constructor.
If you are going to verify the RSA signature using the public keys, you will need a custom JWT object so you can access the header information. I chose to extend springs JWT, and add some parsing on creation to access the header. It may also be useful to have some custom Pojos for parsing the returned meta data and rsakey information into.
An extension of the JwtAccessTokenConverter, with an overridden "decode" method. Azure does not give a "user_name" nor a "client_id" in the returned id_token, so you need to add those. I also included some logic in the super class that I found suefull (such as converting strings to int/long when appropriate).
A custom UserDetailsManger to override the default in memory one. This can either retrioeve user information from the GraphAPI, or it can load it from your user repository. I actually did not create either of these, and instead used the default in memory service, but injected it into the token converter; then whenever a user was properly authenticated, I would add them to the managers store, or update them if they already existed.
There are a few things I have not done yet.
RSA verification is not being done. Any help on this is appreciated.

Resources