Skip to content

Conversation

@mgaffigan
Copy link
Contributor

Closes #122 / original #5569 by:

  • Normalizing username after login success
  • Using case-insensitive comparisons in DB

Implementation Notes:

  • Used LOWER() in pgsql instead of collation to avoid having to rely upon system defaults or database defined collation. Presumably table is not so large that sargability is a concern (since we're loading the full table to the client on each login)
  • No collation support seems to exist in Derby, so LOWER()
  • MSSQL and MySQL already case insensitive by system default

@david-labs-ca
Copy link

So, John.doe and john.doe are same person?

@mgaffigan
Copy link
Contributor Author

@david-labs-ca, there's discussion on the original ticket.

I think the world at large usually assumes usernames to be case-insensitive. It's also just plum broken on several case-insensitive database engines in main, so if the decision were to make them case sensitive, a change would still be required.

@tonygermano
Copy link
Member

@david-labs-ca, there's discussion on the original ticket.

I think the world at large usually assumes usernames to be case-insensitive. It's also just plum broken on several case-insensitive database engines in main, so if the decision were to make them case sensitive, a change would still be required.

I get angry any time I encounter a system with case-sensitive usernames. I expect to always be able to type my username in all lowercase, regardless of how the admin added it to the system.

@tonygermano
Copy link
Member

suggestion: don't assume anything about which charset, collation, or locale are in use

I think it would be a good idea to use LOWER(USERNAME) = LOWER(#{username}) across all databases, and if that returns multiple results because a case-sensitive collation is in use and there are similar names, then fall back to USERNAME = #{username}.

@mgaffigan
Copy link
Contributor Author

@tonygermano
Re: collation, at a certain level every string compare is done in the context of a collation, implicit or explicit. UPPER and LOWER also produce sargability challenges. In my experience, you will make more DBA friends with COLLATE than with LOWER(...). The only reason I did not use COLLATE uniformly is to avoid DDL changes.

Re: existing users, I've added a fallback to match case-sensitive if multiple users match. Adding a new user with a different casing fails with com.mirth.connect.client.core.ControllerException: Error adding user: username must be unique

@tonygermano
Copy link
Member

@tonygermano Re: collation, at a certain level every string compare is done in the context of a collation, implicit or explicit. UPPER and LOWER also produce sargability challenges. In my experience, you will make more DBA friends with COLLATE than with LOWER(...). The only reason I did not use COLLATE uniformly is to avoid DDL changes.

@mgaffigan I don't think the PERSON table is expected to get very large where a scan would be a problem, and this seems evident because there isn't an index on USERNAME. In this case, I think it's better to be safe and use the standard SQL function without making assumptions about the environment rather than going for performance. LOWER should work across all databases respecting their current collation, character encoding, and locale.

This is completely up to you, but if you want to address this issue, too, it's related nextgenhealthcare/connect#3386

@mgaffigan mgaffigan force-pushed the feature/case-insensitive-username branch from 6d64ab2 to 4f8bcdd Compare November 26, 2025 18:41
@mgaffigan
Copy link
Contributor Author

@tonygermano, I still think COLLATE is the correct way to do this - but I've updated it to use LOWER(...). Let me know if you see any blockers.

@tonygermano
Copy link
Member

@mgaffigan for completeness, what are your thoughts on updating mysql-user.xml and sqlserver-user.xml, too? Though it's not needed for a default configuration, both of these servers can be configured to be case sensitive.

@mgaffigan
Copy link
Contributor Author

@mgaffigan for completeness, what are your thoughts on updating mysql-user.xml and sqlserver-user.xml, too?

If it will get the PR merged, I'm unopposed.

I do not think it is called for, but I do not like lower to start with. If those default collations are changed, the system is likely running with locale specific collation that is more correct than what lower would provide. Running with a non-default collation is also something I would call an unsupported configuration.

From a maintenance perspective I think it is counterproductive to keep the different database server scripts in sync: I've never found SQL to be an actually portable language at scale (DDL aside, the query engines are too different). The appropriate interface for changing persistence is at the DAL - not at SQL. This also allows in memory stores for unit tests, no-SQL, etc.

Signed-off-by: Mitch Gaffigan <mitch.gaffigan@comcast.net>
Signed-off-by: Mitch Gaffigan <mitch.gaffigan@comcast.net>
@mgaffigan mgaffigan force-pushed the feature/case-insensitive-username branch from 4f8bcdd to 1ff71d4 Compare November 29, 2025 18:36
@mgaffigan mgaffigan requested a review from Copilot November 29, 2025 18:36
Copilot finished reviewing on behalf of mgaffigan November 29, 2025 18:40
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an issue where usernames were treated as case-sensitive, making it inconsistent and potentially confusing for users. The implementation makes username comparisons case-insensitive across all supported database systems while preserving the original casing stored in the database and preferring exact case matches when multiple users exist with different casing (for backward compatibility).

Key changes:

  • Modified database queries to use case-insensitive username comparison via LOWER() function
  • Updated getUser() method to handle potential multiple results and prefer exact case matches
  • Enhanced LoginStatus to return the normalized username from the database to the client

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
server/src/com/mirth/connect/server/controllers/DefaultUserController.java Updated getUser() to return lists and prefer case-sensitive matches; updated authorizeUser() to pass normalized username to LoginStatus
server/dbconf/postgres/postgres-user.xml Added case-insensitive username comparison using LOWER() function
server/dbconf/sqlserver/sqlserver-user.xml Added case-insensitive username comparison using LOWER() function
server/dbconf/oracle/oracle-user.xml Added case-insensitive username comparison using LOWER() function
server/dbconf/mysql/mysql-user.xml Added case-insensitive username comparison using LOWER() function
server/dbconf/derby/derby-user.xml Added case-insensitive username comparison using LOWER() function

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

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.

[BUG] Username is case-sensitive when logging into MC Administrator

3 participants