mirror of https://github.com/status-im/consul.git
making ACLToken.ExpirationTime a *time.Time value instead of time.Time (#5663)
This is mainly to avoid having the API return "0001-01-01T00:00:00Z" as a value for the ExpirationTime field when it is not set. Unfortunately time.Time doesn't respect the json marshalling "omitempty" directive.
This commit is contained in:
parent
db43fc3a20
commit
7928305279
|
@ -358,16 +358,16 @@ func (a *ACL) tokenSetInternal(args *structs.ACLTokenSetRequest, reply *structs.
|
||||||
if token.ExpirationTTL < 0 {
|
if token.ExpirationTTL < 0 {
|
||||||
return fmt.Errorf("Token Expiration TTL '%s' should be > 0", token.ExpirationTTL)
|
return fmt.Errorf("Token Expiration TTL '%s' should be > 0", token.ExpirationTTL)
|
||||||
}
|
}
|
||||||
if !token.ExpirationTime.IsZero() {
|
if token.HasExpirationTime() {
|
||||||
return fmt.Errorf("Token Expiration TTL and Expiration Time cannot both be set")
|
return fmt.Errorf("Token Expiration TTL and Expiration Time cannot both be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
token.ExpirationTime = token.CreateTime.Add(token.ExpirationTTL)
|
token.ExpirationTime = timePointer(token.CreateTime.Add(token.ExpirationTTL))
|
||||||
token.ExpirationTTL = 0
|
token.ExpirationTTL = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if !token.ExpirationTime.IsZero() {
|
if token.HasExpirationTime() {
|
||||||
if token.CreateTime.After(token.ExpirationTime) {
|
if token.CreateTime.After(*token.ExpirationTime) {
|
||||||
return fmt.Errorf("ExpirationTime cannot be before CreateTime")
|
return fmt.Errorf("ExpirationTime cannot be before CreateTime")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +417,15 @@ func (a *ACL) tokenSetInternal(args *structs.ACLTokenSetRequest, reply *structs.
|
||||||
return fmt.Errorf("cannot toggle local mode of %s", token.AccessorID)
|
return fmt.Errorf("cannot toggle local mode of %s", token.AccessorID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if token.ExpirationTTL != 0 || !token.ExpirationTime.Equal(existing.ExpirationTime) {
|
if token.ExpirationTTL != 0 {
|
||||||
|
return fmt.Errorf("Cannot change expiration time of %s", token.AccessorID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !token.HasExpirationTime() {
|
||||||
|
token.ExpirationTime = existing.ExpirationTime
|
||||||
|
} else if !existing.HasExpirationTime() {
|
||||||
|
return fmt.Errorf("Cannot change expiration time of %s", token.AccessorID)
|
||||||
|
} else if !token.ExpirationTime.Equal(*existing.ExpirationTime) {
|
||||||
return fmt.Errorf("Cannot change expiration time of %s", token.AccessorID)
|
return fmt.Errorf("Cannot change expiration time of %s", token.AccessorID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1041,3 +1049,7 @@ func (a *ACL) ReplicationStatus(args *structs.DCSpecificRequest,
|
||||||
a.srv.aclReplicationStatusLock.RUnlock()
|
a.srv.aclReplicationStatusLock.RUnlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func timePointer(t time.Time) *time.Time {
|
||||||
|
return &t
|
||||||
|
}
|
||||||
|
|
|
@ -1054,7 +1054,7 @@ func TestACLEndpoint_TokenSet(t *testing.T) {
|
||||||
Description: "foobar",
|
Description: "foobar",
|
||||||
Policies: nil,
|
Policies: nil,
|
||||||
Local: false,
|
Local: false,
|
||||||
ExpirationTime: time.Now().Add(test.offset),
|
ExpirationTime: timePointer(time.Now().Add(test.offset)),
|
||||||
},
|
},
|
||||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||||
}
|
}
|
||||||
|
@ -1099,7 +1099,7 @@ func TestACLEndpoint_TokenSet(t *testing.T) {
|
||||||
Description: "foobar",
|
Description: "foobar",
|
||||||
Policies: nil,
|
Policies: nil,
|
||||||
Local: false,
|
Local: false,
|
||||||
ExpirationTime: time.Now().Add(4 * time.Second),
|
ExpirationTime: timePointer(time.Now().Add(4 * time.Second)),
|
||||||
ExpirationTTL: 4 * time.Second,
|
ExpirationTTL: 4 * time.Second,
|
||||||
},
|
},
|
||||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||||
|
@ -1138,7 +1138,7 @@ func TestACLEndpoint_TokenSet(t *testing.T) {
|
||||||
require.NotNil(t, token.AccessorID)
|
require.NotNil(t, token.AccessorID)
|
||||||
require.Equal(t, token.Description, "foobar")
|
require.Equal(t, token.Description, "foobar")
|
||||||
require.Equal(t, token.AccessorID, resp.AccessorID)
|
require.Equal(t, token.AccessorID, resp.AccessorID)
|
||||||
requireTimeEquals(t, expectExpTime, resp.ExpirationTime)
|
requireTimeEquals(t, &expectExpTime, resp.ExpirationTime)
|
||||||
|
|
||||||
tokenID = token.AccessorID
|
tokenID = token.AccessorID
|
||||||
})
|
})
|
||||||
|
@ -1152,7 +1152,7 @@ func TestACLEndpoint_TokenSet(t *testing.T) {
|
||||||
Description: "foobar",
|
Description: "foobar",
|
||||||
Policies: nil,
|
Policies: nil,
|
||||||
Local: false,
|
Local: false,
|
||||||
ExpirationTime: expTime,
|
ExpirationTime: &expTime,
|
||||||
},
|
},
|
||||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||||
}
|
}
|
||||||
|
@ -1170,7 +1170,7 @@ func TestACLEndpoint_TokenSet(t *testing.T) {
|
||||||
require.NotNil(t, token.AccessorID)
|
require.NotNil(t, token.AccessorID)
|
||||||
require.Equal(t, token.Description, "foobar")
|
require.Equal(t, token.Description, "foobar")
|
||||||
require.Equal(t, token.AccessorID, resp.AccessorID)
|
require.Equal(t, token.AccessorID, resp.AccessorID)
|
||||||
requireTimeEquals(t, expTime, resp.ExpirationTime)
|
requireTimeEquals(t, &expTime, resp.ExpirationTime)
|
||||||
|
|
||||||
tokenID = token.AccessorID
|
tokenID = token.AccessorID
|
||||||
})
|
})
|
||||||
|
@ -1183,7 +1183,7 @@ func TestACLEndpoint_TokenSet(t *testing.T) {
|
||||||
ACLToken: structs.ACLToken{
|
ACLToken: structs.ACLToken{
|
||||||
Description: "new-description",
|
Description: "new-description",
|
||||||
AccessorID: tokenID,
|
AccessorID: tokenID,
|
||||||
ExpirationTime: expTime.Add(-1 * time.Second),
|
ExpirationTime: timePointer(expTime.Add(-1 * time.Second)),
|
||||||
},
|
},
|
||||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||||
}
|
}
|
||||||
|
@ -1202,7 +1202,7 @@ func TestACLEndpoint_TokenSet(t *testing.T) {
|
||||||
ACLToken: structs.ACLToken{
|
ACLToken: structs.ACLToken{
|
||||||
Description: "new-description",
|
Description: "new-description",
|
||||||
AccessorID: tokenID,
|
AccessorID: tokenID,
|
||||||
ExpirationTime: expTime,
|
ExpirationTime: &expTime,
|
||||||
},
|
},
|
||||||
WriteRequest: structs.WriteRequest{Token: "root"},
|
WriteRequest: structs.WriteRequest{Token: "root"},
|
||||||
}
|
}
|
||||||
|
@ -1220,7 +1220,7 @@ func TestACLEndpoint_TokenSet(t *testing.T) {
|
||||||
require.NotNil(t, token.AccessorID)
|
require.NotNil(t, token.AccessorID)
|
||||||
require.Equal(t, token.Description, "new-description")
|
require.Equal(t, token.Description, "new-description")
|
||||||
require.Equal(t, token.AccessorID, resp.AccessorID)
|
require.Equal(t, token.AccessorID, resp.AccessorID)
|
||||||
requireTimeEquals(t, expTime, resp.ExpirationTime)
|
requireTimeEquals(t, &expTime, resp.ExpirationTime)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("cannot update a token that is past its expiration time", func(t *testing.T) {
|
t.Run("cannot update a token that is past its expiration time", func(t *testing.T) {
|
||||||
|
@ -2217,10 +2217,16 @@ func retrieveTestPolicy(codec rpc.ClientCodec, masterToken string, datacenter st
|
||||||
return &out, nil
|
return &out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func requireTimeEquals(t *testing.T, expect, got time.Time) {
|
func requireTimeEquals(t *testing.T, expect, got *time.Time) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if !expect.Equal(got) {
|
if expect == nil && got == nil {
|
||||||
t.Fatalf("expected=%q != got=%q", expect, got)
|
return
|
||||||
|
} else if expect == nil && got != nil {
|
||||||
|
t.Fatalf("expected=NIL != got=%q", *got)
|
||||||
|
} else if expect != nil && got == nil {
|
||||||
|
t.Fatalf("expected=%q != got=NIL", *expect)
|
||||||
|
} else if !expect.Equal(*got) {
|
||||||
|
t.Fatalf("expected=%q != got=%q", *expect, *got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,14 +79,14 @@ func (s *TokenExpirationIndex) FromObject(obj interface{}) (bool, []byte, error)
|
||||||
if s.LocalFilter != token.Local {
|
if s.LocalFilter != token.Local {
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
if token.ExpirationTime.IsZero() {
|
if !token.HasExpirationTime() {
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
if token.ExpirationTime.Unix() < 0 {
|
if token.ExpirationTime.Unix() < 0 {
|
||||||
return false, nil, fmt.Errorf("token expiration time cannot be before the unix epoch: %s", token.ExpirationTime)
|
return false, nil, fmt.Errorf("token expiration time cannot be before the unix epoch: %s", token.ExpirationTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := s.encodeTime(token.ExpirationTime)
|
buf := s.encodeTime(*token.ExpirationTime)
|
||||||
|
|
||||||
return true, buf, nil
|
return true, buf, nil
|
||||||
}
|
}
|
||||||
|
@ -669,10 +669,10 @@ func (s *Store) ACLTokenMinExpirationTime(local bool) (time.Time, error) {
|
||||||
|
|
||||||
token := item.(*structs.ACLToken)
|
token := item.(*structs.ACLToken)
|
||||||
|
|
||||||
return token.ExpirationTime, nil
|
return *token.ExpirationTime, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACLTokenListExpires lists tokens that are expires as of the provided time.
|
// ACLTokenListExpires lists tokens that are expired as of the provided time.
|
||||||
// The returned set will be no larger than the max value provided.
|
// The returned set will be no larger than the max value provided.
|
||||||
func (s *Store) ACLTokenListExpired(local bool, asOf time.Time, max int) (structs.ACLTokens, <-chan struct{}, error) {
|
func (s *Store) ACLTokenListExpired(local bool, asOf time.Time, max int) (structs.ACLTokens, <-chan struct{}, error) {
|
||||||
tx := s.db.Txn(false)
|
tx := s.db.Txn(false)
|
||||||
|
@ -689,8 +689,7 @@ func (s *Store) ACLTokenListExpired(local bool, asOf time.Time, max int) (struct
|
||||||
)
|
)
|
||||||
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
||||||
token := raw.(*structs.ACLToken)
|
token := raw.(*structs.ACLToken)
|
||||||
|
if token.ExpirationTime != nil && !token.ExpirationTime.Before(asOf) {
|
||||||
if !token.ExpirationTime.Before(asOf) {
|
|
||||||
return tokens, nil, nil
|
return tokens, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1741,7 +1741,7 @@ func TestTokenPoliciesIndex(t *testing.T) {
|
||||||
SecretID: newUUID(),
|
SecretID: newUUID(),
|
||||||
Description: desc,
|
Description: desc,
|
||||||
Local: local,
|
Local: local,
|
||||||
ExpirationTime: expTime,
|
ExpirationTime: &expTime,
|
||||||
CreateTime: baseTime,
|
CreateTime: baseTime,
|
||||||
RaftIndex: structs.RaftIndex{
|
RaftIndex: structs.RaftIndex{
|
||||||
CreateIndex: 9,
|
CreateIndex: 9,
|
||||||
|
|
|
@ -218,7 +218,11 @@ type ACLToken struct {
|
||||||
// ExpirationTime represents the point after which a token should be
|
// ExpirationTime represents the point after which a token should be
|
||||||
// considered revoked and is eligible for destruction. The zero value
|
// considered revoked and is eligible for destruction. The zero value
|
||||||
// represents NO expiration.
|
// represents NO expiration.
|
||||||
ExpirationTime time.Time `json:",omitempty"`
|
//
|
||||||
|
// This is a pointer value so that the zero value is omitted properly
|
||||||
|
// during json serialization. time.Time does not respect json omitempty
|
||||||
|
// directives unfortunately.
|
||||||
|
ExpirationTime *time.Time `json:",omitempty"`
|
||||||
|
|
||||||
// ExpirationTTL is a convenience field for helping set ExpirationTime to a
|
// ExpirationTTL is a convenience field for helping set ExpirationTime to a
|
||||||
// value of CreateTime+ExpirationTTL. This can only be set during
|
// value of CreateTime+ExpirationTTL. This can only be set during
|
||||||
|
@ -293,17 +297,21 @@ func (t *ACLToken) ServiceIdentityList() []*ACLServiceIdentity {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ACLToken) IsExpired(asOf time.Time) bool {
|
func (t *ACLToken) IsExpired(asOf time.Time) bool {
|
||||||
if asOf.IsZero() || t.ExpirationTime.IsZero() {
|
if asOf.IsZero() || !t.HasExpirationTime() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return t.ExpirationTime.Before(asOf)
|
return t.ExpirationTime.Before(asOf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *ACLToken) HasExpirationTime() bool {
|
||||||
|
return t.ExpirationTime != nil && !t.ExpirationTime.IsZero()
|
||||||
|
}
|
||||||
|
|
||||||
func (t *ACLToken) UsesNonLegacyFields() bool {
|
func (t *ACLToken) UsesNonLegacyFields() bool {
|
||||||
return len(t.Policies) > 0 ||
|
return len(t.Policies) > 0 ||
|
||||||
len(t.ServiceIdentities) > 0 ||
|
len(t.ServiceIdentities) > 0 ||
|
||||||
t.Type == "" ||
|
t.Type == "" ||
|
||||||
!t.ExpirationTime.IsZero() ||
|
t.HasExpirationTime() ||
|
||||||
t.ExpirationTTL != 0
|
t.ExpirationTTL != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +413,7 @@ type ACLTokenListStub struct {
|
||||||
Policies []ACLTokenPolicyLink `json:",omitempty"`
|
Policies []ACLTokenPolicyLink `json:",omitempty"`
|
||||||
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
||||||
Local bool
|
Local bool
|
||||||
ExpirationTime time.Time `json:",omitempty"`
|
ExpirationTime *time.Time `json:",omitempty"`
|
||||||
CreateTime time.Time `json:",omitempty"`
|
CreateTime time.Time `json:",omitempty"`
|
||||||
Hash []byte
|
Hash []byte
|
||||||
CreateIndex uint64
|
CreateIndex uint64
|
||||||
|
|
|
@ -31,7 +31,7 @@ type ACLToken struct {
|
||||||
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
||||||
Local bool
|
Local bool
|
||||||
ExpirationTTL time.Duration `json:",omitempty"`
|
ExpirationTTL time.Duration `json:",omitempty"`
|
||||||
ExpirationTime time.Time `json:",omitempty"`
|
ExpirationTime *time.Time `json:",omitempty"`
|
||||||
CreateTime time.Time `json:",omitempty"`
|
CreateTime time.Time `json:",omitempty"`
|
||||||
Hash []byte `json:",omitempty"`
|
Hash []byte `json:",omitempty"`
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ type ACLTokenListEntry struct {
|
||||||
Policies []*ACLTokenPolicyLink `json:",omitempty"`
|
Policies []*ACLTokenPolicyLink `json:",omitempty"`
|
||||||
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
ServiceIdentities []*ACLServiceIdentity `json:",omitempty"`
|
||||||
Local bool
|
Local bool
|
||||||
ExpirationTime time.Time `json:",omitempty"`
|
ExpirationTime *time.Time `json:",omitempty"`
|
||||||
CreateTime time.Time
|
CreateTime time.Time
|
||||||
Hash []byte
|
Hash []byte
|
||||||
Legacy bool
|
Legacy bool
|
||||||
|
|
|
@ -15,8 +15,8 @@ func PrintToken(token *api.ACLToken, ui cli.Ui, showMeta bool) {
|
||||||
ui.Info(fmt.Sprintf("Description: %s", token.Description))
|
ui.Info(fmt.Sprintf("Description: %s", token.Description))
|
||||||
ui.Info(fmt.Sprintf("Local: %t", token.Local))
|
ui.Info(fmt.Sprintf("Local: %t", token.Local))
|
||||||
ui.Info(fmt.Sprintf("Create Time: %v", token.CreateTime))
|
ui.Info(fmt.Sprintf("Create Time: %v", token.CreateTime))
|
||||||
if !token.ExpirationTime.IsZero() {
|
if token.ExpirationTime != nil && !token.ExpirationTime.IsZero() {
|
||||||
ui.Info(fmt.Sprintf("Expiration Time: %v", token.ExpirationTime))
|
ui.Info(fmt.Sprintf("Expiration Time: %v", *token.ExpirationTime))
|
||||||
}
|
}
|
||||||
if showMeta {
|
if showMeta {
|
||||||
ui.Info(fmt.Sprintf("Hash: %x", token.Hash))
|
ui.Info(fmt.Sprintf("Hash: %x", token.Hash))
|
||||||
|
@ -46,8 +46,8 @@ func PrintTokenListEntry(token *api.ACLTokenListEntry, ui cli.Ui, showMeta bool)
|
||||||
ui.Info(fmt.Sprintf("Description: %s", token.Description))
|
ui.Info(fmt.Sprintf("Description: %s", token.Description))
|
||||||
ui.Info(fmt.Sprintf("Local: %t", token.Local))
|
ui.Info(fmt.Sprintf("Local: %t", token.Local))
|
||||||
ui.Info(fmt.Sprintf("Create Time: %v", token.CreateTime))
|
ui.Info(fmt.Sprintf("Create Time: %v", token.CreateTime))
|
||||||
if !token.ExpirationTime.IsZero() {
|
if token.ExpirationTime != nil && !token.ExpirationTime.IsZero() {
|
||||||
ui.Info(fmt.Sprintf("Expiration Time: %v", token.ExpirationTime))
|
ui.Info(fmt.Sprintf("Expiration Time: %v", *token.ExpirationTime))
|
||||||
}
|
}
|
||||||
ui.Info(fmt.Sprintf("Legacy: %t", token.Legacy))
|
ui.Info(fmt.Sprintf("Legacy: %t", token.Legacy))
|
||||||
if showMeta {
|
if showMeta {
|
||||||
|
|
Loading…
Reference in New Issue