diff --git a/auth/auth.go b/auth/auth.go index 4c175110..206d2d76 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -5,7 +5,6 @@ import ( "context" "encoding/json" "errors" - "fmt" "time" "github.com/micro/go-micro/v2/metadata" @@ -42,8 +41,8 @@ type Auth interface { Verify(acc *Account, res *Resource) error // Inspect a token Inspect(token string) (*Account, error) - // Token generated using an account ID and secret - Token(id, secret string, opts ...TokenOption) (*Token, error) + // Token generated using refresh token + Token(opts ...TokenOption) (*Token, error) // String returns the name of the implementation String() string } @@ -60,36 +59,32 @@ type Resource struct { // Account provided by an auth provider type Account struct { - // ID of the account (UUIDV4, email or username) + // ID of the account e.g. email ID string `json:"id"` - // Secret used to renew the account - Secret string `json:"secret"` + // Type of the account, e.g. service + Type string `json:"type"` + // Provider who issued the account + Provider string `json:"provider"` // Roles associated with the Account Roles []string `json:"roles"` // Any other associated metadata Metadata map[string]string `json:"metadata"` // Namespace the account belongs to, default blank Namespace string `json:"namespace"` + // Secret for the account, e.g. the password + Secret string `json:"secret"` } // Token can be short or long lived type Token struct { - // The token itself - Token string `json:"token"` - // Type of token, e.g. JWT - Type string `json:"type"` + // The token to be used for accessing resources + AccessToken string `json:"access_token"` + // RefreshToken to be used to generate a new token + RefreshToken string `json:"refresh_token"` // Time of token creation Created time.Time `json:"created"` // Time of token 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 ( @@ -132,8 +127,3 @@ func ContextWithAccount(ctx context.Context, account *Account) (context.Context, // generate a new context with the MetadataKey set 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)) -} diff --git a/auth/default.go b/auth/default.go index c637f7c6..20f16a4f 100644 --- a/auth/default.go +++ b/auth/default.go @@ -40,8 +40,8 @@ func (n *noop) Generate(id string, opts ...GenerateOption) (*Account, error) { return &Account{ ID: id, Roles: options.Roles, + Secret: options.Secret, Metadata: options.Metadata, - Secret: uuid.New().String(), }, nil } @@ -68,6 +68,6 @@ func (n *noop) Inspect(token string) (*Account, error) { } // 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 } diff --git a/auth/options.go b/auth/options.go index 90bbc1df..929cf674 100644 --- a/auth/options.go +++ b/auth/options.go @@ -10,13 +10,13 @@ import ( type Options struct { // ID is the services auth ID ID string - // Secret is used to generate new tokens + // Secret is used to authenticate the service Secret string // Token is the services token used to authenticate itself Token *Token - // Public key base64 encoded + // PublicKey for decoding JWTs PublicKey string - // Private key base64 encoded + // PrivateKey for encoding JWTs PrivateKey string // Provider is an auth provider Provider provider.Provider @@ -78,10 +78,30 @@ type GenerateOptions struct { Roles []string // Namespace the account belongs too 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) +// 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 func WithMetadata(md map[string]string) GenerateOption { 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 func NewGenerateOptions(opts ...GenerateOption) GenerateOptions { var options GenerateOptions @@ -113,16 +140,35 @@ func NewGenerateOptions(opts ...GenerateOption) GenerateOptions { } type TokenOptions struct { - // TokenExpiry is the time the token should live for - TokenExpiry time.Duration + // ID for the account + 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) -// WithTokenExpiry for the token -func WithTokenExpiry(ex time.Duration) TokenOption { +// WithExpiry for the token +func WithExpiry(ex time.Duration) TokenOption { 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 - if options.TokenExpiry == 0 { - options.TokenExpiry = time.Minute + if options.Expiry == 0 { + options.Expiry = time.Minute } return options diff --git a/auth/provider/basic/basic.go b/auth/provider/basic/basic.go index 413053ef..ed19190a 100644 --- a/auth/provider/basic/basic.go +++ b/auth/provider/basic/basic.go @@ -25,7 +25,7 @@ func (b *basic) Options() provider.Options { return b.opts } -func (b *basic) Endpoint() string { +func (b *basic) Endpoint(...provider.EndpointOption) string { return "" } diff --git a/auth/provider/oauth/oauth.go b/auth/provider/oauth/oauth.go index 52ae08a6..45b79c8e 100644 --- a/auth/provider/oauth/oauth.go +++ b/auth/provider/oauth/oauth.go @@ -3,7 +3,6 @@ package oauth import ( "fmt" "net/url" - "strings" "github.com/micro/go-micro/v2/auth/provider" ) @@ -29,17 +28,25 @@ func (o *oauth) Options() provider.Options { 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.Add("response_type", "code") + if len(options.State) > 0 { + params.Add("state", options.State) + } + if clientID := o.opts.ClientID; len(clientID) > 0 { params.Add("client_id", clientID) } if scope := o.opts.Scope; len(scope) > 0 { - // spaces are url encoded since this cannot be passed in env vars - params.Add("scope", strings.ReplaceAll(scope, "%20", " ")) + params.Add("scope", scope) } if redir := o.Redirect(); len(redir) > 0 { diff --git a/auth/provider/provider.go b/auth/provider/provider.go index 86a4504d..26f80034 100644 --- a/auth/provider/provider.go +++ b/auth/provider/provider.go @@ -12,7 +12,7 @@ type Provider interface { // Options returns the options of a provider Options() Options // Endpoint for the provider - Endpoint() string + Endpoint(...EndpointOption) string // Redirect url incase of UI Redirect() string } @@ -26,3 +26,15 @@ type Grant struct { // Scopes associated with grant Scopes []string } + +type EndpointOptions struct { + State string +} + +type EndpointOption func(*EndpointOptions) + +func WithState(c string) EndpointOption { + return func(o *EndpointOptions) { + o.State = c + } +} diff --git a/auth/service/proto/auth.pb.go b/auth/service/proto/auth.pb.go index 0b941edc..3cffecb4 100644 --- a/auth/service/proto/auth.pb.go +++ b/auth/service/proto/auth.pb.go @@ -119,17 +119,13 @@ func (m *ListAccountsResponse) GetAccounts() []*Account { } type Token struct { - Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` - Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,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"` - Subject string `protobuf:"bytes,5,opt,name=subject,proto3" json:"subject,omitempty"` - Roles []string `protobuf:"bytes,6,rep,name=roles,proto3" json:"roles,omitempty"` - 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"` - Namespace string `protobuf:"bytes,8,opt,name=namespace,proto3" json:"namespace,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,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"` + Expiry int64 `protobuf:"varint,4,opt,name=expiry,proto3" json:"expiry,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Token) Reset() { *m = Token{} } @@ -157,16 +153,16 @@ func (m *Token) XXX_DiscardUnknown() { var xxx_messageInfo_Token proto.InternalMessageInfo -func (m *Token) GetToken() string { +func (m *Token) GetAccessToken() string { if m != nil { - return m.Token + return m.AccessToken } return "" } -func (m *Token) GetType() string { +func (m *Token) GetRefreshToken() string { if m != nil { - return m.Type + return m.RefreshToken } return "" } @@ -185,40 +181,14 @@ func (m *Token) GetExpiry() int64 { 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 { 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"` 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"` + 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_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -256,9 +226,9 @@ func (m *Account) GetId() string { return "" } -func (m *Account) GetSecret() string { +func (m *Account) GetType() string { if m != nil { - return m.Secret + return m.Type } return "" } @@ -284,6 +254,20 @@ func (m *Account) GetNamespace() string { 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 { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,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"` 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"` + 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_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -402,6 +389,27 @@ func (m *GenerateRequest) GetNamespace() string { 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 { Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -678,7 +686,8 @@ func (m *InspectResponse) GetAccount() *Account { type TokenRequest struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,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_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -723,6 +732,13 @@ func (m *TokenRequest) GetSecret() string { return "" } +func (m *TokenRequest) GetRefreshToken() string { + if m != nil { + return m.RefreshToken + } + return "" +} + func (m *TokenRequest) GetTokenExpiry() int64 { if m != nil { return m.TokenExpiry @@ -1079,7 +1095,6 @@ func init() { proto.RegisterType((*ListAccountsRequest)(nil), "go.micro.auth.ListAccountsRequest") proto.RegisterType((*ListAccountsResponse)(nil), "go.micro.auth.ListAccountsResponse") 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.RegisterMapType((map[string]string)(nil), "go.micro.auth.Account.MetadataEntry") proto.RegisterType((*Resource)(nil), "go.micro.auth.Resource") @@ -1108,59 +1123,61 @@ func init() { } var fileDescriptor_11312eec02fd5712 = []byte{ - // 860 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xdd, 0x8e, 0xdb, 0x44, - 0x14, 0x5e, 0xff, 0xc4, 0xf1, 0x9e, 0xfc, 0x6c, 0x34, 0xdd, 0x16, 0x2b, 0xfd, 0x21, 0x18, 0x84, - 0x96, 0x8a, 0x3a, 0x28, 0xbd, 0xe0, 0xa7, 0x12, 0x22, 0x6a, 0xa2, 0xd0, 0x42, 0x83, 0xb0, 0x8a, - 0x0a, 0x17, 0x08, 0x79, 0x9d, 0xa3, 0x5d, 0xb3, 0x89, 0x1d, 0x3c, 0xe3, 0x15, 0x79, 0x02, 0xee, - 0x78, 0x14, 0x9e, 0xa8, 0x97, 0x48, 0xbc, 0x06, 0x9a, 0xf1, 0x8c, 0x37, 0x71, 0x9c, 0x55, 0x84, - 0x72, 0xc1, 0xdd, 0x9c, 0x99, 0x33, 0xdf, 0x7c, 0xdf, 0xe7, 0x33, 0xc7, 0x03, 0x9f, 0x5e, 0x44, - 0xec, 0x32, 0x3b, 0xf7, 0xc2, 0x64, 0xd1, 0x5f, 0x44, 0x61, 0x9a, 0xf4, 0x2f, 0x92, 0x27, 0xf9, - 0x20, 0xc8, 0xd8, 0x65, 0x9f, 0x62, 0x7a, 0x1d, 0x85, 0xd8, 0x5f, 0xa6, 0x09, 0xcb, 0xa7, 0x3c, - 0x31, 0x24, 0xad, 0x8b, 0xc4, 0x13, 0x79, 0x1e, 0x9f, 0x74, 0xef, 0xc2, 0x9d, 0x6f, 0x23, 0xca, - 0x86, 0x61, 0x98, 0x64, 0x31, 0xa3, 0x3e, 0xfe, 0x96, 0x21, 0x65, 0xee, 0x4b, 0x38, 0xdd, 0x9c, - 0xa6, 0xcb, 0x24, 0xa6, 0x48, 0x06, 0x60, 0x07, 0x72, 0xce, 0xd1, 0x7a, 0xc6, 0x59, 0x63, 0x70, - 0xcf, 0xdb, 0x00, 0xf4, 0xe4, 0x16, 0xbf, 0xc8, 0x73, 0xff, 0xd2, 0xa1, 0xf6, 0x3a, 0xb9, 0xc2, - 0x98, 0x9c, 0x42, 0x8d, 0xf1, 0x81, 0xa3, 0xf5, 0xb4, 0xb3, 0x63, 0x3f, 0x0f, 0x08, 0x01, 0x93, - 0xad, 0x96, 0xe8, 0xe8, 0x62, 0x52, 0x8c, 0x89, 0x03, 0xf5, 0x30, 0xc5, 0x80, 0xe1, 0xcc, 0x31, - 0x7a, 0xda, 0x99, 0xe1, 0xab, 0x90, 0xdc, 0x03, 0x0b, 0x7f, 0x5f, 0x46, 0xe9, 0xca, 0x31, 0xc5, - 0x82, 0x8c, 0xf8, 0x0e, 0x9a, 0x9d, 0xff, 0x8a, 0x21, 0x73, 0x6a, 0x02, 0x48, 0x85, 0xfc, 0xd4, - 0x34, 0x99, 0x23, 0x75, 0xac, 0x9e, 0xc1, 0x4f, 0x15, 0x01, 0xf9, 0x12, 0xec, 0x05, 0xb2, 0x60, - 0x16, 0xb0, 0xc0, 0xa9, 0x0b, 0x25, 0x6e, 0x49, 0x89, 0xe0, 0xec, 0xbd, 0x92, 0x49, 0xe3, 0x98, - 0xa5, 0x2b, 0xbf, 0xd8, 0x43, 0x1e, 0xc0, 0x71, 0x1c, 0x2c, 0x90, 0x2e, 0x83, 0x10, 0x1d, 0x5b, - 0x9c, 0x78, 0x33, 0xd1, 0x7d, 0x06, 0xad, 0x8d, 0x8d, 0xa4, 0x03, 0xc6, 0x15, 0xae, 0xa4, 0x70, - 0x3e, 0xe4, 0xb4, 0xae, 0x83, 0x79, 0xa6, 0x74, 0xe7, 0xc1, 0x17, 0xfa, 0x67, 0x9a, 0xfb, 0xb7, - 0x06, 0x75, 0x69, 0x23, 0x69, 0x83, 0x1e, 0xcd, 0xe4, 0x36, 0x3d, 0x12, 0xf2, 0x29, 0x86, 0x29, - 0x32, 0xb9, 0x4d, 0x46, 0x37, 0x22, 0x8d, 0x75, 0x91, 0x5f, 0xad, 0x89, 0x34, 0x85, 0xc8, 0x0f, - 0xaa, 0x3f, 0xd7, 0x7e, 0x32, 0x6b, 0x07, 0x95, 0x39, 0x05, 0xdb, 0x47, 0x9a, 0x64, 0x69, 0x88, - 0xbc, 0x06, 0x38, 0xaa, 0xdc, 0x28, 0xc6, 0x95, 0x75, 0xd1, 0x05, 0x1b, 0xe3, 0xd9, 0x32, 0x89, - 0x62, 0x26, 0x0a, 0xe3, 0xd8, 0x2f, 0x62, 0xf7, 0xad, 0x06, 0x27, 0x13, 0x8c, 0x31, 0x0d, 0x18, - 0xca, 0x3a, 0xde, 0xb2, 0xaf, 0xb0, 0x49, 0x5f, 0xb7, 0xe9, 0xeb, 0x35, 0x9b, 0x0c, 0x61, 0xd3, - 0xc7, 0x25, 0x9b, 0x4a, 0xb8, 0xfb, 0xd9, 0x65, 0x1e, 0xd4, 0xae, 0x11, 0x74, 0x6e, 0x58, 0xc8, - 0xeb, 0xf8, 0x09, 0xd4, 0xe5, 0x35, 0x13, 0x18, 0xbb, 0x6f, 0xa3, 0x4a, 0x73, 0xdf, 0x40, 0x73, - 0x92, 0x06, 0x31, 0x53, 0x06, 0x11, 0x30, 0xb9, 0x07, 0xca, 0x78, 0x3e, 0x26, 0x4f, 0xc1, 0x4e, - 0xe5, 0x87, 0x11, 0x34, 0x1a, 0x83, 0x77, 0x4a, 0xb0, 0xea, 0xbb, 0xf9, 0x45, 0xa2, 0x7b, 0x02, - 0x2d, 0x09, 0x9c, 0x73, 0x73, 0x7f, 0x84, 0x96, 0x8f, 0xd7, 0xc9, 0x15, 0x1e, 0xfc, 0xa8, 0x0e, - 0xb4, 0x15, 0xb2, 0x3c, 0xeb, 0x43, 0x68, 0xbf, 0x88, 0xe9, 0x12, 0xc3, 0x42, 0x57, 0x65, 0xab, - 0x71, 0x9f, 0xc3, 0x49, 0x91, 0xf7, 0x9f, 0x2d, 0xfc, 0x09, 0x9a, 0xa2, 0x35, 0xec, 0xaa, 0xb1, - 0x5d, 0x57, 0xf4, 0x3d, 0x68, 0x0a, 0x16, 0xbf, 0xc8, 0xfe, 0x95, 0x37, 0xb6, 0x86, 0x98, 0x1b, - 0x8b, 0x29, 0xf7, 0x19, 0xb4, 0x24, 0xb4, 0x64, 0xf7, 0x78, 0x5d, 0x46, 0x63, 0x70, 0x5a, 0xd5, - 0xa2, 0x94, 0xb8, 0x3f, 0x35, 0x30, 0xfd, 0x6c, 0x8e, 0x5b, 0x84, 0x94, 0xf1, 0xfa, 0x0e, 0xe3, - 0x8d, 0x3d, 0x8d, 0x27, 0x4f, 0xc0, 0x0a, 0xc2, 0x10, 0x29, 0x15, 0xa5, 0xdd, 0x1e, 0xdc, 0xdd, - 0xb6, 0x0a, 0x29, 0xf5, 0x65, 0x92, 0xfb, 0x87, 0x06, 0xad, 0xe7, 0xa2, 0x6d, 0x1f, 0xba, 0x04, - 0xd6, 0x98, 0x18, 0xfb, 0x30, 0xe9, 0x40, 0x5b, 0x11, 0x91, 0x15, 0xc3, 0xb9, 0x8d, 0x70, 0x8e, - 0xff, 0x0b, 0x6e, 0x8a, 0x88, 0xe4, 0xd6, 0x82, 0x06, 0xff, 0xf9, 0xaa, 0x7f, 0xf1, 0xe7, 0xd0, - 0xcc, 0x43, 0x59, 0x13, 0x1f, 0x41, 0x2d, 0xcd, 0x78, 0x0f, 0xcb, 0x7f, 0xc0, 0x77, 0xca, 0x8c, - 0xb2, 0x39, 0xfa, 0x79, 0xc6, 0x63, 0x0f, 0xac, 0xfc, 0x34, 0xd2, 0x80, 0xfa, 0x0f, 0xd3, 0x6f, - 0xa6, 0xdf, 0xbd, 0x99, 0x76, 0x8e, 0x78, 0x30, 0xf1, 0x87, 0xd3, 0xd7, 0xe3, 0x51, 0x47, 0x23, - 0x00, 0xd6, 0x68, 0x3c, 0x7d, 0x31, 0x1e, 0x75, 0xf4, 0xc1, 0x3f, 0x1a, 0x98, 0xc3, 0x8c, 0x5d, - 0x92, 0x57, 0x60, 0xab, 0x66, 0x43, 0x1e, 0xdd, 0xde, 0x0b, 0xbb, 0xef, 0xee, 0x5c, 0x97, 0x7a, - 0x8e, 0xc8, 0x4b, 0xa8, 0xcb, 0x7b, 0x47, 0x1e, 0x96, 0xb2, 0x37, 0xef, 0x6d, 0xf7, 0xd1, 0xae, - 0xe5, 0x02, 0x6b, 0xa4, 0x5e, 0x13, 0xf7, 0x2b, 0x2f, 0x83, 0xc4, 0x79, 0x50, 0xbd, 0xa8, 0x50, - 0x06, 0x3f, 0x83, 0xad, 0x1e, 0x37, 0xe4, 0x7b, 0x30, 0xb9, 0xc1, 0xa4, 0xfc, 0x00, 0xa8, 0x78, - 0x18, 0x75, 0xdf, 0xbf, 0x35, 0xa7, 0x80, 0x7f, 0xab, 0x41, 0x8d, 0x7f, 0x08, 0x4a, 0x26, 0x60, - 0xe5, 0xa5, 0x47, 0xca, 0x94, 0x36, 0xae, 0x46, 0xf7, 0xe1, 0x8e, 0xd5, 0x42, 0xf7, 0x04, 0xac, - 0xbc, 0x4e, 0xb6, 0x80, 0x36, 0xea, 0x78, 0x0b, 0xa8, 0x54, 0x5c, 0x47, 0x64, 0x28, 0xe5, 0x76, - 0x2b, 0xa4, 0x28, 0x90, 0xfb, 0x95, 0x6b, 0x0a, 0xe2, 0xdc, 0x12, 0x6f, 0xc9, 0xa7, 0xff, 0x06, - 0x00, 0x00, 0xff, 0xff, 0x24, 0x1b, 0xf8, 0x32, 0x86, 0x0a, 0x00, 0x00, + // 896 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0x4b, 0x6f, 0xdb, 0x46, + 0x10, 0x36, 0x49, 0x89, 0x92, 0x47, 0x0f, 0x0b, 0x1b, 0x27, 0x25, 0x98, 0x47, 0x1d, 0xa6, 0x28, + 0xdc, 0xa0, 0xa1, 0x0b, 0xe5, 0xd0, 0x47, 0x2e, 0x35, 0x22, 0x41, 0x4d, 0xda, 0xa8, 0x28, 0x91, + 0x22, 0xbd, 0x14, 0x01, 0x43, 0x4d, 0x6d, 0xc2, 0x32, 0xc9, 0xee, 0x2e, 0x8d, 0xfa, 0x52, 0xa0, + 0xa7, 0xde, 0x7a, 0xea, 0x4f, 0xe8, 0xcf, 0xea, 0xbd, 0x7f, 0xa3, 0xe0, 0x3e, 0x28, 0x91, 0xa2, + 0x02, 0xa3, 0xf5, 0x21, 0xb7, 0x9d, 0x07, 0x67, 0xe6, 0xfb, 0x66, 0x76, 0xb8, 0xf0, 0xe9, 0x49, + 0xcc, 0x4f, 0xf3, 0x37, 0x7e, 0x94, 0x9e, 0x1f, 0x9d, 0xc7, 0x11, 0x4d, 0x8f, 0x4e, 0xd2, 0x47, + 0xf2, 0x10, 0xe6, 0xfc, 0xf4, 0x88, 0x21, 0xbd, 0x88, 0x23, 0x3c, 0xca, 0x68, 0xca, 0xa5, 0xca, + 0x17, 0x47, 0x32, 0x38, 0x49, 0x7d, 0xe1, 0xe7, 0x17, 0x4a, 0xef, 0x26, 0xdc, 0xf8, 0x26, 0x66, + 0xfc, 0x38, 0x8a, 0xd2, 0x3c, 0xe1, 0x2c, 0xc0, 0x9f, 0x73, 0x64, 0xdc, 0x7b, 0x0e, 0xfb, 0x55, + 0x35, 0xcb, 0xd2, 0x84, 0x21, 0x19, 0x43, 0x37, 0x54, 0x3a, 0xc7, 0x38, 0xb0, 0x0e, 0x7b, 0xe3, + 0x5b, 0x7e, 0x25, 0xa0, 0xaf, 0x3e, 0x09, 0x4a, 0x3f, 0xef, 0x37, 0x03, 0xda, 0x2f, 0xd3, 0x33, + 0x4c, 0xc8, 0x7d, 0xe8, 0x87, 0x51, 0x84, 0x8c, 0xbd, 0xe6, 0x85, 0xec, 0x18, 0x07, 0xc6, 0xe1, + 0x6e, 0xd0, 0x93, 0x3a, 0xe9, 0xf2, 0x00, 0x06, 0x14, 0x7f, 0xa2, 0xc8, 0x4e, 0x95, 0x8f, 0x29, + 0x7c, 0xfa, 0x4a, 0x29, 0x9d, 0x1c, 0xe8, 0x44, 0x14, 0x43, 0x8e, 0x0b, 0xc7, 0x3a, 0x30, 0x0e, + 0xad, 0x40, 0x8b, 0xe4, 0x16, 0xd8, 0xf8, 0x4b, 0x16, 0xd3, 0x4b, 0xa7, 0x25, 0x0c, 0x4a, 0xf2, + 0xfe, 0x34, 0xa1, 0xa3, 0x2a, 0x23, 0x43, 0x30, 0xe3, 0x85, 0xca, 0x6d, 0xc6, 0x0b, 0x42, 0xa0, + 0xc5, 0x2f, 0x33, 0x54, 0x99, 0xc4, 0x99, 0xec, 0x43, 0x9b, 0xa6, 0x4b, 0x64, 0x8e, 0x75, 0x60, + 0x1d, 0xee, 0x06, 0x52, 0x20, 0x5f, 0x42, 0xf7, 0x1c, 0x79, 0xb8, 0x08, 0x79, 0xe8, 0xb4, 0x04, + 0xfa, 0x0f, 0x9a, 0xd1, 0xfb, 0x2f, 0x94, 0xdb, 0x34, 0xe1, 0xf4, 0x32, 0x28, 0xbf, 0x22, 0x77, + 0x60, 0x37, 0x09, 0xcf, 0x91, 0x65, 0x61, 0x84, 0x4e, 0x5b, 0x24, 0x5c, 0x29, 0x88, 0x0b, 0xdd, + 0x8c, 0xa6, 0x17, 0xf1, 0x02, 0xa9, 0x63, 0x0b, 0x63, 0x29, 0x17, 0xc8, 0x18, 0x46, 0x14, 0xb9, + 0xd3, 0x11, 0x16, 0x25, 0xb9, 0x4f, 0x60, 0x50, 0x49, 0x46, 0x46, 0x60, 0x9d, 0xe1, 0xa5, 0xc2, + 0x57, 0x1c, 0x0b, 0x30, 0x17, 0xe1, 0x32, 0xd7, 0x08, 0xa5, 0xf0, 0x85, 0xf9, 0x99, 0xe1, 0xcd, + 0xa1, 0x1b, 0x20, 0x4b, 0x73, 0x1a, 0x61, 0x41, 0x43, 0x51, 0x89, 0xfa, 0x50, 0x9c, 0x1b, 0xa9, + 0x71, 0xa1, 0x8b, 0xc9, 0x22, 0x4b, 0xe3, 0x84, 0x0b, 0xf6, 0x77, 0x83, 0x52, 0xf6, 0xfe, 0x32, + 0x61, 0x6f, 0x86, 0x09, 0xd2, 0x90, 0xa3, 0x1a, 0xa5, 0x0d, 0xba, 0x4b, 0x6a, 0xcd, 0x75, 0x6a, + 0xbf, 0x5a, 0xa3, 0xd6, 0x12, 0xd4, 0x7e, 0x5c, 0xa3, 0xb6, 0x16, 0xf7, 0x6a, 0x14, 0xb7, 0xea, + 0x14, 0xaf, 0x68, 0x6c, 0xaf, 0xd3, 0x58, 0x22, 0xb5, 0xab, 0x48, 0xcb, 0x76, 0x74, 0xaa, 0xed, + 0xf8, 0x7f, 0xb4, 0x4f, 0x60, 0xb4, 0x42, 0xa3, 0x6e, 0xd6, 0x27, 0xd0, 0x51, 0x37, 0x46, 0xc4, + 0xd8, 0x7e, 0xb1, 0xb4, 0x9b, 0xf7, 0x0a, 0xfa, 0x33, 0x1a, 0x26, 0x5c, 0x13, 0x4d, 0xa0, 0x55, + 0x70, 0xa9, 0x1b, 0x58, 0x9c, 0xc9, 0x63, 0xe8, 0x52, 0xd5, 0x60, 0x51, 0x46, 0x6f, 0xfc, 0x5e, + 0x2d, 0xac, 0xee, 0x7f, 0x50, 0x3a, 0x7a, 0x7b, 0x30, 0x50, 0x81, 0x65, 0x6d, 0xde, 0x0f, 0x30, + 0x08, 0xf0, 0x22, 0x3d, 0xc3, 0x6b, 0x4f, 0x35, 0x82, 0xa1, 0x8e, 0xac, 0x72, 0x7d, 0x08, 0xc3, + 0x67, 0x09, 0xcb, 0x30, 0x2a, 0x71, 0xed, 0x43, 0x7b, 0x7d, 0x5d, 0x48, 0xc1, 0x7b, 0x0a, 0x7b, + 0xa5, 0xdf, 0x7f, 0xa6, 0xf0, 0x57, 0xe8, 0x8b, 0x8d, 0xb2, 0x6d, 0x56, 0x57, 0xd3, 0x62, 0x56, + 0xa6, 0x65, 0x63, 0x4b, 0x59, 0x0d, 0x5b, 0xea, 0x3e, 0xf4, 0x85, 0xf1, 0x75, 0x65, 0x23, 0xf5, + 0x84, 0x6e, 0x2a, 0xd7, 0xd2, 0x13, 0x18, 0xa8, 0xfc, 0x0a, 0xc2, 0xc3, 0x75, 0xac, 0xbd, 0xf1, + 0x7e, 0x0d, 0x80, 0x74, 0x56, 0x0c, 0xfc, 0x61, 0x40, 0x2b, 0xc8, 0x97, 0xd8, 0xb4, 0xd0, 0x44, + 0x77, 0xcc, 0x2d, 0xdd, 0xb1, 0xae, 0xd8, 0x1d, 0xf2, 0x08, 0x6c, 0xb9, 0x9b, 0x45, 0xed, 0xc3, + 0xf1, 0xcd, 0x4d, 0x3e, 0x91, 0xb1, 0x40, 0x39, 0x79, 0xbf, 0x1b, 0x30, 0x78, 0x2a, 0x16, 0xf1, + 0x75, 0xcf, 0xc9, 0x5a, 0x25, 0xd6, 0x55, 0x2a, 0x19, 0xc1, 0x50, 0x17, 0xa2, 0xc6, 0xaa, 0xa8, + 0x6d, 0x82, 0x4b, 0x7c, 0x27, 0x6a, 0xd3, 0x85, 0xa8, 0xda, 0x06, 0xd0, 0x2b, 0x7e, 0xb6, 0xfa, + 0xdf, 0xfb, 0x39, 0xf4, 0xa5, 0xa8, 0x66, 0xe2, 0x23, 0x68, 0xd3, 0xbc, 0x58, 0x98, 0xf2, 0x87, + 0x7b, 0xa3, 0x5e, 0x51, 0xbe, 0xc4, 0x40, 0x7a, 0x3c, 0xf4, 0xc1, 0x96, 0xd9, 0x48, 0x0f, 0x3a, + 0xdf, 0xcf, 0xbf, 0x9e, 0x7f, 0xfb, 0x6a, 0x3e, 0xda, 0x29, 0x84, 0x59, 0x70, 0x3c, 0x7f, 0x39, + 0x9d, 0x8c, 0x0c, 0x02, 0x60, 0x4f, 0xa6, 0xf3, 0x67, 0xd3, 0xc9, 0xc8, 0x1c, 0xff, 0x63, 0x40, + 0xeb, 0x38, 0xe7, 0xa7, 0xe4, 0x05, 0x74, 0xf5, 0x46, 0x22, 0xf7, 0xde, 0xbe, 0x78, 0xdd, 0xf7, + 0xb7, 0xda, 0x15, 0x9e, 0x1d, 0xf2, 0x1c, 0x3a, 0xea, 0x72, 0x92, 0xbb, 0x35, 0xef, 0xea, 0xe5, + 0x76, 0xef, 0x6d, 0x33, 0x97, 0xb1, 0x26, 0xfa, 0xf5, 0x70, 0xbb, 0xf1, 0x32, 0xa8, 0x38, 0x77, + 0x9a, 0x8d, 0x3a, 0xca, 0xf8, 0x47, 0xe8, 0xea, 0xc7, 0x0c, 0xf9, 0x0e, 0x5a, 0x05, 0xc1, 0xc4, + 0xab, 0x7d, 0xd3, 0xf0, 0x10, 0x72, 0x1f, 0xbc, 0xd5, 0xa7, 0x0c, 0xff, 0xb7, 0x01, 0xed, 0xa2, + 0x11, 0x8c, 0xcc, 0xc0, 0x96, 0xa3, 0x47, 0xea, 0x25, 0x55, 0xae, 0x86, 0x7b, 0x77, 0x8b, 0xb5, + 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, } diff --git a/auth/service/proto/auth.proto b/auth/service/proto/auth.proto index ba53076b..d7d09418 100644 --- a/auth/service/proto/auth.proto +++ b/auth/service/proto/auth.proto @@ -26,22 +26,20 @@ message ListAccountsResponse { } message Token { - string token = 1; - string type = 2; + string access_token = 1; + string refresh_token = 2; int64 created = 3; int64 expiry = 4; - string subject = 5; - repeated string roles = 6; - map<string, string> metadata = 7; - string namespace = 8; } message Account { string id = 1; - string secret = 2; + string type = 2; repeated string roles = 3; map<string, string> metadata = 4; string namespace = 5; + string provider = 6; + string secret = 7; } message Resource{ @@ -55,6 +53,9 @@ message GenerateRequest { repeated string roles = 2; map<string, string> metadata = 3; string namespace = 4; + string secret = 5; + string type = 6; + string provider = 7; } message GenerateResponse { @@ -86,7 +87,8 @@ message InspectResponse { message TokenRequest { string id = 1; string secret = 2; - int64 token_expiry = 3; + string refresh_token = 3; + int64 token_expiry = 4; } message TokenResponse { diff --git a/auth/service/service.go b/auth/service/service.go index 0cc11d98..a0ce48b7 100644 --- a/auth/service/service.go +++ b/auth/service/service.go @@ -77,7 +77,7 @@ func (s *svc) Init(opts ...auth.Option) { tokenTimer := time.NewTicker(time.Minute) go func() { - s.loadToken() + s.refreshToken() for { <-tokenTimer.C @@ -94,7 +94,7 @@ func (s *svc) Init(opts ...auth.Option) { // all the services calling the auth service // at the exact same time 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{ Id: id, + Type: options.Type, + Secret: options.Secret, Roles: options.Roles, Metadata: options.Metadata, + Provider: options.Provider, Namespace: options.Namespace, }) if err != nil { @@ -191,23 +194,14 @@ func (s *svc) Verify(acc *auth.Account, res *auth.Resource) error { // Inspect a token func (s *svc) Inspect(token string) (*auth.Account, error) { - // try to decode JWT locally and fall back to srv if an error - // 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 + // try to decode JWT locally and fall back to srv if an error occurs if len(strings.Split(token, ".")) == 3 && s.jwt != nil { - if tok, err := s.jwt.Inspect(token); err == nil { - return &auth.Account{ - ID: tok.Subject, - Roles: tok.Roles, - Metadata: tok.Metadata, - }, nil + if acc, err := s.jwt.Inspect(token); err == nil { + return acc, nil } } - rsp, err := s.auth.Inspect(context.TODO(), &pb.InspectRequest{ - Token: token, - }) + rsp, err := s.auth.Inspect(context.TODO(), &pb.InspectRequest{Token: token}) if err != nil { return nil, err } @@ -216,13 +210,14 @@ func (s *svc) Inspect(token string) (*auth.Account, error) { } // 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...) rsp, err := s.auth.Token(context.Background(), &pb.TokenRequest{ - Id: id, - Secret: secret, - TokenExpiry: int64(options.TokenExpiry.Seconds()), + Id: options.ID, + Secret: options.Secret, + RefreshToken: options.RefreshToken, + TokenExpiry: int64(options.Expiry.Seconds()), }) if err != nil { return nil, err @@ -286,13 +281,22 @@ func (s *svc) loadRules() { s.rules = rsp.Rules } -// loadToken generates a new token for the service to use when making calls -func (s *svc) loadToken() { - rsp, err := s.auth.Token(context.TODO(), &pb.TokenRequest{ - Id: s.Options().ID, - Secret: s.Options().Secret, +// refreshToken generates a new token for the service to use when making calls +func (s *svc) refreshToken() { + req := &pb.TokenRequest{ 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() defer s.Unlock() @@ -306,13 +310,10 @@ func (s *svc) loadToken() { func serializeToken(t *pb.Token) *auth.Token { return &auth.Token{ - Token: t.Token, - Type: t.Type, - Created: time.Unix(t.Created, 0), - Expiry: time.Unix(t.Expiry, 0), - Subject: t.Subject, - Roles: t.Roles, - Metadata: t.Metadata, + AccessToken: t.AccessToken, + RefreshToken: t.RefreshToken, + Created: time.Unix(t.Created, 0), + Expiry: time.Unix(t.Expiry, 0), } } @@ -320,8 +321,9 @@ func serializeAccount(a *pb.Account) *auth.Account { return &auth.Account{ ID: a.Id, Roles: a.Roles, - Metadata: a.Metadata, - Namespace: a.Namespace, Secret: a.Secret, + Metadata: a.Metadata, + Provider: a.Provider, + Namespace: a.Namespace, } } diff --git a/auth/token/basic/basic.go b/auth/token/basic/basic.go index 34b79f92..364e2f3a 100644 --- a/auth/token/basic/basic.go +++ b/auth/token/basic/basic.go @@ -35,30 +35,19 @@ func NewTokenProvider(opts ...token.Option) token.Provider { } // 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...) - // 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 - bytes, err := json.Marshal(token) + bytes, err := json.Marshal(acc) if err != nil { return nil, err } // write to the store + key := uuid.New().String() err = b.store.Write(&store.Record{ - Key: fmt.Sprintf("%v%v", StorePrefix, token.Token), + Key: fmt.Sprintf("%v%v", StorePrefix, key), Value: bytes, Expiry: options.Expiry, }) @@ -67,11 +56,15 @@ func (b *Basic) Generate(subject string, opts ...token.GenerateOption) (*auth.To } // return the token - return &token, nil + return &token.Token{ + Token: key, + Created: time.Now(), + Expiry: time.Now().Add(options.Expiry), + }, nil } // 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 recs, err := b.store.Read(StorePrefix + t) if err == store.ErrNotFound { @@ -82,18 +75,12 @@ func (b *Basic) Inspect(t string) (*auth.Token, error) { bytes := recs[0].Value // unmarshal the bytes - var tok *auth.Token - if err := json.Unmarshal(bytes, &tok); err != nil { + var acc *auth.Account + if err := json.Unmarshal(bytes, &acc); err != nil { return nil, err } - // ensure the token hasn't expired, the store should - // expire the token but we're checking again - if tok.Expiry.Unix() < time.Now().Unix() { - return nil, token.ErrInvalidToken - } - - return tok, err + return acc, nil } // String returns basic diff --git a/auth/token/basic/basic_test.go b/auth/token/basic/basic_test.go index 4498db3c..127e201d 100644 --- a/auth/token/basic/basic_test.go +++ b/auth/token/basic/basic_test.go @@ -2,8 +2,8 @@ package basic import ( "testing" - "time" + "github.com/micro/go-micro/v2/auth" "github.com/micro/go-micro/v2/auth/token" "github.com/micro/go-micro/v2/store/memory" ) @@ -12,7 +12,7 @@ func TestGenerate(t *testing.T) { store := memory.NewStore() b := NewTokenProvider(token.WithStore(store)) - _, err := b.Generate("test") + _, err := b.Generate(&auth.Account{ID: "test"}) if err != nil { t.Fatalf("Generate returned %v error, expected nil", err) } @@ -35,12 +35,7 @@ func TestInspect(t *testing.T) { roles := []string{"admin"} subject := "test" - opts := []token.GenerateOption{ - token.WithMetadata(md), - token.WithRoles(roles...), - } - - tok, err := b.Generate(subject, opts...) + tok, err := b.Generate(&auth.Account{ID: subject, Roles: roles, Metadata: md}) if err != nil { t.Fatalf("Generate returned %v error, expected nil", err) } @@ -49,8 +44,8 @@ func TestInspect(t *testing.T) { if err != nil { t.Fatalf("Inspect returned %v error, expected nil", err) } - if tok2.Subject != subject { - t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.Subject, subject) + if tok2.ID != subject { + t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.ID, subject) } if 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) { _, err := b.Inspect("Invalid token") if err != token.ErrInvalidToken { diff --git a/auth/token/jwt/jwt.go b/auth/token/jwt/jwt.go index e35ac5e7..a633736d 100644 --- a/auth/token/jwt/jwt.go +++ b/auth/token/jwt/jwt.go @@ -11,7 +11,9 @@ import ( // authClaims to be encoded in the JWT type authClaims struct { + Type string `json:"type"` Roles []string `json:"roles"` + Provider string `json:"provider"` Metadata map[string]string `json:"metadata"` Namespace string `json:"namespace"` @@ -31,7 +33,7 @@ func NewTokenProvider(opts ...token.Option) token.Provider { } // 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 priv, err := base64.StdEncoding.DecodeString(j.opts.PrivateKey) if err != nil { @@ -50,8 +52,8 @@ func (j *JWT) Generate(subject string, opts ...token.GenerateOption) (*auth.Toke // generate the JWT expiry := time.Now().Add(options.Expiry) t := jwt.NewWithClaims(jwt.SigningMethodRS256, authClaims{ - options.Roles, options.Metadata, options.Namespace, jwt.StandardClaims{ - Subject: subject, + acc.Type, acc.Roles, acc.Provider, acc.Metadata, acc.Namespace, jwt.StandardClaims{ + Subject: acc.ID, ExpiresAt: expiry.Unix(), }, }) @@ -61,20 +63,15 @@ func (j *JWT) Generate(subject string, opts ...token.GenerateOption) (*auth.Toke } // return the token - return &auth.Token{ - Subject: subject, - Token: tok, - Type: j.String(), - Created: time.Now(), - Expiry: expiry, - Roles: options.Roles, - Metadata: options.Metadata, - Namespace: options.Namespace, + return &token.Token{ + Token: tok, + Expiry: expiry, + Created: time.Now(), }, nil } // 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 pub, err := base64.StdEncoding.DecodeString(j.opts.PublicKey) if err != nil { @@ -99,11 +96,12 @@ func (j *JWT) Inspect(t string) (*auth.Token, error) { } // return the token - return &auth.Token{ - Token: t, - Subject: claims.Subject, - Metadata: claims.Metadata, + return &auth.Account{ + ID: claims.Subject, + Type: claims.Type, Roles: claims.Roles, + Provider: claims.Provider, + Metadata: claims.Metadata, Namespace: claims.Namespace, }, nil } diff --git a/auth/token/jwt/jwt_test.go b/auth/token/jwt/jwt_test.go index 576a1e2e..5d4b5591 100644 --- a/auth/token/jwt/jwt_test.go +++ b/auth/token/jwt/jwt_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/micro/go-micro/v2/auth" "github.com/micro/go-micro/v2/auth/token" ) @@ -18,7 +19,7 @@ func TestGenerate(t *testing.T) { token.WithPrivateKey(string(privKey)), ) - _, err = j.Generate("test") + _, err = j.Generate(&auth.Account{ID: "test"}) if err != nil { t.Fatalf("Generate returned %v error, expected nil", err) } @@ -44,12 +45,8 @@ func TestInspect(t *testing.T) { roles := []string{"admin"} subject := "test" - opts := []token.GenerateOption{ - token.WithMetadata(md), - token.WithRoles(roles...), - } - - tok, err := j.Generate(subject, opts...) + acc := &auth.Account{ID: subject, Roles: roles, Metadata: md} + tok, err := j.Generate(acc) if err != nil { t.Fatalf("Generate returned %v error, expected nil", err) } @@ -58,8 +55,8 @@ func TestInspect(t *testing.T) { if err != nil { t.Fatalf("Inspect returned %v error, expected nil", err) } - if tok2.Subject != subject { - t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.Subject, subject) + if acc.ID != subject { + t.Errorf("Inspect returned %v as the token subject, expected %v", acc.ID, subject) } if 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) { - tok, err := j.Generate("foo", token.WithExpiry(-10*time.Second)) + tok, err := j.Generate(&auth.Account{}, token.WithExpiry(-10*time.Second)) if err != nil { t.Fatalf("Generate returned %v error, expected nil", err) } diff --git a/auth/token/options.go b/auth/token/options.go index 2e8d3bbd..8afe174d 100644 --- a/auth/token/options.go +++ b/auth/token/options.go @@ -53,12 +53,6 @@ func NewOptions(opts ...Option) Options { type GenerateOptions struct { // Expiry for the token 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) @@ -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 func NewGenerateOptions(opts ...GenerateOption) GenerateOptions { var options GenerateOptions diff --git a/auth/token/token.go b/auth/token/token.go index da8409f1..61b1b6f5 100644 --- a/auth/token/token.go +++ b/auth/token/token.go @@ -2,6 +2,7 @@ package token import ( "errors" + "time" "github.com/micro/go-micro/v2/auth" ) @@ -17,7 +18,16 @@ var ( // Provider generates and inspects tokens type Provider interface { - Generate(subject string, opts ...GenerateOption) (*auth.Token, error) - Inspect(token string) (*auth.Token, error) + Generate(account *auth.Account, opts ...GenerateOption) (*Token, error) + Inspect(token string) (*auth.Account, error) 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"` +} diff --git a/client/grpc/grpc.go b/client/grpc/grpc.go index 71a89f9c..9d2fd597 100644 --- a/client/grpc/grpc.go +++ b/client/grpc/grpc.go @@ -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 var srvToken string 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 { header["authorization"] = auth.BearerScheme + srvToken diff --git a/config/cmd/cmd.go b/config/cmd/cmd.go index 0af37fdd..7b90b29a 100644 --- a/config/cmd/cmd.go +++ b/config/cmd/cmd.go @@ -670,7 +670,6 @@ func (c *cmd) Before(ctx *cli.Context) error { if len(ctx.String("auth_public_key")) > 0 { authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key"))) } - if len(ctx.String("auth_private_key")) > 0 { authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key"))) }