14 Replies Latest reply on Feb 11, 2013 3:34 AM by sebbay

    Local lookup with user authentication

    fernando.rubbo

      Hi,

       

      I'm migrating our ERP from JBoss 4.2 to JBoss 7.1.1. Although I got blocked trying to make a lookup of an local interface of a EJB.

       

      Let me explain with the attachement. In LookupTest.zip I have 3 eclipse projects:

      • LookupTestEJB
        • com.test.ejb.Calculator - the local interface
        • com.test.ejb.CalculatorBean - the ejb stateless

      @Local(Calculator.class)

      @Stateless

      @SecurityDomain("test")                      

      public class CalculatorBean implements Calculator {

             ....

        • com.test.security.TestLoginModule - a very simple UsernamePasswordLoginModule
      • LookupTestWAR
        • index.jsp - with the code of the lookup into it

      try

      {

        Hashtable<Object, Object> env = new Hashtable();

        env.put(Context.SECURITY_PRINCIPAL, "Micke");

        env.put(Context.SECURITY_CREDENTIALS, "123");

       

        ??????? WHAT SHOULD I PUT HERE ????????

       

        InitialContext context = new InitialContext(env);

        Calculator c = (Calculator)context.lookup("java:app/LookupTestEJB/CalculatorBean!com.test.ejb.Calculator");

        out.println("<p>class: " + c);

        out.println("<p>principal: " + c.getCallerName());

        out.println("<p>add(10,34): " + c.add(10, 34));       

      }

      catch(NamingException e)

      {

        e.printStackTrace();

      }

      • LookupTestEJBEAR
        • just to pack the above projects into an ear

       

      Beside this I've attached the standalone.xml configuration. Which is the original one with following difference.

              <subsystem xmlns="urn:jboss:domain:security:1.2">

                  <security-domains>

                      <security-domain name="test" cache-type="default">

                          <authentication>

                              <login-module code="com.test.security.TestLoginModule" flag="requisite"/>

                          </authentication>

                      </security-domain>

                      ....

       

      So, let's go back to the issue.

       

      If you look at the code you will see I'm trying to look up a local interface.. So, I can NOT replace the red mark above with the following lines:

       

              env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");

      env.put(Context.PROVIDER_URL, "remote:/localhost:4447");

      env.put("jboss.naming.client.ejb.context", true);

       

      However, I would like to get logged in into the EJB container with the user 'Micke' because I'm using the method ctx.getCallerPrincipal() in my EJB CalculatorBean. Note that without the login it will always return 'anonymous'. So the behaviour will be differente between a remote client and a local client.

       

      It is important to say that In jboss 4.2 this works as expected using the below lines. However, I know jboss 7 does not support this solution anymore.

       

      env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory");

      env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");

       

      So, THE QUESTION IS:

           What should I do to have the same behaviour in remote and local clients?

           Or being more specific. What should I do to get 'Micke' authenticated into the containar even when it uses a local interface? 

           Or what shoud I put in the red mark above?

       

      Thanks in advance,

      Fernando Rubbo

        • 1. Re: Local lookup with user authentication
          dmlloyd

          You can't use a remote JNDI context to perform a local JNDI lookup.  Why not simply use @Resource or @EJB to inject the EJB?

          • 2. Re: Local lookup with user authentication
            fernando.rubbo

            First of all, thanks for your response

             

            Second,

             

            The idea is not using a remote JNDI context to perform a local JNDI lookup. The idea is to perform a local jndi lookup with user authentication.

             

            The issue we are facing is that we are migrating from jboss 4.3 to jboss 7. But we are not able to have the same behaviour we had before. This is one of our cases: In our app all EJB calls must have an user logged in to check it he/she/it has enough privileges for that call. Currently our app supports calls from the web container through local lookups, calls from external apps through WS facades and calls from external apps through remote lookups. In all these cases we are able to authenticate the user and get the caller principal (what is mandatory for us).

             

            So... how in jboss 7 we could perform this 3 option of calls and still getCallerPrincipal() correctly?

            • 3. Re: Local lookup with user authentication
              sfcoy

              If the user has already "logged in" using form or basic authentication then their user Principal should be propogated automatically to your local EJB.

               

              ie. if request.getUserPrincipal() returns a valid object then you should see a corresponding Principal object from EJBContext.getCallerPrincipal().

               

              Therefore you only need to use the "no parameters" constructor for your new InitialContext() call.

              1 of 1 people found this helpful
              • 4. Re: Local lookup with user authentication
                dlofthouse

                As with previous AS releases if you need to switch users before calling the an EJB from a Web application define a security domain that contains only the ClientLoginModule then create a LoginContext for that domain and login with a callback handler that supplies the username and password as desired - after the EJB call ensure you logout of the LoginContext.

                1 of 1 people found this helpful
                • 5. Re: Local lookup with user authentication
                  fernando.rubbo

                  Thanks Darran and Stephen for your responses, but I think I've forgotten two other important scenarios:

                  1. The people which developed the authentication has implemented their own loggin method. :-(
                    1. But may be a good idea refactor the app for using BASIC auth. I will be checking how much work it is.
                  2. There is another local lookup which the "user" will not be authenticated. This case happens whenever a quartz job is fired. So, the user used is the one which has registred the job. In this case, we are inside of the container and do not have the user logged in yet. So, for me it seems we still need a local lookup authentication in this situation.
                  3. Another case is when a user impersonate another user.
                    1. We have implemented this changing the user at local EJB lookup time

                   

                  Darran, do you have an example of code or a link where I could look at it?

                  • 6. Re: Local lookup with user authentication
                    sfcoy

                    Hi Fernando,

                     

                    1. As you are now running in a JEE6 container, you can take advantage of some additions to the servlet api to make this "fix" a lot easier, namely javax.servlet.http.HttpServletRequest#login(java.lang.String,%20java.lang.String). The custom authentication code can call this to establish a security context for your application.
                    2. The quartz job may be a tricky migration task as these actually run "outside" of the container in their own thread. Local EJB lookups may not work as expected. Consider migrating this functionality to EJB timers.
                    3. An authentication demo can be found at Testing secured EJBs on JBoss AS7.1.x with Arquillian which demonstrates how you could solve this issue. The same strategy would be required for your timer tasks.
                    • 7. Re: Local lookup with user authentication
                      sebbay

                      Hello I'm facing the same problem.

                      When trying the solution with the LoginContext, I am able to lookup the ejb. But while invoking a method of this ejb, the security principal is empty.    

                             

                      LoginContext loginContext = JBossLoginContextFactory.createLoginContext("user", "password");

                      loginContext.login();

                       

                       

                      Subject.doAs(loginContext.getSubject(), new PrivilegedAction<String>()

                      {

                        @Override

                        public String run()

                        {

                          try

                          {

                            InitialContext initialContext = new InitialContext();

                            Object obj;

                            obj = initialContext.lookup("java:app/ejb_package_name/EJBManager!com.test.EJBManager");

                            EJBManager remoteInterface = (EJBManager) obj;

                            remoteInterface.createSession(DUMMY_DEBUG_LEVEL);

                          }

                          catch (Exception e)

                          {

                            e.printStackTrace();

                          }

                          return "";

                        }

                      });

                       

                       

                      I used JBossLoginContextFactory from here: https://github.com/sfcoy/demos/blob/master/arquillian-security-demo/src/test/java/org/jboss/arquillian/secureejb/JBossLoginContextFactory.java.

                       

                      Has someone a solution for this problem?

                       

                      Best regards,

                      Sebastian

                      • 8. Re: Local lookup with user authentication
                        sfcoy

                        Any particular reason you're using a remote interface?

                        • 9. Re: Local lookup with user authentication
                          sebbay

                          I need to access the ejb's by a remote client and also inside the EAR.

                          • 10. Re: Local lookup with user authentication
                            fernando.rubbo

                            Hi,

                             

                             

                            Due to my vacations and due to other priorities I could get back to this issue only now.

                             

                            So, let me explain what I'm trying to do and what I'm facing. To simplify this I've added two pictures:

                             

                            • jboss4-currentsolution.jpg

                            This picture shows our current solution. In this solution it is possible to see that our ERP, writting in JavaEE, does not use any standard auth method when requests came from web pages. Another important point to highlight is that all EJB calls requires a principal to be looged in. Currently we use local ejb lookups passing user/pass and WS call passining http header Authenticaiton: basic user/pass. Jboss works accordingly and only users logged in can access services deployed in the container EJB.

                             

                            • jboss7-help.jpg

                            This picture shows what we are trying to do. As it was discussed in this thread, JBoss 7 does not accept local call passing user/pass anymore. So we need to change our strategy to login into the container web using FORM Based. Doing this, there is no need to pass user/password at lookup time once the container knows which principal is logged in. However, we are facing an issue in all WS calls, once they do not understand FROM auth.

                             

                            I've modified the color in this picture to show what we have changed.

                             

                             

                            The question is: Is there a way to configure the container WEB to use FORM based authentication and still keep receiving those WS calls? If not. What do you suggest?

                             

                            I was thinking to create another package (for example, ws.war) in which we could put BASIC authentication. But I do not like this solution. Seems to be a hack.

                             

                            Another important point is that the WS client MUST NOT be impacted once we do not have control of the other teams deadlines and/our deployments.

                             

                            Thankyou guys for your help

                            Fernando Rubbo

                            • 11. Re: Local lookup with user authentication
                              sebbay

                              Hey Fernando,

                               

                              Have you got a solution for this issue?

                               

                              Regards,

                              Sebastian

                              • 12. Re: Local lookup with user authentication
                                fernando.rubbo

                                Hi Sebastian,

                                 

                                Unfortunatly no. The only solution we found it rewrite the login strategy of our app. However, we foud it be much more complex than we were expecting. So, we are planning to refactory the whole app because of this. But it will take months.

                                 

                                Good luck

                                • 13. Re: Local lookup with user authentication
                                  penczek

                                  I'm facing basicaly the same problem, the old org.jboss.security.jndi.JndiLoginInitialContextFactory was a fantastic feature to allow a  programatic "runas" for Quartz, socket servers, and everything that runs on JBoss but is not in EJB scope.

                                  I've found a "solution" here:

                                  - I've changed my local interface to remote, just changing @Local to @Remote;

                                  - MyEJBImpl is annotated with @org.jboss.ejb3.annotation.SecurityDomain("other")

                                  - And change the code below:

                                  Hashtable<String, String> env = new Hashtable<String, String>();
                                  env.put(Context.SECURITY_PRINCIPAL, this.user);
                                  env.put(Context.SECURITY_CREDENTIALS, this.password);
                                  env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.JndiLoginInitialContextFactory");
                                  env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
                                  env.put("jnp.disableDiscovery", Boolean.TRUE.toString());
                                  MyEJBLocal ejb = (MyEJBLocal) new InitialContext(env).lookup("/MyEJBImpl/local");
                                  ejb.doSomeMethod();
                                  

                                   

                                  for something like that:

                                  Properties env = new Properties();
                                  env.put(Context.URL_PKG_PREFIXES,"org.jboss.ejb.client.naming");
                                  MyEJBLocal ejb = (MyEJBLocal) new InitialContext(env).lookup("ejb:MyEAR/MyEJBJar//MyEJBImpl!com.xxx.MyEJBLocal");
                                  JBossSecurityContext jsc = new JBossSecurityContext("other"); // the same security domain as defined in @SecurityDomain on EJB
                                  SecurityContextAssociation.setSecurityContext(jsc);
                                  SecurityContextAssociation.setPrincipal(new Principal() {
                                            @Override
                                            public String getName() {
                                                      return user;
                                            }
                                  });
                                  SecurityContextAssociation.setCredential(this.password);
                                  ejb.doSomeMethod();
                                  
                                  • 14. Re: Local lookup with user authentication
                                    sebbay

                                    Hey,

                                     

                                    That's it. If I add these lines to my code, it works fine!

                                     

                                    Regards,

                                    Sebastian