You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Scott Kelley <sk...@biomail.ucsd.edu> on 2003/06/11 20:13:52 UTC

Valve as Custom Authenticator

We've had an Apache/Tomcat configuration deployed for a couple years 
now. Authentication is handled by a custom Apache plugin written in 
C. Everything works great and has been quite reliable.

Now we would like to move to a standalone Tomcat configuration and 
have been investigating writing a Valve/Authenticator to replace our 
existing Apache plugin.

I've written a prototype Valve and it does almost everything we need. 
This gives us the ability to require a server-wide login independent 
of how the individual servlet contexts are configured. This ends up 
being Tomcat-specific, but we're ok with that.

The only problem with the current prototype is that if a user hits a 
servlet or JSP in a Context that's configured for basic 
authentication, they still get the browser-generated basic login 
dialog, even after being logged in with our Valve.

In my code, I check for a particular cookie, and if I find it, I set 
the user principal in the request to the appropriate user, something 
like this:

     // Has connection already been authenticated
     // (i.e. do we have the login cookie?)
     Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);

     // If the request has the login cookie, let it pass through
     if (lcookie!=null) {
         log("Found login cookie, validating");
         if (validLoginCookie(lcookie,hreq)) {
             log("cookie is valid, allowing request");
             // See AuthenticatorBase.invoke(), which also sets 
authType and userPrincipal
             // See SignleSignOn.invoke(), which also set authType and 
userPrincipal
             hrequest.getRequest().setUserPrincipal(new 
TempPrincipal("bob_temp_user"));
             hrequest.getRequest().setAuthType("BASIC");
             context.invokeNext(request,response);
         } else {
             log("cookie not valid, going to error page");
             hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
         }
         return;
     }

