CAS and SAML2 SSO by example - java

We have about a dozen internal admin web apps (mostly Java) that employees use for various workflows, and each of them have their own, disparate sign-in/authentication systems. I've been asked to federate them all together under a single sing-on system. I was handed the following diagram to use as a starting point:
As you can see, each app uses a CAS client to connect to a CAS server. This server also has Apache httpd with a Shibboleth plugin (?) configured. This CAS server then communicates with our Active Directory ("AD") server.
I need to make sure I completely understand how these technologies all work together:
What is happening between the CAS server and Apache/Shibboleth?
What is happening between Apache/Shibboleth and the "Trust Store"?
What is being communicated between the CAS server and AD?
What is stored in this SAML2 token being sent back from the CAS server to each CAS client?
How can I, as a Java developer, do with the SAML2 token (or lack thereof if auth fails) to actually sign users in with?
Are there any better technology choices here: if so what are they, and why? Bear in mind that all of these are Java apps, except one of them, which is a C#.NET app.

Here are a few of your answers:
First, let me give you a quick overview of how the interaction between a CAS client and a CAS server normally works: (I am not familiar with the Shibboleth portion, so I am omitting that.)
User hits the application webpage.
application redirects user to CAS.
CAS, using standard cookies and sessions, determines if user is already logged in.
if User is not logged in, CAS displays a login form for the user to provide login credentials. IF the user is already logged in, CAS skips to step #7.
CAS then interacts with the AD to verify that the provided credentials are valid.
if they are, then CAS logs in the user.
then CAS will redirect back to the application, providing a ticket.
The application makes a direct call to CAS to validate the provided ticket.
If the ticket is valid, then CAS returns user information as a response to the request.
The application then creates an authenticated session for the user, potentially looking up user information based on the info provided by CAS, and redirects them wherever is appropriate.
Now for your questions:
CAS and AD : CAS will actually login to AD and use the user provided credentials to find and authenticate the user. If you are using a forest, make sure you use the correct port to log into the Global Catalog, as that is easy to miss.
The contents of the token are not significant, as the standard CAS protocol will send the token back to CAS and retrieve user details in the response.
As a developer, this is actually very little you can do with the token, as it is tied to the application and can only be used once, and, for security reasons, has to be used within a very short amount of time (ie, sent back to CAS to be validated) or it will expire.
If you are doing primarily CAS and you have the ability to do your own CAS clients in your applications, CAS can be a very nice solution. Unfortunately, CAS does not have full SAML2 support, using it's own protocol instead, though CAS's protocol is very similar to the ARTIFACT profile for SAML2. If you want to integrate with other SAML2 clients, some work needs to be done.
Also, if your java applications happen to use Spring, Spring security includes a CAS client out of the box.
It is also pretty easy to write a custom client as you can see that the protocol is not terribly complex.
Also, while it is a bit more work and can be a pain to set up, if your employees already login to your domain via windows, then you can actually piggy back on that and configure CAS to use the windows login information users have already provided rather than prompting users with a login form making them re-enter their windows credentials.

Related

Authenticating, using and reusing password and Kerberos credentials in Java

