Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
HP Open Source Middleware Stacks Blueprint: J2EE Application Server on HP ProLiant Servers with JBoss, MySQL or Oracle, and SLES10

Secure the J2EE Middleware Stack

» 

Technical documentation

Complete book in PDF
» Feedback
Content starts here

 » Table of Contents

J2EE security is a complex topic. The following three topics are described in this blueprint:

  • Data Transportation—Secure Sockets Layer (SSL) is a widely used technology to protect data transfer. SSL enablement methods for both the Apache Web Server and JBoss Enterprise Application Server Platform are covered in this section.

  • Application Authentication—Symas Connexitor Directory Services (CDS) is a directory-service solution based on OpenLDAP, Berkeley DB, Cyrus SASL and OpenSSL. It provides an integrated authentication and authorization-based security mechanism for enterprise applications managed and deployed in JBoss. The directory server can store credential information and application privileges about the users who are granted or forbidden access to specific resources. In addition to controlling user identities, OpenLDAP can control access based on other attributes such as network address, transport, encryption strength, dynamic relationships, and so on. Some applications or Web pages in specific JBoss applications, require access only by authenticated users. Symas CDS can provide this authentication mechanism by storing user credentials in the directory server. When authentication starts, the JBoss Enterprise Application Server uses the org.jboss.security.auth.spi.LdapLoginModule module to query the Symas CDS for the user's identity

  • EJB Security—J2EE specifications define a role-based security model for Enterprise Java Bean (EJB) components. The security policies and mechanisms are provided by the EJB Deployer. Business methods in EJB should not contain any security logic. When certain business methods are invoked by an EJB client, the EJB container identifies the role of the client and checks the permissions to base the invocation on the security requirements as configured in the EJB descriptor files.

Enabling HTTPS Support in Apache

The mod_ssl module provides an SSL implementation that allows Web applications running within the Apache Web Server to communicate securely with their respective clients. Communication can still occur over standard HTTP, if desired.

To enable HTTP over SSL (HTTPS), perform the following steps:

  1. Run the shell script file /usr/bin/gensslcert, to create dummy ssl keys for mod_ssl.

    This tool copies the /etc/apache2/ssl.crt/ca.crt file to /srv/www/htdocs/CA.crt and creates the following key files:

    • /etc/apache2/ssl.crt/ca.crt

    • /etc/apache2/ssl.key/server.key

    • /etc/apache2/ssl.crt/server.crt

    • /etc/apache2/ssl.csr/server.csr

  2. Edit the /etc/sysconfig/apache2 file by adding ssl to the APACHE_MODULES definition and SSL to the APACHE_SERVER_FLAGS definition.

    After completing the edits, the lines should look like the following:

    APACHE_MODULES="... ssl ..."

    APACHE_SERVER_FLAGS="SSL"

  3. Create an SSL virtual host configuration file by copying template file to perform the test:

    # cp /etc/apache2/vhosts.d/vhost-ssl.template /etc/apache2/vhosts.d/vhost-ssl.conf

  4. Restart Apache by entering the following:

    # /etc/init.d/apache2 restart

  5. Perform the test by navigating to the Web site located at:

    https://<YOUR_HOSTNAME>

Verify the certificate is displayed as in Figure 17:

Figure 17 SSL_Enabled Apache

SSL_Enabled Apache

Enabling HTTPS Support in JBoss

