Costin Manolache wrote:
> > This is one of the reasons that I defined a separate Realm object in the
> > Catalina architecture (see directory "proposals/catalina" in the source CVS
> > repository). A Realm is a very thin API that provides only what the servlet
> > container needs to satisfy its requirements -- implementations on top of JNDI,
> > JAAS, or whatever are quite easy to create.
>
> That's exactly what I said - but in reverse :-)
>
> - How do you plan to integrate between web-server-based authentication
> and tomcat ? ( static files are served by the web server ).
Two different approaches are feasible:
* A Realm implementation that directly reads the same files, or
* A Realm implementation that knows it's running with a web server
connector and uses the proprietary webserver-Tomcat protocol to
ask the questions it needs.
In other words, its exactly the same amount of new code you would add in a subclass
of SecurityCheck to do the same thing.
>
> - How can you implement "trust only users from a certain IP domain ( a very valid
> and common security restriction )"?
>
Even easier (and doesn't require a Realm) - a Valve that looks at the value returned
by getRemoteAddr() or getRemoteHost() and applies the filters you've configured. One
thing Valves can do that RequestInterceptors cannot is to handle the request and
return (in this case, the IP filter Valve would return
HttpServletResponse.SC_FORBIDDEN), instead of passing the request on to the rest of
the engine - in particular, no Valve or Container after this filter would even see
requests from invalid IP domains. You'd undoubtedly deploy this Valve earlier in the
request processing pipeline than the security check, to avoid wasting the time to
look up a user you're not going to accept anyway because of the IP address filtering.
>
> And most important question:
>
> Why use an interface that doesn't provide you anything that is not already
> available, but reduce the flexibility and add complexity ?
>
As Stefano would say :-), the issue is "separation of concerns". The fundamental
design issue that Catalina changes vs. Tomcat 3.x (in respect to security) is a
separation between the following concepts:
* the mechanics of enforching the authentication rules defined in web.xml
(for example, doing the challenge for BASIC authentication).
* the "database-like" lookup of users and roles, by default done against
the "MemoryRealm" private class in SecurityCheck.
In the current architecture, you have to subclass SecurityCheck to create a link to
something different than the conf/tomcat-users.xml file -- as Mark did. Now,
consider some issues:
* How do you implement request.isUserInRole()? (This was Mark's
comment that sparked the current discussion). Currently, there's
no way for the request implementation to "get to" the underlying
realm you've loaded into the interceptor. The proposed solution
is to add yet another method callback to the 9 or 10 already there
in RequestInterceptor. Like most of the other ones, this is only
needed to get around the fact that the two concepts above are
combined instead of separated.
* What happens when another authentication method is added in
some future version of the servlet API? The current architecture
forces you to add it to SecurityCheck (plus side effects on at least
three other source modules, instead of being able to do everything
in one place). With Catalina, you can do that all in a single class,
or define a separate Valve for each type of authentication that is
installed when you read web.xml to see what is necessary. And,
you can mix and match any authentication method with any Realm
implementation -- they don't have a common subclass, so they
can be developed and deployed independently.
Finally, it's amusing to note that this doesn't really add a new kind of object :-).
We already have a MemoryRealm object with similar characteristics -- it's just hidden
inside SecurityCheck (as a private class) instead of being public where it is more
useful.
>
> What is missing in the current model? It seems all web servers ( IIS, Nes, Apache
> at least) are doing fine with the filter/SAF/module model.
>
One particular thing that's missing is a way to implement isUserInRole() without
adding another callback.
On a larger scale, and as we will discuss more, I'm sure, Tomcat is not a web server
-- that problem has been solved quite nicely, thank you. Instead, it is a container
for web based applications, which do not necessarily have the same requirements for
functionality (or even the same sweet spots for performance optimizations).
Doing things in Tomcat "just because web servers do them that way" is not a
sufficient argument, without understanding the costs imposed by that design. (For
example, have you counted the number of empty method calls the current Interceptor
design causes to happen on every request? They are fairly cheap, but they are
definitely not free.)
>
> The interceptor is not supposed to implement password-based authentication -
> it is just a _bridge_ between tomcat and the real backend - that can be anything,
> including Realm ( or JAAS, or JNDI ). With the addition that you can take
> complex decisions based on the full request.
> Reading from JAAS - it may be a smart card or an eye-scanning device -
> hard to fit it into authenticate( String user, char credentials[]) :-)
>
No difference if the Realm is publicly visible or not. If Realms need the full
request content to authenticate (probably necessary for SSL-based authentication at
least), adding another authenticate() message signature to pass it will be the right
answer.
>
> > But of course - a different class needs to be used to authenticate using
>
> > > SSL certificates for example.
> > > And another type to just integrate with the Apache auth ( if you
> > > let apache do the authentication and authorization - you don't want
> > > your static files authenticated from a different database, and it's
> > > clear that static files served by apache is important to support)
> > >
> >
> > The logic of performing BASIC or DIGEST of FORM based authentication is plenty
> > complicated enough, without trying to mold in authentication lookups. It is
> > also *independent* of the way that you do the password authentication and role
> > identification. That really needs to be its own component.
>
> Yes - the interceptor is not supposed to implement authentication lookups, but to
> _use_ a component. With the difference that the authentication component is not
> imposed by tomcat, but it's anything you want, with any interface. It needs to be
> in its own component - but the component is not under our control, we should use
> existing systems where possible.
>
The *interface* to the component is being defined (that's what Realm is for) so you
can plug in the implementation you want. This interface defines only what Tomcat
needs to satisfy its questions ("is this user authenticated?" "is this user in this
role?"). Realm does not impose any restrictions on *how* those questions are
answered.
As mentioned above, you've already done exactly the same thing inside SecurityCheck
-- it's just hidden, so it's not useful quite everywhere it needs to be. I'm
proposing that people be able to implement realms independent of messing with
SecurityCheck.
>
> Costin
>
Craig