14 Replies Latest reply on Jul 21, 2006 9:01 AM by twittemb

    In valve getRemoteUser value returned as NULL always

    juserp

      I have JBOSs apllication first imtercepted by a Apache auth module that does external authentication and sets Remote User. I have written a valve that would check for this , so that based on this value I can further decide that Authentication flow.However the valve always returns NULL value.
      Any hint whats going wrong in this case?

        • 2. Re: In valve getRemoteUser value returned as NULL always
          juserp

          I set tomcatAuthentication=false, and able to get the REMOTE_USER value.
          However , get NULL pointer exception at org.jboss.web.tomcat.security.JBossSecurityMgrRealm.hasRole.

          Could any one provide pointers , how to handle authorization in this case.What would be a workaround to set roles so that authorization works out.

          In this case , is the login-module configuration completely ignored?,
          Am not clear how the security configuration to be done in this case.

          Thanks.

          • 3. Re: In valve getRemoteUser value returned as NULL always
            starksm64

            jboss version, stack trace.

            • 4. Re: In valve getRemoteUser value returned as NULL always
              juserp

              JBOSS Verison:
              jboss-4.0.2 release for the J2EE? 1.4 codebase
              embedded tomcat version: 5.5.9

              Stack Trace is:
              16:00:34,759 ERROR [CoyoteAdapter] An exception or error occurred in the container during the request processing
              java.lang.NullPointerException
              at org.jboss.web.tomcat.security.JBossSecurityMgrRealm.hasRole(JBossSecurityMgrRealm.java:286)
              at org.apache.catalina.realm.RealmBase.hasResourcePermission(RealmBase.java:763)
              at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:464)
              at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:59)
              at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
              at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
              at my.sso.MyValve.invoke(MyValve.java:68)
              at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
              at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
              at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:307)
              at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:385)
              at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:748)
              at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:678)
              at org.apache.jk.common.SocketConnection.runIt(ChannelSocket.java:871)
              at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
              at java.lang.Thread.run(Thread.java:536)

              • 5. Re: In valve getRemoteUser value returned as NULL always
                starksm64

                So you have a custom valve that has introduced a principal that does not map to a know value. The principal has to map to a valid JBossGenericPrincipal.

                • 6. Re: In valve getRemoteUser value returned as NULL always
                  juserp

                  Pointers to do this would be really helpful.
                  Thanks,

                  • 7. Re: In valve getRemoteUser value returned as NULL always
                    juserp

                    Scott,

                    I realised that JBossGenericPrincipal class is a private class.How could I set my principal to this type?

                    In current LoginModules like UserRoles etc , I see that the prinicipal is added to subject as SimplePrincipal. Where in JBOSS code do we set it to type JBossGenericPrincipal ?

                    Few queries:
                    The AuthenticatorBase class checks for request.setUserPrincipal, which components responsibility is to set this?
                    Do I need to set it in my valve?

                    Am new to this, So kindly excuse if my queries are dumb :)


                    • 8. Re: In valve getRemoteUser value returned as NULL always
                      guidomuelleraventis

                      I have the same problem. I have the request variable REMOTE_USER set and I get the NullPointerException. Do I have to write my own valve to create a JBossGenericPrincipal and associate this principal with the request? Is there an example program to do this?

                      • 9. Re: In valve getRemoteUser value returned as NULL always
                        starksm64

                        The JBossGenericPrincipal is created when the authentication layer calls the Realm to authenticate the request. If this is not happening with the mod_jk connector then a valve is needed that does so. Essentially its a custom authentor valve that cause the mod_jk request to behave the same as like an authenticated request as this is what is required to engage the normal security paths.

                        • 10. Re: In valve getRemoteUser value returned as NULL always
                          twittemb

                          hello all ...

                          i'm facing exactely the same problem. I've developed my own clustered sso mecanism. I have an SSO Valve that gets the Principal from a distributed authentication cache (handle by JGroups) and call the request.setUserPrincipal() in order to authenticate it.

                          But when the request is adress to a server on which the user has never been authenticated, although the SSOValve do its job, I have this NullPointerException that is raised. I assum that this is because the server's JBossSecurityMgrRealm roleMap does not map the principal with a JBossGenericPrincipal.

                          I have tried to force the authenticate(string, string) method of the JBossSecurityMgrRealm .... but that gives à Null Principal because there is no securityContext available thru JNDI !!!

                          How can i do to force silent authentication in order to build a JBossGenericPrincipal that will be put in the roleMap ???

                          I Assume that the JBoss ClusteredSingleSignOn Valve work properly ... apparently it has a mecanism that is close to my own valve .... so what is the real difference ???

                          thanks a lot for your help scott. See ya !

                          PS : Sorry for my poor english !

                          • 11. Re: In valve getRemoteUser value returned as NULL always
                            soshah

                            twittemb-

                            You can also consider using a CustomAuthenticator that extends one of the four BASIC,FORM,CERT,etc depending on your Authentication method


                            Thanks
                            Sohil

                            • 12. Re: In valve getRemoteUser value returned as NULL always
                              twittemb

                              my authentiction methods are BASIC or FORM ...

                              How a CustomAuthenticator would fix my problem ? have u an example of use ?

                              thx for your answers.

                              • 13. Re: In valve getRemoteUser value returned as NULL always
                                soshah

                                twittemb-

                                Here is the CustomAuthenticator code that we use in the JBoss Federated SSO project. I am pasting the code for the FormAuthenticator

                                /*
                                * JBoss, Home of Professional Open Source
                                * Copyright 2005, JBoss Inc., and individual contributors as indicated
                                * by the @authors tag. See the copyright.txt in the distribution for a
                                * full listing of individual contributors.
                                *
                                * This is free software; you can redistribute it and/or modify it
                                * under the terms of the GNU Lesser General Public License as
                                * published by the Free Software Foundation; either version 2.1 of
                                * the License, or (at your option) any later version.
                                *
                                * This software is distributed in the hope that it will be useful,
                                * but WITHOUT ANY WARRANTY; without even the implied warranty of
                                * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
                                * Lesser General Public License for more details.
                                *
                                * You should have received a copy of the GNU Lesser General Public
                                * License along with this software; if not, write to the Free
                                * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
                                * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
                                */
                                package org.jboss.security.authenticator;
                                
                                
                                //core java classes
                                import java.io.IOException;
                                import java.security.Principal;
                                
                                
                                //servlet classes
                                import javax.servlet.ServletException;
                                
                                
                                //core jboss specific classes
                                
                                
                                //core catalina classes for tomcat specific functions
                                import org.apache.catalina.connector.Request;
                                import org.apache.catalina.connector.Response;
                                import org.apache.catalina.deploy.LoginConfig;
                                import org.apache.catalina.authenticator.FormAuthenticator;
                                
                                
                                //JBoss-SSO Framework classes
                                //jboss-sso-saml library
                                import org.jboss.security.saml.SingleSignOn;
                                import org.jboss.security.saml.SSOException;
                                import org.jboss.security.valve.*;
                                
                                //jboss-identity-management classes
                                import org.jboss.security.idm.Identity;
                                import org.jboss.security.idm.IdentityManager;
                                import org.jboss.security.idm.IdentityProvider;
                                
                                //jboss-sso-common classes
                                import org.jboss.security.util.HTTPUtil;
                                import org.jboss.security.util.SSOUtil;
                                
                                
                                
                                /**
                                 * @author Sohil Shah - sohil.shah@jboss.com
                                 *
                                 * The SSOAutoLogin Tomcat Form Authenticator intercepts requests and checks the presence of an SSOToken domain cookie.
                                 * If a domain cookie is found it is processed and a Principal is generated resulting in AutoLogin
                                 */
                                public class SSOAutoLoginForm extends FormAuthenticator
                                {
                                
                                 //----------------------------------------------------- Instance Variables
                                
                                 /**
                                 * Descriptive information about this implementation.
                                 */
                                 private static final String info = "org.jboss.security.valve.SSOAutoLogin/1.0";
                                
                                
                                 // ------------------------------------------------------------- Properties
                                
                                
                                 /**
                                 * Return descriptive information about this Valve implementation.
                                 */
                                 public String getInfo()
                                 {
                                 return (info);
                                 }
                                
                                
                                 /**
                                 *
                                 */
                                 public void invoke(Request request, Response response)
                                 throws IOException, ServletException
                                 {
                                 try
                                 {
                                 boolean wasSSOPerformed = false;
                                 boolean performSSO = false;
                                 SSOSession activeSession = SSOSession.getSSOSession(request.getSession(true));
                                
                                 //check for the block on automatic sso login, if one is found, don't perform the automatic login
                                 //without this, the user is never able to logout, because all dependent requests to "logout usecase",
                                 //fire up the automatic sso login
                                 if(activeSession.getTurnOff()==null)
                                 {
                                 performSSO = true;
                                 }
                                
                                
                                 if(performSSO)
                                 {
                                 wasSSOPerformed = this.performSSO(request,response);
                                 }
                                
                                 if(!wasSSOPerformed)
                                 {
                                 //if I get here then no SSO processing was done. perform the regular form based authentication
                                 super.invoke(request,response);
                                 if(
                                 request.getSessionInternal(false)!=null &&
                                 request.getSessionInternal(false).getPrincipal()!=null &&
                                 SSOSession.getSSOSession(request.getSession()).getPrincipal()==null
                                 )
                                 {
                                 SSOSession.getSSOSession(request.getSession()).
                                 setPrincipal(
                                 request.getContextPath(),
                                 request.getSessionInternal(false).getPrincipal());
                                 }
                                 return;
                                 }
                                
                                 //this is only if SSO automated login happened on this request
                                 this.getNext().invoke(request,response);
                                 }
                                 catch(SSOException ssoe)
                                 {
                                 ssoe.printStackTrace();
                                 throw new ServletException(ssoe);
                                 }
                                 catch(Exception e)
                                 {
                                 e.printStackTrace();
                                 throw new ServletException(e);
                                 }
                                 }
                                
                                
                                 /**
                                 *
                                 * @param request
                                 * @param response
                                 * @return
                                 */
                                 private boolean performSSO(Request request,Response response) throws IOException,SSOException,Exception
                                 {
                                 boolean wasSSOPerformed = false;
                                 String ssoToken = null;
                                 boolean ssoCookieFound = false;
                                
                                 //find the SSOToken cookie and setup the proper state
                                 ssoToken = HTTPUtil.getSSOToken(request,SingleSignOn.SSO_TOKEN);
                                 if(ssoToken!=null && ssoToken.trim().length()>0)
                                 {
                                 ssoCookieFound = true;
                                 }
                                
                                
                                 if(ssoCookieFound)
                                 {
                                 Principal principal = request.getSessionInternal(true).getPrincipal();
                                 if(principal==null)
                                 {
                                 //perform auto login for this principal
                                 LoginConfig config = this.context.getLoginConfig();
                                 String username = SSOUtil.getUsername(ssoToken);
                                 String password = this.getPassword(username);
                                 request.setAttribute(SingleSignOn.SSO_USERNAME,username);
                                 request.setAttribute(SingleSignOn.SSO_PASSWORD,password);
                                
                                
                                 boolean ssoLogin = this.ssoLogin(request,response,config);
                                 if(ssoLogin)
                                 {
                                 String requestURI = request.getRequestURI();
                                 String contextPath = request.getContextPath();
                                 SSOSession ssoSession = SSOSession.getSSOSession(request.getSession());
                                 ssoSession.setPrincipal(contextPath,
                                 request.getSessionInternal(true).getPrincipal());
                                 wasSSOPerformed = true;
                                 }
                                 }
                                 }
                                 return wasSSOPerformed;
                                 }
                                
                                 /**
                                 *
                                 * @param request
                                 * @param response
                                 * @param config
                                 * @return
                                 * @throws IOException
                                 */
                                 private boolean ssoLogin(Request request,Response response,LoginConfig config)
                                 throws IOException
                                 {
                                 boolean success = false;
                                
                                 Principal principal = null;
                                
                                 // Validate any credentials already included with this request
                                 String username = (String)request.getAttribute(SingleSignOn.SSO_USERNAME);
                                 String password = (String)request.getAttribute(SingleSignOn.SSO_PASSWORD);
                                 principal = this.context.getRealm().authenticate(username, password);
                                 if (principal != null)
                                 {
                                 register(request, response, principal,"FORM",username, password);
                                 success = true;
                                 }
                                 return success;
                                 }
                                
                                
                                 /**
                                 *
                                 */
                                 private String getPassword(String username) throws Exception
                                 {
                                 String password = null;
                                
                                 //perform check against JBoss' central identity data (stored in LDAP)
                                 IdentityProvider provider = IdentityManager.findProvider();
                                
                                 if(
                                 provider.exists(username)
                                 )
                                 {
                                 Identity identity = provider.read(username);
                                 password = new String(identity.getPassword());
                                 }
                                
                                 return password;
                                 }
                                }
                                



                                Hope this helps

                                Thanks
                                Sohil

                                • 14. Re: In valve getRemoteUser value returned as NULL always
                                  twittemb

                                  hello !

                                  thx for all your answers

                                  I have found a solution tom y problem ... it is certainely not the moste efficient but it works.

                                  I have created my own JBossSecurityMgrRealm (the server.xml file has to be updated) and i have adapted the hasRole() method. When no JBossGenricPrincipal can be found in the local cache (roleMap) I get roles and credentials from my own authentication clustered cache. I build a JBossGenericPrincipal and put it in the local cache, sa as the next time it will be directly found in the roleMap.

                                  I'm not very proud of this fix but that seems to work properly !

                                  What do you think about it ?

                                  Thx.