3 Replies Latest reply on Oct 14, 2010 3:19 PM by nlmarco

    stick authentication info to EJB handle?

    nlmarco

      Hello *,

      in our use case, quite a few EJB methods (mostly of stateless session beans) need to communicate with many EJBs on different servers (some on the same server, but then mostly still as different user). Therefore, we want to stick the authentication info to the EJBs, making code like this possible:

      EjbOfPartner ejbOfPartner1 = EjbOfPartnerUtil.getHome(getInitCtxProps(partner1)).create();
      EjbOfPartner ejbOfPartner2 = EjbOfPartnerUtil.getHome(getInitCtxProps(partner2)).create();
      EjbOfPartner ejbOfPartner3 = EjbOfPartnerUtil.getHome(getInitCtxProps(partner3)).create();
      
      ejbOfPartner1.doSomeBusiness(...);
      Result result = ejbOfPartner2.doSomethingElse(...);
      ejbOfPartner1.doSomethingWithResult(result);
      ejbOfPartner3.doWhatever(...);
      // ... and so on ...

      Without this feature, the user of our framework would need to track manually for which EJB handle he needs to be authenticated how; and then login, logout, login, etc. all the time. This makes things extremely error-prone and some code even impossible (e.g. where EJB handles are provided by a factory).

      Already a while ago, I tried to use org.jboss.security.jndi.LoginInitialContextFactory. But after analysing the source-code ('cause it didn't work), I saw that it doesn't really stick the user data to the EJB handle, but instead only performs a login. Hence, in my above example, the calls to ejbOfPartner1 and 2 fail (if the EJBs are on a remote server) or communicate with partner3 instead of 1/2 (if the EJBs are on the same server). This is, because the user required for partner3 is logged in globally (for all EJB handles) after the last EjbOfPartnerUtil.getHome(...).create().

      Therefore, I hacked a workaround consisting of an InitialContextFactory, a Context and an Interceptor. This seemed to work fine for JBoss 3.2.x (not sure anymore, but I think it was 3.2.5). Unfortunately, I didn't work on the code requiring this feature for quite a while and didn't recognize that it broke some time ago.

      You can find details for my workaround here, btw.:
      * source
      * wiki page
      * issue tracking

      Now, I need to get it running again, and I was already extremely happy when I saw the new org.jboss.security.jndi.JndiLoginInitialContextFactory which seemed (according to the wiki page) to do exactly what I need.

      Unfortunately, however, it doesn't :-( and actually behaves in the same wrong way as my workaround does. I tried to set the flags jnp.restoreLoginIdentity and jnp.multi-threaded, but it didn't help. What am I doing wrong? Doesn't JndiLoginInitialContextFactory support what I need?

      Well, I thought I'll take a look at my workaround again and I saw that the org.jboss.invocation.InvocationContext which I use to pass my auth info, is somehow reused for different EJB handles pointing to different partners (maybe there's a new caching feature?). This leads to wrong authentications :-( Maybe I should add, that multiple partners can be hosted on the same machine and thus connections to different partners can sometimes go to the same server (even locally, i.e. loopback).

      Is there an easy way to do what I want? Maybe using JndiLoginInitialContextFactory correctly (in case I'm doing this wrong) or using another InitialContextFactory (which one?)... any ideas?

      If there's no such solution, can you give me hints on how I can pass the information from my own InitialContextFactory to an interceptor?

      Or is there a totally different and better way to achieve this? Maybe EJB3?

      Thanks a lot in advance!

      Best regards, Marco :-)

        • 1. Re: stick authentication info to EJB handle?
          nlmarco

          After some further investigation, I saw sth. very interesting:

          EjbOfPartnerHome home1 = EjbOfPartnerUtil.getHome(getInitCtxProps(partner1));
          EjbOfPartner ejbOfPartner1 = home1.create();
          EjbOfPartnerHome home2 = EjbOfPartnerUtil.getHome(getInitCtxProps(partner2));
          EjbOfPartner ejbOfPartner2 = home2.create();
          EjbOfPartnerHome home3 = EjbOfPartnerUtil.getHome(getInitCtxProps(partner3));
          EjbOfPartner ejbOfPartner3 = home3.create();

          Even though, home1, home2 and home3 are all different objects, the above create() methods return every time the same instance of EjbOfPartner - i.e. ejbOfPartner1 == ejbOfPartner2 == ejbOfPartner3. And this happens, even though my initial-context-properties are different! To be more precise, these properties look like this:
          Properties props = new Properties();
          props.put(InitialContext.INITIAL_CONTEXT_FACTORY, initialContextFactory);
          props.put(InitialContext.PROVIDER_URL, initialContextURL);
          props.put(InitialContext.SECURITY_PRINCIPAL, username);
          props.put(InitialContext.SECURITY_CREDENTIALS, password);
          props.put(InitialContext.SECURITY_PROTOCOL, "jfire");

          The two properties InitialContext.SECURITY_PRINCIPAL and InitialContext.SECURITY_CREDENTIALS differ while the others are the same.

          Is there any possibility to force JBoss to create different EJBs for different initial-context-properties? That might already solve my problem.

          Best regards, Marco :-)

          • 2. Re: stick authentication info to EJB handle?
            nlmarco

            Yabbadabbado!!! It's working again!!!

            My client-interceptor checks now, whether the returned Proxy is already tagged with other user-data. If yes, I clone it via serialization and deserialization. The user thus gets a clone which is tagged correctly and everything seems to work fine.

            But this all isn't perfect and I'd really appreciate it, if someone can provide a clean solution - in case there is.

            Best regards, Marco :-)

            • 3. Re: stick authentication info to EJB handle?
              nlmarco

              Hello again,

               

              I just wanted to let you know that I found a much better and cleaner solution, already quite a while ago: I wrap the resulting EJB which I got from JNDI into another proxy which does a login/logout around invoking the EJB. To achieve this, we use a custom InitialContextFactory and custom contexts. The source codes (in case you're interested) can be seen here (they're LGPL):

               

              https://svn.nightlabs.org/svn/main/tags/jfire_1.0.1/org.nightlabs.unifiedjndi.jboss.client/src/org/nightlabs/unifiedjndi/jboss/client/

               

              Best regards, Marco