I'm needing to do some custom things when a user tries to log in depending on their username but these things need to happen before the authentication process. Here's what I've got so far.
Our system allows for multiple email addresses and the client wants the user to be able to authenticate using any 1 of them. To allow for this I created a custom UserDetailsService and had the code lookup the user appropriately.
The other things I need to do require a few flags on the user object that spring-security doesn't really know or care about. But I need to hook into the auth process, check these flags, and return appropriate error messages to the user. To give a more concrete example, I need to know if this is the first time a user has ever logged into the system. So we have a flag on the user to track this. When the user tries to authenticate, I need to read this value and do some stuff, including sending a message back to the user and halting authentication.
I looked into the Event Listener mechanisms in the documentation but what I am not seeing how to do is how to inject my own workflow via the listeners. I need to do a flow like this:
Auth with valid email but first time -> cancel authentication -> display message on login page
I think if I can get that one scenario handled, I can figure the others out that I need.
UPDATE: I'm reading on filters now to see if I missed something...
The simplest was to hook into the authentication process is to provide your own AuthenticationProvider. There are only two methods to implement. In authenticate() you can do all of your custom stuff.
To configure your provider into the framework do something like:
<authentication-manager>
<authentication-provider ref="myAuthenticationProvider" />
</authentication-manager>
Related
We have implemented Spring Oauth authorization+resource server that can be used for external applications.
Now we would like to add custom checks before some oauth calls returns in the authorization server, most importantly for the authorization code but also before allowing returning a token sometimes.
An example use case might be that which users that are allowed to login for a specific client_id might vary and if not allowed this should generate a redirect back with an error.
So for example a user might trigger a login from a third-party app, redirected to our authorization server and shown a login page, however after login it is discovered (through our business logic) that this specific user is not allowed to authorize access to that specific app/client id.
What is the best way to achive this result in a way that is consistent error handling in Spring oauth?
Also, a related question is also how to resolve the client details before the login screen shown so more specific client details can be shown when logging in?
We could parse the client_id parameter manually but maybe there is a more elegant way to hook into Spring oauth to solve this?
(sorry for dual question but its sort of related and the first question is the most important one)
Let's imagine I have following scenario
User receives an email that there is a new item waiting for her
Clicks on a link and is able to either confirm or reject item (details skipped)
Can then access a list of all her items
The trick is that I would like to allow all this happen without user signing in but then limit access to other parts of the website (like sending an item to another user)
How I see it is that:
when user clicks a link she is signed in but only on tier 1 - with access only to confirm/reject action and read only to index of items (that's when Devise session is created)
when user wants to access other part of the website the sign in page is presented
when user comes to the website just by typing in the url http://example.com and wants to access own account she is asked to sign in.
after sign in session is "promoted" to tier which allows full access
after some time of inactivity session is downgraded to tier 1 for security reasons
My inspiration comes from how Amazon works - you can access in read-only most parts of the account but before performing any destructible actions you need to sign in.
Does anyone have any experience with such approach or can share some blog posts, etc?
I didn's find anything on SO and Google mostly returned things about two-factor auth which is not the case here.
I also understand that there are security concerns with links in email.
I have implemented a very similar behavior few months ago. I don't have very interesting resources to show you but I can explain a bit how you could organize or think about the problem to solve.
Description
For the problem you state, it looks like once you have identified a user, you have two different states you can give him:
limited access (perform certain actions, read most of the resources, etc)
full access (allows them to do anything they would normally do).
Having stated that, what you need to do is figure out in which cases you will give a user each access state (for example):
signing in with email token -> limited access
password -> full access
authentication_token -> full access
omniauth -> full access
After that, you will need to save this information in the user session. This should be done anytime the user is authenticated, as you will know what strategy was used to authenticate the user.
To know if a user can or cannot perform an action you will need two things, know what the user can do, and the current "access state". Depending on those you will decide wether the user is allowed or not to perform a certain action.
Whenever a user can't perform an action and is logged in with limited access you should bring him to the flow for verifying his crendetials. This flow is pretty simple, almost like a sign in but just with the password. Once you verify his crendetials you can upgrade his authorization to a full access one.
Implementation details
I recommend you to create a Authorization model which will represent the "access states" that I mentioned. This model will have to be serialized in the session so you should be able to build it from a simple structure and serialize it again into that structure. The simplest the better (a boolean flag, an array or maybe a hash). For the case mentioned, it looks like a boolean would do the job.
Regarding implementation details, I recommend you implementing this with a Warden after_atuhentication callback.
You could implement this with CanCan by creating you own Ability that would be built with an Authorization instance and a User instance.
I think you're confusing authorization and authentication. Devise is an authentication solution, meaning it handles the "proof me you are who you say you are" part. Authorization is the "Ok, I know who you are, now let's see what can you do". Devise doesn't provide an authorization system beyond the simple "logged/not logged". If you need a more complex authorization system, use an authorization gem. CanCan is very popular.
I'm working on a Grails application and want to integrate with a custom single-sign-on service (not CAS, but similar). I'm struggling to find all the pieces that I need to customize to make this happen. Can someone explain to me a general outline as to what I need to use to accomplish this? I've read the documentation on the plugin, but it assumes I know which beans to override and where to put all the needed files.
I've block-quoted what I think needs to be done based on my research below each point.
Order of Operations
1- The user requests secure content (everything is secure in the application for now)
I believe this setting is in the Config.groovy file:
grails.plugins.springsecurity.rejectIfNoRule = true
grails.plugins.springsecurity.securityConfigType = "InterceptUrlMap"
grails.plugins.springsecurity.interceptUrlMap = [
'/**':['ROLE_ADMIN']
]
2- Spring Security checks to see if the user has a specific value set in a cookie provided by the authentication service
I'm guessing I need to create an authentication filter, but I don't know where to put it or what it should look like.
If they don't, the user is redirected to this custom SSO service, they login, once authenticated, the user is redirected back to my application (with a new cookie set)
3- Spring security checks for the cookie value and validates it against the custom service (via HTTP POST)
From some research, I think that I need to use PreAuthenticatedProcessingFilter, but I haven't been able to find any examples of how to do this.
4- The custom service returns a series of name/value pairs, a user then needs to be created in the local application database (or the timestamp of "lastLoggedIn" is updated if they user's data is already in the database)
I believe this is done in the same PreAuthenticatedProcessingFilter as number 3 or in a GrailsUserDetailsService
5- The user's authentication is cached in the session for a period of time (6-8 hours) so that re-validation against the SSO service doesn't need to occur every time the user requests a new resource.
I'm not sure if this is something that's done inherently or if I need to add code to do this (and also set the session timeout)
We have some shopping cart pages which work with both guest and user paths. We want to allow a user to login at any time during the process but don't really want to create yet another login page. I'd prefer that we can simply redirect the user to the existing login and tell Spring Security what URL to come back to.
I know this happens automatically when sessions timeout and/or protected pages are requested without a session, but is there a way I can give the URL to Spring Security myself?
If you just need a simple return-to URL to retrieve the cart, then you are probably best to implement that yourself in an AuthenticationSuccessHandler. You can look at the source for SimpleUrlAuthenticationSuccessHandler and its parent for inspiration.
The default login mechanism uses the RequestCache and a SavedRequest, but that is intended to actually replay a request which would not otherwise be authorised. That's probably overkill in your case.
I'm new to Grails, and have jumped into version 2. I'm developing a project that uses Spring Security 3 - and this is working fine - but I want to use my organisations LDAP server (if / when it is available) to do the following:
authenticate users
update the local user data with details from LDAP
create the user if they don't exist
update the local users password (in case the LDAP server isn't available)
log that user in
I may have skipped a lot of fundamental stuff on my way to getting this working, like actually how Grails works - and I'm struggling to understand how to actually interrupt the Spring Security authentication process with an LDAP lookup, then how to get those details back in a way that I can use them to either update an existing user or create a new one...
I found a basic tutorial here: http://jamesjefferies.com/2011/01/06/grails-spring-security-ldap/ which means I can authenticate myself as a user from the LDAP server - although Spring Security still shows me as logged out, but will not let me log in either until I manually log out... so its kind of in a login-limbo.
The magic is doing my head in... at first I was amazed that I could build an entire web-app with a few commands and a few hours customization - but it's coming back to bite me now - as is the lack of useful examples... and the Spring Security LDAP plugin documentation is somewhat lacking (or maybe its my lack of understanding).
So, primarily I would like some help to complete the authentication so that it checks the user database for an existing user and updates them, or creates the user if they don't exist... but I would also love it if someone could give me a brief overview of the authentication process in Grails so I can understand whats actually happening, and where I should intercept things.
Cheers in advance for any help
Steve
There is a good example here that shows how to implement a custom user details mapper. I used that method on an LDAP login Grails 2.0 app successfully. Basically you have a CustomUserDetailsContextMapper that implements the UserDetailsContextMapper interface which you then use to override the default implementation by registering the bean in conf>spring>resources.groovy. Then inside your CustomUserDetailsContextMapper you check for a user(your domain class) with a matching username and if none exists you creates one using data from the ctx.originalAttrs which contains data from the ldap query results. You must then return a new org.springframework.security.core.userdetails.User. You can extend this class to add other fields that you want to be able to access directly from the principal object.