How to get custom User object from AuthenticationFailureBadCredentialsEvent / AuthenticationSuccessEvent object - spring

I'm trying to show no of invalid attempts of user using spring security.I'm using a custom User class to get additional user details other than username and password. I've created two listener classes i.e. AuthenticationSuccessEventListener & AuthenticationFailureListener to update user's invalid attempts.
Now in the onApplicationEvent method i'm trying to get custom User object (CustomUserDetails) like shown below:
#Component
public class AuthenticationFailureListener implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
#Autowired
private ILoginDAO loginDAO ;
#Override
public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
CustomUserDetails user = (CustomUserDetails)event.getAuthentication().getPrincipal();//I get ClassCastException here.
String strUserID = user.getUserID();
CustomUserDetails customUser = loginDAO.loadUserByUsername(strUserID);
if (customUser != null){
...
} } }
event.getAuthentication().getPrincipal() returns a String i.e. username which i'm trying to cast it to CustomUserDetails (custom User class) and i get error.
P.S - I'm entering userid/password in login page and hence i pass userid as parameter for all the methods including loadUserByUsername(strUserID).
How can i get my custom User object in the listener class from AuthenticationFailureBadCredentialsEvent / AuthenticationSuccessEvent object?

The event just contains the authentication request object, i.e. the Authentication which was passed to the AuthenticationManager and which failed. So it will contain the submitted username as the principal.
Authentication may have failed for a variety of reasons, including a non-existent username, and in fact doesn't even need to involve a UserDetails object at all, so if you want the full information you will need to load it using the username.
Alternatively you could customize an AuthenticationProvider to perform the additional work you want in the implementation itself, rather than via an event.

Related

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

How can I store user details into database after LDAP successful login?

I'm working on a Spring Boot application and I need to make it secure by adding LDAP authentication. The authentication process based on LDAPusername/password is working, but I'm having a hard time in getting user data (username, full name, etc.) after a successful login and storing it into a database.
You can surely save the data of the LDAP user in the db. After successful authentication, you can call your custom class, something like this :
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
#Service
public class LDAPUserDetailsMapper extends LdapUserDetailsMapper{}
Then you can override the method :
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username,
Collection<? extends GrantedAuthority> authorities) {
/** your custom logic goes here. Here you can get the user details from ctx,
and then use the information to store the data in db and then return the user details.**/
}

Spring Security - How to get authenticated object in non-secure and secure pages?

I have a Spring-boot/Thymeleaf application with two ends point:
1: /int/: requires sso/authorization;
2. /ext/: public pages, everyone can access;
Using a PreAuthenticationFilter, I was able to secure /int/* pages. When an user tries to access the /ext/* pages, I'd like to be able to tell in the controller if the user has previously been authenticated (by accessing a secured page). Currently I save the authenticated Principal object in the HTTP session in UserDetailsService's loadUserDetails(). Just curious if this is the right way (or a better way) to do it.
You can get your authenticated object via #AuthenticationPrincipal annotation instead of getting the object from httpsession and casting it back to your object for every controller method.
Let me give you an example, given login page is a public page and User object as below:
User Class:
public class User implement UserDetails {
String contact;
Integer age;
}
Controller:
#GetMapping(value = "/login")
ModelAndView login(#AuthenticationPrincipal User user) {
if (user == null) {
return new ModelAndView("/login");
} else {
return new ModelAndView(new RedirectView("/home"));
}
}

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.

How to integrate spring security and spring social to have the same execution flow in both cases?

I am using spring security for the authentication purposes in my project wherein after successful authentication, I get the principal object inside which the various details are stored.
This principal object is passed to various methods which allow the entries to be reflected in the database against the current user. In short, principal helps me in giving principal.getName() everywhere i need it.
But now when I login through spring social then I do not have principal object of Principal in hand, instead I have implemented MyPrincipal class --->
public class MyPrincipal implements Principal {
public String name;
public boolean flag;
public boolean isflag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public void setName(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
}
Then in the social login handler, I am adding the current username and flag value to myPrincipal object, and forwarding the user to the same home page where the spring security forwards in case of normal login.
MyPrincipal myPrincipal = new MyPrincipal();
myPrincipal.name = username;
myPrincipal.socialFlag = true;
modelMap.addAttribute("myPrincipal", myPrincipal);
return new ModelAndView("forward:/home");
Adding this object in session by annotating class with
#SessionAttributes({"myPrincipal"})
Now from here on-wards I want the flow to be handed over to the home page with all the functionality working for the user correctly. But each method is taking Principal principal as argument, just like this -->
#RequestMapping(value = {"/home"}, method = RequestMethod.POST)
#ResponseBody
public ModelAndView test(ModelMap modelMap, Principal principal) {
String name = principal.getName();
}
There are two different things going around in both cases-
Normal login is giving me principal directly but social login is giving me it in session attributes.
I do not want to pass principal as parameters even in case of normal spring security login, instead here also I want to put it in session attribute.
How can I do this and where to make the changes when I have implemented my own authentication provider.
I don't think I fully understand...However, in general it shouldn't be necessary to pass principal instances around. Use org.springframework.security.core.context.SecurityContextHolder.getContext() to get a hold of the context then call SecurityContext.getAuthentication().getPrincipal() or SecurityContext.getAuthentication().getDetails().

Resources