To enable HTTPS support in JBoss, perform the following steps on the JBoss Enterprise Application Server:

  1. Generate the encryption key for HTTPS by entering the following:

    # $JAVA_HOME/bin/keytool -genkey -keyalg RSA \

    -keystore osms.keystore -validity 3650

  2. Input a value for both the keystore and key password for mykey at the prompt. In the example, osmspass is used as the password. After the input is finished, a key file named osms.keystore is created in the current directory.

  3. Copy the keystore file to $JBOSS_HOME/server/default/conf by entering the following:

    # cp osms.keystore $JBOSS_HOME/server/default/conf

  4. Open the file $JBOSS_HOME/server/default/deploy/jboss-web.deployer/server.xml and uncomment the SSL/TLS Connector section.

    Update the keystore file location and keystore password in the server.xml file as follows:

    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
                   maxThreads="150" scheme="https" secure="true"
                    clientAuth="false"
                    keystoreFile="${jboss.server.home.dir}/conf/osms.keystore"
                    keystorePass="osmspass" sslProtocol = "TLS" />

    where:

    keystoreFile is the location of the keystore file.
    keystorePassis the same password input used in Step 2.

  5. Start the JBoss Enterprise Application Server by entering the following:

    # $JBOSS_HOME/bin/run.sh -b 0.0.0.0 -c default

  6. Open a browser and navigate to the following URL:

    https://<YOUR_HOSTNAME>:8443

    The security alert prompt is displayed as in Figure 18:

    Figure 18 Security Alert Prompt

    Security Alert Prompt
  7. Click Yes. The JBoss Enterprise Application Server default main page displays as in Figure 19:

    Figure 19 JBoss Main Page

    JBoss Main Page

Application Authentication with the Symas CDS

Configuring the CDS Server

  1. Install the appropriate version of Symas CDS and configure the CDS Server by setting the directive suffix to dc=example,dc=com in the slapd.conf. The schema files, cosine.schema and inetorgperson.schema should be included in the slapd.conf file.

  2. Restart the CDS Server by entering the following:

    # /etc/init.d/cdsserver restart

  3. Run the following command to add the example entries to the CDS server:

    /opt/symas/bin/ldapadd -x -D <ROOTDN> -w <ROOTPW>

    where:

    <ROOTDN> is the ROOTDN value in the slapd.conf file.
    <ROOTPW> is the ROOTPW value in the slapd.conf file.

    Input the following entries to stdin. Once you have completed the entries, press CTRL+D .

    dn: dc=example,dc=com
    objectClass: dcObject
    objectClass: organization
    dc: example
    o: example
    
    dn: dc=osm,dc=example,dc=com
    objectClass: dcObject
    objectClass: organizationalUnit
    dc: osm
    ou: osm
    
    dn: uid=tomy,dc=osm,dc=example,dc=com
    objectClass: inetOrgPerson
    uid: tomy
    sn: tom
    cn: tom yan
    mail: tom.yan@example.com
    carLicense: sea4321
    userPassword: tom
    
    dn: uid=benw,dc=osm,dc=example,dc=com
    objectClass: inetOrgPerson
    uid: benw
    sn: ben
    cn: ben won
    mail: ben.won@example.com
    userPassword: ben
    
    dn: cn=jmxRole,dc=osm,dc=example,dc=com
    objectClass: groupOfUniqueNames
    cn: jmxRole
    uniqueMember: uid=tomy,dc=osm,dc=example,dc=com
    
    dn: cn=ejbRole,dc=osm,dc=example,dc=com
    objectClass: groupOfUniqueNames
    cn: ejbRole
    uniqueMember: uid=benw,dc=osm,dc=example,dc=com
    

Securing the JMX-Console Using Symas CDS

