From d9e960fffa91a71ffcc940535db59f32e56fc085 Mon Sep 17 00:00:00 2001 From: chaosinthecrd Date: Thu, 7 Dec 2023 15:44:29 +0000 Subject: [PATCH] updated to add token path flag and remove idToken function magic Signed-off-by: chaosinthecrd --- hack/test.token | 2 +- signer/fulcio/fulcio.go | 52 ++++++++++++++++++++++-------------- signer/fulcio/fulcio_test.go | 50 +++++++++++++--------------------- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/hack/test.token b/hack/test.token index 43eed6d1..fbcb3807 100644 --- a/hack/test.token +++ b/hack/test.token @@ -1 +1 @@ -eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJhYmNkMTIzIiwiZXhwaXJ5IjoxNjQ2NjM1NjExMzAxfQ.3Thp81rDFrKXr3WrY1MyMnNK8kKoZBX9lg-JwFznR-M +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb29iYXIiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjIsIkVtYWlsIjoidGVzdEBpbi10b3RvLmlvIn0.IswtNc6aJL3zAf-lSGvuz7Okf2tBr-I3ulJ_SRUMt0k diff --git a/signer/fulcio/fulcio.go b/signer/fulcio/fulcio.go index f0cd93cb..8bef1e4d 100644 --- a/signer/fulcio/fulcio.go +++ b/signer/fulcio/fulcio.go @@ -93,7 +93,7 @@ func init() { ), registry.StringConfigOption( "token", - "Raw token to use for authentication. The token or a path to the file containing the token is accepted", + "Raw token string to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token-path)", "", func(sp signer.SignerProvider, token string) (signer.SignerProvider, error) { fsp, ok := sp.(FulcioSignerProvider) @@ -105,6 +105,20 @@ func init() { return fsp, nil }, ), + registry.StringConfigOption( + "token-path", + "Path to the file containing a raw token to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token)", + "", + func(sp signer.SignerProvider, tokenPath string) (signer.SignerProvider, error) { + fsp, ok := sp.(FulcioSignerProvider) + if !ok { + return sp, fmt.Errorf("provided signer provider is not a fulcio signer provider") + } + + WithTokenPath(tokenPath)(&fsp) + return fsp, nil + }, + ), ) } @@ -113,6 +127,7 @@ type FulcioSignerProvider struct { OidcIssuer string OidcClientID string Token string + TokenPath string } type Option func(*FulcioSignerProvider) @@ -141,6 +156,12 @@ func WithToken(tokenOption string) Option { } } +func WithTokenPath(tokenPathOption string) Option { + return func(fsp *FulcioSignerProvider) { + fsp.TokenPath = tokenPathOption + } +} + func New(opts ...Option) FulcioSignerProvider { fsp := FulcioSignerProvider{} for _, opt := range opts { @@ -210,13 +231,18 @@ func (fsp FulcioSignerProvider) Signer(ctx context.Context) (cryptoutil.Signer, return nil, err } - case fsp.Token != "": - // reading from file if a path was supplied - raw, err = idToken(fsp.Token) + // we want to fail if both flags used (they're mutually exclusive) + case fsp.TokenPath != "" && fsp.Token != "": + return nil, errors.New("only one of --fulcio-token-path or --fulcio-raw-token can be used") + case fsp.Token != "" && fsp.TokenPath == "": + raw = fsp.Token + case fsp.TokenPath != "" && fsp.Token == "": + f, err := os.ReadFile(fsp.TokenPath) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to read fulcio token from filepath %s: %w", fsp.TokenPath, err) } + raw = string(f) case fsp.Token == "" && isatty.IsTerminal(os.Stdin.Fd()): tok, err := oauthflow.OIDConnect(fsp.OidcIssuer, fsp.OidcClientID, "", "", oauthflow.DefaultIDTokenGetter) if err != nil { @@ -285,7 +311,7 @@ func (fsp FulcioSignerProvider) Signer(ctx context.Context) (cryptoutil.Signer, func getCert(ctx context.Context, key *rsa.PrivateKey, fc fulciopb.CAClient, token string) (*fulciopb.SigningCertificate, error) { t, err := jwt.ParseSigned(token) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to parse jwt token for fulcio: %w", err) } var claims struct { @@ -407,17 +433,3 @@ func newClient(ctx context.Context, fulcioURL string, fulcioPort int, isInsecure // Create the Fulcio client return fulciopb.NewCAClient(conn), nil } - -// idToken tries to parse a string as a token in JWS form. If it fails, -// it treats the string as a path and tries to open the file at that path -func idToken(s string) (string, error) { - // If this is a valid raw token, just return it - // NOTE: could be replaced with https://pkg.go.dev/go.step.sm/crypto/jose in future if features helpful - if _, err := jwt.ParseSigned(s); err == nil { - return s, nil - } - - // Otherwise, if this is a path to a token return the contents - c, err := os.ReadFile(s) - return string(c), err -} diff --git a/signer/fulcio/fulcio_test.go b/signer/fulcio/fulcio_test.go index bbfa65c9..435ab5b7 100644 --- a/signer/fulcio/fulcio_test.go +++ b/signer/fulcio/fulcio_test.go @@ -78,37 +78,6 @@ func TestNewClient(t *testing.T) { require.NotNil(t, client) } -func TestIDToken(t *testing.T) { - // test when supplying a raw token, the same token is returned - tok := generateTestToken("test@example.com", "testsubject") - out, err := idToken(tok) - require.NoError(t, err) - require.Equal(t, tok, out) - - // test when supplying a path, a valid token is returned - // NOTE: this function could be refactored to accept a fileSystem or io.Reader so reading the file can be mocked, - // but unsure if this is the way we want to go for now - wd, err := os.Getwd() - if err != nil { - t.Fatalf("failed to get working directory: %v", err) - } - rootDir := filepath.Dir(filepath.Dir(wd)) - tok = filepath.Join(rootDir, "hack", "test.token") - testTok, err := os.ReadFile(tok) - if err != nil { - t.Fatalf("failed to read test token file: %v", err) - } - - out, err = idToken(tok) - require.NoError(t, err) - require.Equal(t, string(testTok), out) - - // test that when neither valid token nor a path is supplied, an error is returned - tok = "test" - _, err = idToken(tok) - require.Error(t, err) -} - type dummyCAClientService struct { client fulciopb.CAClient server *grpc.Server @@ -231,6 +200,25 @@ func TestSigner(t *testing.T) { _, err = provider.Signer(ctx) //this should be a tranport err since we cant actually test on 443 which is the default require.ErrorContains(t, err, "lookup test") + + // Test signer with token read from file + // NOTE: this function could be refactored to accept a fileSystem or io.Reader so reading the file can be mocked, + // but unsure if this is the way we want to go for now + wd, err := os.Getwd() + if err != nil { + t.Fatalf("failed to get working directory: %v", err) + } + rootDir := filepath.Dir(filepath.Dir(wd)) + tp := filepath.Join(rootDir, "hack", "test.token") + + provider = New(WithFulcioURL(fmt.Sprintf("http://%v:%v", hostname, port)), WithTokenPath(tp)) + signer, err = provider.Signer(ctx) + require.NoError(t, err) + + // Test signer with both token read from file and raw token + provider = New(WithFulcioURL(fmt.Sprintf("http://%v:%v", hostname, port)), WithTokenPath(tp), WithToken(token)) + signer, err = provider.Signer(ctx) + require.ErrorContains(t, err, "only one of --fulcio-token-path or --fulcio-raw-token can be used") } func generateCertChain(t *testing.T) []string {