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

Replace EOL Google Oauth library #409

Merged
merged 14 commits into from
Oct 10, 2024
Merged

Replace EOL Google Oauth library #409

merged 14 commits into from
Oct 10, 2024

Conversation

jtnord
Copy link
Member

@jtnord jtnord commented Oct 2, 2024

This changes the Google OAuth library which is in maintenance mode with a supported library (nimbusds via pac4j)

Warning
The library requires that the Issuer is set to enforce security and there is no option to disable this requirement as it is mandated in the specification. As such users must first update to 4.355.v3a_fb_fca_b_96d4 to set the Issuer before updating to this version.
Additionally this removes the option to send the scopes when requesting the access token. users of non conformant OPs that require this functionality should remain on the previous version until the provider fixes their implementation.

The change no longer determines how often to refresh the well-known settings (if used), they are now refreshed every hour.

fixes: #313

Testing done

  • mvn hpi:run (java11) against a local AD FS server (login, logout) (disable TLS verification) (well known config)
  • mvn hpi:run (java11) against a local AD FS server (login, logout) (trusted TLS cert) (well known config)
  • java -jar jenkins-2.479.war --httpListenAddress=127.0.0.1 --prefix=/jenkins (java17) against a local AD FS server (login, logout) (disable TLS verification) (well known config)
  • JENKINS_VERSION=2.462.3 LOCAL_JARS=/path/to/oic-auth-plugin/target/oic-auth.hpi mvn -Dtest=OicAuthPluginTest
  • JENKINS_VERSION=2.479 LOCAL_JARS=/path/to/oic-auth-plugin/target/oic-auth.hpi mvn test -Dtest=OicAuthPluginTest
  • mvn hpi:run (java11) against an AWS Cognito server (login, logout) (well known config)
  • mvn hpi:run (java11) against an AWS Cognito server (login, logout) (manual config)
  • oidcc-client-basic-certification-test-plan passed

Submitter checklist

  • Make sure you are opening from a topic/feature/bugfix branch (right side) and not your main branch!
  • Ensure that the pull request title represents the desired changelog entry
  • Please describe what you did
  • Link to relevant issues in GitHub or Jira
  • Link to relevant pull requests, esp. upstream and downstream changes
  • Ensure you have provided tests - that demonstrates feature works or fixes the issue

import jenkins.security.FIPS140;

@SuppressFBWarnings(value = "WEAK_TRUST_MANAGER", justification = "Opt in by user")
final class AnythingGoesTrustManager implements X509TrustManager {
Copy link
Member Author

Choose a reason for hiding this comment

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

there are enough of these in all plugins this should really be in Jenkins core.

* {@link HostnameVerifier} that accepts any presented hostanme including incorrect ones.
*/
@Restricted(NoExternalUse.class)
public final class IgnoringHostNameVerifier implements HostnameVerifier {
Copy link
Member Author

Choose a reason for hiding this comment

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

Again, enough plugins use something like this that it should be offered from Jenkins core.

+ "\"token_endpoint\":\"http://localhost:%1$d/token\","
+ "\"userinfo_endpoint\":\"http://localhost:%1$d/user\","
+ "\"jwks_uri\":\"http://localhost:%1$d/jwks\","
+ "\"scopes_supported\": null,"
Copy link
Member Author

Choose a reason for hiding this comment

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

the OpenID spec says if something is empty is it ommitted completely and does not contain "null"
may as well say we support the default.

}

flow.createAndStoreCredential(response, null);
public void doCommenceLogin(@QueryParameter String from, @Header("Referer") final String referer)

Check warning

Code scanning / Jenkins Security Scan

Stapler: Missing POST/RequirePOST annotation Warning

Potential CSRF vulnerability: If OicSecurityRealm#doCommenceLogin connects to user-specified URLs, modifies state, or is expensive to run, it should be annotated with @POST or @RequirePOST
src/main/java/org/jenkinsci/plugins/oic/ssl/TLSUtils.java Dismissed Show dismissed Hide dismissed
@@ -1,6 +1,11 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">


<f:entry title="${%Issuer}" field="issuer">
Copy link
Member Author

@jtnord jtnord Oct 3, 2024

Choose a reason for hiding this comment

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

moved up as it is now mandatory to make it more prominent vs the other fields.

pom.xml Outdated
<jenkins.version>2.426.3</jenkins.version>
<spotless.check.skip>false</spotless.check.skip>
<spotbugs.effort>Max</spotbugs.effort>
<configuration-as-code.version>1836.vccda_4a_122a_a_e</configuration-as-code.version>
<hpi.compatibleSinceVersion>4.347</hpi.compatibleSinceVersion>
<hpi.compatibleSinceVersion>4.356</hpi.compatibleSinceVersion>
Copy link
Member Author

Choose a reason for hiding this comment

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

needs to be checked and updated before final merge.

}