Perform the following steps on the JBoss Enterprise Application Server:

  1. Edit the file $JBOSS_HOME/server/default/conf/login-config.xml and add the following contents:

    <application-policy name="LdapRealm">
    <authentication>
    <login-module code="org.jboss.security.auth.spi.LdapLoginModule" flag="required">
    <module-option name="java.naming.factory.initial">
    com.sun.jndi.ldap.LdapCtxFactory
    </module-option>
    <module-option name="java.naming.provider.url">
    ldap://[IP or Name of CDS Server]:389/
    </module-option>
    <module-option name="java.naming.security.authentication">
    simple
    </module-option>
    <module-option name="principalDNPrefix">
    uid=
    </module-option>
    <module-option name="principalDNSuffix">
    ,dc=osm,dc=example,dc=com
    </module-option>
    <module-option name="rolesCtxDN">dc=osm,dc=example,dc=com
    </module-option>
    <module-option name="roleAttributeID">cn
    </module-option>
    <module-option name="uidAttributeID">uniqueMember
    </module-option>
    <module-option name="matchOnUserDN">true
    </module-option>
    </login-module>
    </authentication>
    </application-policy>
  2. Edit the file $JBOSS_HOME/server/default/deploy/jmx-console.war/WEB-INF/web.xml and make the following changes:

    change

    <auth-constraint>
    	<role-name>
    	JBossAdmin
    	</role-name>
    </auth-constraint>

    to

    <auth-constraint>
    	<role-name>
    	jmxRole
    	</role-name>
    </auth-constraint><security-role>

    and, change

    <security-role>
    	<role-name>
    	JBossAdmin
    	</role-name>
    </security-role>

    to

    </security-role> <security-role>
    	<role-name>
    	jmxRole
    	</role-name>
    </security-role>
    NOTE: The jmxRole was previously created in “Configuring the CDS Server”. The file is configured so the users in the group jmxRole have access to jmx-console. For users who are not defined in jmxRole or do not exist in the directory server, access is denied.
  3. Edit the file $JBOSS_HOME/server/default/deploy/jmx-console.war/WEB-INF/jboss-web.xml and change the contents to the following::

    <jboss-web>
       <!-- Uncomment the security-domain to enable security. You will
          need to edit the htmladaptor login configuration to setup the
          login modules used to authentication users.
          <security-domain>java:/jaas/jmx-console</security-domain>
       -->
    <security-domain>java:/jaas/LdapRealm</security-domain>
    </jboss-web>
  4. If the JBoss Enterprise Application Server is running, stop it and rerun by entering the following:

    NOTE: The username and password used with the shutdown.sh command are the same as ones used to access to the jmx-console.

    # $JBOSS_HOME/bin/shutdown.sh -u admin -p admin -S

    # $JBOSS_HOME/bin/run.sh -b 0.0.0.0 -c default

  5. Open a browser and navigate to the website located at:

    https://YOUR_JBOSS_SERVER:8443/jmx-console

    The authentication window is displayed as in Figure 20:

    Figure 20 Authentication Log-In

    Authentication Log-In
  6. Enter benw for the username and ben for the password. Click OK.

    Because the user benw is not in the jmxRole group, access to the page is denied as displayed in Figure 21:

    Figure 21 Access Denied to JMX-Console

    Access Denied to JMX-Console
  7. Open another browser and navigate to the same website as in Step 5.

  8. Enter tomy for the username and tom for the password.

    Because the user tomy is in the group jmxRole, which is granted access to jmx-console, the jmx-console page is displayed as in Figure 22:

    Figure 22 Access Granted to JMX-Console

    Access Granted to JMX-Console

Implementing EJB Invocation Security with Symas CDS

All access information to EJB methods is defined in the standard J2EE XML descriptor file ejb-jar.xml. The methods that a specific role can invoke are described in the <method-permission> elements. When a user logs in and tries to call a method in an EJB, the EJB container in JBoss identifies the user's role by querying the CDS Server and checks to see if the user has the appropriate permission, as defined in the configuration file ejb-jar.xml.

