Covering J2EE Security and WebLogic Topics

Implicit Groups in WebLogic

WebLogic has some special groups which you would only learn about if you read the documentation. I know, that’s a good one! But seriously, there is a special group for authenticated users and one for all users which I’ll get to in a moment.

Default Groups

Per the documentation, BEA supplies several default groups. The four you probably know about are:

  • Administrators
  • Deployers
  • Operators
  • Monitors

You know about these default groups because they appear automatically in the list of groups within the security realm. Each of these groups is associated with an authentication provider and you can delete them if you wish (assuming you’re aware of the consequences). Furthermore, the documentation states that "users" and "everyone" are also default groups. However, I prefer to call these "Implicit Groups."

Implicit Groups

The implicit groups "users" and "everyone" are not associated with any security provider. Rather, you can think of them as virtual groups spanning all authentication providers. Membership in these implicit groups is dynamically handled by the server.

So, what are these implicit groups?

The "users" Implicit Group

Simply stated, any authenticated user is a member of this group. If an authenticated user otherwise has no group memberships (such as Administrators, StockTrader, etc.), he’ll still be a member of this group.

The "everyone" Implicit Group

All users are members of the "everyone" group whether they are authenticated or not. As such, an authenticated user will be in both the "everyone" and "users" groups. The "everyone" group seems a little silly to me because I can’t think of a good use for it but maybe I’m missing something.

In fact, I know I’m missing something because there is a default global role called "Anonymous." This global role maps to the "everyone" group. However, since the "everyone" group contains anonymous (i.e., unauthenticated) and authenticated users, an authenticated user would have the Anonymous role. Isn’t that like matter and anti-matter colliding?

Using Implicit Groups

What can you do with these puppies?

It’s important to realize that implicit groups are legitimate albeit hidden groups so you can use them for security constraints like any other group. In other words, you can map a role used by a security constraint to the "users" group. You can also query the mapped role with HttpServletRequest.isUserInRole() to see if the user has the role that maps to an implicit group. (NOTE: Don’t let WebLogic 8.1’s default mapping of roles to group names bite you when you move to WebLogic 9.x. See WebLogic 9.1 Authorization Gotcha for more information.)

For example, you might have a scenario where you want your initial web page to be accessible to any user who can authenticate. The user can then determine if they need access to the application and can click a link to request access. Other links deeper into the application would probably have security constraints with application-specific roles like StockTrader which our unprivileged yet authenticated user would not be able to access or even see.

Auditing and Implicit Groups

With the Default Auditor, authorization events include the groups to which the user belongs. But the implicit groups are so implicit that they aren’t listed! It actually makes sense after a moment’s thought — Authorization happens after authentication and an authenticated user is ALWAYS in the "users" and "everyone" groups by definition. As for anonymous users, they haven’t authenticated so there are no audit entries, anyway.

Parting Questions

Can you think of any other uses for implicit groups? Can you enlighten me on the usefulness of the "everyone" group? I look forward to hearing your ideas.

How to Protect Against CSRF Attacks

In Unconventional Warfare, I took a somewhat whimsical approach to describing the challenges of application security today. While the analogy was fun, the message was quite serious. The take-away was that we as developers need to know more about the latest techniques used to subvert our applications.

With this post, I’m going to show you a simple but eye-opening CSRF exploit against WebLogic console. We’ll add a user to your WebLogic security realm without any outward indication that it happened.

Before we go on, it’s important to know what CSRF is. CSRF stands for Cross-Site Request Forgery. Essentially, a malicious website takes advantage of another website’s trust in the user.

I’m just learning about vulnerabilities like CSRF but it occurred to me that administrators would be likely targets for such attacks. Could I compromise my WebLogic server? Turns out I could, and it took about five minutes for me to figure out how to add a user with CSRF. The significance of this paragraph is that someone who has a cursory knowledge of CSRF can cause considerable damage.

As I researched CSRF for this post, I learned that administrators have always been targeted. Also, there are many different ways to pull off the attack and it might be a multi-step process with Cross-Site Scripting (XSS) thrown in for good measure. It’s my intention that my simple demonstration of CSRF will stoke your interest in the subject enough to start defending against these attacks. I’ll supply some techniques for avoiding CSRF vulnerabilities in your applications as well as how to protect your WebLogic console.

OK, time for the demo. You’ll need the following things if you want to try this for yourself:

  • A WebLogic 8.1 domain running on your local machine (I tested against 8.1.4)
  • Your domain has to have the default realm name (myrealm)
  • Your domain has to have the default authenticator named DefaultAuthenticator
  • Your server needs to run on port 80 or 7001

