Merge pull request #1459 from micro/auth-interface-update

Auth Interface Iteration
This commit is contained in:
ben-toogood 2020-04-01 17:56:38 +01:00 committed by GitHub
commit cd3d704aa5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 315 additions and 291 deletions

View File

@ -5,7 +5,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"time" "time"
"github.com/micro/go-micro/v2/metadata" "github.com/micro/go-micro/v2/metadata"
@ -42,8 +41,8 @@ type Auth interface {
Verify(acc *Account, res *Resource) error Verify(acc *Account, res *Resource) error
// Inspect a token // Inspect a token
Inspect(token string) (*Account, error) Inspect(token string) (*Account, error)
// Token generated using an account ID and secret // Token generated using refresh token
Token(id, secret string, opts ...TokenOption) (*Token, error) Token(opts ...TokenOption) (*Token, error)
// String returns the name of the implementation // String returns the name of the implementation
String() string String() string
} }
@ -60,36 +59,32 @@ type Resource struct {
// Account provided by an auth provider // Account provided by an auth provider
type Account struct { type Account struct {
// ID of the account (UUIDV4, email or username) // ID of the account e.g. email
ID string `json:"id"` ID string `json:"id"`
// Secret used to renew the account // Type of the account, e.g. service
Secret string `json:"secret"` Type string `json:"type"`
// Provider who issued the account
Provider string `json:"provider"`
// Roles associated with the Account // Roles associated with the Account
Roles []string `json:"roles"` Roles []string `json:"roles"`
// Any other associated metadata // Any other associated metadata
Metadata map[string]string `json:"metadata"` Metadata map[string]string `json:"metadata"`
// Namespace the account belongs to, default blank // Namespace the account belongs to, default blank
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
// Secret for the account, e.g. the password
Secret string `json:"secret"`
} }
// Token can be short or long lived // Token can be short or long lived
type Token struct { type Token struct {
// The token itself // The token to be used for accessing resources
Token string `json:"token"` AccessToken string `json:"access_token"`
// Type of token, e.g. JWT // RefreshToken to be used to generate a new token
Type string `json:"type"` RefreshToken string `json:"refresh_token"`
// Time of token creation // Time of token creation
Created time.Time `json:"created"` Created time.Time `json:"created"`
// Time of token expiry // Time of token expiry
Expiry time.Time `json:"expiry"` Expiry time.Time `json:"expiry"`
// Subject of the token, e.g. the account ID
Subject string `json:"subject"`
// Roles granted to the token
Roles []string `json:"roles"`
// Metadata embedded in the token
Metadata map[string]string `json:"metadata"`
// Namespace the token belongs to
Namespace string `json:"namespace"`
} }
const ( const (
@ -132,8 +127,3 @@ func ContextWithAccount(ctx context.Context, account *Account) (context.Context,
// generate a new context with the MetadataKey set // generate a new context with the MetadataKey set
return metadata.Set(ctx, MetadataKey, string(bytes)), nil return metadata.Set(ctx, MetadataKey, string(bytes)), nil
} }
// ContextWithToken sets the auth token in the context
func ContextWithToken(ctx context.Context, token string) context.Context {
return metadata.Set(ctx, "Authorization", fmt.Sprintf("%v%v", BearerScheme, token))
}

View File

@ -40,8 +40,8 @@ func (n *noop) Generate(id string, opts ...GenerateOption) (*Account, error) {
return &Account{ return &Account{
ID: id, ID: id,
Roles: options.Roles, Roles: options.Roles,
Secret: options.Secret,
Metadata: options.Metadata, Metadata: options.Metadata,
Secret: uuid.New().String(),
}, nil }, nil
} }
@ -68,6 +68,6 @@ func (n *noop) Inspect(token string) (*Account, error) {
} }
// Token generation using an account id and secret // Token generation using an account id and secret
func (n *noop) Token(id, secret string, opts ...TokenOption) (*Token, error) { func (n *noop) Token(opts ...TokenOption) (*Token, error) {
return &Token{}, nil return &Token{}, nil
} }

View File

@ -10,13 +10,13 @@ import (
type Options struct { type Options struct {
// ID is the services auth ID // ID is the services auth ID
ID string ID string
// Secret is used to generate new tokens // Secret is used to authenticate the service
Secret string Secret string
// Token is the services token used to authenticate itself // Token is the services token used to authenticate itself
Token *Token Token *Token
// Public key base64 encoded // PublicKey for decoding JWTs
PublicKey string PublicKey string
// Private key base64 encoded // PrivateKey for encoding JWTs
PrivateKey string PrivateKey string
// Provider is an auth provider // Provider is an auth provider
Provider provider.Provider Provider provider.Provider
@ -78,10 +78,30 @@ type GenerateOptions struct {
Roles []string Roles []string
// Namespace the account belongs too // Namespace the account belongs too
Namespace string Namespace string
// Provider of the account, e.g. oauth
Provider string
// Type of the account, e.g. user
Type string
// Secret used to authenticate the account
Secret string
} }
type GenerateOption func(o *GenerateOptions) type GenerateOption func(o *GenerateOptions)
// WithSecret for the generated account
func WithSecret(s string) GenerateOption {
return func(o *GenerateOptions) {
o.Secret = s
}
}
// WithType for the generated account
func WithType(t string) GenerateOption {
return func(o *GenerateOptions) {
o.Type = t
}
}
// WithMetadata for the generated account // WithMetadata for the generated account
func WithMetadata(md map[string]string) GenerateOption { func WithMetadata(md map[string]string) GenerateOption {
return func(o *GenerateOptions) { return func(o *GenerateOptions) {
@ -103,6 +123,13 @@ func WithNamespace(n string) GenerateOption {
} }
} }
// WithProvider for the generated account
func WithProvider(p string) GenerateOption {
return func(o *GenerateOptions) {
o.Provider = p
}
}
// 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
@ -113,16 +140,35 @@ func NewGenerateOptions(opts ...GenerateOption) GenerateOptions {
} }
type TokenOptions struct { type TokenOptions struct {
// TokenExpiry is the time the token should live for // ID for the account
TokenExpiry time.Duration ID string
// Secret for the account
Secret string
// RefreshToken is used to refesh a token
RefreshToken string
// Expiry is the time the token should live for
Expiry time.Duration
} }
type TokenOption func(o *TokenOptions) type TokenOption func(o *TokenOptions)
// WithTokenExpiry for the token // WithExpiry for the token
func WithTokenExpiry(ex time.Duration) TokenOption { func WithExpiry(ex time.Duration) TokenOption {
return func(o *TokenOptions) { return func(o *TokenOptions) {
o.TokenExpiry = ex o.Expiry = ex
}
}
func WithCredentials(id, secret string) TokenOption {
return func(o *TokenOptions) {
o.ID = id
o.Secret = secret
}
}
func WithToken(rt string) TokenOption {
return func(o *TokenOptions) {
o.RefreshToken = rt
} }
} }
@ -134,8 +180,8 @@ func NewTokenOptions(opts ...TokenOption) TokenOptions {
} }
// set defualt expiry of token // set defualt expiry of token
if options.TokenExpiry == 0 { if options.Expiry == 0 {
options.TokenExpiry = time.Minute options.Expiry = time.Minute
} }
return options return options

View File

@ -25,7 +25,7 @@ func (b *basic) Options() provider.Options {
return b.opts return b.opts
} }
func (b *basic) Endpoint() string { func (b *basic) Endpoint(...provider.EndpointOption) string {
return "" return ""
} }

