Skip to content

Commit

Permalink
systemview: adds method for plugins to generate identity tokens (#24929)
Browse files Browse the repository at this point in the history
* systemview: adds method for plugins to generate identity tokens

* change test name and godoc

* adds changelog

* make proto to include comment
  • Loading branch information
austingebauer committed Jan 18, 2024
1 parent ee1e7e1 commit d90c7e8
Show file tree
Hide file tree
Showing 9 changed files with 563 additions and 236 deletions.
3 changes: 3 additions & 0 deletions changelog/24929.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
sdk: adds new method to system view to allow plugins to request identity tokens
```
40 changes: 40 additions & 0 deletions sdk/helper/pluginutil/identity_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package pluginutil

import (
"time"
)

const redactedTokenString = "ey***"

type IdentityTokenRequest struct {
// Audience identifies the recipient of the token. The requested
// value will be in the "aud" claim. Required.
Audience string
// TTL is the requested duration that the token will be valid for.
// Optional with a default of 1hr.
TTL time.Duration
}

type IdentityTokenResponse struct {
// Token is the plugin identity token.
Token IdentityToken
// TTL is the duration that the token is valid for after truncation is applied.
// The TTL may be truncated depending on the lifecycle of its signing key.
TTL time.Duration
}

type IdentityToken string

// String returns a redacted token string. Use the Token() method
// to obtain the non-redacted token contents.
func (t IdentityToken) String() string {
return redactedTokenString
}

// Token returns the non-redacted token contents.
func (t IdentityToken) Token() string {
return string(t)
}
29 changes: 29 additions & 0 deletions sdk/helper/pluginutil/identity_token_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package pluginutil

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

// TestIdentityToken_Stringer ensures that plugin identity tokens that
// are printed in formatted strings or errors are redacted and getters
// return expected values.
func TestIdentityToken_Stringer(t *testing.T) {
contents := "header.payload.signature"
tk := IdentityToken(contents)

// token getters
assert.Equal(t, contents, tk.Token())
assert.Equal(t, redactedTokenString, tk.String())

// formatted strings and errors
assert.NotContains(t, fmt.Sprintf("%v", tk), tk.Token())
assert.NotContains(t, fmt.Sprintf("%s", tk), tk.Token())
assert.NotContains(t, fmt.Errorf("%v", tk).Error(), tk.Token())
assert.NotContains(t, fmt.Errorf("%s", tk).Error(), tk.Token())
}
7 changes: 7 additions & 0 deletions sdk/logical/system_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ type SystemView interface {
// write forwarding (WriteForwardedPaths). This value will be templated
// in for the {{cluterId}} sentinel.
ClusterID(ctx context.Context) (string, error)

// GenerateIdentityToken returns an identity token for the requesting plugin.
GenerateIdentityToken(ctx context.Context, req *pluginutil.IdentityTokenRequest) (*pluginutil.IdentityTokenResponse, error)
}

type PasswordPolicy interface {
Expand Down Expand Up @@ -265,6 +268,10 @@ func (d StaticSystemView) ClusterID(ctx context.Context) (string, error) {
return d.ClusterUUID, nil
}

func (d StaticSystemView) GenerateIdentityToken(_ context.Context, _ *pluginutil.IdentityTokenRequest) (*pluginutil.IdentityTokenResponse, error) {
return nil, errors.New("GenerateIdentityToken is not implemented in StaticSystemView")
}

func (d StaticSystemView) APILockShouldBlockRequest() (bool, error) {
return d.APILockShouldBlockRequestVal, nil
}
35 changes: 35 additions & 0 deletions sdk/plugin/grpc_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,21 @@ func (s gRPCSystemViewClient) ClusterID(ctx context.Context) (string, error) {
return reply.ClusterID, nil
}

func (s *gRPCSystemViewClient) GenerateIdentityToken(ctx context.Context, req *pluginutil.IdentityTokenRequest) (*pluginutil.IdentityTokenResponse, error) {
resp, err := s.client.GenerateIdentityToken(ctx, &pb.GenerateIdentityTokenRequest{
Audience: req.Audience,
TTL: int64(req.TTL.Seconds()),
})
if err != nil {
return nil, err
}

return &pluginutil.IdentityTokenResponse{
Token: pluginutil.IdentityToken(resp.Token),
TTL: time.Duration(resp.TTL) * time.Second,
}, nil
}

type gRPCSystemViewServer struct {
pb.UnimplementedSystemViewServer

Expand Down Expand Up @@ -394,3 +409,23 @@ func (s *gRPCSystemViewServer) ClusterInfo(ctx context.Context, _ *pb.Empty) (*p
ClusterID: clusterId,
}, nil
}

func (s *gRPCSystemViewServer) GenerateIdentityToken(ctx context.Context, req *pb.GenerateIdentityTokenRequest) (*pb.GenerateIdentityTokenResponse, error) {
if s.impl == nil {
return nil, errMissingSystemView
}

res, err := s.impl.GenerateIdentityToken(ctx, &pluginutil.IdentityTokenRequest{
Audience: req.GetAudience(),
TTL: time.Duration(req.GetTTL()) * time.Second,
})
if err != nil {
return &pb.GenerateIdentityTokenResponse{}, status.Errorf(codes.Internal,
"failed to generate plugin identity token")
}

return &pb.GenerateIdentityTokenResponse{
Token: res.Token.Token(),
TTL: int64(res.TTL.Seconds()),
}, nil
}
Loading

0 comments on commit d90c7e8

Please sign in to comment.