That’s it. You can just take the defaults when you configure the domain and everything will be as required.

With the pre-requisites in place, let’s add the user. Perform these steps:

  1. Fire up WebLogic
  2. Sign into the console
  3. In the same browser session as your console, navigate to my CSRF demo page

See the helpful web page? Now, go back to the console and examine your users. Did you add the user named SpongebobWasHere? I didn’t think so…

The user SpongebobWasHere was added by a CSRF exploit

Perhaps you are wary of going to my demo attack page. I don’t blame you. Security researcher sites don’t display “Best viewed with telnet to port 80” simply for the humor of it. Assuming you don’t want to telnet you have two other choices for seeing the user get added:

  1. Save the link to your machine, examine the contents, and then load that downloaded page in your browser when you’re satisfied that it’s safe
  2. Go to the URL below by copying and pasting it into your browser (I had to add spaces to get the long text to wrap so you’ll have to remove them)

http://localhost:7001/console/actions/security/DoCreateUserAction? cancelAction=%2Factions%2Fsecurity%2FListUsersAction%3F scopeMBean%3DSecurity%253AName%253Dmyrealm&realm= Security%3AName%3Dmyrealm&continueAction=%2Factions%2F security%2FDoEditUserAction%3FcancelAction%3D%252Factions %252Fsecurity%252FListUsersAction%253FscopeMBean%253DSecurity %25253AName%25253Dmyrealm%26realm%3DSecurity%253AName %253Dmyrealm%26provider%3DSecurity%253AName%253D myrealmDefaultAuthenticator&provider=Security%3AName%3D myrealmDefaultAuthenticator& wl_control_weblogic_management_security_User_Name= SpongebobWasHere&wl_control_weblogic_management_security_User_Password =password&dependentPassword_wl_control_weblogic_management_ security_User_Password=password

Change the port as required.

By the way, the URL above is the only “active” ingredient in the demo page. It serves as the source of an IMG tag. Essentially, the IMG tag issues a GET against the server running on localhost at the specified port. All of the parameters in the URL were gleaned from the HTML source of the console Add User page. The interesting stuff is at the end where I specifed the username and passwords.

The reason this exploit works is that the request to your WebLogic server came from YOUR browser. With YOUR cookies. In fact, if auditing is turned on, it looks like YOU did it.

So, there it is — a quick and easily understandable CSRF attack. I’m amazed at the ease with which this was done. Granted, I made several assumptions when crafting the URL regarding the names of things. Changing any one name would have defeated this particular attack, but a determined attacker might have employed other techniques to learn the names.

Protecting WebLogic Console from CSRF Exploits

Since WebLogic 8.1 console is vulnerable to CSRF, one solution is to change the name of the console. Another is to undeploy the console and use the scripting tools, instead. Hiding behind a firewall is not an option. Non-routable IPs are exploitable as you can see from the use of “localhost” in the URL above.

Yet another solution is to log out of the console before browsing anywhere else. This is probably a good habit for anything you need to log in to such as your bank’s web site.

What’s the likelihood that someone would do this particular exploit? Not very likely, but I believe it is possible even if your server is not on localhost. For example, an attacker might check your browser history and notice you’ve been to http://192.168.1.143/console. Hmmm…

Now, I don’t mean to pick on WebLogic console. From what I’ve read, MANY applications are vulnerable to CSRF. BEA might have fixed the problem in 9.x because I wasn’t able to duplicate my success there. So, either they fixed it or I didn’t craft the URL correctly.

Protecting Your Applications from CSRF Exploits

How can you prevent CSRF attacks in your applications? I was hoping you would ask!

First, know that checking the referrer or doing POST instead of GET won’t save you. To have a shot at preventing a CSRF attack, consider the following techniques:

  • Set a short session timeout
  • Use a token for forms
  • Re-authenticate the user or use a CAPTCHA for each important action
  • Have no XSS vulnerabilities

For more information, check out the sources below. From this list you can see that it’s a tall order to prevent CSRF attacks. However, the various techniques add up to hopefully raise the bar high enough to require a skilled attacker. That’s probably the best you can hope for since a skilled attacker will probably get in, anyway.

Further Reading

As I said earlier, I’m just learning this stuff and know enough to whip up the simple demo you’ve seen here. I encourage you to read more about this issue because there are excellent resources out there describing it much better than I can. Here’s a starter set:

Find WebLogic MBeans with Ease

There was an old woman who lived in a shoe
She had so many MBeans she didn’t know what to do
— With apologies to Mother Goose

It’s hard to deny that MBeans are incredibly useful for accessing configuration and runtime data. But with so many MBeans in an application server, it’s also incredibly hard to find the needle in the haystack.

