Skip to content

Commit

Permalink
[v10] Remove update verb requirement when creating Tokens (#14506) (#…
Browse files Browse the repository at this point in the history
…14624)

Remove `update` verb requirement when creating Tokens (#14506)

The used method to create a token in the UI is UpsertToken.
This method requires Create and Update verbs.

It shouldn't be necessary to have the Update verb - we are only creating
and not changing anything.

This PR adds
- a new method - CreateToken - which only requires the Create verb.
- apiserver uses this method to issue a new token
  • Loading branch information
marcoandredinis authored Jul 19, 2022
1 parent 147b112 commit 6bc13d8
Show file tree
Hide file tree
Showing 11 changed files with 842 additions and 719 deletions.
10 changes: 10 additions & 0 deletions api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,16 @@ func (c *Client) UpsertToken(ctx context.Context, token types.ProvisionToken) er
return trail.FromGRPC(err)
}

// CreateToken creates a provision token.
func (c *Client) CreateToken(ctx context.Context, token types.ProvisionToken) error {
tokenV2, ok := token.(*types.ProvisionTokenV2)
if !ok {
return trace.BadParameter("invalid type %T", token)
}
_, err := c.grpc.CreateToken(ctx, tokenV2, c.callOpts...)
return trail.FromGRPC(err)
}

// GenerateToken generates a new auth token for the given service roles.
// This token can be used by corresponding services to authenticate with
// the Auth server and get a signed certificate and private key.
Expand Down
1,399 changes: 719 additions & 680 deletions api/client/proto/authservice.pb.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions api/client/proto/authservice.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2275,6 +2275,8 @@ service AuthService {
rpc GetTokens(google.protobuf.Empty) returns (types.ProvisionTokenV2List);
// UpsertToken upserts a token in a backend.
rpc UpsertToken(types.ProvisionTokenV2) returns (google.protobuf.Empty);
// CreateToken creates a token in a backend.
rpc CreateToken(types.ProvisionTokenV2) returns (google.protobuf.Empty);
// GenerateToken generates a new auth token.
rpc GenerateToken(GenerateTokenRequest) returns (GenerateTokenResponse);
// DeleteToken deletes an existing token in a backend described by the given request.
Expand Down
7 changes: 7 additions & 0 deletions lib/auth/auth_with_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -1551,6 +1551,13 @@ func (a *ServerWithRoles) UpsertToken(ctx context.Context, token types.Provision
return a.authServer.UpsertToken(ctx, token)
}

func (a *ServerWithRoles) CreateToken(ctx context.Context, token types.ProvisionToken) error {
if err := a.action(apidefaults.Namespace, types.KindToken, types.VerbCreate); err != nil {
return trace.Wrap(err)
}
return a.authServer.CreateToken(ctx, token)
}

func (a *ServerWithRoles) UpsertPassword(user string, password []byte) error {
if err := a.currentUserAction(user); err != nil {
return trace.Wrap(err)
Expand Down
3 changes: 3 additions & 0 deletions lib/auth/clt.go
Original file line number Diff line number Diff line change
Expand Up @@ -1663,6 +1663,9 @@ type ProvisioningService interface {
// UpsertToken adds provisioning tokens for the auth server
UpsertToken(ctx context.Context, token types.ProvisionToken) error

// CreateToken creates a new provision token for the auth server
CreateToken(ctx context.Context, token types.ProvisionToken) error

// RegisterUsingToken calls the auth service API to register a new node via registration token
// which has been previously issued via GenerateToken
RegisterUsingToken(ctx context.Context, req *types.RegisterUsingTokenRequest) (*proto.Certs, error)
Expand Down
12 changes: 12 additions & 0 deletions lib/auth/grpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2887,6 +2887,18 @@ func (g *GRPCServer) UpsertToken(ctx context.Context, token *types.ProvisionToke
return &empty.Empty{}, nil
}

// CreateToken creates a token.
func (g *GRPCServer) CreateToken(ctx context.Context, token *types.ProvisionTokenV2) (*empty.Empty, error) {
auth, err := g.authenticate(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
if err = auth.ServerWithRoles.CreateToken(ctx, token); err != nil {
return nil, trace.Wrap(err)
}
return &empty.Empty{}, nil
}

// GenerateToken generates a new auth token.
func (g *GRPCServer) GenerateToken(ctx context.Context, req *proto.GenerateTokenRequest) (*proto.GenerateTokenResponse, error) {
auth, err := g.authenticate(ctx)
Expand Down
40 changes: 32 additions & 8 deletions lib/services/local/provisioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,51 @@ func NewProvisioningService(backend backend.Backend) *ProvisioningService {

// UpsertToken adds provisioning tokens for the auth server
func (s *ProvisioningService) UpsertToken(ctx context.Context, p types.ProvisionToken) error {
if err := p.CheckAndSetDefaults(); err != nil {
item, err := s.tokenToItem(p)
if err != nil {
return trace.Wrap(err)
}

_, err = s.Put(ctx, *item)
if err != nil {
return trace.Wrap(err)
}
return nil
}

// CreateToken creates a new token for the auth server
func (s *ProvisioningService) CreateToken(ctx context.Context, p types.ProvisionToken) error {
item, err := s.tokenToItem(p)
if err != nil {
return trace.Wrap(err)
}

_, err = s.Create(ctx, *item)
if err != nil {
return trace.Wrap(err)
}

return nil
}

func (s *ProvisioningService) tokenToItem(p types.ProvisionToken) (*backend.Item, error) {
if err := p.CheckAndSetDefaults(); err != nil {
return nil, trace.Wrap(err)
}
if p.Expiry().IsZero() || p.Expiry().Sub(s.Clock().Now().UTC()) < time.Second {
p.SetExpiry(s.Clock().Now().UTC().Add(defaults.ProvisioningTokenTTL))
}
data, err := services.MarshalProvisionToken(p)
if err != nil {
return trace.Wrap(err)
return nil, trace.Wrap(err)
}
item := backend.Item{
item := &backend.Item{
Key: backend.Key(tokensPrefix, p.GetName()),
Value: data,
Expires: p.Expiry(),
ID: p.GetResourceID(),
}
_, err = s.Put(ctx, item)
if err != nil {
return trace.Wrap(err)
}
return nil
return item, nil
}

// DeleteAllTokens deletes all provisioning tokens
Expand Down
3 changes: 3 additions & 0 deletions lib/services/provisioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ type Provisioner interface {
// UpsertToken adds provisioning tokens for the auth server
UpsertToken(ctx context.Context, token types.ProvisionToken) error

// CreateToken adds provisioning tokens for the auth server
CreateToken(ctx context.Context, token types.ProvisionToken) error

// GetToken finds and returns token by id
GetToken(ctx context.Context, token string) (types.ProvisionToken, error)

Expand Down
2 changes: 1 addition & 1 deletion lib/web/apiserver_login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func configureClusterForMFA(t *testing.T, env *webPack, spec *types.AuthPreferen
// Create user.
const user = "llama"
const password = "password"
env.proxies[0].createUser(ctx, t, user, "root", "password", "" /* otpSecret */)
env.proxies[0].createUser(ctx, t, user, "root", "password", "" /* otpSecret */, nil /* roles */)

// Register device.
clt, err := env.server.NewClient(auth.TestUser(user))
Expand Down
Loading

0 comments on commit 6bc13d8

Please sign in to comment.