User: stark   
  Date: 01/01/21 11:59:15

  Added:       documentation HowTo.Security.html
  Log:
  This document describes the JBoss server's security architecture in some detail. It
  should be sufficient to allow you to configure a simple security setup for testing.
  It should also give you a good start to being able to inegrate your own custom
  security implementation into JBoss.
  
  Revision  Changes    Path
  1.1                  newsite/documentation/HowTo.Security.html
  
  Index: HowTo.Security.html
  ===================================================================
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  <html>
  <head>
        <title>How To Setup JAAS Based Security in JBoss</title>
  </head>
  
  <body>
  
  <h1>How To Setup JAAS Based Security in JBoss</h1>
  <p>By <a href="mailto:[EMAIL PROTECTED]">Scott Stark</a>
  for JBoss-PRE2.1, Jan 20 2001</p>
  
  <h2>Introduction</h2>
  This document describes the JBoss server's security architecture in some detail. It
  should be sufficient to allow you to configure a simple security setup for testing.
  It should also give you a good start to being able to inegrate your own custom
  security implementation into JBoss.
  <ul>
        <li><a href="#Security Model Overview">Security Model Overview</a></li>
        <li><a href="#SecurityInterceptor">How to Associate Security With the 
Container SecurityInterceptor</a></li>
        <li><a href="#Using JaasSecurityManager">Using JaasSecurityManager</a></li>
        <li><a href="#The Stateless Session Bean">The Stateless Session Bean</a></li>
        <li><a href="#Deploying a Bean with Security">Deploying a Bean with 
Security</a></li>
        <li><a href="#Key Sequence Diagrams">Key Sequence Diagrams</a></li>
  </ul>
  
  <h2><a name="Security Model Overview">Security Model Overview</a></h2>
  <p>
  The security model in JBoss is based on the server container architecture's pluggable
  method interceptors and the fact that the container factory always inserts security
  interceptor(org.jboss.ejb.plugins.SecurityInterceptor). For a view of
  see <a href="../pictures/Entity_container_call.gif">Entity Container Diagram</a>
  for additional details.
  </p>
  <p>
  Integration of custom security requires implementing the two interfaces that the
  SecurityInterceptor class uses to externalize its security checks. They are:
  <code><pre>
  package org.jboss.security;
  public interface EJBSecurityManager
  {
        public boolean isValid(java.security.Principal principal, Object credential);
  }
  </pre></code>
  and:
  <code><pre>
  package org.jboss.security;
  public interface RealmMapping
  {
      public java.security.Principal getPrincipal(java.security.Principal principal);
      public boolean doesUserHaveRole(java.security.Principal principal, Set 
roleNames);
  }
  </pre></code>
  
  JBoss includes a number of sample implementations of both interfaces. These can be 
found
  in the org.jboss.security.plugins.samples package. There is also a JMX service bean 
that can
  be used to setup a JAAS based implementation of both interfaces. The JMX bean is
  org.jboss.security.JaasSecurityManagerService and the security manager 
implementation is
  org.jboss.security.JaasSecurityManager. This document will focus on setting up the
  JaasSecurityManager via the JaasSecurityManagerService for a trivial stateless 
session
  bean. Once you can perform the steps documented to secure the example bean, you 
should
  be able to introduce your own production ready security using this example as a 
template.
  
  <h2><a name="#SecurityInterceptor">How to Associate Security With the Container 
SecurityInterceptor</a></h2>
  Ok, so you know that every EJB container in JBoss includes a SecurityInterceptor
  that delegates its security checks to an EJBSecurityManger and RealmMapping 
implementation.
  Question: How do you choose which implementations a given container uses?
  Answer: You specify this information via the jboss deployment descriptor.
  <p>
  <h3>The JBoss Deployment Descriptor(jboss.xml and standardjboss.xml)</h3>
  The JBoss deployment descriptor is the JBoss application specific deployment
  configuration file. It describes optional behavior that is outside of the
  EJB spec ejb-jar.xml deployment descriptor. The standardjboss.xml version
  of the file is located in ${jboss_home}/conf/conf_name where ${jboss_home}
  is the directory into which you have installed the JBoss distribution and conf_name
  is the specific runtime configuration that you specify to the run.sh or run.bat
  script when starting the server. The default value for conf_name is of
  course "default". The standardjboss.xml specifies the global configuration
  default values. You can also specific ejb-jar or j2ee-ear specific jboss.xml
  descriptors that override specific configuration properties as appropriate
  for your application.
  
  There are a quite a few configurable properties that can be set in the file,
  but all are optional. For all of the possible configuration elements and
  their details see the <a href="jboss.dtd">jboss.dtd</a>.
  We are only concerned with the two security specific elements:
  <ul>
        <li>role-mapping-manager</li>
        <li>authentication-module</li>
  </ul>
  </p>
  <h4>role-mapping-manager</h4>
  The role-mapping-manager element specifies the implementation of the
  org.jboss.security.RealmMapping interface that is to be used by the container
  SecurityInterceptor. The value is specified as the JNDI name to where the
  object is located. Hence, the role-mapping-manager is like a JMS 
