Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SHIRO-512] catch SessionException in getRunAsPrincipalsStack #372

Merged
merged 2 commits into from
Sep 15, 2022

Conversation

lprimak
Copy link
Contributor

@lprimak lprimak commented Sep 5, 2022

Fixes SHIRO-512
Fixes flowlogix/flowlogix#284

Following this checklist to help us incorporate your contribution quickly and easily:

  • Make sure there is a JIRA issue filed
    for the change (usually before you start working on it). Trivial changes like typos do not
    require a JIRA issue. Your pull request should address just this issue, without pulling in other changes.
  • Each commit in the pull request should have a meaningful subject line and body.
  • Format the pull request title like [SHIRO-XXX] - Fixes bug in SessionManager,
    where you replace SHIRO-XXX with the appropriate JIRA issue. Best practice
    is to use the JIRA issue title in the pull request title and in the first line of the commit message.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Run mvn clean install apache-rat:check to make sure basic checks pass. A more thorough check will be performed on your pull request automatically.
  • If you have a group of commits related to the same change, please squash your commits into one and force push your branch using git rebase -i.

Trivial changes like typos do not require a JIRA issue (javadoc, comments...).
In this case, just format the pull request title like (DOC) - Add javadoc in SessionManager.

If this is your first contribution, you have to read the Contribution Guidelines

If your pull request is about ~20 lines of code you don't need to sign an Individual Contributor License Agreement
if you are unsure please ask on the developers list.

To make clear that you license your contribution under the Apache License Version 2.0, January 2004
you have to acknowledge this by using the following check-box.

@sunshineandy
Copy link

sunshineandy commented Sep 5, 2022 via email

@lprimak lprimak closed this Sep 5, 2022
@lprimak lprimak reopened this Sep 5, 2022
@lprimak
Copy link
Contributor Author

lprimak commented Sep 5, 2022

Something's wrong with Jenkins environment:

com.github.mjeanroy.junit.servers.exceptions.ServerStartException: java.io.IOException: Failed to bind to 0.0.0.0/0.0.0.0:37081
Caused by: java.io.IOException: Failed to bind to 0.0.0.0/0.0.0.0:37081
Caused by: java.net.BindException: Address already in use
@fpapon fpapon self-requested a review September 5, 2022 06:09
Copy link
Member

@fpapon fpapon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
Thanks for your contribution!

Comment on lines 474 to 479
try {
return (List<PrincipalCollection>) session.getAttribute(RUN_AS_PRINCIPALS_SESSION_KEY);
} catch (SessionException se) {
log.debug("Encountered session exception trying to get 'runAs' principal stack. This "
+ "can generally safely be ignored.", se);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some more information? Not sure whether it should be a comment or go into the exception message, though. Can you elaboare, WHY this can be ignored and WHY and WHEN this occurs? Is it true it only occurs on Tomcat? Shouldn't we file an issue there instead?

Copy link
Member

@fpapon fpapon Sep 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exception seems to be a race condition on Tomcat but appear randomly so I'm not sure we can find more information in the exception and it could be hard to reproduce.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underlying IllegalStateException is thrown, if the session is invalidated (servlet spec).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see the underlying JIRA. It's not only Tomcat, but any other servlet container.
I have reproduced it on both Payara, Glassfish and Jetty.
There is also the same try/catch block on clearRunAsIdentitiesInternal() for the same reason.

I did add some comments to the code

@lprimak lprimak marked this pull request as draft September 5, 2022 15:29
@lprimak lprimak marked this pull request as ready for review September 5, 2022 15:53
@fpapon fpapon merged commit e1df06b into apache:main Sep 15, 2022
@lprimak lprimak deleted the session-invalidation-race branch September 15, 2022 19:36
// this thread could throw this exception, so we catch it
// similar issue as in clearRunAsIdentitiesInternal()
// See https://issues.apache.org/jira/browse/SHIRO-512
log.debug("Encountered session exception trying to get 'runAs' principal stack. This "

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not trying to be rude, I'm legitimately trying to understand, how is this safe to ignore? This appears to be the reason one of my unit tests is failing now after bumping Shiro up to 1.10.0

So if Thread_1 invalidates the subject, then Thread_2 attempts to get the session, this block here would originally throw an exception to Thread_2 informing that the session has been invalidated. But now Thread_2 will catch and just log the exception instead. This would essentially let Thread_2 believe the subject is still authenticated, when the session should actually be invalidated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamenveil
I can sort of see both sides of this. I think what this change was trying to prevent was:

  1. Thread 1 - calls Session session = getSession(false); // valid session returned
  2. Thread 2 - calls session.invalidate(); // somewhere else in the code
  3. Thread 1 - calls session.getAttribute(RUN_AS_PRINCIPALS_SESSION_KEY); // that throws an exception, the session is invalid.
  4. Thread 1 - the getRunAsPrincipalsStack method returns null

If this same flow of events happened in a different order:

  1. Thread 1 - calls Session session = getSession(false); // valid session returned
  2. Thread 1 - calls session.getAttribute(RUN_AS_PRINCIPALS_SESSION_KEY); // object returned
  3. Thread 2 - calls session.invalidate(); // somewhere else in the code

The caller of getRunAsPrincipalsStack() doesn't know the session has been invalidated.

Or in the order of:

  1. Thread 2 - calls session.invalidate(); // somewhere else in the code
  2. Thread 1 - calls Session session = getSession(false); // null is returned
  3. Thread 1 - the getRunAsPrincipalsStack method returns null

Can you give us an idea of what your code is doing maybe there is something else we could do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamenveil Think of a session is an implementation detail, and that's all.
Previous code had an exception leak through because of the session invalidation.
Some of which could never be caught (if it was in the web flow) and thus random exception logs would appear,
as stated in the multiple commenters in the JIRA
It's notgetRunAsPrincipalsStack job to check if the session is invalid. If it is, it just returns null in the new code,
which is the correct behavior.

Think about it like this: old code forced to check an (unrelated) session validity in every call to Shiro, which is not the right thing for an API to do.

API needs to handle it's own errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e. it's not specified that the subject is automatically logged out when session is invalidated.
Proper way (according to the API) to log a subject out is SecurityUtils.getSubject().invalidate() and not session.invalidate()

It is true that Shiro could add HttpSession listeners and automatically log the subject out if a session gets invalidated, but neither the old nor new code does this, perhaps this could be an additional feature in the future, but certainly not a showstopper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
7 participants