Warning: This is an extremly long post, simply because I don't know how to explain our specific problems any other way (sorry).
Short version:
We are building a very modular suite of Java applications (both client and server side). Some clients have to authenticate against the servers, and the servers can authenticate against different types of user stores. Servers can also call other servers on behalf of their authenticated user, i.e. using their credentials. This has worked fine so far using simple username/password credentials, but now we have to optionally support SSO via Kerberos (and later other authentication systems). So far, we're failing (partly miserably).
Long version:
Our central Java library for handling principals is called User Access Layer (UAL). This library is used by both client and server applications and provides three types of funcationality:
Authenticate users based on their credentials (results in a failed authentication or basic information about the user, i.e. at least a login name or ID)
Perform principal queries
Perform principal modifications in the user store, if the backend supports it
(2) and (3) can be performed either using credentials specified by the caller or (if the backend supports it) as a technical user.
Actual access to the user store is handled by the configured backend. We provide a number of backends (LDAP, WebDAV, a custom JDBC database, a custom XML file) which can all be configured through a unified configuration file, usually named useraccess.xml. This file defines which backend (or backends) should be used and how it is configured, e.g. LDAP server and structure data for the LDAP backend or the database URL and database user credentials for the database backend. All backends implement the same interfaces so the application code is independent from the backends configured for a particular installation.
In our product, UAL is used by two different types of applications:
Clients (both command line/desktop clients and web frontend applications opened by a user in a browser). These applications use UAL to perform principal queries (e.g. our file browser application when modifying the ACLs of a WebDAV resource) or principal modifications (we have a web based user management application). Depending on the application, they get the credentials used for their UAL operations in one of the following ways:
a. User provides the credentials on the command line when calling the application
b. Application opens a dialogue and prompts the user to input credentials when a server access requires them
c. A login screen displayed when the user first accesses a web frontend application
Servers. which use UAL to:
a. Authenticate a user based on the credentials provided via the used protocol (e.g. HTTP/WebDAV or SOAP/WSSE)
b. Perform authorization for a user based on the user's (or the user's groups') attributes
c. Perform UAL operations (queries/modifications) on behalf of the client
d. Call other servers on behalf of the client, i.e. passing another server the user's credentials (e.g. via HTTP/WebDAV or SOAP/WSSE)
Until now, all our credentials were user name/password pairs, which worked fine as long as we made sure to keep these credentials in the user's session where necessary to later use them for accessing another server. We could do that every call that retrieved credentials or passed them to a server went through some of our code which could store/provide the necessary credentials.
Everything has become much more complicated with the requirement to support SSO via Kerberos. We've tried several approaches and modified our code base several times, but every time we believe to be on the right track, we realise that there's one spot we overlooked which cannot work the way we intended.
What makes things so confusing is that we have to handle credentials in several different ways. These are some of the ways we have to provide credentials to a server:
Via Apache HttpClient when accessing a HTTP/WebDAV server
Via SOAP/WSSE when accessing a web service
Via JNDI when accessing the LDAP server (in UAL)
And some of the ways we have to receive and verify credentials from a client:
As a login module in Apache Jackrabbit
When receiving a SOAP/WSSE message in one of our JAX-WS web services
A very common use case for us is the following:
Client calls server A via SOAP, providing credentials
Server A retrieves the credentials from the SOAP message and verifies them (responds with an error if they are invalid (authentication error) or the user is not authorized to perform the desired operation (authorization error))
Server A then calls WebDAV server B on behalf of the user, passing the user's credentials so that the WebDAV operation can be carried out with that user's permissions (and using that user's name and other attributes)
Server B retrieves the credentials from the HTTP message and verifies them
Server B then performs a principal query on the user store C, passing the user's credentials to the user store (depending on the configured UAL backend, this may simply compare the user's name and password to those in the user store XML file, or use them to establish an LDAP connection and query the LDAP store as that user)
And the problem is: There seems to be very little information on the internet to help with our specific problems. For starters, most resources simply describe how to setup a JAAS configuration file for a container to let its web applications perform user authentications. But our code has to run on both clients and servers and use one configuration file to specify the user store config for both authentication and principal queries/modifications. Furthermore, this has to work, with the same code, with user name/password credentials against a variety of user stores (some of them custom written) and with Kerberos (and later other) tickets against an LDAP server. And finally, it's not enough to have an authentication library which reliably tells us that user has provided the correct credentials (as many JAAS login modules seem to do), since we actually have to keep the user's credentials for further calls.
Since Apache Jackrabbit, which is the base for one of our core components, needs us to configure a JAAS login module, and there already are JAAS login modules for LDAP and Kerberos authentication, we have successfully modified UAL to perform all its authentication tasks via JAAS. For this we had two write login modules for our custom backends, and I had to implement my own LDAP login module since the default JAAS one would successfully authenticate the user against the LDAP server, but then throw away both the user's credentials and the LDAP context, so we couldn't perform further LDAP query using the same credentials. All our own login modules store the credentials in the authenticated subject's private credentials set, which is what JAAS's default Kerberos login module does as well. Using the resulting subject, we can then perform user queries. This works with all our backends and with both passwords and Kerberos tickets.
We were also able to modify our SOAP services to extract the credentials from the SOAP message. In the case of password credentials, we can simply pass them to JAAS when the authentication callback asks for credentials. However, there doesn't seem to be a way to do the same with a Kerberos ticket. Instead, our SOAP services currently handle those on their own, passing them through the necessary GSS API calls to verify the ticket, retrieve a matching ticket for the SOAP service's configured service user, and create a Subject containing the credentials and user information. Using this subject, we can then perform queries/modifications through UAL. However, this not only means that our SOAP services completely bypass UAL when authenticating Kerberos tickets, they also need some Kerberos configuration data (the service user name, the realm and the keytab file) in their own configuration, in addition to the useraccess.xml which already contains the same data (but not directly accessible to a generic UAL client because these settings are specific to the UAL LDAP/Kerberos backend). Obviously, things will only get worse when we add support for other ticket based authentication methods and they also have to be manually implemented in each SOAP service in addition to the UAL backend that actually handles the user store access.
Worst of all, we're still unsure how to get all this into our Jackrabbit based WebDAV server. Jackrabbit needs a login module, which should be fine for handling user name/password credentials but (as far as we can tell) fail for Kerberos tickets. We could probably fetch those manually from the HTTP headers, but that won't stop Jackrabbit from calling the login module and the login module from failing because it will still ask for a password and then fail to authenticate against Kerberos without one.
I can't shake the feeling that either our approach or (quite possibly) our understanding of how all these pieces should fit together is fundamentally flawed, but nothing we can find on the net spans enough of our requirements to indicate what we're doing wrong (or, more importantly, how it should be done to make it right). Because of the complexity of even describing our problems I so far shied away from posting this as a question, but if you've read this far and can give us any pointers on how to resolve this, you could save us from weeks of frustration.
You can remove everything after
Until now, all our credentials were user name/password pairs, which worked fine as long as we made sure to keep these credentials in the user's session where necessary to later use them for accessing another server. We could do that every call that retrieved credentials or passed them to a server went through some of our code which could store/provide the necessary credentials.
You problem is plain simple: you need credential delegation with Kerberos. The basic technique is quite simple. Since you have multiple problem areas here, I would recommend to break them up to have you problem solved:
OS/environment configuration for Kerberos credential delegation
How to request a delegable service token
How to retrieve the delegated TGT from the client
How to reuse the TGT from the client and request another service token
Since your inbound channel is HTTP, here are the answers:
If you are in an Active Directory environment, request your admin to set "trusted for delegation" on the machine account which will accept the GSS security context.
This is a bit tricky because it depends on the client language and library. In Java it is as simple as setting GSSContext.requestCredDeleg(true). Eloborate on the rest.
Inspect the code of my Tomcat SPNEGO/AD Authenticator library, I am extracting the client's TGT and storing it in the Principal implementation served by HttpServletRequest#getPrincipal method.
Assuming that your backend client library supports GSS-API properly, there are basically two ways to do it: (1) explicit credential usage: pass the delegated GSSCredential instance to the client lib and it should the rest. (2) implicit: Wrap your client action in a PrivilegedAction, construct a Subject with the private GSSCredential and invoke Subject.doAs with both. JAAS will use the implicit credential from the thread's subject and perform the operation on behalf of your user.
It seems like you haven't even reached point 2 or 3 yet.

