mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 10:25:42 +03:00
nomad: generate accessor/secret ID server side
This commit is contained in:
@@ -150,7 +150,7 @@ func (a *ACL) GetPolicy(args *structs.ACLPolicySpecificRequest, reply *structs.S
|
||||
}
|
||||
|
||||
// UpsertTokens is used to create or update a set of tokens
|
||||
func (a *ACL) UpsertTokens(args *structs.ACLTokenUpsertRequest, reply *structs.GenericResponse) error {
|
||||
func (a *ACL) UpsertTokens(args *structs.ACLTokenUpsertRequest, reply *structs.ACLTokenUpsertResponse) error {
|
||||
if done, err := a.srv.forward("ACL.UpsertTokens", args, args, reply); done {
|
||||
return err
|
||||
}
|
||||
@@ -161,11 +161,40 @@ func (a *ACL) UpsertTokens(args *structs.ACLTokenUpsertRequest, reply *structs.G
|
||||
return fmt.Errorf("must specify as least one token")
|
||||
}
|
||||
|
||||
// Snapshot the state
|
||||
state := a.srv.State()
|
||||
|
||||
// Validate each token
|
||||
for idx, token := range args.Tokens {
|
||||
if err := token.Validate(); err != nil {
|
||||
return fmt.Errorf("token %d invalid: %v", idx, err)
|
||||
}
|
||||
|
||||
// Generate an accessor and secret ID if new
|
||||
if token.AccessorID == "" {
|
||||
token.AccessorID = structs.GenerateUUID()
|
||||
token.SecretID = structs.GenerateUUID()
|
||||
token.CreateTime = time.Now().UTC()
|
||||
|
||||
} else {
|
||||
// Verify the token exists
|
||||
out, err := state.ACLTokenByAccessorID(nil, token.AccessorID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("token lookup failed: %v", err)
|
||||
}
|
||||
if out == nil {
|
||||
return fmt.Errorf("cannot find token %s", token.AccessorID)
|
||||
}
|
||||
|
||||
// Do not allow the secret ID or create time to be changed
|
||||
token.SecretID = out.SecretID
|
||||
token.CreateTime = out.CreateTime
|
||||
|
||||
// Cannot toggle the "Global" mode
|
||||
if token.Global != out.Global {
|
||||
return fmt.Errorf("cannot toggle global mode of %s", token.AccessorID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update via Raft
|
||||
@@ -174,6 +203,17 @@ func (a *ACL) UpsertTokens(args *structs.ACLTokenUpsertRequest, reply *structs.G
|
||||
return err
|
||||
}
|
||||
|
||||
// Populate the response. We do a lookup against the state to
|
||||
// pickup the proper create / modify times.
|
||||
state = a.srv.State()
|
||||
for _, token := range args.Tokens {
|
||||
out, err := state.ACLTokenByAccessorID(nil, token.AccessorID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("token lookup failed: %v", err)
|
||||
}
|
||||
reply.Tokens = append(reply.Tokens, out)
|
||||
}
|
||||
|
||||
// Update the index
|
||||
reply.Index = index
|
||||
return nil
|
||||
|
||||
@@ -538,22 +538,48 @@ func TestACLEndpoint_UpsertTokens(t *testing.T) {
|
||||
|
||||
// Create the register request
|
||||
p1 := mock.ACLToken()
|
||||
p1.AccessorID = "" // Blank to create
|
||||
|
||||
// Lookup the tokens
|
||||
req := &structs.ACLTokenUpsertRequest{
|
||||
Tokens: []*structs.ACLToken{p1},
|
||||
WriteRequest: structs.WriteRequest{Region: "global"},
|
||||
}
|
||||
var resp structs.GenericResponse
|
||||
var resp structs.ACLTokenUpsertResponse
|
||||
if err := msgpackrpc.CallWithCodec(codec, "ACL.UpsertTokens", req, &resp); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
assert.NotEqual(t, uint64(0), resp.Index)
|
||||
|
||||
// Get the token out from the response
|
||||
created := resp.Tokens[0]
|
||||
assert.NotEqual(t, "", created.AccessorID)
|
||||
assert.NotEqual(t, "", created.SecretID)
|
||||
assert.NotEqual(t, time.Time{}, created.CreateTime)
|
||||
assert.Equal(t, p1.Type, created.Type)
|
||||
assert.Equal(t, p1.Policies, created.Policies)
|
||||
assert.Equal(t, p1.Name, created.Name)
|
||||
|
||||
// Check we created the token
|
||||
out, err := s1.fsm.State().ACLTokenByAccessorID(nil, p1.AccessorID)
|
||||
out, err := s1.fsm.State().ACLTokenByAccessorID(nil, created.AccessorID)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, out)
|
||||
assert.Equal(t, created, out)
|
||||
|
||||
// Update the token type
|
||||
req.Tokens[0] = created
|
||||
created.Type = "management"
|
||||
created.Policies = nil
|
||||
|
||||
// Upsert again
|
||||
if err := msgpackrpc.CallWithCodec(codec, "ACL.UpsertTokens", req, &resp); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
assert.NotEqual(t, uint64(0), resp.Index)
|
||||
|
||||
// Check we modified the token
|
||||
out, err = s1.fsm.State().ACLTokenByAccessorID(nil, created.AccessorID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, created, out)
|
||||
}
|
||||
|
||||
func TestACLEndpoint_UpsertTokens_Invalid(t *testing.T) {
|
||||
|
||||
@@ -5513,3 +5513,9 @@ type ACLTokenUpsertRequest struct {
|
||||
Tokens []*ACLToken
|
||||
WriteRequest
|
||||
}
|
||||
|
||||
// ACLTokenUpsertResponse is used to return from an ACLTokenUpsertRequest
|
||||
type ACLTokenUpsertResponse struct {
|
||||
Tokens []*ACLToken
|
||||
WriteMeta
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user