I was able to integrate Spring Boot and Spring Security SAML by using the #ImportResource annotation.
Now, I'd like to go on as follows:
the user selects an IdP [DONE].
it performs the login (successful) [DONE].
the SP obtains user data (by parsing the SAMLCredential object) [DONE].
the webapp had to check if the userID (e.g email) retrieved via SAML exists in my own DB.
a) If yes, the webapp reads from the DB the role and sets related privileges.
b) If no, the webapp had to perform a redirect to a sign-up page, in order to insert the user into the system.
Make it sense perform the points 4 and 5 by using a UserDetailsService implementation or have I to setup the security context defining authentication providers, filters, etc?
You should implement org.springframework.security.saml.userdetails.SAMLUserDetailsService and plug it into the samlAuthenticationProvider bean. In case user doesn't exist you should throw UsernameNotFoundException exception, otherwise just populate and return data from your DB.
On top of that you should implement your own org.springframework.security.web.authentication.AuthenticationFailureHandler and plug it into samlWebSSOProcessingFilter bean. This implementation will be called with the UsernameNotFoundException sent as a parameter and you can then redirect the user to the correct sign-up page as a reaction to it.
Related
I have a Spring REST-API which is secured by SpringSecurity.
I have different ways to authenticate in that application.
Customer (db)
Employees (ldap)
Other Applications/Services (inMemory)
Each of these are covered by a different authentication provider, which properly assigns the access roles. (Works)
However I need to know which authentication provider was used to authenticate the user, so I can write it to the logs, history...
User CUSTOMER/max.pain created a new entry.
And of course the username does not really contain that prefix, neither in the db, nor in ldap.
I considered adding a special role based on the authentication provider used, but extracting that information over and over is annoying and probably has bad performance and might cause problems in the future. (user.getGrantedAuthorities().findStartingWith("AP_"))
I also tried using org.springframework.security.config.annotation.SecurityConfigurerAdapter.addObjectPostProcessor(ObjectPostProcessor<?>) but i cannot use it to wrap the AuthenticationProvider with a custom AuthenticationProvider class, because it requires the use the same class for whatever reason.
Is there an inbuild method I could use to achieve that or do I have to use a custom implementation/configuration?
Prozess steps:
Login: EMPLOYEE/always.calm
Don't check CUSTOMER AuthenticationProvider
Check EMPLOYEE AuthenticationProvider
Don't check SERVICE AuthenticationProvider
authentication.getPrincipal().getAP() = EMPLOYEE
in my project, I m using request.getUserPrincipal() to check whether user is logged in or not, but I am confused where to set the instance as logged in user?
and i also notice that request.getUserPrincipal().getName() return user login id .
Finally I found where is the place we set our own db user details to the spring security Principal, we have a class which implemented spring security AuthenticationProvider interface , and inside public Authentication authenticate(Authentication authentication) method, we set the value from USER_TB to Spring security UserDetails object. I am still investagating, spring security is a big part to learn
I'm using Spring Security to provide authentication and authorization to my webapp.
I use the standard method UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; to login with a DaoAuthenticationProvider.
Once successfully logged in, I can access the user's authorities in two different ways:
1# SecurityContextHolder.getContext().getAuthentication().getAuthorities()
2# ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getAuthorities()
They are supposed to be the same, as the Authentication instance authority list is constructed from the UserDetails' user.getAuthorities(), but they are in fact 2 different Collection instances. The principal's one is an UnmodifiableSet, the one in the Authentication instance is an UnmodifiableRandomAccessList.
2 different Collection instances that contain the same list of authority.
This struck me when trying to find a solution to dynamically add an authority to the currently authenticated Principal. It's not a good thing and the security layer should not allow me to do so, but still that's what I need.
A solution I found acceptable was to programmatically login with the currently authenticated user with
new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), dbAuthsSet);
authentication being the current authentication instance and dbAuthSet the current list of authorities + the one I need to add.
And this works fine. The only odd thing now is that
1# SecurityContextHolder.getContext().getAuthentication().getAuthorities()
2# ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getAuthorities()
don't return the same list of authorities anymore.
If I check authorities against the Authentication's list in my application, I'm good, and this is perfectly justified thing to do. But if I check against the Principal's list, I'm faced with the inconsistency.
What do you think? Is it a problem that should be addressed in Spring's Security 3.2?
Do you find it reasonable to programmatically login with new UsernamePasswordAuthenticationToken() to achieve my goal of giving an additional authority to the currently authenticated user for the session?
Would it be a good case to use Spring's Run-As Authentication Replacement feature?
Could anyone share experience on this ?
Using a Jersey service, what would be the most elegant method to authenticate a user with more than just username and password? say, a Business Id, and username as the Principals, and password as the only Credential.
I have a postgres DB with a users table, the same username string can exist for multiple Business entities. (A unique constraint belongs to two columns, Business id and username together).
I Use Basic authentication, having the client send an additional HTTP Header for the Business id. how do I go on from here?
Now, Regarding Authorization, how would I set up Roles and Permissions, if roles are created specifically for each business entity (each business can define it's own roles and connect it to permissions.)? Permissions are static.
does apache shiro (or any other pluggable security extension) offer a solution in this case?
Thanks.
You might consider.
Implement auth logic in the good old servlet filter. JAX-RS application is just normal WWW aplication, so Filters fits well as a simple authorization mechanism.
JAX-RS interceptors (PreProcessInterceptor) where you can implement your auth logic as you need (calling database, etc.) This is "more idiomatic" while working with JAX-RS.
Use Spring Security. This is a good option if you are ready to learn a little it of Spring Framework. Spring Security provides full featured authentication and access control mechanism, so you can implement whatever you need. Note that the rest of application does not neeed to use Spring.
You might also use CDI decorators (example) to implement auth logic, but that would be sort of exotic given still low CDI adoption.
Personaly I would go with 1. or 2, for simple cases and 3 for something more advanced.
(Old question! a response for new users) As you tagged SHIRO in your question, you can just add your own logic by extanding org.apache.shiro.realm.jdbc.JdbcRealm and #Override: getRoleNamesForUser(...) , getPermissions(..), doGetAuthenticationInfo(..) This is an example:
#Override
protected Set<String> getRoleNamesForUser(Connection conn, String username) throws SQLException {
Set<String> roleNames = new LinkedHashSet<>();
Collection<UserRole> roles = /* Get roles from your DB, this example use JPA entity, **but you put here any logic you want**...*/
for(UserRole userRole:roles){
roleNames.add(userRole.getRole().getName());
}
return roleNames; // return roles so Shiro is 'aware' of roles to add them to current user
}
*note that same logic applies for other methods that you override.
** You don't need 2 http calls to log the user, you can just user Shiro programatic auth.
here is a Complete example with Shiro annotation enabled..and more
Summary
How do you get the session of a web service client using spring web services and spring security?
Details
After submitting
<form method="POST" action="<c:url value="/j_spring_security_check" />">...</form>
I've noticed that you can:
public class MyUserDetailsService implements UserDetailsService {}
Which will allow you to override methods like loadUserByUsername(String username) therefore being able to retrieve the submitted username and do a database lookup to return a user object.
The issue I have, however, is that I'm unsure where SecurityContextHolder gets set. I'm able to get the user object by using this line of code:
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
But I'm not sure how it gets set in the first place. I would like to know the flow after submitting the above-mentioned form so that I can identify how SecurityContextHolder gets set.
The reason why I want to know this is because I want to use it as a "session" for web service client authentication instead of having the client resubmit credentials with every request.
Spring Version: 3.0.2.RELEASE
/j_spring_security_check is handled by the UsernamePasswordAuthenticationFilter which extends AbstractAuthenticationFilter. The security context is set in the latter's successfulAuthentication method.
However, web-service clients are usually stateless and would be more likely to use something like Basic authentication with a shared secret. I'm not sure there would be much benefit in rolling your own session system based on the security context contents. If you are worried about performance then you could use a cache of authentication information on the server.