add Name to auth.Account as a user friendly alias (#1992)

* add Name to auth.Account as a user friendly alias
This commit is contained in:
Dominic Wong
2020-09-10 14:49:51 +01:00
committed by GitHub
parent 04d2aa4696
commit 601b223cfb
6 changed files with 58 additions and 5 deletions

View File

@@ -49,7 +49,7 @@ type Auth interface {
// Account provided by an auth provider // Account provided by an auth provider
type Account struct { type Account struct {
// ID of the account e.g. email // ID of the account e.g. UUID. Should not change
ID string `json:"id"` ID string `json:"id"`
// Type of the account, e.g. service // Type of the account, e.g. service
Type string `json:"type"` Type string `json:"type"`
@@ -61,6 +61,8 @@ type Account struct {
Scopes []string `json:"scopes"` Scopes []string `json:"scopes"`
// Secret for the account, e.g. the password // Secret for the account, e.g. the password
Secret string `json:"secret"` Secret string `json:"secret"`
// Name of the account. User friendly name that might change e.g. a username or email
Name string `json:"name"`
} }
// Token can be short or long lived // Token can be short or long lived

View File

@@ -54,13 +54,17 @@ func (j *jwtAuth) Generate(id string, opts ...auth.GenerateOption) (*auth.Accoun
if len(options.Issuer) == 0 { if len(options.Issuer) == 0 {
options.Issuer = j.Options().Issuer options.Issuer = j.Options().Issuer
} }
name := options.Name
if name == "" {
name = id
}
account := &auth.Account{ account := &auth.Account{
ID: id, ID: id,
Type: options.Type, Type: options.Type,
Scopes: options.Scopes, Scopes: options.Scopes,
Metadata: options.Metadata, Metadata: options.Metadata,
Issuer: options.Issuer, Issuer: options.Issuer,
Name: name,
} }
// generate a JWT secret which can be provided to the Token() method // generate a JWT secret which can be provided to the Token() method

View File

@@ -40,13 +40,17 @@ func (n *noop) Options() auth.Options {
// Generate a new account // Generate a new account
func (n *noop) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) { func (n *noop) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
options := auth.NewGenerateOptions(opts...) options := auth.NewGenerateOptions(opts...)
name := options.Name
if name == "" {
name = id
}
return &auth.Account{ return &auth.Account{
ID: id, ID: id,
Secret: options.Secret, Secret: options.Secret,
Metadata: options.Metadata, Metadata: options.Metadata,
Scopes: options.Scopes, Scopes: options.Scopes,
Issuer: n.Options().Issuer, Issuer: n.Options().Issuer,
Name: name,
}, nil }, nil
} }

View File

@@ -110,6 +110,8 @@ type GenerateOptions struct {
Secret string Secret string
// Issuer of the account, e.g. micro // Issuer of the account, e.g. micro
Issuer string Issuer string
// Name of the acouunt e.g. an email or username
Name string
} }
type GenerateOption func(o *GenerateOptions) type GenerateOption func(o *GenerateOptions)
@@ -156,6 +158,13 @@ func WithIssuer(i string) GenerateOption {
} }
} }
// WithName for the generated account
func WithName(n string) GenerateOption {
return func(o *GenerateOptions) {
o.Name = n
}
}
// NewGenerateOptions from a slice of options // NewGenerateOptions from a slice of options
func NewGenerateOptions(opts ...GenerateOption) GenerateOptions { func NewGenerateOptions(opts ...GenerateOption) GenerateOptions {
var options GenerateOptions var options GenerateOptions

View File

@@ -14,6 +14,7 @@ type authClaims struct {
Type string `json:"type"` Type string `json:"type"`
Scopes []string `json:"scopes"` Scopes []string `json:"scopes"`
Metadata map[string]string `json:"metadata"` Metadata map[string]string `json:"metadata"`
Name string `json:"name"`
jwt.StandardClaims jwt.StandardClaims
} }
@@ -47,10 +48,17 @@ func (j *JWT) Generate(acc *auth.Account, opts ...token.GenerateOption) (*token.
// parse the options // parse the options
options := token.NewGenerateOptions(opts...) options := token.NewGenerateOptions(opts...)
// backwards compatibility
name := acc.Name
if name == "" {
name = acc.ID
}
// generate the JWT // generate the JWT
expiry := time.Now().Add(options.Expiry) expiry := time.Now().Add(options.Expiry)
t := jwt.NewWithClaims(jwt.SigningMethodRS256, authClaims{ t := jwt.NewWithClaims(jwt.SigningMethodRS256, authClaims{
acc.Type, acc.Scopes, acc.Metadata, jwt.StandardClaims{ Type: acc.Type, Scopes: acc.Scopes, Metadata: acc.Metadata, Name: name,
StandardClaims: jwt.StandardClaims{
Subject: acc.ID, Subject: acc.ID,
Issuer: acc.Issuer, Issuer: acc.Issuer,
ExpiresAt: expiry.Unix(), ExpiresAt: expiry.Unix(),
@@ -94,6 +102,12 @@ func (j *JWT) Inspect(t string) (*auth.Account, error) {
return nil, token.ErrInvalidToken return nil, token.ErrInvalidToken
} }
// backwards compatibility
name := claims.Name
if name == "" {
name = claims.Subject
}
// return the token // return the token
return &auth.Account{ return &auth.Account{
ID: claims.Subject, ID: claims.Subject,
@@ -101,6 +115,7 @@ func (j *JWT) Inspect(t string) (*auth.Account, error) {
Type: claims.Type, Type: claims.Type,
Scopes: claims.Scopes, Scopes: claims.Scopes,
Metadata: claims.Metadata, Metadata: claims.Metadata,
Name: name,
}, nil }, nil
} }

View File

@@ -44,8 +44,9 @@ func TestInspect(t *testing.T) {
md := map[string]string{"foo": "bar"} md := map[string]string{"foo": "bar"}
scopes := []string{"admin"} scopes := []string{"admin"}
subject := "test" subject := "test"
name := "testname"
acc := &auth.Account{ID: subject, Scopes: scopes, Metadata: md} acc := &auth.Account{ID: subject, Scopes: scopes, Metadata: md, Name: name}
tok, err := j.Generate(acc) tok, err := j.Generate(acc)
if err != nil { if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err) t.Fatalf("Generate returned %v error, expected nil", err)
@@ -64,6 +65,9 @@ func TestInspect(t *testing.T) {
if len(tok2.Metadata) != len(md) { if len(tok2.Metadata) != len(md) {
t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md) t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md)
} }
if tok2.Name != name {
t.Errorf("Inspect returned %v as the token name, expected %v", tok2.Name, name)
}
}) })
t.Run("Expired token", func(t *testing.T) { t.Run("Expired token", func(t *testing.T) {
@@ -84,4 +88,19 @@ func TestInspect(t *testing.T) {
} }
}) })
t.Run("Default name", func(t *testing.T) {
tok, err := j.Generate(&auth.Account{ID: "test"})
if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err)
}
tok2, err := j.Inspect(tok.Token)
if err != nil {
t.Fatalf("Inspect returned %v error, expected nil", err)
}
if tok2.Name != "test" {
t.Fatalf("Inspect returned %v as the token name, expected test", tok2.Name)
}
})
} }