pyehouse
7Aug/140

Weblogic, Kerberos, Single Sign On and You

We recently needed to implement single sign on in Weblogic for a client and finally managed to get it working, but had more difficulty than we probably ought to have. While some of our problems stemmed from our lack of experience with Weblogic, we also ran into problems with the documentation we were pointed to being vague, incomplete, and/or misleading. My goal with this post is to hopefully help others avoid some of the same misunderstandings and pitfalls we experienced.

First, I'll point you to three pertinent links which helped. Understand, though, that there were a number of other things we ran across through various searches that led to us working these issues out. The first two are official Oracle documents and the third was a scribd article that helped us put some pieces together.

How To Configure Browser-based SSO with Kerberos/SPNEGO and Oracle WebLogic Server

Configuring Single Sign-On with Microsoft Clients

Enable Kerberos With Workspace 11.1.1.3

As I said, the first two links are to Oracle documentation. I believe the second link is a bit more useful, to be honest, though the first does have a little sample servlet code you can slap into place for testing; but keep in mind that the instructions to make it work are incomplete. The useful bits on both have more to do with configuring Kerberos (e.g. account and SPN generation, keytab generation and installation) but leave a little out that would be very useful. The third article is a scribd article that describes exactly what the title indicates, but the setup for Kerberos was helpful in terms of getting the keytab right.

The first problem we had was with the account and keytab generation. We were using the first Oracle link which was a little more spartan with its explanation of how to set up the accounts in Active Directory and set up the keytab file. Sure, it has images and explanations but the selection of account and machine names is ridiculously confusing. The second Oracle link has a better explanation of the account setup and keytab generation but still includes some information that is either unnecessary or misleading.

  1. In the Active Directory create a user account which will be doing 'Kerberos things'. e.g. svc_someapp_krb
    1. By all means, ignore the suggestion of using the name of the client machine for the account name. Adhere to whatever naming convention makes the most sense. This one suggestion led to a lot of confusion while trying to decide how to configure the 'ktpass' command.
    2. 'ktpass' will create an SPN for you, but you can also do it yourself. The instructions suggest creating the SPN separately. It matters little.
    3. Keep in mind what encryption type to select in AD for the user. It must be consistent. We used AES 128. If you go higher than this remember you'll need to download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files here and install them properly.
    4. Make note of the fact that changing the encryption type AFTER setting your password can corrupt the encrypted password. Reset your password (even if to the current value) if you change encryption.
    5. Sometimes Java implementations for keytabs have problems with special characters. What is a special character? We wound up using strictly alphanumerics to avoid the problem. We couldn't find a firm definition of what was allowed. You could try underscores and hyphens. Much more than that and you begin risking running into this issue.
  2. For our 'ktpass' our principal was of the form 'HTTP/ourserver.some.domain.com@SOME.DOMAIN.COM'. Notice the caps? You'll need that. Notice the repetition of the domain? You'll need that to. So our 'ktpass' was like:
    1. ktpass /princ HTTP/weblogicserver.domain.com@DOMAIN.COM /pass domainuserpassword  /mapuser domainuser@domain.com /ptype KRB5_NT_PRINCIPAL /out weblogic.keytab /crypto AES128-SHA1 /kvno 0
  3. If you are not using node manager, but are running your Weblogic server as a Windows service, you presumably already set up your install.cmd file. You'll need to add the specified options as JAVA_OPTIONS here. Remember, the Server->Server Start arguments are only useful when the Node Manager is handling things on a remote server. For local setup you'll need to use different means. We ended up using full paths for our various files.
  4. If you don't have access to the C:\Windows\ folder, you'll need to create your krb5.ini file and place it somewhere else, then add a startup option to point to it as the default location can't be used. You can do this via the following additional JAVA_OPTIONS parameter:
    1. -Djava.security.krb5.conf=C:\OurApp\krbstuff\krb5.ini

Keeping these points in mind while setting up things for Kerberos will help you avoid some of the issues we ran into. At this point we were able to add the NegotiateIdentityProvider to our security realm. The Kerberos debug settings allowed us to see that the ticket setup was working, plus kinit confirmed things too. But the test servlet still wasn't working.

So what went wrong next? For starters, our inexperience with Weblogic led to a lack of understanding of how the authentication system works. Let's take a look at that sample servlet in the first link. The weblogic.xml snippet (well, it's complete but tiny for sample purposes) looks like this:

<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN" "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">
<weblogic-web-app>
  <security-role-assignment>
    <role-name>negotiateAdminRole</role-name>
    <principal-name>negotiateAdmin</principal-name>
    <principal-name>Administrators</principal-name>
  </security-role-assignment>
</weblogic-web-app>

If you understand this part, please skip it. This is just saying that "if something in the Weblogic security layer declares that the current visitor is a 'negotiateAdmin' thing or an 'Administrators' thing, then for this servlet we will treat it is a 'negotiateAdminRole' thing". I'm dumbing it down a bit, but given our inexperience with Weblogic when we were setting things up, we didn't yet know how Weblogic would determine that the current user was a 'negotiateAdmin' or an 'Administrators' member. We had the notion of an LDAP or AD (via LDAP) lookup but nothing had yet crystallized.

Now for a snippet from the sample web.xml:

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>BasicAuthSimpleTestServlet</web-resource-name>
            <url-pattern>/*</url-pattern>
            <url-pattern>/</url-pattern>
            <http-method>POST</http-method>
            <http-method>GET</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>negotiateAdminRole</role-name>
        </auth-constraint>
        <user-data-constraint>
            <description>no description</description>
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <security-role>
        <role-name>negotiateAdminRole</role-name>
    </security-role>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>default</realm-name>
    </login-config>

Starting from the bottom and going up, check out the auth-method. BASIC is going to trigger a login prompt. We want single sign on and this page is meant to be an example of such using Kerberos. You want CLIENT-CERT here, not BASIC. CLIENT-CERT says "hey, browser, you are GOING to give me a certificate of some kind, including possibly a Kerberos ticket, or you will be denied". Quite simple. I suppose the sample was intended to give a visual cue but typically a browser would be configured to do that anyway if an 'Authorization: Negotiate' header came back from the server so again I'm not sure why this change was left in. Anyhow...

Moving up, we declare the existence of a security-role called 'negotiateAdminRole'. This makes it available for reference elsewhere, in this case in the auth-constraints tag agove it. If you take a look in the security-constraint you get the gist of what is going on; the servlet is being set up with its available access methods and is constrained to only those users with the negotiateAdminRole assigned. Now, recall the web.xml where we indicated who would be granted the negotiateAdminRole? That made some sense to us, but what was missing was the following:

The mapping of principal-name to role-name in web.xml is based on mapping whatever identity is retrieved from authentication providers to retrieved roles from various role providers via a simple string match.

Let's jump ahead a bit. Because of the NegotiateIdentityProvider in our security realm, Weblogic knew what our account name was due to the Kerberos ticket authentication taking place. So user 'jsmith' comes along and now the current user is identified as user 'jsmith'. But 'jsmith' doesn't belong to any roles and gets no principals assigned. Weblogic will take the user account and check with other providers to see if they know who 'jsmith' is and see if it has any group/role memberships.

It turns out that to make the sample servlet work, you can simply add a user to the built in Weblogic Users/Groups with the same account name as an account from the Kerberos domain, in this case 'jsmith'. Now add 'jsmith' to a Weblogic group as used in the sample servlet, e.g. 'Administrators'. That will immediately make the sample servlet start working assuming you are 'jsmith'. Moreover, it means that 'jsmith' will become an Administrator when hitting the Weblogic console so you now have single sign on working for your console.

But now the next part comes in, linking to your Active Directory implementation for LDAP lookups. Just as you added the NegotiateIdentityProvider, you can also add an ActiveDirectoryAuthentication provider as well as LDAPAuthentication. We read a number of articles suggesting that even if you are targeting Active Directory, you may still want to use LDAPAuthenticator to work around some problems. We in fact tried LDAP first but ended up getting ActiveDirectoryAuthenticator to work for us. The trick boils down to what you use for the Principal name and the various filters. You need an account you can log in with, preferably a service account of some kind. Some suggested you could log in with the Principal set to just the account name. We ended up having to use the full distinguished name. As for your filters, you'll have to consult with your AD admin, or be capable of examining your LDAP structure to draw your own conclusions. Keep in mind that if you don't fill in the fields for the 'All Users' and 'All Groups' filters, then the Users/Groups tabs will not be auto populated with the users/groups from AD.

Once you have this hooked up, you can start referencing groups that your Active Directory users are members of for security purposes. None of the actual steps in the process are necessarily difficult. What made this difficult for us was more to do with lack of complete and cogent documentation. This post isn't sufficient on its own to get you where you need to be, but hopefully will help clarify some of what you will read on other pages. Good luck!

Filed under: development No Comments