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:

Unconventional Warfare

Let’s get medieval.

Imagine a castle, stout and impenetrable even on this ordinary day. Guards mill about with glistening swords at their sides, anxious to try them out. Bored look-outs peer over the parapets, ever watchful for the approach of a mighty army. Prima donna archers play Uno in the towers.

Meanwhile, real life happens. Peasants and traders enter and exit the castle as part of their daily activities. The scent of steak-on-a-stake and cotton candy fills the air. All is well at our imaginary castle.

Or is it?

While the castle is certainly ready for a conventional enemy that would storm the gates and attempt to smash the walls, it was totally unprepared for what happened that fine day.

The crown jewels were stolen.

The lord of the castle is perplexed. After all, the defenses were ready — every man was at his post and ready to engage in mortal combat with enemy knights. Everyone was on the look-out. And still, the jewels are gone.

This castle scenario is what computer security seems like to me these days. We have DMZs and firewalls, intrusion detection, intrusion prevention, encryption, application resources protected by roles, and if we’re lucky, maybe even strong passwords. But more and more I’m coming to the realization that while we need those things, we as developers really need to bring out our inner guerilla. We have a handle on the conventional warfare but we almost never think like a hacker. They’re going to dress like a peasant and mimic the ways of a peasant. They’re going to be the peasant.

They’re also going to rob you blind.

The problem is, thinking like a hacker is not in our nature. Unfortunately, that needs to change. Because quite simply, unlike the crown jewels that physically disappeared, our electronic crown jewels can be stolen and yet simultaneously remain in our possession. It’s the nature of the ones and zeros.

We even need to be security conscious during non-coding activities such as writing uses cases. The reason is that even seemingly innocuous business functions can provide a covert pathway to the crown jewels.

Consider this blog post. Be sure to read the case study.

Scared?

Did you notice that conventional security techniques wouldn’t have prevented it?

This realization I had — that we need to think more like hackers to protect ourselves — did not just hit me out of the blue. I’m far too dense for that and wouldn’t have felt it. Instead, it comes from reading the blogs of the white hat hackers. In my case, Jeremiah Grossman and RSnake are the ones that scare me on a daily basis. In fact, the blog post above is the work of RSnake. It’s these guys that repeatedly hit me upside the head to make me see things in a different light. And when they hit me, I definitely feel it.

Today, more and more developers are aware of the perils of SQL injection. That doesn’t mean there’s not a lot of vulnerabilities out there but developer awareness of this particular attack is rising. That’s good. Now we need to learn more about XSS and CSRF and do what we can to avoid them. It’s all too easy to read about these attacks and yet not fully comprehend the danger because the descriptions are often too abstract. But folks like Jeremiah and RSnake make us smarter by showing us exactly what the ramifications are in all of the gory detail.

As developers, we need to be familiar with what these guys are writing about. Black hat hackers probably already know this stuff. So should we.

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!

Serious Adobe Reader (PDF) Vulnerability

There is a very serious Cross-Site Scripting (XSS) vulnerability in Windows versions of Adobe Reader less than 8.x.

If you have a website that hosts PDF files, your website is vulnerable to session hijacking since a user can have his JSESSIONID cookie stolen. There’s little you can do about it server-side since it’s a browser/plugin problem. Server-side, you can either not host PDF files or (possibly) change your MIME type to something unknown.

Users themselves can have a host of bad things happen to them with this exploit. See MSNBC for more details in general terms. For technical details, start with Jeremiah Grossman’s write-up.

The solution is to upgrade to Adobe Reader 8. Adobe says that they will have patches for older versions if people can’t upgrade for some reason. You could also turn off JavaScript or tell your browser to open Acrobat outside of the browser, but getting the new plugin is more fool-proof.

