Combining a one-time "provisioning" process with JSF? - facebook

Let me preface this by admitting that this is my first webapp and first experience with JSF, so I've probably made some poor design decisions.
Here's what I'm trying to do:
I have a webapp using JSF 2.0, which is accessible through a Facebook canvas. This webapp allows a user to view/manipulate data from a database of sensor readings. On the very first time the Facebook user accesses my app, I ask the user to enter login credentials for the database, then send the user to the home page. Thereafter, the user should always go straight to the home page, since I associate the user's FB id with the database user profile.
Current implementation:
I have the Facebook canvas URL going to a servlet. This servlet checks the signed_request parameter passed by Facebook to get the user ID, and then looks in the database to see if the user has already completed the provisioning process. If the user has done so, he is redirected to the application home page.
The problem:
Most of my logic to do these checks currently exists within a managed bean (session-scoped). To use the bean within the servlet, I'm manually instantiating the bean and adding it to the session, since the JSF framework hasn't had a chance to create it yet. As my system is getting more complicated, this is causing problems due to dependencies between the various beans. Also, it seems like a generally bad approach to the problem.
Solutions? From my web searching, it sounds like there might be several ways to do this. One way would be to set the canvas to a JSF landing page, where a managed bean would grab the signed_request parameter and validate that the user has completed the provisioning step. From there, the bean would forward to the proper page. Another possibility might be to have an eager bean that does the same thing, but this seems "wrong".
What's the best way to resolve this and adhere to "proper" JSF paradigms?
Thanks in advance!

There are a number of different ways that this can be handled. The JSF landing page is one idea and the eager bean are some ways that this can be handled.
If you ignore the fact that you are integrating with Facebook then ultimately you are trying to solve an authentication and authorization problem. Facebook is handling your authentication, and telling your web application what the identity of a user is, and it is your web app's job to remember that person's identity throughout the session, and authorize this person to visit the requested page.
I have implemented it before where I had all of my managed beans extend a BaseBean class that on creation and initialization checked for the existence of a specific SessionScoped bean that contained the user identitification information. If this bean did not exist or was not authorized to access this bean then I would redirect. The problem with this approach was that it authorized only the use of managed beans, and not pages.
Another approach I had was to utilize a servlet filter that would essentially check every page request and look for the session scoped bean that contained the currently authenticated user. If this wasn't found then I would look for the specific request parameters and authenticate and create the session bean, and if that didn't exist would redirect to an Unauthorized page.
This approach worked well until I realized that Authentication and Authorization of Java web applications is a well understood and near universal problem. After a little bit of looking and research I discovered that security frameworks like Spring Security 3 can indeed be integrated into JSF and handle nearly all of the complexity of complex authentication and authorization. You could very easily integrate a custom Facebook authentication handler for Spring Security and control access by user role to the individual page level, all from XML configuration. It is highly worth looking into if you have the time to learn something new.

Related

IdentityServer handling timeouts and subsequent redirects