TopicConnectionFactory
  in that it is accessed via a JNDI name. As far as the container configuration is
  concerned, an implementation of org.jboss.security.RealmMapping exists in the
  JBoss server JNDI namespace and role-mapping-manager element provides the
  location. We'll se how you get a RealmMapping instance into the JNDI namespace
  shortly.
  <h4>authentication-module</h4>
  The authentication-module element specifies the implementation of the
  org.jboss.security.EJBSecurityManager interface that is to be used by the container
  SecurityInterceptor. The value is specified as the JNDI name to where the
  object is located, just like the role-mapping-manager.
  
  <h4>Sample jboss.xml</h4>
  The jboss.xml descriptor will we use is:
  <code><pre>
  &lt;?xml version="1.0"?&gt;
  &lt;jboss&gt;
        &lt;container-configurations&gt;
                &lt;container-configuration&gt;
                        &lt;container-name&gt;Standard Stateless 
SessionBean&lt;/container-name&gt;
                        
&lt;role-mapping-manager&gt;java:/jaas/other&lt;/role-mapping-manager&gt;
                        
&lt;authentication-module&gt;java:/jaas/other&lt;/authentication-module&gt;
                &lt;/container-configuration&gt;
        &lt;/container-configurations&gt;
  
        &lt;enterprise-beans&gt;
                &lt;session&gt;
                        &lt;ejb-name&gt;StatelessSession&lt;/ejb-name&gt;
                        &lt;configuration-name>Standard Stateless 
SessionBean&lt;/configuration-name&gt;
                &lt;/session&gt;
        &lt;/enterprise-beans&gt;
  &lt;/jboss&gt;
  </pre></code>
  This says that we are augmenting the definition of the "Standard Stateless 
SessionBean"
  container to include role-mapping-manager and authentication-module security 
elements,
  the values of which are the JNDI name "java:/jaas/other". We will see the reason for
  choosing this particular name over the next couple of sections. The "Standard 
Stateless SessionBean"
  name is coming from the standardjboss.xml default configuration file.
  
  <h3>Setting Up the RealmMapping and EJBSecurityManager in JNDI</h3>
  So the container configuration security elements specify the JNDI names where
  the desired RealmMapping and EJBSecurityManager implementations are to be
  obtained from for a given container. Now the question is how to bind implementations
  into the JBoss server JNDI namespace. The answer is to create a JMX mbean that
  creates and binds the desired implementations at server startup. The 
JaasSecurityManagerService
  is an mbean that has been written that we will use to perform the required setup.
  
  <p>
  To configure the JaasSecurityManagerService, open the 
${jboss_home}/conf/default/jboss.jcml
  file and look for an entry like:
  <code><pre>
  &lt;!-- JAAS security manager and realm mapping --&gt;
  &lt;mbean code="org.jboss.security.plugins.JaasSecurityManagerService"
        name="DefaultDomain:service=JaasSecurityManager" /&gt;
  </code></pre>
  If it is commented out or does not exist, uncomment or add the entry. The service
  creates a reference to a JNDI Context at java:/jaas that lazily binds instances
  of JaasSecurityManager under java:/jaas as requested. If you don't know JNDI
  well or this just makes no sense, don't worry about. All we care about is that with
  the JaasSecurityManagerService setup, any lookup on the JBoss server JNDI 
InitialContext
  using a name of the form java:/jaas/xyz results in an object of type
  org.jboss.security.plugins.JaasSecurityManager that has the name xyz.
  Translated to code, this means:
  <code><pre>
  InitialContext ctx = new InitialContext();
  JaasSecurityManager jsm1 = (JaasSecurityManager) ctx.lookup("java:/jaas/xyz");
  </code></pre>
  where jsm1 is an instance of JaasSecurityManager that was created using the
  name "xyz". We are going to use this feature to bind a single instance of 
