I made an extension which allows you to choose your
own implementation of SecurityRequestWrapper.
Example:
Suppose we have a special kind of realm in which users
have certain roles in certain groups. If we want to check
if a principal has a certain role, we also have to provide
the group (because the roles of a principal depend on
the group you consider). So
realm.isUserInRole(getUserPrincipal(), role);
becomes
groupRealm.isUserInRole(getUserPrincipal(), role,
group);
This is something which can be nicely done in the
SecurityRequestWrapper, without changing the
interface of SecurityRequestWrapper. The wrapper
implements the isUserInRole(String role) method by
retrieving the group from the request and passing it to
the realm.
Therefore it would be nice to make it possible to use
another implementation of the SecurityRequestWrapper.
This can be done by using a RequestWrapperFactory to
create the SecurityRequestWrapper objects. The
implementation of the specific factory can be configured
in security-filter.xml, which also allows you to pass
some factory-params (name, value).
If no factory is specified in security-filter.xml, a default
factory will return the current implementation of
SecurityRequestWrapper.
diff of changed files
new file: factory interface
new file: default factory implementation
Logged In: YES
user_id=590231
ABOUT THE FUNCTIONAL REQUIREMENTS:
I see that having a more flexible schema for the users and
roles/groups would be nice for some applications. The one you
describe seems like it would apply to many different situations.
However, the users and roles (a.k.a. groups) structure is well
established and baked into many, many systems. Fortunately, it
is very easy to map the schema you desire to the established
system.
"user", "group", "role" -- maps to --> "user", "group.role"
By doing this mapping, you can use all the existing realm
implementations, security frameworks, etc. without having to
change anything.
Does that meet your needs?
ABOUT THE IMPLEMENTATION METHOD:
One issue with changing/extending the request interface is that
you aren't always going to get what you expect. Consider a case
where you have two filters deployed -- SecurityFilter and another
filter that does logging or something, call it LoggingFilter. If a
request comes in, it will be handled by SecurityFilter, and passed
down the chain with a SecurityRequestWrapper wrapped request
object. Then LoggingFilter gets it, wraps the request again in
LoggingRequestWrapper and then finally it arrives at a servlet or
JSP in the app. If the app tries to cast the request it gets to
SecurityRequestWrapper to access some extended functionality,
you will get a ClassCastException, since the request is really a
LoggingRequestWrapper. You severely limit your ability to use
other filters in that scenario, which is kind of at odds with their
chainable nature. I don't even think you are really guarateed that
you will get the request object exactly as your last filter wraps it --
the container may be free to wrap it again if it wants to (though I
don't think any containers do this).
Extentions to the HttpServletRequest (or response) interfaces
have this bad architectural side effect, so I think it is good to
stick with the standard interfaces. It would be cool if the request
could sort of gain functionality as it gets wrapped, and all the
interface extensions would be available, but you lose some of the
meaning of the wrapping concept that way, so I don't think that
would really be a good idea after all.
Here is one architectural solution I thought of for this kind of
extension: You can have your filter stuff a reference to itself, the
request wrapper, or some other object that provides extended
services into the request scope so that you can access it at any
time after the request passes through the filter. You could have a
static method on a class somewhere that you pass the request to
that would dig the reference out of the request and return a
handle to the service provider object (i.e. the filter, the request
wrapper, some other object).
-Max