oAuth Token for Anonymous User in Spring boot - java

Team
Using Spring boot I am able to accomplish workflows, where oAuth server can generate the token for the logged-in user. However, how does the oAuth server generate a unique token for each anonymous user?
For e.g. if 2 concurrent users are trying to access the resource server from their respective browsers, then I would like the resource server to identify the 2 different users in each subsequent requests that they make. For that, I would like to generate different tokens for each anonymous user. Is that possible and if yes then how?

It is simple thing, you are making it complex.
I would like to generate different tokens for each anonymous user. Is that possible
Once you generate valid token, user will become authenticated user.
You might think about validating token and setting ROLE='ROLE_ANONYMOUS'. As I told it will be like making simple thing to complex. Making authenticated user to Anonymous user is not good approach. You can create a new role like ROLE_SEMIANONYMOUS and grant authorities which were open for ANONYMOUS user.
(but this approach doesn't make any sense for me so explaining alternative to achieve your requirement of identifying AnonymousUser)
As "Anonymous User = UnAuthenticated User".
For anonymous user if you print principal
String principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
principal = "anonymousUser"
You can create a session for anonymous user for identifying him as given below
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Object principal = authentication.getPrincipal();
if(principal instanceof String && ((String)principal).equalsIgnoreCase("anonymousUser"))
{
if(request.getSession(false) == null)
{
HttpSession session = request.getSession();
session.setMaxInactiveInterval(300); // As per Your requirement
// store session id from session and ip address from request in to DB or cache if required and use it
}
else
{
//identify anonymous user against session id and stored details
}
}
You can achieve this by registering a filter
In convetional spring order of filter should be after springSecurityFilterChain.
In spring boot you can achieve it by FilterRegistrationBean

Related

Different response based on logged user role

In my RestController I have POST method which returns different object based on user role:
#PostMapping("getlocal")
#PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
public ResponseEntity<LocalDto> getLocal(#RequestBody LocalRequest localRequest){
return status(OK).body(localService.findLocalBylocalId(localRequest));
}
Service method:
public LocalDto findLocalBylocalId(LocalRequest localRequest) {
Role role = userRoleRepository.findByUsername(localRequest.getUsername());
if(role == Role.ROLE_ADMIN) //return localDto infromation object for ADMIN
else if(role == Role.ROLE_USER) //return localDto information for USER
}
LocalRequest contains username of current logged in user.
The problem is when user will authenticate and hit this endpoint he can pass to RequestBody admin's username. In this case he will get access to admin resources even if he is logged as USER.
How to avoid this situation and modify the code?
Should I create two different endpoints - one secured only for USER, and one secured only for ADMIN?
Should I pass Principal object instead passing username in POST method as parameter? Can I pass Princpal object if I am using jwt mechanism?
You can access the currently authenticated username by specifying Principal as an argument. For example:
#PostMapping("getlocal")
#PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
public ResponseEntity<LocalDto> getLocal(Principal principal){
return status(OK).body(localService.findLocalBylocalId(principal.getName()));
}
This works because Spring MVC will resolve the Principal argument from the HttpServletRequest.getUserPrincipal() method and Spring Security overrides the method to align with the currently logged in user. You would then need to update your LocalDto to accept a username instead of a Localrequest.
Alternatively, you can also resolve the entire Spring Security Authentication in the same way since the HttpServletRequest.getUserPrincipal() will be an Authentication.
#PostMapping("getlocal")
#PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
public ResponseEntity<LocalDto> getLocal(Authentication authentication){
return status(OK).body(localService.findLocalBylocalId(principal.getName()));
}
This gives you access to the roles without needing to look them up again. The disadvantage of this approach is that you are now relying on Spring Security's API directly.
You can also consider using the #AuthenticationPrincipal annotation to decouple yourself from Spring Security. This approach is the best if you need access to more than just the username because you can still be decoupled from Spring Security, but it also involves more work (i.e for username/password authentication you need a custom UserDetailsService, custom UserDetails). Because the amount of work/variables here, it is difficult to provide more guidance than a link to the documentation without further details.

JWT Spring - user based access

I'm implementing JWT based authentication in my Spring boot application. I have an Accounts table which contains user's bank account info. Now, the user signs in using Account number and pin from that table. The problem is that after logging in, user can access anything with the token assigned to it by JWT. He can even change someone else's account info. How can I restrict the access only to the user for which the token is created?
Every user should be able to access info associated with that user only, so creating roles is not an option. Does JWT provides any such feature or do i have to check the tokens manually? I can parse the token and retrieve the account number out of it and compare it with the account number passed in controller methods, but it doesn't seem like a neat solution as this will require changing every Controller method.
As security in your case depends on business logic I guess there is no way to perform such verification on the Auth provider side.
What you can do is to implement it with the help of the Spring in AOP way quite elegant. You could use spring method security with custom securiry resolver
#PreAuthorize("#securityResolver.isOwner(#userId)")
void changeAccount(UUID userId, Request body);
#Component("securityResolver")
public class CustomSecurityResolver {
public boolean isOwner(final String userId) {
//TODO business check here
}
}
You could even pass JWT token to the security resolver method and implement custom check. In this case you can avoid changing business logic of your service and just add couple of annotations with custom resolver.
I've always implemented such checks as user could only change its own info or tenant isolation with the help of custom method security

Java SE - storing currently logged in user details

Current approach in my Java SE app is to (once authenticated) store only the username as a system property, which I understand may have security implications
Whenever an action is attempted to be performed that requires a certain role, this username is used to make a call to the database to check whether the given user has the role.
I would prefer to load all the roles up front - then to check against some "User" object whether they were permitted for access. All of this needs to be done in a very controlled way, though.
Is there a standard approach / framework for this? Bare in mind I have already authenticated, and just want to store the user's details. Would storing the currently logged in user as a Singleton be a sensible way to approach this?
You could use JAAS for authentication and authorization in your application. This framework is applicable for all java applications (Web,Standalone, Java EE etc)
Another option could be Spring Security. In Spring Security there is class SecurityContextHolder where you can store the authentication status (Roles) once the user is authenticated. Later this could be use to verify user role when trying to access any operation. This should not be web application , you can use it in java SE.
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new RestUserAuthrity("ROLE_USER"));
CustomAuthenticationToken authenticationToken = new CustomAuthenticationToken(authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
During the method call or where you want to check the role. Just get the role from SecurityContextHolder and verify appropriate role.
I suggest you to use spring framework for session management as well as spring give you currently logged in users list then you can stored logged in users.

Spring security openId support and user deauthentication

I am trying to handle a situation when after an successful authentication with openId provider I discover that there is no account in my db associated with user openId identifier.
Can you tell me how should I handle the situation. Now, I am displaying register form and ask a user for creating an account. However, I have a problem with user authentication status, he is now being seen as authenticated by spring SecurityContext class.
How do I deauthenticate user in my controller action before redirecting to ''register new user page''? Is this approach a good one or should I do it in some other way?
Ok, so separating authentication from authorization as was mentioned in Samuel's post was really helpful. However there are still many gotchas and I found deauthentication still a must because there is no easy way in spring to add to user new roles. So the easiest way is to force user to login again and let spring handle role assignment during login.
In order to deauthenticate user in spring security you have to invoke:
SecurityContextHolder.clearContext();
as an alternative you can throw an exception in your UserDetailsService implementation (see below). It has the downside that you would deauthenticate user and lose user context data so it would be impossible to match new user accout with openid account during process of creating new local account. And you have to match those account after user login with traditional username and password. My solution was to deauthenticate user just after creating new account.
In order to grant user roles(privileges) you have to override UserDetailsService, in case someone find this useful here is my implementation:
public final class MyUserDetailsService implements UserDetailsService {
private final UsersDao usersDao;
#Autowired
public UserDetailsServiceImpl(final UsersDao usersDao) {
this.usersDao = usersDao;
}
#Override
public UserDetails loadUserByUsername(final String username) {
UserEntity user = usersDao.getUserByOpenIdIdentifier(username);
if (user == null) {
// there is no such user in our db, we could here throw
// an Exception instead then the user would also be deuthenticated
return new User(username, "", new ArrayList<GrantedAuthority>());
}
//here we are granting to users roles based on values from db
final Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(user.getUserType().toString()));
final UserDetails result = new User(username, "", authorities);
return result;
}
}
I think that you might be mixing two concepts: authentication and authorization. Authentication is knowing who the user is, authorization is the right to use access a resource of a feature.
In spring security, this two concepts are implemented by the authentication-manager and the access-decision-manager.
The fact that a user does not exist in your database is not a reason to deny him is identity: no deauthentication! But beeing authenticated can be a criterion in the access decision management. Example: the AuthenticatedVoter.
You should not touch at the authentication, but customize the access-decision-manager to apply the following rules:
A user who exists in your database has access to everything except account creation feature
A user who doesn't exist in your database has access only to the account creation feature.
This is all about access management, not authentication.
Read more at http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html#ns-access-manager
PS: The documentation is not exhaustive in spring security, but the source code is very readable. My advice is to check it out and look at the implementation of the elements you need to customize.