Whether you’re looking for an MBean type, a particular attribute, or the bean that goes along with a known value (domain name, for example), how do you quickly find it? I’ve already posted one trick I use for finding MBeans via the audit log. In this post, I’ll show you my bestest trick of all for finding WebLogic MBeans. I’d like to fancy myself as an Evil Genius(TM) but it’s actually quite obvious. Here we go…

The weblogic.Admin utility has several commands such as GET and QUERY. You can find MBeans by type, name, or name pattern which is useful if you already have an idea of what you want. The following command uses weblogic.Admin to print all MBeans and their attributes to the command console:

java weblogic.Admin -username weblogic -password weblogic -url t3://localhost:80 query -pretty -pattern *:*

Substitute your username, password, and URL and you’ll get a ton of output. Here’s a representative snippet:

MBeanName: "Security:Name=myrealmDefaultAuthenticator"
	ControlFlag: REQUIRED
	Description: WebLogic Authentication Provider
	EnableGroupMembershipLookupHierarchyCaching: false
	GroupHierarchyCacheTTL: 60
	GroupMembershipSearching: unlimited
	MaxGroupHierarchiesInCache: 100
	MaxGroupMembershipSearchLevel: 0
	MinimumPasswordLength: 8
	ProviderClassName: weblogic.security.providers. \
authentication.DefaultAuthenticationProviderImpl
	Realm: Security:Name=myrealm
	SupportedExportConstraints: users|groups
	SupportedExportFormats: DefaultAtn
	SupportedImportConstraints: 
	SupportedImportFormats: DefaultAtn
	UseRetrievedUserNameAsPrincipal: false
	Version: 1.0

By the way, if you’ve never used weblogic.Admin before, you must first run the setEnv (or setDomainEnv) script in your domain directory to set up environment variables and paths.

Now, that output is all well and good but it might not make finding things any easier. Time for a little redirection, my friend:

java weblogic.Admin -username weblogic -password weblogic -url t3://localhost:80 query -pretty -pattern *:* > MBeans.txt

This time, the output goes into the MBeans.txt file. You can use this file to do automated searches. When you search, you’ll get MBean names, attribute names, and attribute values. Wanna search with RegEx? More power to you! <evil-genius>Muuwhaahaaaahaaa!</evil-genius>

Anyway, like I said, it’s fairly obvious but very useful. Mother Goose’s old woman would be proud of how we spanked those MBeans soundly and sent them to bed.

Epilogue

weblogic.Admin was deprecated in WebLogic 9. It’s still there and works, but it’s being phased out in favor of WLST. I don’t know of a quick way to use WLST to dump MBeans to a file. However, WLST is clearly powerful enough to write a script that does it. I haven’t pursued a solution in WLST because I cheat and use the deprecated weblogic.Admin to dump MBeans to a file. Please don’t tell…

If anyone knows how to use WLST to the same effect, please post a comment and share the solution with everyone. Thanks!

Fallback Authentication in WebLogic 9.2

Ah, nothing like blogging near a crackling fire. Sort of sounds like a line from a Christmas song, doesn’t it?

Speaking of hot topics, I recently noticed that BEA added the concept of container-managed fallback authentication to WebLogic 9.2. What’s fallback authentication? Here’s an example of a use case that I’ve heard more than once:

Imagine your application uses client certificates to authenticate users. Unfortunately, sometimes reality is less than tidy and you find that some users don’t have certificates nor are they able to get them for some reason. You’d like to be able to use form-based authentication if the user doesn’t present a valid certificate. In other words, if client certificate authentication fails, you want to have a fallback method for authentication.

You can do this today with any servlet engine but you’ll have to handle security on your own. Container-managed security is out because the servlet specification does not consider fallback authentication. After all, you can only supply one auth-method in web.xml. (For the literary buffs among you, the previous line is a foreshadowing detail.)

So now back to WebLogic’s support for fallback authentication. The documentation for it is here. Essentially, you have two choices for enabling fallback authentication:

  1. Supply a comma-separated list of auth-methods in web.xml
  2. Specify the REALM auth-method in web.xml which ultimately grabs the comma-separated list from the security realm

I tried the first approach first. Just kinda made sense. Here’s the snippet from my web.xml:

<login-config>
  <auth-method>CLIENT-CERT,FORM</auth-method>
  <realm-name>ArbitraryName</realm-name>
  <form-login-config>
    <form-login-page>/login.jsp</form-login-page>
    <form-error-page>/login.jsp</form-error-page>
  </form-login-config>
</login-config>

