JBoss guide: How to enable SSL (HTTPS) on JBoss, as well as other “nice-to-know” configurations

From time to time you might have the need of running a web application over https, or there can be requests of having Single-Sign-On between multiple web applications running on your server. This small jboss-guide will give you some clues on how to solve tasks like this, with configurations for both jboss-4.0.4.GA and jboss-4.2.2.GA. Since the name of the server instance might differ and it’s also possible to use custom names, I’ll refer to it as jboss/server/<NAME>/, but what I mean here is for example jboss/server/default/.

Changing the port that jboss runs on

For 4.0.4 you should locate the server.xml inside jboss/server/<NAME>/deploy/jbossweb-tomcat55.sar/, and then change the port=”8080″ parameter in the HTTP Connector to your wishes, for example port 80 as I have done it here.

 <!-- A HTTP/1.1 Connector on port 8080 -->
      <Connector port="80" address="${jboss.bind.address}"
         maxThreads="250" strategy="ms" maxHttpHeaderSize="8192"
         emptySessionPath="true"
         enableLookups="false" redirectPort="8443" acceptCount="100"
         connectionTimeout="20000" disableUploadTimeout="true"/>

For 4.2.2 you do exactly the same, but the server.xml is located inside jboss/server/<NAME>/deploy/jboss-web.deployer/ instead.

Make tomcat able to compile java5 – by default it doesn’t

If you have the need of using java5 (jdk 1.5), you need to set the source-level of the compiler. If you don’t do this and have deployed web-applications with java5 code, you will get exceptions during startup. For 4.0.4 edit the web.xml in jboss/server/<NAME>/deploy/jbossweb-tomcat55.sar/conf. Locate the jsp servlet by searching for <servlet-name>jsp</servlet-name>, and uncomment the section that enables jdk1.5 features:

  <!-- Uncomment to use jdk1.5 features in jsp pages -->
      <init-param>
         <param-name>compilerSourceVM</param-name>
         <param-value>1.5</param-value>
      </init-param>

For 4.2.2 you find the web.xml inside jboss/server/<NAME>/deploy/jbossweb-deployer/conf. Locate the same servlet, and make sure that the parameters both for source & target compiler are set like this:

   	<servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
         <param-name>compilerSourceVM</param-name>
         <param-value>1.5</param-value>
        </init-param>
  	<init-param>
         <param-name>compilerTargetVM</param-name>
         <param-value>1.5</param-value>
        </init-param>

Activate support for Single Sign-On

For both versions, locate server.xml (4.0.4 = jboss/server/<NAME>/deploy/jbossweb-tomcat55.sar/, 4.2.2 = jboss/server/<NAME>/deploy/jboss-web.deployer/). Find the “Host” section, and uncomment the following Valve:

   	 <!-- Uncomment to enable single sign-on across web apps
                deployed to this host. Does not provide SSO across a cluster.     

                If this valve is used, do not use the JBoss ClusteredSingleSignOn
                valve shown below. 

                A new configuration attribute is available beginning with
                release 4.0.4:

                cookieDomain  configures the domain to which the SSO cookie
                              will be scoped (i.e. the set of hosts to
                              which the cookie will be presented).  By default
                              the cookie is scoped to "/", meaning the host
                              that presented it.  Set cookieDomain to a
                              wider domain (e.g. "xyz.com") to allow an SSO
                              to span more than one hostname.
             -->

            <Valve className="org.apache.catalina.authenticator.SingleSignOn" />

Then in your jboss-web.xml it’s important that all the web applications that are going to “exchange” credentials points to the same security-domain:

<jboss-web>
 	<security-domain>java:/jaas/USE_THE_SAME_APPLICATION_POLICY_HERE</security-domain>
	<context-root>/YOUR_APPLICATION_ROOT</context-root>
</jboss-web>

If you now open and logon to one application, going to another one running on the same server should not prompt you for username/password again. Note that there are alternatives also if you have applications running on different servers/locations – check the other Valves.

Enable SSL on JBoss

