Before I log in I can hit anything outside of my security constraint directory. If I try to go to a location inside of the security constraint directory it redirects me to the form login page. As you would expect.
Once logged in I can go about my business, and hit resources both outside and inside my security constraint.
But, when the LTPA token expires (Still have an active session) and I try to go to a unrestricted page, lets say like being redirected to the login page, I get the error in the title.
So a few things I would like to figure out: 1. Can I get the LTPA token to not expire like my session? 2. Can I expire my session when the LTPA token does? 3. Why can't I hit an unrestricted page anonymously? It's clearly recognizing that my LTPA token has expired and tries to redirect me to login. At which point it fails.
OK, So got somewhere with a filter. The filter redirects someone who isn't logged in to the login page. But the problem again is as soon as the ltpa token is expired this line fails ((HttpServletRequest) request).getSession(false)
throwing the exception in the title, UnauthorizedSessionRequestException
. So as you can see I tried to catch that error and do a log out. Which, woops, throws another UnauthorizedSessionRequestException
. So how am I to not use the session?
@Override
public void doFilter(final ServletRequest request, final ServletResponse response,
final FilterChain chain) throws IOException, ServletException
{
final String sourceMethod = "doFilter";
if (logger.isLoggable(Level.FINER)) {
logger.entering(sourceClass, sourceMethod, new Object[] { request, response, chain });
}
try {
final HttpSession session = ((HttpServletRequest) request).getSession(false);
final UserBean user = (session != null) ? (UserBean) session.getAttribute("userBean")
: null;
if (user == null || (user != null && !user.isLoggedOn())) {
final HttpServletResponse res = (HttpServletResponse) response;
res.sendRedirect("../login.jsf");
}
} catch (final UnauthorizedSessionRequestException exc) {
((HttpServletRequest) request).logout();
final HttpServletResponse res = (HttpServletResponse) response;
res.sendRedirect("../login.jsf");
} catch (final Exception exc) {
final ServletException exception = new ServletException(
"[UserBeanFilter] Exception doFilter.", exc);
logger.throwing(sourceClass, sourceMethod, exception);
throw exception;
}
chain.doFilter(request, response);
logger.exiting(sourceClass, sourceMethod);
}
Can I get the LTPA token to not expire like my session?
Unfortunately no. LTPA token has fixed timeout, and session has inactivity timeout. If you need you may extend LTPA token timeout for example to 8 hours to avoid expiration.
Why can't I hit an unrestricted page anonymously?
Because it tries to access session which was previously associated with authenticated user. You can allow anonymous access to session by disabling Security integration
setting in Servers > Server Types > WebSphere application servers > server_name > Session management
.
You can also check if Use available authentication data when an unprotected URI is accessed
is enabled in Security > Global security > Authentication > Web and SIP security > General settings
.
It's clearly recognizing that my LTPA token has expired and tries to redirect me to login. At which point it fails.
Try to disable session support on your login page, if it is jsp then try to set <@page session="false">
in the page.
UPDATE
So if you want to be preventive, you can check the LTPA expiration, and based on that logout user before token expires, for example 5 min before. Of course, if user will be inactive for that 5 min, you will still get that exception, but it should be sufficient for 90% of cases.
To get expiration of the token use the following code (pseudo code):
WSSubject subject = WSSubject.getRunAsSubject();
Set<WSCredential> credentials = subject.getPublicCredentials(WSCredential.class);
for(WSCredential credential : credentials) {
// in the most cases you will find only one credential, but if you
// want to be sure you can check credential OID
System.out.println("Exp date:" + new Date(credential.getExpiration()));
System.out.println("userName: " + credential.getSecurityName());
System.out.println("cred: " + credential.getOID());
// if expiration date closer than your threshold - logout user
// ...
}
OIDs for auth mechanisms
BasicAuth (GSSUP): oid:2.23.130.1.1.1
KRB5: OID: 1.2.840.113554.1.2.2
LTPA: oid:1.3.18.0.2.30.2
UPDATE 2
Ok, I found nicer solution for you.
Just set the following flag in session manager:
InvalidateOnUnauthorizedSessionRequestException=true
InvalidateOnUnauthorizedSessionRequestException
Set this property to true if, in response to an unauthorized request, you want the session manager to invalidate a session instead of issuing an UnauthorizedSessionRequestException error message.
When a session is invalidated, the requester can create a new session, but does not have access to any of the previously saved session data. This invalidation allows a single user to continue processing requests after a logout while still protecting session data.
See details in here Session management custom properties