Spring security access roles inside a method - spring

In Spring security is it possible to get roles and properties the user might have associated with their token inside a method?
#PreAuthorize("hasAuthority(T(ROLES.Admin)")
#Timed
public ResponseEntity<base> save(#RequestBody body) throws URISyntaxException {
// here i want to get all the data associated whit this user ie. jwt token
// roles etc .. as i need to pass this on
}
I have seen you can get the principal

Yes,you can get it through Principal.like this:
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
user.getAuthorities();

Related

What is the best way accessing username from request

I am developing a simple todo application with Spring Boot. I am using JWT for authorisation. All todos belongs to a user will be get with following endpoint.
#GetMapping("")
public List<Todo> todos(){
//get username from token
//return todos belongs to user
}
I have two problems in here:
Is getting username from token a good practise?
What is the best way accessing username with token from a controller class or a service class?
This answer shows how to reach token from controller class.
but what if we want to reach token from service class? This answer shows it. But the class is deprecated.
you can get username like this:
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
String username = userDetails.getUsername();

Roles and Permission at method level Spring boot

I need to have authorization at the method level so that the users with proper permissions only can access it. The method will contain a token as a parameter. I need to make an API call passing the token and get the user email id. Once I have the email id, I need to fetch the user's roles & permissions from the database. Then I invoke the method if the user have appropriate roles else return a 403 error.
Is there a way to get this done in spring boot? I will have multiple methods behind authorization and would like to have some kind of annotation at method level.
Thanks.
#PreAuthorize annotation is what you want
Please read the following link for spring method level authorization
baeldung method authorization
you will also need to undestand SPEL(Spring Expression Language) as this is what the PreAuthorize method gets as parameter , link can be found here
please note that spring uses the SecurityContext to get the user data(Role etc..), meaning that the user already passed the login(authentication) stage and has SecurityContext loaded for said user
Example:
//other annotations
#PreAuthorize("hasRole('ROLE_VIEWER')") // hasRole('ROLE_VIEWER') -> this is SPEL
public ResponseEntity<String> methodName() {
//method
}
You can use #PreAuthorize with more flex as:-
#PreAuthorize("#securityService.hasPermission({'PERMISSION_1'})")
and service:-
#Component("securityService")
public class SecurityService {
public boolean hasPermission(PermissionEnum... permissions) {
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication()
.getAuthorities();
for (PermissionEnum permission : permissions) {
if (authorities.contains(new SimpleGrantedAuthority(permission.toString))) {
return true;
}
}
return false;
}
}
You can make it as you want.
For more
https://dreamix.eu/blog/java/implementing-custom-authorization-function-for-springs-pre-and-post-annotations
https://try2explore.com/questions/10125443

Spring security oauth2: create user if not exists, provision user

Here is an excerpt from spring oauth2 tutorial:
How to Add a Local User Database
Many applications need to hold data about their users locally, even if
authentication is delegated to an external provider. We don’t show the
code here, but it is easy to do in two steps.
Choose a backend for your database, and set up some repositories (e.g.
using Spring Data) for a custom User object that suits your needs and
can be populated, fully or partially, from the external
authentication.
Provision a User object for each unique user that logs in by
inspecting the repository in your /user endpoint. If there is already
a user with the identity of the current Principal, it can be updated,
otherwise created.
Hint: add a field in the User object to link to a unique identifier in
the external provider (not the user’s name, but something that is
unique to the account in the external provider).
So, in the user controller we have the following code:
#RequestMapping("/user")
public Map<String, Object> user(Principal user) {
Map<String, Object> map = new HashMap<String, Object>();
// for a facebook the name is facebook id, not an actual name
map.put("name", user.getName());
map.put("roles", AuthorityUtils.authorityListToSet(((Authentication) user)
.getAuthorities()));
return map;
}
Dave Syer(spring maintainer) suggests to:
Downcast the Principal to an Authentication (or possibly
OAuth2Authentication and grab the userAuthentication from that) and
then look in the details property. If your user was authenticated
using a UserInfoTokenServices you will see the Map returned from the
external provider's user info endpoint.
But for me that seems unnatural by two reasons:
Why should we do that in controller call...it smells.
Why should we do all that instanceof and casts..smells as well.
Wouldn't it be better to plugin the OAuth2AuthenticationManager instead: org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// ...
OAuth2Authentication auth = tokenServices.loadAuthentication(token);
// ...
auth.setDetails(authentication.getDetails());
auth.setAuthenticated(true);
// here we could've create our own Authentication object
// to set as Principal with application specific info.
// Note: no casts are required since we know the actual auth type
return auth;
}
What's the best way of creating a user after oauth2 dance completed?

security to url for a user

For a url like
#RequestMapping(value = "/users/{userId}/update/password", method = RequestMethod.PUT)
how to be sure the connected user can modify only its password and not the one of other user...
actually, i have protection on url... but it's not enough to prevent this case
http.authorizeRequests().antMatchers("/rest/users/**").hasRole("USER");
Assuming that you have a Spring bean with a public method with username as one of the arguments (it can be in controller, security layer, service layer or DAO), you can add a #PreAuthorize annotation:
#PreAuthorize("#username == authentication.name")
public void updateUserPassword(String username, String newPassword);
You must enable pre- and post-annotations in your security config if not already done so.
I soppuse you have a authentication over /rest/users/**. You can get current user with the following code.
YourUserPrincipalDto dto = (YourUserPrincipalDto) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Long userId = dto.getUserId();
YourUserPrincipalDto should implements UserDetails.
Add the Principal object (like here) to your method's argument list to confirm that the authenticated user is the same user as the userId in the API URL (do whatever background DAO queries are necessary to map between the userId and the authenticated user). Return a 403 or 404 if it is not, otherwise update the password. Whether you return 403 or 404, best to be consistent and return the same number for both unauthorized and user-not-found situations in order to not provide unwanted information to hackers.

Spring security Preauth: how to pass user roles through customized authentication filter

I'm new to Spring security, and working on a grails app that connect to external authentication and session management service for authentication/authorization. So what I did is create customized authentication filter
class TokenAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
//in here i call an external service, passing in the a cookie from the request,
//and get username and role information from the service
//not sure what to do with user roles
return username
}
}
Then I looked at super class AbstractPreAuthenticatedProcessingFilter code, in it's doFilter() method, it create an PreAuthenticatedAuthenticationToken (new PreAuthenticatedAuthenticationToken(principal, credentials);) for authentication, but it only takes username and credential, not the role information. Then I tried to inject a different details source J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource into the filter, because looks to me (i might be wrong) this detail source will pass the role information to the authentication object by calling setDetails(). but J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource is reading role information from http request object.
protected Collection<String> getUserRoles(HttpServletRequest request) {
ArrayList<String> j2eeUserRolesList = new ArrayList<String>();
for (String role : j2eeMappableRoles) {
if (request.isUserInRole(role)) {
j2eeUserRolesList.add(role);
}
}
return j2eeUserRolesList;
}
I got confused about the life cycle of authentication. I thought the http request object is getting role information through authentication object in security context, which hasn't been created at this point. I need the role information in order to create the authentication object. Isn't this running in cycle? or am I misunderstanding anything?
I know I can go with another approach to make my app work, just making my own filter to create the authentication object (which takes the role parameter) instead of letting super class (AbstractPreAuthenticatedProcessingFilter) to create the authentication object, but I'm just curious why the first approach is not working. What is J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource trying to do? It calls request.isUserInRole(role), but by who and when is the user role set to http request?
Hopefully I express myself clear enough for someone to understand.

Resources