In this example I’m only using a self-signed certificate, but the procedure would be more or less the same even if you are going to use a certificate from a Certification Authority.

  1. Generate the keystore with the following command
    keytool -genkey -alias tomcat -keyalg RSA -keystore NAME_OF_KEYSTORE -validity NUMBER_OF_DAYS
  2. Copy the file into the jboss/server/<NAME>/conf/ directory
  3. Edit the server.xml (4.0.4 = jboss/server/<NAME>/deploy/jbossweb-tomcat55.sar/, 4.2.2 = jboss/server/<NAME>/deploy/jboss-web.deployer/).For 4.0.4 the SSL-connector should be configured like:
     <!-- SSL/TLS Connector configuration using the admin devl guide keystore     -->
          <Connector port="THE_PORT_YOU_LIKE" address="${jboss.bind.address}"
               maxThreads="100" strategy="ms" maxHttpHeaderSize="8192"
               emptySessionPath="true"
               scheme="https" secure="true" clientAuth="false"
               keystoreFile="${jboss.server.home.dir}/conf/THE_KEYSTORE_NAME"
               keystorePass="PASSWORD_FOR_THE_KEYSTORE" sslProtocol = "TLS" />

    For 4.2.2, configure it like this:

     <Connector port="THE_PORT_YOU_LIKE" protocol="HTTP/1.1" SSLEnabled="true"
                   maxThreads="150" scheme="https" secure="true"
                   clientAuth="false"
    	       strategy="ms"
                   address="${jboss.bind.address}"
                   keystoreFile="${jboss.server.home.dir}/conf/THE_KEYSTORE_NAME"
                   keystorePass="PASSWORD_FOR_THE_KEYSTORE"
                   truststoreFile="${jboss.server.home.dir}/conf/THE_KEYSTORE_NAME"
                   truststorePass="PASSWORD_FOR_THE_KEYSTORE"
                   sslProtocol="TLS"/>
  4. Now you should be able to access your application through https. Remember to use https:// instead of http:// in your browser-url, or else it will fail.
  5. Remember that if you want to disable the non-secured port 8080 (or custom), making sure that people can only access through https, comment and disable that connector in the same server.xml.

Tell jboss 4.2.2 to not use the bundled JSF 1.2 implementation

By default this version of jboss comes bundled with the Glassfish JSF 1.2 implementation. If you deploy web applications that use other implementations, like myfaces, you should tell jboss to use the implementations(s) deployed together with the web applications instead. Do this by adding the following to the web.xml of your application(s):

  <context-param>
     <param-name>org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL</param-name>
     <param-value>true</param-value>
  </context-param>

Access jboss-4.2.2GA using ip address instead of localhost – use the “-b” parameter

I’ve been using the 4.0.4 version for some time, and I could start it on my machine (accessing it through localhost:8080), and access it from other machines in my network it by using the ip-address of my machine instead of localhost. With 4.2.2, you can start it the same way and it will work from your machine by going localhost. But trying to start the application remotely from other machines by using the ip-address would fail, giving you a 404.

This is because before 4.2.2.GA, jboss was always bound to the any address “0.0.0.0”. But this was considered a security issue, and this default behavior was removed. It’s now up to the user to explicitly configure this.

What you need to do to solve it is to start the jboss with another parameter, you need to set the bind address for the jboss services. The following command would start a jboss server named “myserver” on ip 192.168.100.100:

  run.bat -c myserver -b 192.168.100.100

If you now try to start the application from other machines by using this IP it works! If you use the server named default you can leave out the -c parameter. It’s also possible to revert back to the “old configuration” by using -b 0.0.0.0, but this is not recommended.Ok, I hope that this small guide might be of help to someone! 🙂

Automatic logon to a web application (JSF on jboss-4.2.2.GA) using JCIFS NTLM HTTP Authentication

The goal was to be able to make users which are logged in on a windows domain to automatically authenticate with their windows credentials when starting a web application, and also to make this solution possible both for IE and Firefox. In other words, the user doesn’t have to enter user-name/password when starting a corporate web application.

