diff --git a/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java b/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java
index 488f33fd..aabbfddd 100644
--- a/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java
+++ b/src/main/java/org/jenkinsci/plugins/oic/OicSecurityRealm.java
@@ -823,12 +823,15 @@ private OicJsonWebTokenVerifier getJwksVerifier() {
if (jwtVerifier == null) {
jwtVerifier = new OicJsonWebTokenVerifier(
serverConfiguration.getJwksServerUrl(),
- new OicJsonWebTokenVerifier.Builder().setHttpTransportFactory(new HttpTransportFactory() {
- @Override
- public HttpTransport create() {
- return httpTransport;
- }
- }));
+ new OicJsonWebTokenVerifier.Builder()
+ .setHttpTransportFactory(new HttpTransportFactory() {
+ @Override
+ public HttpTransport create() {
+ return httpTransport;
+ }
+ })
+ .setIssuer(getServerConfiguration().getIssuer())
+ .setAudience(List.of(clientId)));
}
return jwtVerifier;
}
diff --git a/src/main/java/org/jenkinsci/plugins/oic/OicServerConfiguration.java b/src/main/java/org/jenkinsci/plugins/oic/OicServerConfiguration.java
index c543ff26..889c7c73 100644
--- a/src/main/java/org/jenkinsci/plugins/oic/OicServerConfiguration.java
+++ b/src/main/java/org/jenkinsci/plugins/oic/OicServerConfiguration.java
@@ -33,5 +33,8 @@ public abstract class OicServerConfiguration extends AbstractDescribableImpl
+
+
+
diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/config.properties b/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/config.properties
index 56bbf500..857f29e1 100644
--- a/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/config.properties
+++ b/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/config.properties
@@ -1,6 +1,7 @@
AuthorizationServerUrl=Authorization server url
Basic=Basic
EndSessionUrl=End session URL for OpenID Provider
+Issuer=Issuer
JwksServerUrl=Jwks server url
Post=Post
Scopes=Scopes
diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/help-issuer.html b/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/help-issuer.html
new file mode 100644
index 00000000..7209bfcc
--- /dev/null
+++ b/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/help-issuer.html
@@ -0,0 +1,3 @@
+
+ Strongly recommended. The received ID Token's issuer must match the specified issuer.
+
diff --git a/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/help-issuer_fr.html b/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/help-issuer_fr.html
new file mode 100644
index 00000000..0e98f08e
--- /dev/null
+++ b/src/main/resources/org/jenkinsci/plugins/oic/OicServerManualConfiguration/help-issuer_fr.html
@@ -0,0 +1,3 @@
+
+ Fortement recommandé. Le Token ID reçu doit avoir l'émetteur indiqué.
+
diff --git a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java
index 35048967..94348b6c 100644
--- a/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java
+++ b/src/test/java/org/jenkinsci/plugins/oic/PluginTest.java
@@ -47,6 +47,7 @@
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
+import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.Url;
import org.kohsuke.stapler.Stapler;
@@ -987,6 +988,58 @@ public void loginWithCheckTokenFailure() throws Exception {
assertAnonymous();
}
+ @Test
+ @Issue("SECURITY-3441")
+ public void loginWithIncorrectIssuerFails() throws Exception {
+ mockAuthorizationRedirectsToFinishLogin();
+ mockTokenReturnsIdTokenWithGroup();
+ jenkins.setSecurityRealm(
+ new TestRealm.Builder(wireMockRule).WithIssuer("another_issuer").build());
+ assertAnonymous();
+ webClient.setThrowExceptionOnFailingStatusCode(false);
+ browseLoginPage();
+ assertAnonymous();
+ }
+
+ @Test
+ @Issue("SECURITY-3441")
+ public void loginWithoutIssuerSetSucceeds() throws Exception {
+ mockAuthorizationRedirectsToFinishLogin();
+ mockTokenReturnsIdTokenWithGroup();
+ jenkins.setSecurityRealm(
+ new TestRealm.Builder(wireMockRule).WithIssuer(null).build());
+ assertAnonymous();
+ webClient.setThrowExceptionOnFailingStatusCode(false);
+ browseLoginPage();
+ assertTestUser();
+ }
+
+ @Test
+ @Issue("SECURITY-3441")
+ public void loginWithEmptyIssuerSetSucceeds() throws Exception {
+ mockAuthorizationRedirectsToFinishLogin();
+ mockTokenReturnsIdTokenWithGroup();
+ jenkins.setSecurityRealm(
+ new TestRealm.Builder(wireMockRule).WithIssuer(null).build());
+ assertAnonymous();
+ webClient.setThrowExceptionOnFailingStatusCode(false);
+ browseLoginPage();
+ assertTestUser();
+ }
+
+ @Test
+ @Issue("SECURITY-3441")
+ public void loginWithIncorrectAudienceFails() throws Exception {
+ mockAuthorizationRedirectsToFinishLogin();
+ mockTokenReturnsIdTokenWithGroup();
+ jenkins.setSecurityRealm(new TestRealm.Builder(wireMockRule)
+ .WithClient("another_client_id", "client_secret").build());
+ assertAnonymous();
+ webClient.setThrowExceptionOnFailingStatusCode(false);
+ browseLoginPage();
+ assertAnonymous();
+ }
+
@Test
public void testAccessUsingJenkinsApiTokens() throws Exception {
mockAuthorizationRedirectsToFinishLogin();
diff --git a/src/test/java/org/jenkinsci/plugins/oic/TestRealm.java b/src/test/java/org/jenkinsci/plugins/oic/TestRealm.java
index d7f3cc5a..fd6235b7 100644
--- a/src/test/java/org/jenkinsci/plugins/oic/TestRealm.java
+++ b/src/test/java/org/jenkinsci/plugins/oic/TestRealm.java
@@ -20,6 +20,7 @@ public class TestRealm extends OicSecurityRealm {
public static class Builder {
public String clientId = CLIENT_ID;
public Secret clientSecret = Secret.fromString("secret");
+ public String issuer = "issuer";
public String wellKnownOpenIDConfigurationUrl;
public String tokenServerUrl;
public String jwksServerUrl = null;
@@ -59,6 +60,11 @@ public Builder WithClient(String clientId, String clientSecret) {
return this;
}
+ public Builder WithIssuer(String issuer) {
+ this.issuer = issuer;
+ return this;
+ }
+
public Builder WithUserInfoServerUrl(String userInfoServerUrl) {
this.userInfoServerUrl = userInfoServerUrl;
return this;
@@ -139,6 +145,7 @@ public OicServerConfiguration buildServerConfiguration() {
}
conf.setJwksServerUrl(jwksServerUrl);
conf.setEndSessionUrl(endSessionEndpoint);
+ conf.setIssuer(issuer);
return conf;
} catch (Exception e) {
throw new IllegalArgumentException(e);
diff --git a/src/test/java/org/jenkinsci/plugins/oic/WellKnownOpenIDConfigurationResponseTest.java b/src/test/java/org/jenkinsci/plugins/oic/WellKnownOpenIDConfigurationResponseTest.java
index 525e5286..9cf1c184 100644
--- a/src/test/java/org/jenkinsci/plugins/oic/WellKnownOpenIDConfigurationResponseTest.java
+++ b/src/test/java/org/jenkinsci/plugins/oic/WellKnownOpenIDConfigurationResponseTest.java
@@ -75,6 +75,7 @@ public class WellKnownOpenIDConfigurationResponseTest {
Set.of("token_endpoint_auth_methods_supported", "scopes_supported", "grant_types_supported");
private static final List FIELDS = List.of(
"authorization_endpoint",
+ "issuer",
"token_endpoint",
"userinfo_endpoint",
"jwks_uri",