JaasSecurityManager
  for use as both the RealmMapping and EJBSecurityManager implementations(because
  JaasSecurityManager implements both interfaces). We'll see this when we get to the
  session bean example. Now we need to know how we can actually authenticate users
  and specify the roles/identies they posses with a JaasSecurityManager.
  
  <h2><a name="Using JaasSecurityManager">Using JaasSecurityManager</a></h2>
  As you would expect, the JaasSecurityManager uses the JAAS
  (<a href="http://www.javasoft.com/products/jaas">Java Authentication and
  Authorization Service</a>) to implement both the user authentication and
  role mapping function of the RealmMapping and EJBSecurityManager interfaces.
  It does this by creating a JAAS Subject using the 
javax.security.auth.login.LoginContext
  mechanism. The JAAS Subject creation involves:
  <code><pre>
  Principal principal = ... passed in by SecurityInterceptor;
  char[] password = ... passed in by SecurityInterceptor;
  String name = ... the xyz component of java:/jaas/xyz used in the 
authentication-module and role-mapping-manager
  LoginContext lc = new LoginContext(name, new CallbackHandler(){...});
  lc.login(); // This validates principal, password
  Subject subject = lc.getSubject();
  Set roles = subject.getPrincipals();
  </code></pre>
  
  If you know JAAS, you'll see that the name that was used in the creation of the
  JaasSecurityManager correlates with the LoginContext Configuration index. The
  JAAS LoginContext object looks to a configuration file that is made up of
  named sections that describe the LoginModules that need to be executed in
  order to perform authentication. This abstraction allows the authentication
  api to be independent of a particular implementation. The authentication
  of users and the assignment of user roles comes down to implementing a
  javax.security.auth.spi.LoginModule and creating login configuration entry
  that correlates with the JaasSecurityManager name. There exist a number
  of sample LoginModule implementation in the org.jboss.security.plugins.samples
  package. We are going to use the JaasServerLoginModule to demonstrate the
  how to configure a LoginModule to work with the JaasSecurityManager. If
  you need different authentication and role mapping you can choose another
  LoginModule or implement you own and then configure it using the same
  steps we will use.
  
  <h3><a name="Using JaasServerLoginModule">Using JaasServerLoginModule</a></h3>
  The JaasServerLoginModule class is a simple file based implemention that
  uses two files(users.properties and roles.properities) to perform authentication
  and role mapping respectively.
  
  <h4>users.properties</h4>
  The users.properties file is a java properties formatted file that specifies
  the username to password mapping. Its format is
  <code><pre>
  username1=password1
  username2=password2
  ...
  </pre></code>
  with one entry per line.
  
  <h4>roles.properties</h4>
  The roles.properties file is a java properties formatted file that specifies
  the username to role(s) mapping. Its format is
  <code><pre>
  username1=role1[,role2,...]
  username2=role1
  ...
  </pre></code>
  with one entry per line. If a user has multiple roles they are specified using
  a comma separated list.
  
  <h4>The LoginModule Configuration File</h4>
  The JAAS LoginModule Configuration file is ${jboss_home)/conf/default/auth.conf.
  The syntax is:
  <code><pre>
  name {
        login_module_class_name (required|optional|...) [options];
  };
  </pre></code>
  See the JAAS documentation for the complete syntax description. There should be
  an entry like the following:
  // The default server login module
  <code><pre>
  other {
      // A realistic server login module, which can be used when the number 
      // of users is relatively small. It uses two properties files:
      //   users.properties, which holds users (key) and their password (value).
      //   roles.properties, which holds users (key) and a comma-separated list of 
their roles (value).
      org.jboss.security.plugins.samples.JaasServerLoginModule required;
  };
  </pre></code>
  This indicates that the JaasServerLoginModule we want to use is setup for the
  "other" configuration. This happens to the the configuration that JAAS uses when
  it can't find a match and it will work fine for us.
  <p>
  We have touched on all of the JBoss security related elements we need to configure.
  Let's now put together a simple session bean that we will secure to demonstrate
  how to use what we have gone over to deploy a secure bean.
  
  <h2><a name="The Stateless Session Bean">The Stateless Session Bean</a></h2>
  Here are the home, remote and bean classes for the simple stateless
  session bean we are going to secure, along with a simple client that
  creates an instance of the session bean:
  
  <h3>StatelessSession.java</h3>
  <code><pre>
  import javax.ejb.*;
  import java.rmi.*;
  
  public interface StatelessSession extends EJBObject
  {
      public String echo(String arg) throws RemoteException;
  }
  </pre></code>
  <h3>StatelessSessionHome.java</h3>
  <code><pre>
  import javax.ejb.*;
  import java.rmi.*;
  
  public interface StatelessSessionHome extends EJBHome
  {
      public StatelessSession create() throws RemoteException, CreateException;
  }
  </pre></code>
  <h3>StatelessSessionBean.java</h3>
  <code><pre>
  import java.rmi.RemoteException;
  import java.security.Principal;
  import javax.ejb.*;
  
  public class StatelessSessionBean implements SessionBean
  {
      private SessionContext sessionContext;
  
      public void ejbCreate() throws RemoteException, CreateException
      {
          System.out.println("StatelessSessionBean.ejbCreate() called");
      }
  
      public void ejbActivate() throws RemoteException
      {
          System.out.println("StatelessSessionBean.ejbActivate() called");
      }
  
      public void ejbPassivate() throws RemoteException
      {
          System.out.println("StatelessSessionBean.ejbPassivate() called");
      }
  
      public void ejbRemove() throws RemoteException
      {
          System.out.println("StatelessSessionBean.ejbRemove() called");
      }
  
      public void setSessionContext(SessionContext context) throws RemoteException
      {
          sessionContext = context;
      }
  
      public String echo(String arg)
      {
          System.out.println("StatelessSessionBean.echo, arg="+arg);
          Principal p = sessionContext.getCallerPrincipal();
          System.out.println("StatelessSessionBean.echo, callerPrincipal="+p);
          return arg;
      }
  
  }
  </pre></code>
  
  <h3>ejb-jar.xml</h3>
  <code><pre>
  &lt;?xml version="1.0"?&gt;
  &lt;!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 