The web-app is done in JSF (myfaces 1.1.5), the application server is jboss-4.2.2.GA and the library I use to “grab” the windows user is JCIFS NTLM HTTP Authentication version 1.2.17 (http://jcifs.samba.org/). I will try to give a step-by-step explanation to what I did to make this work, and I will point out the differences you need to do compared to JAAS authentication mechanism (which is commonly used with applications running on jboss).

  1. The first ting you need to do is to download and put the jcifs library (jcifs-1.2.17.jar – or newer version) into your JBOSS_HOME/server/<NAME-OF-SERVER>/lib -folder.
  2. In your web.xml, you need to apply the following:
    <filter>
    
    	<filter-name>NtlmHttpFilter</filter-name>
    
    	<filter-class>jcifs.http.NtlmHttpFilter</filter-class>
    
    	<init-param>
    
    		<param-name>jcifs.http.domainController</param-name>
    
    		<param-value>IP ADDRESS_OF_THE_DOMAIN_CONTROLLER</param-value>
    
    	</init-param>
    
    	<init-param>
    
    		<param-name>jcifs.smb.client.domain</param-name>
    
    		<param-value>NAME_OF_DOMAIN</param-value>
    
    	</init-param>
    
    	<init-param>
    
    		<param-name>jcifs.smb.client.username</param-name>
    
    		<param-value>A_USERNAME_IN_ACTIVE_DIRECTORY</param-value>
    
    	</init-param>
    
    	<init-param>
    
    		<param-name>jcifs.smb.client.password</param-name>
    
    		<param-value>PASSWORD_FOR_THIS_USER</param-value>
    
    	</init-param>
    
    	<init-param>
    
    		<param-name>jcifs.util.loglevel</param-name>
    
    		<param-value>3</param-value>
    
    	</init-param>
    
    </filter>
    
    <filter-mapping>
    
    	<filter-name>NtlmHttpFilter</filter-name>
    
    	<url-pattern>/*</url-pattern>
    
    </filter-mapping>

    For the jcifs.http.domainController you specify the ip-address of the domainController you are authenticating against, e.g. 192.168.1.100.

    For jcifs.smb.client.domain you specify the domain that the users are logging in to. If you are uncertain about this check the logon-box in windows (XP login to domain) and write the domain name as its written here.

    In some examples on the net the jcifs.smb.client.username and jcifs.smb.client.password are not included. These are used for pre-authentication, think of it as a user that has access to the active directory so that it can retrieve information about the other users trying to log in. My experience is that if I leave out these two parameters, it works fine for the first user logging in, but for the first user only. When the second user logs in you get a 0xC0000022: jcifs.smb.SmbAuthException in the server log, and the negotiation of user-name/password fails. Including those parameters solves this issue. You could perhaps create a “dummy user” in the Active Directory just for this purpose (if you have administrator rights), if not use any other user of the AD.

    At least when trying to get this up and running I would recommend a logging-level set to 3. And of course you would set the url-pattern of the filter according to the path of the resources you want to protect, e.g. <url-pattern>/myJsps/*</url-pattern>

  3. If you are used to restricting access to your web application, you might have something like this in your web.xml:
    <security-constraint>
    
    	<web-resource-collection>
    
    		<web-resource-name>PROTECTED AREA</web-resource-name>
    
    		<description>Require users to authenticate</description>
    
    		<url-pattern>/*</url-pattern>
    
    	</web-resource-collection>
    
    	<auth-constraint>
    
    		<role-name>SOME_ROLE</role-name>
    
    	</auth-constraint>
    
    </security-constraint>
    
    <login-config>
    
    	<auth-method>BASIC</auth-method>
    
    	<realm-name>MY_NAME</realm-name>
    
    </login-config>
    
    <security-role>
    
    	<role-name>SOME_ROLE</role-name>
    
    </security-role>

    And then you would also have a security-domain set up in jboss-web.xml that points to an application-policy in login-config.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.3//EN"
    
    "http://www.jboss.org/j2ee/dtd/jboss-web_3_2.dtd">
    
    <jboss-web>
    
    	<security-domain>java:/jaas/MY_APPLICATION_POLICY</security-domain> -->
    
    	<context-root>/MY_CONTEXT_ROOT</context-root>
    
    </jboss-web>

    To be able to use the security filter with success, you would need to remove all of the settings related to security and JAAS. Remove the <security-constraint> (including children) , <login-config> and <security-role> tags from web.xml, and also delete the line specifying the <security-domain> in jboss-web.xml

  4. All the settings server-side are done now, what remains is a very simple configuration of the client/web browser. You need to tell your browser that the host/site you are trying to reach should be considered a trusted site. If you don’t do this, the browser would pop up the usual login-dialog and ask for username and password.
    • Enable it in IE:Go to tools->Internet Options->SecuritySelect Local Intranet icon and press “Sites”Press “Advanced”Fill in the url to the host of your application and press add. (Do not use the full application path or port settings, only the host address – for example: http://192.168.1.100)
    • Enable it in Firefox:Type about:config in the url-barLocate the key network.automatic-ntlm-auth.trusted-urisAdd the url to the host in the value-field. If there is other urls specified, separate them with a comma.
  5. If you now try to start your application, you should be automatically logged in with your windows user. The server log should say something like this if you have a successful authentication:
    [STDOUT] NtlmHttpFilter: THE_DOMAIN\user_name successfully authenticated
    
    against 0.0.0.0<00>/IP_OF_DOMAIN_CONTROLLER

I hope this overview can be helpful, but of course there are situations and special cases that I haven’t covered here. I would have to point you to the documentation and the FAQ on the homepage of the JCIFS library (see link in the start of this post). Still, I spent some time sorting out configurations, parameters and mistakes, so hopefully this will give others a shorter path to the goal.

Good luck!