The following example implements an EJB with two public methods: hello()and helloWorld(). The security for these two methods is configured in the ejb-jar.xml file.

  1. Verify that all steps from the previous section, "Application Authentication with Symas CDS", passed without errors.

  2. Implement a simple session bean with two methods, for the test. For this test, the following source code is for the bean implementation class. You need to create the appropriate Home interface and Remote interface for the session bean.

    /**
            Bean implementation class for Enterprise Bean: Hello
    */
    public class HelloBean implements javax.ejb.SessionBean
    {
            private javax.ejb.SessionContext mySessionCtx;
            public javax.ejb.SessionContext getSessionContext(){
                    return mySessionCtx;
            }
            public void setSessionContext(javax.ejb.SessionContext ctx){
                    mySessionCtx = ctx;
            }
            public void ejbActivate(){
            }
            public void ejbCreate() throws javax.ejb.CreateException{
            }
            public void ejbPassivate(){
            }
            public void ejbRemove(){
            }
            public String hello(){
                    return "This is from hello!";
            }
            public String helloWorld(){
                    return "This is from helloWorld!";
           }
    }
  3. Compile the Remote interface, the Home interface, and the implementation class from Step 2 by entering the following:

    javac Hello.java HelloBean.java HelloHome.java

  4. Create the directory META-INF, at the same level as the *.class files generated in Step 3.

  5. Create the file META-INF/ejb-jar.xml and insert the following contents:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems,
    Inc.//DTD Enterprise JavaBeans 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>
    
    <ejb-jar>
    <description>OSMS EJB Security Hello Application</description>
    <display-name>Hello EJB</display-name>
    	<enterprise-beans>
    		<session>
     			<ejb-name>Hello</ejb-name>
     			<home>HelloHome</home>
     			<remote>Hello</remote>
     			<ejb-class>HelloBean</ejb-class>
     			<session-type>Stateless</session-type>
     			<transaction-type>Bean</transaction-type>
    		</session>
    	</enterprise-beans>
    	<assembly-descriptor>
    		<security-role><role-name>ejbRole</role-name></security-role>
    		<security-role><role-name>jmxRole</role-name></security-role>
    		<method-permission><role-name>ejbRole</role-name>
    			<method>
    			<ejb-name>Hello</ejb-name><method-name>hello</method-name>
    			</method>
    			<method>
    			<ejb-name>Hello</ejb-name><method-name>create</method-name>
    			</method>
    		</method-permission>
    		<method-permission><role-name>jmxRole</role-name>
    			<method>
    			<ejb-name>Hello</ejb-name><method-name>helloWorld</method-name>
    			</method>
    			<method>
    			<ejb-name>Hello</ejb-name><method-name>create</method-name>
    			</method>
    		</method-permission>
    	</assembly-descriptor>
    </ejb-jar>

    The META-INF/ejb-jar.xml file is configured so the role ejbRole is permitted to invoke the hello()() method while jmxRole is permitted to invoke the helloWorld()() method.

  6. Create a file named META-INF/jboss.xml that contains the following contents:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems,
    Inc.//DTD Enterprise JavaBeans 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>
    <jboss>
    	<security-domain>java:/jaas/LdapRealm</security-domain>
    		<enterprise-beans>
    			<session>
     			<ejb-name>Hello</ejb-name>
    			<jndi-name>osmsHello</jndi-name>
    			</session>
    		</enterprise-beans>
    </jboss>

    The <security-domain> in the jboss.xml file should be consistent with the application policy name for CDS Server authentication in the $JBOSS_HOME/server/default/conf/login-config.xml file.

  7. Pack the directory META-INF and all *.class files into a JAR package by entering the following:

    # jar cvf hello.jar META-INF Hello.class HelloBean.class \

    HelloHome.class

  8. Deploy the JAR package to the JBoss Enterprise Application Server by entering the following:

    # cp hello.jar $JBOSS_HOME/ server/default/deploy

  9. Check the JBoss output on the screen and verify that the following messages appear:

    INFO  [EjbModule] Deploying Hello
    [ProxyFactory] Bound EJB Home 'Hello' to jndi 'osmsHello'
    

    This means that the EJB has been deployed to JBoss successfully.

Implementing EJB Invocation Security from Standard EJB Clients

