Skip to content

Commit 6f89b98

Browse files
elianddbclaude
andcommitted
Fix wildcard user authentication for IP patterns
- Add matchesHostPattern function to handle MySQL wildcard patterns like '127.0.0.%' - Modify GetUser to check both normalized host and original host against patterns - Use regex matching where % is converted to .* for proper wildcard matching - Fixes issue where users with wildcard hostnames (e.g., 'user'@'10.0.0.%') would fail authentication with 'No authentication methods available' 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 028d9ca commit 6f89b98

File tree

1 file changed

+28
-1
lines changed

1 file changed

+28
-1
lines changed

sql/mysql_db/mysql_db.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"encoding/json"
2121
"fmt"
2222
"net"
23+
"regexp"
2324
"sort"
2425
"strings"
2526
"sync"
@@ -591,6 +592,27 @@ func (db *MySQLDb) AddLockedSuperUser(ed *Editor, username string, host string,
591592
}
592593
}
593594

595+
// matchesHostPattern checks if a host matches a MySQL host pattern.
596+
// This function handles wildcard patterns like '127.0.0.%' which should match '127.0.0.1', '127.0.0.255', etc.
597+
func matchesHostPattern(host, pattern string) bool {
598+
// If pattern doesn't contain %, it's not a wildcard pattern
599+
if !strings.Contains(pattern, "%") {
600+
return false
601+
}
602+
603+
// Replace % with .* for regex matching, but first escape other regex metacharacters
604+
// We need to escape everything except % first, then replace % with .*
605+
regexPattern := regexp.QuoteMeta(pattern) // This escapes everything including %
606+
regexPattern = strings.ReplaceAll(regexPattern, "%", ".*") // Replace % with .*
607+
regexPattern = "^" + regexPattern + "$"
608+
609+
matched, err := regexp.MatchString(regexPattern, host)
610+
if err != nil {
611+
return false
612+
}
613+
return matched
614+
}
615+
594616
// GetUser returns a user matching the given user and host if it exists. Due to the slight difference between users and
595617
// roles, roleSearch changes whether the search matches against user or role rules.
596618
func (db *MySQLDb) GetUser(fetcher UserFetcher, user string, host string, roleSearch bool) *User {
@@ -607,6 +629,9 @@ func (db *MySQLDb) GetUser(fetcher UserFetcher, user string, host string, roleSe
607629
//TODO: Allow for CIDR notation in hostnames
608630
//TODO: Which user do we choose when multiple host names match (e.g. host name with most characters matched, etc.)
609631

632+
// Store the original host for pattern matching against IP patterns
633+
originalHost := host
634+
610635
if "127.0.0.1" == host || "::1" == host {
611636
host = "localhost"
612637
}
@@ -626,7 +651,9 @@ func (db *MySQLDb) GetUser(fetcher UserFetcher, user string, host string, roleSe
626651
if host == user.Host ||
627652
(host == "localhost" && user.Host == "::1") ||
628653
(host == "localhost" && user.Host == "127.0.0.1") ||
629-
(user.Host == "%" && (!roleSearch || host == "")) {
654+
(user.Host == "%" && (!roleSearch || host == "")) ||
655+
matchesHostPattern(host, user.Host) ||
656+
matchesHostPattern(originalHost, user.Host) {
630657
return user
631658
}
632659
}

0 commit comments

Comments
 (0)