Can i use Jasig CAS server for android mobile applications?

I know that CAS is a single sign-on protocol for the web. Its purpose is to permit a user to access multiple applications while providing their credentials (such as userid and password) only once. It also allows web applications to authenticate users without gaining access to a user's security credentials, such as a password.
So, How can i use Jasig CAS server for android mobile applications ? some guidelines would be very useful!
Actually there exist two ways of doing this, each of them has some drawbacks.
1) Expose the REST interface (here you'll find a simple JAVA client that consumes them and a iOS sample how to use it on a mobile)
The problem here is that if somebody downloads your application from the store and checks the network traffic in it (or simply decomposes it) he'll find the calls you make. With this he could create an APP that does the same as you do, and log the passwords entered by the users (like a man-in-the-middle attack)
2) Open the real website in a web view inside your APP
You'll need to create a modle login page, or a responsive one on your CAS server so that it looks nice. Obviously even here somebody could theoretically copy your APP and the Website on your CAS fake both to look like your APP grab the username and password and send it in background to your CAS to give to the user the impression that everything went right but it is much more complex.
However even here u'll need to tweak the CAS; CAS is designed to accept a login for a service to which it would redirect after successful login. Therefore in this case you'll need to add a fake service to the CAS configuration and check if the webview will redirect to it. when that happens u'll find the TGT in the CASTGC cookie.
In our first APPs we used the REST version, but then as we use our CAS for websites too we wanted to restrict the REST access only to other servers in the facility, so we came up with the second solution which seems to fit better, but overall CAS seems not to be prepared for mobile APPs
You can set up CAS in order to expose REST service, this allow to validate credentials.
Documentation: https://wiki.jasig.org/display/casum/restful+api

