From 114f944faa23eb4293aaa5e3c672527dd67bfa9e Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 6 Jun 2024 12:08:26 +0200 Subject: [PATCH] Polishing. Refactor AuthenticationSteps creation into static factory method. Extend tests, add documentation. See gh-821 Original pull request: gh-853 --- .../authentication/GitHubAuthentication.java | 22 ++++++++-- .../GitHubAuthenticationOptions.java | 1 - .../GitHubAuthenticationIntegrationTest.java | 43 +++++++++++++++---- .../ROOT/pages/vault/authentication.adoc | 38 ++++++++++++++++ 4 files changed, 92 insertions(+), 12 deletions(-) diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/GitHubAuthentication.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/GitHubAuthentication.java index 197a5247..d6fdadaa 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/authentication/GitHubAuthentication.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/GitHubAuthentication.java @@ -16,8 +16,10 @@ package org.springframework.vault.authentication; import java.util.Map; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.util.Assert; import org.springframework.vault.VaultException; import org.springframework.vault.support.VaultResponse; @@ -30,6 +32,7 @@ import org.springframework.web.client.RestOperations; * personal access token. * * @author Nanne Baars + * @author Mark Paluch * @since 3.2 * @see GitHubAuthentication * @see RestOperations @@ -58,11 +61,24 @@ public class GitHubAuthentication implements ClientAuthentication, Authenticatio this.restOperations = restOperations; } + /** + * Creates a {@link AuthenticationSteps} for GitHub authentication given + * {@link GitHubAuthenticationOptions}. + * @param options must not be {@literal null}. + * @return {@link AuthenticationSteps} for github authentication. + */ + public static AuthenticationSteps createAuthenticationSteps(GitHubAuthenticationOptions options) { + + Assert.notNull(options, "GitHubAuthentication must not be null"); + + return AuthenticationSteps.fromSupplier(options.getTokenSupplier()) + .map(GitHubAuthentication::getGitHubLogin) + .login(AuthenticationUtil.getLoginPath(options.getPath())); + } + @Override public AuthenticationSteps getAuthenticationSteps() { - return AuthenticationSteps.fromSupplier(options.getTokenSupplier()) - .map(token -> getGitHubLogin(token)) - .login(AuthenticationUtil.getLoginPath(this.options.getPath())); + return createAuthenticationSteps(options); } @Override diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/GitHubAuthenticationOptions.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/GitHubAuthenticationOptions.java index 3edc0ba4..808e69d4 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/authentication/GitHubAuthenticationOptions.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/GitHubAuthenticationOptions.java @@ -27,7 +27,6 @@ import org.springframework.util.Assert; * Instances of this class are immutable once constructed. * * @author Nanne Baars - * @author Mark Paluch * @since 3.2 * @see GitHubAuthentication * @see #builder() diff --git a/spring-vault-core/src/test/java/org/springframework/vault/authentication/GitHubAuthenticationIntegrationTest.java b/spring-vault-core/src/test/java/org/springframework/vault/authentication/GitHubAuthenticationIntegrationTest.java index 5893afd7..52de704a 100644 --- a/spring-vault-core/src/test/java/org/springframework/vault/authentication/GitHubAuthenticationIntegrationTest.java +++ b/spring-vault-core/src/test/java/org/springframework/vault/authentication/GitHubAuthenticationIntegrationTest.java @@ -53,10 +53,13 @@ class GitHubAuthenticationIntegrationTest extends IntegrationTestSupport { prepare().mountAuth("github"); } - prepare().getVaultOperations() - .doWithSession( - restOperations -> restOperations.postForEntity("auth/github/config", Map.of("organization_id", 1, - "base_url", "http://localhost:%d".formatted(gitHubMockServer.getPort())), Map.class)); + gitHubMockServer.start(); + + prepare().getVaultOperations().doWithSession(restOperations -> { + Map config = Map.of("organization", "foo", "organization_id", "" + organizationId, + "base_url", "http://localhost:%d".formatted(gitHubMockServer.getPort())); + return restOperations.postForEntity("auth/github/config", config, Map.class); + }); } @AfterEach @@ -66,21 +69,45 @@ class GitHubAuthenticationIntegrationTest extends IntegrationTestSupport { @Test void shouldLoginSuccessfully() { + + GitHubAuthenticationOptions options = GitHubAuthenticationOptions.builder() + .tokenSupplier(() -> "TOKEN") + .build(); RestTemplate restTemplate = TestRestTemplateFactory.create(Settings.createSslConfiguration()); setupGithubMockServer(gitHubUserResponse(), gitHubOrganizationResponse(organizationId), gitHubTeamResponse(organizationId)); - GitHubAuthentication authentication = new GitHubAuthentication( - GitHubAuthenticationOptions.builder().tokenSupplier(() -> "TOKEN").build(), restTemplate); + GitHubAuthentication authentication = new GitHubAuthentication(options, restTemplate); VaultToken loginToken = authentication.login(); assertThat(loginToken.getToken()).isNotNull(); } @Test - void shouldFailIfOrganizationIsNotTheSame() { + void shouldLoginUsingAuthenticationSteps() { + + GitHubAuthenticationOptions options = GitHubAuthenticationOptions.builder() + .tokenSupplier(() -> "TOKEN") + .build(); RestTemplate restTemplate = TestRestTemplateFactory.create(Settings.createSslConfiguration()); - var wrongOrganizationId = organizationId + 1; + setupGithubMockServer(gitHubUserResponse(), gitHubOrganizationResponse(organizationId), + gitHubTeamResponse(organizationId)); + + AuthenticationSteps steps = GitHubAuthentication.createAuthenticationSteps(options); + + AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, restTemplate); + VaultToken loginToken = executor.login(); + + assertThat(loginToken.getToken()).isNotNull(); + } + + @Test + void shouldFailIfOrganizationIsNotTheSame() { + + RestTemplate restTemplate = TestRestTemplateFactory.create(Settings.createSslConfiguration()); + + int wrongOrganizationId = organizationId + 1; + setupGithubMockServer(gitHubUserResponse(), gitHubOrganizationResponse(wrongOrganizationId), gitHubTeamResponse(wrongOrganizationId)); diff --git a/src/main/antora/modules/ROOT/pages/vault/authentication.adoc b/src/main/antora/modules/ROOT/pages/vault/authentication.adoc index 3b9f3439..35d76fd1 100644 --- a/src/main/antora/modules/ROOT/pages/vault/authentication.adoc +++ b/src/main/antora/modules/ROOT/pages/vault/authentication.adoc @@ -537,6 +537,44 @@ See also: * https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signJwt * https://cloud.google.com/iam/docs/reference/rest/v1/projects.serviceAccounts/signJwt (deprecated) +[[vault.authentication.github]] +== GitHub Authentication + +The https://www.vaultproject.io/docs/auth/github.html[github] +auth backend provides an authentication mechanism based on GitHub tokens. +Vault does not support an OAuth workflow to generate GitHub tokens, +so it does not act as a GitHub application. + +The authentication mechanism requires a GitHub token (or a supplier) +to pass on the token to Vault which then authenticates against your GitHub +account. + +==== +[source,java] +---- +@Configuration +class AppConfig extends AbstractVaultConfiguration { + + // … + + @Override + public ClientAuthentication clientAuthentication() { + + GitHubAuthentication options = GitHubAuthentication.builder() + .token(…).build(); + + return new GitHubAuthentication(options, restOperations()); + } + + // … +} +---- +==== + +See also: + +* https://www.vaultproject.io/api-docs/auth/github[Vault Documentation: GitHub auth method] + [[vault.authentication.pcf]] == PCF authentication