Ok, here we go...

Step 1: use a RealmIdentifierInterceptor like this (I've removed a few quirks 
which were specific to our solution):


/**
 * This incerceptor intercepts calls to SessionBeans which have been annotated
 * appropriately. It determines the principal issuing the request and identifies
 * the target realm. It then injects the EntityManager for the chosen realm.
 * 
 * @author Jörg Henne
 */
public class RealmIdentifierInterceptor {
        private static final Logger logger = Logger
                        .getLogger(RealmIdentifierInterceptor.class);

        private static final String EM_JNDI_PREFIX = "java:/EntityManagers/";

        /**
         * A cache of injectors, indexed by class.
         */
        private Map<Class, Field> fieldCache = new HashMap<Class, Field>();

        @Resource
        javax.ejb.SessionContext sctx;

        @AroundInvoke
        public Object identifyRealm(InvocationContext ctx) throws Exception {
                Field field = getFieldForInjection(ctx.getBean().getClass());
                if (null != field) {
                        Principal callerPrincipal = sctx.getCallerPrincipal();
                        if (null == callerPrincipal)
                                throw new EJBAccessException(
                                                "No caller principal to detect 
the realm name from");

                        String realmName = 
getRealmName(callerPrincipal.getName());

                        try {
                                logger.debug("Injecting EM for realm " + 
realmName + " during call to "
                                                + ctx.getBean());

                                String emName = EM_JNDI_PREFIX + realmName;
                                EntityManager em = (EntityManager) new 
InitialContext().lookup(emName);

                                field.set(ctx.getBean(), em);
                        } catch (NamingException e) {
                                throw new EJBAccessException("Realm " + 
realmName + " not found");
                        }
                }
                return ctx.proceed();
        }

        /**
         * Extract Realm name from Windows-style realm\\username pattern.
         * 
         * @param principalName
         * 
         * @return
         */
        private String getRealmName(String principalName) {
                int idx = principalName.indexOf('\\');
                if (idx <= 0)
                        throw new EJBAccessException("Can't parse the principal 
name "
                                        + principalName);
                
                return principalName.substring(0,idx);
        }

        /**
         * Get the injector for the given class. Returns null, if the
         * class doesn't declare a field annotated with
         * 
         * @RealmBasedPersistenceContext.
         * 
         * @param clazz
         * @return
         */
        private Field getFieldForInjection(Class<? extends Object> clazz) {
                // a null injector is possible and idicates a class which 
declared
                // this interceptor, but doesn't declare a field annotated with
                // @RealmBasedPersistenceContext.
                if (fieldCache.containsKey(clazz))
                        return fieldCache.get(clazz);

                Field[] fields = clazz.getDeclaredFields();
                for (int i = 0; i < fields.length; i++) {
                        Field field = fields[ i ];
                        RealmBasedPersistenceContext annotation = field         
                .getAnnotation(RealmBasedPersistenceContext.class);

                        if (null != annotation) {
                                logger.info("Found field for EntityManager 
injection: " + field
                                                + " on " + 
field.getDeclaringClass());

                                field.setAccessible(true);
                                fieldCache.put(clazz, field);
                                return field;
                        }
                }

                logger.warn("Class " + clazz
                                + " is annotated with 
@RealmIdentifierInterceptor bit doesn't "
                                + "declare a field annotated with 
@RealmBasedPersistenceContext");

                // nothing found - put null map entry to indicate invalid class
                fieldCache.put(clazz, null);
                return null;
        }
}


Step 2: Define the following annotation interface:


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RealmBasedPersistenceContext {
}


Step 3: 


Annotate your session beans with 
@Interceptors({RealmIdentifierInterceptor.class})
and your EntityManager field with @RealmBasedPersistenceContext


A simple bean would thus look like this:


@Stateless
@Interceptors({RealmIdentifierInterceptor.class})
public class YadaBean implements Yada {

        private static final Logger logger = Logger
                        .getLogger(AccountAdminDAOBean.class);

        @RealmBasedPersistenceContext
        private EntityManager em;

     ...
}


Step 4: Implement a custom login module which is able to deal with principal 
names using the pattern realmName/userName. 

Our solution is rather complicated in this area, insofar as we subclassed a 
specialized Principal from SimplePrincipal which parses the compound 
realmName/userName into its separate parts. The customized LoginModule  
converts an incoming SimplePrincipal into the specialized one, but clients are 
preferred to supply the specialized one directly, if possible.

The problem with this solution is that that the JBoss login mechanism with 
ClientLoginModule and the server-side handling silently dump the specialized 
Principal instance and replace it with a simple one again. Therefore it is 
easier to just stick with SimplePrincipals and deal with the compound principal 
name in your LoginModule.

Step 5: Implement an EJB which lists the configured realms from JNDI like this:


@Stateless
public class RealmListServiceBean implements RealmListService {
        /*
         * (non-Javadoc)
         * 
         * @see de.hess.zas.business.RealmListService#listRealmNames()
         */
        public List listRealmNames() throws NamingException {
                NamingEnumeration name = new InitialContext()
                                .list("java:/EntityManagers");
                List results = new ArrayList();
                while (name.hasMoreElements()) {
                        results.add(name.next().getName());
                }

                return results;
        }
}


In order to make this work, you have to grant access to this bean to 
unauthenticated users, obviously. There are several ways to do this:

Deploy the bean outside the security domain
Except the bean from security
Allow logon using a special guest user (that's our solution)



I hope, this explanation was helpful.

Joerg Henne

View the original post : 
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3952942#3952942

Reply to the post : 
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3952942

Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
JBoss-user mailing list
JBoss-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jboss-user

Reply via email to