Skip to content

Commit

Permalink
Update oidc provider detection
Browse files Browse the repository at this point in the history
Signed-off-by: Appu Goundan <[email protected]>
  • Loading branch information
loosebazooka committed Apr 11, 2024
1 parent 8bd98de commit 004d01c
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import dev.sigstore.oidc.client.OidcException;
import dev.sigstore.oidc.client.OidcToken;
import java.io.IOException;
import java.util.Map;

public class TokenStringOidcClient implements OidcClient {

Expand All @@ -32,12 +33,12 @@ public TokenStringOidcClient(String idToken) {
}

@Override
public boolean isEnabled() {
public boolean isEnabled(Map<String, String> env) {
return true;
}

@Override
public OidcToken getIDToken() throws OidcException {
public OidcToken getIDToken(Map<String, String> env) throws OidcException {
try {
var jws = JsonWebSignature.parse(new GsonFactory(), idToken);
return ImmutableOidcToken.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
import dev.sigstore.fulcio.v2.CertificateChain;
import dev.sigstore.fulcio.v2.CreateSigningCertificateRequest;
import dev.sigstore.fulcio.v2.Credentials;
import dev.sigstore.fulcio.v2.GetTrustBundleRequest;
import dev.sigstore.fulcio.v2.PublicKey;
import dev.sigstore.fulcio.v2.PublicKeyRequest;
import dev.sigstore.fulcio.v2.TrustBundle;
import dev.sigstore.http.GrpcChannels;
import dev.sigstore.http.HttpParams;
import dev.sigstore.http.ImmutableHttpParams;
Expand Down Expand Up @@ -80,6 +82,15 @@ public FulcioClient build() {
}
}

public TrustBundle trustBundle() throws Exception {
var channel = GrpcChannels.newManagedChannel(uri.getAuthority(), httpParams);
try {
var client = CAGrpc.newBlockingStub(channel);
return client.getTrustBundle(GetTrustBundleRequest.newBuilder().build());
} finally {
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}
}
/**
* Request a signing certificate from fulcio.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import dev.sigstore.http.ImmutableHttpParams;
import io.grpc.Internal;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Logger;

/**
Expand All @@ -35,9 +36,9 @@ public class GithubActionsOidcClient implements OidcClient {

private static final Logger log = Logger.getLogger(GithubActionsOidcClient.class.getName());

private static final String GITHUB_ACTIONS_KEY = "GITHUB_ACTIONS";
private static final String REQUEST_TOKEN_KEY = "ACTIONS_ID_TOKEN_REQUEST_TOKEN";
private static final String REQUEST_URL_KEY = "ACTIONS_ID_TOKEN_REQUEST_URL";
static final String GITHUB_ACTIONS_KEY = "GITHUB_ACTIONS";
static final String REQUEST_TOKEN_KEY = "ACTIONS_ID_TOKEN_REQUEST_TOKEN";
static final String REQUEST_URL_KEY = "ACTIONS_ID_TOKEN_REQUEST_URL";

private static final String DEFAULT_AUDIENCE = "sigstore";

Expand Down Expand Up @@ -75,19 +76,25 @@ public GithubActionsOidcClient build() {
}

@Override
public boolean isEnabled() {
var githubActions = System.getenv(GITHUB_ACTIONS_KEY);
public boolean isEnabled(Map<String, String> env) {
var githubActions = env.get(GITHUB_ACTIONS_KEY);
if (githubActions == null || githubActions.isEmpty()) {
log.fine("Github env not detected: skipping github actions oidc");
return false;
}
var bearer = env.get(REQUEST_TOKEN_KEY);
var urlBase = env.get(REQUEST_URL_KEY);
if (bearer == null || bearer.isEmpty() || urlBase == null || urlBase.isEmpty()) {
log.info("Github env detected, but github idtoken not found: skipping github actions oidc");
return false;
}
return true;
}

@Override
public OidcToken getIDToken() throws OidcException {
var bearer = System.getenv(REQUEST_TOKEN_KEY);
var urlBase = System.getenv(REQUEST_URL_KEY);
public OidcToken getIDToken(Map<String, String> env) throws OidcException {
var bearer = env.get(REQUEST_TOKEN_KEY);
var urlBase = env.get(REQUEST_URL_KEY);
if (bearer == null) {
throw new OidcException(
"Could not get github actions environment variable '" + REQUEST_TOKEN_KEY + "'");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@
*/
package dev.sigstore.oidc.client;

import java.util.Map;

public interface OidcClient {

/**
* Determine if this client can be used in the current environment. For example, we can ignore
* Oidc Clients that are scoped to a specific CI environment
*
* @param env the configured system environment
* @return true if we should use credentials from this client
*/
boolean isEnabled();
boolean isEnabled(Map<String, String> env);

OidcToken getIDToken() throws OidcException;
OidcToken getIDToken(Map<String, String> env) throws OidcException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
package dev.sigstore.oidc.client;

import com.google.common.collect.ImmutableList;
import java.util.Map;
import java.util.logging.Logger;

/** An ordered list of oidc clients to use when looking for credentials. */
public class OidcClients {

private static final Logger log = Logger.getLogger(OidcClients.class.getName());

public static final OidcClients PUBLIC_GOOD =
of(GithubActionsOidcClient.builder().build(), WebOidcClient.builder().build());

Expand All @@ -29,13 +33,15 @@ public class OidcClients {
WebOidcClient.builder().setIssuer(WebOidcClient.STAGING_DEX_ISSUER).build());

private final ImmutableList<OidcClient> clients;
private final Map<String, String> env;

public static OidcClients of(OidcClient... clients) {
return new OidcClients(ImmutableList.copyOf(clients));
return new OidcClients(ImmutableList.copyOf(clients), System.getenv());
}

private OidcClients(ImmutableList<OidcClient> clients) {
private OidcClients(ImmutableList<OidcClient> clients, Map<String, String> env) {
this.clients = clients;
this.env = env;
}

/**
Expand All @@ -47,10 +53,12 @@ private OidcClients(ImmutableList<OidcClient> clients) {
*/
public OidcToken getIDToken() throws OidcException {
for (var client : clients) {
if (client.isEnabled()) {
return client.getIDToken();
if (client.isEnabled(env)) {
return client.getIDToken(env);
}
}
log.info(
"Could not find an oidc provider, if you are in CI make sure the token is available to the sigstore signing process");
throw new OidcException("Could not find an oidc provider");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Logger;

/**
* A client to obtain oidc tokens from an oauth provider via web workflow for use with sigstore. By
* default this client is configued to use the public sigstore dex instance.
*/
public class WebOidcClient implements OidcClient {
private static final Logger log = Logger.getLogger(WebOidcClient.class.getName());

public static final String PUBLIC_DEX_ISSUER = "https://oauth2.sigstore.dev/auth";
public static final String STAGING_DEX_ISSUER = "https://oauth2.sigstage.dev/auth";

Expand Down Expand Up @@ -112,12 +116,13 @@ public WebOidcClient build() {
}
}

/**
* This provider is always enabled by default, however it should be lower priority over other
* providers which obtain ambient credentials.
*/
/** This provider is usually enabled unless we're in CI. */
@Override
public boolean isEnabled() {
public boolean isEnabled(Map<String, String> env) {
if ("true".equalsIgnoreCase(env.get("CI"))) {
log.info("Skipping browser based oidc provider because CI detected");
return false;
}
return true;
}

Expand All @@ -128,7 +133,7 @@ public boolean isEnabled() {
* @throws OidcException if an error occurs doing the authorization flow
*/
@Override
public OidcToken getIDToken() throws OidcException {
public OidcToken getIDToken(Map<String, String> env) throws OidcException {
JsonFactory jsonFactory = new GsonFactory();
HttpTransport httpTransport = HttpClients.newHttpTransport(httpParams);
DataStoreFactory memStoreFactory = new MemoryDataStoreFactory();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ public void sign_passGithubOidcCheck() throws Exception {
// silly way to get the right oidc identity to make sure our simple matcher works
var jws =
JsonWebSignature.parse(
new GsonFactory(), GithubActionsOidcClient.builder().build().getIDToken().getIdToken());
new GsonFactory(),
GithubActionsOidcClient.builder().build().getIDToken(System.getenv()).getIdToken());
var expectedGithubSubject = jws.getPayload().getSubject();
var signer =
KeylessSigner.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,56 @@

import dev.sigstore.testkit.annotations.EnabledIfOidcExists;
import dev.sigstore.testkit.annotations.OidcProviderType;
import io.github.netmikey.logunit.api.LogCapturer;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.slf4j.event.Level;

public class GithubActionsOidcClientTest {

@RegisterExtension
LogCapturer logs =
LogCapturer.create().captureForType(GithubActionsOidcClient.class, Level.DEBUG);

@Test
@EnabledIfOidcExists(provider = OidcProviderType.GITHUB)
public void getToken() throws OidcException {
var client = GithubActionsOidcClient.builder().build();
var token = client.getIDToken();
var token = client.getIDToken(System.getenv());

Assertions.assertNotNull(token.getSubjectAlternativeName());
Assertions.assertNotNull(token.getIdToken());
}

@Test
public void isEnabled_github() {
var client = GithubActionsOidcClient.builder().build();
var env =
Map.of(
GithubActionsOidcClient.GITHUB_ACTIONS_KEY,
"ignored",
GithubActionsOidcClient.REQUEST_TOKEN_KEY,
"ignored",
GithubActionsOidcClient.REQUEST_URL_KEY,
"ignored");
Assertions.assertTrue(client.isEnabled(env));
}

@Test
public void isEnabled_githubButNoTokenInfo() {
var client = GithubActionsOidcClient.builder().build();
var env = Map.of(GithubActionsOidcClient.GITHUB_ACTIONS_KEY, "ignored");
Assertions.assertFalse(client.isEnabled(env));
logs.assertContains(
"Github env detected, but github idtoken not found: skipping github actions oidc");
}

@Test
public void isEnabled_notGithub() {
var client = GithubActionsOidcClient.builder().build();
Assertions.assertFalse(client.isEnabled(Map.of()));
logs.assertContains("Github env not detected: skipping github actions oidc");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,21 @@

import com.gargoylesoftware.htmlunit.WebClient;
import dev.sigstore.testing.MockOAuth2ServerExtension;
import io.github.netmikey.logunit.api.LogCapturer;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.slf4j.event.Level;

public class WebOidcClientTest {

@RegisterExtension
private static final MockOAuth2ServerExtension server = new MockOAuth2ServerExtension();

@RegisterExtension
LogCapturer logs = LogCapturer.create().captureForType(WebOidcClient.class, Level.DEBUG);

@Test
public void testAuthFlow() throws OidcException {
try (var webClient = new WebClient()) {
Expand All @@ -35,9 +41,22 @@ public void testAuthFlow() throws OidcException {
.setBrowser(webClient::getPage)
.build();

var eid = oidcClient.getIDToken();
var eid = oidcClient.getIDToken(System.getenv());
Assertions.assertEquals(
MockOAuth2ServerExtension.DEFAULT_CONFIGURED_EMAIL, eid.getSubjectAlternativeName());
}
}

@Test
public void isEnabled_CI() {
var client = WebOidcClient.builder().build();
Assertions.assertFalse(client.isEnabled(Map.of("CI", "true")));
logs.assertContains("Skipping browser based oidc provider because CI detected");
}

@Test
public void isEnabled_notCI() {
var client = WebOidcClient.builder().build();
Assertions.assertTrue(client.isEnabled(Map.of("CI", "false")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public OidcToken getOidcToken() throws OidcException {
.setBrowser(webClient::getPage)
.build();

return oidcClient.getIDToken();
return oidcClient.getIDToken(System.getenv());
}
}

Expand Down

0 comments on commit 004d01c

Please sign in to comment.