Seriously, don’t go another day without upgrading. This exploit is going to be huge… :-(

Reflections 2006

It’s hard to believe that it’s been a year since I started this blog. From its inception, my intention was to give a little something back to the massive Internet community from which I’ve acquired a wealth of information on subjects ranging from professional to personal. I also knew that I’d get a deeper knowledge of the technical subject matter by simply writing about it.

Blogging also allows me to scratch my writing itch. During the first month or so, I wrote several posts a week. Over time, that was simply not a pace I could maintain. I’m down to one or two posts a month now primarily because each post takes several hours since I usually prototype what I’m discussing and try to be very thorough.

I also thought that Google AdSense income would cover my hosting costs. Let’s just say that part hasn’t panned out. 😉 If you plan on starting a technical blog and want AdSense income, pick a subject that has broad appeal. Also keep in mind that technical websites tend to attract corporate workers who are behind ad-blocking software such as WebSense so many of your viewers won’t even see the ads. Fortunately, hosting is cheap these days.

Top 10 Posts for 2006

In case you missed them, here are my top 10 most popular posts:

  1. WebLogic Embedded LDAP
  2. The Fifteen Minute Guide to Mutual Authentication
  3. Common Problems with Authentication Provider Configuration
  4. The Mysterious CLIENT-CERT
  5. WebLogic Security Framework Overview
  6. Authentication Methods in Web Applications
  7. WebLogic 9.1 Authorization Gotcha
  8. WebLogic Auditing
  9. Security Realm Logging in WebLogic 8.1
  10. Mutual Authentication in Action

Yes, I’m also surprised that a post on WebLogic’s embedded LDAP takes the top slot. While most of its traffic is subject-specific, it also gets a lot of hits for a Firefox error message that I included in the text. Hmm, I wonder if “Britney Spears” is still the top ranking search phrase. I’ll have to start sprinkling such terms around! 😉

Another thing to note from this list is that all of the posts are WebLogic-related. I had intended to cover generic J2EE security but the reality is that there’s only so much J2EE security you can cover before getting into specific implementations of it. With this in mind, I hope to expand somewhat into the security aspects of WebSphere and JBoss in 2007. Hopefully, I’ll be able to provide meaningful content related to these servers while expanding my horizons at the same time.

Thanks for reading and please consider using the RSS feed or the email list for getting the latest posts. This isn’t a high volume blog so getting the posts sent to you sure beats checking the website for them.

Have a great new year!

Encrypting Only the Login Page

I occasionally hear people say that they don’t want to use SSL for anything other than the login page for fear of the performance hit that SSL adds. Most recently, I came upon this post which claims to show how to implement such functionality in a J2EE web application.

While the above post seems to have some technical inaccuracies, I’m not writing to criticize it. Rather, I think it’s interesting to consider the ramifications of only encrypting the login page. The issues fall into three categories:

  • Performance
  • Maintainability
  • Security Impacts

Let’s have a look at each category in turn.

Performance

Performance is the crux of the reason to only encrypt the username and password. Developers hear that SSL adds a 30% overhead to response times, freak out, and then don’t want to use SSL or to only use it sparingly as this use case indicates. But really, the biggest hit of SSL is the initial setup of the socket. Once that is done, a big chunk of the SSL performance burden is gone. Since the socket is usually maintained until a timeout happens, multiple requests can leverage that same one-time setup cost.

Another thing to realize about SSL performance is that you don’t pay the overhead for your total response time. For example, assume that you have a dynamic page that takes 1 second to complete. Let’s further assume that 25% of that time is socket-level and 75% is making the database call and rendering the page. Clearly, I’m just fudging these numbers but you’re not going to see a 30% increase in the 650ms database access time, for example. By the same token, the more data you present (including images!) the more encryption has to be done which will take time.

Finally, a hardware SSL accelerator will go a long way toward reducing the SSL overhead. I don’t have any numbers for this but encryption in hardware will beat encryption in software any day.

Maintainability

While it doesn’t seem like this should be the case, encrypting only the login page introduces a software maintainability issue. Specifying that the login page should have a transport-guarantee of CONFIDENTIAL in web.xml will do the trick of ensuring that SSL is used for the login. No custom coding is required.

However, once the browser has switched to the SSL port, how do you declaratively tell it to go back to the clear (non-SSL) port after login? The answer is you can’t. Even though other resources defined in web.xml may not have the CONFIDENTIAL guarantee, the server will not automatically switch back to the clear port.

I can only think of two ways to switch back to the clear port — a servlet filter or links.

By using a servlet filter you could examine the request and then redirect to the clear port for anything other than the login page if the request was made over SSL. Do-able but not pretty.

The other way is to have all of your links specifically refer to the clear port with something like http://whatever/somepage.jsp. Clicking such a link will cause the request to be serviced without SSL but now you have hard-coded links all over the place. You could also build your link dynamically but then you’d have that code to maintain.

So far, we’ve talked about performance and maintainability. Now it’s time to consider the security aspects…

Security

In this section you’ll see what that 30% SSL premium buys you.

It makes sense that you’d want to protect the user’s password and perhaps even the username itself. You wouldn’t want anyone sniffing the wire and finding those goodies. But by not encrypting the link post-login, all data sent or received from that user can be sniffed. You require authorization for the user to see the data but allow anyone with a packet sniffer to see social security numbers, medical conditions, or whatever sensitive data your application handles. Shouldn’t that be kept safe, too?

Perhaps you think you’re safe because you’re not going out over the internet. That is a good thing, of course, but the majority (80% is what sticks in my head) of attacks are from insiders. Kinda risky.

You’ve now seen that sensitive data can be sniffed from the link. Here’s where it gets really interesting…

You’ve encrypted the username and password during login so that no bad guys can login as that user in the future. But since subsequent traffic is unencrypted you’ve just given away the keys to the kingdom. How’s that? Session hijacking.

Now that traffic is unencrypted, someone sniffing the network can see session IDs either as a request parameter or in a cookie. Given this information and an active session on the server, the malicious use can become the previously authenticated user and access the application as if he were the legitimate user. Scary stuff…

Summary

I think you can tell by now what side of the fence I fall on. I think the security issues alone call for SSL during and after login. That 30% premium allows me to sleep at night.

Did I forget or overemphasize anything? Please post your thoughts below.

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.

Verisign’s New Intermediate CA and You

Starting in August, 2006, Verisign introduced a new intermediate Certificate Authority (CA) into its certificate hierarchy. As a result, Verisign server certificates are signed by this CA instead of being signed by the Verisign root as before. This article will guide you through the process of using keytool to install a certificate signed by this new CA certificate.

Why is this scenario different than before or with other CAs? The reason is that since the CA certificate is new, it hasn’t had time to fully propagate into the various places it needs to be, such as the cacerts trust store that comes with Java. (The new CA certificate is not in cacerts as of JDK 1.5.0_04 but it might be there in a later release.) Without the CA certificate in cacerts, you won’t be able to use keytool to import a certificate signed by the new CA.

For the purposes of this article, I’ll assume you have a JKS keystore with your private key and that you’ve submitted a Certificate Signing Request (CSR) to Verisign. Verisign signs your certificate with the new CA and sends you a cert.cer file containing your signed certificate.

Here’s what you need to do:

  1. Obtain the new intermediate CA certificate
  2. Import the intermediate CA certificate into cacerts using keytool
  3. Import your signed certificate into your keystore using keytool

Obtain the Intermediate CA Certificate

You can get the new CA certificate from here. Save the certificate contents to a file (the example below uses “NewVerisignIntermediateCA.cer”).

Before moving on, spend a few moments playing a game of Boggle with the certificate contents. 😉

Import the CA Certificate into cacerts

The keytool utility can be found in the <JAVA_HOME>\bin directory. The cacerts file it uses can be found in <JAVA_HOME>jre\lib\security. We’ll load the new CA certificate into cacerts:

keytool -import -keystore <JAVA_HOME>jre\lib\security\cacerts -file NewVerisignIntermediateCA.cer

The default cacerts password is “changeit”.

Import the Signed Certificate into the Keystore

We’ll use keytool again to load the signed certificate over the same alias as your key entry. (By the way, this is a good time to make a backup of your keystore!)

But first, a word about what Verisign sent you. The email will contain the certificate contents as part of the email text. There will also be an attachment of the same contents called cert.cer. Regardless of which one you use, ensure that there are no spaces or blank lines at the end of the file. The attached cert.cer likely has two blank lines. Remove those and ensure that there are no spaces at the end of the file.

Load the signed certificate:

keytool -import -keystore <keystore> -alias <alias> -file cert.cer -trustcacerts

where keystore is the name of your JKS file and alias is the alias of your key entry.

What you want to see from this command is

Certificate reply was installed in keystore

If you didn’t get this message, perhaps you got this beauty instead:

java.io.IOException: DerInputStream.getLength(): lengthTag=127, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:530)
at sun.security.util.DerValue.init(DerValue.java:346)
at sun.security.util.DerValue.<init>(DerValue.java:302)
at sun.security.provider.X509Factory.parseX509orPKCS7Cert(X509Factory.ja
va:522)
at sun.security.provider.X509Factory.engineGenerateCertificates(X509Fact
ory.java:407)
at java.security.cert.CertificateFactory.generateCertificates(Certificat
eFactory.java:511)
at sun.security.tools.KeyTool.installReply(KeyTool.java:1193)
at sun.security.tools.KeyTool.doCommands(KeyTool.java:504)
at sun.security.tools.KeyTool.run(KeyTool.java:124)
at sun.security.tools.KeyTool.main(KeyTool.java:118)
keytool error: java.security.cert.CertificateException: DerInputStream.getLength
(): lengthTag=127, too big.

If so, you played too much Boggle. Remove any blank lines and spaces from the end of your signed certificate file and try again.

Another indication of an unsuccessful load is this output:

keytool error: java.lang.Exception: Failed to establish chain from reply

If you get this message, keytool can’t find the new Verisign intermediate CA. Double-check the instructions above but skip the Boggle part or you’ll be messed up for the rest of the day.

Assuming you successfully imported your signed certificate, have a look at your handiwork with

keytool -list -keystore <keystore> -v

You should see something similar to the following:

Keystore type: jks
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: server
Creation date: Oct 3, 2006
Entry type: keyEntry
Certificate chain length: 3
Certificate[1]:
Owner: CN=monduke.com, OU=Terms of use at www.verisign.com/rpa (c)05, OU
=Department of Blogging Department, O=Bastion Blog, L=Pasadena, ST=Maryland
, C=US
Issuer: CN=VeriSign Class 3 Secure Server CA, OU=Terms of use at https://www.ver
isign.com/rpa (c)05, OU=VeriSign Trust Network, O=”VeriSign, Inc.”, C=US
Serial number: 4a3b4682eab7b25b13dac435aefb3c5a
Valid from: Thu Sep 28 20:00:00 EDT 2006 until: Fri Oct 24 19:59:59 EDT 2008
Certificate fingerprints:
MD5: 9A:1E:CC:92:44:AF:CD:C0:57:67:63:3D:C0:F7:17:13
SHA1: 3D:79:41:BE:DB:DA:7B:5C:B6:F8:78:D8:60:4E:F8:80:33:E1:08:92
Certificate[2]:
Owner: CN=VeriSign Class 3 Secure Server CA, OU=Terms of use at https://www.veri
sign.com/rpa (c)05, OU=VeriSign Trust Network, O=”VeriSign, Inc.”, C=US
Issuer: OU=Class 3 Public Primary Certification Authority, O=”VeriSign, Inc.”, C
=US
Serial number: 75337d9ab0e1233bae2d7de4469162d4
Valid from: Tue Jan 18 19:00:00 EST 2005 until: Sun Jan 18 18:59:59 EST 2015
Certificate fingerprints:
MD5: 2A:C8:48:C0:85:F3:27:DE:32:29:44:BB:B0:2C:79:F8
SHA1: 18:85:90:E9:48:78:47:8E:33:B6:19:4E:59:FB:BB:28:FF:08:88:D5
Certificate[3]:
Owner: OU=Class 3 Public Primary Certification Authority, O=”VeriSign, Inc.”, C=
US
Issuer: OU=Class 3 Public Primary Certification Authority, O=”VeriSign, Inc.”, C
=US
Serial number: e49efdf33ae80ecfa5113e19a4240232
Valid from: Sun Jan 28 19:00:00 EST 1996 until: Wed Jan 07 18:59:59 EST 2004
Certificate fingerprints:
MD5: 78:2A:02:DF:DB:2E:14:D5:A7:5F:0A:DF:B6:8E:9C:5D
SHA1: 4F:65:56:63:36:DB:65:98:58:1D:58:4A:59:6C:87:93:4D:5F:2A:B4

From this output you can see the issuer hierarchy where certificate 1 is your server certificate, certificate 2 is the intermediate CA, and certificate 3 is the Verisign root.

Enough work. Time for some more Certificate Boggle(TM). The great thing about it is that you can play all day and it’s boss-proof. When your boss asks why you’re staring at gibberish, you can say that you’re checking the server certificate for accuracy. He’ll admire your attention to detail and you’ll get a nice raise.

😉

« Previous Entries   Next Entries »

Bookmark this page on del.icio.us