How to add a role filter on request combined with OAuth

I would like to develop a portal which contains some modules
The portal and each module consume data provided by a webservice based on Jersey and secured with OAuth 1.0
For the moment I have almost implement the OAuth provider
A user can connect to the portal and access to a module
Each app or module has a specific access token to consume resource
What I want to do is to add a role implementation
For example for the module1, the user can have 2 roles (role1 and role2) but can't use the 2 roles in parallel
First the user uses the access (module1 / user1 / role1) and he will have a token and later the user uses the access (module1 / user1 / role2) and he will have an other token
Depending on the role, I would like to filter the request with a RolesAllowed annotation for example
I have read this article: http://objecthunter.congrace.de/tinybo/blog/articles/89
When the user is authenticated to the web service I could persist in a database the username, and the role used for the module and the RolesAllowedResourceFilterFactory could use the realm to check if the user is in the role and can access to the resource
But can I by-passed the auth method?
Anyway I really need your help to implement this role filter thing
I will try to give you more details if you need
Thanks
The Jersey oauth filter sets the security context based on what access token was used. You just have to make sure your custom implementation of the oauth provider assigns a token with the right return values from the isInRole() method when called with various roles. The role for a given token can be established during the token authorization flow (e.g. the client can request a particular role using a custom parameter that it passes to the server when requesting a request token (this gets passed in the parameters parameter to the provider.newRequestToken() method).
The security context that the oauth filter sets will delegate to the token isInRole() method when determining the roles - and the RolesAllowedResourceFilterFactory relies on the security context. So, everything should work as expected if OAuthToken.isInRole() returns the right value. Are you facing any issues?
I know it is an old post but I was facing similar issue. In my case I solved it exactly the same way as Martin described. During token authorisation I set allowed roles:
String verifier = provider.authorizeToken(token, sContext.getUserPrincipal(), roles);
where provider is #Context DefaultOAuthProvider, token is DefaultOAuthProvider.Token and roles is a Set of roles I want to allow the access by this token:
Set<String> roles = new HashSet<String>();
roles.add("someRole");
Then in my service I just use a #Context SecurityContext method isUserInRole("someRole") which gives me true in case the user is in specified role and false if not:
if (sContext.isUserInRole("someRole")) {
....
}
Hope it will help somebody.

Categories