Skip to content

Commit

Permalink
[improve] Use HTTPS in OIDC Identity Provider Integration Tests (apac…
Browse files Browse the repository at this point in the history
…he#20746)

### Motivation

While investigating https://stackoverflow.com/questions/76631732/apache-pulsar-unable-to-validate-issuer-certificate-when-attempting-to-load-open, I got the integration tests working using HTTPS.

### Modifications

* Update the tests for OIDC to use HTTPS

### Documentation

- [x] `doc-not-needed`
  • Loading branch information
michaeljmarshall authored Jul 7, 2023
1 parent 76b0ef4 commit cedc513
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 12 deletions.
22 changes: 22 additions & 0 deletions pulsar-broker-auth-oidc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,28 @@
</environmentVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>test-compile</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.testOutputDirectory}/certificate-authority</outputDirectory>
<overwrite>true</overwrite>
<resources>
<resource>
<directory>${project.parent.basedir}/tests/certificate-authority</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import static org.testng.Assert.fail;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.stubbing.Scenario;
import com.google.common.io.Resources;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultJwtBuilder;
import io.jsonwebtoken.io.Decoders;
Expand Down Expand Up @@ -69,6 +70,7 @@ public class AuthenticationProviderOpenIDIntegrationTest {

AuthenticationProviderOpenID provider;
PrivateKey privateKey;
String caCert = Resources.getResource("certificate-authority/jks/broker.truststore.pem").getPath();

// These are the kid values for JWKs in the /keys endpoint
String validJwk = "valid";
Expand All @@ -89,7 +91,11 @@ void beforeClass() throws IOException {

// Port matches the port supplied in the fakeKubeConfig.yaml resource, which makes the k8s integration
// tests work correctly.
server = new WireMockServer(wireMockConfig().port(0));
server = new WireMockServer(wireMockConfig().dynamicHttpsPort()
.keystorePath(Resources.getResource("certificate-authority/jks/broker.keystore.jks").getPath())
.keystoreType("JKS")
.keyManagerPassword("111111")
.keystorePassword("111111"));
server.start();
issuer = server.baseUrl();
issuerWithTrailingSlash = issuer + "/trailing-slash/";
Expand Down Expand Up @@ -235,7 +241,7 @@ void beforeClass() throws IOException {
conf.setAuthenticationEnabled(true);
conf.setAuthenticationProviders(Set.of(AuthenticationProviderOpenID.class.getName()));
Properties props = conf.getProperties();
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
props.setProperty(AuthenticationProviderOpenID.ALLOWED_TOKEN_ISSUERS, issuer + "," + issuerWithTrailingSlash
+ "," + issuerThatFails);
Expand Down Expand Up @@ -328,7 +334,7 @@ public void testKidCacheMissWhenRefreshConfigZero() throws Exception {
conf.setAuthenticationEnabled(true);
conf.setAuthenticationProviders(Set.of(AuthenticationProviderOpenID.class.getName()));
Properties props = conf.getProperties();
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
// Allows us to retrieve the JWK immediately after the cache miss of the KID
props.setProperty(AuthenticationProviderOpenID.KEY_ID_CACHE_MISS_REFRESH_SECONDS, "0");
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
Expand All @@ -348,7 +354,7 @@ public void testKidCacheMissWhenRefreshConfigLongerThanDelta() throws Exception
conf.setAuthenticationEnabled(true);
conf.setAuthenticationProviders(Set.of(AuthenticationProviderOpenID.class.getName()));
Properties props = conf.getProperties();
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
// This value is high enough that the provider will not refresh the JWK
props.setProperty(AuthenticationProviderOpenID.KEY_ID_CACHE_MISS_REFRESH_SECONDS, "100");
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
Expand All @@ -375,7 +381,7 @@ public void testKubernetesApiServerAsDiscoverTrustedIssuerSuccess() throws Excep
conf.setAuthenticationEnabled(true);
conf.setAuthenticationProviders(Set.of(AuthenticationProviderOpenID.class.getName()));
Properties props = conf.getProperties();
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
props.setProperty(AuthenticationProviderOpenID.FALLBACK_DISCOVERY_MODE, "KUBERNETES_DISCOVER_TRUSTED_ISSUER");
// Test requires that k8sIssuer is not in the allowed token issuers
Expand Down Expand Up @@ -409,7 +415,7 @@ public void testKubernetesApiServerAsDiscoverTrustedIssuerFailsDueToMismatchedIs
conf.setAuthenticationEnabled(true);
conf.setAuthenticationProviders(Set.of(AuthenticationProviderOpenID.class.getName()));
Properties props = conf.getProperties();
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
props.setProperty(AuthenticationProviderOpenID.FALLBACK_DISCOVERY_MODE, "KUBERNETES_DISCOVER_TRUSTED_ISSUER");
props.setProperty(AuthenticationProviderOpenID.ALLOWED_TOKEN_ISSUERS, "");
Expand All @@ -434,7 +440,7 @@ public void testKubernetesApiServerAsDiscoverPublicKeySuccess() throws Exception
conf.setAuthenticationEnabled(true);
conf.setAuthenticationProviders(Set.of(AuthenticationProviderOpenID.class.getName()));
Properties props = conf.getProperties();
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
props.setProperty(AuthenticationProviderOpenID.FALLBACK_DISCOVERY_MODE, "KUBERNETES_DISCOVER_PUBLIC_KEYS");
// Test requires that k8sIssuer is not in the allowed token issuers
Expand Down Expand Up @@ -465,7 +471,7 @@ public void testKubernetesApiServerAsDiscoverPublicKeyFailsDueToMismatchedIssuer
conf.setAuthenticationEnabled(true);
conf.setAuthenticationProviders(Set.of(AuthenticationProviderOpenID.class.getName()));
Properties props = conf.getProperties();
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
props.setProperty(AuthenticationProviderOpenID.FALLBACK_DISCOVERY_MODE, "KUBERNETES_DISCOVER_PUBLIC_KEYS");
props.setProperty(AuthenticationProviderOpenID.ALLOWED_TOKEN_ISSUERS, "");
Expand Down Expand Up @@ -527,7 +533,7 @@ public void testAuthenticationStateOpenIDForTokenExpiration() throws Exception {
conf.setAuthenticationEnabled(true);
conf.setAuthenticationProviders(Set.of(AuthenticationProviderOpenID.class.getName()));
Properties props = conf.getProperties();
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
props.setProperty(AuthenticationProviderOpenID.ALLOWED_TOKEN_ISSUERS, issuer);
// Use the leeway to allow the token to pass validation and then fail expiration
Expand Down Expand Up @@ -557,7 +563,7 @@ public void testAuthenticationProviderListStateSuccess() throws Exception {
conf.setAuthenticationProviders(Set.of(AuthenticationProviderOpenID.class.getName(),
AuthenticationProviderToken.class.getName()));
Properties props = conf.getProperties();
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
props.setProperty(AuthenticationProviderOpenID.ALLOWED_TOKEN_ISSUERS, issuer);

Expand Down Expand Up @@ -602,7 +608,7 @@ void ensureRoleClaimForNonSubClaimReturnsRole() throws Exception {
props.setProperty(AuthenticationProviderOpenID.ALLOWED_TOKEN_ISSUERS, issuer);
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
props.setProperty(AuthenticationProviderOpenID.ROLE_CLAIM, "test");
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
ServiceConfiguration config = new ServiceConfiguration();
config.setProperties(props);
provider.initialize(config);
Expand All @@ -622,7 +628,7 @@ void ensureRoleClaimForNonSubClaimFailsWhenClaimIsMissing() throws Exception {
props.setProperty(AuthenticationProviderOpenID.ALLOWED_TOKEN_ISSUERS, issuer);
props.setProperty(AuthenticationProviderOpenID.ALLOWED_AUDIENCES, "allowed-audience");
props.setProperty(AuthenticationProviderOpenID.ROLE_CLAIM, "test");
props.setProperty(AuthenticationProviderOpenID.REQUIRE_HTTPS, "false");
props.setProperty(AuthenticationProviderOpenID.ISSUER_TRUST_CERTS_FILE_PATH, caCert);
ServiceConfiguration config = new ServiceConfiguration();
config.setProperties(props);
provider.initialize(config);
Expand Down
3 changes: 3 additions & 0 deletions tests/certificate-authority/generate_keystore.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ java ../RemoveJksPassword.java broker.truststore.jks 111111 broker.truststore.no
java ../RemoveJksPassword.java proxy.truststore.jks 111111 proxy.truststore.nopassword.jks
java ../RemoveJksPassword.java proxy-and-client.truststore.jks 111111 proxy-and-client.truststore.nopassword.jks

# write broker truststore to pem file for use in http client as a ca cert
keytool -keystore broker.truststore.jks -exportcert -alias truststore | openssl x509 -inform der -text > broker.truststore.pem

# cleanup
rm broker.cer
rm client.cer
Expand Down
73 changes: 73 additions & 0 deletions tests/certificate-authority/jks/broker.truststore.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 17442377827579325010 (0xf20fc6387303ea52)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=Unknown, ST=Unknown, L=Unknown, O=Unknown, OU=Unknown, CN=localhost
Validity
Not Before: Feb 13 05:52:32 2023 GMT
Not After : Jan 20 05:52:32 2123 GMT
Subject: C=Unknown, ST=Unknown, L=Unknown, O=Unknown, OU=Unknown, CN=localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:e8:b7:df:ee:32:88:98:0e:07:18:41:fd:d8:e2:
34:c8:7e:54:86:9b:d8:a3:7b:47:6e:e9:a1:8c:74:
f3:0f:bb:a6:83:43:11:77:c4:9a:ab:53:74:64:46:
fe:81:8f:72:03:97:0b:37:78:6e:ff:6e:64:68:eb:
9e:b0:6b:ae:79:6a:50:e1:1e:1d:39:df:51:0b:04:
8e:89:4b:e4:02:6b:e4:12:d3:41:47:2c:8e:75:30:
14:1a:ed:32:93:a6:fe:73:7d:dc:e0:d4:93:d9:8c:
44:55:d2:53:4a:0c:2e:f9:95:5f:4f:cb:2f:e5:41:
c5:bc:33:88:eb:d8:52:0e:19:55:36:02:31:0f:81:
0b:c2:4f:35:63:a6:06:e3:3b:93:3c:04:5c:63:32:
3d:c3:26:50:96:b7:8c:67:8e:9e:d1:a3:7e:7b:54:
86:35:07:fe:15:32:fb:6d:4e:e7:4c:97:95:32:e2:
d8:04:8b:e2:00:4b:85:64:91:70:ae:24:88:07:47:
45:7d:19:c3:c1:25:02:50:f8:f4:0a:a3:7b:6a:11:
c3:6f:b9:da:06:a0:2d:3d:65:47:8e:28:d2:18:8a:
45:bb:79:7b:ba:d5:d8:29:4d:4e:da:fd:b2:1e:eb:
b6:59:1b:f1:c9:8a:ea:ac:7d:72:dc:8d:e7:43:7d:
d3:c7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
88:3A:59:9D:B2:72:AC:64:FB:F3:8D:79:ED:54:FE:20:C3:83:49:24
Signature Algorithm: sha256WithRSAEncryption
71:88:eb:c7:f2:f2:84:35:f7:ab:bc:3c:ce:be:11:f9:c9:36:
b5:1e:93:96:cf:66:06:4a:f1:b6:f5:cc:97:b9:cd:93:0f:8a:
66:62:85:cb:fd:c1:63:7e:38:d9:02:0c:6b:04:38:7b:ec:82:
e6:25:f3:8c:99:8d:d1:20:c6:eb:5e:75:9e:b6:f0:ec:ad:9a:
76:22:41:bd:88:e9:c3:7f:3d:8e:9a:f1:4a:b3:e2:30:ca:e0:
68:39:8d:7c:e6:db:dc:fd:44:75:66:55:d3:a7:8f:eb:fb:28:
86:bd:ae:3e:93:9d:f6:76:32:db:05:4d:6e:34:92:16:21:85:
d3:0e:2f:73:d3:89:f7:69:6e:0c:74:35:95:8c:e3:ff:c6:f7:
5c:b4:55:c0:49:7d:00:ae:6c:88:5b:46:31:b3:62:64:62:b0:
0d:9c:7c:d0:84:68:d9:e3:52:ed:35:f8:5a:6f:9e:57:62:4b:
36:8f:f7:3e:31:15:fc:bb:df:51:c4:fd:92:96:59:d5:55:3e:
7b:fb:2f:2e:5a:15:be:ec:46:38:e0:c9:b4:46:cb:5c:71:4a:
fe:c7:19:2c:84:1c:d9:15:12:fc:40:cc:7c:fc:f4:38:22:f6:
ba:db:f2:05:97:c1:26:f5:cb:c0:ed:ba:16:e6:33:0c:37:3a:
07:b3:a3:ca
-----BEGIN CERTIFICATE-----
MIIDgjCCAmqgAwIBAgIJAPIPxjhzA+pSMA0GCSqGSIb3DQEBCwUAMG4xEDAOBgNV
BAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vua25vd24x
EDAOBgNVBAoTB1Vua25vd24xEDAOBgNVBAsTB1Vua25vd24xEjAQBgNVBAMTCWxv
Y2FsaG9zdDAgFw0yMzAyMTMwNTUyMzJaGA8yMTIzMDEyMDA1NTIzMlowbjEQMA4G
A1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93
bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjESMBAGA1UEAxMJ
bG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Lff7jKI
mA4HGEH92OI0yH5UhpvYo3tHbumhjHTzD7umg0MRd8Saq1N0ZEb+gY9yA5cLN3hu
/25kaOuesGuueWpQ4R4dOd9RCwSOiUvkAmvkEtNBRyyOdTAUGu0yk6b+c33c4NST
2YxEVdJTSgwu+ZVfT8sv5UHFvDOI69hSDhlVNgIxD4ELwk81Y6YG4zuTPARcYzI9
wyZQlreMZ46e0aN+e1SGNQf+FTL7bU7nTJeVMuLYBIviAEuFZJFwriSIB0dFfRnD
wSUCUPj0CqN7ahHDb7naBqAtPWVHjijSGIpFu3l7utXYKU1O2v2yHuu2WRvxyYrq
rH1y3I3nQ33TxwIDAQABoyEwHzAdBgNVHQ4EFgQUiDpZnbJyrGT784157VT+IMOD
SSQwDQYJKoZIhvcNAQELBQADggEBAHGI68fy8oQ196u8PM6+EfnJNrUek5bPZgZK
8bb1zJe5zZMPimZihcv9wWN+ONkCDGsEOHvsguYl84yZjdEgxutedZ628OytmnYi
Qb2I6cN/PY6a8Uqz4jDK4Gg5jXzm29z9RHVmVdOnj+v7KIa9rj6TnfZ2MtsFTW40
khYhhdMOL3PTifdpbgx0NZWM4//G91y0VcBJfQCubIhbRjGzYmRisA2cfNCEaNnj
Uu01+FpvnldiSzaP9z4xFfy731HE/ZKWWdVVPnv7Ly5aFb7sRjjgybRGy1xxSv7H
GSyEHNkVEvxAzHz89Dgi9rrb8gWXwSb1y8DtuhbmMww3Ogezo8o=
-----END CERTIFICATE-----

0 comments on commit cedc513

Please sign in to comment.