users@glassfish.java.net

Glassfish authenticated user propagation across multiple EARs

From: <glassfish_at_javadesktop.org>
Date: Mon, 12 Apr 2010 13:20:38 PDT

Hello.

I am currently trying to port our legacy system onto Glassfish v2.1. The system comprises of 3 separate enterprise archives, which use ejb 2.1 for a number of stateless session beans. I have run into trouble while trying to get the security to work. The intention is that we perform a programmatic login to authenticate the user, then run as that user for all subsequent processing. The issue I get, is that when the authenticated user calls en ejb from a separate enterprise archive, the authenticated subject is not propagated and I either get ANOMYMOUS user or the glassfish administrative user for the domain as the caller principle for the ejb.

Is it possible to configure a trust domain around more than one enterprise archive, such that when running as an authenticated user, this user will be propagated as the caller principle for ejb calls to separate enterprise archives?

I made a simple mock up of the scenario we have, where a client application performs a login as a valid user to call a simple hello world ejb in the first enterprise archive, which in turn calls a second hello world ejb in another archive. Both ejb modules are configured exactly as in the example below:

/* EJB module 1 */
/* Remote interface */

package com.example.company.ejb.interfaces;

import java.rmi.RemoteException;

public interface HelloWorld extends javax.ejb.EJBObject {
        public String sayHello(String myName) throws RemoteException;
}
/* Home interface */
package com.example.company.ejb.interfaces;

import java.rmi.RemoteException;

import javax.ejb.CreateException;

public interface HelloWorldHome extends javax.ejb.EJBHome {
        public HelloWorld create() throws CreateException, RemoteException;
        public HelloWorld create(String message) throws CreateException, RemoteException;
}
/* ejb class */
package com.example.company.ejb.impl;

import java.rmi.RemoteException;
import java.security.Principal;

import javax.ejb.EJBException;
import javax.ejb.EJBHome;
import javax.ejb.EJBObject;
import javax.ejb.Handle;
import javax.ejb.RemoveException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

import com.example.company.ejb.interfaces.HelloWorld;
import com.example.company2.ejb.interfaces.HelloWorld2;
import com.example.company2.ejb.interfaces.HelloWorld2Home;

public class HelloWorldBean implements SessionBean, HelloWorld {

        private SessionContext sessctx;

        public String sayHello(String myName) {
                try {
                        Principal p = sessctx.getCallerPrincipal();
                        System.out.println("sayHello(myName) caller is "+p.getName());
                        //now invoke sayHello2 in 2nd ejb
                        InitialContext ctx = new InitialContext();
                        Object homeObj = ctx.lookup("jndi/helloWorld2");
                        HelloWorld2Home hwHome =
                                (HelloWorld2Home)PortableRemoteObject.narrow(homeObj,HelloWorld2Home.class);
                        HelloWorld2 hw = hwHome.create();
                        return hw.sayHello2(myName);
                } catch (Exception e) {
                        System.out.println("Error executing HelloWorld2: "+e.getMessage());
                        return "Couldnt invoke hello2(myName)!";
                }
        }

        public void setSessionContext(SessionContext ctx) throws EJBException,
                        RemoteException {
                this.sessctx = ctx;
        }
        
        //other required methods...
}

