All my custom authentication schemes are now operational! On both 4.1.29 and 5.0.18.
I have had a real tough time, though. Apparently, the subject is complex, since no one
here had any comment.
-----
Together with custom authentication, I can also do HTTP content compression, override
all input in the request like headers and the data to be read from the input-stream on
the way down filter-chains and on the way back up the chains, I can read headers set
upon the response, modify the content of the output-stream and do all sorts of tricks
necessary for internal snooping, modification and filtering.
The custom authentication scheme can also co-exist with one of the usual schemes part
of static servlet-configuration (though not desirable for anything but purposes of
test).
To do these things, I have implemented two generic adapters - one for the request and
one for the response. They both accept a number of plug-ins - a "HeaderResource" and a
"ParameterResource", for instance - same concept like the "IdentityResource"-interface
shown.
And yes, it does make a difference whether "request.getUserPrincipal()" or
"super.getUserPrincipal()" is called - same for headers and so on for all public
method of "HttpServletRequest" and "HttpServletResponse". Using "super" instead of
"request" does do the trick!!!
The default wrappers have side-effects, which are necessary to invoke. I do not know
which, because I have not looked.... Yet. I originally - and after a lot of thought -
chose "request" instead, because this will per-construction avoid cyclic calls, should
one of the methods from the interface "HttpServletRequest" be implemented in
"HttpServletRequestWrapper" by invoking *another* of the interface-methods. It was
intended to safe-guard me from "faulty" wrapper-implementations.
I sure hope, that the guys who implemented
"javax.servlet.http.HttpServletRequestWrapper" and "HttpServletResponseWrapper" did a
real good job. For each servlet-engine in existence.
If no interface-methods are implemented through other interface-methods, then
everything will continue to work. If not, then trouble is ahead somewhere.
Within TC 4.1.29 and 5.0.18, the side-effects are necessary and the default-wrappers
appears to be solid.
To those trying to implement generic wrappers with "plug-in" adapters, I can tell,
that the Servlet-API is not just ideal - that would be so very sad to say -, since for
instance headers can be accessed and modified in multiple ways, the input- and
output-streams can both be accessed in two ways ("getInputStream()", "getReader()" and
"getOutputStream()", "getWriter()") - and so on. So very clumsy - nothing becomes
simple. "HttpServletRequest" and "HttpServletResponse" are reasonable for direct
access, but not for adaption - they should have been designed in at least two levels -
one set for handling the protocol and one set for direct access - just like it is
possible to control streams by implementing "InputStream" and "OutputStream", but have
easy access by adapting them with "DataInputStream" and "DataOutputStream"........
Most certainly impossible to repair at this point in time.
Common API's are far from perfect.
-----
Next time, please give me a hint.
Regards,
Morten Sabroe Mortensen
-----Original Message-----
From: Morten S. Mortensen
Sent: 3. februar 2004 20:09
To: [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED]
Subject: Customized authentication - overriding "getUserPrincipal()"
Hi all,
I am in the process of testing some custom authentication schemes of my own. One
thing, I would like, is to have "request.getUserPrincipal()" and
"request.getAuthType()" return what I tell the request to return.
The "usual" way to grab and manipulate things is to write a filter (or servlet), which
wraps the incoming request and/or response and sends the wrapped versions down the
filter-chain. One should suspect, that e.g. a wrapping of the request ends up in the
request-objects accessible within JSP (possible wrapped again multiple times,
depending upon the implementation of the engine) - so if I override
"getUserPrincipal()" and "getAuthType()" and add a couple of setters
"setUserPrincipal()" and "setAuthType()", I can control the result of
"request.getUserPrincipal().getName()" and "request.getAuthType()".
This I have done.
Actually I created a kind of "plug-in"-object in the form of the interface shown
below; it is supposed to include "isUserInRole()", too. The specializations of this
interface have equivalent methods for setting the content to be returned. This
"IdentityResource" plugs into the type of request-wrapper, which I create in a filter
and use to invoke the filter-chain (of course a specialization of
"javax.servlet.http.HttpServletRequestWrapper").
*Apparently*, somewhere between my filter-chain - which implements the custom
authentication scheme and wraps the request before invoking the filter-chain - and the
actual JSP-pages, which I use as a test, the result og "getAuthType()" and
"getUserPrincipal()" is lost; the two methods return 'null'.
This is somewhat of a disappointment.
Since I suspect, that Tomcat does something with the request in between the
filter-chain and the JSP-page, I have looked a bit at the types. On the "main JSP
page", which I invoke, the request is of type -
"org.apache.coyote.tomcat4.CoyoteRequestFacade"
- and on a sub-page included from the main page with <jsp:include>, the request is of
type -
"org.apache.catalina.core.ApplicationHttpRequest".
This has made me take a look at some of the source-code for this, but I can not find
anything suspect, except that the top appears to.... not wrap the original request,
but ends up in kind of a value-object...
Does something mess with the request before I hit the JSP-page-servlet-thingy?
This realm-plugin-facility, which Tomcat has built in - it does not touch the
request-object passed between filters and JSP-page-servlets?
Somehow it does not work. Maybe I have screwed something up in my code, but after a
lot of investigation, I do not thing this is the case.
Anyone care to comment?
Who knows some details?
Anyone have tried something similar?
(yes, I now that the subject of "custom authentication schemes" within Servlets has
been discussed, but postponed - but the construction, I try, should never the less be
possible, if wrapping is done consistently)
? ? ?
Regards,
Morten Sabroe Mortensen
-----
/*** FILE "IdentityResource.java" *********************************************/
/******************************************************************************/
/** **/
/** 2003-10-28 Morten Sabroe Mortensen. **/
/** **/
/******************************************************************************/
/*
* $Log$
*/
package dk.tefs.J2EE.servlet.resource.http.identity;
import java.security.*;
import java.util.*;
/*** IdentityResource: ********************************************************/
/**
* Identification of a authenticated user.
*
* @author <a href="mailto:[EMAIL PROTECTED]"
* >Morten Sabroe Mortensen</a>
* @version 1.0
*/
public interface IdentityResource
{
/**
* Gets the name of the authentication scheme used to protect
* the requested resource.
* @see javax.servlet.http.HttpServletRequest#getAuthType
* @return Name of authentication scheme.
*/
String getAuthType();
/**
* Indicates, whether the authenticated user is included in
* a specified logical "role".
* @see javax.servlet.http.HttpServletRequest#isUserInRole
* @param role Logical role to get indication for.
* @return Indicates, if the role indicates the authenticated user.
*/
boolean isUserInRole(String role);
/**
* Gets a representation of the authenticated user, if any.
* If the user has not been authenticated,
* this return <code>null</code>.
* @see javax.servlet.http.HttpServletRequest#getUserPrincipal
* @return Representation of the authenticated user.
*/
Principal getUserPrincipal();
/**
* Gets the name of the authenticated user, if any.
* @see javax.servlet.http.HttpServletRequest#getRemoteUser
* @return Name of authenticated user.
*/
String getRemoteUser();
}
/******** "IdentityResource.java" *********************************************/
-----
Fragment of "HttpServletRequestWrapper"-instance used to invoke filter-chain:
/**
* Wrapped request.
*/
protected HttpServletRequest request;
/**
* Alternative identity-resource.
*/
private IdentityResource identity;
/**
* Sets the identity-resource.
* @param identity Identity-resource.
*/
public void setIdentityResource(IdentityResource identity)
{
this.identity=identity;
}
/**
*
*/
public Principal getUserPrincipal()
{
Principal res=null;
{
if (identity!=null)
{
res=identity.getUserPrincipal();
}
else
{
res=request.getUserPrincipal();
//Note: It does a difference if 'super' or 'request' is called here!
}
}
return res;
}
-----
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]