How to secure Android App that pulls data from OAuth protected resource

My company is building a RESTful API that will return moderately sensitive information (i.e. financial information, but not account numbers). I have control over the RESTful API code/server and also am building the Android app. I've setup the API to use OAuth 2 with authorization code grant flow (with client ID and secret), and I auto-approve users without them having to approve the client since we own both client and provider. We use CAS for SSO and I am using this for the Authorization server as part of the OAuth 2 process when the user logs in to retrieve the token.
I am contemplating various ways to secure the data on the Android app. I've concluded that storing the client id and secret on the device is definitely not going to happen, but am thinking that storing the auth token might work, since it is only risk to the individual user (and really only if they happen to have a rooted phone).
Here are two options I have thought of. They both require me to have a sort of proxy server that is CAS protected, does the dance with the API server, and returns the auth token. This gets rid of the need for storing the client id and secret in the app code.
Here are what I've come up with:
1) Require the user to enter their password to access data each time they startup the App. This is definitely the most foolproof method. If this were done, I'd probably want to save the userID for convenience, but in that case couldn't use the CAS login (since it's web-based). I might be able to use a headless browser on the backend to log the user into CAS and retrieve the token based on what they enter in the Android form, but this seems hacky. Saving the userID is similar to what the Chase app does (if you happen to use this one) - it saves the userID but not your password between sessions.
2) Store the auth token on the Android device. This is a little less secure, but almost foolproof. When the user starts the app for the first time, open the webpage to the CAS login of the proxy server that returns the token (similar to https://developers.google.com/accounts/docs/MobileApps). After the user logs in and the token is returned to the app, encrypt it and store it private to the application. Also, use ProGuard to obfuscate the code, making the encryption algorithm more difficult to reverse engineer. I could also work in a token refresh, but I think this would be more of a false sense of security.
3) Don't use CAS but come up with another way to get an auth token for the service.
Any advice of how others have implemented similar scenarios (if it's been done)?
Thanks.
Well the reason why standards like OAuth are developed is that not everyone has to rethink the same attack vectors again and again. So most often it is your best choice to stick to something already available instead of baking your own thing.
The first problem with clients that are not capable of secretly storing data is that the user's data could be accessed by some attacker. As it is technically not possible to prevent this (code obfuscation won't help you against an expert attacker), the access token in OAuth 2 typically expires after short time and doesn't give an attacker full access (bounded by scope). Certainly you shouldn't store any refresh token on such a device.
The second problem is client impersonation. An attacker could steal your client secret and access your API in his own (maybe malicious) app. The user would still have to login there himself. The OAuth draft there requires the server to do everything it can to prevent this, but it is really hard.
The authorization server MUST authenticate the client whenever possible. If the authorization server cannot authenticate the client due to the client's nature, the authorization server MUST require the registration of any redirection URI used for receiving authorization responses, and SHOULD utilize other means to protect resource owners from such potentially malicious clients. For example, the authorization server can engage the resource owner to assist in identifying the client and its origin.
I think Google are the first to try another approach to authenticate a client on such devices, by checking the signature of the application, but they are not yet ready for prime time. If you want more insight into that approach, see my answer here.
For now, your best bet is to stay on the OAuth way, i.e. having the access token, client ID and client secrect (when using the authorization code grant flow) on the device, and configure your server to do additional checks. If you feel more secure obfuscating these, just do it, but always think of it as if these values were publicly available.