1.1//EN"
      "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd"&gt;
  
  &lt;ejb-jar&gt;
        &lt;display-name&gt;SecurityTests&lt;/display-name&gt;
        &lt;enterprise-beans&gt;
                &lt;session&gt;
                        &lt;description&gt;A trival echo bean&lt;/description&gt;
                        &lt;ejb-name&gt;StatelessSession&lt;/ejb-name&gt;
                        &lt;home&gt;StatelessSessionHome&lt;/home&gt;
                        &lt;remote&gt;StatelessSession&lt;/remote&gt;
                        &lt;ejb-class&gt;StatelessSessionBean&lt;/ejb-class&gt;
                        &lt;session-type&gt;Stateless&lt;/session-type&gt;
                        &lt;transaction-type&gt;Container&lt;/transaction-type&gt;
                &lt;/session&gt;
      &lt;/enterprise-beans&gt;
  
        &lt;assembly-descriptor&gt;
                &lt;security-role&gt;
                        &lt;role-name&gt;Echo&lt;/role-name&gt;
                &lt;/security-role&gt;
  
                &lt;method-permission&gt;
                        &lt;role-name&gt;Echo&lt;/role-name&gt;
                        &lt;method&gt;
                                &lt;ejb-name&gt;StatelessSession&lt;/ejb-name&gt;
                                &lt;method-name&gt;*&lt;/method-name&gt;
                        &lt;/method&gt;
                &lt;/method-permission&gt;
      &lt;/assembly-descriptor&gt;
  &lt;/ejb-jar&gt;
  </pre></code>
  
  <h3>StatelessSessionClient.java</h3>
  <code><pre>
  import java.io.IOException;
  import javax.naming.InitialContext;
  import javax.rmi.PortableRemoteObject;
  import javax.security.auth.callback.*;
  import javax.security.auth.login.*;
  
  /** Run with -Djava.security.auth.login.config=${jboss_home}/client/auth.conf
  where ${jboss_home} is the location of your JBoss distribution.
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public class StatelessSessionClient
  {
      static class AppCallbackHandler implements CallbackHandler
      {
          private String username;
          private char[] password;
  
          public AppCallbackHandler(String username, char[] password)
          {
              this.username = username;
              this.password = password;
          }
  
          public void handle(Callback[] callbacks) throws
              java.io.IOException, UnsupportedCallbackException
          {
              for (int i = 0; i &lt; 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);
                  }
                  else
                  {
                      throw new UnsupportedCallbackException(callbacks[i], 
"Unrecognized Callback");
                  }
              }
          }
      }
  
      public static void main(String args[]) throws Exception
      {
          try
          {
              if( args.length != 2 )
                  throw new IllegalArgumentException("Usage: username password");
  
              String name = args[0];
              char[] password = args[1].toCharArray();
              AppCallbackHandler handler = new AppCallbackHandler(name, password);
              LoginContext lc = new LoginContext("TestClient", handler);
              System.out.println("Created LoginContext");
              lc.login();
          }
          catch (LoginException le)
          {
              System.out.println("Login failed");
              le.printStackTrace();
          }
  
          try
          {
              InitialContext jndiContext = new InitialContext();
              StatelessSessionHome home = (StatelessSessionHome) 
jndiContext.lookup("StatelessSession");
              System.out.println("Found StatelessSessionHome");
              StatelessSession bean = home.create();
              System.out.println("Created StatelessSession");
              System.out.println("Bean.echo('Hello') -> "+bean.echo("Hello"));
          }
          catch(Exception e)
          {
              e.printStackTrace();
          }
      }
  }
  </code></pre>
  
  The session bean is trivial. The client is also trivial except for the use of a
  JAAS LoginContext and CallbackHandler implementation. This is how a client 
establishes
  the username and password that is sent to jboss. Now, finally let's put everything
  together and deploy the session bean.
  
  <h2><a name="Deploying a Bean with Security">Deploying a Bean with Security</a></h2>
  We will perform the following steps to deploy and test the secured session bean:
  <ol>
        <li>Compile the session bean and client</li>
        <li>Create the session bean ejb-jar with the ejb-jar.xml and jboss.xml security
        elements
        </li>
        <li>Edit the users.properties and roles.properties</li>
        <li>Deploy the session bean jar, users.properties and roles.properties</li>
        <li>Edit the JBoss server jboss.jcml and auth.conf files</li>
        <li>Start the JBoss server</li>
        <li>Setup client env and test access to the session bean</li>
  </ol>
  
  <h3>Compile the session bean and client</h3>
  The examples I'll go through are on a windows 2000 box using the
  <a href="http://sources.redhat.com/cygwin/">cygwin</a> port of the
  GNU tools. So most things will look like unix with the exception
  of the ';' path separator used in the java classpath.
  <p>
  First save all of the files presented in this document. You should have the
  following 6 files:
  <code><pre>
  bash 1066>ls
  StatelessSession.java        StatelessSessionHome.java
  StatelessSessionBean.java    ejb-jar.xml
  StatelessSessionClient.java  jboss.xml
  </code></pre>
  Next, setup the classpath as follows by substituting the value for
  jboss_home appropriate for your system.
  <code><pre>
  bash 1068>export CLASSPATH="${jboss_home}/client/jaas.jar"
  bash 1069>CLASSPATH="${CLASSPATH};${jboss_home}/client/ejb.jar"
  bash 1070>CLASSPATH="${CLASSPATH};${jboss_home}/client/jnp-client.jar"
  bash 1071>CLASSPATH="${CLASSPATH};${jboss_home}/client/jboss-client.jar"
  bash 1072>CLASSPATH="${CLASSPATH};."
  bash 1073>echo $CLASSPATH
  
D:/usr/local/src/cvsroot/jBoss/jboss/dist/client/jaas.jar;D:/usr/local/src/cvsroot/jBoss/jboss/dist/client/ejb.jar;D:/usr/local/src/cvsroot/jBoss/jboss/dist/client/jnp-client.jar;D:/usr/local/src/cvsroot/jBoss/jboss/dist/client/jboss-client.jar;.
  </code></pre>
  Next, compile all of the source.
  <code><pre>
  bash 1077>javac -g *.java
  bash 1078>ls
  StatelessSession.class
  StatelessSession.java
  StatelessSessionBean.class
  StatelessSessionBean.java
  StatelessSessionClient$AppCallbackHandler.class
  StatelessSessionClient.class
  StatelessSessionClient.java
  StatelessSessionHome.class
  StatelessSessionHome.java
  ejb-jar.xml
  jboss.xml
  </code></pre>
  
  <h3>Create the session bean ejb-jar with the ejb-jar.xml and jboss.xml security 
elements</h3>
  Next, create the session bean jar as follows:
  <code><pre>
  bash 1087>jar -cf $jboss_home/deploy/ssbean.jar StatelessSession.class 
StatelessSessionBean.class StatelessSessionHome.class META-INF
  bash 1087>jar -tf $jboss_home/deploy/ssbean.jar
  META-INF/
  META-INF/MANIFEST.MF
  StatelessSession.class
  StatelessSessionBean.class
  StatelessSessionHome.class
  META-INF/ejb-jar.xml
  META-INF/jboss.xml
  </code></pre>
  
  <h3>Edit the users.properties and roles.properties</h3>
  Create a users.properties and roles.properties with the following data in each
  file:
  <code><pre>
  bash 1090>cat users.properties
  scott=echoman
  stark=javaman
  bash 1091>cat roles.properties
  scott=Echo
  stark=Java,Coder
  bash 1092>
  </code></pre>
  
  <h3>Deploy the session bean jar, users.properties and roles.properties</h3>
  We already deployed the session bean jar by jaring the files to the 
$jboss_home/deploy directory.
  To deploy the users.properties and roles.properties simply copy them to to the
  $jboss_home/conf/default directory.
  
  <h3>Edit the JBoss server jboss.jcml and auth.conf files</h3>
  These files needs to be setup as described earlier. The jboss.jcml file needs to
  have the JaasSecurityManagerService mbean element:
  <code><pre>
  ...
  &lt;!-- JAAS security manager and realm mapping --&gt;
    &lt;mbean code="org.jboss.security.plugins.JaasSecurityManagerService" 
name="DefaultDomain:service=JaasSecurityManager" /&gt;
  </code></pre>
  and the auth.conf needs to have the JaasServerLoginModule entry in the other section:
  <code><pre>
  ...
  // The default server login module
  other {
      // A realistic server login module, which can be used when the number 
      // of users is relatively small. It uses two properties files:
      //   users.properties, which holds users (key) and their password (value).
      //   roles.properties, which holds users (key) and a comma-separated list of 
their roles (value).
      org.jboss.security.plugins.samples.JaasServerLoginModule required;
  
      // For database based authentication comment the line above,
      // uncomment the line below and adjust the parameters in quotes
      // Database server login module provides security manager only, no role mapping
      // org.jboss.security.plugins.DatabaseServerLoginModule required 
db="jdbc/DbJndiName" table="UserTable" name="UserNameColumn" password="UserPswColumn";
  };
  </code></pre>
  
  <h3>Start the JBoss server</h3>
  Go to the $jboss_home/bin and start the run.sh or run.bat script as appropriate for
  you system. You will see a good deal of ouput on your console. Mine looks like, and
  I have emphasized the session bean deployment output.
  <code><pre>
  811>run.bat
  Using configuration "default"
  [Info] Java version: 1.3.0_01,Sun Microsystems Inc.
  [Info] Java VM: Java HotSpot(TM) Client VM 1.3.0_01,Sun Microsystems Inc.
  [Info] System: Windows 2000 5.0,x86
  [Shutdown] Shutdown hook added
  [Service Control] Registered with server
  [Jetty] Setting unpackWars=false
  [Jetty] Set successfully
  [Jetty] Adding configuration: 
URL=file:/usr/local/src/cvsroot/jBoss/jboss/dist/conf/default/jetty.xml
  [Jetty] Added successfully
  [Service Control] Initializing 18 MBeans
  [Webserver] Initializing
  [Webserver] Initialized
  [Naming] Initializing
  [Naming] Initialized
  ...
  [J2EE Deployer Default] Starting
  [J2EE Deployer Default] Cleaning up deployment directory
  [J2EE Deployer Default] Started
  [Auto deploy] Starting
  [Auto deploy] Watching D:\usr\local\src\cvsroot\jBoss\jboss\dist\deploy
  <em>
  [Auto deploy] Auto deploy of 
file:/D:/usr/local/src/cvsroot/jBoss/jboss/dist/deploy/ssbean.jar
  [J2EE Deployer Default] Deploy J2EE application: 
file:/D:/usr/local/src/cvsroot/jBoss/jboss/dist/deploy/ssbean.jar
  [J2EE Deployer Default] Create application ssbean.jar
  [J2EE Deployer Default] install module ssbean.jar
  [J2EE Deployer Default] Starting module ssbean.jar
  [Container factory] 
Deploying:file:/D:/usr/local/src/cvsroot/jBoss/jboss/dist/tmp/deploy/Default/ssbean.jar/ejb1001.jar
  </em>
  [Container factory] Deprecated container invoker. Change to 
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker
  [Container factory] Deprecated container invoker. Change to 
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker
  [Container factory] Deprecated container invoker. Change to 
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker
  [Container factory] Deprecated container invoker. Change to 
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker
  <em>
  [Verifier] Verifying 
file:/D:/usr/local/src/cvsroot/jBoss/jboss/dist/tmp/deploy/Default/ssbean.jar/ejb1001.jar
  [Container factory] Deploying StatelessSession
  [Container factory] Deployed application: 
file:/D:/usr/local/src/cvsroot/jBoss/jboss/dist/tmp/deploy/Default/ssbean.jar/ejb1001.jar
  [J2EE Deployer Default] J2EE application: 
file:/D:/usr/local/src/cvsroot/jBoss/jboss/dist/deploy/ssbean.jar is deployed.
  </em>
  [Auto deploy] Started
  [JMX RMI Adaptor] Starting
  [JMX RMI Adaptor] Started
  [JMX RMI Connector] Starting
  [JMX RMI Connector] Started
  [Service Control] Started 18 services
  [Default] JBoss PRE-2.1 Started
  </code></pre>
  
  <h3>Setup client env and test access to the session bean</h3>
  At this point the session bean is deployed and it should only be accessible by
  users with a role of 'Echo', and we have one user with a username 'scott'
  and a password 'echoman' that has this role. We have another user with a
  username 'stark' and a password 'javaman' that should not be able to acccess
  the session bean because he does not have the required role. Let's test this.
  
  <p>
  We need one final bit of information in order for the client to find the JBoss
  server JNDI name service. Since we are using a no arg InitialContext in the
  client, we need a jndi.properties file in our classpath(or we need to specify
  all required properities on the command line). For JBoss, the jndi.properties file
  should look like the following for the server running on the localhost with the
  default name service port:
  <code><pre>
  bash 1108>cat jndi.properties
  # JNDI initial context properties for jboss app server
  java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
  java.naming.provider.url=localhost
  java.naming.factory.url.pkgs=org.jboss.naming
  </code></pre>
  Create this file in the same directory as your StatelessSessionClient.java file since
  this directory is on the classpath we setup earlier. Now, run the client as user
  scott and specify the location of the JBoss client side JAAS login configuration file
  as follows:
  
  <code><pre>
  bash 1109>java 
-Djava.security.auth.login.config=file://${jboss_home}/client/auth.conf 
StatelessSessionClient scott echoman
  Created LoginContext
  Found StatelessSessionHome
  Created StatelessSession
  Bean.echo('Hello') -> Hello
  
  --- Server console:
  [StatelessSession] StatelessSessionBean.ejbCreate() called
  [StatelessSession] StatelessSessionBean.echo, arg=Hello
  [StatelessSession] StatelessSessionBean.echo, callerPrincipal=scott
  </code></pre>
  
  Ok, so that succeed as desired. Now we need to make sure that unauthorized users are
  actually denied access. This time run as user stark:
  
  <code><pre>
  bash 1111>java 
-Djava.security.auth.login.config=file://${jboss_home}/client/auth.conf 
StatelessSessionClient stark javaman
  Created LoginContext
  Found StatelessSessionHome
  java.rmi.ServerException: RemoteException occurred in server thread; nested 
exception is:
          java.rmi.RemoteException: checkSecurityAssociation; nested exception is:
          java.lang.SecurityException: Illegal access exception
  java.rmi.RemoteException: checkSecurityAssociation; nested exception is:
          java.lang.SecurityException: Illegal access exception
  java.lang.SecurityException: Illegal access exception
          at 
sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:245)
          at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:220)
          at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:122)
          at 
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker_Stub.invokeHome(Unknown Source)
          at org.jboss.ejb.plugins.jrmp.interfaces.HomeProxy.invoke(HomeProxy.java:221)
          at $Proxy0.create(Unknown Source)
          at StatelessSessionClient.main(StatelessSessionClient.java:74)
  
  --- Server console: No new output
  </code></pre>
  
  Alright, seems secure. Let's try user scott with an invalid password:
  <code><pre>
  bash 1113>java 
-Djava.security.auth.login.config=file://${jboss_home}/client/auth.conf 
StatelessSessionClient scott badpass
  Created LoginContext
  Found StatelessSessionHome
  java.rmi.ServerException: RemoteException occurred in server thread; nested 
exception is:
          java.rmi.RemoteException: checkSecurityAssociation; nested exception is:
          java.lang.SecurityException: Authentication exception
  java.rmi.RemoteException: checkSecurityAssociation; nested exception is:
          java.lang.SecurityException: Authentication exception
  java.lang.SecurityException: Authentication exception
          at 
sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:245)
          at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:220)
          at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:122)
          at 
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker_Stub.invokeHome(Unknown Source)
          at org.jboss.ejb.plugins.jrmp.interfaces.HomeProxy.invoke(HomeProxy.java:221)
          at $Proxy0.create(Unknown Source)
          at StatelessSessionClient.main(StatelessSessionClient.java:74)
  
  --- Server console:
  [JAASSecurity] Bad password.
  [StatelessSession] javax.security.auth.login.FailedLoginException: Password 
Incorrect/Password Required
  [StatelessSession]      at 
org.jboss.security.plugins.AbstractServerLoginModule.login(AbstractServerLoginModule.java:110)
  [StatelessSession]      at 
org.jboss.security.plugins.samples.JaasServerLoginModule.login(JaasServerLoginModule.java:94)
  [StatelessSession]      at java.lang.reflect.Method.invoke(Native Method)
  [StatelessSession]      at 
javax.security.auth.login.LoginContext.invoke(LoginContext.java:595)
  [StatelessSession]      at 
javax.security.auth.login.LoginContext.access$000(LoginContext.java:125)
  [StatelessSession]      at 
javax.security.auth.login.LoginContext$3.run(LoginContext.java:531)
  [StatelessSession]      at java.security.AccessController.doPrivileged(Native Method)
  [StatelessSession]      at 
javax.security.auth.login.LoginContext.invokeModule(LoginContext.java:528)
  [StatelessSession]      at 
javax.security.auth.login.LoginContext.login(LoginContext.java:449)
  [StatelessSession]      at 
org.jboss.security.plugins.JaasSecurityManager.authenticate(JaasSecurityManager.java:168)
  [StatelessSession]      at 
org.jboss.security.plugins.JaasSecurityManager.isValid(JaasSecurityManager.java:101)
  [StatelessSession]      at 
org.jboss.ejb.plugins.SecurityInterceptor.checkSecurityAssociation(SecurityInterceptor.java:101)
  [StatelessSession]      at 
org.jboss.ejb.plugins.SecurityInterceptor.invokeHome(SecurityInterceptor.java:124)
  [StatelessSession]      at 
org.jboss.ejb.plugins.LogInterceptor.invokeHome(LogInterceptor.java:106)
  [StatelessSession]      at 
org.jboss.ejb.StatelessSessionContainer.invokeHome(StatelessSessionContainer.java:253)
  [StatelessSession]      at 
org.jboss.ejb.plugins.jrmp.server.JRMPContainerInvoker.invokeHome(JRMPContainerInvoker.java:347)
  [StatelessSession]      at java.lang.reflect.Method.invoke(Native Method)
  [StatelessSession]      at 
sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:241)
  [StatelessSession]      at sun.rmi.transport.Transport$1.run(Transport.java:142)
  [StatelessSession]      at java.security.AccessController.doPrivileged(Native Method)
  [StatelessSession]      at 
sun.rmi.transport.Transport.serviceCall(Transport.java:139)
  [StatelessSession]      at 
sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:443)
  [StatelessSession]      at 
sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:643)
  [StatelessSession]      at java.lang.Thread.run(Thread.java:484)
  </code></pre>
  
  Mission accomplished.
  
  <hr>
  <h2><a name="Key Sequence Diagrams">Key Sequence Diagrams</a></h2>
  The section provides sequence diagrams of key steps in the security process.
  I put these together while going over the PRE2.1 server code to tie together
  how the various objects interacted.
  <h4>SeverSecurityContext</h4>
  <img src="../pictures/SeverSecurityContext.sq.gif">
  <h4>ServerSideAuthentication</h4>
  <img src="../pictures/ServerSideAuthentication.sq.gif">
  <h4>ClientSideAuthentication</h4>
  <img src="../pictures/ClientSideAuthentication.sq.gif">
  
  </body>
  </html>
  
  
  

Reply via email to