View File

@ -3,7 +3,6 @@ package oauth
import ( import (
"fmt" "fmt"
"net/url" "net/url"
"strings"
"github.com/micro/go-micro/v2/auth/provider" "github.com/micro/go-micro/v2/auth/provider"
) )
@ -29,17 +28,25 @@ func (o *oauth) Options() provider.Options {
return o.opts return o.opts
} }
func (o *oauth) Endpoint() string { func (o *oauth) Endpoint(opts ...provider.EndpointOption) string {
var options provider.EndpointOptions
for _, o := range opts {
o(&options)
}
params := make(url.Values) params := make(url.Values)
params.Add("response_type", "code") params.Add("response_type", "code")
if len(options.State) > 0 {
params.Add("state", options.State)
}
if clientID := o.opts.ClientID; len(clientID) > 0 { if clientID := o.opts.ClientID; len(clientID) > 0 {
params.Add("client_id", clientID) params.Add("client_id", clientID)
} }
if scope := o.opts.Scope; len(scope) > 0 { if scope := o.opts.Scope; len(scope) > 0 {
// spaces are url encoded since this cannot be passed in env vars params.Add("scope", scope)
params.Add("scope", strings.ReplaceAll(scope, "%20", " "))
} }
if redir := o.Redirect(); len(redir) > 0 { if redir := o.Redirect(); len(redir) > 0 {

View File

@ -12,7 +12,7 @@ type Provider interface {
// Options returns the options of a provider // Options returns the options of a provider
Options() Options Options() Options
// Endpoint for the provider // Endpoint for the provider
Endpoint() string Endpoint(...EndpointOption) string
// Redirect url incase of UI // Redirect url incase of UI
Redirect() string Redirect() string
} }
@ -26,3 +26,15 @@ type Grant struct {
// Scopes associated with grant // Scopes associated with grant
Scopes []string Scopes []string
} }
type EndpointOptions struct {
State string
}
type EndpointOption func(*EndpointOptions)
func WithState(c string) EndpointOption {
return func(o *EndpointOptions) {
o.State = c
}
}

View File

@ -119,17 +119,13 @@ func (m *ListAccountsResponse) GetAccounts() []*Account {
} }
type Token struct { type Token struct {
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` RefreshToken string `protobuf:"bytes,2,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
Created int64 `protobuf:"varint,3,opt,name=created,proto3" json:"created,omitempty"` Created int64 `protobuf:"varint,3,opt,name=created,proto3" json:"created,omitempty"`
Expiry int64 `protobuf:"varint,4,opt,name=expiry,proto3" json:"expiry,omitempty"` Expiry int64 `protobuf:"varint,4,opt,name=expiry,proto3" json:"expiry,omitempty"`
Subject string `protobuf:"bytes,5,opt,name=subject,proto3" json:"subject,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
Roles []string `protobuf:"bytes,6,rep,name=roles,proto3" json:"roles,omitempty"` XXX_unrecognized []byte `json:"-"`
Metadata map[string]string `protobuf:"bytes,7,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` XXX_sizecache int32 `json:"-"`
Namespace string `protobuf:"bytes,8,opt,name=namespace,proto3" json:"namespace,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *Token) Reset() { *m = Token{} } func (m *Token) Reset() { *m = Token{} }
@ -157,16 +153,16 @@ func (m *Token) XXX_DiscardUnknown() {
var xxx_messageInfo_Token proto.InternalMessageInfo var xxx_messageInfo_Token proto.InternalMessageInfo
func (m *Token) GetToken() string { func (m *Token) GetAccessToken() string {
if m != nil { if m != nil {
return m.Token return m.AccessToken
} }
return "" return ""
} }
func (m *Token) GetType() string { func (m *Token) GetRefreshToken() string {
if m != nil { if m != nil {
return m.Type return m.RefreshToken
} }
return "" return ""
} }
@ -185,40 +181,14 @@ func (m *Token) GetExpiry() int64 {
return 0 return 0
} }
func (m *Token) GetSubject() string {
if m != nil {
return m.Subject
}
return ""
}
func (m *Token) GetRoles() []string {
if m != nil {
return m.Roles
}
return nil
}
func (m *Token) GetMetadata() map[string]string {
if m != nil {
return m.Metadata
}
return nil
}
func (m *Token) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
type Account struct { type Account struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Secret string `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,omitempty"` Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Roles []string `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty"` Roles []string `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty"`
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Namespace string `protobuf:"bytes,5,opt,name=namespace,proto3" json:"namespace,omitempty"` Namespace string `protobuf:"bytes,5,opt,name=namespace,proto3" json:"namespace,omitempty"`
Provider string `protobuf:"bytes,6,opt,name=provider,proto3" json:"provider,omitempty"`
Secret string `protobuf:"bytes,7,opt,name=secret,proto3" json:"secret,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -256,9 +226,9 @@ func (m *Account) GetId() string {
return "" return ""
} }
func (m *Account) GetSecret() string { func (m *Account) GetType() string {
if m != nil { if m != nil {
return m.Secret return m.Type
} }
return "" return ""
} }
@ -284,6 +254,20 @@ func (m *Account) GetNamespace() string {
return "" return ""
} }
func (m *Account) GetProvider() string {
if m != nil {
return m.Provider
}
return ""
}
func (m *Account) GetSecret() string {
if m != nil {
return m.Secret
}
return ""
}
type Resource struct { type Resource struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
@ -344,6 +328,9 @@ type GenerateRequest struct {
Roles []string `protobuf:"bytes,2,rep,name=roles,proto3" json:"roles,omitempty"` Roles []string `protobuf:"bytes,2,rep,name=roles,proto3" json:"roles,omitempty"`
Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Namespace string `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"` Namespace string `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"`
Secret string `protobuf:"bytes,5,opt,name=secret,proto3" json:"secret,omitempty"`
Type string `protobuf:"bytes,6,opt,name=type,proto3" json:"type,omitempty"`
Provider string `protobuf:"bytes,7,opt,name=provider,proto3" json:"provider,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -402,6 +389,27 @@ func (m *GenerateRequest) GetNamespace() string {
return "" return ""
} }
func (m *GenerateRequest) GetSecret() string {
if m != nil {
return m.Secret
}
return ""
}
func (m *GenerateRequest) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (m *GenerateRequest) GetProvider() string {
if m != nil {
return m.Provider
}
return ""
}
type GenerateResponse struct { type GenerateResponse struct {
Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
@ -678,7 +686,8 @@ func (m *InspectResponse) GetAccount() *Account {
type TokenRequest struct { type TokenRequest struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Secret string `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,omitempty"` Secret string `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,omitempty"`
TokenExpiry int64 `protobuf:"varint,3,opt,name=token_expiry,json=tokenExpiry,proto3" json:"token_expiry,omitempty"` RefreshToken string `protobuf:"bytes,3,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
TokenExpiry int64 `protobuf:"varint,4,opt,name=token_expiry,json=tokenExpiry,proto3" json:"token_expiry,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -723,6 +732,13 @@ func (m *TokenRequest) GetSecret() string {
return "" return ""
} }
func (m *TokenRequest) GetRefreshToken() string {
if m != nil {
return m.RefreshToken
}
return ""
}
func (m *TokenRequest) GetTokenExpiry() int64 { func (m *TokenRequest) GetTokenExpiry() int64 {
if m != nil { if m != nil {
return m.TokenExpiry return m.TokenExpiry
@ -1079,7 +1095,6 @@ func init() {
proto.RegisterType((*ListAccountsRequest)(nil), "go.micro.auth.ListAccountsRequest") proto.RegisterType((*ListAccountsRequest)(nil), "go.micro.auth.ListAccountsRequest")
proto.RegisterType((*ListAccountsResponse)(nil), "go.micro.auth.ListAccountsResponse") proto.RegisterType((*ListAccountsResponse)(nil), "go.micro.auth.ListAccountsResponse")
proto.RegisterType((*Token)(nil), "go.micro.auth.Token") proto.RegisterType((*Token)(nil), "go.micro.auth.Token")
proto.RegisterMapType((map[string]string)(nil), "go.micro.auth.Token.MetadataEntry")
proto.RegisterType((*Account)(nil), "go.micro.auth.Account") proto.RegisterType((*Account)(nil), "go.micro.auth.Account")
proto.RegisterMapType((map[string]string)(nil), "go.micro.auth.Account.MetadataEntry") proto.RegisterMapType((map[string]string)(nil), "go.micro.auth.Account.MetadataEntry")
proto.RegisterType((*Resource)(nil), "go.micro.auth.Resource") proto.RegisterType((*Resource)(nil), "go.micro.auth.Resource")
@ -1108,59 +1123,61 @@ func init() {
} }
var fileDescriptor_11312eec02fd5712 = []byte{ var fileDescriptor_11312eec02fd5712 = []byte{
// 860 bytes of a gzipped FileDescriptorProto // 896 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xdd, 0x8e, 0xdb, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x4b, 0x6f, 0xdb, 0x46,
0x14, 0x5e, 0xff, 0xc4, 0xf1, 0x9e, 0xfc, 0x6c, 0x34, 0xdd, 0x16, 0x2b, 0xfd, 0x21, 0x18, 0x84, 0x10, 0x36, 0x49, 0x89, 0x92, 0x47, 0x0f, 0x0b, 0x1b, 0x27, 0x25, 0x98, 0x47, 0x1d, 0xa6, 0x28,
0x96, 0x8a, 0x3a, 0x28, 0xbd, 0xe0, 0xa7, 0x12, 0x22, 0x6a, 0xa2, 0xd0, 0x42, 0x83, 0xb0, 0x8a, 0xdc, 0xa0, 0xa1, 0x0b, 0xe5, 0xd0, 0x47, 0x2e, 0x35, 0x22, 0x41, 0x4d, 0xda, 0xa8, 0x28, 0x91,
0x0a, 0x17, 0x08, 0x79, 0x9d, 0xa3, 0x5d, 0xb3, 0x89, 0x1d, 0x3c, 0xe3, 0x15, 0x79, 0x02, 0xee, 0x22, 0xbd, 0x14, 0x01, 0x43, 0x4d, 0x6d, 0xc2, 0x32, 0xc9, 0xee, 0x2e, 0x8d, 0xfa, 0x52, 0xa0,
0x78, 0x14, 0x9e, 0xa8, 0x97, 0x48, 0xbc, 0x06, 0x9a, 0xf1, 0x8c, 0x37, 0x71, 0x9c, 0x55, 0x84, 0xa7, 0xde, 0x7a, 0xea, 0x4f, 0xe8, 0xcf, 0xea, 0xbd, 0x7f, 0xa3, 0xe0, 0x3e, 0x28, 0x91, 0xa2,
0x72, 0xc1, 0xdd, 0x9c, 0x99, 0x33, 0xdf, 0x7c, 0xdf, 0xe7, 0x33, 0xc7, 0x03, 0x9f, 0x5e, 0x44, 0x02, 0xa3, 0xf5, 0x21, 0xb7, 0x9d, 0x07, 0x67, 0xe6, 0xfb, 0x66, 0x76, 0xb8, 0xf0, 0xe9, 0x49,
0xec, 0x32, 0x3b, 0xf7, 0xc2, 0x64, 0xd1, 0x5f, 0x44, 0x61, 0x9a, 0xf4, 0x2f, 0x92, 0x27, 0xf9, 0xcc, 0x4f, 0xf3, 0x37, 0x7e, 0x94, 0x9e, 0x1f, 0x9d, 0xc7, 0x11, 0x4d, 0x8f, 0x4e, 0xd2, 0x47,
0x20, 0xc8, 0xd8, 0x65, 0x9f, 0x62, 0x7a, 0x1d, 0x85, 0xd8, 0x5f, 0xa6, 0x09, 0xcb, 0xa7, 0x3c, 0xf2, 0x10, 0xe6, 0xfc, 0xf4, 0x88, 0x21, 0xbd, 0x88, 0x23, 0x3c, 0xca, 0x68, 0xca, 0xa5, 0xca,
0x31, 0x24, 0xad, 0x8b, 0xc4, 0x13, 0x79, 0x1e, 0x9f, 0x74, 0xef, 0xc2, 0x9d, 0x6f, 0x23, 0xca, 0x17, 0x47, 0x32, 0x38, 0x49, 0x7d, 0xe1, 0xe7, 0x17, 0x4a, 0xef, 0x26, 0xdc, 0xf8, 0x26, 0x66,
0x86, 0x61, 0x98, 0x64, 0x31, 0xa3, 0x3e, 0xfe, 0x96, 0x21, 0x65, 0xee, 0x4b, 0x38, 0xdd, 0x9c, 0xfc, 0x38, 0x8a, 0xd2, 0x3c, 0xe1, 0x2c, 0xc0, 0x9f, 0x73, 0x64, 0xdc, 0x7b, 0x0e, 0xfb, 0x55,
0xa6, 0xcb, 0x24, 0xa6, 0x48, 0x06, 0x60, 0x07, 0x72, 0xce, 0xd1, 0x7a, 0xc6, 0x59, 0x63, 0x70, 0x35, 0xcb, 0xd2, 0x84, 0x21, 0x19, 0x43, 0x37, 0x54, 0x3a, 0xc7, 0x38, 0xb0, 0x0e, 0x7b, 0xe3,
0xcf, 0xdb, 0x00, 0xf4, 0xe4, 0x16, 0xbf, 0xc8, 0x73, 0xff, 0xd2, 0xa1, 0xf6, 0x3a, 0xb9, 0xc2, 0x5b, 0x7e, 0x25, 0xa0, 0xaf, 0x3e, 0x09, 0x4a, 0x3f, 0xef, 0x37, 0x03, 0xda, 0x2f, 0xd3, 0x33,
0x98, 0x9c, 0x42, 0x8d, 0xf1, 0x81, 0xa3, 0xf5, 0xb4, 0xb3, 0x63, 0x3f, 0x0f, 0x08, 0x01, 0x93, 0x4c, 0xc8, 0x7d, 0xe8, 0x87, 0x51, 0x84, 0x8c, 0xbd, 0xe6, 0x85, 0xec, 0x18, 0x07, 0xc6, 0xe1,
0xad, 0x96, 0xe8, 0xe8, 0x62, 0x52, 0x8c, 0x89, 0x03, 0xf5, 0x30, 0xc5, 0x80, 0xe1, 0xcc, 0x31, 0x6e, 0xd0, 0x93, 0x3a, 0xe9, 0xf2, 0x00, 0x06, 0x14, 0x7f, 0xa2, 0xc8, 0x4e, 0x95, 0x8f, 0x29,
0x7a, 0xda, 0x99, 0xe1, 0xab, 0x90, 0xdc, 0x03, 0x0b, 0x7f, 0x5f, 0x46, 0xe9, 0xca, 0x31, 0xc5, 0x7c, 0xfa, 0x4a, 0x29, 0x9d, 0x1c, 0xe8, 0x44, 0x14, 0x43, 0x8e, 0x0b, 0xc7, 0x3a, 0x30, 0x0e,
0x82, 0x8c, 0xf8, 0x0e, 0x9a, 0x9d, 0xff, 0x8a, 0x21, 0x73, 0x6a, 0x02, 0x48, 0x85, 0xfc, 0xd4, 0xad, 0x40, 0x8b, 0xe4, 0x16, 0xd8, 0xf8, 0x4b, 0x16, 0xd3, 0x4b, 0xa7, 0x25, 0x0c, 0x4a, 0xf2,
0x34, 0x99, 0x23, 0x75, 0xac, 0x9e, 0xc1, 0x4f, 0x15, 0x01, 0xf9, 0x12, 0xec, 0x05, 0xb2, 0x60, 0xfe, 0x34, 0xa1, 0xa3, 0x2a, 0x23, 0x43, 0x30, 0xe3, 0x85, 0xca, 0x6d, 0xc6, 0x0b, 0x42, 0xa0,
0x16, 0xb0, 0xc0, 0xa9, 0x0b, 0x25, 0x6e, 0x49, 0x89, 0xe0, 0xec, 0xbd, 0x92, 0x49, 0xe3, 0x98, 0xc5, 0x2f, 0x33, 0x54, 0x99, 0xc4, 0x99, 0xec, 0x43, 0x9b, 0xa6, 0x4b, 0x64, 0x8e, 0x75, 0x60,
0xa5, 0x2b, 0xbf, 0xd8, 0x43, 0x1e, 0xc0, 0x71, 0x1c, 0x2c, 0x90, 0x2e, 0x83, 0x10, 0x1d, 0x5b, 0x1d, 0xee, 0x06, 0x52, 0x20, 0x5f, 0x42, 0xf7, 0x1c, 0x79, 0xb8, 0x08, 0x79, 0xe8, 0xb4, 0x04,
0x9c, 0x78, 0x33, 0xd1, 0x7d, 0x06, 0xad, 0x8d, 0x8d, 0xa4, 0x03, 0xc6, 0x15, 0xae, 0xa4, 0x70, 0xfa, 0x0f, 0x9a, 0xd1, 0xfb, 0x2f, 0x94, 0xdb, 0x34, 0xe1, 0xf4, 0x32, 0x28, 0xbf, 0x22, 0x77,
0x3e, 0xe4, 0xb4, 0xae, 0x83, 0x79, 0xa6, 0x74, 0xe7, 0xc1, 0x17, 0xfa, 0x67, 0x9a, 0xfb, 0xb7, 0x60, 0x37, 0x09, 0xcf, 0x91, 0x65, 0x61, 0x84, 0x4e, 0x5b, 0x24, 0x5c, 0x29, 0x88, 0x0b, 0xdd,
0x06, 0x75, 0x69, 0x23, 0x69, 0x83, 0x1e, 0xcd, 0xe4, 0x36, 0x3d, 0x12, 0xf2, 0x29, 0x86, 0x29, 0x8c, 0xa6, 0x17, 0xf1, 0x02, 0xa9, 0x63, 0x0b, 0x63, 0x29, 0x17, 0xc8, 0x18, 0x46, 0x14, 0xb9,
0x32, 0xb9, 0x4d, 0x46, 0x37, 0x22, 0x8d, 0x75, 0x91, 0x5f, 0xad, 0x89, 0x34, 0x85, 0xc8, 0x0f, 0xd3, 0x11, 0x16, 0x25, 0xb9, 0x4f, 0x60, 0x50, 0x49, 0x46, 0x46, 0x60, 0x9d, 0xe1, 0xa5, 0xc2,
0xaa, 0x3f, 0xd7, 0x7e, 0x32, 0x6b, 0x07, 0x95, 0x39, 0x05, 0xdb, 0x47, 0x9a, 0x64, 0x69, 0x88, 0x57, 0x1c, 0x0b, 0x30, 0x17, 0xe1, 0x32, 0xd7, 0x08, 0xa5, 0xf0, 0x85, 0xf9, 0x99, 0xe1, 0xcd,
0xbc, 0x06, 0x38, 0xaa, 0xdc, 0x28, 0xc6, 0x95, 0x75, 0xd1, 0x05, 0x1b, 0xe3, 0xd9, 0x32, 0x89, 0xa1, 0x1b, 0x20, 0x4b, 0x73, 0x1a, 0x61, 0x41, 0x43, 0x51, 0x89, 0xfa, 0x50, 0x9c, 0x1b, 0xa9,
0x62, 0x26, 0x0a, 0xe3, 0xd8, 0x2f, 0x62, 0xf7, 0xad, 0x06, 0x27, 0x13, 0x8c, 0x31, 0x0d, 0x18, 0x71, 0xa1, 0x8b, 0xc9, 0x22, 0x4b, 0xe3, 0x84, 0x0b, 0xf6, 0x77, 0x83, 0x52, 0xf6, 0xfe, 0x32,
0xca, 0x3a, 0xde, 0xb2, 0xaf, 0xb0, 0x49, 0x5f, 0xb7, 0xe9, 0xeb, 0x35, 0x9b, 0x0c, 0x61, 0xd3, 0x61, 0x6f, 0x86, 0x09, 0xd2, 0x90, 0xa3, 0x1a, 0xa5, 0x0d, 0xba, 0x4b, 0x6a, 0xcd, 0x75, 0x6a,
0xc7, 0x25, 0x9b, 0x4a, 0xb8, 0xfb, 0xd9, 0x65, 0x1e, 0xd4, 0xae, 0x11, 0x74, 0x6e, 0x58, 0xc8, 0xbf, 0x5a, 0xa3, 0xd6, 0x12, 0xd4, 0x7e, 0x5c, 0xa3, 0xb6, 0x16, 0xf7, 0x6a, 0x14, 0xb7, 0xea,
0xeb, 0xf8, 0x09, 0xd4, 0xe5, 0x35, 0x13, 0x18, 0xbb, 0x6f, 0xa3, 0x4a, 0x73, 0xdf, 0x40, 0x73, 0x14, 0xaf, 0x68, 0x6c, 0xaf, 0xd3, 0x58, 0x22, 0xb5, 0xab, 0x48, 0xcb, 0x76, 0x74, 0xaa, 0xed,
0x92, 0x06, 0x31, 0x53, 0x06, 0x11, 0x30, 0xb9, 0x07, 0xca, 0x78, 0x3e, 0x26, 0x4f, 0xc1, 0x4e, 0xf8, 0x7f, 0xb4, 0x4f, 0x60, 0xb4, 0x42, 0xa3, 0x6e, 0xd6, 0x27, 0xd0, 0x51, 0x37, 0x46, 0xc4,
0xe5, 0x87, 0x11, 0x34, 0x1a, 0x83, 0x77, 0x4a, 0xb0, 0xea, 0xbb, 0xf9, 0x45, 0xa2, 0x7b, 0x02, 0xd8, 0x7e, 0xb1, 0xb4, 0x9b, 0xf7, 0x0a, 0xfa, 0x33, 0x1a, 0x26, 0x5c, 0x13, 0x4d, 0xa0, 0x55,
0x2d, 0x09, 0x9c, 0x73, 0x73, 0x7f, 0x84, 0x96, 0x8f, 0xd7, 0xc9, 0x15, 0x1e, 0xfc, 0xa8, 0x0e, 0x70, 0xa9, 0x1b, 0x58, 0x9c, 0xc9, 0x63, 0xe8, 0x52, 0xd5, 0x60, 0x51, 0x46, 0x6f, 0xfc, 0x5e,
0xb4, 0x15, 0xb2, 0x3c, 0xeb, 0x43, 0x68, 0xbf, 0x88, 0xe9, 0x12, 0xc3, 0x42, 0x57, 0x65, 0xab, 0x2d, 0xac, 0xee, 0x7f, 0x50, 0x3a, 0x7a, 0x7b, 0x30, 0x50, 0x81, 0x65, 0x6d, 0xde, 0x0f, 0x30,
0x71, 0x9f, 0xc3, 0x49, 0x91, 0xf7, 0x9f, 0x2d, 0xfc, 0x09, 0x9a, 0xa2, 0x35, 0xec, 0xaa, 0xb1, 0x08, 0xf0, 0x22, 0x3d, 0xc3, 0x6b, 0x4f, 0x35, 0x82, 0xa1, 0x8e, 0xac, 0x72, 0x7d, 0x08, 0xc3,
0x5d, 0x57, 0xf4, 0x3d, 0x68, 0x0a, 0x16, 0xbf, 0xc8, 0xfe, 0x95, 0x37, 0xb6, 0x86, 0x98, 0x1b, 0x67, 0x09, 0xcb, 0x30, 0x2a, 0x71, 0xed, 0x43, 0x7b, 0x7d, 0x5d, 0x48, 0xc1, 0x7b, 0x0a, 0x7b,
0x8b, 0x29, 0xf7, 0x19, 0xb4, 0x24, 0xb4, 0x64, 0xf7, 0x78, 0x5d, 0x46, 0x63, 0x70, 0x5a, 0xd5, 0xa5, 0xdf, 0x7f, 0xa6, 0xf0, 0x57, 0xe8, 0x8b, 0x8d, 0xb2, 0x6d, 0x56, 0x57, 0xd3, 0x62, 0x56,
0xa2, 0x94, 0xb8, 0x3f, 0x35, 0x30, 0xfd, 0x6c, 0x8e, 0x5b, 0x84, 0x94, 0xf1, 0xfa, 0x0e, 0xe3, 0xa6, 0x65, 0x63, 0x4b, 0x59, 0x0d, 0x5b, 0xea, 0x3e, 0xf4, 0x85, 0xf1, 0x75, 0x65, 0x23, 0xf5,
0x8d, 0x3d, 0x8d, 0x27, 0x4f, 0xc0, 0x0a, 0xc2, 0x10, 0x29, 0x15, 0xa5, 0xdd, 0x1e, 0xdc, 0xdd, 0x84, 0x6e, 0x2a, 0xd7, 0xd2, 0x13, 0x18, 0xa8, 0xfc, 0x0a, 0xc2, 0xc3, 0x75, 0xac, 0xbd, 0xf1,
0xb6, 0x0a, 0x29, 0xf5, 0x65, 0x92, 0xfb, 0x87, 0x06, 0xad, 0xe7, 0xa2, 0x6d, 0x1f, 0xba, 0x04, 0x7e, 0x0d, 0x80, 0x74, 0x56, 0x0c, 0xfc, 0x61, 0x40, 0x2b, 0xc8, 0x97, 0xd8, 0xb4, 0xd0, 0x44,
0xd6, 0x98, 0x18, 0xfb, 0x30, 0xe9, 0x40, 0x5b, 0x11, 0x91, 0x15, 0xc3, 0xb9, 0x8d, 0x70, 0x8e, 0x77, 0xcc, 0x2d, 0xdd, 0xb1, 0xae, 0xd8, 0x1d, 0xf2, 0x08, 0x6c, 0xb9, 0x9b, 0x45, 0xed, 0xc3,
0xff, 0x0b, 0x6e, 0x8a, 0x88, 0xe4, 0xd6, 0x82, 0x06, 0xff, 0xf9, 0xaa, 0x7f, 0xf1, 0xe7, 0xd0, 0xf1, 0xcd, 0x4d, 0x3e, 0x91, 0xb1, 0x40, 0x39, 0x79, 0xbf, 0x1b, 0x30, 0x78, 0x2a, 0x16, 0xf1,
0xcc, 0x43, 0x59, 0x13, 0x1f, 0x41, 0x2d, 0xcd, 0x78, 0x0f, 0xcb, 0x7f, 0xc0, 0x77, 0xca, 0x8c, 0x75, 0xcf, 0xc9, 0x5a, 0x25, 0xd6, 0x55, 0x2a, 0x19, 0xc1, 0x50, 0x17, 0xa2, 0xc6, 0xaa, 0xa8,
0xb2, 0x39, 0xfa, 0x79, 0xc6, 0x63, 0x0f, 0xac, 0xfc, 0x34, 0xd2, 0x80, 0xfa, 0x0f, 0xd3, 0x6f, 0x6d, 0x82, 0x4b, 0x7c, 0x27, 0x6a, 0xd3, 0x85, 0xa8, 0xda, 0x06, 0xd0, 0x2b, 0x7e, 0xb6, 0xfa,
0xa6, 0xdf, 0xbd, 0x99, 0x76, 0x8e, 0x78, 0x30, 0xf1, 0x87, 0xd3, 0xd7, 0xe3, 0x51, 0x47, 0x23, 0xdf, 0xfb, 0x39, 0xf4, 0xa5, 0xa8, 0x66, 0xe2, 0x23, 0x68, 0xd3, 0xbc, 0x58, 0x98, 0xf2, 0x87,
0x00, 0xd6, 0x68, 0x3c, 0x7d, 0x31, 0x1e, 0x75, 0xf4, 0xc1, 0x3f, 0x1a, 0x98, 0xc3, 0x8c, 0x5d, 0x7b, 0xa3, 0x5e, 0x51, 0xbe, 0xc4, 0x40, 0x7a, 0x3c, 0xf4, 0xc1, 0x96, 0xd9, 0x48, 0x0f, 0x3a,
0x92, 0x57, 0x60, 0xab, 0x66, 0x43, 0x1e, 0xdd, 0xde, 0x0b, 0xbb, 0xef, 0xee, 0x5c, 0x97, 0x7a, 0xdf, 0xcf, 0xbf, 0x9e, 0x7f, 0xfb, 0x6a, 0x3e, 0xda, 0x29, 0x84, 0x59, 0x70, 0x3c, 0x7f, 0x39,
0x8e, 0xc8, 0x4b, 0xa8, 0xcb, 0x7b, 0x47, 0x1e, 0x96, 0xb2, 0x37, 0xef, 0x6d, 0xf7, 0xd1, 0xae, 0x9d, 0x8c, 0x0c, 0x02, 0x60, 0x4f, 0xa6, 0xf3, 0x67, 0xd3, 0xc9, 0xc8, 0x1c, 0xff, 0x63, 0x40,
0xe5, 0x02, 0x6b, 0xa4, 0x5e, 0x13, 0xf7, 0x2b, 0x2f, 0x83, 0xc4, 0x79, 0x50, 0xbd, 0xa8, 0x50, 0xeb, 0x38, 0xe7, 0xa7, 0xe4, 0x05, 0x74, 0xf5, 0x46, 0x22, 0xf7, 0xde, 0xbe, 0x78, 0xdd, 0xf7,
0x06, 0x3f, 0x83, 0xad, 0x1e, 0x37, 0xe4, 0x7b, 0x30, 0xb9, 0xc1, 0xa4, 0xfc, 0x00, 0xa8, 0x78, 0xb7, 0xda, 0x15, 0x9e, 0x1d, 0xf2, 0x1c, 0x3a, 0xea, 0x72, 0x92, 0xbb, 0x35, 0xef, 0xea, 0xe5,
0x18, 0x75, 0xdf, 0xbf, 0x35, 0xa7, 0x80, 0x7f, 0xab, 0x41, 0x8d, 0x7f, 0x08, 0x4a, 0x26, 0x60, 0x76, 0xef, 0x6d, 0x33, 0x97, 0xb1, 0x26, 0xfa, 0xf5, 0x70, 0xbb, 0xf1, 0x32, 0xa8, 0x38, 0x77,
0xe5, 0xa5, 0x47, 0xca, 0x94, 0x36, 0xae, 0x46, 0xf7, 0xe1, 0x8e, 0xd5, 0x42, 0xf7, 0x04, 0xac, 0x9a, 0x8d, 0x3a, 0xca, 0xf8, 0x47, 0xe8, 0xea, 0xc7, 0x0c, 0xf9, 0x0e, 0x5a, 0x05, 0xc1, 0xc4,
0xbc, 0x4e, 0xb6, 0x80, 0x36, 0xea, 0x78, 0x0b, 0xa8, 0x54, 0x5c, 0x47, 0x64, 0x28, 0xe5, 0x76, 0xab, 0x7d, 0xd3, 0xf0, 0x10, 0x72, 0x1f, 0xbc, 0xd5, 0xa7, 0x0c, 0xff, 0xb7, 0x01, 0xed, 0xa2,
0x2b, 0xa4, 0x28, 0x90, 0xfb, 0x95, 0x6b, 0x0a, 0xe2, 0xdc, 0x12, 0x6f, 0xc9, 0xa7, 0xff, 0x06, 0x11, 0x8c, 0xcc, 0xc0, 0x96, 0xa3, 0x47, 0xea, 0x25, 0x55, 0xae, 0x86, 0x7b, 0x77, 0x8b, 0xb5,
0x00, 0x00, 0xff, 0xff, 0x24, 0x1b, 0xf8, 0x32, 0x86, 0x0a, 0x00, 0x00, 0xc4, 0x3d, 0x03, 0x5b, 0xce, 0xc9, 0x46, 0xa0, 0xca, 0x1c, 0x6f, 0x04, 0xaa, 0x0d, 0xd7, 0x0e,
0x39, 0x56, 0x70, 0xdd, 0x06, 0x28, 0x3a, 0xc8, 0xed, 0x46, 0x9b, 0x0e, 0xf1, 0xc6, 0x16, 0x6f,
0xc7, 0xc7, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x4b, 0x8f, 0xf4, 0x22, 0x76, 0x0a, 0x00, 0x00,
} }

View File

@ -26,22 +26,20 @@ message ListAccountsResponse {
} }
message Token { message Token {
string token = 1; string access_token = 1;
string type = 2; string refresh_token = 2;
int64 created = 3; int64 created = 3;
int64 expiry = 4; int64 expiry = 4;
string subject = 5;
repeated string roles = 6;
map<string, string> metadata = 7;
string namespace = 8;
} }
message Account { message Account {
string id = 1; string id = 1;
string secret = 2; string type = 2;
repeated string roles = 3; repeated string roles = 3;
map<string, string> metadata = 4; map<string, string> metadata = 4;
string namespace = 5; string namespace = 5;
string provider = 6;
string secret = 7;
} }
message Resource{ message Resource{
@ -55,6 +53,9 @@ message GenerateRequest {
repeated string roles = 2; repeated string roles = 2;
map<string, string> metadata = 3; map<string, string> metadata = 3;
string namespace = 4; string namespace = 4;
string secret = 5;
string type = 6;
string provider = 7;
} }
message GenerateResponse { message GenerateResponse {
@ -86,7 +87,8 @@ message InspectResponse {
message TokenRequest { message TokenRequest {
string id = 1; string id = 1;
string secret = 2; string secret = 2;
int64 token_expiry = 3; string refresh_token = 3;
int64 token_expiry = 4;
} }
message TokenResponse { message TokenResponse {

View File

@ -77,7 +77,7 @@ func (s *svc) Init(opts ...auth.Option) {
tokenTimer := time.NewTicker(time.Minute) tokenTimer := time.NewTicker(time.Minute)
go func() { go func() {
s.loadToken() s.refreshToken()
for { for {
<-tokenTimer.C <-tokenTimer.C
@ -94,7 +94,7 @@ func (s *svc) Init(opts ...auth.Option) {
// all the services calling the auth service // all the services calling the auth service
// at the exact same time // at the exact same time
time.Sleep(jitter.Do(time.Second * 5)) time.Sleep(jitter.Do(time.Second * 5))
s.loadToken() s.refreshToken()
} }
}() }()
} }
@ -112,8 +112,11 @@ func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e
rsp, err := s.auth.Generate(context.TODO(), &pb.GenerateRequest{ rsp, err := s.auth.Generate(context.TODO(), &pb.GenerateRequest{
Id: id, Id: id,
Type: options.Type,
Secret: options.Secret,
Roles: options.Roles, Roles: options.Roles,
Metadata: options.Metadata, Metadata: options.Metadata,
Provider: options.Provider,
Namespace: options.Namespace, Namespace: options.Namespace,
}) })
if err != nil { if err != nil {
@ -191,23 +194,14 @@ func (s *svc) Verify(acc *auth.Account, res *auth.Resource) error {
// Inspect a token // Inspect a token
func (s *svc) Inspect(token string) (*auth.Account, error) { func (s *svc) Inspect(token string) (*auth.Account, error) {
// try to decode JWT locally and fall back to srv if an error // try to decode JWT locally and fall back to srv if an error occurs
// occurs, TODO: find a better way of determining if the token
// is a JWT, possibly update the interface to take an auth.Token
// and not just the string
if len(strings.Split(token, ".")) == 3 && s.jwt != nil { if len(strings.Split(token, ".")) == 3 && s.jwt != nil {
if tok, err := s.jwt.Inspect(token); err == nil { if acc, err := s.jwt.Inspect(token); err == nil {
return &auth.Account{ return acc, nil
ID: tok.Subject,
Roles: tok.Roles,
Metadata: tok.Metadata,
}, nil
} }
} }
rsp, err := s.auth.Inspect(context.TODO(), &pb.InspectRequest{ rsp, err := s.auth.Inspect(context.TODO(), &pb.InspectRequest{Token: token})
Token: token,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -216,13 +210,14 @@ func (s *svc) Inspect(token string) (*auth.Account, error) {
} }
// Token generation using an account ID and secret // Token generation using an account ID and secret
func (s *svc) Token(id, secret string, opts ...auth.TokenOption) (*auth.Token, error) { func (s *svc) Token(opts ...auth.TokenOption) (*auth.Token, error) {
options := auth.NewTokenOptions(opts...) options := auth.NewTokenOptions(opts...)
rsp, err := s.auth.Token(context.Background(), &pb.TokenRequest{ rsp, err := s.auth.Token(context.Background(), &pb.TokenRequest{
Id: id, Id: options.ID,
Secret: secret, Secret: options.Secret,
TokenExpiry: int64(options.TokenExpiry.Seconds()), RefreshToken: options.RefreshToken,
TokenExpiry: int64(options.Expiry.Seconds()),
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@ -286,13 +281,22 @@ func (s *svc) loadRules() {
s.rules = rsp.Rules s.rules = rsp.Rules
} }
// loadToken generates a new token for the service to use when making calls // refreshToken generates a new token for the service to use when making calls
func (s *svc) loadToken() { func (s *svc) refreshToken() {
rsp, err := s.auth.Token(context.TODO(), &pb.TokenRequest{ req := &pb.TokenRequest{
Id: s.Options().ID,
Secret: s.Options().Secret,
TokenExpiry: int64((time.Minute * 15).Seconds()), TokenExpiry: int64((time.Minute * 15).Seconds()),
}) }
if s.Options().Token == nil {
// we do not have a token, use the credentials to get one
req.Id = s.Options().ID
req.Secret = s.Options().Secret
} else {
// we have a token, refresh it
req.RefreshToken = s.Options().Token.RefreshToken
}
rsp, err := s.auth.Token(context.TODO(), req)
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
@ -306,13 +310,10 @@ func (s *svc) loadToken() {
func serializeToken(t *pb.Token) *auth.Token { func serializeToken(t *pb.Token) *auth.Token {
return &auth.Token{ return &auth.Token{
Token: t.Token, AccessToken: t.AccessToken,
Type: t.Type, RefreshToken: t.RefreshToken,
Created: time.Unix(t.Created, 0), Created: time.Unix(t.Created, 0),
Expiry: time.Unix(t.Expiry, 0), Expiry: time.Unix(t.Expiry, 0),
Subject: t.Subject,
Roles: t.Roles,
Metadata: t.Metadata,
} }
} }
@ -320,8 +321,9 @@ func serializeAccount(a *pb.Account) *auth.Account {
return &auth.Account{ return &auth.Account{
ID: a.Id, ID: a.Id,
Roles: a.Roles, Roles: a.Roles,
Metadata: a.Metadata,
Namespace: a.Namespace,
Secret: a.Secret, Secret: a.Secret,
Metadata: a.Metadata,
Provider: a.Provider,
Namespace: a.Namespace,
} }
} }

View File

@ -35,30 +35,19 @@ func NewTokenProvider(opts ...token.Option) token.Provider {
} }
// Generate a token for an account // Generate a token for an account
func (b *Basic) Generate(subject string, opts ...token.GenerateOption) (*auth.Token, error) { func (b *Basic) Generate(acc *auth.Account, opts ...token.GenerateOption) (*token.Token, error) {
options := token.NewGenerateOptions(opts...) options := token.NewGenerateOptions(opts...)
// construct the token
token := auth.Token{
Subject: subject,
Type: b.String(),
Token: uuid.New().String(),
Created: time.Now(),
Expiry: time.Now().Add(options.Expiry),
Metadata: options.Metadata,
Roles: options.Roles,
Namespace: options.Namespace,
}
// marshal the account to bytes // marshal the account to bytes
bytes, err := json.Marshal(token) bytes, err := json.Marshal(acc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// write to the store // write to the store
key := uuid.New().String()
err = b.store.Write(&store.Record{ err = b.store.Write(&store.Record{
Key: fmt.Sprintf("%v%v", StorePrefix, token.Token), Key: fmt.Sprintf("%v%v", StorePrefix, key),
Value: bytes, Value: bytes,
Expiry: options.Expiry, Expiry: options.Expiry,
}) })
@ -67,11 +56,15 @@ func (b *Basic) Generate(subject string, opts ...token.GenerateOption) (*auth.To
} }
// return the token // return the token
return &token, nil return &token.Token{
Token: key,
Created: time.Now(),
Expiry: time.Now().Add(options.Expiry),
}, nil
} }
// Inspect a token // Inspect a token
func (b *Basic) Inspect(t string) (*auth.Token, error) { func (b *Basic) Inspect(t string) (*auth.Account, error) {
// lookup the token in the store // lookup the token in the store
recs, err := b.store.Read(StorePrefix + t) recs, err := b.store.Read(StorePrefix + t)
if err == store.ErrNotFound { if err == store.ErrNotFound {
@ -82,18 +75,12 @@ func (b *Basic) Inspect(t string) (*auth.Token, error) {
bytes := recs[0].Value bytes := recs[0].Value
// unmarshal the bytes // unmarshal the bytes
var tok *auth.Token var acc *auth.Account
if err := json.Unmarshal(bytes, &tok); err != nil { if err := json.Unmarshal(bytes, &acc); err != nil {
return nil, err return nil, err
} }
// ensure the token hasn't expired, the store should return acc, nil
// expire the token but we're checking again
if tok.Expiry.Unix() < time.Now().Unix() {
return nil, token.ErrInvalidToken
}
return tok, err
} }
// String returns basic // String returns basic

View File

@ -2,8 +2,8 @@ package basic
import ( import (
"testing" "testing"
"time"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/auth/token" "github.com/micro/go-micro/v2/auth/token"
"github.com/micro/go-micro/v2/store/memory" "github.com/micro/go-micro/v2/store/memory"
) )
@ -12,7 +12,7 @@ func TestGenerate(t *testing.T) {
store := memory.NewStore() store := memory.NewStore()
b := NewTokenProvider(token.WithStore(store)) b := NewTokenProvider(token.WithStore(store))
_, err := b.Generate("test") _, err := b.Generate(&auth.Account{ID: "test"})
if err != nil { if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err) t.Fatalf("Generate returned %v error, expected nil", err)
} }
@ -35,12 +35,7 @@ func TestInspect(t *testing.T) {
roles := []string{"admin"} roles := []string{"admin"}
subject := "test" subject := "test"
opts := []token.GenerateOption{ tok, err := b.Generate(&auth.Account{ID: subject, Roles: roles, Metadata: md})
token.WithMetadata(md),
token.WithRoles(roles...),
}
tok, err := b.Generate(subject, opts...)
if err != nil { if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err) t.Fatalf("Generate returned %v error, expected nil", err)
} }
@ -49,8 +44,8 @@ func TestInspect(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Inspect returned %v error, expected nil", err) t.Fatalf("Inspect returned %v error, expected nil", err)
} }
if tok2.Subject != subject { if tok2.ID != subject {
t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.Subject, subject) t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.ID, subject)
} }
if len(tok2.Roles) != len(roles) { if len(tok2.Roles) != len(roles) {
t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles)) t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles))
@ -60,17 +55,6 @@ func TestInspect(t *testing.T) {
} }
}) })
t.Run("Expired token", func(t *testing.T) {
tok, err := b.Generate("foo", token.WithExpiry(-10*time.Second))
if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err)
}
if _, err = b.Inspect(tok.Token); err != token.ErrInvalidToken {
t.Fatalf("Inspect returned %v error, expected %v", err, token.ErrInvalidToken)
}
})
t.Run("Invalid token", func(t *testing.T) { t.Run("Invalid token", func(t *testing.T) {
_, err := b.Inspect("Invalid token") _, err := b.Inspect("Invalid token")
if err != token.ErrInvalidToken { if err != token.ErrInvalidToken {

View File

@ -11,7 +11,9 @@ import (
// authClaims to be encoded in the JWT // authClaims to be encoded in the JWT
type authClaims struct { type authClaims struct {
Type string `json:"type"`
Roles []string `json:"roles"` Roles []string `json:"roles"`
Provider string `json:"provider"`
Metadata map[string]string `json:"metadata"` Metadata map[string]string `json:"metadata"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
@ -31,7 +33,7 @@ func NewTokenProvider(opts ...token.Option) token.Provider {
} }
// Generate a new JWT // Generate a new JWT
func (j *JWT) Generate(subject string, opts ...token.GenerateOption) (*auth.Token, error) { func (j *JWT) Generate(acc *auth.Account, opts ...token.GenerateOption) (*token.Token, error) {
// decode the private key // decode the private key
priv, err := base64.StdEncoding.DecodeString(j.opts.PrivateKey) priv, err := base64.StdEncoding.DecodeString(j.opts.PrivateKey)
if err != nil { if err != nil {
@ -50,8 +52,8 @@ func (j *JWT) Generate(subject string, opts ...token.GenerateOption) (*auth.Toke
// 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{
options.Roles, options.Metadata, options.Namespace, jwt.StandardClaims{ acc.Type, acc.Roles, acc.Provider, acc.Metadata, acc.Namespace, jwt.StandardClaims{
Subject: subject, Subject: acc.ID,
ExpiresAt: expiry.Unix(), ExpiresAt: expiry.Unix(),
}, },
}) })
@ -61,20 +63,15 @@ func (j *JWT) Generate(subject string, opts ...token.GenerateOption) (*auth.Toke
} }
// return the token // return the token
return &auth.Token{ return &token.Token{
Subject: subject, Token: tok,
Token: tok, Expiry: expiry,
Type: j.String(), Created: time.Now(),
Created: time.Now(),
Expiry: expiry,
Roles: options.Roles,
Metadata: options.Metadata,
Namespace: options.Namespace,
}, nil }, nil
} }
// Inspect a JWT // Inspect a JWT
func (j *JWT) Inspect(t string) (*auth.Token, error) { func (j *JWT) Inspect(t string) (*auth.Account, error) {
// decode the public key // decode the public key
pub, err := base64.StdEncoding.DecodeString(j.opts.PublicKey) pub, err := base64.StdEncoding.DecodeString(j.opts.PublicKey)
if err != nil { if err != nil {
@ -99,11 +96,12 @@ func (j *JWT) Inspect(t string) (*auth.Token, error) {
} }
// return the token // return the token
return &auth.Token{ return &auth.Account{
Token: t, ID: claims.Subject,
Subject: claims.Subject, Type: claims.Type,
Metadata: claims.Metadata,
Roles: claims.Roles, Roles: claims.Roles,
Provider: claims.Provider,
Metadata: claims.Metadata,
Namespace: claims.Namespace, Namespace: claims.Namespace,
}, nil }, nil
} }

View File

@ -5,6 +5,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/auth/token" "github.com/micro/go-micro/v2/auth/token"
) )
@ -18,7 +19,7 @@ func TestGenerate(t *testing.T) {
token.WithPrivateKey(string(privKey)), token.WithPrivateKey(string(privKey)),
) )
_, err = j.Generate("test") _, err = j.Generate(&auth.Account{ID: "test"})
if err != nil { if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err) t.Fatalf("Generate returned %v error, expected nil", err)
} }
@ -44,12 +45,8 @@ func TestInspect(t *testing.T) {
roles := []string{"admin"} roles := []string{"admin"}
subject := "test" subject := "test"
opts := []token.GenerateOption{ acc := &auth.Account{ID: subject, Roles: roles, Metadata: md}
token.WithMetadata(md), tok, err := j.Generate(acc)
token.WithRoles(roles...),
}
tok, err := j.Generate(subject, opts...)
if err != nil { if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err) t.Fatalf("Generate returned %v error, expected nil", err)
} }
@ -58,8 +55,8 @@ func TestInspect(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Inspect returned %v error, expected nil", err) t.Fatalf("Inspect returned %v error, expected nil", err)
} }
if tok2.Subject != subject { if acc.ID != subject {
t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.Subject, subject) t.Errorf("Inspect returned %v as the token subject, expected %v", acc.ID, subject)
} }
if len(tok2.Roles) != len(roles) { if len(tok2.Roles) != len(roles) {
t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles)) t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles))
@ -70,7 +67,7 @@ func TestInspect(t *testing.T) {
}) })
t.Run("Expired token", func(t *testing.T) { t.Run("Expired token", func(t *testing.T) {
tok, err := j.Generate("foo", token.WithExpiry(-10*time.Second)) tok, err := j.Generate(&auth.Account{}, token.WithExpiry(-10*time.Second))
if err != nil { if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err) t.Fatalf("Generate returned %v error, expected nil", err)
} }

View File

@ -53,12 +53,6 @@ func NewOptions(opts ...Option) Options {
type GenerateOptions struct { type GenerateOptions struct {
// Expiry for the token // Expiry for the token
Expiry time.Duration Expiry time.Duration
// Metadata associated with the account
Metadata map[string]string
// Roles/scopes associated with the account
Roles []string
// Namespace the account belongs too
Namespace string
} }
type GenerateOption func(o *GenerateOptions) type GenerateOption func(o *GenerateOptions)
@ -70,27 +64,6 @@ func WithExpiry(d time.Duration) GenerateOption {
} }
} }
// WithMetadata for the token
func WithMetadata(md map[string]string) func(o *GenerateOptions) {
return func(o *GenerateOptions) {
o.Metadata = md
}
}
// WithRoles for the token
func WithRoles(rs ...string) func(o *GenerateOptions) {
return func(o *GenerateOptions) {
o.Roles = rs
}
}
// WithNamespace for the token
func WithNamespace(n string) func(o *GenerateOptions) {
return func(o *GenerateOptions) {
o.Namespace = 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

@ -2,6 +2,7 @@ package token
import ( import (
"errors" "errors"
"time"
"github.com/micro/go-micro/v2/auth" "github.com/micro/go-micro/v2/auth"
) )
@ -17,7 +18,16 @@ var (
// Provider generates and inspects tokens // Provider generates and inspects tokens
type Provider interface { type Provider interface {
Generate(subject string, opts ...GenerateOption) (*auth.Token, error) Generate(account *auth.Account, opts ...GenerateOption) (*Token, error)
Inspect(token string) (*auth.Token, error) Inspect(token string) (*auth.Account, error)
String() string String() string
} }
type Token struct {
// The actual token
Token string `json:"token"`
// Time of token creation
Created time.Time `json:"created"`
// Time of token expiry
Expiry time.Time `json:"expiry"`
}

View File

@ -135,7 +135,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
// was passed with the request, set the service token // was passed with the request, set the service token
var srvToken string var srvToken string
if g.opts.Auth != nil && g.opts.Auth.Options().Token != nil { if g.opts.Auth != nil && g.opts.Auth.Options().Token != nil {
srvToken = g.opts.Auth.Options().Token.Token srvToken = g.opts.Auth.Options().Token.AccessToken
} }
if (opts.ServiceToken || len(header["authorization"]) == 0) && len(srvToken) > 0 { if (opts.ServiceToken || len(header["authorization"]) == 0) && len(srvToken) > 0 {
header["authorization"] = auth.BearerScheme + srvToken header["authorization"] = auth.BearerScheme + srvToken

View File

@ -670,7 +670,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
if len(ctx.String("auth_public_key")) > 0 { if len(ctx.String("auth_public_key")) > 0 {
authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key"))) authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key")))
} }
if len(ctx.String("auth_private_key")) > 0 { if len(ctx.String("auth_private_key")) > 0 {
authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key"))) authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key")))
} }