/*ejb-jar.xml*/

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar id="ejb-jar_ID" version="2.1"
                 xmlns="http://java.sun.com/xml/ns/j2ee"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd">
        <display-name>EJB_security_test</display-name>
        <enterprise-beans>
                <session>
                        <display-name>The HelloWorld EJB</display-name>
                        <ejb-name>TheHelloWorld</ejb-name>
                        <home>com.example.company.ejb.interfaces.HelloWorldHome</home>
                        <remote>com.example.company.ejb.interfaces.HelloWorld</remote>
                        <ejb-class>com.example.company.ejb.impl.HelloWorldBean</ejb-class>
                        <session-type>Stateless</session-type>
                        <transaction-type>Container</transaction-type>
                        <security-role-ref>
                                <role-name>Users</role-name>
                                <role-link>Users</role-link>
                        </security-role-ref>
                        <security-role-ref>
                                <role-name>Admins</role-name>
                                <role-link>Admins</role-link>
                        </security-role-ref>
                        <security-identity>
                                <run-as>
                                        <role-name>Users</role-name>
                                </run-as>
                        </security-identity>
                </session>
        </enterprise-beans>
        <assembly-descriptor>
                <security-role>
                        <role-name>Admins</role-name>
                </security-role>
                <security-role>
                        <role-name>Users</role-name>
                </security-role>
                <method-permission>
                        <role-name>Admins</role-name>
                        <method>
                          <ejb-name>TheHelloWorld</ejb-name>
                          <method-name>*</method-name>
                        </method>
                </method-permission>
                <method-permission>
                        <role-name>Users</role-name>
                        <method>
                          <ejb-name>TheHelloWorld</ejb-name>
                          <method-name>*</method-name>
                        </method>
                </method-permission>
        </assembly-descriptor>
</ejb-jar>

/* sun-ejb-jar.xml */

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 8.1 EJB 2.1//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_2_1-1.dtd">
<sun-ejb-jar>
  <security-role-mapping>
          <role-name>Users</role-name>
          <group-name>Users</group-name>
  </security-role-mapping>
  <security-role-mapping>
          <role-name>Admins</role-name>
          <group-name>Admins</group-name>
  </security-role-mapping>
  <enterprise-beans>
    <unique-id>1</unique-id>
    <ejb>
      <ejb-name>TheHelloWorld</ejb-name>
      <jndi-name>jndi/helloWorld</jndi-name>
    </ejb>
  </enterprise-beans>
</sun-ejb-jar>

/* Ejb module 2 is identical to this, except that exposed methods and jndi names are for HelloWorld2 rather than HelloWorld */

/* The client application */

public void runHelloWorld(String helloWorldJNDI) {
                try {
                        //log in with user1
                        ProgrammaticLogin pm = new ProgrammaticLogin();
                        pm.login("user1", "user1", "file", false);
                        InitialContext ctx = new InitialContext();
                        Object homeObj = ctx.lookup(helloWorldJNDI);
                        HelloWorldHome hwHome =
                                (HelloWorldHome)PortableRemoteObject.narrow(homeObj,HelloWorldHome.class);
                        HelloWorld hw = hwHome.create();
                        log.info("calling sayHello(\"bert\")... response is: "+hw.sayHello("bert"));
                } catch (Exception e) {
                        log.error("Error in running HelloWorld: ",e);
                }
                
        }

/* I then configure a file domain in glassfish which contains the user ‘user1’, with password ‘user1’ */

This scenario results in the ‘user1’ user being used for the first invocation of ejb 1, but causes a security exception when calling ejb 2:

[#|2010-04-12T08:41:02.437+0100|INFO|sun-appserver2.1|javax.enterprise.system.stream.out|_ThreadID=17;_ThreadName=p: thread-pool-1; w: 6;|
sayHello(myName) caller is user1|#]

 [#|2010-04-12T08:41:02.437+0100|FINE|sun-appserver2.1|javax.enterprise.system.core.security|_ThreadID=17;_ThreadName=p: thread-pool-1; w: 6;ClassName=com.sun.enterprise.security.provider.BasePolicyWrapper;MethodName=doImplies;_RequestID=7e42df6d-2b1c-40f9-b72b-20f14f4c2a3a;|JACC Policy Provider, failed Permission Check

This approach currently works for our application on WAS using IBM’s WSSubject.runAs approach. Is propagation of the caller principle possible on Glassfish in this way?

Thanks,
Rob.
[Message sent by forum member 'slossr']

http://forums.java.net/jive/thread.jspa?messageID=396565