This login-config element should allow me to implement the use case given above. However, upon deployment, WebLogic complained with the following message:

Invalid auth-method list – CLIENT-CERT,FORM as the auth-method in web.xml, which is not valid. Valid values are BASIC (default), FORM and CLIENT-CERT.

Well, I could have told it that. Wasn’t WebLogic going to do some proprietary magic to get past the deployment descriptor compliance check? Apparently not, and I don’t know of any way to turn it off. I even removed the web-app DTD DOCTYPE entry in web.xml to no avail.

I’m just tenacious (stupid?) enough to try the other approach where you specify REALM as the auth-method in web.xml. Not surprisingly, it also failed compliance checking. What is surprising is that it didn’t fail because the auth-method was the non-standard "REALM" but because it was null. Now, I knew I hadn’t set the auth-methods attribute on the RealmMBean as described in the doc, but I was doing test-driven configuration so I had to see it fail first. 😉

I suspected that WebLogic was correctly substituting the auth-methods value in the RealmMBean when it encountered the REALM auth-method in web.xml. The value just happened to be null. So, I fired up WLST, set authMethods to "CLIENT-CERT,FORM", and saved the change. After restarting WebLogic, the exact same error occurred as with the plain web.xml method. The comma-separated list was not valid. However, WebLogic did correctly substitute the value from the realm when it saw the REALM auth-method in web.xml.

Sorry to say, but there’s no happy ending here. I can only surmise that BEA’s implementation was half-baked and wasn’t supposed to make it into the docs. Perhaps the next release of WebLogic will have a working implementation. In the meantime, we’re stuck with rolling our own fallback authentication scheme. It’s also very possible that I missed a step somewhere. Please let me know if I did.

Well, the fire’s not really dying, but here I am goodbye-ing… 😉

WebLogicMBeanMaker and Maven

This article illustrates a method of integrating WebLogicMBeanMaker (WebLogic 8.1) into a Maven 2 build.

UPDATE: Joel posted a comment with a much better solution than the one presented in this post. Essentially, adding

<copy file=”${basedir}/conf/ZAuthenticator.xml” todir=”${project.build.directory}/generated-sources/main/java”/>

before the call to WebLogicMBeanMaker prevents you from having to run it twice. Thanks, Joel!

If you’ve ever created a Weblogic security provider, you’ve used the WebLogicMBeanMaker utility. It generates source code for adapting your provider definition to the requirements of the WebLogic security framework. It also compiles some of the classes and can optionally JAR the entire package.

Maven is a project management and build system from Apache. I was lured by its Siren song of dependency management, project comprehension, site building capability, and a promise of less complicated build files. Unbeknownst to me, I set out on an adventure that would make Odysseus himself proud.

Refactoring my Ant file into separate projects started out smoothly enough. Creating separate web application and utility jar projects was quite liberating and I was pleased at the relative simplicity. Then I set about to Mavenize the security provider piece. I should have
borrowed some of Odysseus’ beeswax because I ran head-first into the rocks.

There’s no WebLogicMBeanMaker plugin for Maven but Maven does sport the handy maven-antrun-plugin. This plugin allows you to run Ant snippets within Maven. So, I copied the appropriate parts of the Ant script and did a little tweaking where required. With high hopes I ran "mvn clean compile" and was rewarded with a failed build for my optimism. This was a result that would occur time and time again as I’d check the web, tweak, and try again.

At the time of this writing, the web has a miniscule amount of content on WebLogicMBeanMaker and Maven. As it turns out, most of my flailing was caused by my own stupidity, but one issue remains. I eventually got around the problem but the solution is U-G-L-Y. Regardless, I’m posting the build file snippet here in the hopes that it might help someone.

The following script uses WebLogicMBeanMaker to generate the sources. I don’t care about the class files it makes (in fact I delete them) because I want to use Maven to control compilation so that I can be specific about the compiler version. The generated source tree is added to Maven’s source tree for compilation. Finally, I don’t use WebLogicMBeanMaker to JAR the provider because I let Maven handle that as well.

Here’s the snippet:

<!-- Run WebLogicMBeanMaker to build the authentication provider --> 
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <phase>generate-sources</phase>
      <configuration>
        <tasks>

          <!-- IMPORTANT NOTE: When the WebLogicMbeanMaker is run from
               a clean state, eveything works up until a class not found
               error against ZAuthenticatorMBI even though it's there.
               No real clue about why... However, it will work if 
               WebLogicMBeanMaker is run a second time (not from a clean
               slate).
                                    
               Thus, the workaround is to run WebLogicMBeanMaker twice. 
               The first one's failonerror attribute is set to false and the 
               second is set to true to catch any errors. -->

          <echo>Building Authentication provider with WebLogicMBeanMaker...</echo>
          <echo/>
          <echo>*** IGNORE THE CLASSNOTFOUND FOR ZAuthenticatorMBI ***</echo>
          <echo/>

          <!-- Ensure that WebLogicMBeanMaker starts from a clean slate -->
          <delete dir="${project.build.directory}/generated-sources"/>

          <path id="gen.path">
            <pathelement path=
              "${project.build.directory}\generated-sources\main\java"/>
            <path refid="maven.compile.classpath"/>
          </path>

          <!-- Build the MDF (mbean definition file) for the authenticator -->
          <java classname="weblogic.management.commo.WebLogicMBeanMaker" 
                fork="true" failonerror="false">
            <jvmarg 
              line="-Dfiles=${project.build.directory}/generated-sources/main/java 
                    -DMDF=${basedir}/conf/ZAuthenticator.xml 
                    -DcreateStubs=true -Dverbose=true "/>
            <classpath>
              <path refid="gen.path"/>
            </classpath>
          </java>

          <java classname="weblogic.management.commo.WebLogicMBeanMaker" 
                fork="true" failonerror="true">
            <jvmarg 
              line="-Dfiles=${project.build.directory}/generated-sources/main/java 
                    -DMDF=${basedir}/conf/ZAuthenticator.xml 
                    -DcreateStubs=true -Dverbose=true "/>
            <classpath>
              <path refid="gen.path"/>
            </classpath>
          </java>

          <!-- Move the generated Java source files to the appropriate spot -->
          <move todir=
            "${project.build.directory}/generated-sources/main/java/com/z/provider">
            <fileset dir="${project.build.directory}/generated-sources/main/java">
              <include name="**/*.java"/>        
              <exclude name="**/*MBI.java"/>
            </fileset>
          </move>

          <!-- Delete the class files created by WebLogicMBeanMaker -->
          <delete>
            <fileset dir="${project.build.directory}/generated-sources" 
                     includes="**/*.class"/>
          </delete>

          <!-- Copy meta-data files to the target/classes directory so they 
               get jarred -->
          <copy todir="${project.build.directory}/classes">
            <fileset dir="${basedir}/conf">
              <include name="**/*.xml"/> <!-- ZAuthenticator.xml -->
              <include name="**/*.dtd"/> <!-- commo.dtd --> 
            </fileset>
            <fileset dir="${project.build.directory}/generated-sources/main/java">
              <include name="**/*.mbi"/> <!-- ZAuthenticator.mbi -->
            </fileset>
          </copy>

          <echo/>
          <echo>*** IGNORE THE CLASSNOTFOUND FOR ZAuthenticatorMBI ***</echo>
          <echo/>
          <echo>Building Authentication provider with WebLogicMBeanMaker. DONE!</echo>
        </tasks>
        
        <!-- Add the generated sources to the Maven source directory list -->
        <sourceRoot>${project.build.directory}/generated-sources/main/java</sourceRoot>
      </configuration>

      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
</plugin>

This script is very similar to the one presented in the WebLogic documentation. My ugly kludge is to run WebLogicMBeanMaker twice. Yep, the first time it fails at a certain point and the second time it works like a champ. Here’s part of the ouput when it fails:

[java] Creating the MBI file…
[java] Could not create MBI.
[java] java.lang.ClassNotFoundException: ZAuthenticatorMBI

The class is there regardless of what the error says. I’ve manipulated my classpath a million times trying to fix this silliness. I’m sure it’s probably something really stupid that I’m missing. Wouldn’t be the first time. But for now, I’ll just let it be and get on with my life. If you know the answer, please comment and let me know.

I almost forgot to mention that for me, the jury is still out on Maven. However, I’ve dusted myself off after smashing into the rocks and can now enjoy the Siren song for the time being, at least. Just add some reporting plugins and run "mvn site". That’s pretty nifty. Oh, and that dependency management piece is very nice. No beeswax required.

Troubleshooting Authentication Issues with Audit Logs

In Common Problems with Authentication Provider Configuration, I wrote some tips for troubleshooting authentication/authorization problems in WebLogic. This post is a continuation of that one and shows how to decipher an audit log for troubleshooting purposes.

Audit logs are truly a secret weapon. Sure, they allow you to do the normal audit log things like going back in time to see who did what and when, but that stuff is for your security guy. As a developer, audit logs shine for other reasons such as these uses that I wrote about previously:

While Common Problems with Authentication Provider Configuration discussed the relationship between authentication and authorization, this post will highlight each as a discrete step and make it clear as to why a user can’t access a resource.

