nomad: generate accessor/secret ID server side

This commit is contained in:
Armon Dadgar
2017-08-12 16:29:11 -07:00
parent 70cdccf643
commit 18eec0398f
3 changed files with 76 additions and 4 deletions

View File

@@ -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

View File

@@ -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) {

View File

@@ -5513,3 +5513,9 @@ type ACLTokenUpsertRequest struct {
Tokens []*ACLToken
WriteRequest
}
// ACLTokenUpsertResponse is used to return from an ACLTokenUpsertRequest
type ACLTokenUpsertResponse struct {
Tokens []*ACLToken
WriteMeta
}