You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Tim K <ti...@gmail.com> on 2022/07/12 14:09:56 UTC

Secondary Authentication method for application

Hello,
I currently have a custom realm in Tomcat 9 that uses form
authentication (j_username/j_password POST to j_security_check).  I'm
looking to create a secondary way to establish an authenticated
session.  I want to allow trusted sources to be able to POST a
username param to a specific URL and establish an authenticated
session with that provided username (I know, seems kind of scary, but
it's just for a proof of concept right now).  Eventually this
secondary method may replace the custom realm all together, i.e.
offloading authentication to an external provider.

I've searched the list and other internet sources which led me to
attempt to extend the ValveBase to try and set a UserPrincipal on the
org.apache.catalina.connector.Request.  I was trying to intercept POST
requests to a new specific RequestURI and if the provided username
param is acceptable, I do the request.setUserPrincipal with the role
that is required.

Am I going down the wrong path to accomplish this?  When the valve
code gets hit, It doesn't seem that the user is really getting
authenticated; I believe because the request comes/goes and the
principal is getting lost when the request is done...

Also, I'm getting a 405 error on the actual POST, even though it
appears the principal gets established for that request...  Not sure
if this has something to do with the JSESSIONID cookie...

Thanks,
Tim

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Secondary Authentication method for application

Posted by Christopher Schultz <ch...@christopherschultz.net>.
Tim,

On 7/12/22 10:09, Tim K wrote:
> Hello,
> I currently have a custom realm in Tomcat 9 that uses form
> authentication (j_username/j_password POST to j_security_check).  I'm
> looking to create a secondary way to establish an authenticated
> session.  I want to allow trusted sources to be able to POST a
> username param to a specific URL and establish an authenticated
> session with that provided username (I know, seems kind of scary, but
> it's just for a proof of concept right now).  Eventually this
> secondary method may replace the custom realm all together, i.e.
> offloading authentication to an external provider.
> 
> I've searched the list and other internet sources which led me to
> attempt to extend the ValveBase to try and set a UserPrincipal on the
> org.apache.catalina.connector.Request.  I was trying to intercept POST
> requests to a new specific RequestURI and if the provided username
> param is acceptable, I do the request.setUserPrincipal with the role
> that is required.
> 
> Am I going down the wrong path to accomplish this?  When the valve
> code gets hit, It doesn't seem that the user is really getting
> authenticated; I believe because the request comes/goes and the
> principal is getting lost when the request is done...
> 
> Also, I'm getting a 405 error on the actual POST, even though it
> appears the principal gets established for that request...  Not sure
> if this has something to do with the JSESSIONID cookie...

There isn't much magic to what Tomcat does for a (normal) login. It just 
does the authentication (which you will handle) and shoves an object 
into the user's session. You can't access that object, but it drives the 
return values of Request.getUserPrincipal() and Request.isInRole().

You can very easily use a Filter to wrap the request in your own wrapper 
(hint: extend HttpRequestWrapper) and return whatever values from 
wherever you want them to go. You can maintain your own authentication 
source however you want. The big advantage to doing this is that you 
will end up with a container-agnostic solution that will continue to 
work even if Tomcat changes something it does. It's always best to have 
a standards-based solution.

Something like this:

class MyAuthenticationFilter implements Filter {
   public void filter(ServletRequest request, ServletResponse response, 
FilterChain chain) {
     // Do all the checking/casting for HttpStuff
     request = new MyAuthenticationWrapper(httpRequest);

     chain.doFilter(request, response);
   }

   static interface MyPrincipal extends Principal {
     public boolean isInRole(String role);
   }

   static class MyAuthenticationWrapper extends HttpServletRequestWrapper {
     public static final String PRINCIPAL_KEY = "my.auth.principal";

     public MyAuthenticationWrapper(HttpServletRequest request) {
       super(request);
     }

     public Principal getUserPrincipal() {
       Principal p = super.getUserPrincipal();

       if(null == p) {
         HttpSession session = getSession(false);

         if(null != session) {
           p = (Principal)session.getAttribute(PRINCIPAL_KEY);
         }
       }

       return p;
     }

     public boolean isInRole(String role) {
       Principal p = getUserPrincipal();
       if(p instanceof MyPrincipal) {
         return ((MyPrincipal)p).isInRole(role);
       } else {
         // Let the container decide
         return super.isInRole(role);
       }
     }

     // TODO: If you are really paranoid about your code, you should
     //       wrap getSession to return a wrapped session that doesn't
     //       allow anyone to set (or maybe even GET) a value for the
     //       PRINCIPAL_KEY.
   }
}

Now, to authenticate your users using your hand-wavy authentication, 
just shove something into the HttpSession which implements MyPrincipal. 
Users who login as usual will get a "normal" principal and the container 
will handle the role checks. If you put an object in the session with 
the right key, this will work because the container doesn't have a 
container-managed Principal.

-chris

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Secondary Authentication method for application

Posted by Tim K <ti...@gmail.com>.
On Wed, Jul 13, 2022 at 10:21 AM EXT-Denton, Sam T
<sa...@boeing.com> wrote:
>
> This may help you: https://stackoverflow.com/questions/15742580/how-to-programmatically-login-to-j-security-check
>
> Sam Denton
> Advisor, Solutions Architect
> Mobile (314) 827-4017
> 24x7 SBS Suppot (405) 312-9936
>

Thanks for the reply, but what I'm trying to do is a bit different as
I won't have the users password.  I was basically looking for a
backdoor way to establish a session using just the username.

I think I was able to get it working but don't know if its the best
way.  What I was missing was, I was not saving the principal to the
Session, only the Request initially.  Also, I created a dummy servlet
in my webapp that has both doGet and doPost methods so that the status
codes would not be a 404-405.  The valve will only create a new
Principal for a POST request to a specific url.

Eventually, my custom realm (form login) may go away and the login for
my app will be done by this external app which will be the only thing
that will be able to call this new "backdoor" way.

Tim

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org