Laying the Groundwork

We’re going to look at three authentication/authorization scenarios to compare the audit log output:

  • Successful Authentication and Authorization
  • Authentication Failure
  • Authorization Failure

You can run through the scenarios on your own WebLogic domain if you’d like. For this demonstration I started with a new domain and added a “Managers” group which will simply be an extraneous group that you’ll see in the output. I then added a user named “squidward” and added him to the the Administrators and Managers groups. I also added user “spongebob” but only included him in the Managers group.

We now have two users in the Managers group. Squidward is in the Administrators group and will be able to access the WebLogic Admin Console application. Spongebob is not an administrator and will not have access.

Finally, I created a new DefaultAuditor (see WebLogic Auditing for how to do this) and restarted WebLogic.

Now let’s try it out…

Successful Authentication and Authorization

I pulled up the Admin console and logged in as Squidward. Here’s the audit log output:

#### Audit Record Begin <Sep 16, 2006 10:24:23 AM> <Severity =SUCCESS> <<<Event Type = Authentication Audit Event><squidward><AUTHENTICATE>>> Audit Record End ####

#### Audit Record Begin <Sep 16, 2006 10:24:23 AM> <Severity =SUCCESS> <<<Event Type = Authorization Audit Event ><Subject: 3
Principal = class weblogic.security.principal.WLSUserImpl(“squidward”)
Principal = class weblogic.security.principal.WLSGroupImpl(“Administrators”)
Principal = class weblogic.security.principal.WLSGroupImpl(“Managers”)
><ONCE><<url>><type=<url>, application=console, contextPath=/console, uri=/, httpMethod=GET>>> Audit Record End ####

You can see that we have two events representing authentication and authorization. The Authentication event indicates that Squidward successfully established his identity. Furthermore, the Authorization event shows that he was permitted access because he’s in the Administrators group.

Note that the authorization event contains some useful extra information. First, we see that it’s Squidward who accessed the resource (/console). We also see that he is in the Administrators and Managers groups. Inclusion in the Administrators group is his ticket to the Console application, but you also now know that he happens to be in the Managers group even though the Console application does not care about that group.

We now know what the “happy path” looks like in the audit log. Now for the not-so-happy paths…

Authentication Failure

I logged Squidward out of the Console application. I then tried to log in as Squidward again but this time I supplied a wrong password. The audit log output is shown below:

#### Audit Record Begin <Sep 16, 2006 7:35:59 PM> <Severity =FAILURE> <<<Event Type = Authentication Audit Event><squidward><AUTHENTICATE>>> <FailureException =javax.security.auth.login.FailedLoginException: [Security:090304]Authentication Failed: User squidward javax.security.auth.login.FailedLoginException: [Security:090302]Authentication Failed: User squidward denied> Audit Record End ####

Note that this time there is only a failed authentication event. WebLogic did not attempt authorization because it could not establish the user’s identity. Naturally, you can only check a user’s permissions if you know who the user is.

In this example, I provided a correct username but an incorrect password. I could have gotten the exact same output if I had provided a username/password for a non-existent user. In each case, no identity could be established.

Authorization Failure

For this scenario, I logged in as Spongebob with the correct password. The resulting audit events are shown below:

#### Audit Record Begin <Sep 16, 2006 7:39:40 PM> <Severity =SUCCESS> <<<Event Type = Authentication Audit Event><spongebob><AUTHENTICATE>>> Audit Record End ####

#### Audit Record Begin <Sep 16, 2006 7:39:40 PM> <Severity =FAILURE> <<<Event Type = Authorization Audit Event ><Subject: 2
Principal = class weblogic.security.principal.WLSUserImpl(“spongebob”)
Principal = class weblogic.security.principal.WLSGroupImpl(“Managers”)
><ONCE><<url>><type=<url>, application=console, contextPath=/console, uri=/, httpMethod=GET>>> Audit Record End ####

The output here is very similar to the successful first scenario. Spongebob authenticated just fine but was not authorized to access the Console application. The reason is evident in the event itself — Spongebob is not a member of the Administrators group.

Conclusion

You can see that the audit log can help you track down access problems. Was it a bad username/password combination or simply an authorization error? Output from your application (or Console as used here) doesn’t help you make the determination. In fact, the two very different failure scenarios showed the exact same error message on the Console login page. Audit logs show the real reason.

The other nice thing about authorization events is that the output shows the groups for which the user is a member. That sometimes comes in handy.

If the tips here weren’t sufficient to solve your problem, your last resort is security debugging. By enabling security debugging you can get copious amounts of output from the security providers to see exactly what is going on. Here are some links to get you going:

Happy auditing!

Common Problems with Authentication Provider Configuration

I haunt the BEA security forum and often see people struggling with common authenticator configuration issues. One of two things usually happens:

  • The server won’t boot
  • A user can’t authenticate or authorize

I’ll show you how to fix these problems after a brief explanation of what authenticators do. This will give you context for understanding the solutions and handling future troubleshooting sessions.

What Authenticators Do

Authenticators are responsible for authenticating users as part of the WebLogic security framework. I know you want to throw your monitor at me for making such an obvious statement. Even my cat smacked me when I wrote it. However, what’s not so obvious is that authenticators have a supporting role in the authorization process.

Authenticators deal with principals. In WebLogic, principals are users and groups. Thus, an authenticator can tell the security framework that a user successfully authenticated or not but it can also say to which groups a user belongs. It does this by creating a Subject object and populating it with the username and group names for which the user is a member. This information is used by the role mapping providers which in turn feed the authorization providers. The authorization providers make a decision based on the security policy of the requested resource and the information provided by the other security providers. This is how an authenticator can cause authorization problems. We’ll see more on that in a bit.

Out of the box, users are stored in WebLogic’s embedded LDAP. This means all “normal” users as well as the WebLogic administrative user typically named “weblogic” or “admin” are stored there. Additionally, groups are also stored in embedded LDAP. Users and groups are stored there because the embedded LDAP serves as the DefaultAuthenticator’s data store. Remove the DefaultAuthenticator and the users and groups in embedded LDAP will not be used. Or, you could add another authenticator which would have its own user/group storage. Now, the users and groups known to WebLogic encompass both data stores.

There’s one more critical piece about authenticators and that’s the Control Flag. Each authenticator has a Control Flag that can be set to REQUIRED, REQUISITE, SUFFICIENT, or OPTIONAL. Each flag indicates how the authenticator will be treated by the security framework and whether or not that authenticator has to be able to successfully authenticate the user or not. You can find an explanation of these flags here.

With the authenticator explanations out of the way, let’s move on to the problems and their solutions.

Getting the Server to Start

Starting WebLogic requires authorization. The boot identity (the main WebLogic administrative user) is used to do it. Just like any other protected resource, authentication and authorization is delegated to the security framework. With the normal security configuration, the DefaultAuthenticator will find the boot user, authenticate it, populate the Subject with the groups, and start-up will continue assuming the authorizers are pleased.

You must have at least one authenticator in a security realm. One of those authenticators must be able to find and authenticate the boot user. If not, the server won’t start and you’ll get the following error message:

Authentication denied: Boot identity not valid

When this happens, check the following:

  1. That the boot identity (normally “weblogic”) is stored in a data store managed by an active authenticator
  2. That the boot identity is in the “Admin” group
  3. Authenticator order matters — check the control flags of all active authenticators. Forgetting to change the DefaultAuthenticator to OPTIONAL or SUFFICIENT in multiple authenticator configurations is the leading cause of authentication issues
  4. That boot.properties contains the correct username/password (or you’re typing in the correct username/password when you’re not using boot.properties)

Essentially, getting the server to start requires that a user be authenticated and authorized. This sounds an awful lot like…

Authenticating Users for an Application

That’s right. The same principles apply to “normal” authentication and authorization in J2EE applications. A common problem is trying to login to a web application only to get the login page again. As mentioned above, you don’t really know if the failure to access the page is from an incorrect username/password or the simple fact that the user (while properly authenticated) is not authorized for access.

Check the following when you can’t log in to your application:

  1. That the user is located in a data store managed by an active authenticator
  2. That the role mentioned in the security constraint in web.xml maps to a principal (usually a group) in weblogic.xml (For WebLogic 9.x, you can read WebLogic 9.1 Authorization Gotcha for a painful lesson I learned)
  3. Authenticator order matters — check the control flags of all active authenticators. Forgetting to change the DefaultAuthenticator to OPTIONAL or SUFFICIENT in multiple authenticator configurations is the leading cause of authentication issues.

This checklist is essentially the same as the first list because the two problem areas are actually the same type of problem. Starting the server is just a special case due to the mechanics of specifying the boot identity (such as via boot.properties).

The tips given above should have you well on your way to solving your authentication/authorization problems.

Identity Assertion

If your user authenticates with a perimeter token such as a client certificate, most of the tips above still apply. The difference is that 1) there’s an identity asserter provider for the token type in question; and 2) that token has to be mapped to an existing user in the realm.

