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

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

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 (b48a299) to head (d5e1522).
Report is 10 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     74.16%   71.80%   -2.37%     
+ Complexity      261      199      -62     
============================================
  Files            15       16       +1     
  Lines          1022      883     -139     
  Branches        147      120      -27     
============================================
- Hits            758      634     -124     
+ Misses          191      185       -6     
+ Partials         73       64       -9     

☔ 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
Copy link
Member Author

jtnord commented Oct 7, 2024

Managed to get a Cognito server setup (FFR. you can use http if the URL is for localhost)
The code works if using well-known discovery, but not if using manual config, and I have tracked down one simple error (2941d99) and it is working for me now (tested simple login and logout)

refresh tokens do not work with cognito as the return from the token refresh is missing the refresh token so it gets overwritten with null here and then the profile blows up.

This was fixed in 6.0.4.1 but needs java 17 which means we need to bump the baseline...

The provider config did not contain the jsksServerUrl if it was present
in the manual configuration.  This caused signed tokens to be rejected
when in manual configuration mode.
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.

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

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
Contributor

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");

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

Co-authored-by: Pere <pbuenoyerbes@cloudbees.com>
@fcojfernandez
Copy link
Contributor

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?

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
6 participants