I've implemented IdentityServer3 in my application and it has been working really good. However recently I came across some behaviour I can't quite figure out so I was hoping someone could tell me what I'm either doing wrong or how I should be doing the following:
I have a ASP.NET MVC application that uses IdentityServer for authentication. The user authenticates and opens a specific page within the application. He moves away from his PC, comes back a little later and clicks another link within the application (e.g. controller/action/38). The application then redirects the user to:
http://localhost/MyIdentityServer/identity/connect/authorize?client_id=myapp&redirect_uri=http://localhost/MyApp/controller/action/38&response_mode=form_post&response_type=id_token&scope=openid+profile+roles etc.
Since only the root url of the app (http://localhost/MyApp) is registered as a RedirectUrl in IdentityServer it shows the following message:
The client application is not known or is not authorized.
Rightfully so, since the controller + action aren't valid RedirectUrls. However, I cannot image that I'd have to add all the controllers and actions to the RedirectUrl property, especially since they take data-related parameters. Surely I must be doing something wrong but what?
You're modifying the redirecturi provided to idsrv on each request to idsrv:
remove this line:
notification.ProtocolMessage.RedirectUri = something

Adobe CQ5: SSO without LDAP?

A customer of ours has just purchased CQ5 and would like to externalize all of its security. We'd like to use an STS server for SSO and then leverage a custom authorization/attribute provider instead of the CQ5 repository. Ultimately, we do not want to use LDAP in any way.
Here is how we envision this (some pieces already working):
User browses to CQ5 Dispatcher running in Apache
Apache filter redirects user to STS site where login is completed.
User is redirected back to Apache with SAML Claims.
User ID token is placed as cookie into browser. (everything is working up to here)
CQ5 captures that cookie based on the SSO configuration (working)
Problem starts here: From here, we want to call a custom authorization provider for the user's attributes, roles, groups etc...
We have tried to figure out how to do this and can't seem to find the missing link.
Do we need to create a custom login module? Do we need to create a custom principal provider? Do we somehow use the existing LDAP capability in CQ5 but have it call a custom class which leverages the external auth source?
If anyone here has any idea how to do this, their karma quotient would be full for the year if they could share it. I'm not sure if this is a basic thing you do with JAAS or even where to put my classes after I've created them.
We've worked really hard on this so far and seem to be close, but we keep hitting dead-ends.
Thanks so much if you have an idea where to begin!!
-joe
Recent versions of AEM now include the SAMLAuthenticationHandler which allows you to:
Redirect users to SSO to simulate IDP initiated login, or
Allow AEM to perform SP initiated login with IDP
Specify attributes to take from the SAML Assertion and add to the user's profile node (not sure if you can use this for groups)
Specify which groups users should be added to
Set a cookie called request-path that will store the URL the user arrived at, and then redirect them to that location when they're authenticated (ie. deep linking)
This makes relying on the SAMLAuthenticationHandler better than using Apache to redirect. The current version of the handler bundled with AEM 6.2 does not properly set the cookie when using the redirect method, but Adobe does have an updated version that they can provide that will fix that problem.
I normally recommend that clients do not have their own authentication handlers developed inside AEM.
When not using LDAP, this does create an issue where users will not exist until they've logged in. Additionally, when your architecture includes more than one load balanced publisher, it is possible that a user may exist on one server user synchronization.
Try searching the google group for SSO details. Here's one useful post:
http://groups.google.com/group/day-communique/browse_thread/thread/72c235c83a501252/fba4d08a90487156?lnk=gst&q=SSO#fba4d08a90487156
It seems that you will have to implement a custom LoginModule, more information here: http://dev.day.com/docs/en/crx/current/deploying/custom-login-modules.html

Keeping GWT History Hashes thru Spring Security Login

I'm retrofitting my application with GWT History support, and I've stumbled on a case where I'm not quite sure what to do. The answer to this question doesn't necessarily have to be GWT-related.
GWT's History support functions by passing around hash tags (i.e. index.html#token). Security restrictions require users be logged in prior to actually being able to access index.html, so they get sent over to a login page, retaining the token (login.html#token). So far, so good. Now the user becomes authenticated and Spring sends them over to index.html (the default target) and eliminates the #token part of the URL.
How can I force Spring Security to maintain the token and send my newly authenticated user to the page they requested (index.html#token)? Since I've already got Spring Security authentication working, I'd prefer to not restructure the way my app handles logins.
After a great deal of digging, I found my answer on Spring's Jira. As Colin Alworth stated, that token isn't actually part of the request, so Spring Security never sees it server-side, and thus can't use it to determine the final URL. So the approach I used was to append the hash (client-side) to j_spring_security_check, making it j_spring_security_check#token. Now the token gets passed along just fine, allowing me to have a well-secured app with working tokens.
Thanks for your help Colin, your answer got me thinking in the right direction.
The server doesn't get to see this token as part of the GET/POST request as you've noted, it is only seen by the browser. Best fix that I've seen for this in the past is for the login page to take note of the current window.location.hash, and pass that along, either along with the login form (assuming a redirect will take place that keeps the hash around), or to the server as a login param so it can redirect properly.
Here's what happens, it might help you solve the problem:
sending unauthenticated users from index.html to login.html is most
likely implemented as an HTTP 3xx redirect, and that's why the
browser keeps the hash fragment (#token).
Once they login, spring sends them from login.html to index.html not
via 3xx redirect so the browser doesn't keep the token.
One solution would be to inject the token into index.html, and pick it up with GWT. Another one is to make login.html -> index.html a 3xx redirect (if spring allows that).

Integrated Exchange login with GWT on Tomcat

I have a GWT app to deploy to Tomcat on a Windows server, with the following requirements:
1- The app should work fully, whether the user is in the Windows domain or not;
2- If the user happens to be in the domain, the app should be able to identify the user in some manner. Presumably, this should be via getThreadLocalRequest().getRemoteUser(), but any other alternative is fine...
3- If the user happens to be in the domain, the app should be able to access the MS Exchange server in that domain, without requiring the user to enter their password.
I've scoured the web high and low for this, but unfortunately, it seems there's no way to get authentication without forcing authentication. There are many examples of exclusions for, say, a login form or other "public" resources, but that won't work for us, since all the resources in a GWT app are packed into the same "page".
Maybe it's my limited understanding that's making me fail in some basic way, but I've tried to look at JCIFS, Jespa, Waffle and SPNEGO, and I just can't seem to get working the way I want to...
Any help would be greatly appreciated.
Cheers,
J.
How about putting a Javascript on your front page and have a Kerberos/SPNEGO protected page. The javascript will attempt to request a protected page, if the user is on the domain you will get the correct result from the page otherwise you will get 401 access denied. In the former case you can redirect your browser to exchange page, or have another AJAX call to retrieve things from exchange server in the later case you either show a log-in form or a generic anonymous page.
What about using JNI to call the Win32Api function LogonUser?
By doing impersonation at the thread level you will have the NTLM token added to the current thread and you would be able to call exchange with no issues

How to map facebook authenticate users to roles using the asp.net RoleProvider?

I'm trying to switch my site from the asp.net membership sql provider to using facebook connect to do OAuth single signon. I'd like to keep using the role provider as it makes it pretty easy secure sections of my site by flagging the controller class or controller methods with the Authorize(Roles="...") attribute. The site isn't live yet so I'll be completely ditching the Asp.net membership provider if I can. (keeping the roles and profile provider)
I've got the facebook connect logging the user in and I can get his info. But how do I associate that with a role?
I'd like the system to automatically add a new user to the "SuperHero" role after he authenticates and authorizes my app.
Am I on track here? Is there a better way to handle roles when using OAuth2? I'd like to add other OAuth providers later.
An alternate approach would be to keep the asp membership, then when I user logs in through facebook connect, I could find his record and sign him in with aspmembership. But that seems sloppy.
Some sample code would be great and I'd think others would find it helpful too.
thx,
Dan
The easiest way to do this ime is to actually implement a FacebookMembershipProvider for yourself. That way it ties in to all the other providers naturally. The main downsides are a) a lot of code b/c Membership is a fat interface, and b) some cruft b/c it assumes you'll be doing passwords, etc, which obviously you don't need for OAuth.