Skip to content

Commit

Permalink
fix: Make it explicit that there is a network call to MDS to get Secu…
Browse files Browse the repository at this point in the history
…reSessionAgentConfig (#1573)

* S2A utility returns S2AConfig.

* S2A -> SecureSessionAgent.

* getConfig + javadocs.

* static create.

* typo.

* add javadoc.

* format.
  • Loading branch information
rmehta19 authored Nov 8, 2024
1 parent 7c5ed2f commit 18020fe
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
* <p>This is an experimental utility.
*/
@ThreadSafe
public final class S2A {
public class SecureSessionAgent {
static final String S2A_PLAINTEXT_ADDRESS_JSON_KEY = "plaintext_address";
static final String S2A_MTLS_ADDRESS_JSON_KEY = "mtls_address";
static final String S2A_CONFIG_ENDPOINT_POSTFIX =
Expand All @@ -72,23 +72,25 @@ public final class S2A {
private static final String MDS_MTLS_ENDPOINT =
ComputeEngineCredentials.getMetadataServerUrl() + S2A_CONFIG_ENDPOINT_POSTFIX;

private S2AConfig config;

private transient HttpTransportFactory transportFactory;

S2A(S2A.Builder builder) {
SecureSessionAgent(SecureSessionAgent.Builder builder) {
this.transportFactory = builder.getHttpTransportFactory();
this.config = getS2AConfigFromMDS();
}

/** @return the mTLS S2A Address from the mTLS config. */
public String getMtlsS2AAddress() {
return config.getMtlsAddress();
/**
* This method makes a network call to MDS to get the {@link SecureSessionAgentConfig} which
* contains the plaintext and mtls address to reach the S2A (Secure Session Agent).
*
* @return a SecureSessionAgentConfig.
*/
public SecureSessionAgentConfig getConfig() {
return getSecureSessionAgentConfigFromMDS();
}

/** @return the plaintext S2A Address from the mTLS config. */
public String getPlaintextS2AAddress() {
return config.getPlaintextAddress();
/** @return default instance of SecureSessionAgent */
public static SecureSessionAgent create() {
return newBuilder().build();
}

public static Builder newBuilder() {
Expand All @@ -110,17 +112,18 @@ public HttpTransportFactory getHttpTransportFactory() {
return this.transportFactory;
}

public S2A build() {
return new S2A(this);
public SecureSessionAgent build() {
return new SecureSessionAgent(this);
}
}

/**
* Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link S2AConfig}.
* Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link
* SecureSessionAgentConfig}.
*
* <p>Returns {@link S2AConfig}. If S2A is not running, or if any error occurs when making the
* request to MDS / processing the response, {@link S2AConfig} will be populated with empty
* addresses.
* <p>Returns {@link SecureSessionAgentConfig}. If S2A is not running, or if any error occurs when
* making the request to MDS / processing the response, {@link SecureSessionAgentConfig} will be
* populated with empty addresses.
*
* <p>Users are expected to try to fetch the mTLS-S2A address first (via {@link
* getMtlsS2AAddress}). If it is empty or they have some problem loading the mTLS-MDS credentials,
Expand All @@ -129,9 +132,9 @@ public S2A build() {
* when talking to the MDS / processing the response or that S2A is not running in the
* environment; in either case this indicates S2A shouldn't be used.
*
* @return the {@link S2AConfig}.
* @return the {@link SecureSessionAgentConfig}.
*/
private S2AConfig getS2AConfigFromMDS() {
private SecureSessionAgentConfig getSecureSessionAgentConfigFromMDS() {
if (transportFactory == null) {
transportFactory =
Iterables.getFirst(
Expand All @@ -144,9 +147,9 @@ private S2AConfig getS2AConfigFromMDS() {
request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl);
} catch (IOException ignore) {
/*
* Return empty addresses in {@link S2AConfig} if error building the GET request.
* Return empty addresses in {@link SecureSessionAgentConfig} if error building the GET request.
*/
return S2AConfig.createBuilder().build();
return SecureSessionAgentConfig.createBuilder().build();
}

request.setParser(new JsonObjectParser(OAuth2Utils.JSON_FACTORY));
Expand All @@ -173,14 +176,14 @@ private S2AConfig getS2AConfigFromMDS() {
HttpResponse response = request.execute();
InputStream content = response.getContent();
if (content == null) {
return S2AConfig.createBuilder().build();
return SecureSessionAgentConfig.createBuilder().build();
}
responseData = response.parseAs(GenericData.class);
} catch (IOException ignore) {
/*
* Return empty addresses in {@link S2AConfig} once all retries have been exhausted.
* Return empty addresses in {@link SecureSessionAgentConfig} once all retries have been exhausted.
*/
return S2AConfig.createBuilder().build();
return SecureSessionAgentConfig.createBuilder().build();
}

String plaintextS2AAddress = "";
Expand All @@ -190,19 +193,19 @@ private S2AConfig getS2AConfigFromMDS() {
OAuth2Utils.validateString(responseData, S2A_PLAINTEXT_ADDRESS_JSON_KEY, PARSE_ERROR_S2A);
} catch (IOException ignore) {
/*
* Do not throw error because of parsing error, just leave the address as empty in {@link S2AConfig}.
* Do not throw error because of parsing error, just leave the address as empty in {@link SecureSessionAgentConfig}.
*/
}
try {
mtlsS2AAddress =
OAuth2Utils.validateString(responseData, S2A_MTLS_ADDRESS_JSON_KEY, PARSE_ERROR_S2A);
} catch (IOException ignore) {
/*
* Do not throw error because of parsing error, just leave the address as empty in {@link S2AConfig}.
* Do not throw error because of parsing error, just leave the address as empty in {@link SecureSessionAgentConfig}.
*/
}

return S2AConfig.createBuilder()
return SecureSessionAgentConfig.createBuilder()
.setPlaintextAddress(plaintextS2AAddress)
.setMtlsAddress(mtlsS2AAddress)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import com.google.errorprone.annotations.CanIgnoreReturnValue;

/** Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. */
final class S2AConfig {
public class SecureSessionAgentConfig {
// plaintextAddress is the plaintext address to reach the S2A.
private final String plaintextAddress;

Expand Down Expand Up @@ -86,12 +86,12 @@ public Builder setMtlsAddress(String mtlsAddress) {
return this;
}

public S2AConfig build() {
return new S2AConfig(plaintextAddress, mtlsAddress);
public SecureSessionAgentConfig build() {
return new SecureSessionAgentConfig(plaintextAddress, mtlsAddress);
}
}

private S2AConfig(String plaintextAddress, String mtlsAddress) {
private SecureSessionAgentConfig(String plaintextAddress, String mtlsAddress) {
this.plaintextAddress = plaintextAddress;
this.mtlsAddress = mtlsAddress;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ private MockLowLevelHttpRequest getMockRequestForMtlsConfig(String url) {
@Override
public LowLevelHttpResponse execute() throws IOException {

String metadataRequestHeader = getFirstHeaderValue(S2A.METADATA_FLAVOR);
if (!S2A.GOOGLE.equals(metadataRequestHeader)) {
String metadataRequestHeader = getFirstHeaderValue(SecureSessionAgent.METADATA_FLAVOR);
if (!SecureSessionAgent.GOOGLE.equals(metadataRequestHeader)) {
throw new IOException("Metadata request header not found");
}

Expand Down Expand Up @@ -337,6 +337,7 @@ protected boolean isIdentityDocumentUrl(String url) {
protected boolean isMtlsConfigRequestUrl(String url) {
return url.equals(
String.format(
ComputeEngineCredentials.getMetadataServerUrl() + S2A.S2A_CONFIG_ENDPOINT_POSTFIX));
ComputeEngineCredentials.getMetadataServerUrl()
+ SecureSessionAgent.S2A_CONFIG_ENDPOINT_POSTFIX));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Test cases for {@link S2AConfig}. */
/** Test cases for {@linkSecureSessionAgentConfig}. */
@RunWith(JUnit4.class)
public class S2AConfigTest {
public class SecureSessionAgentConfigTest {
private static final String S2A_PLAINTEXT_ADDRESS = "plaintext";
private static final String S2A_MTLS_ADDRESS = "mtls";

@Test
public void createS2AConfig_success() {
S2AConfig config =
S2AConfig.createBuilder()
SecureSessionAgentConfig config =
SecureSessionAgentConfig.createBuilder()
.setPlaintextAddress(S2A_PLAINTEXT_ADDRESS)
.setMtlsAddress(S2A_MTLS_ADDRESS)
.build();
Expand All @@ -56,7 +56,7 @@ public void createS2AConfig_success() {

@Test
public void createEmptyS2AConfig_success() {
S2AConfig config = S2AConfig.createBuilder().build();
SecureSessionAgentConfig config = SecureSessionAgentConfig.createBuilder().build();
assertTrue(config.getPlaintextAddress().isEmpty());
assertTrue(config.getMtlsAddress().isEmpty());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Test cases for {@link S2A}. */
/** Test cases for {@link SecureSessionAgent}. */
@RunWith(JUnit4.class)
public class S2ATest {
public class SecureSessionAgentTest {

private static final String INVALID_JSON_KEY = "invalid_key";
private static final String S2A_PLAINTEXT_ADDRESS = "plaintext";
Expand All @@ -53,15 +53,17 @@ public void getS2AAddress_validAddress() {
MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory();
transportFactory.transport.setS2AContentMap(
ImmutableMap.of(
S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY,
SecureSessionAgent.S2A_PLAINTEXT_ADDRESS_JSON_KEY,
S2A_PLAINTEXT_ADDRESS,
S2A.S2A_MTLS_ADDRESS_JSON_KEY,
SecureSessionAgent.S2A_MTLS_ADDRESS_JSON_KEY,
S2A_MTLS_ADDRESS));
transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK);

S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build();
String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress();
String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress();
SecureSessionAgent s2aUtils =
SecureSessionAgent.newBuilder().setHttpTransportFactory(transportFactory).build();
SecureSessionAgentConfig config = s2aUtils.getConfig();
String plaintextS2AAddress = config.getPlaintextAddress();
String mtlsS2AAddress = config.getMtlsAddress();
assertEquals(S2A_PLAINTEXT_ADDRESS, plaintextS2AAddress);
assertEquals(S2A_MTLS_ADDRESS, mtlsS2AAddress);
}
Expand All @@ -71,16 +73,18 @@ public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() {
MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory();
transportFactory.transport.setS2AContentMap(
ImmutableMap.of(
S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY,
SecureSessionAgent.S2A_PLAINTEXT_ADDRESS_JSON_KEY,
S2A_PLAINTEXT_ADDRESS,
S2A.S2A_MTLS_ADDRESS_JSON_KEY,
SecureSessionAgent.S2A_MTLS_ADDRESS_JSON_KEY,
S2A_MTLS_ADDRESS));
transportFactory.transport.setRequestStatusCode(
HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE);

S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build();
String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress();
String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress();
SecureSessionAgent s2aUtils =
SecureSessionAgent.newBuilder().setHttpTransportFactory(transportFactory).build();
SecureSessionAgentConfig config = s2aUtils.getConfig();
String plaintextS2AAddress = config.getPlaintextAddress();
String mtlsS2AAddress = config.getMtlsAddress();
assertTrue(plaintextS2AAddress.isEmpty());
assertTrue(mtlsS2AAddress.isEmpty());
}
Expand All @@ -90,16 +94,18 @@ public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() {
MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory();
transportFactory.transport.setS2AContentMap(
ImmutableMap.of(
S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY,
SecureSessionAgent.S2A_PLAINTEXT_ADDRESS_JSON_KEY,
S2A_PLAINTEXT_ADDRESS,
S2A.S2A_MTLS_ADDRESS_JSON_KEY,
SecureSessionAgent.S2A_MTLS_ADDRESS_JSON_KEY,
S2A_MTLS_ADDRESS));
transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK);
transportFactory.transport.setEmptyContent(true);

S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build();
String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress();
String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress();
SecureSessionAgent s2aUtils =
SecureSessionAgent.newBuilder().setHttpTransportFactory(transportFactory).build();
SecureSessionAgentConfig config = s2aUtils.getConfig();
String plaintextS2AAddress = config.getPlaintextAddress();
String mtlsS2AAddress = config.getMtlsAddress();
assertTrue(plaintextS2AAddress.isEmpty());
assertTrue(mtlsS2AAddress.isEmpty());
}
Expand All @@ -111,13 +117,15 @@ public void getS2AAddress_queryEndpointResponseInvalidPlaintextJsonKey_plaintext
ImmutableMap.of(
INVALID_JSON_KEY,
S2A_PLAINTEXT_ADDRESS,
S2A.S2A_MTLS_ADDRESS_JSON_KEY,
SecureSessionAgent.S2A_MTLS_ADDRESS_JSON_KEY,
S2A_MTLS_ADDRESS));
transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK);

S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build();
String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress();
String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress();
SecureSessionAgent s2aUtils =
SecureSessionAgent.newBuilder().setHttpTransportFactory(transportFactory).build();
SecureSessionAgentConfig config = s2aUtils.getConfig();
String plaintextS2AAddress = config.getPlaintextAddress();
String mtlsS2AAddress = config.getMtlsAddress();
assertTrue(plaintextS2AAddress.isEmpty());
assertEquals(S2A_MTLS_ADDRESS, mtlsS2AAddress);
}
Expand All @@ -127,15 +135,17 @@ public void getS2AAddress_queryEndpointResponseInvalidMtlsJsonKey_mtlsEmptyAddre
MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory();
transportFactory.transport.setS2AContentMap(
ImmutableMap.of(
S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY,
SecureSessionAgent.S2A_PLAINTEXT_ADDRESS_JSON_KEY,
S2A_PLAINTEXT_ADDRESS,
INVALID_JSON_KEY,
S2A_MTLS_ADDRESS));
transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK);

S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build();
String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress();
String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress();
SecureSessionAgent s2aUtils =
SecureSessionAgent.newBuilder().setHttpTransportFactory(transportFactory).build();
SecureSessionAgentConfig config = s2aUtils.getConfig();
String plaintextS2AAddress = config.getPlaintextAddress();
String mtlsS2AAddress = config.getMtlsAddress();
assertEquals(S2A_PLAINTEXT_ADDRESS, plaintextS2AAddress);
assertTrue(mtlsS2AAddress.isEmpty());
}
Expand Down

0 comments on commit 18020fe

Please sign in to comment.