Skip to content

[#2924] - WildcardPermission and DomainPermission lower-case with the JVM default locale - #2925

Merged
lprimak merged 2 commits into
apache:mainfrom
sharanggupta:permission-default-locale
Oct 22, 2026
Merged

lprimak merged 2 commits into
apache:mainfrom
sharanggupta:permission-default-locale

Conversation

@sharanggupta

Copy link
Copy Markdown
Contributor

fixes #2924

What happened: WildcardPermission.setParts implements the default case-insensitive mode with wildcardString.toLowerCase(), and DomainPermission.getDomain derives the domain with clazz.getSimpleName().toLowerCase(). Both follow the JVM default locale. On a JVM whose default locale is Turkish (tr-TR — the default on any Turkish OS/user account; -Duser.language=tr -Duser.country=TR reproduces it anywhere) an uppercase I lower-cases to a dotless ı (U+0131), so the "case-insensitive" comparison is no longer case-insensitive for any token containing I/i:

default locale = tr_TR                       (shiro-core 3.0.1)
"ADMIN:*" implies "admin:read"               = false   (granted parts: admın:*, checked parts: admin:read)
"admin:*" implies "ADMIN:read"               = false
InvoicePermission.getDomain()                = ınvoice
"invoice:*" implies InvoicePermission("view") = false

Under en-US every line is true/invoice. Permission strings are machine-read (realm data, @RequiresPermissions, isPermitted(...)), so a grant stored as ADMIN:* silently stops matching admin:read, and any DomainPermission subclass with a capital I in its name (InvoicePermission, InventoryPermission, …) never matches its configured domain.

This is the same class of bug fixed in SHIRO-415 ("BASIC".toLowerCase() in isLoginAttempt) and SHIRO-483 (passwordsMatch under tr_TR); those fixes used Locale.ENGLISH, as do HttpAuthenticationFilter, SimpleCookie and the hash-format classes today. Secondary site with the same shape: DefaultWebSessionManager looks for the JSESSIONID URL parameter via name.toLowerCase() (jsessıonıd under tr-TR).

How to reproduce: run the snippet above (or any WildcardPermission check with an I in a token) with -Duser.language=tr -Duser.country=TR.

Expected: case-insensitive permission matching independent of the host locale.

Versions: 3.0.1 (and main); any JDK.

Fix: toLowerCase(Locale.ENGLISH) at WildcardPermission.java:158 and DomainPermission.java:98 (+ DefaultWebSessionManager), with a test that sets the default locale to tr-TR around a WildcardPermission("ADMIN:*").implies(new WildcardPermission("admin:read")) check. I have the change ready.

  • I have the right to license this contribution to the Apache Software Foundation under the Apache License, Version 2.0.
  • mvn verify run on core (JDK 21); the new PermissionDefaultLocaleTest is @Isolated because the suite runs methods concurrently.

…th the JVM default locale

WildcardPermission (default case-insensitive mode) and
DomainPermission.getDomain() lower-cased with String.toLowerCase(),
which follows the JVM default locale. Under a Turkish default locale
"ADMIN:*" no longer implied "admin:read" and InvoicePermission derived
the domain "ınvoice" (dotless i). DefaultWebSessionManager looked up the
JSESSIONID URL parameter the same way.

Use Locale.ENGLISH, as the SHIRO-415 and SHIRO-483 fixes did, and add an
@isolated test (the test suite runs methods concurrently) that checks
permission matching under a tr-TR default locale.
@lprimak lprimak added this to the 3.0.2 milestone Oct 22, 2026
@lprimak
lprimak merged commit f839b78 into apache:main Oct 22, 2026
19 checks passed
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.

WildcardPermission and DomainPermission lower-case with the JVM default locale, so permission checks fail under a Turkish locale

2 participants