The first difference is fairly obvious. It’s the second one that can cause some problems. Regardless of the token type, somehow its contents must map to a user known to WebLogic. For example, if you configure an identity asserter to handle X.509 certificates, you might indicate that the user name is the email address within the certificate. In that case, your user data store must contain that email address just like the data store must contain the username and password for username/password authentication. By the same token (yes, the pun was definitely intended), the user must be in the appropriate group for authorization purposes, just like in all of the scenarios above.

For more information on X.509 identity assertion, see Mutual Authentication in Action.

Multiple Security Realms

Up until now, I never mentioned a domain with multiple security realms. The reason I didn’t mention it is that there can only be one realm active at a time. Inactive ones are not used at all. Referencing an inactive realm in web.xml has no effect. In fact, the realm name in web.xml is totally arbitrary and regardless of what you specify, the active realm will be used. See WebLogic Security Framework Overview for more information.

Even so, WebLogic’s functionality in this regard can cause you grief if you configured an authenticator in an inactive realm. The fix, of course, is to either make your new realm the active one or add the extra authenticator to the active realm.

Summary

This post described the authentication and authorization process. When troubleshooting authentication and authorization problems, consider the following:

  • Is the username and password correct?
  • Is the security constraint mapped to the role you think it is?
  • Is the role mapped to the proper group?
  • Is the user actually in that group?
  • Is an authenticator properly configured to point to the data store containing the user and group?
  • For multiple authenticators, are the control flags and authenticator order appropriate?
  • If you have multiple security realms, realize that only one is active at a time

In my next post, I’ll show you some troubleshooting techniques that quickly make the cause of the problem jump up and bite you on the nose.

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:

  1. Apply a security constraint to a resource in web.xml
  2. Set the authentication method to CLIENT-CERT in web.xml
  3. 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.

Using Audit Logs to Make Scripting Easier

Scripting configuration settings in WebLogic is fairly straight-forward. You’d typically use the WebLogic Scripting Tool (WLST) or weblogic.Admin* to create and delete MBeans in the server. You can also set properties and invoke MBean methods. While the tools are easy to use, finding the MBeans and the properties you want to use can be time-consuming.

Here’s a little trick I discovered that makes the process a little easier. In WebLogic Auditing, I show how you can use auditing to track configuration changes in the server. That can be very handy. What I realized later was that this logging could be leveraged for MBean discovery. How? With Configuration by Example (CBE).

CBE is admittedly a lame attempt at humor, but it does seem to be an apt description. The reason is that CBE works by manually making the change in WebLogic console for what you want to script and then observing how it did it.

For example, let’s say you want to set the server to production mode in a script. It’s easy enough to do in the console but you might not know where to start looking for the MBean and applicable property. With configuration auditing enabled, simply make the change in the console and observe the entry in the audit log. Here’s an example of what it looks like in the log:

#### Audit Record Begin <Jul 20, 2006 10:01:03 PM> <Severity =SUCCESS> <<<Event Type = SetAttribute Configuration Audit Event><Subject = Subject: 3
Principal = class weblogic.security.principal.WLSUserImpl(“weblogic”)
Principal = class weblogic.security.principal.WLSGroupImpl(“Administrators”)
><Object = AppSec:Name=AppSec,Type=Domain><Attribute = ProductionModeEnabled><From = false><To = true>>> Audit Record End ####

From this entry, you can see that the MBean name is AppSec:Name=AppSec,Type=Domain and the property to set is ProductionModeEnabled. Scripting this change is now a breeze since you have the MBean’s name, property, and value to set it to.

Extra Tips

  • Set the auditing severity to SUCCESS to eliminate a lot of chaff
  • In Unix, tail the audit log for streamlined access
  • Use the Help (question mark) link on the console page for MBean types and property value ranges (not all pages have this data)
  • If you want to refer to the JavaDocs for the MBean, simply add "MBean" to the Type. In the example above, the MBean would be DomainMBean.

* The weblogic.Admin approach is deprecated in WebLogic 9.

Security Debugging in WebLogic 9

The technique for getting debug information from the WebLogic security framework changed in WebLogic 9.x. In fact, BEA has made setting debug flags easier across the entire server.

In the console, navigate to

Servers -> AdminServer -> Debug

and note all of the goodies for which you can get debug information.

Getting back to the security framework, continue navigating to

weblogic -> security

and enable debugging for your areas of interest. Debug output is immediate after you activate the changes.

Thanks to Marky Middleton on the BEA forums for the tip!

Read Security Realm Logging in WebLogic 8.1 if you want debug output from an 8.1 server.

« Previous Entries   Next Entries »

Bookmark this page on del.icio.us