private OidcConfiguration buildOidcConfiguration() {
// TODO cache this and use the well known if available.
Copy link
Member Author

Choose a reason for hiding this comment

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

for a future PR. We can cache the client and invalidate it every 1 hour if using the well-known (as the well known refresh is now hard coded to 1hr).

Comment on lines +476 to +478
// TODO what do we prefer?
// conf.setPreferredJwsAlgorithm(JWSAlgorithm.HS256);
// set many more as needed...
Copy link
Member Author

Choose a reason for hiding this comment

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

not intending for this to happen in this PR but a follow-up that exposes some more advanced options.
e.g. #408

Copy link

codecov bot commented Oct 4, 2024

Codecov Report

Attention: Patch coverage is 68.48875% with 98 lines in your changes missing coverage. Please review.

Project coverage is 71.80%. Comparing base (5b51704) to head (d5e1522).
Report is 18 commits behind head on master.

Files with missing lines Patch % Lines
...va/org/jenkinsci/plugins/oic/OicSecurityRealm.java 75.48% 26 Missing and 12 partials ⚠️
...i/plugins/oic/OicServerWellKnownConfiguration.java 50.00% 18 Missing and 6 partials ⚠️
...nsci/plugins/oic/OicServerManualConfiguration.java 76.47% 5 Missing and 3 partials ⚠️
...kinsci/plugins/oic/AnythingGoesTokenValidator.java 66.66% 7 Missing ⚠️
...jenkinsci/plugins/oic/CustomOidcConfiguration.java 65.00% 4 Missing and 3 partials ⚠️
...insci/plugins/oic/ProxyAwareResourceRetriever.java 70.58% 3 Missing and 2 partials ⚠️
...nsci/plugins/oic/ssl/AnythingGoesTrustManager.java 37.50% 4 Missing and 1 partial ⚠️
...n/java/org/jenkinsci/plugins/oic/ssl/TLSUtils.java 50.00% 2 Missing and 1 partial ⚠️
...nsci/plugins/oic/ssl/IgnoringHostNameVerifier.java 50.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master     #409      +/-   ##
============================================
- Coverage     72.66%   71.80%   -0.87%     
  Complexity      199      199              
============================================
  Files            16       16              
  Lines           867      883      +16     
  Branches        116      120       +4     
============================================
+ Hits            630      634       +4     
- Misses          177      185       +8     
- Partials         60       64       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

This changes the Google OAuth library which is in maintainance mode with
a supported library (nimbusds via pac4j)

The library requires that the Issuer is set to enforce security and
there is no option to disable this requirement as it is mandated in the
specificiation.  As such users must first update to 4.355.v3a_fb_fca_b_96d4
to set the Issuer before updating to this version.

fixes: jenkinsci#313
jtnord added 2 commits October 7, 2024 14:56
The option is not removed here, so that it can staty in the config.
This will at least allow users to downgrade as the option would be
retained.
@jtnord
Copy link
Member Author

jtnord commented Oct 8, 2024

fixing the NPE, shows there is another more serious issue here, the token validator is used to cehck the id token when refreshing (actually creating a new!) Profile.
The id token may not contain a nonce (in fact "SHOULD NOT") which is the case in AWS Cognito. However the library (infact the token verifier) is expecting a nonce and is then failing that it does not exist.

FINE: Missing JWT nonce (nonce) claim
com.nimbusds.jwt.proc.BadJWTException: Missing JWT nonce (nonce) claim
        at com.nimbusds.openid.connect.sdk.validators.BadJWTExceptions.<clinit>(BadJWTExceptions.java:70)
        at com.nimbusds.openid.connect.sdk.validators.IDTokenClaimsVerifier.verify(IDTokenClaimsVerifier.java:248)
        at com.nimbusds.jwt.proc.DefaultJWTProcessor.verifyClaims(DefaultJWTProcessor.java:271)
        at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:373)
        at com.nimbusds.openid.connect.sdk.validators.IDTokenValidator.validate(IDTokenValidator.java:321)
        at com.nimbusds.openid.connect.sdk.validators.IDTokenValidator.validate(IDTokenValidator.java:254)
        at org.pac4j.oidc.profile.creator.TokenValidator.validate(TokenValidator.java:108)
        at org.pac4j.oidc.profile.creator.OidcProfileCreator.create(OidcProfileCreator.java:108)
        at org.pac4j.core.client.BaseClient.retrieveUserProfile(BaseClient.java:126)
        at org.pac4j.core.client.BaseClient.getUserProfile(BaseClient.java:105)
        at org.pac4j.oidc.client.OidcClient.renewUserProfile(OidcClient.java:69)
        at org.jenkinsci.plugins.oic.OicSecurityRealm.refreshExpiredToken(OicSecurityRealm.java:1220)

