Skip to content

Commit b7e8ec6

Browse files
committed
Add unit tests for the CertificateIdentityPoolSubjectTokenSupplier class.
1 parent fb3d375 commit b7e8ec6

File tree

2 files changed

+157
-1
lines changed

2 files changed

+157
-1
lines changed

oauth2_http/java/com/google/auth/oauth2/CertificateIdentityPoolSubjectTokenSupplier.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import static com.google.common.base.Preconditions.checkNotNull;
3535

36+
import com.google.common.annotations.VisibleForTesting;
3637
import com.google.gson.Gson;
3738
import com.google.gson.JsonArray;
3839
import com.google.gson.JsonPrimitive;
@@ -83,7 +84,8 @@ private static X509Certificate loadLeafCertificate(String path)
8384
return parseCertificate(leafCertBytes);
8485
}
8586

86-
private static X509Certificate parseCertificate(byte[] certData) throws CertificateException {
87+
@VisibleForTesting
88+
static X509Certificate parseCertificate(byte[] certData) throws CertificateException {
8789
if (certData == null || certData.length == 0) {
8890
throw new IllegalArgumentException("Invalid certificate data: empty or null input");
8991
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright 2025, Google LLC
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
*
15+
* * Neither the name of Google LLC nor the names of its
16+
* contributors may be used to endorse or promote products derived from
17+
* this software without specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
32+
package com.google.auth.oauth2;
33+
34+
import static org.junit.Assert.*;
35+
36+
import com.google.auth.oauth2.IdentityPoolCredentialSource.CertificateConfig;
37+
import com.google.gson.Gson;
38+
import com.google.gson.JsonArray;
39+
import com.google.gson.JsonPrimitive;
40+
import java.io.ByteArrayInputStream;
41+
import java.io.File;
42+
import java.io.IOException;
43+
import java.nio.charset.StandardCharsets;
44+
import java.nio.file.Files;
45+
import java.security.cert.CertificateException;
46+
import java.security.cert.CertificateFactory;
47+
import java.security.cert.X509Certificate;
48+
import java.util.Base64;
49+
import org.junit.Before;
50+
import org.junit.Rule;
51+
import org.junit.Test;
52+
import org.junit.rules.TemporaryFolder;
53+
import org.junit.runner.RunWith;
54+
import org.junit.runners.JUnit4;
55+
import org.mockito.Mock;
56+
import org.mockito.junit.MockitoJUnit;
57+
import org.mockito.junit.MockitoRule;
58+
59+
/** Tests for {@link CertificateIdentityPoolSubjectTokenSupplier}. */
60+
@RunWith(JUnit4.class)
61+
public class CertificateIdentityPoolSubjectTokenSupplierTest {
62+
63+
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
64+
@Rule public TemporaryFolder tempFolder = new TemporaryFolder();
65+
66+
@Mock private IdentityPoolCredentialSource mockCredentialSource;
67+
@Mock private CertificateConfig mockCertificateConfig;
68+
@Mock private ExternalAccountSupplierContext mockContext;
69+
70+
private CertificateIdentityPoolSubjectTokenSupplier supplier;
71+
private static final Gson GSON = new Gson();
72+
73+
// Certificate data from X509ProviderTest
74+
private static final String TEST_CERT_PEM =
75+
"-----BEGIN CERTIFICATE-----\n"
76+
+ "MIICGzCCAYSgAwIBAgIIWrt6xtmHPs4wDQYJKoZIhvcNAQEFBQAwMzExMC8GA1UE\n"
77+
+ "AxMoMTAwOTEyMDcyNjg3OC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbTAeFw0x\n"
78+
+ "MjEyMDExNjEwNDRaFw0yMjExMjkxNjEwNDRaMDMxMTAvBgNVBAMTKDEwMDkxMjA3\n"
79+
+ "MjY4NzguYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20wgZ8wDQYJKoZIhvcNAQEB\n"
80+
+ "BQADgY0AMIGJAoGBAL1SdY8jTUVU7O4/XrZLYTw0ON1lV6MQRGajFDFCqD2Fd9tQ\n"
81+
+ "GLW8Iftx9wfXe1zuaehJSgLcyCxazfyJoN3RiONBihBqWY6d3lQKqkgsRTNZkdFJ\n"
82+
+ "Wdzl/6CxhK9sojh2p0r3tydtv9iwq5fuuWIvtODtT98EgphhncQAqkKoF3zVAgMB\n"
83+
+ "AAGjODA2MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQM\n"
84+
+ "MAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4GBAD8XQEqzGePa9VrvtEGpf+R4\n"
85+
+ "fkxKbcYAzqYq202nKu0kfjhIYkYSBj6gi348YaxE64yu60TVl42l5HThmswUheW4\n"
86+
+ "uQIaq36JvwvsDP5Zoj5BgiNSnDAFQp+jJFBRUA5vooJKgKgMDf/r/DCOsbO6VJF1\n"
87+
+ "kWwa9n19NFiV0z3m6isj\n"
88+
+ "-----END CERTIFICATE-----\n";
89+
90+
private static final byte[] TEST_CERT_BYTES = TEST_CERT_PEM.getBytes(StandardCharsets.UTF_8);
91+
private static final byte[] INVALID_CERT_BYTES =
92+
"invalid certificate data".getBytes(StandardCharsets.UTF_8);
93+
94+
@Before
95+
public void setUp() throws IOException {
96+
File testCertFile = tempFolder.newFile("certificate.pem");
97+
Files.write(testCertFile.toPath(), TEST_CERT_BYTES);
98+
mockCredentialSource.certificateConfig = mockCertificateConfig;
99+
mockCredentialSource.credentialLocation = testCertFile.getAbsolutePath();
100+
supplier = new CertificateIdentityPoolSubjectTokenSupplier(mockCredentialSource);
101+
}
102+
103+
@Test
104+
public void parseCertificate_validData_returnsCertificate() throws Exception {
105+
X509Certificate cert =
106+
CertificateIdentityPoolSubjectTokenSupplier.parseCertificate(TEST_CERT_BYTES);
107+
assertNotNull(cert);
108+
}
109+
110+
@Test
111+
public void parseCertificate_emptyData_throwsIllegalArgumentException() {
112+
IllegalArgumentException exception =
113+
assertThrows(
114+
IllegalArgumentException.class,
115+
() -> CertificateIdentityPoolSubjectTokenSupplier.parseCertificate(new byte[0]));
116+
assertEquals("Invalid certificate data: empty or null input", exception.getMessage());
117+
}
118+
119+
@Test
120+
public void parseCertificate_nullData_throwsIllegalArgumentException() {
121+
IllegalArgumentException exception =
122+
assertThrows(
123+
IllegalArgumentException.class,
124+
() -> CertificateIdentityPoolSubjectTokenSupplier.parseCertificate(null));
125+
assertEquals("Invalid certificate data: empty or null input", exception.getMessage());
126+
}
127+
128+
@Test
129+
public void parseCertificate_invalidData_throwsCertificateException() {
130+
CertificateException exception =
131+
assertThrows(
132+
CertificateException.class,
133+
() -> CertificateIdentityPoolSubjectTokenSupplier.parseCertificate(INVALID_CERT_BYTES));
134+
assertEquals("Failed to parse X.509 certificate data.", exception.getMessage());
135+
}
136+
137+
@Test
138+
public void getSubjectToken_success() throws Exception {
139+
// Calculate expected result
140+
CertificateFactory cf = CertificateFactory.getInstance("X.509");
141+
X509Certificate expectedCert =
142+
(X509Certificate) cf.generateCertificate(new ByteArrayInputStream(TEST_CERT_BYTES));
143+
String expectedEncodedDer = Base64.getEncoder().encodeToString(expectedCert.getEncoded());
144+
JsonArray expectedJsonArray = new JsonArray();
145+
expectedJsonArray.add(new JsonPrimitive(expectedEncodedDer));
146+
String expectedSubjectToken = GSON.toJson(expectedJsonArray);
147+
148+
// Execute
149+
String actualSubjectToken = supplier.getSubjectToken(mockContext);
150+
151+
// Verify
152+
assertEquals(expectedSubjectToken, actualSubjectToken);
153+
}
154+
}

0 commit comments

Comments
 (0)