Skip to content
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

[Feature] Support mysql client OpenID Connect Pluggable Authentication #55846

Merged
merged 1 commit into from
Feb 18, 2025

Conversation

HangyuanLiu
Copy link
Contributor

@HangyuanLiu HangyuanLiu commented Feb 12, 2025

Why I'm doing:

Compatible with openIdConnect authentication method in MySQL 9.2

What I'm doing:

Fixes #55847

What type of PR is this:

  • BugFix
  • Feature
  • Enhancement
  • Refactor
  • UT
  • Doc
  • Tool

Does this PR entail a change in behavior?

  • Yes, this PR will result in a change in behavior.
  • No, this PR will not result in a change in behavior.

If yes, please specify the type of change:

  • Interface/UI changes: syntax, type conversion, expression evaluation, display information
  • Parameter changes: default values, similar parameters but with different default values
  • Policy changes: use new policy to replace old one, functionality automatically enabled
  • Feature removed
  • Miscellaneous: upgrade & downgrade compatibility, etc.

Checklist:

  • I have added test cases for my bug fix or my new feature
  • This pr needs user documentation (for new or modified features or behaviors)
    • I have added documentation for my new feature or new function
  • This is a backport pr

Bugfix cherry-pick branch check:

  • I have checked the version labels which the pr will be auto-backported to the target branch
    • 3.4
    • 3.3
    • 3.2
    • 3.1
    • 3.0

@HangyuanLiu HangyuanLiu requested a review from a team as a code owner February 12, 2025 11:14
* The aud field in the JWT identifies the recipients that the JWT is intended for.
*/
@ConfField(mutable = false)
public static String oidc_required_audience = "";
}
Copy link

Choose a reason for hiding this comment

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

The most risky bug in this code is:
Using an empty string for critical JWT configuration values can lead to insecure defaults and potential security vulnerabilities if not handled properly when validating JWTs.

You can modify the code like this:

@ConfField(mutable = false)
public static String oidc_jwks_url = "default_value_here"; // Set a sensible default or validate it programmatically

@ConfField(mutable = false)
public static String oidc_required_issuer = "default_value_here"; // Set a sensible default or validate prior to use

@ConfField(mutable = false)
public static String oidc_required_audience = "default_value_here"; // As above, set or validate as necessary

Ensure that each configuration has a valid default or check them during application initialization/configuration loading to avoid using insecure defaults.

byte[] openIdConnect = MysqlProto.readLenEncodedString(authBuffer);
OpenIdConnectVerifier.verify(new String(openIdConnect), user, jwksUrl, principalFiled, requireIssuer, requireAudience);
}
} No newline at end of file
Copy link

Choose a reason for hiding this comment

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

The most risky bug in this code is:
The typo in the variable name principalFiled should be principalField.

You can modify the code like this:

package com.starrocks.authentication;

//... other imports ...

public class OpenIdConnectAuthenticationProvider implements AuthenticationProvider {
    public static final String PLUGIN_NAME = AuthPlugin.AUTHENTICATION_OPENID_CONNECT.name();

    private final String jwksUrl;
    private final String principalField; // Corrected variable name
    private final String requireIssuer;
    private final String requireAudience;

    public OpenIdConnectAuthenticationProvider(String jwksUrl, String principalField, // Corrected parameter name
                                               String requireIssuer, String requireAudience) {
        this.jwksUrl = jwksUrl;
        this.principalField = principalField; // Use corrected variable name
        this.requireIssuer = requireIssuer;
        this.requireAudience = requireAudience;
    }

    //... rest of the code ...
}


return JWKSet.load(inputStream);
}
}
Copy link

Choose a reason for hiding this comment

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

The most risky bug in this code is:
The verifyJWT method lacks a null check for the return value of jwkSet.getKeyByKeyId(kid), which can lead to a NullPointerException.

You can modify the code like this:

private static void verifyJWT(String jwt, JWKSet jwkSet) throws AuthenticationException, ParseException, JOSEException {
    SignedJWT signedJWT = SignedJWT.parse(jwt);
    String kid = signedJWT.getHeader().getKeyID();

    var key = jwkSet.getKeyByKeyId(kid);
    if (key == null) {
        throw new AuthenticationException("Cannot find public key for kid: " + kid);
    }

    RSAPublicKey publicKey = key.toRSAKey().toRSAPublicKey();
    if (publicKey == null) {
        throw new AuthenticationException("Public key conversion failed for kid: " + kid);
    }

    RSASSAVerifier verifier = new RSASSAVerifier(publicKey);
    if (!signedJWT.verify(verifier)) {
        throw new AuthenticationException("JWT with kid " + kid + " is invalid!");
    }
}

@@ -3474,4 +3474,32 @@ public class Config extends ConfigBase {

@ConfField(mutable = false)
public static int max_historical_automated_cluster_snapshot_jobs = 100;

/**
* The URL to a JWKS service or a local file in the conf dir
Copy link
Contributor

Choose a reason for hiding this comment

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

The comments can be added in to the comment field like
@ConfField(mutable = fase, comment = "xxx");
So that admin show config will see the usage of this config param.

if (jwksUrl.startsWith("http://") || jwksUrl.startsWith("https://")) {
jwksInputStream = new URL(jwksUrl).openStream();
} else {
String filePath = StarRocksFE.STARROCKS_HOME_DIR + "/conf/" + jwksUrl;
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this file have to be added to the conf/ directory? If so, the comments of this param should be marked.

Copy link

[Java-Extensions Incremental Coverage Report]

pass : 0 / 0 (0%)

Copy link

[FE Incremental Coverage Report]

pass : 64 / 72 (88.89%)

file detail

path covered_line new_line coverage not_covered_line_detail
🔵 com/starrocks/authentication/JwkMgr.java 1 6 16.67% [29, 30, 32, 33, 35]
🔵 com/starrocks/authentication/OpenIdConnectAuthenticationProvider.java 20 22 90.91% [67, 68]
🔵 com/starrocks/authentication/OpenIdConnectVerifier.java 31 32 96.88% [29]
🔵 com/starrocks/mysql/privilege/AuthPlugin.java 2 2 100.00% []
🔵 com/starrocks/authentication/AuthenticationMgr.java 1 1 100.00% []
🔵 com/starrocks/common/Config.java 4 4 100.00% []
🔵 com/starrocks/server/GlobalStateMgr.java 4 4 100.00% []
🔵 com/starrocks/mysql/MysqlHandshakePacket.java 1 1 100.00% []

Copy link

[BE Incremental Coverage Report]

pass : 0 / 0 (0%)

@Astralidea Astralidea merged commit 64d0f20 into StarRocks:main Feb 18, 2025
51 of 52 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support mysql client OpenID Connect Pluggable Authentication
3 participants