This section provides the steps for invoking EJB methods from standard EJB clients.

  1. Write a standard EJB client which contains the following contents:

    /*HelloClient.java*/
    import java.util.*;
    import javax.ejb.CreateException;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import javax.rmi.PortableRemoteObject;
    import javax.security.auth.login.LoginContext;
    import javax.security.auth.login.LoginException;
    import java.io.*;
    import java.rmi.RemoteException;
    import javax.security.auth.callback.*;
    
    public class HelloClient
    {
      public static void main( String [] args ){
            String userName = args[0];
            String password = args[1];
    
            System.out.println("Logging in user:" + userName);
            final String authFile = "./ejbLogin.conf";
            System.setProperty("java.security.auth.login.config", authFile);
            MyCallbackHandler handler = new
     							MyCallbackHandler(userName,password);
            try{
                    LoginContext lc = new 
    LoginContext("ejbLogin",handler);
                    lc.login();
                    System.out.println("Successfully logged in user:" + 
    userName);
            }
            catch (LoginException le){
                    System.out.println("Login failed");
                    le.printStackTrace();
                    return;
            }
            try{
    Properties props = new Properties();
    props.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
    props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
    props.put("java.naming.provider.url", "localhost:1099");                
    
    Context context = new InitialContext(props);
                    Object lookupObj = context.lookup("osmsHello");
            HelloHome home = (HelloHome)
    PortableRemoteObject.narrow(lookupObj, 
    HelloHome.class);
                    Hello hello = home.create();
                    System.out.println("EJB method hello returns:" + 
    hello.hello());
            }
            catch(Exception e){
                    e.printStackTrace();
                    return;
            }
      }
    }
    class MyCallbackHandler implements CallbackHandler
    {
            private String username;
            private String password;
            public MyCallbackHandler(String username, String password){
                    this.username = username;
                    this.password = password;
            }
            public void handle(Callback[] callbacks) throws IOException,
     							UnsupportedCallbackException {
                    for (int i = 0; i < callbacks.length; i++){
                            if (callbacks[i] instanceof NameCallback){
                                    NameCallback nc = (NameCallback)
     												callbacks[i];
                                    nc.setName(username);
    
                            }
                             else if (callbacks[i] instanceof
     												PasswordCallback){
                                 PasswordCallback pc =
    (PasswordCallback) callbacks[i];
    pc.setPassword(password.toCharArray());
    
                            }
                            else{
                                throw new UnsupportedCallbackException(
    callbacks[i], "Unrecognized Callback");
                            }
                    }
            }
    }

    In the code, the hello()() method is invoked and its return string is set to print to the console.

  2. Compile the EJB client by entering the following:

    # javac HelloClient.java

  3. Create an EJB login configuration file named ejbLogin.conf, save it in the same directory as HelloClient.class, and add the following contents:

    ejbLogin{
    org.jboss.security.ClientLoginModule required;
    };
  4. Run HelloClient() with the user benw and password ben, by entering the following:

    # java HelloClient benw ben

    NOTE: Set the environment variable CLASSPATH so that it contains the current working directory, the path of jbossall-client.jar, and the path to the EJB interface which you created in the previous section.

    The following messages appear:

    Logging in user:benw
    Successfully logged in user:benw
    EJB method hello returns:This is from hello!

    Because the user benw has the role of ejbRole in the CDS Server and ejbRole is granted the privilege of invoking hello()() method, the EJB client can invoke the hello() ()method successfully.

  5. Run HelloClient() with the user tomy and the password tom by entering the following:

    # java HelloClient tomy tom

    The following messages appear:

    Logging in user:tomy
    Successfully logged in user:tomy
    java.rmi.AccessException: SecurityException; nested exception is:
             java.lang.SecurityException: Insufficient method permissions,
    				principal=tomy, ejbName=Hello, method=hello, interface=REMOTE, 
    				requiredRoles=[ejbRole], principalRoles=[jmxRole]
    …

    Even though the user tomy exists in the CDS Server, it does not have the role ejbRole and cannot invoke the hello()() method.

Implementing EJB Invocation Security from Web Applications

