9 Replies Latest reply on Jun 19, 2004 12:00 AM by Scott Stark

    JAAS bug or tomcat integration?

    Eleas Newbie

      Please explain me.
      I encounter with one interesting bug which prevent me from further development. Please, help me! I wrote test page. You can use it to understand the problem:

      <%@ page import="org.jboss.security.SecurityAssociation,
       java.io.PrintWriter,
       javax.security.auth.Subject,
       java.security.PrivilegedExceptionAction,
       java.security.AccessControlContext,
       java.security.AccessController,
       javax.security.auth.login.LoginContext,
       javax.security.auth.login.LoginException,
       java.util.HashMap,
       java.io.IOException,
       javax.security.auth.callback.*"%><html>
      <head>
      <title>
      Security Test
      </title>
      </head>
      <body>
      <%!
       private HashMap map = new HashMap();
       public class MyCallbackHandler implements CallbackHandler
      {
       private String name = null;
       private String password = null;
      
       public MyCallbackHandler(String name, String password)
       {
       this.name = name;
       this.password = password;
       }
      
       public void handle(Callback[] callbacks)
       throws IOException, UnsupportedCallbackException
       {
       for (int i = 0; i < callbacks.length; i++)
       {
       Callback callback = callbacks;
       if(callback instanceof PasswordCallback)
       {
       PasswordCallback pc = (PasswordCallback) callback;
       pc.setPassword(password.toCharArray());
       }
       else if(callback instanceof NameCallback)
       {
       NameCallback nc = (NameCallback) callback;
       nc.setName(name);
       }
       }
       }
       }
       public Subject getSubject(String user, String password) throws LoginException
       {
       Subject ret = (Subject) map.get(user);
       if (ret==null)
       {
       LoginContext lc = new LoginContext("!YOURDOMAIN!",new MyCallbackHandler(user,password));
       lc.login();
       ret = lc.getSubject();
       map.put(user,ret);
       }
       return ret;
       }
       %>
       Curent sycurity:<br>
       request.getUserPrincipal() <%=request.getUserPrincipal()%><br>
       SecurityAssociation.getPrincipal() <%=SecurityAssociation.getPrincipal()%><br>
       SecurityAssociation.getPrincipal().getClass() <%=SecurityAssociation.getPrincipal().getClass()%><br>
       SecurityAssociation.getSubject() <%=SecurityAssociation.getSubject()%><br>
       doAs internal:<br>
       <%final JspWriter outWriter = out;
       Subject.doAs(getSubject("guest","guest"),new PrivilegedExceptionAction()
       {
       public Object run() throws Exception
       {
       outWriter.println("SecurityAssociation.getPrincipal() "+SecurityAssociation.getPrincipal()+"<br>");
       outWriter.println("SecurityAssociation.getPrincipal().getClass() "+SecurityAssociation.getPrincipal().getClass()+"<br>");
       outWriter.println("SecurityAssociation.getSubject() "+SecurityAssociation.getSubject()+"<br>");
       return null;
       }
       });
       %>
       Curent sycurity:<br>
       request.getUserPrincipal() <%=request.getUserPrincipal()%><br>
       SecurityAssociation.getPrincipal() <%=SecurityAssociation.getPrincipal()%><br>
       SecurityAssociation.getPrincipal().getClass() <%=SecurityAssociation.getPrincipal().getClass()%><br>
       SecurityAssociation.getSubject() <%=SecurityAssociation.getSubject()%><br>
       doAsPrincipal<br>
       <%
       Subject.doAsPrivileged(getSubject("internal","internal"),new PrivilegedExceptionAction()
       {
       public Object run() throws Exception
       {
       outWriter.println("SecurityAssociation.getPrincipal() "+SecurityAssociation.getPrincipal()+"<br>");
       outWriter.println("SecurityAssociation.getPrincipal().getClass() "+SecurityAssociation.getPrincipal().getClass()+"<br>");
       outWriter.println("SecurityAssociation.getSubject() "+SecurityAssociation.getSubject()+"<br>");
       return null;
       }
       },AccessController.getContext());
       %>
      
       </body>
       </html>
      


      Where:
      !YOURDOMAIN! - your security domain - please change it!
      Also JSP use users principals fro "guest" with password "guest" and "internal" with password "internal". You can change this users names too to fit your users set.

      And as a result of JSP I got:
      Curent sycurity:
      request.getUserPrincipal() phantom
      SecurityAssociation.getPrincipal() phantom
      SecurityAssociation.getPrincipal().getClass() class
      XXX.security.UserPrincipal
      SecurityAssociation.getSubject() Subject: Principal: phantom
      Principal: Roles(members:all(members),administrators(members),phantom,administrators(members))
      doAs internal:
      SecurityAssociation.getPrincipal() phantom
      SecurityAssociation.getPrincipal().getClass() class XXX.security.UserPrincipal
      SecurityAssociation.getSubject() Subject: Principal: phantom
      Principal: Roles(members:all(members),administrators(members),phantom,administrators(members))
      Curent sycurity:
      request.getUserPrincipal() phantom
      SecurityAssociation.getPrincipal() phantom
      SecurityAssociation.getPrincipal().getClass() class XXX.security.UserPrincipal
      SecurityAssociation.getSubject() Subject: Principal: phantom
       Principal: Roles(members:all(members),administrators(members),phantom,administrators(members))
      doAsPrincipal
      SecurityAssociation.getPrincipal() phantom
      SecurityAssociation.getPrincipal().getClass() class XXX.security.UserPrincipal
      SecurityAssociation.getSubject() Subject: Principal: phantom
       Principal: Roles(members:all(members),administrators(members),phantom,administrators(members))
      

      where XXX - mypackages and my custom user principal and "phantom" my user principal which i used to logon to the system.
      And as you can see: doAs didn't effect SecurityAssociation!!! Please help me! I need in doAs because we store users paramters by entity EJB and I need to have access to this EJBs from LoginModule and I think to use "internal" user to resolve this problem! Also we need to use SecurityAssociation because in our code a lot of simple java classes (not EJB or JSP pages) where we use user principals.


        • 1. Re: JAAS bug or tomcat integration?
          Scott Stark Master

          We don't use the JAAS Subject based authorization mechanism initiated via Subject.doAs. Read the JAAS howto at the start of the forum to see how JAAS is used.

          • 2. Re: JAAS bug or tomcat integration?
            Eleas Newbie

            Sorry, but may be I'm a fool, but I didn't find how I can execute some particular code under different principal:-( I found method SecurityAssociation.pushRunAsRole(), but it seems that this method doesn't have a effect: SecurityAssociation.getPrincipal before and after returns the same principal.

            Or please help me to resolve such problem: I want to use my entity EJBs in my particular LoginModule? Question is: when I try to invoke some method of ent.ejb from LoginModule I get SecurityException. And there is no surprise because I don't authentificate yet. To resolve this problem I used Subject.doAs methodology in weblogic server, but after switching to JBOSS server this method don't work and I'm confused and I can't find any approapriate method in JBOSS. Please help me! I read a lot of information regarding this problem in JBOSS, but I don't see a solution:(

            • 3. Re: JAAS bug or tomcat integration?
              sys user Master

              Are you sure that there is information on role substitution in the HOWTO? Unfortunately, I couldn't find it there. I've implemented basic login in my system (this is described in the howto), but I can't get know how should I substitute internal user (if I can't use doAs).

              Can you post a simple example of solving this problem?

              • 4. Re: JAAS bug or tomcat integration?
                Scott Stark Master

                Executing code with an identity inside the server is no different than a java client outside of the server. You have to establish the caller identity with a JAAS login that uses a login configuration that includes the jboss org.jboss.security.ClientLoginModule login module, as the client-login configuration entry in the conf/login-config.xml does. Here is an unsecured servlet doing a JAAS login to call a secured EJB as jduke.

                package org.jboss.test.web.servlets;
                
                import java.io.IOException;
                import java.io.PrintWriter;
                import java.security.Principal;
                import javax.naming.InitialContext;
                import javax.naming.NamingException;
                import javax.servlet.ServletConfig;
                import javax.servlet.ServletException;
                import javax.servlet.http.HttpServlet;
                import javax.servlet.http.HttpServletRequest;
                import javax.servlet.http.HttpServletResponse;
                import javax.security.auth.login.LoginContext;
                import javax.security.auth.login.LoginException;
                
                import org.jboss.security.auth.callback.UsernamePasswordHandler;
                import org.jboss.test.web.interfaces.StatelessSession;
                import org.jboss.test.web.interfaces.StatelessSessionHome;
                
                /** A servlet that performs a JAAS login to access a secure EJB.
                
                @author Scott.Stark@jboss.org
                @version $Revision: 1.2 $
                */
                public class ClientLoginServlet extends HttpServlet
                {
                 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                 throws ServletException, IOException
                 {
                 LoginContext lc = null;
                 String echoMsg = null;
                 try
                 {
                 lc = doLogin("jduke", "theduke");
                 InitialContext ctx = new InitialContext();
                 StatelessSessionHome home = (StatelessSessionHome) ctx.lookup("java:comp/env/ejb/SecuredEJB");
                 StatelessSession bean = home.create();
                 echoMsg = bean.echo("ClientLoginServlet called SecuredEJB.echo");
                 }
                 catch(LoginException e)
                 {
                 throw new ServletException("Failed to login to client-login domain as jduke", e);
                 }
                 catch(Exception e)
                 {
                 throw new ServletException("Failed to access SecuredEJB", e);
                 }
                 finally
                 {
                 if( lc != null )
                 {
                 try
                 {
                 lc.logout();
                 }
                 catch(LoginException e)
                 {
                 }
                 }
                 }
                
                 response.setContentType("text/html");
                 PrintWriter out = response.getWriter();
                 out.println("<html>");
                 out.println("<head><title>ClientLoginServlet</title></head>");
                 out.println("<h1>ClientLoginServlet Accessed</h1>");
                 out.println("<body>Login as user=jduke succeeded.<br>SecuredEJB.echo returned:"+echoMsg+"</body>");
                 out.println("</html>");
                 out.close();
                 }
                
                 protected void doGet(HttpServletRequest request, HttpServletResponse response)
                 throws ServletException, IOException
                 {
                 processRequest(request, response);
                 }
                
                 protected void doPost(HttpServletRequest request, HttpServletResponse response)
                 throws ServletException, IOException
                 {
                 processRequest(request, response);
                 }
                
                 private LoginContext doLogin(String username, String password)
                 throws LoginException
                 {
                 UsernamePasswordHandler handler = new UsernamePasswordHandler(username, password.toCharArray());
                 LoginContext lc = new LoginContext("client-login", handler);
                 lc.login();
                 return lc;
                 }
                }
                
                



                • 5. Re: JAAS bug or tomcat integration?
                  Eleas Newbie

                  It seems that your example don't work (JBOSS 3.2.3 +Tomcat 4).

                  Code from unsecured page:

                  <%@ page import="javax.security.auth.login.LoginContext,
                   org.jboss.security.auth.callback.UsernamePasswordHandler,
                   org.jboss.security.SecurityAssociation,
                   javax.security.auth.Subject,
                   java.security.PrivilegedAction,
                   java.io.IOException,
                   XXX.core.DBHelper,
                   XXX.ejb.core.XXXObjectHome"%>
                  <%=SecurityAssociation.getPrincipal()%>
                  <%
                   LoginContext lc = new LoginContext("my-domain",new UsernamePasswordHandler("internal","internal"));
                   lc.login();
                  %>
                  <%=request.getUserPrincipal()%>
                  <%=SecurityAssociation.getPrincipal()%>
                  <%
                   XXXObjectHome XXObjectHome = DBHelper.getInstance().getXXXObjectHome();
                   XXXObjectHome.findByPath("system/object").getName();
                   lc.logout();
                  %>
                  


                  returns me in logs:

                  2004-04-05 17:10:30,835 ERROR [org.jboss.ejb.plugins.LogInterceptor] EJBExceptio
                  n, causedBy:
                  java.lang.SecurityException: Authentication exception, principal=null
                   at org.jboss.ejb.plugins.SecurityInterceptor.checkSecurityAssociation(Se
                  curityInterceptor.java:164)
                   at org.jboss.ejb.plugins.SecurityInterceptor.invokeHome(SecurityIntercep
                  tor.java:81)
                   at org.jboss.ejb.plugins.LogInterceptor.invokeHome(LogInterceptor.java:1
                  20)
                   at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invokeHome(ProxyF
                  actoryFinderInterceptor.java:93)
                   at org.jboss.ejb.EntityContainer.internalInvokeHome(EntityContainer.java
                  :483)
                   at org.jboss.ejb.Container.invoke(Container.java:720)
                   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
                  java:39)
                   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
                  sorImpl.java:25)
                   at java.lang.reflect.Method.invoke(Method.java:324)
                   at org.jboss.mx.capability.ReflectedMBeanDispatcher.invoke(ReflectedMBea
                  nDispatcher.java:284)
                   at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:546)
                   at org.jboss.invocation.local.LocalInvoker.invoke(LocalInvoker.java:101)
                   at org.jboss.invocation.InvokerInterceptor.invoke(InvokerInterceptor.jav
                  a:90)
                   at org.jboss.proxy.TransactionInterceptor.invoke(TransactionInterceptor.
                  java:46)
                   at org.jboss.proxy.SecurityInterceptor.invoke(SecurityInterceptor.java:4
                  5)
                   at org.jboss.proxy.ejb.HomeInterceptor.invoke(HomeInterceptor.java:173)
                   at org.jboss.proxy.ClientContainer.invoke(ClientContainer.java:85)
                   at $Proxy43.findByPath(Unknown Source)
                   at org.apache.jsp.sec_jsp._jspService(sec_jsp.java:64)
                   at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:137)
                   at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
                  
                  


                  But I have user internal/internal!
                  Please help me!

                  • 6. Re: JAAS bug or tomcat integration?
                    Scott Stark Master

                    You have modified the example to use the "my-domain" login configuration instead of the "client-login". As described in the JAAS howto the name passed to the LoginContext maps to the server side login-config.xml login module configuration entry that will be used for authentication. The preconfigured entry which includes the org.jboss.security.ClientLoginModule is named "client-login". The ClientLoginModule must be included in any configuration called by code doing a JAAS login that wants the security context to propagate with the thread.

                    • 7. Re: JAAS bug or tomcat integration?
                      Eleas Newbie

                      Thank you Scott!!!

                      • 8. Re: JAAS bug or tomcat integration?
                        Eleas Newbie

                        Please, tell me: is it real to restore previous login principals after lc.logout()? It seems that ClientLoginModule clearing up all Security Associations after logout. We need to have "principal stacking" possibility.

                        • 9. Re: Security and Message Driven Beans
                          Scott Stark Master

                          I got the same problem when using unauthenticatedIdentity=nobody in auth.conf (also with message driven beans). When I don't use this anonymous user the login fails which I suspect it to. But what I find strange is that it doesn't even get to the login method with unauthenticatedIdentity. btw I'm using a subclass of UsernamePasswordLoginModule.

                          Here's the exception:

                          [Default] New Client Connection accepted. Current Thread=Thread[OIL Worker,5,JB
                          ossMQ Server Threads]
                          [Default] Client Connection set spyDistributedConnection, ClientID=ID2. Current
                          Thread=Thread[OIL Worker,5,JBossMQ Server Threads]
                          [Default] ConnectionReceiver: Receive(ReceiveRequest[1])
                          [Default] SpyConnectionConsumer:Topic@testTopic->addMessage(mes=TextMessage@ tes
                          t message nr0 and type JMS)
                          [Default] SpyConnectionConsumer:Topic@testTopic->processMessages()
                          [Default] SpyConnectionConsumer:Topic@testTopic Starting the ServerSession.
                          [Default] SpySession: run()
                          [MDB] Insufficient method permissions, principal=null, method=onMessage, require
                          dRoles=[]
                          [Container factory] Exception in JMSCI message listener: : java.rmi.RemoteExcept
                          ion: checkSecurityAssociation; nested exception is:
                          java.lang.SecurityException: Insufficient method permissions, principal=
                          null, method=onMessage, requiredRoles=[]
                          [Default] java.rmi.RemoteException: checkSecurityAssociation; nested exception i
                          s:
                          java.lang.SecurityException: Insufficient method permissions, principal=
                          null, method=onMessage, requiredRoles=[]
                          [Default] java.lang.SecurityException: Insufficient method permissions, principa
                          l=null, method=onMessage, requiredRoles=[]
                          [Default] at org.jboss.ejb.plugins.SecurityInterceptor.checkSecurityAssoci
                          ation(SecurityInterceptor.java:215)
                          [Default]
                          [Default] at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInte
                          rceptor.java:117)
                          [Default]
                          [Default] at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.ja
                          va:195)
                          [Default]
                          [Default] at org.jboss.ejb.MessageDrivenContainer.invoke(MessageDrivenCont
                          ainer.java:281)
                          [Default]
                          [Default] at org.jboss.ejb.plugins.jms.JMSContainerInvoker.invoke(JMSConta
                          inerInvoker.java:150)
                          [Default]
                          [Default] at org.jboss.ejb.plugins.jms.JMSContainerInvoker$MessageListener
                          Impl.onMessage(JMSContainerInvoker.java:495)
                          [Default]
                          [Default] at org.jbossmq.SpyMessageConsumer.deliverMessage(SpyMessageConsu
                          mer.java:296)
                          [Default]
                          [Default] at org.jbossmq.SpySession.run(SpySession.java:218)
                          [Default]
                          [Default] at org.jboss.jms.asf.StdServerSession.run(StdServerSession.java:
                          132)
                          [Default]
                          [Default] at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(Po
                          oledExecutor.java:642)
                          [Default]
                          [Default] at java.lang.Thread.run(Thread.java:484)
                          [Default]