I would like to retrieve group information about the user in most standard way.
I'm using ssocicrcle as IdP, and spring security (on Tomcat 8.5) as framework for SSO.
My post-authentication servlet looks like:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SAMLCredential credential = (SAMLCredential) authentication.getCredentials();
String email = authentication.getName();
// how to get group information
I understand that SSOCircle might not have a notion of group - I will soon be using PingIdentity. But is there some standard concept of group in SAML, and if so, how would I go about retrieving that, when using spring security.
Thanks
The IdP could provide the 'group' information in whatever format as attribute statements in the assertion. On the SP side you then need to read those attribute statements and 'map' them to security roles on SP side.
As there is not standard way of doing this you need to negotiate with the IdP about this.
Related
I am having a hard time learning OAuth2 and OpenID Connect.
Every time I think I understand everything now, I come across another gimmick.
This time it's Spring Securities OAuth2LoginAuthenticationProvider.
The OAuth2LoginAuthenticationProvider is used instead of OidcAuthorizationCodeAuthenticationProvider if scope openid is not contained in requested scopes.
if (loginAuthenticationToken.getAuthorizationExchange().getAuthorizationRequest().getScopes().contains("openid")) {
// This is an OpenID Connect Authentication Request so return null
// and let OidcAuthorizationCodeAuthenticationProvider handle it instead
return null;
}
But why does this AuthenticationProvider load an OAuth2User via UserInfoEndpoint?
Isn't UserInfoEndpoint OIDC specific?
You are correct that OIDC defines a User-Info endpoint.
When using OAuth 2.0 to authenticate, there is still a need to figure out the user's information and so Spring Security publishes an interface (OAuth2UserService) that does that.
For non-OIDC implementations, I'd imagine that the OAuth2UserService is not pointed at an OIDC-compliant User-Info endpoint.
I'd like to provide two ways to authenticate in my application, one is basic auth (users), and the other is some kind of token based (technical users). I understand that I need a custom ReactiveAuthenticationManager but I can't find clues on the big picture. (Actually, there are a very few insights for MVC, and none for WebFlux.)
1) How do I populate the Authentication's name and credentials in the token based approach? If I configure Spring Security to use httpBasic it's already populated. Some kind of filter needed?
2) How do I distinguish in the authentication manager where the credentials are coming from? Do I have to lookup in the userRepository and (if not found) in the technicalUserRepository too?
3) Do I have to override the SecurityContextRepository? All the tutorials do it but I don't see any reason to do so. What is it exactly? This source states that "SecurityContextRepository is similar to userDetailsService provided in regular spring security that compares the username and password of the user." but I think he means ReactiveUserDetailsService (neither UserDetailsService nor ReactiveUserDetailsService does that by the way, it's just for user lookup).
Since i am decent at Webflux and i have worked a lot with oauth2 i'll try and answer some of your questions.
1) How do I populate the Authentication's name and credentials in the
token based approach? If I configure Spring Security to use httpBasic
it's already populated. Some kind of filter needed?
A token never contains credentials. A token is something you get issued after an authentication has been done. So usually you authenticate against an issuing service. After you have authenticated yourself against that service you will be issued a token.
If its an oauth2 token the token itself is just a random string. It contains no data about the user itself. When this token is sent (using the appropriate header) to a service using spring security. Spring security has a token filter that will basically check that the token is valid, usually by sending the token to the issuer and asking "is this token valid?".
If using a jwt, its different, the jwt must contain some information like issuer, scopes, subject etc. etc. but its basically the same thing, there is a built in filter that will validate the jwt by sending it to the issuer (or using a jwk that the service fetches from the issuer so it can verify the integrity of the jwt without doing an extra request).
2) How do I distinguish in the authentication manager where the credentials are coming from? Do I have to lookup in the userRepository and (if not found) in the technicalUserRepository too?
You don't You usually define multiple SecurityWebFilterChains for different url paths. I have not done this in Webflux Spring Security, but thats how you do it in regular Spring Applications, and i don't see any difference here. Unless you are doing something crazy custom.
3) Do I have to override the SecurityContextRepository? All the tutorials do it but I don't see any reason to do so. What is it exactly? This source states that "SecurityContextRepository is similar to userDetailsService provided in regular spring security that compares the username and password of the user." but I think he means ReactiveUserDetailsService (neither UserDetailsService nor ReactiveUserDetailsService does that by the way, it's just for user lookup).
The answer here is probably no. You see Spring security 4 had very bad support for oauth2 and especially JWT. So people got accustomed to writing their own JWT parsers. When spring Security 5 came, Spring implemented a jwt filter that you can configure and use built in. But there are a lot of outdated Spring Security tutorials out there and foremost there are a lot of developers that don't read the official documentation.
They mostly google tutorials and get the wrong information and then work on that.
But easy explained:
SecurityContextRepository
If you have session based authentication (server establishes a session with a client) it will store the SecurityContext (session) in ThreadLocal during a request. But as soon as the request ends, the session will go lost unless we store it somewhere. The SecurityContextPersistenceFilter will use the SecurityContextRepository to extract the session from ThreadLocal and store it, most common is to store it in the HttpSession.
AuthenticationManager
Override this if you want to do a custom authentication process. Example if you want to validate something, call a custom LDAP, database, etc etc. It\s here you perform you authentication. But remember, most standard logins (like ldap, sql-servers, basic login etc.) already have prebuilt configurable managers implemented, when you select what login type like .httpBasic() you will get a pre-implemented AuthenticationManager.
UserDetailsManager
You override this when you want create a custom UserDetails object (also usually called Principal) In the UserDetailsManager you do you database lookup and fetch the user and then build and return a UserDetails object.
Those two interfaces are the most regular custom implementations, and are used if you need to to basic authentication/session based authentication.
If you wish to do token, you have to think about, who is the token issuer? usually the issuer is separate and all services just get tokens and validate them against the issuer.
I hope this explains some of the questions. I have written this on the bus so some things are probably wrong and not 100% correct etc. etc.
I have searched enough but I haven't got a clear answer and thus posting this question.
I have an existing application which uses spring security for authentication.
Current implementation uses a custom implementation of UsernamePasswordAuthenticationFilter for doing this.
Thus the flow is something like below(in very simple terms):
inputrequest>DelegatingFilterProxy>LoginUrlAuthenticationEntryPoint>CustomUsernamePasswordAuthenticationFilter>AuthenticationManager>CustomAuthenticationProvider
Now I have a requirement to implement SSO (since the user is already asusmed to be authenticated) in some scenarios.
The requirement states that if I have a specific request parameter present then I need to automatically authenticate the request without bothering about user/password.
So it is same set of resources and I do not have to authenticate user/password if the specific SSO related request parameter is present.
e.g
suppose a resource \test\bus is a secure resource.
if I come from normal way then we need to check if the user is authenticated or nor and force user to put valid user/password
if I come from SSO channel then I need to show the \test\bus resource as the user is already authenticated.
currently all the access restrictions are put through <http> element
e.g the snippet of security-config.xml is as follows:
Query: What options do I have in this case. I can think of below options:
Pre-authenticate the user before spring security framework kicks in. This will mean creating an authentication token and putting in spring context before spring security filter is called. This can be done through another filter which is called before spring security filter chain. I have tested it and it works.
Create another custom security filter which set-up the authentication token. I am not clear if this is correct approach as not sure when do we create multiple custom security filter
Create another custom authentication provider e.g SSOCustomAuthenticationProvider. This provider will be called in the existing current flow as we can have multiple authentication providers to a authentication manager. The only issue is that in order to achieve this I have to change the request url to authentication filter's target url so that spring security doesn't check for authentication.
to explain more,
let's say request uri is /test/bus, I will write a filter which will intercept the request and change it to /test/startlogin. This is currently my CustomUsernamePasswordAuthenticationFilter's target url i.e
<property name="filterProcessesUrl" value="/test/startlogin"/>
The flow will be
inputrequest>DelegatingFilterProxy>LoginUrlAuthenticationEntryPoint>CustomUsernamePasswordAuthenticationFilter>AuthenticationManager>SSOCustomAuthenticationProvider
I have tested this and this works. Is this a valid approach or a hack.
Is there any other viable option available with me.
Thanks for reading this.
I'm using Spring Security OAuth to build application with token based authentication (using this article http://porterhead.blogspot.com/2014/05/securing-rest-services-with-spring.html).
In the next step I want to store some additional data with token. I decided, that Spring Session is good enough for it. First, it have HeaderHttpSessionStrategy (user sends session ID in custom header - X-Auth-Token), second, it supports different storages (including Redis - good for quick access to session data).
Spring Security OAuth uses Bearer Authorization, that means I need to create child class from HeaderHttpSessionStrategy, which will return correct session ID (not from X-Auth-Token).
So my questions are:
How to hook on login success method in Spring Security OAuth and create session with provided ID (ID == new generated token) in this moment?
How to hook on logout method?
Is it right way to use Spring Session in this case? If not, what alternatives?
I have a webapplication using spring security. I'd like to login using an account i have configured on the WSO2 identity server using OpenID.
I can login just fine, the identity server asks for the password and redirects me back to my webapplication. So far, so good. However, when i try to request additional attributes using the attribute-exchange, i get empty values.
I have tried a few different types:
schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
axschema.org/namePerson/first
urn:scim:schemas:core:1.0:name.givenName
schema.openid.net/2007/05/claims/nickname
wso2.org/claims/givenname
But none of them seem to yield any results.
Am i missing something obvious?
The reason may be the fields are empty as well.
Can you try with the following claim URI, http://wso2.org/claims/role. By default all users have the everyone role. So that value should be returned.