Skip to content

Fix broken login flow in shiro-basic example - #545

Merged
lukaszlenart merged 1 commit into
mainfrom
fix/shiro-basic-login-flow
Aug 14, 2026
Merged

Fix broken login flow in shiro-basic example#545
lukaszlenart merged 1 commit into
mainfrom
fix/shiro-basic-login-flow

Conversation

@lukaszlenart

Copy link
Copy Markdown
Member

Makes the shiro-basic example usable again. It follows #536 (Shiro 3.0.0), which fixed the module's startup — this fixes the login flow that was broken underneath it.

What was wrong

Two independent problems, both pre-existing:

1. Infinite redirect loop. shiro.ini defined only [users] and [roles], with no filter chain, so Shiro protected every path — including the login page and the form it posts to. Unauthenticated visitors were redirected to Shiro's default loginUrl of /login.jsp, which does not exist in this webapp (the form is rendered by the login Struts action). Every URL redirected to a page that redirected again; I measured 50 redirects without resolving.

Worth noting for anyone fixing something similar: shiroFilter is mapped for FORWARD as well as REQUEST, so the JSPs the Struts actions forward to are filtered too. Listing only the actions as anon is not enough — /pages/login.jsp has to be listed as well.

2. HTTP 400 on a visitor's first request. With no session cookie yet, the container rewrote the redirect as .../login.action;jsessionid=..., and Jetty 11 rejects that URI with 400 Invalid request. It only affected the first request, which made it easy to miss — a reload appeared to "fix" it.

The fix

  • shiro.ini gains a [main] section pointing authc.loginUrl at /login.action, and a [urls] chain that leaves the login path anonymous and protects everything else. Authentication itself stays programmatic in LoginAction; authc only decides where to send an unauthenticated visitor.
  • web.xml restricts session tracking to COOKIE, which stops the URL rewriting.

Verification

Ran under mvn jetty:run and exercised the flow in a browser and over HTTP:

  • / → login form renders (one redirect, no loop, no ;jsessionid=)
  • login as lonestarr → welcome page showing Welcome lonestarr, the schwartz role, and both lightsaber and winnebago:drive:eagle5 permissions — so authentication, role resolution, and permission checks all work under Shiro 3.0.0
  • logout → returns to the login page
  • welcome.action after logout → redirects to the login page, confirming the chain actually protects it rather than just being loop-free

mvn clean test passes on JDK 17.

🤖 Generated with Claude Code

The example was unusable: every request redirected to Shiro's default
loginUrl of /login.jsp, which does not exist here, producing an infinite
redirect loop. shiro.ini defined only [users] and [roles], so no filter
chain was configured and Shiro protected every path including the login
page and the form it posts to. Because shiroFilter is mapped for FORWARD
as well as REQUEST, the JSPs the Struts actions forward to were caught
too, so listing only the actions would not have been enough.

Adds a [main] section pointing authc at the login action, and a [urls]
chain leaving the login path anonymous while protecting the rest.

Separately, the container rewrote redirect URLs as ...;jsessionid=... on
a visitor's first request, and Jetty 11 rejects its own rewritten URI
with HTTP 400 Invalid request. Restricting session tracking to cookies
stops the rewriting.

Verified in a browser and over HTTP: login as lonestarr renders the
welcome page with roles and permissions resolved, logout returns to the
login page, and welcome.action is no longer reachable afterwards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lukaszlenart
lukaszlenart merged commit b8b977a into main Aug 14, 2026
2 checks passed
@lukaszlenart
lukaszlenart deleted the fix/shiro-basic-login-flow branch August 14, 2026 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant