Mutual Authentication in Action
This post is a continuation of the Fifteen Minute Guide to Mutual Authentication. In that post, I walked you through configuring WebLogic for two-way SSL, or mutual authentication. It was a whirlwind tour whose purpose was to drive home the essentials of PKI theory while emerging with a simple working implementation.
This post picks up where the other left off by having the user’s certificate suffice for web application authentication. In other words, with mutual authentication the user does not have to log in with a username and password. Instead, the user’s certificate is his ticket to ride.
Here’s what we’ll do in this post:
- Create a user
- Configure identity assertion in WebLogic
- Configure a web application to use CLIENT-CERT authentication
- Configure role-to-principal mapping in weblogic.xml
The pre-requisite of this post is a browser that will accept the server’s certificate and a server that will accept the browser’s client certificate. If you don’t already have that set up, refer to the Fifteen Minute Guide to Mutual Authentication and follow the steps there. You can also use certificates issued by other Certificate Authorities (CAs) but you must be able to connect the browser to the server as described in the guide. If not, the steps in this post will not work for you until the basic problem is resolved.
Enough introductory babble. Let’s get to it.
Create a User
When we’re done with configuration, client certificates will map to known users in the WebLogic security realm. I’m assuming here that you are using the DefaultAuthenticator which stores users and group information in WebLogic’s embedded LDAP.
You need to add a user via WebLogic Console. Note that the steps given here are for WebLogic 8.1.4 but they are approximately the same for WebLogic 9.x. To add a user, navigate to the Security->Realms->myrealm->Users node in the applet.
On the right-hand side, click on Configure a new User. In the General tab, enter the user ID in the Name field. If you used the example from the Mutual Authentication Guide, enter "Spongebob". Otherwise, enter the value of the Common Name (CN) of your test certificate. Enter and confirm a password. The password won’t be used for mutual authentication, but make it a strong password anyway.
Click Apply and then select the Groups tab. Add the user to the Administrators group by moving "Administrators" to the Current Groups box. Click Apply.
You now have a new user in the Administrators group. The user ID for this user matches the CN of the client certificate you’ve loaded in your browser.
Configure Identity Assertion
Next up is identity assertion configuration. Identity assertion is the process by which a token from the request is mapped to a known user.
You need to configure WebLogic to use an X.509 certificate as the authentication token. Furthermore, you’ll configure a username mapper to map the certificate’s Distinguished Name (DN) to a user ID. The username mapper is part of the identity asserter.
These steps assume you are using the DefaultIdentityAsserter. To configure it, navigate to the Security->Realms->myrealm->Providers->Authentication->DefaultIdentityAsserter node in the applet.
On the General tab, the User Name Mapper Class Name and Trusted Client Principals fields can remain blank. For Types, however, move X.509 to the Chosen side and remove AuthenticatedUser. An identity asserter can only support one type at a time. Click Apply.
Click the Details tab to configure username mapping. Check the Use Default User Name Mapper field. Select CN for the Default User Name Mapper Attribute Type. Leave Default User Name Mapper Attribute Delimiter and Base64DecodingRequired set to "@" and selected, respectively. Click Apply and then restart WebLogic for the changes to take effect.
What you’ve done is told WebLogic to use its default username mapper to map the certificate to the user. It does this by pulling the CN value from the DN of the certificate. The default usernmame mapper can handle these basic functions. If you have more complicated mapping requirements, you can write a custom username mapper and specify it on the General tab in the User Name Mapper Class Name field.
Regardless, given a valid client certificate, if the username mapper emits a user ID that can be found in the security realm, the user will be authenticated.
Configure a Web Application
At this point, you’ve defined a user whose username matches the CN of the client certificate. You’ve also told WebLogic how to map client certificates to users.
You now need to configure your web application to use what you’ve configured. You only need to do three things:
- Apply a security constraint to a resource in web.xml
- Set the authentication method to CLIENT-CERT in web.xml
- Configure role-to-principal mapping in weblogic.xml
All three of these changes are made in the web application’s deployment descriptors. I’ve provided a sample web application for you that can be deployed without changes if you want to skip the editing. The application also shows how to pull the user’s certificate from the request if you need to (although you usually don’t).
You must protect a resource with a security constraint for the security framework to kick in. Here’s an example security constraint from web.xml:
<security-constraint>
<display-name>Example Security Constraint</display-name>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/protected/*</url-pattern>
<http-method>DELETE</http-method>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>PUT</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>Admin</role-name>
</auth-constraint>
</security-constraint>
With a security constraint in place, you need to tell WebLogic how you want it to handle authentication. You’re probably most familiar with the FORM authentication type for doing username/password authentication. However, we want to extract the certificate from the two-way SSL session that’s already been established. To do this, we use the CLIENT-CERT authentication type. (You can find more information on the various authentication types here.) Here’s the pertinent snippet from web.xml:
<login-config> <auth-method>CLIENT-CERT</auth-method> <realm-name>ArbitraryName</realm-name> </login-config>
With this web.xml file in place, we’ve told WebLogic what we want to protect and how users should be authenticated. When the user requests a protected resource, WebLogic will notice and the security framework will spring into action. Before a user can be authorized to access the protected resource, WebLogic first has to determine who the user is. Since we told it to use the certificate from the SSL connection, WebLogic will extract the certificate and hand it to the identity asserter. The identity asserter will attempt to map the certificate to a known user using a username mapper class. If it finds a match, the user is authenticated.
After authentication, authorization checks kick in and the request will be processed if the user is allowed access.
The last thing to do is to map the "Admin" security role defined in web.xml to one or more principals. This mapping is done in weblogic.xml. We’ll map the "Admin" role to the "Administrators" group so that any user in the Administrators group will have the Admin role and will thus be granted access. Here’s the relevant snippet from weblogic.xml:
<security-role-assignment>
<role-name>Admin</role-name>
<principal-name>Administrators</principal-name>
</security-role-assignment>
At this point, deploy your application (or use the sample) and see if you can log in with the certificate.
If it doesn’t work, troubleshooting is straight-forward. Since you already have two-way SSL working properly, there should be no problem with the server, client, or CA certificates. Here’s what could be wrong:
- Incorrect security constraint
- Incorrect role to principal mapping in weblogic.xml
- Not requesting a web page with a security constraint
- Not using https
- Incorrect username mapper configuration
- Non-existent user (given the username mapping)
- User is not in the appropriate group for the security constraint
Once everything is correctly configured, you should be able to log in with only the client certificate.
Summary
You now have a web application that uses private/public keys for a very strong form of authentication. In the implementation shown here, the user’s public certificate does not exist on the server side. Rather, the user’s certificate is trusted because the server trusts the certificate’s issuer. Assuming the certificate is trusted, WebLogic then maps the certificate to a known user which can have the normal group memberships as any user.
Finally, thanks to the J2EE specification, your application does not have to deal with any of the mutual authentication machinery other than specifying in web.xml that you want it.
Great overview! I’m wondering about role mapping though. I need to assign each user’s roles by first calling a web service that takes his X.509 DN and returns info on him. Is the user’s X.509 cert available to a custom role mapper or has it already been mapped to a WL username at the point role mapping takes place? If it’s the latter, how does one get access to the user’s cert/DN from within a custom role mapper?
Thanks!
Comment by Kevin Moran — October 3, 2006 @ 4:14 am
Thanks, Kevin.
As you suspected, the username mapping has already occurred by the time role mapping happens. You might still be able to get the DN, though.
The RoleMapper interface is
getRoles(javax.security.auth.Subject subject, Resource resource, ContextHandler handler)
The Subject will contain the WL username. However, the ContextHandler contains extra information that a security provider can use. This object is simply a group of name/value pairs. If one of them is the HttpServletRequest, you’re in business. Have a look at http://monduke.com/2006/03/01/reversed-dn-in-weblogic-814/ for how to pull the DN from this object.
I’ve never examined the context data for a role mapper so I can’t tell you what’s in it. It’s also not documented. You’ll just need to loop through the data from your custom role mapper to see what’s inside.
Let me know how it goes.
HTH,
Mike
Comment by Mike Fleming — October 3, 2006 @ 8:44 am
I would like to know when to use default Identity Asserter (X509 token) and LDAP X509 Identity Asserter
Comment by Prem Sumetpong — October 10, 2006 @ 10:54 pm
Prem,
The default identity asserter will try to extract a known user from the certificate. It does this by pulling something (which is definable by the username mapper) out of the certificate and passing that along as the username. Then, an authenticator will check to see if that user exists. The authenticator might check a database or LDAP server, for example.
The LDAP x509 Identity Asserter differs from the default one in that the certificate presented by the user is the same one that’s stored in LDAP as an attribute of that user. That is, the user’s certificate is stored in LDAP and compared to the certificate that WebLogic received from the user. Furthermore, the username has to be from one of the attributes of the DN such as the CN.
Hope this helps,
Mike
Comment by Mike Fleming — October 11, 2006 @ 6:58 pm
Mike,
I finally got around to testing your suggestion for how to get user’s DN from the ContextHandler. I’m happy to report it worked like a champ. The key ‘com.bea.contextelement.servlet.HttpServletRequest’ allowed me to get his X.509 cert from the ContextHandler. Now my role mapper’s getRoles() method knows the caller’s DN.
Thanks!
-kevin
Comment by Kevin Moran — October 18, 2006 @ 3:23 am
Kevin: Excellent!
Comment by Mike Fleming — October 18, 2006 @ 7:27 pm
Isn’t this part of weblogic.xml
Your article mentions web.xml. Thanks.
Here’s the pertinent snippet from web.xml:
- m
Admin
Administrators
Comment by Madhav Lakkapragada — March 23, 2007 @ 3:15 pm
Madhav,
You’re right — I hosed that up big time.
I’ve made the corrections in the post.
Thanks!
Comment by Mike Fleming — March 24, 2007 @ 7:34 pm
very good work …
but, Can be avoied the creation of each user in weblogic security realm?
I must give the acces to many user …
thanks
Comment by mek — April 13, 2007 @ 1:29 pm
Mek,
If I understand you correctly, your users have certificates but you don’t have (and don’t want) a list of users in a data store such as an LDAP server or database.
That scenario is possible but you’ll have to write a custom authentication security provider. The default identity asserter maps the certificate to a username. Part of that work is done by a username mapper class which can pull the value of certain attributes. You could also write your own username mapper if your needs are more elaborate.
Regardless of the username mapper, though, you still have to deal with authentication. If the username mapper returns the CN from the certificate, for example, that CN needs to “exist” in the realm. As a result, your authentication provider will need to say that this CN does indeed represent a valid user even though he doesn’t really exist anywhere.
You can find more information at http://e-docs.bea.com/wls/docs81/dvspisec/ia.html. Note that my description above takes the approach of a separate authentication provider but you could wrap the assertion and authentication into the identity asserter.
Another issue to think about is authorization. I get the feeling that you don’t care about roles but just want the user to be authenticated before accessing your system. If that’s the case, implicit groups might do the trick.
Hope this helps!
Comment by Mike Fleming — April 13, 2007 @ 9:07 pm
Hallo Mike,
I try to setup WebLogic 8.1sp5 for handling Soap Messages with a signed Header. Much of your description was very usefull for me. But I configure d a web-servies.xml file, all according to the Bea documentation. However my webservice answers with: ‘{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}InvalidSecurityToken’
May I ask your help for this ?
kind regards,
Harry van Rijn
Comment by Harry van Rijn — September 10, 2007 @ 8:16 am
Harry,
I’d be happy to assist if I can. Please post the stack trace and we’ll take it from there.
Mike
Comment by Mike Fleming — September 10, 2007 @ 9:50 pm