For my REST aplication I used Basic Authentication (sending user's password and login with every request). For some needs I obtain logged user using:
User loggedUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
But then I implemented Spring-Security-Oauth2 and I am using access token instead password and login. And now .getPrincipal() method returns "anonymousUser".
So my question: Is there any way to obtain logged User somehow as above in spring-security-oauth?
EDIT:
I figured out that I had a proplem in my security "intercept-url pattern". So now I can use SecurityContextHolder from which I can obtain authenticated user.
inside controller method you can add this paramter then it will be injected for you and you can access user information
getUserAuthentication(OAuth2Authentication auth,Model model)
Related
We are using Okta as a OAuth login provider.
What we wish to achieve is to fetch user role information in the authentication response itself. We are using spring security.
Currently we get following details in org.springframework.security.oauth2.core.oidc.user.OidcUser object
[Edit]
Adding content of authorities
This does not include user role information. Is there a way to get the user role information in the authentication response itself?
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.
I am using spring security to authenticate a user. The user is authenticated by a third party and will already be authenticated when he reaches my application.
To implemented this, I have simulated a Authentication object.
I don't have any username and password and instead just have identifier. I check if this identifier is valid or not using my custom code.
My query is as follows:
Do I require a username and password to create a authentication object.
I have done without providing username and password and my application works fine.
I just want to ensure that I am using spring-security correctly.
Is there any impact of not putting username and password in Authentication object. I read below in AbstractUserDetailsAuthenticationProvider:
// Ensure we return the original credentials the user supplied,
// so subsequent attempts are successful even with encoded passwords.
I have also implemented a custom provider.
What does above comments means?
Is my approach correct?
The Authentication interface in Spring Security represents a token for carrying out validations against the configured security rules and the current call context. This interface has six methods of interest - getPrincipal, getCredentials, getDetails, getAuthorities, isAuthenticated and setAuthenticated.
Since you are authenticating users on your own, you should be mostly concerned with calling setAuthenticated(true) at an appropriate stage in the flow so that isAuthenticated starts returning true to indicate an authenticated user. Additionally, you may add GrantedAuthoritys to the Authentication for any role-based checks to work correctly.
However, it will be useful to make sure that getPrincipal (username in the case of form login) returns a unique value per user or per session. This will prevent the possibility of user sessions getting interchanged due to non-unique principal, which is used by the framework to identify users uniquely.
You may leave getCredentials and getDetails unimplemented. In fact, getCredentials (password in the case of form login) should be left unimplemented in your case because your application does not have the credentials used to actually authenticate the user; plus, it is a security risk to keep the credentials around after the user has been authenticated successfully.
I'm trying to implement two factor authentication in my Spring application.
Desired situation
I want the user to first log in with his username and password, if those are correct I want the system to generate a random key and email that to the user. After that the system has to redirect the user to a page where he only has to enter the token and login to the system.
What I got so far (in pseudo code)
User enters the login.jsp page. Upon logging in with username/password the system sends out a CustomMade AuthenticationException. In the AuthenticationFailureHandler I do a getAuthentication on the exception (I'm aware of deprecacy) But I use the username to send the user his token. After that I put the exception in the session (using request.getSession().setAttribute ) and finally the system reloads the login.jsp.
Login.jsp sees the exception in the session and shows the token input field. User fills the token input field and logs in. System authenticates the user with the credentials in the session and the given token.
Question
I think it's bad practice to save the username/password in session. Two possible solutions I thought of:
After checking Username/Password. Save the username in a static variable or in DB. When user is entering the token check whether username is in the variable/db and check the token. If the token is correct do a login with the user.
After checking username / password log the user in with a low role. With the low role the user can only go to the token page, after entering a valid token the system gives the user new authorities.
What would be the best solution to implement?
I am using a custom UsernamePasswordAuthenticationFilter (which is called before the login page). I am considering the session id of the already logged in user in this filter. If the auth_token exists for the corresponding session id I want to bypass the login page.
How can I do that ?.
You just have to populate the security context with an authenticated Authencation once you have checked the auth_token. Something like that (in your custom filter):
... // first check the existence of the auth_token and extract some information from it like user name and roles
String login = ...
String role = ...
PreAuthenticatedAuthenticationToken preAuthenticatedAuthenticationToken
= new PreAuthenticatedAuthenticationToken(login, auth_token, Collections.singleton(new SimpleGrantedAuthority(role)));
SecurityContextHolder.getContext().setAuthentication(preAuthenticatedAuthenticationToken);
//At this point : the security context contains an authenticated Authentication and other security filters won't have any impact anymore
I don't say it is the best approach for your needs, but it will works with a more or less standard spring security configuration.