Polishing.

Convert space to tab indentation. Rename Gcp…Provider to Gcp…Accessor. Merge default implementation of accessors into DefaultGcpCredentialAccessors enum. Reduce builder method visibility of accessor configuration methods to expose fewer public methods. Javadoc, formatting, extract methods.

Original pull request: gh-287.
See gh-261
This commit is contained in:
Mark Paluch
2018-09-03 11:08:59 +02:00
parent 41645f1034
commit 481431593e
8 changed files with 233 additions and 185 deletions

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.vault.authentication;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Default implementation of{@link GcpProjectIdAccessor} and
* {@link GcpServiceAccountIdAccessor}. Used by {@link GcpIamAuthentication}.
*
* @author Magnus Jungsbluth
* @author Mark Paluch
* @since 2.1
* @see GcpIamAuthentication
*/
enum DefaultGcpCredentialAccessors implements GcpProjectIdAccessor,
GcpServiceAccountIdAccessor {
INSTANCE;
/**
* Get a the service account id (email) to be placed in the signed JWT.
*
* @param credential credential object to obtain the service account id from.
* @return the service account id to use.
*/
@Override
public String getServiceAccountId(GoogleCredential credential) {
Assert.notNull(credential, "GoogleCredential must not be null");
Assert.notNull(
credential.getServiceAccountId(),
"The configured GoogleCredential does not represent a service account. Configure the service account id with GcpIamAuthenticationOptionsBuilder#serviceAccountId(String).");
return credential.getServiceAccountId();
}
/**
* Get a the GCP project id to used in Google Cloud IAM API calls.
*
* @param credential the credential object to obtain the project id from.
* @return the service account id to use.
*/
@Override
public String getProjectId(GoogleCredential credential) {
Assert.notNull(credential, "GoogleCredential must not be null");
return StringUtils.isEmpty(credential.getServiceAccountProjectId()) ? "-"
: credential.getServiceAccountProjectId();
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.vault.authentication;
import org.springframework.util.StringUtils;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
/**
* Default implementation to obtain a GCP project id for GCP IAM authentication.
* Used by {@link GcpIamAuthentication}.
*
* @author Magnus Jungsbluth
* @since 2.1
* @see GcpIamAuthentication
*/
public class DefaultGcpProjectIdProvider implements GcpProjectIdProvider {
@Override
public String getProjectId(GoogleCredential credential) {
if (StringUtils.isEmpty(credential.getServiceAccountProjectId())) {
return "-";
} else {
return credential.getServiceAccountProjectId();
}
}
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.vault.authentication;
import org.springframework.util.Assert;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
/**
* Default implementation to obtain a service account id for GCP IAM authentication.
* Used by {@link GcpIamAuthentication}.
*
* @author Magnus Jungsbluth
* @since 2.1
* @see GcpIamAuthentication
*/
public class DefaultGcpServiceAccountIdProvider implements GcpServiceAccountIdProvider {
@Override
public String getServiceAccountId(GoogleCredential credential) {
Assert.notNull(credential.getServiceAccountId(), "The configured GoogleCredential does not represent a service account. Configure the service account id manually");
return credential.getServiceAccountId();
}
}

View File

@@ -50,6 +50,7 @@ import org.springframework.web.client.RestOperations;
* {@link GcpIamAuthentication} uses Google Java API that uses synchronous API.
*
* @author Mark Paluch
* @author Magnus Jungsbluth
* @since 2.1
* @see GcpIamAuthenticationOptions
* @see HttpTransport
@@ -125,8 +126,8 @@ public class GcpIamAuthentication extends GcpJwtAuthenticationSupport implements
protected String signJwt() {
String projectId = options.getProjectIdProvider().getProjectId(credential);
String serviceAccount = options.getServiceAccountIdProvider().getServiceAccountId(credential);
String projectId = getProjectId();
String serviceAccount = getServiceAccountId();
Map<String, Object> jwtPayload = getJwtPayload(options, serviceAccount);
Iam iam = new Builder(httpTransport, JSON_FACTORY, credential)
@@ -154,6 +155,14 @@ public class GcpIamAuthentication extends GcpJwtAuthenticationSupport implements
}
}
private String getServiceAccountId() {
return options.getServiceAccountIdAccessor().getServiceAccountId(credential);
}
private String getProjectId() {
return options.getProjectIdAccessor().getProjectId(credential);
}
private static Map<String, Object> getJwtPayload(GcpIamAuthenticationOptions options,
String serviceAccount) {

View File

@@ -32,6 +32,7 @@ import org.springframework.util.Assert;
* constructed.
*
* @author Mark Paluch
* @author Magnus Jungsbluth
* @see GcpIamAuthentication
* @see #builder()
* @since 2.1
@@ -65,26 +66,27 @@ public class GcpIamAuthenticationOptions {
private final Clock clock;
/**
* Provide the service account id to use as sub/iss claims
* Provide the service account id to use as sub/iss claims.
*/
private final GcpServiceAccountIdProvider serviceAccountIdSupplier;
private final GcpServiceAccountIdAccessor serviceAccountIdAccessor;
/**
* The GCP project id to use in GCP IAM API calls
* The GCP project id to use in GCP IAM API calls.
*/
private final GcpProjectIdProvider projectIdSupplier;
private final GcpProjectIdAccessor projectIdAccessor;
private GcpIamAuthenticationOptions(String path,
GcpCredentialSupplier credentialSupplier, String role, Duration jwtValidity,
Clock clock, GcpServiceAccountIdProvider serviceAccountIdSupplier, GcpProjectIdProvider projectIdSupplier) {
Clock clock, GcpServiceAccountIdAccessor serviceAccountIdSupplier,
GcpProjectIdAccessor projectIdAccessor) {
this.path = path;
this.credentialSupplier = credentialSupplier;
this.role = role;
this.jwtValidity = jwtValidity;
this.clock = clock;
this.serviceAccountIdSupplier = serviceAccountIdSupplier;
this.projectIdSupplier = projectIdSupplier;
this.serviceAccountIdAccessor = serviceAccountIdSupplier;
this.projectIdAccessor = projectIdAccessor;
}
/**
@@ -130,17 +132,19 @@ public class GcpIamAuthenticationOptions {
}
/**
* Provide the service account id to use as sub/iss claims
* @return the service account id to use as sub/iss claims.
* @since 2.1
*/
public GcpServiceAccountIdProvider getServiceAccountIdProvider() {
return serviceAccountIdSupplier;
public GcpServiceAccountIdAccessor getServiceAccountIdAccessor() {
return serviceAccountIdAccessor;
}
/**
* The GCP project id to use in GCP IAM API calls
* @return GCP project id accessor to obtain the project id of GCP IAM API calls.
* @since 2.1
*/
public GcpProjectIdProvider getProjectIdProvider() {
return projectIdSupplier;
public GcpProjectIdAccessor getProjectIdAccessor() {
return projectIdAccessor;
}
/**
@@ -160,9 +164,9 @@ public class GcpIamAuthenticationOptions {
private Clock clock = Clock.systemDefaultZone();
private GcpServiceAccountIdProvider serviceAccountIdProvider = new DefaultGcpServiceAccountIdProvider();
private GcpServiceAccountIdAccessor serviceAccountIdAccessor = DefaultGcpCredentialAccessors.INSTANCE;
private GcpProjectIdProvider projectIdProvider = new DefaultGcpProjectIdProvider();
private GcpProjectIdAccessor projectIdAccessor = DefaultGcpCredentialAccessors.INSTANCE;
GcpIamAuthenticationOptionsBuilder() {
}
@@ -198,7 +202,7 @@ public class GcpIamAuthenticationOptions {
}
/**
* Configure an {@link GcpCredentialSupplier}, required to create a signed JWT.
* Configure a {@link GcpCredentialSupplier}, required to create a signed JWT.
* Alternatively, configure static {@link #credential(GoogleCredential)
* credentials}.
*
@@ -216,57 +220,72 @@ public class GcpIamAuthenticationOptions {
}
/**
* Configure an explicit service account id to use in GCP IAM calls. If none is configured, falls back to using
* {@link GoogleCredential#getServiceAccountId()}.
* Configure an explicit service account id to use in GCP IAM calls. If none is
* configured, falls back to using {@link GoogleCredential#getServiceAccountId()}.
*
* @param serviceAccountId the service account id (email) to use
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
* @since 2.1
*/
public GcpIamAuthenticationOptionsBuilder serviceAccountId(String serviceAccountId) {
Assert.notNull(serviceAccountId, "Service account id may not be null");
return serviceAccountIdProvider((GoogleCredential credential) -> serviceAccountId);
return serviceAccountIdAccessor((GoogleCredential credential) -> serviceAccountId);
}
/**
* Configure an {@link GcpServiceAccountIdProvider} to obtain the service account id used in GCP IAM calls.
* If none is configured, falls back to using {@link GoogleCredential#getServiceAccountId()}.
* Configure an {@link GcpServiceAccountIdAccessor} to obtain the service account
* id used in GCP IAM calls. If none is configured, falls back to using
* {@link GoogleCredential#getServiceAccountId()}.
*
* @param serviceAccountIdProvider the service account id provider to use
* @param serviceAccountIdAccessor the service account id provider to use
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
* @see GcpServiceAccountIdProvider
* @see GcpServiceAccountIdAccessor
* @since 2.1
*/
public GcpIamAuthenticationOptionsBuilder serviceAccountIdProvider(GcpServiceAccountIdProvider serviceAccountIdProvider) {
Assert.notNull(serviceAccountIdProvider, "GcpServiceAccountIdProvider must not be null");
GcpIamAuthenticationOptionsBuilder serviceAccountIdAccessor(
GcpServiceAccountIdAccessor serviceAccountIdAccessor) {
this.serviceAccountIdProvider = serviceAccountIdProvider;
Assert.notNull(serviceAccountIdAccessor,
"GcpServiceAccountIdAccessor must not be null");
this.serviceAccountIdAccessor = serviceAccountIdAccessor;
return this;
}
/**
* Configure an explicit GCP project id to use in GCP IAM API calls. If none is configured, falls back using
* Configure an explicit GCP project id to use in GCP IAM API calls. If none is
* configured, falls back using
* {@link GoogleCredential#getServiceAccountProjectId()}.
*
* @param projectId the GCP project id to use in GCP IAM API calls
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
* @since 2.1
*/
public GcpIamAuthenticationOptionsBuilder projectId(String projectId) {
Assert.notNull(projectId, "GCP project id must not be null");
return projectIdProvider((GoogleCredential credential) -> projectId);
return projectIdAccessor((GoogleCredential credential) -> projectId);
}
/**
* Configure an {@link GcpProjectIdProvider} to use in GCP IAM API calls. If none is configured, falls back using
* Configure an {@link GcpProjectIdAccessor} to use in GCP IAM API calls. If none
* is configured, falls back using
* {@link GoogleCredential#getServiceAccountProjectId()}.
*
* @param projectIdProvider the GCP project id supplier to use in GCP IAM API calls
* @param projectIdAccessor the GCP project id supplier to use in GCP IAM API
* calls
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
* @since 2.1
*/
public GcpIamAuthenticationOptionsBuilder projectIdProvider(GcpProjectIdProvider projectIdProvider) {
Assert.notNull(projectIdProvider, "GcpProjectIdProvider must not be null");
GcpIamAuthenticationOptionsBuilder projectIdAccessor(
GcpProjectIdAccessor projectIdAccessor) {
this.projectIdProvider = projectIdProvider;
Assert.notNull(projectIdAccessor, "GcpProjectIdAccessor must not be null");
this.projectIdAccessor = projectIdAccessor;
return this;
}
@@ -325,7 +344,7 @@ public class GcpIamAuthenticationOptions {
Assert.notNull(role, "Role must not be null");
return new GcpIamAuthenticationOptions(path, credentialSupplier, role,
jwtValidity, clock, serviceAccountIdProvider, projectIdProvider);
jwtValidity, clock, serviceAccountIdAccessor, projectIdAccessor);
}
}
}

View File

@@ -18,19 +18,21 @@ package org.springframework.vault.authentication;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
/**
* Interface to obtain a GCP project id for GCP IAM authentication.
* Implementations are used by {@link GcpIamAuthentication}.
* Interface to obtain a GCP project id for GCP IAM authentication. Implementations are
* used by {@link GcpIamAuthentication}.
*
* @author Magnus Jungsbluth
* @author Mark Paluch
* @since 2.1
* @see GcpIamAuthentication
*/
@FunctionalInterface
public interface GcpProjectIdProvider {
public interface GcpProjectIdAccessor {
/**
* Get a the GCP project id to used in Google Cloud IAM API calls.
*
* @param credential the credential object to obtain the project id from.
* @return the service account id to use.
*/
String getProjectId(GoogleCredential credential);

View File

@@ -26,11 +26,12 @@ import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
* @see GcpIamAuthentication
*/
@FunctionalInterface
public interface GcpServiceAccountIdProvider {
public interface GcpServiceAccountIdAccessor {
/**
* Get a the service account id (email) to be placed in the signed JWT.
*
* @param credential credential object to obtain the service account id from.
* @return the service account id to use.
*/
String getServiceAccountId(GoogleCredential credential);

View File

@@ -1,96 +1,124 @@
/*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.vault.authentication;
import java.security.PrivateKey;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import java.security.PrivateKey;
import org.junit.Test;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
/**
* Unit tests for {@link GcpIamAuthenticationOptions.GcpIamAuthenticationOptionsBuilder}
* Unit tests for {@link GcpIamAuthenticationOptions}.
*
* @author Magnus Jungsbluth
*/
public class GcpIamAuthenticationOptionsBuilderUnitTests {
private GoogleCredential createGoogleCredential() {
GoogleCredential credential = new GoogleCredential.Builder().setServiceAccountId("hello@world")
.setServiceAccountProjectId("foobar")
.setServiceAccountPrivateKey(mock(PrivateKey.class))
.setServiceAccountPrivateKeyId("key-id").build();
credential.setAccessToken("foobar");
return credential;
}
@Test
public void shouldDefaultToCredentialServiceAccountId() {
GoogleCredential credential = createGoogleCredential();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential)
.role("foo")
.build();
assertThat(options.getServiceAccountIdProvider().getServiceAccountId(credential)).isEqualTo("hello@world");
GoogleCredential credential = createGoogleCredential();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential).role("foo").build();
assertThat(options.getServiceAccountIdAccessor().getServiceAccountId(credential))
.isEqualTo("hello@world");
}
@Test
public void shouldAllowServiceAccountIdOverride() {
GoogleCredential credential = createGoogleCredential();
GoogleCredential credential = createGoogleCredential();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential)
.serviceAccountId("override@foo.com")
.role("foo")
.credential(credential).serviceAccountId("override@foo.com").role("foo")
.build();
assertThat(options.getServiceAccountIdProvider().getServiceAccountId(credential)).isEqualTo("override@foo.com");
assertThat(options.getServiceAccountIdAccessor().getServiceAccountId(credential))
.isEqualTo("override@foo.com");
}
@Test
public void shouldAllowServiceAccountIdProviderOverride() {
GoogleCredential credential = createGoogleCredential();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential)
.serviceAccountIdProvider((GoogleCredential googleCredential) -> "override@foo.com")
.role("foo")
.build();
@Test
public void shouldAllowServiceAccountIdProviderOverride() {
assertThat(options.getServiceAccountIdProvider().getServiceAccountId(credential)).isEqualTo("override@foo.com");
}
GoogleCredential credential = createGoogleCredential();
@Test
public void shouldDefaultToCredentialProjectId() {
GoogleCredential credential = createGoogleCredential();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential)
.role("foo")
.build();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions
.builder()
.credential(credential)
.serviceAccountIdAccessor(
(GoogleCredential googleCredential) -> "override@foo.com")
.role("foo").build();
assertThat(options.getProjectIdProvider().getProjectId(credential)).isEqualTo("foobar");
}
assertThat(options.getServiceAccountIdAccessor().getServiceAccountId(credential))
.isEqualTo("override@foo.com");
}
@Test
public void shouldAllowProjectIdOverride() {
GoogleCredential credential = createGoogleCredential();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential)
.projectId("my-project")
.role("foo")
.build();
@Test
public void shouldDefaultToCredentialProjectId() {
assertThat(options.getProjectIdProvider().getProjectId(credential)).isEqualTo("my-project");
}
GoogleCredential credential = createGoogleCredential();
@Test
public void shouldAllowProjectIdProviderOverride() {
GoogleCredential credential = createGoogleCredential();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential)
.projectIdProvider((GoogleCredential googleCredential) -> "my-project")
.role("foo")
.build();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential).role("foo").build();
assertThat(options.getProjectIdProvider().getProjectId(credential)).isEqualTo("my-project");
}
assertThat(options.getProjectIdAccessor().getProjectId(credential)).isEqualTo(
"project-id");
}
@Test
public void shouldAllowProjectIdOverride() {
GoogleCredential credential = createGoogleCredential();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential).projectId("my-project").role("foo").build();
assertThat(options.getProjectIdAccessor().getProjectId(credential)).isEqualTo(
"my-project");
}
@Test
public void shouldAllowProjectIdProviderOverride() {
GoogleCredential credential = createGoogleCredential();
GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
.credential(credential)
.projectIdAccessor((GoogleCredential googleCredential) -> "my-project")
.role("foo").build();
assertThat(options.getProjectIdAccessor().getProjectId(credential)).isEqualTo(
"my-project");
}
private static GoogleCredential createGoogleCredential() {
GoogleCredential credential = new GoogleCredential.Builder()
.setServiceAccountId("hello@world")
.setServiceAccountProjectId("project-id")
.setServiceAccountPrivateKey(mock(PrivateKey.class))
.setServiceAccountPrivateKeyId("key-id").build();
credential.setAccessToken("foobar");
return credential;
}
}