Declarative Security Example

To illustrate declarative security, we modify our last example, Example ch10-ex2. The modified example is labeled Example ch10-ex3, and its sources can be found in the directory tree rooted at srcjsbookch10ex3 in the JSTK installation.

This example has a gateway bean EchoGW, in addition to the client program and the echo server bean Echo. This bean acts as a gateway between the client program and Echo bean, acting as the target bean for the client and a client to the Echo bean. This gives us the opportunity to talk about and demonstrate identity propagation and delegation concepts. To realize this scenario, the sources of the client and the server beans have been modified.

Overview of the Example

In this example, Echo bean has four methods: echo(), echo2(), echo3(), and echo4(). Each of these methods takes a java.lang.String object as an argument and returns the same String object, as the echo() method of the previous example. The method echo3() is slightly different—it uses the isCallerInRole() method to enforce access control and returns the argument only for callers with role "echomanager", throwing a java.security.AccessControlException for all other callers.

The body of the method echo3() is shown in Listing 10-9.

Listing 10-9. The method echo3() of Echo bean
public String echo3(String arg) {
  System.out.println("--- BEGIN EchoBean.echo3("" + arg + "") --- ");
  printCallerInfo();
  if (!ctx.isCallerInRole("echomanager"))
							throw new java.security.AccessControlException
							("Caller not in proper role.");
  System.out.println("----- END EchoBean.echo3() ----- ");
  return arg;
}

The EchoGW bean has only one method: gwEcho(). It takes a String object as an argument, locates the Echo bean, invokes the echo() method on the located bean, passing its own argument string, and returns the returned value to the caller. To locate the Echo bean, this bean needs the URL of the target server and JNDI name of the Echo bean. It gets these values from its ENC (Environment Naming Context) as named properties, configured through its deployment descriptor.

This runtime behavior of the EchoGW bean will be apparent from the body of method gwEcho(), shown in Listing 10-10.

Listing 10-10. The methog gwEcho() of the bean EchoGW
public String gwEcho(String arg) {
  System.out.println("--- BEGIN EchoGWBean.gwEcho("" +arg+ "") ---");
  printCallerInfo();

  String retval = "Cannot Forward";
  try {
    InitialContext lic = new InitialContext();
    String targetUrl = (String)lic.lookup("java:comp/env/target_url");
    String jndiName =
        (String)lic.lookup("java:comp/env/target_jndi_name");

    Properties h = new Properties();
    h.put(Context.INITIAL_CONTEXT_FACTORY,
        "weblogic.jndi.WLInitialContextFactory");
    h.put(Context.PROVIDER_URL, targetUrl);
    InitialContext ic = new InitialContext(h);
    Object home = ic.lookup(targetJNDIName);
    EchoHome echoHome = (EchoHome)narrow(home, EchoHome.class);
    Echo echo = (Echo)narrow(echoHome.create(), Echo.class);
    System.out.println("----- END EchoGWBean.gwEcho() -----");
    retval = echo.echo("gwEcho:: " + arg);
  } catch (Exception e){
    System.err.println("gwEcho:: Exception -- " + e);
  }

  return retval;
}

The client program can either invoke a method on the Echo bean directly or through the EchoGW bean. It takes the URL of the Server hosting the target bean and the method name as command line arguments. From the method name, it knows whether the target is the EchoGW or Echo bean and uses appropriate interface classes and JNDI name. Optionally, it can also take a username and password as command line arguments and use these values for the JNDI authentication.

The client source file is in the Client.java file of the subdirectory client. The name and location of source and deployment descriptor files for the Echo and EchoGW bean are given in Table 10-1. All names are relative to the example home directory srcjsbookch10ex3.

As the source files are quite similar to the ones we have already seen, we will skip them. The contents of the various deployment descriptors are of more interest.