This appears to be a bug with pac4j. We ae not using the latest version as that requires java17 which is not required for Jenkins prior to 2.463 (which will mean the upcoming LTS version of 2.479).
Whilst I have not found any indication that pac4j 6.x fixes this, it should be tested as this is the active (comminuity) supported line.

jtnord added 4 commits October 8, 2024 12:03
Pac4j setups the token validators, which during the refresh lifecycle
will attempt to check an ID tokens nonce.
However a provider should not set the nonce in the idtoken during a
refresh, and in this case the validator fails because the nonce is
missing from the token!

we disable the nonce check for the refresh call.  it can be optionally
re-enabled by setting the system property
org.jenkinsci.plugins.oic.OicSecurityRealm.checkNonceInRefreshFlow to
true.
this is not exposed as a config option in the UI as
1) providers should not be sending the nonce anyway
2) this should be a short lived workaround whilst the issue with the
   library is filed and fixed.
@jtnord
Copy link
Member Author

jtnord commented Oct 8, 2024

This appears to be a bug with pac4j. We ae not using the latest version as that requires java17 which is not required for Jenkins prior to 2.463 (which will mean the upcoming LTS version of 2.479). Whilst I have not found any indication that pac4j 6.x fixes this, it should be tested as this is the active (comminuity) supported line.

workaround added in fb4ce0c

@fcojfernandez is attempting to reproduce this with pac4j v6 to either upgrade or file a report upstream

jtnord added 2 commits October 8, 2024 15:53
For extra security disable the "none" algorithm if the server claims to
support it.

Whilst we are using code flow, it is not needed, but providers MUST
support RS256 so there would always be a more secure option we can use.
}

setWellKnownExpires(response.getHeaders());
// do not allow the "none" singing algorithm for security
Copy link
Member Author

Choose a reason for hiding this comment

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

Whilst we are using code flow, it is not needed, but providers MUST support RS256 so there would always be a more secure option we can use.

@jtnord jtnord marked this pull request as ready for review October 8, 2024 16:05
public OIDCProviderMetadata toProviderMetadata() {
// we perform this download manually rather than letting pac4j perform it
// so that we can cache and expire the result.
// pac4j will cache the result yet never expire it.
Copy link
Member

Choose a reason for hiding this comment

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

👍

@jglick
Copy link
Member

jglick commented Oct 9, 2024

We [are] not using the latest version as that requires java17 which is not required for Jenkins prior to 2.463 (which will mean the upcoming LTS version of 2.479).

I do not think you should hesitate to switch the plugin baseline to 2.479, especially for a major change like this one.

CustomOidcConfiguration(boolean disableTLS) {
this.disableTLS = disableTLS;
if (FIPS140.useCompliantAlgorithms() && disableTLS) {
throw new IllegalStateException("Cannot disable TLS validation in FIPS-140 mode");
Copy link
Contributor

Choose a reason for hiding this comment

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

For my own learning.
IllegalState instead of IllegalArgument because this is only used during login, so it means configuration was already wrong (and should have been raised when creating the realm once jtnord#1 is merged) isn't it?

Copy link
Member Author

@jtnord jtnord Oct 9, 2024

Choose a reason for hiding this comment

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

and should have been raised when creating the realm once jtnord#1 is merged

correct

@fcojfernandez
Copy link
Member

We [are] not using the latest version as that requires java17 which is not required for Jenkins prior to 2.463 (which will mean the upcoming LTS version of 2.479).

I do not think you should hesitate to switch the plugin baseline to 2.479, especially for a major change like this one.

@jglick I'm doing it as part of #409 (comment)

fcojfernandez
fcojfernandez previously approved these changes Oct 9, 2024
@jtnord
Copy link
Member Author

jtnord commented Oct 9, 2024

@michael-doubez would you like to take a look at this before I merge?

Copy link
Contributor

@mikecirioli mikecirioli left a comment

Choose a reason for hiding this comment

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

I played around with this locally using a keycloak idp that i already had configured and did not encounter any issues. This change did help me uncover a misconfiguration in my security realm (disable token validation was not checked, but no JWKS url was specified - the old code cleverly hid this from you for some reason 🥲 )

@jtnord jtnord merged commit 7706fbd into jenkinsci:master Oct 10, 2024
19 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Replace OpenID Connect backend library
7 participants