In a recent post Josh said
There is another approach that, unfortunately, is rather common - use a Web Gate in front of WebLogic Server and use a very weak identity asserter or no SSPI connector at all.
I'd started writing this post before Josh wrote that and figured I'd post this anyway in hopes that my longer and more detailed write up is helpful to someone unfamiliar with what all of the terms and acronyms mean.
WebLogic Server includes a great security framework that provides five services - authentication, role mapping, authorization, auditing, credential mapping. There's also a sixth service called adjudication that kicks in if you have more than one authorization provider, but that's a story for another day. Out of the box WebLogic ships with a bunch of providers for each of those services.
The authentication service/interface does exactly what you'd think - takes a set of credentials, verifies them, and allows WebLogic to create a JAAS subject and principals for the user. Out of the box credentials are things like username and password against an LDAP directory. The ability to assert a user's identity without having their actual password, for example via a certificate, is also supported; in that case the authenticator is called an Identity Asserter.
So what is the worlds most dangerous identity asserter?
To answer that you have to understand the typical WebLogic deployment architecture. The recommended way to deploy WebLogic is to deploy a load balancer, two or more web servers (Apache, OHS, IIS) with the WebLogic plug-in, and then two or more WebLogic servers. Here's a diagram:
This architecture allows you to do a bunch of very useful things - gracefully handling single component failure, load balance across the components, scale up more or less linearly by adding additional WLS servers, and more.
Enterprise deployments also typically involve integrating with web single sign-on solutions like Oracle Access Manager (OAM), SiteMinder, or even Microsoft's Kerberos implementation included in Windows.
When you do the authentication at the web tier you need to convey the user's identity over to WebLogic and install in an Identity Asserter to populate the JAAS subject and principals. When you're doing authentication on the web server the most obvious way to write an Identity Asserter is to just consume the username HTTP header - after all the web server already did the authentication why bother doing anything more?
Why? Because if anyone manages to sneak by your web server they can impersonate any user in your user directory. Combine that with the commonly quoted statistic that two-thirds of security breaches are internal rather than from a hacker on the outside.
Let the implications of that sink in for a second...
Assuming you did everything else right in your app and environment your biggest risk is a bad guy inside your network. If you write an Identity Asserter that just blindly trusts an HTTP header you'd better be sure to do something to protect the WebLogic server.
I recently encountered a customer that wanted to authenticate their users with Kerberos authentication at IIS rather than inside WebLogic. They could have done the authentication in WebLogic with the SPNEGO authenticator but, for a variety of reasons, doing the authentication in IIS was a better fit for their environment. We wrote a very simple Identity Asserter that consumed the Proxy-Remote-User HTTP header, stripped off the Windows domain name and asserted the remainder as the username.
How do you protect the WebLogic Server in this architecture?
There are really two options:
- two-way SSL between the web server and WebLogic Server
- firewalling
Two-way SSL between the web server and WebLogic Server both protects the data sent by encrypting it but also prevents access to the WebLogic Server from any client that doesn't have an appropriate client certificate. The actual steps are covered in the documentation for the ISAPI plug-in for IIS and for the Apache module. Using SSL requires certificates and imparts a performance impact, the magnitude of the impact depends on the environment so we always recommend testing.
An alternative to using two-way SSL is to use a firewall to protect the WebLogic Server. You can use a network based firewall, the traffic filtering functionality built into your host Operating System, or WebLogic Network Connection Filters. No matter which of these you opt to use the objective is to insure that any HTTP traffic coming into the WLS server orignated at one of the Web Servers and not from somewhere else in your environment.
Update November 2010: Due to popular demand the source code to this Identity Asserter is available at https://sample-identity-asserters.samplecode.oracle.com/
Is it possible to find an example of how to build this?
ReplyDelete"We wrote a very simple Identity Asserter that consumed the Proxy-Remote-User HTTP header, stripped off the Windows domain name and asserted the remainder as the username."
There's an example in the WLS documentation at http://download.oracle.com/docs/cd/E12840_01/wls/docs103/dvspisec/ia.html
ReplyDeleteIt looks like all of the "stuff" you need to build is there, but if you run into trouble let us know and we'll help you sort it out.
You might also find the post at http://fusionsecurity.blogspot.com/2009/07/building-custom-security-providers-with.html helpful.
ReplyDeleteI've been working with this quite a bit, but have a question. When doing this, if I do a getCookies("username") from a jsp file, should I see my username, or would it be null?
ReplyDeleteI have the SimpleAuthentication apparently working, but I'm not sure about the assertion. Should something be setup in there to set the username in the cookie? What order should the two be in, in the providers.
Is there a way I can work with you directly on this?
Thanks,
the username won't be stored in a cookie. You can get the username by using the normal WebLogic API. If all you want is the username then request.getRemoteUser() will do it. If you want all of the principals then check out weblogic.security.Security.getCurrentSubject().getPrincipals().
ReplyDeleteSupport should be able to help you with this or you can post a question to the OTN discussion forums and pop a reference to that here.