This section provides the steps for invoking the EJB methods from Web applications.

  1. Create a file named helloWorld.jsp in the current working directory, for example $EJB_TESTAPP_HOME, and add the following contents:

    <%@page contentType="text/html;charset=GBK"%>
    <%@page import="java.io.*,
    javax.naming.Context,
    javax.naming.InitialContext"
    %>
    <html>
    <body>
    <%
            try{
                    Context ctx = new InitialContext();
                    Object obj = ctx.lookup("osmsHello");
                    HelloHome home =(HelloHome)javax.rmi.PortableRemoteObject.narrow(obj,
    							HelloHome.class );
                    Hello helloWorld = home.create();
                    out.println("helloWorld method returns:" + helloWorld.helloWorld());
            }
            catch (Exception e){
                    out.println(e.toString());
            }
    %>
    </body>
    </html>
    NOTE: In the helloWorld.jsp file, helloWorld()() is invoked and its return string is output on the Web page.
  2. Create the directory WEB-INF at the same level as the file helloWorld.jsp.

  3. Create a file named WEB-INF/web.xml, in the current working directory, and add the following contents:

    <?xml version="1.0"?>
    <!DOCTYPE web-app PUBLIC
       "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
       "http://java.sun.com/dtd/web-app_2_3.dtd">
    
    <web-app>
    <ejb-ref><ejb-ref-name>ejb/Hello</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <home>HelloHome</home><remote> Hello</remote>
    <ejb-link>Hello</ejb-link>
    </ejb-ref>
    
    <security-constraint>
    <display-name>Constraints of osms Security Environment
    </display-name>
    <!-- URI security patterns and the HTTP methods to protect on them. -->
    <web-resource-collection><web-resource-name>
    Protected Admininistration Console Resources
    </web-resource-name>
    <url-pattern>/helloWorld.jsp</url-pattern>
    <http-method>GET</http-method>
    <http-method>POST</http-method>
    </web-resource-collection>
    <!-- Anyone with these roles may enter this area. -->
    <auth-constraint>
    <role-name>ejbRole</role-name>
    <role-name>jmxRole</role-name>
    </auth-constraint>
    <user-data-constraint>
    <description>no description</description>
    <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>
    </security-constraint>
    <!-- Default login configuration uses form-based authentication -->
    <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>LdapRealm</realm-name>
    </login-config>
    <!-- Security roles referenced by this web application -->
    <security-role><role-name>ejbRole</role-name></security-role>
    <security-role><role-name>jmxRole</role-name></security-role>
    </web-app>

    Both the ejbRole and jmxRole are granted access to the helloWorld.jsp file.

  4. Create a file named file WEB-INF/jboss-web.xml in the current working directory and add the following contents:

    <?xml version="1.0" encoding="UTF-8"?>
    <jboss-web>
    <ejb-ref>
    <ejb-ref-name>ejb/Hello</ejb-ref-name><jndi-name>osmsHello</jndi-name>
    </ejb-ref>
    <security-domain>java:/jaas/LdapRealm</security-domain>
    </jboss-web

    The element <security-domain> should be defined in the $JBOSS_HOME/server/default/conf/login-config.xml file.

  5. Pack the files in WEB-INF and helloWorld.jsp into a WAR file by entering the following:

    # jar cvf ejbTest.war WEB-INF/ helloWorld.jsp

  6. Copy the WAR package to the JBoss environment by entering the following:

    # cp ejbTest.war $JBOSS_HOME/ server/default/deploy

    The following messages appear, indicating the Web application deployed successfully:

    INFO [TomcatDeployer] deploy, ctxPath=/ejbTest,

    warUrl=.../tmp/deploy/tmp41792ejbTest-exp.war/

  7. Open a browser and navigate to the website located at:

    http://<YOUR_JBOSS_SERVER>:8080/ejbTest/helloWorld.jsp

  8. When the login window is displayed, enter benw as the user and ben as the password. Verify that access is denied as displayed inFigure 23:

    Figure 23 Access Denied to EJB Test

    Access Denied to EJB Test

    The messages indicate that the user benw does not have permission to invoke helloWorld()().

  9. Open a browser and navigate to the website located at:

    http://<YOUR_JBOSS_SERVER>:8080/ejbTest/helloWorld.jsp

  10. When the login window is displayed, enter tomy as the user and tom as the password. Verify that access is granted as displayed in Figure 24 :

    Figure 24 Access Granted to EJB Test

    Access Granted to EJB Test

    The message indicates the user tomy has permission to invoke the method helloWorld()().

Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© 2007 Hewlett-Packard Development Company, L.P.