Skip to content

Authentication #1696

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Authentication #1696

wants to merge 2 commits into from

Conversation

rusher
Copy link
Contributor

@rusher rusher commented Apr 16, 2025

Description

authentication has been revamp. this is a simplification of #1694, without new authentication plugin addition, since it's already a big change.

Current implementation was requiring authentication switch plugins data to begin with iAuthMoreData, but that's only required for "caching_sha2_password" and "sha256_password" plugins.
Additionally, now permits multi-authentication (in mariadb: https://mariadb.com/kb/en/create-user/#identified-viawith-authentication_plugin / mysql: https://dev.mysql.com/doc/refman/8.0/en/multifactor-authentication.html)

goal is to add MariaDB main authentication plugins (like parsec, PAM, GSSAPI, ...) based on plugin like this

Checklist

  • Code compiles correctly
  • Created tests which fail without the change (if possible)
  • All tests passing
  • Extended the README / documentation, if necessary
  • Added myself / the copyright holder to the AUTHORS file

Summary by CodeRabbit

  • New Features

    • Introduced a pluggable authentication system supporting multiple MySQL and MariaDB authentication methods, including native password, caching SHA2 password, cleartext password, old password, SHA256 password, and Ed25519 authentication.
    • Added detailed documentation describing the supported authentication plugins and their usage.
  • Bug Fixes

    • Improved test coverage for authentication flows, including multi-step authentication switch scenarios and enhanced collation and timezone handling in tests.
  • Refactor

    • Centralized and abstracted authentication logic behind a plugin interface, removing legacy, hardcoded, and cryptographic details from core files.
    • Updated authentication handling to use a global plugin registry and interface-based approach.
  • Chores

    • Added a new author to the contributors list.

rusher added 2 commits March 31, 2025 18:04
* ensuring performance schema is enabled when testing some performance schema results
* Added logic to check if the default collation is overridden by the server character_set_collations
* ensure using IANA timezone in test, since tzinfo depending on system won't have deprecated tz like "US/Central" and "US/Pacific"
Current implementation was requiring authentication plugin that are have multiple step to begin with iAuthMoreData, but that's only required for "caching_sha2_password" and "sha256_password" plugins.
Additionally, now permits multi-authentication (in mariadb: https://mariadb.com/kb/en/create-user/#identified-viawith-authentication_plugin / mysql: https://dev.mysql.com/doc/refman/8.0/en/multifactor-authentication.html)

goal is to add MariaDB main authentication plugins (like parsec, PAM, GSSAPI, ...)
Copy link

coderabbitai bot commented Apr 16, 2025

Walkthrough

This change introduces a modular authentication plugin system for the Go MySQL driver. The authentication logic is refactored to use a plugin interface, with each authentication method implemented in its own file as a plugin. The connector now retrieves plugins from a global registry and delegates authentication steps to them, removing hardcoded logic for individual plugins. The README and AUTHORS files are updated to document the new system and contributors. The test suite is updated to use the plugin interface, and new tests are added for multi-step authentication flows. Several legacy functions and constants are removed as their responsibilities move to the new plugin structure.

Changes

File(s) Change Summary
auth.go, packets.go, const.go Removed legacy authentication logic, constants, and the readAuthResult function. Refactored authentication flow to delegate to plugins and removed direct cryptographic operations and plugin-specific code.
auth_plugin.go Introduced the AuthPlugin interface, a simple plugin registry, and supporting types for modular authentication.
auth_caching_sha2.go, auth_cleartext.go, auth_ed25519.go, auth_mysql_native.go, auth_old_password.go, auth_sha256.go Added new files implementing authentication plugins for caching_sha2_password, mysql_clear_password, client_ed25519, mysql_native_password, mysql_old_password, and sha256_password. Each plugin handles its own authentication logic and registration.
connector.go Updated connection logic to use the plugin registry, removed fallback authentication, and enforced a maximum number of authentication switches.
driver.go Added and initialized a global plugin registry variable.
auth_test.go Refactored tests to use the plugin interface, updated calls to authentication methods, and added tests for multi-step authentication switches.
driver_test.go Improved collation and timezone tests, enhanced handling of server-specific behaviors, and added checks for performance schema availability.
README.md Added documentation for the new authentication plugin system, listing supported plugins and their usage.
AUTHORS Added a new contributor entry in alphabetical order.

Sequence Diagram(s)

sequenceDiagram
    participant Connector
    participant PluginRegistry
    participant AuthPlugin
    participant MySQLServer

    Connector->>PluginRegistry: GetPlugin(pluginName)
    PluginRegistry-->>Connector: AuthPlugin instance
    Connector->>AuthPlugin: InitAuth(authData, config)
    AuthPlugin-->>Connector: Initial response
    Connector->>MySQLServer: Send initial response
    loop (Up to maximum switches)
        MySQLServer-->>Connector: Auth result packet
        alt Auth switch requested
            Connector->>AuthPlugin: ContinuationAuth(packet, authData, conn)
            AuthPlugin-->>Connector: Next response
            Connector->>MySQLServer: Send next response
        else OK or Error
            Connector-->>Connector: Exit loop
        end
    end
Loading

Suggested reviewers

  • methane

Poem

In the warren of code, a new path we lay,
Plugins for auth—each with their own say!
No more old hashes, no more hard-wired fright,
Each bunny plugin hops in, handling auth right.
The registry grows, the tests multiply,
With modular paws, our code leaps high!
🐇✨

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
driver.go (1)

42-44: Global plugin registry introduction
This new variable and initialization appear well-structured for the upcoming plugin-based authentication system. Ensure the globalPluginRegistry registration and usage is thread-safe, especially if plugin registrations can occur at runtime.

README.md (1)

540-546: Use consistent list style per markdownlint
Static analysis flags these lines for inconsistent unordered list style. Switch from dashes to asterisks to comply with the configured Markdown style guidelines.

Apply the following diff to update the list style:

- - `mysql_native_password` - The default MySQL authentication method
- - `caching_sha2_password` - Default authentication method in MySQL 8.0+
- - `mysql_clear_password` - Cleartext authentication (requires `allowCleartextPasswords=true`)
- - `mysql_old_password` - Old MySQL authentication (requires `allowOldPasswords=true`)
- - `sha256_password` - SHA256 authentication
- - `client_ed25519` - MariaDB Ed25519 authentication
+ * `mysql_native_password` - The default MySQL authentication method
+ * `caching_sha2_password` - Default authentication method in MySQL 8.0+
+ * `mysql_clear_password` - Cleartext authentication (requires `allowCleartextPasswords=true`)
+ * `mysql_old_password` - Old MySQL authentication (requires `allowOldPasswords=true`)
+ * `sha256_password` - SHA256 authentication
+ * `client_ed25519` - MariaDB Ed25519 authentication
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

541-541: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


542-542: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


543-543: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


544-544: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


545-545: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


546-546: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

auth_ed25519.go (1)

29-63: Ed25519 authentication logic appears correct.
The scalar clamping, base multiplication, uniform hashing, and final combined signature steps reflect standard Ed25519 signing internals. Error handling for scalar creation is handled properly. One optional consideration is whether to sanitize (zero) sensitive intermediate data in memory once done, if there's concern about side-channel leaks in ephemeral memory. Overall, the plugin method is well-structured.

auth_caching_sha2.go (1)

67-74: Use descriptive constants for magic numbers.
The sub-switch values 3 and 4 can be replaced by clearly named constants to enhance maintainability and code clarity.

auth_sha256.go (1)

107-131: RSA-OAEP with SHA1.
While this aligns with MySQL's required method, note that SHA1 is considered weaker cryptographically. Keep it for compatibility, or consider offering a stronger alternative if not constrained by server support.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 879eb11 and 5dd643c.

📒 Files selected for processing (16)
  • AUTHORS (1 hunks)
  • README.md (1 hunks)
  • auth.go (2 hunks)
  • auth_caching_sha2.go (1 hunks)
  • auth_cleartext.go (1 hunks)
  • auth_ed25519.go (1 hunks)
  • auth_mysql_native.go (1 hunks)
  • auth_old_password.go (1 hunks)
  • auth_plugin.go (1 hunks)
  • auth_sha256.go (1 hunks)
  • auth_test.go (53 hunks)
  • connector.go (2 hunks)
  • const.go (0 hunks)
  • driver.go (1 hunks)
  • driver_test.go (4 hunks)
  • packets.go (0 hunks)
💤 Files with no reviewable changes (2)
  • const.go
  • packets.go
🧰 Additional context used
🧬 Code Graph Analysis (9)
driver.go (1)
auth_plugin.go (1)
  • NewPluginRegistry (42-47)
auth_cleartext.go (3)
auth_plugin.go (2)
  • SimpleAuth (28-30)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrCleartextPassword (23-23)
auth_plugin.go (1)
dsn.go (1)
  • Config (37-84)
auth_old_password.go (3)
auth_plugin.go (2)
  • SimpleAuth (28-30)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrOldPassword (25-25)
auth_mysql_native.go (3)
auth_plugin.go (2)
  • SimpleAuth (28-30)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrNativePassword (24-24)
auth_sha256.go (3)
auth_plugin.go (2)
  • AuthPlugin (12-26)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrMalformPkt (21-21)
auth_test.go (2)
auth_old_password.go (1)
  • OldPasswordPlugin (12-12)
auth_mysql_native.go (1)
  • NativePasswordPlugin (14-16)
auth_caching_sha2.go (3)
auth_plugin.go (2)
  • AuthPlugin (12-26)
  • RegisterAuthPlugin (61-63)
dsn.go (1)
  • Config (37-84)
errors.go (1)
  • ErrMalformPkt (21-21)
auth.go (2)
auth_plugin.go (1)
  • AuthPlugin (12-26)
errors.go (1)
  • ErrMalformPkt (21-21)
🪛 markdownlint-cli2 (0.17.2)
README.md

541-541: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


542-542: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


543-543: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


544-544: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


545-545: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


546-546: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

🔇 Additional comments (96)
AUTHORS (1)

40-40: No concerns found with this addition
Adding the new author entry in alphabetical order is correct and maintains consistency with the file’s structure.

README.md (1)

537-539: Good addition of the new authentication section
Introducing a dedicated subsection clarifies how the new pluggable authentication system works. The explanation gives a clear overview for end users.

connector.go (4)

147-150: Appropriate plugin existence check
Returning an error if the plugin is missing is a good defensive approach. Make sure any dynamic plugin loading is handled before this point to avoid unexpected failures for known custom plugins.


153-156: Plugin-driven auth initialization
Delegating InitAuth to the plugin fosters modularity. The cleanup after error is correct.


164-165: Bounded authentication flow
Passing authMaximumSwitch and reusing the same plugin instance ensures a controlled multi-step authentication without fallback confusion.


21-23:

✅ Verification successful

Reasonable limit on plugin switch attempts
Using a constant for the maximum number of authentication plugin switches keeps the logic maintainable. Confirm that the limit of 5 attempts aligns with all supported multi-factor authentication scenarios.


🏁 Script executed:

#!/bin/bash
# Description: Check references to authMaximumSwitch across the codebase to ensure it is not exceeded or bypassed during multi-factor auth flows.
rg -A 5 "authMaximumSwitch"

Length of output: 876


Verification Confirmed: Consistent and Intentional Limit

The constant authMaximumSwitch is set to 5 in connector.go and is referenced both in the authentication flow (mc.handleAuthResult) and in generating the error message ("maximum of %d authentication switch reached") in auth.go. The grep output confirms that the limit is applied consistently across the multi-factor authentication logic.

  • The constant is declared and used in a way that prevents exceeding the intended number of switch attempts.
  • There’s no evidence from the codebase that the limit is bypassed or that additional scenarios require a higher count.

If later multi-factor authentication scenarios demand a different limit, please update the constant accordingly.

driver_test.go (3)

1633-1658: Improved collation test to handle server overrides - good approach.

The added code correctly handles cases where the server overrides the default collation based on character_set_collations. This makes the test more robust against different server configurations by:

  1. Fetching the server's character set collations mapping
  2. Parsing it into a usable dictionary structure
  3. Checking if the expected collation's charset has a server-mandated override
  4. Using the overridden value for comparison when necessary

1721-1721: Updated timezone test locations for broader coverage.

Changed test timezones from "US/Central", "US/Pacific" to "America/New_York", "Asia/Hong_Kong" which provides more global timezone coverage and uses IANA standard timezone names.


3577-3585: Good addition of performance_schema availability check.

This change adds an important check to verify the performance_schema is enabled before attempting to query connection attributes. This prevents test failures when running against MySQL servers with performance_schema disabled.

auth_cleartext.go (4)

11-23: Good implementation of the cleartext password plugin.

The ClearPasswordPlugin is well-structured and properly embeds SimpleAuth. The comments clearly document the security implications of cleartext authentication and when it should be used (TLS/SSL, Unix sockets, PAM).


25-27: Appropriate plugin registration in init.

The plugin correctly registers itself with the global plugin registry during package initialization, allowing the driver to discover it without manual registration.


29-31: Plugin identification method.

The GetPluginName method correctly returns "mysql_clear_password" which matches MySQL's internal plugin name.


33-46: Well-implemented authentication initialization.

The InitAuth method has good security practices:

  1. It checks if cleartext passwords are allowed in the configuration
  2. Returns an appropriate error if not allowed
  3. Correctly appends a null terminator to the password as required by the protocol

The null termination handling is particularly important for external authentication systems that need access to the original password.

auth_mysql_native.go (5)

13-16: Proper implementation of native password plugin.

The plugin structure is clean and correctly embeds SimpleAuth for shared functionality.


18-20: Self-registration pattern is consistent.

The plugin registers itself in init, matching the pattern used in other authentication plugins.


22-24: Plugin name matches MySQL's internal name.

The GetPluginName method correctly returns "mysql_native_password" in accordance with MySQL's naming.


26-34: Security check in initialization method.

InitAuth properly checks configuration settings before proceeding:

  1. Verifies AllowNativePasswords configuration flag
  2. Handles empty passwords correctly
  3. Calls scramblePassword with the correct portion of authData (first 20 bytes)

36-64: Accurate implementation of MySQL 4.1+ password hashing.

The scramblePassword function correctly implements the MySQL 4.1+ native password hashing algorithm:

  1. Properly handles empty passwords
  2. Calculates the SHA1 hash of the password (stage1)
  3. Creates a SHA1 hash of the stage1 hash
  4. Creates a SHA1 hash of the scramble + stage1 hash
  5. XORs the scramble hash with stage1 to produce the authentication token

The implementation follows the MySQL protocol specification precisely.

auth_plugin.go (4)

11-26: Well-designed plugin interface for authentication.

The AuthPlugin interface is cleanly defined with three essential methods:

  1. GetPluginName - Identifies the plugin
  2. InitAuth - Handles initial authentication
  3. ContinuationAuth - Manages subsequent authentication steps

The interface provides enough flexibility for different authentication mechanisms while maintaining a consistent API. The documentation for each method clearly explains parameters and purpose.


28-34: Good base implementation with SimpleAuth.

The SimpleAuth struct provides a sensible default implementation for ContinuationAuth, making it easier to implement simple plugins by embedding this struct. This avoids code duplication for plugins that don't need multi-step authentication.


36-58: Clean implementation of plugin registry.

The PluginRegistry implementation is straightforward and effective:

  1. Uses a map to store plugins by name
  2. Provides methods to register and retrieve plugins
  3. Has a proper constructor (NewPluginRegistry)
  4. Returns a boolean status with GetPlugin to safely handle missing plugins

This design allows for efficient plugin lookup while avoiding panics for unavailable plugins.


60-63: Global registry access with RegisterAuthPlugin.

This helper function simplifies plugin registration by accessing the global registry, following a common pattern in Go libraries. This makes it easy for both built-in and external plugins to register themselves.

auth_ed25519.go (4)

1-8: License and package header look good.
No issues found in the licensing block or package declaration.


16-19: Struct definition is straightforward.
Embedding SimpleAuth aligns with the plugin-based design. No immediate concerns.


21-23: Plugin registration is correct.
RegisterAuthPlugin invocation follows the new authentication system’s pattern.


25-27: Plugin name retrieval is fine.
The function name and return value match plugin naming conventions.

auth_test.go (41)

53-55: Initiating OldPasswordPlugin in test.
Constructing the plugin directly is acceptable for targeted testing. No issues.


122-122: Invocation of handleAuthResult.
Looks consistent with new multi-step auth approach.


137-138: Retrieving plugin from registry and calling InitAuth.
This is correct and aligns with the plugin-based design.


179-186: Setting up plugin and verifying handshake response flow.
Combining registry lookup with InitAuth is correct. The subsequent writeHandshakeResponsePacket call properly handles the returned bytes.


236-237: Caching SHA2 plugin retrieval and initialization.
Implementation follows the same pattern as other plugins. No issues.


289-290: Secure plugin initialization.
Reading from registry and calling InitAuth is consistent.


346-347: Cleartext password plugin retrieval and InitAuth check.
This test ensures errors are returned when not allowed. Logic is fine.


364-365: Acquiring plugin instance and retrieving auth response.
Matches the plugin design. Good coverage for empty password.


391-391: handleAuthResult usage.
Consistent approach to finalizing authentication.


407-408: Same pattern for plugin acquisition and initialization.
Design is uniform—straightforward test validation.


511-511: InitAuth with native password plugin in test.
Implementation is correct, verifying empty password logic.


553-553: sha256_password plugin test.
Empty password scenario is covered. Appropriately tested.


602-602: SHA256 password plugin retrieval & initialization.
No issues—standard plugin usage.


631-631: handleAuthResult for RSA scenario.
Ensures RSA logic is properly tested.


652-652: SHA256 plugin with custom pubKey.
Test coverage is thorough, ensuring plugin handles configured RSA key.


685-685: sha256_password plugin with secure connection.
Test ensures fallback to sending decrypted password over TLS. Implementation is correct.


714-714: handleAuthResult final check.
Standard multi-step auth logic, no issues.


741-741: Auth switch with &NativePasswordPlugin{}.
Matches plugin-based approach. No concerns.


773-773: handleAuthResult with empty password.
Trivial test scenario is validated.


807-807: Multi-step RSA-based handshake switch.
Test ensures partial hush vs. final hush approach. No issues.


849-849: Authorization switch with provided pubKey.
Flow is consistent with the plugin’s logic.


889-889: handleAuthResult for secure SHA256.
Ensures it sends cleartext password if TLS is verified. Good coverage.


913-913: Invalid plugin switch for cleartext password.
Expects error. Aligned with new plugin design.


935-935: handleAuthResult with explicit plugin object.
Demonstrates multi-auth switch for cleartext password.


959-959: Empty password old auth test.
Ensures correct fallback or error.


979-979: Disallow old password scenario.
Tests the config-based restriction. Good coverage.


1001-1001: Handling native password switch with non-empty password.
Ensures the scramble is created properly.


1029-1029: Empty password with native password switch.
Covered scenario; no issues.


1047-1047: handleAuthResult for old password not allowed.
Correctly returns ErrOldPassword. Test logic is fine.


1062-1062: handleAuthResult for old password with OldAuthSwitch request.
Same approach, verifying it fails.


1084-1084: Allowed old passwords.
Ensures scramble logic is tested.


1109-1109: Handling OldAuthSwitch with allowed old passwords.
Test confirms fallback is correct.


1132-1132: Handling old password with empty credentials.
Test ensures short-circuit for empty password.


1155-1155: Confirm empty old password switch.
No issues. Good coverage for an edge case.


1180-1180: Auth switch for sha256 with empty plugin data.
Verifies no crash or unexpected errors.


1211-1211: RSA-based pub key response.
Ensures correctness of encryption step.


1243-1243: RSA-based key scenario with custom pubKey.
Ensures no break with user-provided key.


1275-1275: Secure connection usage.
Checks fallback to sending password in cleartext over TLS.


1315-1319: Verifying Ed25519 client output.
Checks 64-byte response correctness, ensuring the derived signature matches expectations. Logic is correct.


1335-1370: TestMultiAuthSimpleSwitch.
Demonstrates multi-step switch from caching_sha2_password to mysql_clear_password. Asserts the correct handshake sequence is written.


1372-1413: TestMultiAuthSwitch.
Similar multi-step example, now adding RSA pub key steps before switching to cleartext. Thorough test coverage of multi-factor flow.

auth_old_password.go (6)

1-8: License and package declaration.
No concerns with the added header.


11-16: Plugin struct registration.
Embedding SimpleAuth and registering under mysql_old_password is consistent with the new system.


18-20: Plugin name retrieval.
Matches the typical plugin naming pattern. No issues.


22-33: InitAuth method for old password.
Properly checks AllowOldPasswords config flag. The scrambleOldPassword call is restricted to the first 8 bytes of the server scramble, matching MySQL’s old approach. This is correct for pre-4.1 style.


35-55: scrambleOldPassword implementation.
The code matches the historical MySQL algorithm, including skipping tabs/spaces and performing an insecure hash-based scramble. The approach is intentionally insecure but historically compatible. No immediate issues beyond inherent weakness of the scheme.


57-109: myRnd and pwHash logic.
Implements the legacy MySQL random generator and two-component hashing precisely. This is correct for old-style password scrambling.

auth_caching_sha2.go (12)

19-24: Clean separation of the plugin struct.
Embedding AuthPlugin in CachingSha2PasswordPlugin aligns well with the new plugin-based approach, making the design modular and maintainable.


26-28: Automatic plugin registration.
Registering the plugin in the init() function ensures it is discovered without additional user code, improving developer experience.


30-32: Correct and consistent plugin name.
Returning "caching_sha2_password" matches MySQL’s official plugin name and fulfills the AuthPlugin interface requirement.


34-42: Clear initial scramble implementation.
Delegating the scrambling logic to scrambleSHA256Password keeps the implementation focused and maintainable.


55-57: Empty packet handling.
It's good to error on an empty authentication response packet. Confirm there's no valid scenario in which the server sends an empty packet mid-auth.


59-62: iERR case verification.
Returning (packet, nil) for iERR relies on higher-level logic to recognize an error packet. Double-check that the caller properly treats it as an error and does not inadvertently proceed.


63-66: Fast auth success scenario.
This path indicates an immediate indication of success and proceeds to mc.readPacket(). Ensure this matches MySQL's spec for cached credentials with zero extended data.


75-127: Validate cleartext sending logic.
When TLS or a Unix socket is used, the password is sent in cleartext. Verify if you need to respect AllowCleartextPasswords or similar flags to avoid unexpected exposures.


129-131: Clear error for unknown state.
Throwing an error on unrecognized state ensures robust error handling and quicker debugging.


133-135: Unexpected packet length fallback.
Raising an error for mismatched lengths prevents subtle protocol mishandling.


136-139: Failsafe for invalid packet types.
Rejecting unknown packet types maintains stability, ensuring the driver doesn’t silently ignore server anomalies.


141-176: MySQL 8+ scramble algorithm.
The three-step SHA256-based hashing followed by XOR is consistent with caching_sha2_password specification.

auth_sha256.go (5)

20-22: Struct embedding for sha256_password plugin.
Adhering to the same plugin pattern keeps authentication logic uniform across plugins.


24-26: Init-based plugin registration.
Similar to the other plugins, this ensures the plugin is discovered and available at runtime.


28-30: Accurate plugin naming.
"sha256_password" properly identifies the authentication method for MySQL and matches server expectations.


32-62: Comprehensive InitAuth logic.
Handles empty passwords, TLS-based cleartext, RSA encryption fallback, and public key requests. Confirm any relevant AllowCleartextPasswords or usage constraints are enforced as needed.


64-105: ContinuationAuth multi-step support.
The switch statement properly handles OK, error, or public-key retrieval. Double-check iERR handling to ensure the caller interprets the error scenario correctly.

auth.go (6)

12-12: Introducing the bytes import.
Used to parse and locate the plugin name from null-terminated data, which is appropriate within packet parsing logic.


59-65: Guard against infinite re-auth loops.
Limiting remainingSwitch avoids potential recursion issues in multi-factor or repeated authentication switch scenarios.


67-79: Delegation to ContinuationAuth.
Continuing the authentication flow via the plugin maintains modular design. Ensure the returned packet is consistently valid for follow-up logic.


80-85: Direct handling of OK/ERR.
Returning the result or error packet as-is is concise. Validate that a server error via iERR is recognized upstream.


86-104: Auth switch recursion with new plugin.
Efficiently fetches next plugin from the registry and re-invokes auth logic, decrementing remainingSwitch. This structure elegantly supports multi-step authentication.


110-132: Plugin name extraction.
Automatically falls back to mysql_old_password if only a single byte remains, preserving legacy compatibility. Good approach for older server versions.

@coveralls
Copy link

Coverage Status

coverage: 82.964% (-0.08%) from 83.048%
when pulling 5dd643c on rusher:authentication
into 879eb11 on go-sql-driver:master.

@methane
Copy link
Member

methane commented Apr 19, 2025

Make "test stability improvement." PR first.
I did it by myself.

// mysql.RegisterServerPubKey("mykey", rsaPubKey)
// } else {
// log.Fatal("not a RSA public key")
// }
Copy link
Member

Choose a reason for hiding this comment

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

why remove this?

}

// PluginRegistry is a registry of available authentication plugins
type PluginRegistry struct {
Copy link
Member

Choose a reason for hiding this comment

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

Why is this public?
I don't want add library surface as much as possible because every surface can be technical debt.

}

// NewPluginRegistry creates a new plugin registry
func NewPluginRegistry() *PluginRegistry {
Copy link
Member

Choose a reason for hiding this comment

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

same here. make it private unless strict necessary.

dials map[string]DialContextFunc
dialsLock sync.RWMutex
dials map[string]DialContextFunc
globalPluginRegistry = NewPluginRegistry()
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
globalPluginRegistry = NewPluginRegistry()
pluginRegistry = NewPluginRegistry()

Comment on lines +13 to +14
// GetPluginName returns the name of the authentication plugin
GetPluginName() string
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// GetPluginName returns the name of the authentication plugin
GetPluginName() string
// PluginName returns the name of the authentication plugin
PluginName() string

// packet is the data from the server's auth response
// authData is the initial auth data from the server
// conn is the MySQL connection (for performing additional interactions if needed)
ContinuationAuth(packet []byte, authData []byte, conn *mysqlConn) ([]byte, error)
Copy link
Member

Choose a reason for hiding this comment

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

Can external plugins use mysqlConn?

We should not expose plugin interface until its design is complete and stable.

@methane
Copy link
Member

methane commented Apr 21, 2025

Maybe, its time to use internal package.

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.

3 participants