12 Replies Latest reply on Oct 17, 2008 9:51 AM by jignajoshi

    combination of JAAS

    zilbi

      Hi Guys,

      am trying to develop a website with the regular login feature and also to enable programmatic login to be used by affiliates via API.

      working with "jboss-4.2.2.GA" i got the first part (using the FORM login) done fast enough. but i cannot complete the second part...
      :(

      also added a simple LoginServlet; trying to login to this servlet works.
      but after that, when i try access a resource that is under the protected area i get redirection to the login.jsp page!
      why? didn't i just login with the servlet?
      what am i missing?

      here is my code below...
      thanks!

      my login-config.xml:

      <application-policy name="jinni">
       <authentication>
      
       <login-module code="org.jboss.security.ClientLoginModule" flag="required">
       <module-option name="restore-login-identity">true</module-option>
       <module-option name="multi-threaded">true</module-option>
       </login-module>
      
       <login-module code="com.jinni.security.LoginModule" flag="required">
      
       <module-option name="managedConnectionFactoryName">
       jboss.jca:service=LocalTxCM,name=JinniDatasource
       </module-option>
      
       <module-option name="dsJndiName">
       java:/JinniDatasource
       </module-option>
      
       <module-option name="principalsQuery">
       select password from users where user_name =?
       </module-option>
      
       <module-option name="rolesQuery">
       select roles.name as 'Roles', 'Roles' as 'RoleGroups' from users, security_profile_roles, roles
       where roles.id = security_profile_roles.role_id
       and security_profile_roles.security_profile_id = users.security_profile_id
       and users.user_name =?
       </module-option>
      
       <module-option name="restore-login-identity">true</module-option>
       <module-option name="multi-threaded">true</module-option>
      
       </login-module>
      
       </authentication>
       </application-policy>


      and my web.xml:
      <security-constraint>
      
       <web-resource-collection>
       <web-resource-name>action</web-resource-name>
       <url-pattern>/protected/*</url-pattern>
       <http-method>HEAD</http-method>
       <http-method>GET</http-method>
       <http-method>POST</http-method>
       <http-method>PUT</http-method>
       <http-method>DELETE</http-method>
       </web-resource-collection>
      
       <auth-constraint>
       <role-name>Echo</role-name>
       </auth-constraint>
      
       <user-data-constraint>
       <description>no description</description>
       <transport-guarantee>NONE</transport-guarantee>
       </user-data-constraint>
       </security-constraint>
      
       <login-config>
       <auth-method>FORM</auth-method>
       <form-login-config>
       <form-login-page>/login.jsp</form-login-page>
       <form-error-page>/error.jsp</form-error-page>
       </form-login-config>
       </login-config>
      
       <security-role>
       <description>A user allowed to invoke echo methods</description>
       <role-name>Echo</role-name>
       </security-role>
       <servlet>



      the login.jsp:
      <html >
       <head>
       <title></title>
       <!-- To prevent caching -->
       <%
       response.setHeader("Cache-Control","no-cache"); // HTTP 1.1
       response.setHeader("Pragma","no-cache"); // HTTP 1.0
       response.setDateHeader ("Expires", -1); // Prevents caching at the proxy server
       %>
       </head>
       <body>
       <form name="logonForm" action="j_security_check" method="post">
       <table width="100%" border="0" cellspacing="0" cellpadding="1" bgcolor="white">
       <tr align="center">
       <td align="right" class="Prompt"></TD>
       <td align="left">
       <input type="text" name="j_username" maxlength=20>
       </td>
       </tr>
       <tr align="center">
       <td align="right" class="Prompt"> </TD>
       <td align="left">
       <input type="password" name="j_password" maxlength=20 >
       </td>
       </tr>
       <tr align="center">
       <td align="right" class="Prompt"> </TD>
       <td align="left">
       <input type="submit" value="Login">
       </td>
       </tr>
       </table>
       </form>
       </body>
      </html>



      the LoginServlet:
      protected void doPost(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
       {
       PrintWriter pw = response.getWriter();
       try {
       // Get the form's username & password fields
       //
       String user = req.getParameter("user");
       String pass = req.getParameter("pass");
      
       // is that needed???
       // could not hurt
       WebAuthentication webA = new WebAuthentication();
       boolean flag = webA.login(user, pass);
       pw.write("flag = " + flag);
       pw.write('\n');
      
      
       // Use the username/password to initialize the
       // callback handler and then do the authentication.
       PassiveCallbackHandler cbh = new PassiveCallbackHandler(user, pass);
       LoginContext lc = new LoginContext("jinni", cbh);
       lc.login();
      
       // Loop through all Principals and Credentials.
       //
       Iterator it = lc.getSubject().getPrincipals().iterator();
       while (it.hasNext())
       pw.write("Authenticated: " + it.next().toString() + "<br>");
      
       it = lc.getSubject().getPublicCredentials(Properties.class).iterator();
      
       while (it.hasNext())
       pw.write(it.next().toString());
      
       lc.logout();
       }
       catch(Exception E)
       {
       System.err.println(E);
       pw.write("An Error Has Occurred");
       pw.flush();
       }
       }


      thanks again
      :)

        • 1. Re: combination of JAAS
          margielm

          Hello,
          have exactly the same problem.
          am trying to login in in servlet by calling

          LoginContext lc=...;
           c.login();
          

          after that when I call
          lc.getSubject()
          


          I see my principal but both, request.getUserPrincipat() and request.getRemoteUser(), returns null.

          pls help.

          best regards
          Michal Margiel

          • 2. Re: combination of JAAS
            ragavgomatam

            This is my guess....When a Http Request is sent by the browser to a web based Jaas enabled application, the request is first intercepted by the container using j_security_check, j_user_name and j_password. Then it is jaas logged in and the HttpRequest is attached the Principal ...After that the request is passed on to the secured web app with the Request populated...However when you programatically login do you use j_security_check for the container to intercept ? I think not....Your request come directly to servlet where you use callback handlers to do jaas login...This helps to propogate your credentials to ejb container, where as web container is bypassed...

            • 3. Re: combination of JAAS
              zilbi

              thanks,

              i think that you are right in understanding the general concept.

              however, in my servlet i do:

              WebAuthentication webA = new WebAuthentication();
              boolean flag = webA.login(user, pass);
              


              which if i understand correctly is intended exactly for this problem.
              also note that the flag is 'true' meaning the web login is good.

              so i still do not understand why after logging in with the servlet, protected pages still get re-directed to the login.jsp?

              jboss people, can you assist, please?

              • 4. Re: combination of JAAS
                ragavgomatam

                Correct me if I am missing something here....You do

                WebAuthentication webA = new WebAuthentication();
                boolean flag = webA.login(user, pass);
                and also do ?

                // Use the username/password to initialize the
                // callback handler and then do the authentication.
                 PassiveCallbackHandler cbh = new PassiveCallbackHandler(user, pass); LoginContext lc = new LoginContext("jinni", cbh); lc.login();
                

                So which is actually logging you in ? The callback handler or WebAuthentication ?


                • 5. Re: combination of JAAS
                  zilbi

                  both, and none.
                  :)

                  i tried all 3 combinations (only web, only jaas and both) and i get the same result always.
                  there must be something else wrong...
                  but i am quite lost here my friend

                  • 6. Re: combination of JAAS
                    ragavgomatam

                    Check this out from the following url
                    http://wiki.jboss.org/wiki/Wiki.jsp?page=SecurityFAQ

                    Q7: Why does getUserPrincipal/getPrincipal return null after a JAAS login
                    A7: The only time getUserPrincipal/getPrincipal return a non-null value is when the user has authenticated to the container. Doing a JAAS login from within a servlet/ejb method is simply executing an independent authentication against the corresponding JAAS login configuration.


                    • 7. Re: combination of JAAS
                      zilbi

                      yes thanks, i read it before.

                      but from reading:
                      http://wiki.jboss.org/wiki/Wiki.jsp?page=WebAuthentication

                      and
                      http://roneiv.wordpress.com/2008/02/19/perform-a-jaas-programmatic-login-in-jboss-try-to-solve-the-empty-remote-user-problem/

                      I was thinking that it will solve the problem.

                      going back to the FAQ, does A7 means that there is no way to mimic the j_security_check using a simple api?

                      all i want here is to have a servlet for login that enables the other side to invoke other api requests over http which will than propagate to the EJB layer with the correct proncipal. (as my j_security_check does)

                      is it not possible in jboss?

                      • 8. Re: combination of JAAS
                        ragavgomatam

                        As per http://wiki.jboss.org/wiki/Wiki.jsp?page=WebAuthentication

                        WebAuthentication pwl = new WebAuthentication();
                        pwl.login(username, pass);

                        //Only when there is web login, does the principal be visible
                        log("User Principal="+request.getUserPrincipal());


                        you can't......But as per
                        http://roneiv.wordpress.com/2008/02/19/perform-a-jaas-programmatic-login-in-jboss-try-to-solve-the-empty-remote-user-problem/
                        you can......


                        1. WebAuthentication webA = new WebAuthentication();
                        2. webA.login(username, password);

                        WebAuthentication webA = new WebAuthentication();
                        webA.login(username, password);

                        And you’re on :) Both getUserPrincipal() and getRemoteUser() works.


                        Going by FAQ, answer appears to be no. You can't.

                        • 9. Re: combination of JAAS
                          eivind1

                          Hi!

                          I was asked by a response to my blog post (http://roneiv.wordpress.com/2008/02/19/perform-a-jaas-programmatic-login-in-jboss-try-to-solve-the-empty-remote-user-problem/) to comment and maybe help on this issue.

                          I'm no expert on these matters, but I've managed to use the WebAuthentication BOTH from servlet context and from a handler to login a user to the application. And the user is properly set also in web container, so both externalContext.getRemoteUser() AND externalContext.getUserPrincipal().toString() return the logged on username.

                          Zilbi, it is my understanding that you have managed to log on to your application whith basic form-logon, using j_security_check etc. That's nice, because we then know that your login-config and ds works. Still, I will provide an example of the login-config I use, just in case it matters ;) This one uses a database with a user table, but the groups are static:

                          <application-policy name = "myApplication">
                           <authentication>
                           <login-module code = "org.jboss.security.auth.spi.DatabaseServerLoginModule" flag = "required">
                           <module-option name = "dsJndiName">java:/myDatasource-ds</module-option>
                           <module-option name = "principalsQuery">Select password from user_table where user_name =? AND active = 'true'</module-option>
                           <module-option name = "rolesQuery">Select 'user', 'Roles', 'RoleGroups' from user_table where user_name =?</module-option>
                           <module-option name ="hashAlgorithm">md5</module-option>
                           <module-option name="hashEncoding">hex</module-option>
                           <module-option name="debug">false</module-option>
                           </login-module>
                           <login-module code="org.jboss.security.ClientLoginModule" flag="required" />
                           </authentication>
                           </application-policy>
                          


                          The first thing to try is that the WebAuthentication class works as it should.
                          Create a LoginHandler or something similar, with a method login() and two helper-methods getRemoteUser and getUserPrincipal. Something like this:

                          public class LoginHandler
                          {
                          
                          public String login()
                          {
                           WebAuthentication webAuthentication = new WebAuthentication();
                          
                           String hardcodedUserName = "zilbi@jboss.com";
                           String hardcodedPassword = "zilbi123";
                          
                           if (webAuthentication.login(hardcodedUserName, hardcodedPassword))
                           {
                           System.out.println("Logged in successfully");;
                          
                           log.debug("userPrincipal: " + getUserPrincipal());
                           log.debug("remoteUser: " + getRemoteUser());
                           }
                           else
                           {
                           log.debug("Login failed");
                           }
                          
                           return "";
                          }
                          public String getUserPrincipal()
                          {
                           FacesContext context = FacesContext.getCurrentInstance();
                           ExternalContext externalContext = context.getExternalContext();
                           return externalContext.getUserPrincipal() != null ? externalContext.getUserPrincipal().toString() : "null";
                          }
                          
                          public String getRemoteUser()
                          {
                           FacesContext context = FacesContext.getCurrentInstance();
                           ExternalContext externalContext = context.getExternalContext();
                           String remoteUser = externalContext.getRemoteUser();
                           return remoteUser;
                          }
                          
                          }
                          


                          We basically hardcode the username/password, and just test if we get login to work. You should of course change these values to something that matches your login domain. Then create a simple jsp, but don't put it inside your protected folder. I see from you web.xml that you protect everything under /protected/*. Create it one level up so that you can access it without being asked to log in.

                          In this jsp you will have a stupid commandButton, as well as two outputs that displays the remoteUser and userPrincipal:

                          <f:view >
                           <t:document>
                           <t:documentHead>
                           <f:loadBundle basename="MessageResources" var="messages" />
                           </t:documentHead>
                          
                           <f:verbatim>
                           <body>
                           </f:verbatim>
                           <h:form>
                           <h:panelGrid>
                           <h:commandButton value="Login" action="#{loginHandler.login}"></h:commandButton>
                           <h:outputText value="User Principal: #{loginHandler.userPrincipal}"></h:outputText>
                           <h:outputText value="Remote User: #{loginHandler.remoteUser}"></h:outputText>
                           </h:panelGrid>
                           </h:form>
                           <f:verbatim>
                           </body>
                           </f:verbatim>
                           </t:document>
                          </f:view>
                          


                          Now, launch your application by going to this page. You will see that userPrincipal shows "null" and remoteUser is empty. Press the Login button. When the page reloads it should display your username in both outputTexts. If you check your log or console it should say "Logged in successfully." The user is now properly set in the web container. Do you get this to work? Also, if you now try to change the url to go to one of your protected pages, you should not be redirected to any login.jsp, but the page should display properly - because you are already logged on.

                          Then, to do the logon from a servlet there's really not a big difference. I set up my web.xml to use a FORM-based logon, like this:

                          <login-config>
                           <auth-method>FORM</auth-method>
                           <form-login-config>
                           <form-login-page>/login.faces</form-login-page>
                           <form-error-page>/loginFailed.faces</form-error-page>
                           </form-login-config>
                           </login-config>
                          


                          I also register my LoginServlet in web.xml like this:
                          <servlet>
                           <servlet-name>LoginServlet</servlet-name>
                           <servlet-class>com.test.servlet.LoginServlet</servlet-class>
                           </servlet>
                          
                           <servlet-mapping>
                           <servlet-name>LoginServlet</servlet-name>
                           <url-pattern>/LoginServlet</url-pattern>
                           </servlet-mapping>
                          


                          My login.jsp is 99% the same as when using j_security_check, we just point the action to the LoginServlet instead:
                          <form method="POST" name="loginform" action="${pageContext.request.contextPath}/LoginServlet">
                           <table style="vertical-align: middle;">
                           <tr>
                           <td>Username:</td><td><input type="text" name="j_username"/></td>
                           </tr>
                           <tr>
                           <td>Password:</td><td><input type="password" name="j_password"/></td>
                           </tr>
                           <tr>
                           <td><input type="submit" value="Login" /></td>
                           </tr>
                           </table>
                          </form>
                          
                          


                          My LoginServlet uses the parameters that was originally passed to the j_security_check. Also, if we successfully log on, we get the "Referer" from the request to redirect to the page that originally was the target for the user. I did not include the code that handles if the logon failed here:
                          public class LoginServlet extends HttpServlet
                          {
                           @Override
                           protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                           throws ServletException, IOException
                           {
                           // TODO Auto-generated method stub
                           doPost(req, resp);
                          
                           }
                          
                           @Override
                           protected void doPost(HttpServletRequest req, HttpServletResponse resp)
                           throws ServletException, IOException
                           {
                           String user = req.getParameter("j_username");
                           String pass = req.getParameter("j_password");
                           WebAuthentication webAuthentication = new WebAuthentication();
                           if( webAuthentication.login(user, pass))
                           {
                           String redirectUrl = "";
                           String referer = req.getHeader("Referer");
                           resp.sendRedirect(redirectUrl);
                           return;
                           }
                           else
                           {
                           System.out.println("Login attempt failed " + user);
                           ...
                           Handle incorrect logon, go back to login page etc
                           ...
                           }
                           }
                          }
                          


                          So, to test this, start your application by pointing directly to some page that is protected. Your login.jsp should be presented, and when you press Login the servlet uses the credentials you passed in the forms, authenticates and redirect you to the page. For debug reasons you could add the same outputTexts here on this page (remoteUser and userPrincipal), and they SHOULD show the user you logged in with now.

                          Hope that this might help you, but as I said, I'm no expert on this. And I don't know the effect of the two options you include in your login-config, if this could cause some bad behaviour or not:

                          <module-option name="restore-login-identity">true</module-option>
                          <module-option name="multi-threaded">true</module-option>


                          A good tip is to start with a minimal configuration till you get it working, and then slowly building it up to go where you want. :)

                          • 10. Re: combination of JAAS
                            zilbi

                            thanks for the help man!

                            got some new extremely urgent pressured feature to take care of, so i'll get back to this in a few days...

                            thanks, it is appreciated.

                            • 11. Re: combination of JAAS
                              zilbi

                              it works!!!

                              thanks man,

                              got rid of the bloody j_security_check, replaced it with my own servlet like you said, and suddenly all is ok.

                              my web.xml did not change at all, my login.jsp:

                              <form name="logonForm" action="<%=request.getContextPath()%>/LoginServlet" method="post">
                               <table width="100%" border="0" cellspacing="0" cellpadding="1" bgcolor="white">
                               <tr align="center">
                               <td align="right" class="Prompt"></TD>
                               <td align="left">
                               <input type="text" name="user" maxlength=20>
                               </td>
                               </tr>
                               <tr align="center">
                               <td align="right" class="Prompt"> </TD>
                               <td align="left">
                               <input type="password" name="pass" maxlength=20 >
                               </td>
                               </tr>
                               <tr align="center">
                               <td align="right" class="Prompt"> </TD>
                               <td align="left">
                               <input type="submit" value="Login">
                               </td>
                               </tr>
                               </table>
                               </form>


                              and my servlet doPost:
                              // Get the form's username & password fields
                              String userName = req.getParameter("user");
                              String pass = req.getParameter("pass");
                              
                              WebAuthentication webA = new WebAuthentication();
                              boolean loginFlag = webA.login(userName, pass);
                              
                              if (loginFlag)
                              {
                               User user = userDao.findByUserName( req.getUserPrincipal().getName() );
                               // do some things with the user...
                              
                               String redirectUrl = req.getHeader("Referer");
                              
                               if (redirectUrl != null)
                               {
                               res.sendRedirect( redirectUrl );
                               }
                              }
                              else
                              {
                               res.sendRedirect( "error.jsp" );
                              }
                              


                              still i do not understand why it does not work with j_security_check? is this a bug?
                              how come the j_security_check does not 'recognize' what the WebAuthentication is doing?
                              well, got it around it so i guess i can live with that...

                              thanks again to everyone...
                              Zilbi

                              • 12. Re: combination of JAAS
                                jignajoshi

                                Hi,
                                I have tried Programmic WebAuthentication in JBoss portal 2.6.6..
                                i m calling LoginServelt from login.jsp and it’s working fine..
                                in LoginServlet.java
                                WebAuthentication webAuthentication = new WebAuthentication();
                                if(webAuthentication.login(user, pass))
                                {
                                System.out.println(�In Web Authentication “);

                                System.out.println(�redirectUrl : “+redirectUrl);
                                String referer = req.getHeader(�Referer�);

                                resp.sendRedirect(�http://localhost:8080/portal/auth/dashboard�);

                                }
                                This is working fine if i login from login link on Portal home page..but, in my real scenario i ve to login it from outside..so i m running one simple html throgh apache
                                http://localhost/scripts/login.html..in this login.html i m calling LoginServlet of Portal..

                                it is doing Authentication but not doing authorization…and so if i do re-login..it works…
                                Am i missing something, please help me..
                                thanx in advance