For my JSF/TomEE application, I have a NoSQL database with users and roles that specifies how users can access resources (basically, IDs in a url parameter) either read-only or write.
I want to implement security and this post gave me some ideas but I am keen to try a 3rd party library - probably Shiro or PicketLink. The rule is that users will authenticate themselves with a client certificate, and if that is not provided, they will be authenticated as a default guest user.
Surprisingly, I am having a bit of trouble finding some information on how to do this in Shiro, it doesn't look straight forward. It is a bit of a surprise to me that there is nothing "out of the box" in Shiro to implement client certificate authentication.
So I think I have to create a Realm to "connect" Shiro with my database. Then I read I might need to extend org.apache.shiro.authc.UsernamePasswordToken to read the certificate and pass it to Shiro. Then I suppose I have to restrict access to content in JSF xhtml pages (using the rendered attribute for example) and I suppose that even in all methods of the Named Managed beans I will need to check the permissions.
Also, It is not clear to me how I can assign the guest user when a certificate is not provided, since apparently it is TomEE the one who validates the client, so if no certificate is provided, my code will not get executed to assign the guest user. I could open two different ports in TomEE, but then the access will not be unified, since I want to treat the guest user uniformely, as any other user in the system. How can this be done?
Is this implemented in a easier way in PicketLink? (which is also better prepared for JSF)
OK, it took me a while and a lot of research, so I will summarise my findings dramatically. I documented everything but do not want to create a book chapter.
So I decided to go with Shiro, and everything I describe works and can be done. This X509certificate project for Shiro was quite useful. Basically, you need to implement a Realm overriding two methods (one for authentication and another for authorisation) - there is a class to extend in the code I mentioned before.
The distiction of a user not providing a cert can be done in the Shiro Filter, so when no token (certificate) is provided, one can be created on the fly or read from a keystore.
For restricting access in JSF there are some shiro tags that can help, no need to use rendered. I have checked permissions also in the beans or other classes accessing the database. This works once the permissions have been established in the authorisation method.
The issue with Tomcat can be solved by using <Connector port="..." ClientAuth="want" ... which will ask for a certificate but will not stop the user if no certificate is provided.
Related
If I have a single server with multiple domains, what is the preferred method for implementing a single-sign-on solution on the same domain. I am currently using devise, have a few million cookies in place on separate domains, and am stuck. On top of just implementing SSO, I also need to migrate the various cookies to a central domain. Regarding the various servers, they only have one single page that requires me to show different states depending on whether or not the user is logged in.
I have tried the following:
CORS: pick one domain as the central auth hub. From all other domains make cross domain checks to see if the user is logged in. For migrating cookies, detect if there's a "current_user" object, send it to the client, make a CORS request, sign the user in and kill the token. Works Great! BUT... After building it for 2-3 weeks, it TOTALLY FAILS in IE. Even IE11, I'm noticing the default setting is disabling this behavior.
tried tinkering with the session store at
Rails.application.config.session_store
with no luck.
I am currently experimenting with the following:
JSONP: I have someone right now trying to convert the above to JSONP instead while I try some other options:
Set up a custom OAUTH provider. Like before, it will be the "central domain" if the person is signed in, return to the requested domain with a token from which the users can make requests. https://github.com/songkick/oauth2-provider
Looking at this but it looks outdated? https://github.com/rubycas/rubycas-client. I also get the feeling this could have been a solution if I rolled this out from the get-go, but given how far we are into the project, it's unclear to me how I'd transfer the existing cookies. Also it's unclear if this requires two applications for me to get up and running ( one for client(s), one for auth server)
As I go through each of these possibilities, if anyone has had any experience doing what I'm doing, please do inform me and save me a whole lot of work :)
The best way unless this is a toy app is probably to set up an oauth provider.
We use Doorkeeper with Devise for this and it works great. It will be worth your time to set a little time aside to read through the documentation and watch a talk or two on youtube if you're not already familiar with the strategy but once you understand the core concepts its actually pretty simple to set up with the help of this gem.
There is a quick video run down on http://railscasts.com/episodes/353-oauth-with-doorkeeper
I am trying to implement XPagesSBT on localhost.
I have followed this article http://heidloff.net/home.nsf/dx/12152011034545AMNHECAP.htm and the SBT document by Niklas and was trying to implement dropbox oAuth.
I have also placed http://localhost/XPagesSBT.nsf/ and http://localhost/WebSecurityStore.nsf in root folder
but still i get this error
Error while executing JavaScript action expression
Script interpreter error, line=1, col=26: Error calling method 'isAuthenticated()' on java class 'com.ibm.xsp.extlib.sbt.services.client.endpoints.DropboxEndpoint'
No application is registered with id XPagesSBT and provider Dropbox
if(!#Endpoint("dropbox").isAuthenticated()) {#Endpoint("dropbox").authenticate(true);}
do i need to make any other configuration /setup to XPagesSBT db? or it wont work with Localhost?
I don't remember exactly anymore but reading my blog entry you linked it says you shouldn't use Anonymous:
"Additionally there are a couple of security related settings which are important to understand. First of all you need to assign access to the document with the application keys to the ID with which you signed the two NSFs. In the screenshot above I've entered both OpenNTF servers and my own user ID. When you use the web UI to do this these names are added to the document in an authors field and a readers field.
In the last step you need to configure the ACL of the security store. Anonymous must not have access to this database. All users who you want to be able to use the Social Enabler OAuth functionality need to have author access. This is so that their user keys can be stored in this database so that they only have to do the OAuth dance once. "
It should work on localhost. It looks like a configuration issue with SBT not being able to read the security tokens from the websecuritystore.nsf . Did you create the Dropbox Application Key with an admin id and sign the websecuritystore with the correct id?
Padraic
I've gotten a good number of OAuth logins working on my site now. My implementation is based on the WebSecurity classes with amends to the code to suit my needs (I pulled the WebSecurity source into mine).
However I'm now facing a new set of problems. In my application I have opted to make the user email address the login identifier of choice. It's naturally unique and suits this use case.
However, the OAuth "standards" strikes again.
Some providers will return your email address as "username" (Google) some will return the display name (Facebook). As it stands I see two options given my particular scenario:
Option 1
Pull even more framework source code into my solution until I can chase down where the OpenIdRelyingParty class is actually interacted with (via the DotNetOpenAuth.AspNet facade) and make addition information requests from the OpenID Providers.
Option 2
When a user first logs in using an OpenID provider I can display a kind of "complete registration" form that requests missing info based on the provider selected.*
Option 2 is the most immediate and probably the quickest to implement but also includes some code smells through having to do something different based on the provider selected.
Option 1 will take longer but will ultimately make things more future proof. I will need to perform richer interactions down the line so this also has an edge in that regard.
The more I get into the code it does seem that the WebSecurity class itself is actually very limiting as it hides lots of useful DotNetOpenAuth functionality in the name of making integration easier.
Andrew (the author of DNOA) has said that the Attribute Exchange stuff happens in the OpenIdRelyingParty class but I cannot see from the DotNetOpenAuth.AspNet source code where this class is used so I'm unsure of what source would need to be pulled into my code in order to enable the functionality I need.
Has anyone completely something similar?
AttributeExchange only applies to the OpenID Providers (Google and Yahoo!) and you can see the extension used in their respective source files.
I recommend against using email address as the username. Email addresses can be recycled (an account can expire or be closed/canceled and the email address can be reassigned to a new user). If this happens, your site based on email addresses would "give away" all the data of the old user to the new user. Massive privacy violation and lawsuit potentially happening there. Far better to use the Claimed Identifier for the OpenID cases, or the service provider-specific user id number in the OAuth cases, as the primary identifier in your user table. Certainly you may capture and display the email address everywhere on the web site where you would display a username so as far as the user knows that's the username -- it's just that internally you use something more precise than that.
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)
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.