CAS SSO with multiple web applications

I've spent the last day or so looking in CAS and have managed to get the server working with a simple test application. When I enter a protected area, I'm redirect to a login page - when I log in, I'm taken back to my previous page.
From there, the next step would be deploy two client applications, log into client A, visit the client B protected area and have the system handle the authentication for me (since I'm already logged into client A).
This isn't actually working however. I have to log into the client B site whether I'm logged into the client A site or not.
CAS is running on Tomcat, client A and B are the same project deployed as separate wars on a single instance of JBoss AS 6.
Any ideas how I can achieve the suggested behavior?
EDIT: Yes, both are using CAS. The issue is that it doesn't seem to be recognizing that the user is already logged in. It's as if the CAS isn't able to determine that there is a 'link' between the two services and that when one service has been authenticated, the other service should be automatically authenticated.
I should note that at this stage, I am not using SSL within the application. I'm focused on getting a simple example up and going using HTTP before I look at introducing SSL.
Both of your applications need to be configured to use the CAS server for authentication. The normal procedure would be that application A redirects you to your CAS login page, lets you log in and redirects you back to A. If you then try to log into B, it checks with the CAs server whether you're already logged in and, if so, sends back information about the logged in user.
Again, both your applications need to support CAS as a login mechanism, which I am not sure about from your description.
Detailed description of the CAS protocol can be found here.
CAS was working without SSL in that it would take you to the login site and authenticate you correctly. The issue was if you tried to access via another site, it would ask you to sign in again.
Once I enabled SSL and tried it, it was working correctly. Once logged into client A, it would automatically authenticate you in client B. I had spent some time on the wiki and while it spoke of the importance of using SSL, I do not recall it explicitly stating that SSO will not work without SSL enabled. Maybe a warning should be added to the wiki?
If you want to focus on your applications and make your life easier, use a cloud provider for the CAS server: http://www.casinthecloud.com (free servers are available for tests).

Is using AD credentials entered into form fields as opposed to the browser integrated auth window bad practice?

I’m looking for a bit of feedback on the practice of requesting users to authenticate to an intranet based web app by entering their AD credentials directly in form fields. For example, using domain\username and password fields as opposed to using the native browser based challenge window for integrated authentication. In the form based example, credentials are passed to the application in plain text and it’s essentially up to the integrity of the application to handle the data appropriately. It seems to me this is the equivalent of entering my Open ID credentials directly into a host app on the Internet.
So my questions are:
Is there any best practice guidance on authenticating to a custom web app (assume predominantly .NET / Java stacks) in an AD environment?
Can you think of any legitimate circumstances where this is really necessary?
Is this a legitimate concern or am I just being paranoid?!
In a highly secure environment, users would be encouraged to only enter their credentials when using the Secure Attention Sequence CTRL-ALT-DEL, which is designed so that it can't be intercepted by applications.
So in such an environment, even the browser challenge window for authentication would be suspect. Instead you would log on locally using the same AD credentials as you need to access the website, and would be authenticated without needing to be prompted.
I'd say entering AD credentials in form fields is extremely suspect if the credentials can also be used for access to other sensitive resources. Even if the app developers are well-intentioned, it is an unnecessary security hole. For example, anyone who has write access to the web directory can easily replace the login form and capture credentials.
If it's a browser based application, why wouldn't you just enable Windows authentication in your web.config (not sure what the equivalent is in the Java world, sorry) and let the browser handle authentication.
Otherwise, I'd say if you do this over a secure transport (SSL) then you should be ok. Microsoft's own products often use form fields to submit AD credentials (I know Outlook Web Access and Internet Security & Acceleration Server both do this).
The best approach is to use Kerberos tokens instead of an encrypted username/password.
This open source library, http://spnego.sourceforge.net, will allow your java web apps to perform integrated windows authentication using Kerberos tokens.
The library is installed as a servlet filter so you will not have to write any code.

Categories