Table 10-1. Location of Example ch10-ex3 source files
Echo Server BeanGateway Server BeanDescription
echoEcho.javagwEcho.javaComponent interface
echoEchoHome.javagwEchoHome.javaHome interface
echoEchoBean.javagwEchoBean.javaBean implementation
META-INFechoejb-jar.xmlMETA-INFgwejb-jar.xmlDeployment descriptor
META-INFechoweblogic-ejb-jar.xmlMETA-INFgwweblogic-ejb-jar.xmlWebLogic Server-specific deployment descriptor
All pathnames are relative to example home directory srcjsbooksrcch10ex3

Deployment Descriptors

Let us start with looking at the fragments of the Echo bean deployment descriptor file ejb-jar.xml. These fragments are presented in order, so that a concatenation of individual fragments would yield the complete ejb-jar.xml file:

<?xml version="1.0"?>
<!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>

  <enterprise-beans>
    <session>
      <ejb-name>Echo</ejb-name>
      <home>echo.EchoHome</home>
      <remote>echo.Echo</remote>
      <ejb-class>echo.EchoBean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
      <security-role-ref>
        <description>
          bean method echo3() can be called only by caller in
          role "echomanager"
        </description>
        <role-name>echomanager</role-name>
							<role-link>echouser</role-link>
      </security-role-ref>
    </session>
  </enterprise-beans>

Recall that the Echo bean uses the role name "echomanager" in its code and needs to specify that as part of its bean descriptor. This is done through element security-role-ref. The subelement role-name specifies the role name used within the code of the method echo3(). As you can see, this role is linked to the "echouser" role, to be specified in the assembly-descriptor:

<assembly-descriptor>
  <security-role>
    <role-name>echouser</role-name>
 </security-role>

What it essentially means is that the method isCallerInRole("echomanager") will return true for all callers who have the role "echouser" at the application level.

The next fragment specifies different access policies for different methods:

   <method-permission>
     <unchecked/>
     <method>
       <ejb-name>Echo</ejb-name>
       <method-name>echo</method-name>
     </method>
   </method-permission>

   <method-permission>
     <role-name>echouser</role-name>
     <method>
       <ejb-name>Echo</ejb-name>
       <method-name>echo2</method-name>
     </method>
   </method-permission>

   <exclude-list>
							<method>
							<ejb-name>Echo</ejb-name>
							<method-name>echo4</method-name>
							</method>
							</exclude-list>
  </assembly-descriptor>

  <ejb-client-jar>echo_client.jar</ejb-client-jar>
</ejb-jar>

This deployment descriptor implies that the method echo() can be called by any caller, method echo2() only by callers in role "echouser", and method echo4() by no caller. Notice that there is no policy for method echo3(). The default access policy of the WebLogic Server is to allow all callers. However, as we have seen, the method echo3() uses security API call isCallerInRole() to reject callers without the "echomanager" role, and "echouser" role, by throwing an exception.

The deployment descriptor in ejb-jar.xml is compliant to EJB specification but does not include everything required for deployment into the WebLogic domain. As we know, for WebLogic Server you need a separate, incremental deployment descriptor file weblogic-ejb-jar.xml. This file for the Echo bean is presented below:

<?xml version="1.0"?>
<!DOCTYPE weblogic-ejb-jar PUBLIC
'-//BEA Systems, Inc.//DTD WebLogic 7.0.0 EJB//EN'
'http://www.bea.com/servers/wls700/dtd/weblogic-ejb-jar.dtd'>

<weblogic-ejb-jar>
  <weblogic-enterprise-bean>
    <ejb-name>Echo</ejb-name>
    <jndi-name>ex3-echo-EchoHome</jndi-name>
  </weblogic-enterprise-bean>

  <security-role-assignment>
    <role-name>echouser</role-name>
							<principal-name>EchoApp</principal-name>
  </security-role-assignment>
</weblogic-ejb-jar>

This descriptor assigns a JNDI name "ex3-echo-EchoHome" to the bean and associates WebLogic Server-specific principal name "EchoApp" to the role name "echouser". If you have a user named "EchoApp" in the WebLogic Server, created through the console, then this user gets the "echouser" role. If you have a group named "EchoApp", created through the console, then all users belonging to this group get the "echouser" role.

Let us turn our attention to the EchoGW bean deployment descriptor. We want to use this bean to illustrate user identity propagation and delegation. For identity propagation, we should insert the following fragment into the bean descriptor:

<security-identity>
  <use-caller-identity/>
</security-identity>

It essentially says that the bean method should run with user identity of the caller. In fact, specification of <use-caller-identity/> is redundant, for this is the default behavior for the WebLogic Server.

For identity delegation, i.e., to run the bean method with an identity different from the identity of the caller, replace the above fragment with the one shown below. This fragment uses "specialuser" as the delegated identity. Of course, you are free to specify whatever identity you want:

<security-identity>
  <run-as>
    <role-name>specialuser</role-name>
  </run-as>
</security-identity>

For the role-name within security-role-ref, you would need to have the same role name specified within a security-role element of assembly-descriptor element:

<assembly-descriptor>
  <security-role>
    <role-name>specialuser</role-name>
  </security-role>
</assembly-descriptor>

You may be wondering: How can a role take the place of a user identity? You are right. This role needs to be mapped to a specific user within the weblogic-ejb-jar.xml file:

<?xml version="1.0"?>
<!DOCTYPE weblogic-ejb-jar PUBLIC
'-//BEA Systems, Inc.//DTD WebLogic 7.0.0 EJB//EN'
'http://www.bea.com/servers/wls700/dtd/weblogic-ejb-jar.dtd'>

<weblogic-ejb-jar>
  <weblogic-enterprise-bean>

    <ejb-name>EchoGW</ejb-name>
    <jndi-name>ex3-gw-EchoGWHome</jndi-name>
  </weblogic-enterprise-bean>
  <security-role-assignment>
    <role-name>specialuser</role-name>
    <principal-name>akriti</principal-name>
  </security-role-assignment>
</weblogic-ejb-jar>

We are now ready to build, deploy and run the beans.

Building, Deploying and Running the Example Beans

The steps in compiling the beans and the client program and packaging the bean components in respective jar files are similar to the steps described earlier: compile the bean interfaces and the implementation classes, create the archive file, and run the EJB Compiler tool. Script file comp.bat, shown in Listing 10-11, has these steps for both Echo and EchoGW beans.

Listing 10-11. The script file to compile Example ch10-ex3 source files
@echo off
setlocal
call "..wlenv.bat"

if not exist build mkdir build
if not exist buildMETA-INF mkdir buildMETA-INF

copy META-INFecho* buildMETA-INF
%JAVAC% -d build echo*.java
jar cf echo.jar -C build .
%JAVA% -Dweblogic.home=%WLS_HOME% weblogic.ejbc -compiler javac echo.jar

%JAVAC% -classpath %CLASSPATH%;echo_client.jar -d build gw*.java
copy META-INFgw* buildMETA-INF
jar cf gw.jar -C build .
%JAVA% -Dweblogic.home=%WLS_HOME% weblogic.ejbc -compiler javac gw.jar

set CP=%CLASSPATH%;echo_client.jar;gw_client.jar
%JAVAC% -classpath %CP% -d build client*.java
endlocal

The end result of running this script is the creation of the following jar files: echo.jar for the Echo bean, gw.jar for the EchoGW bean, echo_client.jar for use with the client of Echo bean, gw_client.jar for use with the client of EchoGW bean, and the compiled Client class under buildclient directory.

The script to run the client, runc.bat, undergoes only a minor change, to make sure that the stub classes to invoke the EchoGW bean are in the CLASSPATH:

@echo off
call "../wlenv.bat"

set CP=%CLASSPATH%;echo_client.jar;gw_client.jar;build
%JAVA% -cp %CP% client.Client %*

Before running the client, we need to deploy the beans. A number of distinct deployment scenarios are possible:

  • Only the bean Echo is deployed.

  • The beans Echo and EchoGW are deployed within the same domain.

  • The beans Echo and EchoGW are deployed in two different domains.