I had thought that this would work, because later in the pipeline the 
request hits BasicAuthenticator, which does this:

     public boolean authenticate(HttpRequest request,
                                 HttpResponse response,
                                 LoginConfig config)
         throws IOException {

         // Have we already authenticated someone?
         Principal principal =
             ((HttpServletRequest) request.getRequest()).getUserPrincipal();
         if (principal != null) {
             if (debug >= 1)
                 log("Already authenticated '" + principal.getName() + "'");
             return (true);
         }


And since I've set the principal to something besides null, I had 
assumed that the basic authentication would just be skipped. Which is 
not the behavior that I'm seeing. Instead, I end up asking the user 
to log in twice: once for my custom Valve (which is a web 
form/redirect thing), and a second time when they hit a servlet in a 
context with basic authentication (which causes the browser to put up 
the basic authentication dialog).

So, what am I missing?

Thanks,

Scott





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


Re: Valve as Custom Authenticator

Posted by Tim Funk <fu...@joedog.org>.
How about placing it inside <host> like the SSO valve?
http://jakarta.apache.org/tomcat/tomcat-4.1-doc/config/host.html#Single%20Sign%20On

I don't think you'll need to write a Realm. Realms are for mapping roles. 
(and authentication)
http://jakarta.apache.org/tomcat/tomcat-4.1-doc/config/realm.html

-Tim

Scott Kelley wrote:
> Aha, you're right!
> 
> First problem, I didn't have the right logging enabled; I hadn't noticed 
> that I didn't see any of the log messages from BasicAuthenticator.java.
> 
> Second problem, with logging cranked up appropriately, is that 
> BasicAuthenticator gets called before my code.
> 
> Which leads to my next question: how can I get called before 
> BasicAuthenticator?
> 
> I had the Valve installed as the first item in the Engine; when it's 
> there it apparently gets called after BasicAuthenticator. I tried moving 
> my valve up a level into the Service, but my code didn't seem to get 
> called at all when I installed the valve there.
> 
> Let me ask a related question: If I have a valve that's setting the 
> principal and authType, do I need to set a Realm in server.xml, and if 
> so, what should I set it to? Do I need to write a Realm that somehow 
> talks to my Valve (since the request info isn't available in Tomcat 4)? 
> This is, I think, the piece of the puzzle that I don't completely 
> understand.
> 
> Scott
> 
> 
> At 5:03 PM -0400 6/11/03, Tim Funk wrote:
> 
>> I took a little longer look. All "looks" ok to me. Turn up debugging. 
>> Are you sure that your valve is being executed before the 
>> BasicAuthenticator valve?
>>
>> -Tim
>>
>>
>> Scott Kelley wrote:
>>
>>> SingleSignOn has much the same code as BasicAuthenticator:
>>>
>>> in org.apache.catalina.authenticator.SingleSignOn.java:
>>>
>>>         // Look up the cached Principal associated with this cookie 
>>> value
>>>         if (debug >= 1)
>>>             log(" Checking for cached principal for " + 
>>> cookie.getValue());
>>>         SingleSignOnEntry entry = lookup(cookie.getValue());
>>>         if (entry != null) {
>>>             if (debug >= 1)
>>>                 log(" Found cached principal '" +
>>>                     entry.principal.getName() + "' with auth type '" +
>>>                     entry.authType + "'");
>>>             request.setNote(Constants.REQ_SSOID_NOTE, 
>>> cookie.getValue());
>>>             ((HttpRequest) request).setAuthType(entry.authType);
>>>             ((HttpRequest) request).setUserPrincipal(entry.principal);
>>>         } else {
>>>             if (debug >= 1)
>>>                 log(" No cached principal found, erasing SSO cookie");
>>>             cookie.setMaxAge(0);
>>>             hres.addCookie(cookie);
>>>         }
>>>
>>>         // Invoke the next Valve in our pipeline
>>>         context.invokeNext(request, response);
>>>
>>> The only piece of that I'm not doing is the setNote() part; I *think* 
>>> that's only used for the form-based login stuff, but I'm not entirely 
>>> sure-- that's probably the part of the puzzle I still don't 
>>> understand. The basic authenicator doesn't seem to use it.
>>>
>>> Scott
>>>
>>> At 3:10 PM -0400 6/11/03, Tim Funk wrote:
>>>
>>>> I don't have time to see whats wrong, but check the 
>>>> SingleSignOnValve as a reference to compare your code.
>>>>
>>>> -Tim
>>>>
>>>> Scott Kelley wrote:
>>>>
>>>>> We've had an Apache/Tomcat configuration deployed for a couple 
>>>>> years now. Authentication is handled by a custom Apache plugin 
>>>>> written in C. Everything works great and has been quite reliable.
>>>>>
>>>>> Now we would like to move to a standalone Tomcat configuration and 
>>>>> have been investigating writing a Valve/Authenticator to replace 
>>>>> our existing Apache plugin.
>>>>>
>>>>> I've written a prototype Valve and it does almost everything we 
>>>>> need. This gives us the ability to require a server-wide login 
>>>>> independent of how the individual servlet contexts are configured. 
>>>>> This ends up being Tomcat-specific, but we're ok with that.
>>>>>
>>>>> The only problem with the current prototype is that if a user hits 
>>>>> a servlet or JSP in a Context that's configured for basic 
>>>>> authentication, they still get the browser-generated basic login 
>>>>> dialog, even after being logged in with our Valve.
>>>>>
>>>>> In my code, I check for a particular cookie, and if I find it, I 
>>>>> set the user principal in the request to the appropriate user, 
>>>>> something like this:
>>>>>
>>>>>     // Has connection already been authenticated
>>>>>     // (i.e. do we have the login cookie?)
>>>>>     Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
>>>>>
>>>>>     // If the request has the login cookie, let it pass through
>>>>>     if (lcookie!=null) {
>>>>>         log("Found login cookie, validating");
>>>>>         if (validLoginCookie(lcookie,hreq)) {
>>>>>             log("cookie is valid, allowing request");
>>>>>             // See AuthenticatorBase.invoke(), which also sets 
>>>>> authType and userPrincipal
>>>>>             // See SignleSignOn.invoke(), which also set authType 
>>>>> and userPrincipal
>>>>>             hrequest.getRequest().setUserPrincipal(new 
>>>>> TempPrincipal("bob_temp_user"));
>>>>>             hrequest.getRequest().setAuthType("BASIC");
>>>>>             context.invokeNext(request,response);
>>>>>         } else {
>>>>>             log("cookie not valid, going to error page");
>>>>>             hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
>>>>>         }
>>>>>         return;
>>>>>     }
>>>>>
>>>>> I had thought that this would work, because later in the pipeline 
>>>>> the request hits BasicAuthenticator, which does this:
>>>>>
>>>>>     public boolean authenticate(HttpRequest request,
>>>>>                                 HttpResponse response,
>>>>>                                 LoginConfig config)
>>>>>         throws IOException {
>>>>>
>>>>>         // Have we already authenticated someone?
>>>>>         Principal principal =
>>>>>             ((HttpServletRequest) 
>>>>> request.getRequest()).getUserPrincipal();
>>>>>         if (principal != null) {
>>>>>             if (debug >= 1)
>>>>>                 log("Already authenticated '" + principal.getName() 
>>>>> + "'");
>>>>>             return (true);
>>>>>         }
>>>>>
>>>>>
>>>>> And since I've set the principal to something besides null, I had 
>>>>> assumed that the basic authentication would just be skipped. Which 
>>>>> is not the behavior that I'm seeing. Instead, I end up asking the 
>>>>> user to log in twice: once for my custom Valve (which is a web 
>>>>> form/redirect thing), and a second time when they hit a servlet in 
>>>>> a context with basic authentication (which causes the browser to 
>>>>> put up the basic authentication dialog).
>>>>>
>>>>> So, what am I missing?
>>>>>
>>>>> Thanks,
>>>>>
>>>>> Scott
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tomcat-user-help@jakarta.apache.org
> 
> 


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


Re: Valve as Custom Authenticator

Posted by Tim Funk <fu...@joedog.org>.
Sweet! (Says the guy who has to write a CustomValve for work in the near future)

-Tim

Bill Barker wrote:
> BasicAutheniticator is a Context-level Valve, so it can't possibly get
> invoked before an Engine-level Valve.  You've got something really strange
> in your setup.
> 
> The other thing to point out is that if you configure your Valve at the
> Context-level, and implement org.apache.catalina.Authenticator, then
> BasicAuthenticator won't even be installed.  Tomcat will trust that you know
> what you are doing, and leave all authentication to your Valve.
> 


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


Re: Valve as Custom Authenticator

Posted by Bill Barker <wb...@wilshire.com>.
BasicAutheniticator is a Context-level Valve, so it can't possibly get
invoked before an Engine-level Valve.  You've got something really strange
in your setup.

The other thing to point out is that if you configure your Valve at the
Context-level, and implement org.apache.catalina.Authenticator, then
BasicAuthenticator won't even be installed.  Tomcat will trust that you know
what you are doing, and leave all authentication to your Valve.

"Scott Kelley" <sk...@biomail.ucsd.edu> wrote in message
news:p0521060ebb0d77c31bb0@[132.239.58.113]...
> Aha, you're right!
>
> First problem, I didn't have the right logging enabled; I hadn't
> noticed that I didn't see any of the log messages from
> BasicAuthenticator.java.
>
> Second problem, with logging cranked up appropriately, is that
> BasicAuthenticator gets called before my code.
>
> Which leads to my next question: how can I get called before
> BasicAuthenticator?
>
> I had the Valve installed as the first item in the Engine; when it's
> there it apparently gets called after BasicAuthenticator. I tried
> moving my valve up a level into the Service, but my code didn't seem
> to get called at all when I installed the valve there.
>
> Let me ask a related question: If I have a valve that's setting the
> principal and authType, do I need to set a Realm in server.xml, and
> if so, what should I set it to? Do I need to write a Realm that
> somehow talks to my Valve (since the request info isn't available in
> Tomcat 4)? This is, I think, the piece of the puzzle that I don't
> completely understand.
>
> Scott
>
>
> At 5:03 PM -0400 6/11/03, Tim Funk wrote:
> >I took a little longer look. All "looks" ok to me. Turn up
> >debugging. Are you sure that your valve is being executed before the
> >BasicAuthenticator valve?
> >
> >-Tim
> >
> >
> >Scott Kelley wrote:
> >>SingleSignOn has much the same code as BasicAuthenticator:
> >>
> >>in org.apache.catalina.authenticator.SingleSignOn.java:
> >>
> >>         // Look up the cached Principal associated with this cookie
value
> >>         if (debug >= 1)
> >>             log(" Checking for cached principal for " +
cookie.getValue());
> >>         SingleSignOnEntry entry = lookup(cookie.getValue());
> >>         if (entry != null) {
> >>             if (debug >= 1)
> >>                 log(" Found cached principal '" +
> >>                     entry.principal.getName() + "' with auth type '" +
> >>                     entry.authType + "'");
> >>             request.setNote(Constants.REQ_SSOID_NOTE,
cookie.getValue());
> >>             ((HttpRequest) request).setAuthType(entry.authType);
> >>             ((HttpRequest) request).setUserPrincipal(entry.principal);
> >>         } else {
> >>             if (debug >= 1)
> >>                 log(" No cached principal found, erasing SSO cookie");
> >>             cookie.setMaxAge(0);
> >>             hres.addCookie(cookie);
> >>         }
> >>
> >>         // Invoke the next Valve in our pipeline
> >>         context.invokeNext(request, response);
> >>
> >>The only piece of that I'm not doing is the setNote() part; I
> >>*think* that's only used for the form-based login stuff, but I'm
> >>not entirely sure-- that's probably the part of the puzzle I still
> >>don't understand. The basic authenicator doesn't seem to use it.
> >>
> >>Scott
> >>
> >>At 3:10 PM -0400 6/11/03, Tim Funk wrote:
> >>
> >>>I don't have time to see whats wrong, but check the
> >>>SingleSignOnValve as a reference to compare your code.
> >>>
> >>>-Tim
> >>>
> >>>Scott Kelley wrote:
> >>>
> >>>>We've had an Apache/Tomcat configuration deployed for a couple
> >>>>years now. Authentication is handled by a custom Apache plugin
> >>>>written in C. Everything works great and has been quite reliable.
> >>>>
> >>>>Now we would like to move to a standalone Tomcat configuration
> >>>>and have been investigating writing a Valve/Authenticator to
> >>>>replace our existing Apache plugin.
> >>>>
> >>>>I've written a prototype Valve and it does almost everything we
> >>>>need. This gives us the ability to require a server-wide login
> >>>>independent of how the individual servlet contexts are
> >>>>configured. This ends up being Tomcat-specific, but we're ok with
> >>>>that.
> >>>>
> >>>>The only problem with the current prototype is that if a user
> >>>>hits a servlet or JSP in a Context that's configured for basic
> >>>>authentication, they still get the browser-generated basic login
> >>>>dialog, even after being logged in with our Valve.
> >>>>
> >>>>In my code, I check for a particular cookie, and if I find it, I
> >>>>set the user principal in the request to the appropriate user,
> >>>>something like this:
> >>>>
> >>>>     // Has connection already been authenticated
> >>>>     // (i.e. do we have the login cookie?)
> >>>>     Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
> >>>>
> >>>>     // If the request has the login cookie, let it pass through
> >>>>     if (lcookie!=null) {
> >>>>         log("Found login cookie, validating");
> >>>>         if (validLoginCookie(lcookie,hreq)) {
> >>>>             log("cookie is valid, allowing request");
> >>>>             // See AuthenticatorBase.invoke(), which also sets
> >>>>authType and userPrincipal
> >>>>             // See SignleSignOn.invoke(), which also set authType
> >>>>and userPrincipal
> >>>>             hrequest.getRequest().setUserPrincipal(new
> >>>>TempPrincipal("bob_temp_user"));
> >>>>             hrequest.getRequest().setAuthType("BASIC");
> >>>>             context.invokeNext(request,response);
> >>>>         } else {
> >>>>             log("cookie not valid, going to error page");
> >>>>
hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
> >>>>         }
> >>>>         return;
> >>>>     }
> >>>>
> >>>>I had thought that this would work, because later in the pipeline
> >>>>the request hits BasicAuthenticator, which does this:
> >>>>
> >>>>     public boolean authenticate(HttpRequest request,
> >>>>                                 HttpResponse response,
> >>>>                                 LoginConfig config)
> >>>>         throws IOException {
> >>>>
> >>>>         // Have we already authenticated someone?
> >>>>         Principal principal =
> >>>>             ((HttpServletRequest)
request.getRequest()).getUserPrincipal();
> >>>>         if (principal != null) {
> >>>>             if (debug >= 1)
> >>>>                 log("Already authenticated '" + principal.getName() +
"'");
> >>>>             return (true);
> >>>>         }
> >>>>
> >>>>
> >>>>And since I've set the principal to something besides null, I had
> >>>>assumed that the basic authentication would just be skipped.
> >>>>Which is not the behavior that I'm seeing. Instead, I end up
> >>>>asking the user to log in twice: once for my custom Valve (which
> >>>>is a web form/redirect thing), and a second time when they hit a
> >>>>servlet in a context with basic authentication (which causes the
> >>>>browser to put up the basic authentication dialog).
> >>>>
> >>>>So, what am I missing?
> >>>>
> >>>>Thanks,
> >>>>
> >>>>Scott




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


Re: Valve as Custom Authenticator

Posted by Scott Kelley <sk...@biomail.ucsd.edu>.
Aha, you're right!

First problem, I didn't have the right logging enabled; I hadn't 
noticed that I didn't see any of the log messages from 
BasicAuthenticator.java.

Second problem, with logging cranked up appropriately, is that 
BasicAuthenticator gets called before my code.

Which leads to my next question: how can I get called before 
BasicAuthenticator?

I had the Valve installed as the first item in the Engine; when it's 
there it apparently gets called after BasicAuthenticator. I tried 
moving my valve up a level into the Service, but my code didn't seem 
to get called at all when I installed the valve there.

Let me ask a related question: If I have a valve that's setting the 
principal and authType, do I need to set a Realm in server.xml, and 
if so, what should I set it to? Do I need to write a Realm that 
somehow talks to my Valve (since the request info isn't available in 
Tomcat 4)? This is, I think, the piece of the puzzle that I don't 
completely understand.

Scott


At 5:03 PM -0400 6/11/03, Tim Funk wrote:
>I took a little longer look. All "looks" ok to me. Turn up 
>debugging. Are you sure that your valve is being executed before the 
>BasicAuthenticator valve?
>
>-Tim
>
>
>Scott Kelley wrote:
>>SingleSignOn has much the same code as BasicAuthenticator:
>>
>>in org.apache.catalina.authenticator.SingleSignOn.java:
>>
>>         // Look up the cached Principal associated with this cookie value
>>         if (debug >= 1)
>>             log(" Checking for cached principal for " + cookie.getValue());
>>         SingleSignOnEntry entry = lookup(cookie.getValue());
>>         if (entry != null) {
>>             if (debug >= 1)
>>                 log(" Found cached principal '" +
>>                     entry.principal.getName() + "' with auth type '" +
>>                     entry.authType + "'");
>>             request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
>>             ((HttpRequest) request).setAuthType(entry.authType);
>>             ((HttpRequest) request).setUserPrincipal(entry.principal);
>>         } else {
>>             if (debug >= 1)
>>                 log(" No cached principal found, erasing SSO cookie");
>>             cookie.setMaxAge(0);
>>             hres.addCookie(cookie);
>>         }
>>
>>         // Invoke the next Valve in our pipeline
>>         context.invokeNext(request, response);
>>
>>The only piece of that I'm not doing is the setNote() part; I 
>>*think* that's only used for the form-based login stuff, but I'm 
>>not entirely sure-- that's probably the part of the puzzle I still 
>>don't understand. The basic authenicator doesn't seem to use it.
>>
>>Scott
>>
>>At 3:10 PM -0400 6/11/03, Tim Funk wrote:
>>
>>>I don't have time to see whats wrong, but check the 
>>>SingleSignOnValve as a reference to compare your code.
>>>
>>>-Tim
>>>
>>>Scott Kelley wrote:
>>>
>>>>We've had an Apache/Tomcat configuration deployed for a couple 
>>>>years now. Authentication is handled by a custom Apache plugin 
>>>>written in C. Everything works great and has been quite reliable.
>>>>
>>>>Now we would like to move to a standalone Tomcat configuration 
>>>>and have been investigating writing a Valve/Authenticator to 
>>>>replace our existing Apache plugin.
>>>>
>>>>I've written a prototype Valve and it does almost everything we 
>>>>need. This gives us the ability to require a server-wide login 
>>>>independent of how the individual servlet contexts are 
>>>>configured. This ends up being Tomcat-specific, but we're ok with 
>>>>that.
>>>>
>>>>The only problem with the current prototype is that if a user 
>>>>hits a servlet or JSP in a Context that's configured for basic 
>>>>authentication, they still get the browser-generated basic login 
>>>>dialog, even after being logged in with our Valve.
>>>>
>>>>In my code, I check for a particular cookie, and if I find it, I 
>>>>set the user principal in the request to the appropriate user, 
>>>>something like this:
>>>>
>>>>     // Has connection already been authenticated
>>>>     // (i.e. do we have the login cookie?)
>>>>     Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
>>>>
>>>>     // If the request has the login cookie, let it pass through
>>>>     if (lcookie!=null) {
>>>>         log("Found login cookie, validating");
>>>>         if (validLoginCookie(lcookie,hreq)) {
>>>>             log("cookie is valid, allowing request");
>>>>             // See AuthenticatorBase.invoke(), which also sets 
>>>>authType and userPrincipal
>>>>             // See SignleSignOn.invoke(), which also set authType 
>>>>and userPrincipal
>>>>             hrequest.getRequest().setUserPrincipal(new 
>>>>TempPrincipal("bob_temp_user"));
>>>>             hrequest.getRequest().setAuthType("BASIC");
>>>>             context.invokeNext(request,response);
>>>>         } else {
>>>>             log("cookie not valid, going to error page");
>>>>             hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
>>>>         }
>>>>         return;
>>>>     }
>>>>
>>>>I had thought that this would work, because later in the pipeline 
>>>>the request hits BasicAuthenticator, which does this:
>>>>
>>>>     public boolean authenticate(HttpRequest request,
>>>>                                 HttpResponse response,
>>>>                                 LoginConfig config)
>>>>         throws IOException {
>>>>
>>>>         // Have we already authenticated someone?
>>>>         Principal principal =
>>>>             ((HttpServletRequest) request.getRequest()).getUserPrincipal();
>>>>         if (principal != null) {
>>>>             if (debug >= 1)
>>>>                 log("Already authenticated '" + principal.getName() + "'");
>>>>             return (true);
>>>>         }
>>>>
>>>>
>>>>And since I've set the principal to something besides null, I had 
>>>>assumed that the basic authentication would just be skipped. 
>>>>Which is not the behavior that I'm seeing. Instead, I end up 
>>>>asking the user to log in twice: once for my custom Valve (which 
>>>>is a web form/redirect thing), and a second time when they hit a 
>>>>servlet in a context with basic authentication (which causes the 
>>>>browser to put up the basic authentication dialog).
>>>>
>>>>So, what am I missing?
>>>>
>>>>Thanks,
>>>>
>>>>Scott

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


Re: Valve as Custom Authenticator

Posted by Tim Funk <fu...@joedog.org>.
I took a little longer look. All "looks" ok to me. Turn up debugging. Are you 
sure that your valve is being executed before the BasicAuthenticator valve?

-Tim


Scott Kelley wrote:
> SingleSignOn has much the same code as BasicAuthenticator:
> 
> in org.apache.catalina.authenticator.SingleSignOn.java:
> 
>         // Look up the cached Principal associated with this cookie value
>         if (debug >= 1)
>             log(" Checking for cached principal for " + cookie.getValue());
>         SingleSignOnEntry entry = lookup(cookie.getValue());
>         if (entry != null) {
>             if (debug >= 1)
>                 log(" Found cached principal '" +
>                     entry.principal.getName() + "' with auth type '" +
>                     entry.authType + "'");
>             request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
>             ((HttpRequest) request).setAuthType(entry.authType);
>             ((HttpRequest) request).setUserPrincipal(entry.principal);
>         } else {
>             if (debug >= 1)
>                 log(" No cached principal found, erasing SSO cookie");
>             cookie.setMaxAge(0);
>             hres.addCookie(cookie);
>         }
> 
>         // Invoke the next Valve in our pipeline
>         context.invokeNext(request, response);
> 
> The only piece of that I'm not doing is the setNote() part; I *think* 
> that's only used for the form-based login stuff, but I'm not entirely 
> sure-- that's probably the part of the puzzle I still don't understand. 
> The basic authenicator doesn't seem to use it.
> 
> Scott
> 
> At 3:10 PM -0400 6/11/03, Tim Funk wrote:
> 
>> I don't have time to see whats wrong, but check the SingleSignOnValve 
>> as a reference to compare your code.
>>
>> -Tim
>>
>> Scott Kelley wrote:
>>
>>> We've had an Apache/Tomcat configuration deployed for a couple years 
>>> now. Authentication is handled by a custom Apache plugin written in 
>>> C. Everything works great and has been quite reliable.
>>>
>>> Now we would like to move to a standalone Tomcat configuration and 
>>> have been investigating writing a Valve/Authenticator to replace our 
>>> existing Apache plugin.
>>>
>>> I've written a prototype Valve and it does almost everything we need. 
>>> This gives us the ability to require a server-wide login independent 
>>> of how the individual servlet contexts are configured. This ends up 
>>> being Tomcat-specific, but we're ok with that.
>>>
>>> The only problem with the current prototype is that if a user hits a 
>>> servlet or JSP in a Context that's configured for basic 
>>> authentication, they still get the browser-generated basic login 
>>> dialog, even after being logged in with our Valve.
>>>
>>> In my code, I check for a particular cookie, and if I find it, I set 
>>> the user principal in the request to the appropriate user, something 
>>> like this:
>>>
>>>     // Has connection already been authenticated
>>>     // (i.e. do we have the login cookie?)
>>>     Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
>>>
>>>     // If the request has the login cookie, let it pass through
>>>     if (lcookie!=null) {
>>>         log("Found login cookie, validating");
>>>         if (validLoginCookie(lcookie,hreq)) {
>>>             log("cookie is valid, allowing request");
>>>             // See AuthenticatorBase.invoke(), which also sets 
>>> authType and userPrincipal
>>>             // See SignleSignOn.invoke(), which also set authType and 
>>> userPrincipal
>>>             hrequest.getRequest().setUserPrincipal(new 
>>> TempPrincipal("bob_temp_user"));
>>>             hrequest.getRequest().setAuthType("BASIC");
>>>             context.invokeNext(request,response);
>>>         } else {
>>>             log("cookie not valid, going to error page");
>>>             hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
>>>         }
>>>         return;
>>>     }
>>>
>>> I had thought that this would work, because later in the pipeline the 
>>> request hits BasicAuthenticator, which does this:
>>>
>>>     public boolean authenticate(HttpRequest request,
>>>                                 HttpResponse response,
>>>                                 LoginConfig config)
>>>         throws IOException {
>>>
>>>         // Have we already authenticated someone?
>>>         Principal principal =
>>>             ((HttpServletRequest) 
>>> request.getRequest()).getUserPrincipal();
>>>         if (principal != null) {
>>>             if (debug >= 1)
>>>                 log("Already authenticated '" + principal.getName() + 
>>> "'");
>>>             return (true);
>>>         }
>>>
>>>
>>> And since I've set the principal to something besides null, I had 
>>> assumed that the basic authentication would just be skipped. Which is 
>>> not the behavior that I'm seeing. Instead, I end up asking the user 
>>> to log in twice: once for my custom Valve (which is a web 
>>> form/redirect thing), and a second time when they hit a servlet in a 
>>> context with basic authentication (which causes the browser to put up 
>>> the basic authentication dialog).
>>>
>>> So, what am I missing?
>>>
>>> Thanks,
>>>
>>> Scott
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tomcat-user-help@jakarta.apache.org
> 
> 


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


Re: Valve as Custom Authenticator

Posted by Scott Kelley <sk...@biomail.ucsd.edu>.
SingleSignOn has much the same code as BasicAuthenticator:

in org.apache.catalina.authenticator.SingleSignOn.java:

         // Look up the cached Principal associated with this cookie value
         if (debug >= 1)
             log(" Checking for cached principal for " + cookie.getValue());
         SingleSignOnEntry entry = lookup(cookie.getValue());
         if (entry != null) {
             if (debug >= 1)
                 log(" Found cached principal '" +
                     entry.principal.getName() + "' with auth type '" +
                     entry.authType + "'");
             request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
             ((HttpRequest) request).setAuthType(entry.authType);
             ((HttpRequest) request).setUserPrincipal(entry.principal);
         } else {
             if (debug >= 1)
                 log(" No cached principal found, erasing SSO cookie");
             cookie.setMaxAge(0);
             hres.addCookie(cookie);
         }

         // Invoke the next Valve in our pipeline
         context.invokeNext(request, response);

The only piece of that I'm not doing is the setNote() part; I *think* 
that's only used for the form-based login stuff, but I'm not entirely 
sure-- that's probably the part of the puzzle I still don't 
understand. The basic authenicator doesn't seem to use it.

Scott

At 3:10 PM -0400 6/11/03, Tim Funk wrote:
>I don't have time to see whats wrong, but check the 
>SingleSignOnValve as a reference to compare your code.
>
>-Tim
>
>Scott Kelley wrote:
>>We've had an Apache/Tomcat configuration deployed for a couple 
>>years now. Authentication is handled by a custom Apache plugin 
>>written in C. Everything works great and has been quite reliable.
>>
>>Now we would like to move to a standalone Tomcat configuration and 
>>have been investigating writing a Valve/Authenticator to replace 
>>our existing Apache plugin.
>>
>>I've written a prototype Valve and it does almost everything we 
>>need. This gives us the ability to require a server-wide login 
>>independent of how the individual servlet contexts are configured. 
>>This ends up being Tomcat-specific, but we're ok with that.
>>
>>The only problem with the current prototype is that if a user hits 
>>a servlet or JSP in a Context that's configured for basic 
>>authentication, they still get the browser-generated basic login 
>>dialog, even after being logged in with our Valve.
>>
>>In my code, I check for a particular cookie, and if I find it, I 
>>set the user principal in the request to the appropriate user, 
>>something like this:
>>
>>     // Has connection already been authenticated
>>     // (i.e. do we have the login cookie?)
>>     Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
>>
>>     // If the request has the login cookie, let it pass through
>>     if (lcookie!=null) {
>>         log("Found login cookie, validating");
>>         if (validLoginCookie(lcookie,hreq)) {
>>             log("cookie is valid, allowing request");
>>             // See AuthenticatorBase.invoke(), which also sets 
>>authType and userPrincipal
>>             // See SignleSignOn.invoke(), which also set authType 
>>and userPrincipal
>>             hrequest.getRequest().setUserPrincipal(new 
>>TempPrincipal("bob_temp_user"));
>>             hrequest.getRequest().setAuthType("BASIC");
>>             context.invokeNext(request,response);
>>         } else {
>>             log("cookie not valid, going to error page");
>>             hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
>>         }
>>         return;
>>     }
>>
>>I had thought that this would work, because later in the pipeline 
>>the request hits BasicAuthenticator, which does this:
>>
>>     public boolean authenticate(HttpRequest request,
>>                                 HttpResponse response,
>>                                 LoginConfig config)
>>         throws IOException {
>>
>>         // Have we already authenticated someone?
>>         Principal principal =
>>             ((HttpServletRequest) request.getRequest()).getUserPrincipal();
>>         if (principal != null) {
>>             if (debug >= 1)
>>                 log("Already authenticated '" + principal.getName() + "'");
>>             return (true);
>>         }
>>
>>
>>And since I've set the principal to something besides null, I had 
>>assumed that the basic authentication would just be skipped. Which 
>>is not the behavior that I'm seeing. Instead, I end up asking the 
>>user to log in twice: once for my custom Valve (which is a web 
>>form/redirect thing), and a second time when they hit a servlet in 
>>a context with basic authentication (which causes the browser to 
>>put up the basic authentication dialog).
>>
>>So, what am I missing?
>>
>>Thanks,
>>
>>Scott

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


Re: Valve as Custom Authenticator

Posted by Tim Funk <fu...@joedog.org>.
I don't have time to see whats wrong, but check the SingleSignOnValve as a 
reference to compare your code.

-Tim

Scott Kelley wrote:
> We've had an Apache/Tomcat configuration deployed for a couple years 
> now. Authentication is handled by a custom Apache plugin written in C. 
> Everything works great and has been quite reliable.
> 
> Now we would like to move to a standalone Tomcat configuration and have 
> been investigating writing a Valve/Authenticator to replace our existing 
> Apache plugin.
> 
> I've written a prototype Valve and it does almost everything we need. 
> This gives us the ability to require a server-wide login independent of 
> how the individual servlet contexts are configured. This ends up being 
> Tomcat-specific, but we're ok with that.
> 
> The only problem with the current prototype is that if a user hits a 
> servlet or JSP in a Context that's configured for basic authentication, 
> they still get the browser-generated basic login dialog, even after 
> being logged in with our Valve.
> 
> In my code, I check for a particular cookie, and if I find it, I set the 
> user principal in the request to the appropriate user, something like this:
> 
>     // Has connection already been authenticated
>     // (i.e. do we have the login cookie?)
>     Cookie lcookie=ValveUtils.findCookie(hreq,LOGIN_COOKIE_NAME);
> 
>     // If the request has the login cookie, let it pass through
>     if (lcookie!=null) {
>         log("Found login cookie, validating");
>         if (validLoginCookie(lcookie,hreq)) {
>             log("cookie is valid, allowing request");
>             // See AuthenticatorBase.invoke(), which also sets authType 
> and userPrincipal
>             // See SignleSignOn.invoke(), which also set authType and 
> userPrincipal
>             hrequest.getRequest().setUserPrincipal(new 
> TempPrincipal("bob_temp_user"));
>             hrequest.getRequest().setAuthType("BASIC");
>             context.invokeNext(request,response);
>         } else {
>             log("cookie not valid, going to error page");
>             hres.sendRedirect(hres.encodeRedirectURL(ERROR_PAGE_URI));
>         }
>         return;
>     }
> 
> I had thought that this would work, because later in the pipeline the 
> request hits BasicAuthenticator, which does this:
> 
>     public boolean authenticate(HttpRequest request,
>                                 HttpResponse response,
>                                 LoginConfig config)
>         throws IOException {
> 
>         // Have we already authenticated someone?
>         Principal principal =
>             ((HttpServletRequest) request.getRequest()).getUserPrincipal();
>         if (principal != null) {
>             if (debug >= 1)
>                 log("Already authenticated '" + principal.getName() + "'");
>             return (true);
>         }
> 
> 
> And since I've set the principal to something besides null, I had 
> assumed that the basic authentication would just be skipped. Which is 
> not the behavior that I'm seeing. Instead, I end up asking the user to 
> log in twice: once for my custom Valve (which is a web form/redirect 
> thing), and a second time when they hit a servlet in a context with 
> basic authentication (which causes the browser to put up the basic 
> authentication dialog).
> 
> So, what am I missing?
> 
> Thanks,
> 
> Scott
> 
> 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tomcat-user-help@jakarta.apache.org
> 
> 


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