Jerry,
On 12/30/23 01:20, Jerry Malcolm wrote:
Chris,
On 12/29/2023 11:22 AM, Christopher Schultz wrote:
Jerry,
On 12/28/23 18:33, Jerry Malcolm wrote:
Chris,
On 12/28/2023 3:38 PM, Christopher Schultz wrote:
Jerry.
On 12/27/23 02:13, Jerry Malcolm wrote:
I implemented the filter as you suggested. But I guess I'm going
to need some education on sessions. Down in a user profile web
page I have a button to "Impersonate".
I'm with you so far.
I create the GenericPrincipal object and store it in the session.
I've checked several times, and every time I come back to that
code, the attribute is set in the session object.
Good. When you do that, do you remove the "real" user's
GenericPrincipal object from the session? Or are they both in there?
>
Sorry... lost you on that one. I am just setting a custom >
"GenericPrincipal" attribute named "impersonatedPrincipal" in the
session when a user clicks the "Impersonate" button on the web page.
This answers my question. I was wondering if you do this:
session.setAttribute("user", impersonatedUser); // Replace
or this:
session.setAttribut("impersonatedUser", impersonatedUser);
And it seems you are doing the second one.
In my understanding, at this point I'm just 'telling' the session
that on subsequent requests in the custom filter, here's a principal
object that I want to insert.
As long as your code agrees with you :)
I also noted in your early example that you stored a 'User' class as
the attribute in the session, not a GenericPrincipal. I couldn't
find a "User" class. So I just used GenericPrincipal, since that was
what I will insert in the request object in the filter.
We use User in our session, and essentially wrap it in a
GenericPrincipal when necessary. We are playing a lot of games, here,
in our code, so I apologize if we go down this road and it's a lot
longer than you had expected...
Remember that if Tomcat is going to enforce your authentication and
authorization constraints, your Filter will run after that, and
Tomcat and your application will disagree over which user is
currently logged-in.
>
I'm not removing the real principal from anything. Not sure how to
do that? in HttpSession? in HttpRequest? I assumed returning my
new GenericPrincipal in the RequestFacade would override any other
code asking for the principal.
It will... unless that code runs before your Filter has a chance to
pull the wool over the application's eyes. For example... Tomcat's
authentication and authorization code will run in a Valve, which runs
before all Filters.
How do I go about removing the real principal?
Let's save that for later ;)
But when I put breakpoint in my new Filter object and look in the
session, no attribute. It's a different session object from what I
can tell.
That's weird.
When you say "every time I come back to that code, the attribute is
set in the session" ... what code are you taking about?
>
The filter's 'version' of the session doesn't have the
"impersonatedPrincipal" attribute set (it doesn't have any attributes
set). But after clicking Impersonate, hitting the breakpoint, and
watching the session attribute get set, I hit F5 to refresh the page.
The filter breakpoint again doesn't have the attribute. But if I
click "Impersonate" again and hit that breakpoint the
"impersonatedPrincipal" session attribute exists in the session.
Is the session identifier changing?
I really thought I understood session objects. I thought there was
only one session object throughout the processing of a servlet.
Yes, if s/servlet/request/.
But I'm obviously missing something in the flows. Why is there a
different session object in the filter than in the main body of the
servlet? I did the getSession(false) as you suggested. The session
object is not null. It just doesn't have the attribute set. Yet if
I hit the Impersonate button again and hit the breakpoint, the
GenericPrincipal attribute is sitting in the session just as I placed
it earlier.
If the difference between when Tomcat evaluates e.g. user-roles
versus when your application does won't explain what's happening, we
might need to see some code.
Code:
Other than a loop that builds a Roles vector, these are the two lines
that create the session attribute when the "Impersonate" button is
clicked.
GenericPrincipal newPrincipal = new GenericPrincipal( getUserName(),
getPassword(),
roles );
getCtrl().getRequest().getSession(false).setAttribute(
"impersonatedPrincipal", newPrincipal );
Hmm. What are Ctrl and Request that you are "getting"? Usually, both
the servlet and the Filter see objects passed to them directly in the
doFilter() and service()/doGet/doPost/whatever methods in the servlet.
And this is the filter:
PrintWriter out = response.getWriter();
HttpSession session =
((HttpServletRequest)request).getSession(false);
if(session != null)
{
final GenericPrincipal impersonatedPrincipal =
(GenericPrincipal) session.getAttribute("impersonatedPrincipal");
if (impersonatedPrincipal != null)
{
System.out.println( "Impersonating");
request = new
HttpServletRequestWrapper((HttpServletRequest)request)
{
public Principal getUserPrincipal()
{
return impersonatedPrincipal;
}
};
}
}
chain.doFilter(request, response);
I feel like I'm right on top of the solution. But I just can't seem
to get over the finish line. Thanks for you help.
Filter looks good. The other code looks sus.
-chris
The saga continues... the Ctrl object is simply a briefcase object that
stores the request object and a bunch of other objects that my model
code needs . The request is passed in on the Ctrl class constructor. So
it is definitely the same request (and therefore the same session) that
comes in on the doGet/doPost method on the servlet.
I added a println of the session id in the filter and in the code that
sets the Principal object in the session. I'm beginning to see the
problem. I have quite a few web apps running in this host. I realize
now that each one has its own session. I'm surprised that the session
id that sets the attribute doesn't match any of the other sessions. But
I realize that at best this is not going to work correctly unless I set
the impersonatedPrinicipal object in every session in the host. I use
SingleSignon. But SingleSignon won't propagate a custom session
attribute to all of the other sessions in the host, will it?
Nope. Single sign-in just propagates authentication information across
the web applications. They definitely do not share sessions.
Because I wanted the filter to work on all web apps, I added the filter
definition to the /conf/web.xml instead of in every web app's web.xml.
Does the global web.xml file have a separate session from all of the
other web app sessions?
Yep. Setting the filter in conf/web.xml has the effect of separately
configuring it by default for all applications, but they aren't shared
in any way.
If I understand what should happen here, the sole purpose of the session
object attribute is to keep track of an impersontated GenericPrincipal
object that I want to use, and to tell the filter to set this as the
Principal for this request if the attribute exists. It's beginning to
seem like the session object(s) may not be the best place to store the
Principal object for the filter to use, given all of the instances of
session.
Probably not. I think maybe this whole approach is not going to work. I
didn't realize you had multiple applications in play. This will probably
require a different strategy. :/
As a possible alternative, I figure it might introduce
additional security risks, but would it be possible to serialize the
impersonatedPrincipal object and pass it back and forth as a cookie? The
filter would check for the cookie and deserialize it and install it as
the UserPrincipal the same way I was trying to do it by storing it in
the session. At least a session cookie would come to all web apps,
correct? Is there a better place to store the impersonatedPrincipal
that would be easily accessible to all webapps?
I wouldn't use GenericPrincipal. I wouldn't use serialization. And I
wouldn't use a Cookie. Instead, I might look at something like JWT (JSON
Web Token) as a way to pass authentication information from one
application to another one. I suppose you could do it via a cookie if
you need it to follow you around through all the various web applications.
This will probably require you to write a custom authentication module
for Tomcat. You could subclass an existing authentication module such as
FormAuthenticator and have it look for a custom cookie containing
authentication information, and fall back to the superclass's behavior
of asking for a form-based login.
The reason I suggest JWT is because the technology exists, you can
easily get Java libraries for it, and it's as secure as you are willing
to make it. Basically, you take some name/value pairs, shove them into a
map, sign it, and you get a JWT. The recipient verifies the signature
using a trusted certificate (you can do it other ways, but this is best
IMHO) and does whatever is appropriate -- such as setting the Principal
on the request/session/whatever.
Here is the list of sessionIds from just bringing up the home page and
the page to set the impersonatedPrincipal attribute. About halfway
down, you'll see the sessionId that I actually stored the
impersonatedPrincipal in.
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: FFB83D207968FBF944D36E86F50A8871
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
ImpersonateFilter: 20121D0DA12AC42E95F0567820D925EA
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
ImpersonateFilter: FFB83D207968FBF944D36E86F50A8871
ImpersonateFilter: FFB83D207968FBF944D36E86F50A8871
ImpersonateFilter: FFB83D207968FBF944D36E86F50A8871
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
ImpersonateFilter: 6A71E7CB18268BAD8A8A2427D264A794
Set session attribute: E6412E5B6419E06D5233F53D40D88E9E
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: 640691F73EB2139A1BA88E47D2FB189F
ImpersonateFilter: 640691F73EB2139A1BA88E47D2FB189F
ImpersonateFilter: 640691F73EB2139A1BA88E47D2FB189F
ImpersonateFilter: 20121D0DA12AC42E95F0567820D925EA
ImpersonateFilter: 640691F73EB2139A1BA88E47D2FB189F
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
ImpersonateFilter: F4D2C34AEBF4980D796D126EA99EE22A
That's ... a lot of applications.
I think a custom authenticator is going to be your best bet.
How does your application authenticate users primarily?
-chris
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org