We have already set up WebLogic domain test in the subsection Configuring a Domain and Running the Server. For the last deployment scenario, we need to set up another WebLogic domain. Follow the steps outlined in the above-mentioned subsection to set up the second domain. It could be on the same machine or on a different machine. For simplicity, let us assume that both the domains are on the same machine. Let us call it test1. Set its HTTP port to be 7005. Now, create user akriti with password akritipass, and user unnati with password unnatipass in both the domains. Also, create user group EchoApp in test domain and assign this group to user akriti. If you want, you could assign different passwords to the same user in different domains.

Deploy the Echo bean to the domain test by modifying the config.xml file as explained in the subsection Deploying Echo EJB and run the client program a number of times, each run with a different set of arguments:

C:ch10ex3>%JAVA% -cp %CLASSPATH%;echo_client.jar;build 
							client.Client t3://localhost:7001 echo
						

This run succeeds with the following message on the WebLogic Server window:

----- BEGIN EchoBean.echo("Hello, World!!") -----
Caller Name: <anonymous>
Caller in role "echomanager"? false
----- END EchoBean.echo() -----

Let us run the same program again, changing the method name to echo2:

C:ch10ex3>%JAVA% -cp %CLASSPATH%;echo_client.jar;build 
							client.Client t3://localhost:7001 echo2
Calling estub.echo2("Hello, World!!")...
Exception in thread "main" java.rmi.AccessException: Security Violation: User:
 '<anonymous>' has insufficient permission to access EJB: type=<ejb>, application=echo_jar,
 module=echo, ejb=Echo, method=echo2, methodInterface=Remote, signature={java.lang.String}.
... more error messages skipped ...

As expected, this call fails. Run the client with method names as echo3 and echo4, respectively. Go back to the deployment descriptor having the access rules for these methods. Can you predict the outcome of these client runs? Try them out. What messages do you see on the client windows and on the WebLogic Server window?

Now run the client program with username akriti and password akritipass:

C:ch10ex3>%JAVA% -cp %CLASSPATH%;echo_client.jar;build 
client.Client t3://localhost:7001 echo2 akriti akritipass

This command succeeds with the following message on the WebLogic Server window.

----- BEGIN EchoBean.echo2("Hello, World!!") -----
Caller Name: akriti
Caller in role "echomanager"? true
----- END EchoBean.echo2() -----

The program output suggests that the caller identity akriti is in role echomanager. This is the expected output, for the user akriti is in the user group EchoApp under WebLogic domain test and this user group is linked to the application role echouser as per the WebLogic Server-specific deployment descriptor weblogic-ejb-jar.xml. Further, the bean role echomanager is linked to the application role echouser in the EJB deployment descriptor ejb-jar.xml.

This setup and the relationship among different elements of the Echo bean deployment descriptor are illustrated in Figure 10-4.

Figure 10-4. Declarative Security in the Example ch10-ex3.


Run the client program with user akriti and password akritipass, specifying the method name as echo2, echo3 and echo4. Repeat the steps with an invalid password or a different username. Which ones succeed? Does the outcome match with the prediction based on the deployment descriptors?

Identity Delegation and Propagation within a Server

To illustrate identity delegation, deploy the EchoGW bean to the domain test. For this you would need to stop the WebLogic Server, modify the config.xml file and restart the server. Now run the client program, specifying method gwEcho as command line argument:

C:ch10ex3>runc t3://localhost:7001 gwEcho akriti akritipass
Calling gstub.gwEcho("Hello, World!!")...
Returned String -- gwEcho:: Hello, World!!
... Client Executed successfully.

And look at the WebLogic Server window for messages:

----- BEGIN EchoGWBean.gwEcho("Hello, World!!") -----
Caller Name: akriti
Caller in role "echomanager"? false
----- END EchoGWBean.gwEcho() -----
----- BEGIN EchoBean.echo("gwEcho:: Hello, World!!") -----
Caller Name: unnati
Caller in role "echomanager"? false

From this output, it is easy to infer that the EchoGW bean has been invoked with identity akriti and the Echo bean has been invoked with caller identity unnati. In other words, bean EchoGW has delegated the caller identity to unnati, an identity of its choice. This happens without the EchoGW bean specifying the password of the delegated identity unnati anywhere. How do you explain this?

With the default configuration, a WebLogic Server forms a protection domain. What it means is that a component can simply tell the other component deployed within the same protection domain about the delegated identity. The other component trusts the caller. As the beans EchoGW and Echo are in the same protection domain, bean Echo simply takes the word of the bean EchoGW regarding the delegated identity.

Figure 10-5 illustrates this delegation, showing the relationship among various elements of the deployment descriptor and delegated identity.

Figure 10-5. Identity Delegation in Example ch10-ex3.


To observe the identity propagation in action, modify the EchoGW deployment descriptor to comment out the elements responsible for identity delegation and run the client program. Figure 10-6 illustrates this.

Figure 10-6. Identity Propagation in Example ch10-ex3.


We just demonstrated that the identity delegation and propagation work fine when the caller bean EchoGW and the callee bean Echo are deployed within the same WebLogic domain. What about the scenario when both beans are deployed within different domains?

Identity Delegation and Propagation across Servers

Intuition says that the identity delegation and propagation shouldn't work across independently configured servers for if it worked, there would be no security for any bean deployed within a server. One could assume any identity by simply setting up a WebLogic server instance, properly configuring it and accessing secured beans deployed on the other WebLogic servers, without knowing the user password.

Let us verify this by deploying the bean Echo to the domain test and the bean EchoGW to the domain test1 and running the client:

C:ch10ex3>runc t3://localhost:7005 gwEcho akriti akritipass
Calling gstub.gwEcho("Hello, World!!")...
Returned String -- Cannot Forward
... Client Executed successfully.

The returned string indicates that forwarding failed. Look at the error messages in the window running the test1 server:

----- BEGIN EchoGWBean.gwEcho("Hello, World!!") -----
Caller Name: akriti
Caller in role "echomanager"? false
gwEcho:: Exception -- java.lang.SecurityException: Invalid Subject: principals=[unnati]
Start server side stack trace:
java.lang.SecurityException: Invalid Subject: principals=[unnati]
... more messages skipped  ...

As per our intuition, the Echo Server is not taking the word of EchoGW server regarding the identity unnati.

This problem is resolved in WebLogic by the formation of a protection domain consisting of multiple domain servers. The way this is done is by setting the security credential of each domain server to the same string value. By default, the security credential of a domain server is generated randomly during installation, and hence each domain Server has its own credential. However, an administrator can change it afterward. To do this, launch the WebLogic server console, log in by supplying the administrator user identity and password, click on the domain name in the left panel; select tab SecurityAdvanced, and then click on Credential: Change. Specify a secret string as the credential. Stop and restart the server for the new credential to become effective. Do this for all domain servers, choosing the same string for the credential.

Once you have formed a protection domain consisting of the domains test and test1, rerun the client. It should work fine this time.

You are encouraged to do more experimentation and find answers to the following questions:

  1. What happens if the bean EchoGW delegates to a user identity that is not a valid user in its own domain, domain test1?

  2. What happens if the bean EchoGW delegates to a user identity that is not a valid user in domain test, the host of the target bean Echo?

  3. What if the bean EchoGW is configured for identity propagation and the caller supplies an identity that is a valid user in the domain test1, but not in domain test?

  4. Will the method invocation isCallerInRole("echomanager") return true in the bean Echo if the caller to the bean EchoGW specified user identity as akriti and the bean EchoGW is configured for identity propagation? Recall that the user akriti is a valid user in both the domains and a direct invocation on the bean Echo with the user identity akriti would make the method isCallerInRole("echomanager") return true.

Unfortunately, EJB specification is quite ambiguous in answering these questions. Answers for WebLogic Server 7.0, SP2, based on author's experimentation, are given below:

  1. The deployment of the bean EchoGW fails.

  2. The invocation of the bean Echo succeeds. The method getCallerPrincipal() in the bean Echo returns the identity specified by the bean EchoGW. This appears somewhat counter-intuitive.

  3. Same as 2. At least this behavior is consistent for both delegation and propagation.

  4. No. This behavior is also not very obvious. The interesting part is that if you deploy Echo and EchoGW on the same domain then the answer is Yes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.42.129