Updated auth interface (#1384)

* Updated  auth interface

* Add Rule

* Remove Rule

* Return token from Renew

* Renew => Refresh

* Implement Tokens & Default Auth Implementation

* Change default auth to noop

* Change default auth to noop

* Move token.Token to auth.Token

* Remove Token from Account

* Auth service implementation

* Decode JWT locally

* Cookie for secret

* Move string to bottom of interface definition

* Depricate auth_exclude

* Update auth wrappers

* Update go.sum

Co-authored-by: Ben Toogood <ben@micro.mu>
This commit is contained in:
ben-toogood 2020-03-23 16:19:30 +00:00 committed by GitHub
parent 9826ddbd64
commit e0e77f3983
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1842 additions and 649 deletions

View File

@ -43,44 +43,42 @@ func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} else { } else {
// Get the token out the cookies if not provided in headers // Get the token out the cookies if not provided in headers
if c, err := req.Cookie("micro-token"); err == nil && c != nil { if c, err := req.Cookie("micro-token"); err == nil && c != nil {
token = strings.TrimPrefix(c.Value, auth.CookieName+"=") token = strings.TrimPrefix(c.Value, auth.TokenCookieName+"=")
req.Header.Set("Authorization", BearerScheme+token) req.Header.Set("Authorization", BearerScheme+token)
} }
} }
// Return if the user disabled auth on this endpoint // Get the account using the token, fallback to a blank account
excludes := h.auth.Options().Exclude // since some endpoints can be unauthenticated, so the lack of an
excludes = append(excludes, DefaultExcludes...) // account doesn't necesserially mean a forbidden request
acc, err := h.auth.Inspect(token)
loginURL := h.auth.Options().LoginURL if err != nil {
if len(loginURL) > 0 { acc = &auth.Account{}
excludes = append(excludes, loginURL)
} }
err = h.auth.Verify(acc, &auth.Resource{
Type: "service",
Name: "go.micro.web",
Endpoint: req.URL.Path,
})
for _, e := range excludes { // The account has the necessary permissions to access the
// is a standard exclude, e.g. /rpc // resource
if e == req.URL.Path { if err == nil {
h.handler.ServeHTTP(w, req) h.handler.ServeHTTP(w, req)
return return
} }
// is a wildcard exclude, e.g. /services/* // The account is set, but they don't have enough permissions,
wildcard := strings.Replace(e, "*", "", 1) // hence we 403.
if strings.HasSuffix(e, "*") && strings.HasPrefix(req.URL.Path, wildcard) { if len(acc.ID) > 0 {
h.handler.ServeHTTP(w, req) w.WriteHeader(http.StatusForbidden)
return
}
}
// If the token is valid, allow the request
if _, err := h.auth.Verify(token); err == nil {
h.handler.ServeHTTP(w, req)
return return
} }
// If there is no auth login url set, 401 // If there is no auth login url set, 401
loginURL := h.auth.Options().LoginURL
if loginURL == "" { if loginURL == "" {
w.WriteHeader(401) w.WriteHeader(http.StatusUnauthorized)
return return
} }

View File

@ -4,24 +4,44 @@ package auth
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"time" "time"
"github.com/micro/go-micro/v2/metadata" "github.com/micro/go-micro/v2/metadata"
) )
var (
// ErrNotFound is returned when a resouce cannot be found
ErrNotFound = errors.New("not found")
// ErrEncodingToken is returned when the service encounters an error during encoding
ErrEncodingToken = errors.New("error encoding the token")
// ErrInvalidToken is returned when the token provided is not valid
ErrInvalidToken = errors.New("invalid token provided")
// ErrInvalidRole is returned when the role provided was invalid
ErrInvalidRole = errors.New("invalid role")
// ErrForbidden is returned when a user does not have the necessary roles to access a resource
ErrForbidden = errors.New("resource forbidden")
)
// Auth providers authentication and authorization // Auth providers authentication and authorization
type Auth interface { type Auth interface {
// Init the auth package // Init the auth
Init(opts ...Option) error Init(opts ...Option)
// Options returns the options set // Options set for auth
Options() Options Options() Options
// Generate a new auth Account // Generate a new account
Generate(id string, opts ...GenerateOption) (*Account, error) Generate(id string, opts ...GenerateOption) (*Account, error)
// Revoke an authorization Account // Grant access to a resource
Revoke(token string) error Grant(role string, res *Resource) error
// Verify an account token // Revoke access to a resource
Verify(token string) (*Account, error) Revoke(role string, res *Resource) error
// String returns the implementation // Verify an account has access to a resource
Verify(acc *Account, res *Resource) error
// Inspect a token
Inspect(token string) (*Account, error)
// Refresh an account using a secret
Refresh(secret string, opts ...RefreshOption) (*Token, error)
// String returns the name of the implementation
String() string String() string
} }
@ -31,40 +51,47 @@ type Resource struct {
Name string Name string
// Type of resource, e.g. // Type of resource, e.g.
Type string Type string
} // Endpoint resource e.g NotesService.Create
Endpoint string
// Role an account has
type Role struct {
// Name of the role
Name string
// The resource it has access
// TODO: potentially remove
Resource *Resource
} }
// 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 (UUIDV4, email or username)
Id string `json:"id"` ID string `json:"id"`
// Token used to authenticate // Secret used to renew the account
Token string `json:"token"` Secret *Token `json:"secret"`
// Time of Account creation
Created time.Time `json:"created"`
// Time of Account expiry
Expiry time.Time `json:"expiry"`
// Roles associated with the Account // Roles associated with the Account
Roles []*Role `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"`
} }
// 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"`
// 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"`
}
const ( const (
// MetadataKey is the key used when storing the account // MetadataKey is the key used when storing the account in metadata
// in metadata
MetadataKey = "auth-account" MetadataKey = "auth-account"
// CookieName is the name of the cookie which stores the // TokenCookieName is the name of the cookie which stores the auth token
// auth token TokenCookieName = "micro-token"
CookieName = "micro-token" // SecretCookieName is the name of the cookie which stores the auth secret
SecretCookieName = "micro-secret"
) )
// AccountFromContext gets the account from the context, which // AccountFromContext gets the account from the context, which

View File

@ -1,122 +1,70 @@
package auth package auth
import ( import (
"encoding/base32" "github.com/google/uuid"
"sync"
"time"
) )
var ( var (
DefaultAuth = NewAuth() DefaultAuth = NewAuth()
) )
func genAccount(id string) *Account {
// return a pseudo account
return &Account{
Id: id,
Token: base32.StdEncoding.EncodeToString([]byte(id)),
Created: time.Now(),
Expiry: time.Now().Add(time.Hour * 24),
Metadata: make(map[string]string),
}
}
// NewAuth returns a new default registry which is memory
func NewAuth(opts ...Option) Auth { func NewAuth(opts ...Option) Auth {
var options Options return &noop{}
for _, o := range opts {
o(&options)
}
return &memory{
accounts: make(map[string]*Account),
opts: options,
}
} }
// TODO: replace with https://github.com/nats-io/nkeys type noop struct {
// We'll then register public key in registry to use
type memory struct {
opts Options opts Options
// accounts
sync.RWMutex
accounts map[string]*Account
} }
func (n *memory) Init(opts ...Option) error { // String returns the name of the implementation
func (n *noop) String() string {
return "noop"
}
// Init the auth
func (n *noop) Init(opts ...Option) {
for _, o := range opts { for _, o := range opts {
o(&n.opts) o(&n.opts)
} }
return nil
} }
func (n *memory) Options() Options { // Options set for auth
func (n *noop) Options() Options {
return n.opts return n.opts
} }
func (n *memory) Generate(id string, opts ...GenerateOption) (*Account, error) { // Generate a new account
var options GenerateOptions func (n *noop) Generate(id string, opts ...GenerateOption) (*Account, error) {
for _, o := range opts { options := NewGenerateOptions(opts...)
o(&options)
}
// return a pseudo account
acc := genAccount(id)
// set opts
if len(options.Roles) > 0 {
acc.Roles = options.Roles
}
if options.Metadata != nil {
acc.Metadata = options.Metadata
}
// TODO: don't overwrite
n.Lock()
// maybe save by account id?
n.accounts[acc.Token] = acc
n.Unlock()
return acc, nil
}
func (n *memory) Revoke(token string) error {
n.Lock()
delete(n.accounts, token)
n.Unlock()
return nil
}
func (n *memory) Verify(token string) (*Account, error) {
n.RLock()
defer n.RUnlock()
if len(token) == 0 {
// pseudo account?
return genAccount(""), nil
}
// try get the local account if it exists
if acc, ok := n.accounts[token]; ok {
return acc, nil
}
// decode the token otherwise
b, err := base32.StdEncoding.DecodeString(token)
if err != nil {
return genAccount(""), nil
}
// return a pseudo account based on token/id
return &Account{ return &Account{
Id: string(b), ID: id,
Token: token, Roles: options.Roles,
Created: time.Now(), Metadata: options.Metadata,
Expiry: time.Now().Add(time.Hour * 24),
Metadata: make(map[string]string),
}, nil }, nil
} }
func (n *memory) String() string { // Grant access to a resource
return "memory" func (n *noop) Grant(role string, res *Resource) error {
return nil
}
// Revoke access to a resource
func (n *noop) Revoke(role string, res *Resource) error {
return nil
}
// Verify an account has access to a resource
func (n *noop) Verify(acc *Account, res *Resource) error {
return nil
}
// Inspect a token
func (n *noop) Inspect(token string) (*Account, error) {
return &Account{ID: uuid.New().String()}, nil
}
// Refresh an account using a secret
func (n *noop) Refresh(secret string, opts ...RefreshOption) (*Token, error) {
return &Token{}, nil
} }

View File

@ -1,133 +0,0 @@
package jwt
import (
"encoding/base64"
"errors"
"github.com/dgrijalva/jwt-go"
"github.com/micro/go-micro/v2/auth"
)
var (
// ErrInvalidPrivateKey is returned when the service provided an invalid private key
ErrInvalidPrivateKey = errors.New("An invalid private key was provided")
// ErrEncodingToken is returned when the service encounters an error during encoding
ErrEncodingToken = errors.New("An error occured while encoding the JWT")
// ErrInvalidToken is returned when the token provided is not valid
ErrInvalidToken = errors.New("An invalid token was provided")
// ErrMissingToken is returned when no token is provided
ErrMissingToken = errors.New("A valid JWT is required")
)
// NewAuth returns a new instance of the Auth service
func NewAuth(opts ...auth.Option) auth.Auth {
svc := new(svc)
svc.Init(opts...)
return svc
}
// svc is the JWT implementation of the Auth interface
type svc struct {
options auth.Options
}
func (s *svc) String() string {
return "jwt"
}
func (s *svc) Options() auth.Options {
return s.options
}
func (s *svc) Init(opts ...auth.Option) error {
for _, o := range opts {
o(&s.options)
}
return nil
}
// AuthClaims to be encoded in the JWT
type AuthClaims struct {
Roles []*auth.Role `json:"roles"`
Metadata map[string]string `json:"metadata"`
jwt.StandardClaims
}
// Generate a new JWT
func (s *svc) Generate(id string, ops ...auth.GenerateOption) (*auth.Account, error) {
// decode the private key
priv, err := base64.StdEncoding.DecodeString(s.options.PrivateKey)
if err != nil {
return nil, err
}
key, err := jwt.ParseRSAPrivateKeyFromPEM(priv)
if err != nil {
return nil, ErrEncodingToken
}
options := auth.NewGenerateOptions(ops...)
account := jwt.NewWithClaims(jwt.SigningMethodRS256, AuthClaims{
options.Roles, options.Metadata, jwt.StandardClaims{
Subject: id,
ExpiresAt: options.Expiry.Unix(),
},
})
token, err := account.SignedString(key)
if err != nil {
return nil, err
}
return &auth.Account{
Id: id,
Token: token,
Roles: options.Roles,
Metadata: options.Metadata,
}, nil
}
// Revoke an authorization account
func (s *svc) Revoke(token string) error {
return nil
}
// Verify a JWT
func (s *svc) Verify(token string) (*auth.Account, error) {
if token == "" {
return nil, ErrMissingToken
}
// decode the public key
pub, err := base64.StdEncoding.DecodeString(s.options.PublicKey)
if err != nil {
return nil, err
}
res, err := jwt.ParseWithClaims(token, &AuthClaims{}, func(token *jwt.Token) (interface{}, error) {
return jwt.ParseRSAPublicKeyFromPEM(pub)
})
if err != nil {
return nil, err
}
if !res.Valid {
return nil, ErrInvalidToken
}
claims, ok := res.Claims.(*AuthClaims)
if !ok {
return nil, ErrInvalidToken
}
return &auth.Account{
Id: claims.Subject,
Metadata: claims.Metadata,
Roles: claims.Roles,
}, nil
}

View File

@ -4,6 +4,7 @@ import (
"time" "time"
"github.com/micro/go-micro/v2/auth/provider" "github.com/micro/go-micro/v2/auth/provider"
"github.com/micro/go-micro/v2/store"
) )
type Options struct { type Options struct {
@ -13,20 +14,20 @@ type Options struct {
PublicKey string PublicKey string
// Private key base64 encoded // Private key base64 encoded
PrivateKey string PrivateKey string
// Endpoints to exclude
Exclude []string
// Provider is an auth provider // Provider is an auth provider
Provider provider.Provider Provider provider.Provider
// LoginURL is the relative url path where a user can login // LoginURL is the relative url path where a user can login
LoginURL string LoginURL string
// Store to back auth
Store store.Store
} }
type Option func(o *Options) type Option func(o *Options)
// Exclude ecludes a set of endpoints from authorization // Store to back auth
func Exclude(e ...string) Option { func Store(s store.Store) Option {
return func(o *Options) { return func(o *Options) {
o.Exclude = e o.Store = s
} }
} }
@ -44,8 +45,8 @@ func PrivateKey(key string) Option {
} }
} }
// Token sets an auth token // ServiceToken sets an auth token
func Token(t string) Option { func ServiceToken(t string) Option {
return func(o *Options) { return func(o *Options) {
o.Token = t o.Token = t
} }
@ -69,31 +70,31 @@ type GenerateOptions struct {
// Metadata associated with the account // Metadata associated with the account
Metadata map[string]string Metadata map[string]string
// Roles/scopes associated with the account // Roles/scopes associated with the account
Roles []*Role Roles []string
//Expiry of the token // SecretExpiry is the time the secret should live for
Expiry time.Time SecretExpiry time.Duration
} }
type GenerateOption func(o *GenerateOptions) type GenerateOption func(o *GenerateOptions)
// Metadata for the generated account // WithMetadata for the generated account
func Metadata(md map[string]string) func(o *GenerateOptions) { func WithMetadata(md map[string]string) GenerateOption {
return func(o *GenerateOptions) { return func(o *GenerateOptions) {
o.Metadata = md o.Metadata = md
} }
} }
// Roles for the generated account // WithRoles for the generated account
func Roles(rs []*Role) func(o *GenerateOptions) { func WithRoles(rs []string) GenerateOption {
return func(o *GenerateOptions) { return func(o *GenerateOptions) {
o.Roles = rs o.Roles = rs
} }
} }
// Expiry for the generated account's token expires // WithSecretExpiry for the generated account's secret expires
func Expiry(ex time.Time) func(o *GenerateOptions) { func WithSecretExpiry(ex time.Duration) GenerateOption {
return func(o *GenerateOptions) { return func(o *GenerateOptions) {
o.Expiry = ex o.SecretExpiry = ex
} }
} }
@ -103,9 +104,40 @@ func NewGenerateOptions(opts ...GenerateOption) GenerateOptions {
for _, o := range opts { for _, o := range opts {
o(&options) o(&options)
} }
//set defualt expiry of token
if options.Expiry.IsZero() { // set defualt expiry of secret
options.Expiry = time.Now().Add(time.Hour * 24) if options.SecretExpiry == 0 {
options.SecretExpiry = time.Hour * 24 * 7
} }
return options
}
type RefreshOptions struct {
// TokenExpiry is the time the token should live for
TokenExpiry time.Duration
}
type RefreshOption func(o *RefreshOptions)
// WithTokenExpiry for the token
func WithTokenExpiry(ex time.Duration) RefreshOption {
return func(o *RefreshOptions) {
o.TokenExpiry = ex
}
}
// NewRefreshOptions from a slice of options
func NewRefreshOptions(opts ...RefreshOption) RefreshOptions {
var options RefreshOptions
for _, o := range opts {
o(&options)
}
// set defualt expiry of token
if options.TokenExpiry == 0 {
options.TokenExpiry = time.Minute
}
return options return options
} }

View File

@ -1,5 +1,5 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: micro/go-micro/auth/service/proto/auth.proto // source: auth/service/proto/auth.proto
package go_micro_auth package go_micro_auth
@ -20,13 +20,98 @@ var _ = math.Inf
// proto package needs to be updated. // proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Account struct { type Token struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
Token string `protobuf:"bytes,2,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"` 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"`
Roles []*Role `protobuf:"bytes,5,rep,name=roles,proto3" json:"roles,omitempty"` Subject string `protobuf:"bytes,5,opt,name=subject,proto3" json:"subject,omitempty"`
Metadata map[string]string `protobuf:"bytes,6,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` 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"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Token) Reset() { *m = Token{} }
func (m *Token) String() string { return proto.CompactTextString(m) }
func (*Token) ProtoMessage() {}
func (*Token) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{0}
}
func (m *Token) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Token.Unmarshal(m, b)
}
func (m *Token) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Token.Marshal(b, m, deterministic)
}
func (m *Token) XXX_Merge(src proto.Message) {
xxx_messageInfo_Token.Merge(m, src)
}
func (m *Token) XXX_Size() int {
return xxx_messageInfo_Token.Size(m)
}
func (m *Token) XXX_DiscardUnknown() {
xxx_messageInfo_Token.DiscardUnknown(m)
}
var xxx_messageInfo_Token proto.InternalMessageInfo
func (m *Token) GetToken() string {
if m != nil {
return m.Token
}
return ""
}
func (m *Token) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (m *Token) GetCreated() int64 {
if m != nil {
return m.Created
}
return 0
}
func (m *Token) GetExpiry() int64 {
if m != nil {
return m.Expiry
}
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
}
type Account struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Secret *Token `protobuf:"bytes,2,opt,name=secret,proto3" json:"secret,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"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -36,7 +121,7 @@ func (m *Account) Reset() { *m = Account{} }
func (m *Account) String() string { return proto.CompactTextString(m) } func (m *Account) String() string { return proto.CompactTextString(m) }
func (*Account) ProtoMessage() {} func (*Account) ProtoMessage() {}
func (*Account) Descriptor() ([]byte, []int) { func (*Account) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{0} return fileDescriptor_21300bfacc51fc2a, []int{1}
} }
func (m *Account) XXX_Unmarshal(b []byte) error { func (m *Account) XXX_Unmarshal(b []byte) error {
@ -64,28 +149,14 @@ func (m *Account) GetId() string {
return "" return ""
} }
func (m *Account) GetToken() string { func (m *Account) GetSecret() *Token {
if m != nil { if m != nil {
return m.Token return m.Secret
} }
return "" return nil
} }
func (m *Account) GetCreated() int64 { func (m *Account) GetRoles() []string {
if m != nil {
return m.Created
}
return 0
}
func (m *Account) GetExpiry() int64 {
if m != nil {
return m.Expiry
}
return 0
}
func (m *Account) GetRoles() []*Role {
if m != nil { if m != nil {
return m.Roles return m.Roles
} }
@ -99,56 +170,10 @@ func (m *Account) GetMetadata() map[string]string {
return nil return nil
} }
type Role struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Role) Reset() { *m = Role{} }
func (m *Role) String() string { return proto.CompactTextString(m) }
func (*Role) ProtoMessage() {}
func (*Role) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{1}
}
func (m *Role) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Role.Unmarshal(m, b)
}
func (m *Role) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Role.Marshal(b, m, deterministic)
}
func (m *Role) XXX_Merge(src proto.Message) {
xxx_messageInfo_Role.Merge(m, src)
}
func (m *Role) XXX_Size() int {
return xxx_messageInfo_Role.Size(m)
}
func (m *Role) XXX_DiscardUnknown() {
xxx_messageInfo_Role.DiscardUnknown(m)
}
var xxx_messageInfo_Role proto.InternalMessageInfo
func (m *Role) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Role) GetResource() *Resource {
if m != nil {
return m.Resource
}
return nil
}
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"`
Endpoint string `protobuf:"bytes,3,opt,name=endpoint,proto3" json:"endpoint,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:"-"`
@ -158,7 +183,7 @@ func (m *Resource) Reset() { *m = Resource{} }
func (m *Resource) String() string { return proto.CompactTextString(m) } func (m *Resource) String() string { return proto.CompactTextString(m) }
func (*Resource) ProtoMessage() {} func (*Resource) ProtoMessage() {}
func (*Resource) Descriptor() ([]byte, []int) { func (*Resource) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{2} return fileDescriptor_21300bfacc51fc2a, []int{2}
} }
func (m *Resource) XXX_Unmarshal(b []byte) error { func (m *Resource) XXX_Unmarshal(b []byte) error {
@ -193,8 +218,18 @@ func (m *Resource) GetType() string {
return "" return ""
} }
func (m *Resource) GetEndpoint() string {
if m != nil {
return m.Endpoint
}
return ""
}
type GenerateRequest struct { type GenerateRequest struct {
Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,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"`
SecretExpiry int64 `protobuf:"varint,4,opt,name=secret_expiry,json=secretExpiry,proto3" json:"secret_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:"-"`
@ -204,7 +239,7 @@ func (m *GenerateRequest) Reset() { *m = GenerateRequest{} }
func (m *GenerateRequest) String() string { return proto.CompactTextString(m) } func (m *GenerateRequest) String() string { return proto.CompactTextString(m) }
func (*GenerateRequest) ProtoMessage() {} func (*GenerateRequest) ProtoMessage() {}
func (*GenerateRequest) Descriptor() ([]byte, []int) { func (*GenerateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{3} return fileDescriptor_21300bfacc51fc2a, []int{3}
} }
func (m *GenerateRequest) XXX_Unmarshal(b []byte) error { func (m *GenerateRequest) XXX_Unmarshal(b []byte) error {
@ -225,13 +260,34 @@ func (m *GenerateRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_GenerateRequest proto.InternalMessageInfo var xxx_messageInfo_GenerateRequest proto.InternalMessageInfo
func (m *GenerateRequest) GetAccount() *Account { func (m *GenerateRequest) GetId() string {
if m != nil { if m != nil {
return m.Account return m.Id
}
return ""
}
func (m *GenerateRequest) GetRoles() []string {
if m != nil {
return m.Roles
} }
return nil return nil
} }
func (m *GenerateRequest) GetMetadata() map[string]string {
if m != nil {
return m.Metadata
}
return nil
}
func (m *GenerateRequest) GetSecretExpiry() int64 {
if m != nil {
return m.SecretExpiry
}
return 0
}
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:"-"`
@ -243,7 +299,7 @@ func (m *GenerateResponse) Reset() { *m = GenerateResponse{} }
func (m *GenerateResponse) String() string { return proto.CompactTextString(m) } func (m *GenerateResponse) String() string { return proto.CompactTextString(m) }
func (*GenerateResponse) ProtoMessage() {} func (*GenerateResponse) ProtoMessage() {}
func (*GenerateResponse) Descriptor() ([]byte, []int) { func (*GenerateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{4} return fileDescriptor_21300bfacc51fc2a, []int{4}
} }
func (m *GenerateResponse) XXX_Unmarshal(b []byte) error { func (m *GenerateResponse) XXX_Unmarshal(b []byte) error {
@ -271,8 +327,87 @@ func (m *GenerateResponse) GetAccount() *Account {
return nil return nil
} }
type GrantRequest struct {
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GrantRequest) Reset() { *m = GrantRequest{} }
func (m *GrantRequest) String() string { return proto.CompactTextString(m) }
func (*GrantRequest) ProtoMessage() {}
func (*GrantRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{5}
}
func (m *GrantRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GrantRequest.Unmarshal(m, b)
}
func (m *GrantRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GrantRequest.Marshal(b, m, deterministic)
}
func (m *GrantRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_GrantRequest.Merge(m, src)
}
func (m *GrantRequest) XXX_Size() int {
return xxx_messageInfo_GrantRequest.Size(m)
}
func (m *GrantRequest) XXX_DiscardUnknown() {
xxx_messageInfo_GrantRequest.DiscardUnknown(m)
}
var xxx_messageInfo_GrantRequest proto.InternalMessageInfo
func (m *GrantRequest) GetRole() string {
if m != nil {
return m.Role
}
return ""
}
func (m *GrantRequest) GetResource() *Resource {
if m != nil {
return m.Resource
}
return nil
}
type GrantResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GrantResponse) Reset() { *m = GrantResponse{} }
func (m *GrantResponse) String() string { return proto.CompactTextString(m) }
func (*GrantResponse) ProtoMessage() {}
func (*GrantResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{6}
}
func (m *GrantResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GrantResponse.Unmarshal(m, b)
}
func (m *GrantResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GrantResponse.Marshal(b, m, deterministic)
}
func (m *GrantResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_GrantResponse.Merge(m, src)
}
func (m *GrantResponse) XXX_Size() int {
return xxx_messageInfo_GrantResponse.Size(m)
}
func (m *GrantResponse) XXX_DiscardUnknown() {
xxx_messageInfo_GrantResponse.DiscardUnknown(m)
}
var xxx_messageInfo_GrantResponse proto.InternalMessageInfo
type VerifyRequest struct { type VerifyRequest struct {
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,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:"-"`
@ -282,7 +417,7 @@ func (m *VerifyRequest) Reset() { *m = VerifyRequest{} }
func (m *VerifyRequest) String() string { return proto.CompactTextString(m) } func (m *VerifyRequest) String() string { return proto.CompactTextString(m) }
func (*VerifyRequest) ProtoMessage() {} func (*VerifyRequest) ProtoMessage() {}
func (*VerifyRequest) Descriptor() ([]byte, []int) { func (*VerifyRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{5} return fileDescriptor_21300bfacc51fc2a, []int{7}
} }
func (m *VerifyRequest) XXX_Unmarshal(b []byte) error { func (m *VerifyRequest) XXX_Unmarshal(b []byte) error {
@ -303,15 +438,21 @@ func (m *VerifyRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_VerifyRequest proto.InternalMessageInfo var xxx_messageInfo_VerifyRequest proto.InternalMessageInfo
func (m *VerifyRequest) GetToken() string { func (m *VerifyRequest) GetAccount() *Account {
if m != nil { if m != nil {
return m.Token return m.Account
} }
return "" return nil
}
func (m *VerifyRequest) GetResource() *Resource {
if m != nil {
return m.Resource
}
return nil
} }
type VerifyResponse struct { type VerifyResponse struct {
Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,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:"-"`
@ -321,7 +462,7 @@ func (m *VerifyResponse) Reset() { *m = VerifyResponse{} }
func (m *VerifyResponse) String() string { return proto.CompactTextString(m) } func (m *VerifyResponse) String() string { return proto.CompactTextString(m) }
func (*VerifyResponse) ProtoMessage() {} func (*VerifyResponse) ProtoMessage() {}
func (*VerifyResponse) Descriptor() ([]byte, []int) { func (*VerifyResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{6} return fileDescriptor_21300bfacc51fc2a, []int{8}
} }
func (m *VerifyResponse) XXX_Unmarshal(b []byte) error { func (m *VerifyResponse) XXX_Unmarshal(b []byte) error {
@ -342,15 +483,9 @@ func (m *VerifyResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_VerifyResponse proto.InternalMessageInfo var xxx_messageInfo_VerifyResponse proto.InternalMessageInfo
func (m *VerifyResponse) GetAccount() *Account {
if m != nil {
return m.Account
}
return nil
}
type RevokeRequest struct { type RevokeRequest struct {
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,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:"-"`
@ -360,7 +495,7 @@ func (m *RevokeRequest) Reset() { *m = RevokeRequest{} }
func (m *RevokeRequest) String() string { return proto.CompactTextString(m) } func (m *RevokeRequest) String() string { return proto.CompactTextString(m) }
func (*RevokeRequest) ProtoMessage() {} func (*RevokeRequest) ProtoMessage() {}
func (*RevokeRequest) Descriptor() ([]byte, []int) { func (*RevokeRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{7} return fileDescriptor_21300bfacc51fc2a, []int{9}
} }
func (m *RevokeRequest) XXX_Unmarshal(b []byte) error { func (m *RevokeRequest) XXX_Unmarshal(b []byte) error {
@ -381,13 +516,20 @@ func (m *RevokeRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_RevokeRequest proto.InternalMessageInfo var xxx_messageInfo_RevokeRequest proto.InternalMessageInfo
func (m *RevokeRequest) GetToken() string { func (m *RevokeRequest) GetRole() string {
if m != nil { if m != nil {
return m.Token return m.Role
} }
return "" return ""
} }
func (m *RevokeRequest) GetResource() *Resource {
if m != nil {
return m.Resource
}
return nil
}
type RevokeResponse struct { type RevokeResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
@ -398,7 +540,7 @@ func (m *RevokeResponse) Reset() { *m = RevokeResponse{} }
func (m *RevokeResponse) String() string { return proto.CompactTextString(m) } func (m *RevokeResponse) String() string { return proto.CompactTextString(m) }
func (*RevokeResponse) ProtoMessage() {} func (*RevokeResponse) ProtoMessage() {}
func (*RevokeResponse) Descriptor() ([]byte, []int) { func (*RevokeResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{8} return fileDescriptor_21300bfacc51fc2a, []int{10}
} }
func (m *RevokeResponse) XXX_Unmarshal(b []byte) error { func (m *RevokeResponse) XXX_Unmarshal(b []byte) error {
@ -419,50 +561,235 @@ func (m *RevokeResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_RevokeResponse proto.InternalMessageInfo var xxx_messageInfo_RevokeResponse proto.InternalMessageInfo
type InspectRequest struct {
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *InspectRequest) Reset() { *m = InspectRequest{} }
func (m *InspectRequest) String() string { return proto.CompactTextString(m) }
func (*InspectRequest) ProtoMessage() {}
func (*InspectRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{11}
}
func (m *InspectRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_InspectRequest.Unmarshal(m, b)
}
func (m *InspectRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_InspectRequest.Marshal(b, m, deterministic)
}
func (m *InspectRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_InspectRequest.Merge(m, src)
}
func (m *InspectRequest) XXX_Size() int {
return xxx_messageInfo_InspectRequest.Size(m)
}
func (m *InspectRequest) XXX_DiscardUnknown() {
xxx_messageInfo_InspectRequest.DiscardUnknown(m)
}
var xxx_messageInfo_InspectRequest proto.InternalMessageInfo
func (m *InspectRequest) GetToken() string {
if m != nil {
return m.Token
}
return ""
}
type InspectResponse struct {
Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *InspectResponse) Reset() { *m = InspectResponse{} }
func (m *InspectResponse) String() string { return proto.CompactTextString(m) }
func (*InspectResponse) ProtoMessage() {}
func (*InspectResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{12}
}
func (m *InspectResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_InspectResponse.Unmarshal(m, b)
}
func (m *InspectResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_InspectResponse.Marshal(b, m, deterministic)
}
func (m *InspectResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_InspectResponse.Merge(m, src)
}
func (m *InspectResponse) XXX_Size() int {
return xxx_messageInfo_InspectResponse.Size(m)
}
func (m *InspectResponse) XXX_DiscardUnknown() {
xxx_messageInfo_InspectResponse.DiscardUnknown(m)
}
var xxx_messageInfo_InspectResponse proto.InternalMessageInfo
func (m *InspectResponse) GetAccount() *Account {
if m != nil {
return m.Account
}
return nil
}
type RefreshRequest struct {
Secret string `protobuf:"bytes,1,opt,name=secret,proto3" json:"secret,omitempty"`
TokenExpiry int64 `protobuf:"varint,2,opt,name=token_expiry,json=tokenExpiry,proto3" json:"token_expiry,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RefreshRequest) Reset() { *m = RefreshRequest{} }
func (m *RefreshRequest) String() string { return proto.CompactTextString(m) }
func (*RefreshRequest) ProtoMessage() {}
func (*RefreshRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{13}
}
func (m *RefreshRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RefreshRequest.Unmarshal(m, b)
}
func (m *RefreshRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RefreshRequest.Marshal(b, m, deterministic)
}
func (m *RefreshRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_RefreshRequest.Merge(m, src)
}
func (m *RefreshRequest) XXX_Size() int {
return xxx_messageInfo_RefreshRequest.Size(m)
}
func (m *RefreshRequest) XXX_DiscardUnknown() {
xxx_messageInfo_RefreshRequest.DiscardUnknown(m)
}
var xxx_messageInfo_RefreshRequest proto.InternalMessageInfo
func (m *RefreshRequest) GetSecret() string {
if m != nil {
return m.Secret
}
return ""
}
func (m *RefreshRequest) GetTokenExpiry() int64 {
if m != nil {
return m.TokenExpiry
}
return 0
}
type RefreshResponse struct {
Token *Token `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RefreshResponse) Reset() { *m = RefreshResponse{} }
func (m *RefreshResponse) String() string { return proto.CompactTextString(m) }
func (*RefreshResponse) ProtoMessage() {}
func (*RefreshResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{14}
}
func (m *RefreshResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RefreshResponse.Unmarshal(m, b)
}
func (m *RefreshResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RefreshResponse.Marshal(b, m, deterministic)
}
func (m *RefreshResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_RefreshResponse.Merge(m, src)
}
func (m *RefreshResponse) XXX_Size() int {
return xxx_messageInfo_RefreshResponse.Size(m)
}
func (m *RefreshResponse) XXX_DiscardUnknown() {
xxx_messageInfo_RefreshResponse.DiscardUnknown(m)
}
var xxx_messageInfo_RefreshResponse proto.InternalMessageInfo
func (m *RefreshResponse) GetToken() *Token {
if m != nil {
return m.Token
}
return nil
}
func init() { func init() {
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((*Role)(nil), "go.micro.auth.Role")
proto.RegisterType((*Resource)(nil), "go.micro.auth.Resource") proto.RegisterType((*Resource)(nil), "go.micro.auth.Resource")
proto.RegisterType((*GenerateRequest)(nil), "go.micro.auth.GenerateRequest") proto.RegisterType((*GenerateRequest)(nil), "go.micro.auth.GenerateRequest")
proto.RegisterMapType((map[string]string)(nil), "go.micro.auth.GenerateRequest.MetadataEntry")
proto.RegisterType((*GenerateResponse)(nil), "go.micro.auth.GenerateResponse") proto.RegisterType((*GenerateResponse)(nil), "go.micro.auth.GenerateResponse")
proto.RegisterType((*GrantRequest)(nil), "go.micro.auth.GrantRequest")
proto.RegisterType((*GrantResponse)(nil), "go.micro.auth.GrantResponse")
proto.RegisterType((*VerifyRequest)(nil), "go.micro.auth.VerifyRequest") proto.RegisterType((*VerifyRequest)(nil), "go.micro.auth.VerifyRequest")
proto.RegisterType((*VerifyResponse)(nil), "go.micro.auth.VerifyResponse") proto.RegisterType((*VerifyResponse)(nil), "go.micro.auth.VerifyResponse")
proto.RegisterType((*RevokeRequest)(nil), "go.micro.auth.RevokeRequest") proto.RegisterType((*RevokeRequest)(nil), "go.micro.auth.RevokeRequest")
proto.RegisterType((*RevokeResponse)(nil), "go.micro.auth.RevokeResponse") proto.RegisterType((*RevokeResponse)(nil), "go.micro.auth.RevokeResponse")
proto.RegisterType((*InspectRequest)(nil), "go.micro.auth.InspectRequest")
proto.RegisterType((*InspectResponse)(nil), "go.micro.auth.InspectResponse")
proto.RegisterType((*RefreshRequest)(nil), "go.micro.auth.RefreshRequest")
proto.RegisterType((*RefreshResponse)(nil), "go.micro.auth.RefreshResponse")
} }
func init() { func init() { proto.RegisterFile("auth/service/proto/auth.proto", fileDescriptor_21300bfacc51fc2a) }
proto.RegisterFile("micro/go-micro/auth/service/proto/auth.proto", fileDescriptor_de609d4872dacc78)
}
var fileDescriptor_de609d4872dacc78 = []byte{ var fileDescriptor_21300bfacc51fc2a = []byte{
// 432 bytes of a gzipped FileDescriptorProto // 663 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x53, 0x4b, 0x6f, 0xd3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xdd, 0x6e, 0xd3, 0x4c,
0x10, 0xae, 0x1d, 0xe7, 0xc1, 0x44, 0x09, 0xd1, 0x80, 0x8a, 0x15, 0xf1, 0x88, 0x56, 0x20, 0x05, 0x10, 0xad, 0xed, 0xfc, 0x75, 0x52, 0x27, 0xd1, 0xaa, 0xea, 0x67, 0xf9, 0xa3, 0x25, 0x18, 0x84,
0x09, 0x1c, 0xe4, 0x5e, 0x10, 0x5c, 0x28, 0x0f, 0xf5, 0x54, 0x21, 0xed, 0x81, 0xfb, 0xe2, 0x0c, 0x2a, 0x54, 0xb9, 0x28, 0xbd, 0x41, 0x20, 0x10, 0x15, 0xad, 0xca, 0x8f, 0xca, 0x85, 0x85, 0x80,
0xad, 0x95, 0xc4, 0x6b, 0xd6, 0xeb, 0x08, 0xff, 0x06, 0x7e, 0x28, 0x7f, 0x03, 0x79, 0xd7, 0x1b, 0x3b, 0xe4, 0x3a, 0x53, 0x6a, 0xd2, 0xd8, 0x66, 0xbd, 0x8e, 0xc8, 0x5b, 0xf0, 0x52, 0xbc, 0x05,
0x6a, 0xb7, 0xe5, 0x00, 0xb7, 0x79, 0x7c, 0xf3, 0xcd, 0xf7, 0x8d, 0x76, 0xe1, 0xc5, 0x2e, 0x4d, 0x77, 0xbc, 0x08, 0xda, 0xf5, 0xae, 0x6b, 0x3b, 0x09, 0x12, 0x05, 0xee, 0x76, 0x76, 0x66, 0xcf,
0x94, 0x5c, 0x5d, 0xc8, 0x97, 0x36, 0x10, 0xa5, 0xbe, 0x5c, 0x15, 0xa4, 0xf6, 0x69, 0x42, 0xab, 0x99, 0x39, 0x73, 0xe2, 0xc0, 0xb6, 0x9f, 0xb1, 0x8b, 0xfd, 0x14, 0xe9, 0x2c, 0x0c, 0x70, 0x3f,
0x5c, 0x49, 0x6d, 0x4b, 0x91, 0x09, 0x71, 0x72, 0x21, 0x23, 0x83, 0x8b, 0xea, 0x22, 0xfb, 0xe9, 0xa1, 0x31, 0x8b, 0xf7, 0xf9, 0x95, 0x2b, 0x8e, 0xc4, 0xfc, 0x18, 0xbb, 0xd3, 0x30, 0xa0, 0xb1,
0xc3, 0xf0, 0x34, 0x49, 0x64, 0x99, 0x69, 0x9c, 0x82, 0x9f, 0xae, 0x43, 0x6f, 0xe1, 0x2d, 0xef, 0xcb, 0x2f, 0x9d, 0xaf, 0x3a, 0x34, 0xdf, 0xc4, 0x13, 0x8c, 0xc8, 0x26, 0x34, 0x19, 0x3f, 0x58,
0x70, 0x3f, 0x5d, 0xe3, 0x7d, 0xe8, 0x6b, 0xb9, 0xa1, 0x2c, 0xf4, 0x4d, 0xc9, 0x26, 0x18, 0xc2, 0xda, 0x50, 0xdb, 0x5d, 0xf7, 0xf2, 0x80, 0x10, 0x68, 0xb0, 0x79, 0x82, 0x96, 0x2e, 0x2e, 0xc5,
0x30, 0x51, 0x24, 0x34, 0xad, 0xc3, 0xde, 0xc2, 0x5b, 0xf6, 0xb8, 0x4b, 0xf1, 0x18, 0x06, 0xf4, 0x99, 0x58, 0xd0, 0x0e, 0x28, 0xfa, 0x0c, 0xc7, 0x96, 0x31, 0xd4, 0x76, 0x0d, 0x4f, 0x85, 0x64,
0x23, 0x4f, 0x55, 0x15, 0x06, 0xa6, 0xd1, 0x64, 0xf8, 0x1c, 0xfa, 0x4a, 0x6e, 0xa9, 0x08, 0xfb, 0x0b, 0x5a, 0xf8, 0x25, 0x09, 0xe9, 0xdc, 0x6a, 0x88, 0x84, 0x8c, 0xf8, 0x8b, 0x34, 0x3b, 0xfb,
0x8b, 0xde, 0x72, 0x1c, 0xdf, 0x8b, 0x5a, 0x12, 0x22, 0x2e, 0xb7, 0xc4, 0x2d, 0x02, 0xdf, 0xc1, 0x84, 0x01, 0xb3, 0x9a, 0x02, 0x48, 0x85, 0x9c, 0x95, 0xc6, 0x97, 0x98, 0x5a, 0xad, 0xa1, 0xc1,
0x68, 0x47, 0x5a, 0xac, 0x85, 0x16, 0xe1, 0xc0, 0xa0, 0x9f, 0x76, 0xd0, 0x8d, 0xd8, 0xe8, 0xbc, 0x59, 0x45, 0x40, 0x9e, 0x40, 0x67, 0x8a, 0xcc, 0x1f, 0xfb, 0xcc, 0xb7, 0xda, 0x43, 0x63, 0xb7,
0x81, 0x7d, 0xca, 0xb4, 0xaa, 0xf8, 0x61, 0x6a, 0xfe, 0x16, 0x26, 0xad, 0x16, 0xce, 0xa0, 0xb7, 0x3b, 0x72, 0xdc, 0x4a, 0xdf, 0xae, 0xe8, 0xd9, 0x3d, 0x95, 0x45, 0xc7, 0x11, 0xa3, 0x73, 0xaf,
0xa1, 0xaa, 0xb1, 0x55, 0x87, 0xb5, 0xaf, 0xbd, 0xd8, 0x96, 0xe4, 0x7c, 0x99, 0xe4, 0x8d, 0xff, 0x78, 0x63, 0x3f, 0x02, 0xb3, 0x92, 0x22, 0x03, 0x30, 0x26, 0x38, 0x97, 0xa3, 0xf1, 0x23, 0x27,
0xda, 0x63, 0x9f, 0x21, 0xa8, 0xd5, 0x20, 0x42, 0x90, 0x89, 0x1d, 0x35, 0x43, 0x26, 0xc6, 0x13, 0x9e, 0xf9, 0x97, 0x99, 0x9a, 0x2c, 0x0f, 0x1e, 0xea, 0x0f, 0x34, 0xe7, 0xbb, 0x06, 0xed, 0xc3,
0x18, 0x29, 0x2a, 0x64, 0xa9, 0x12, 0x3b, 0x38, 0x8e, 0x1f, 0x74, 0x8d, 0x34, 0x6d, 0x7e, 0x00, 0x20, 0x88, 0xb3, 0x88, 0x91, 0x1e, 0xe8, 0xe1, 0x58, 0x3e, 0xd3, 0xc3, 0x31, 0xd9, 0x83, 0x56,
0xb2, 0x18, 0x46, 0xae, 0x7a, 0x23, 0x29, 0x42, 0xa0, 0xab, 0xdc, 0x29, 0x31, 0x31, 0xfb, 0x00, 0x8a, 0x01, 0x45, 0x26, 0x9e, 0x75, 0x47, 0x9b, 0xcb, 0xda, 0xf2, 0x64, 0xcd, 0xd5, 0x70, 0x46,
0x77, 0xcf, 0x28, 0x23, 0x25, 0x34, 0x71, 0xfa, 0x5e, 0x52, 0xa1, 0xf1, 0x15, 0x0c, 0x85, 0xf5, 0x79, 0xb8, 0xa7, 0xa5, 0xe1, 0x1a, 0x62, 0xb8, 0x3b, 0x35, 0x14, 0xc9, 0xfe, 0x6f, 0xc6, 0x7b,
0x6d, 0xa6, 0xc7, 0xf1, 0xf1, 0xcd, 0x57, 0xe1, 0x0e, 0xc6, 0x3e, 0xc2, 0xec, 0x0f, 0x49, 0x91, 0x0d, 0x1d, 0x0f, 0xd3, 0x38, 0xa3, 0x01, 0xf2, 0xed, 0x46, 0xfe, 0x14, 0xe5, 0x43, 0x71, 0x5e,
0xcb, 0xac, 0xa0, 0x7f, 0x60, 0x79, 0x06, 0x93, 0x2f, 0xa4, 0xd2, 0x6f, 0x95, 0x13, 0x72, 0x78, 0xba, 0x71, 0x1b, 0x3a, 0x18, 0x8d, 0x93, 0x38, 0x8c, 0x98, 0x58, 0xf9, 0xba, 0x57, 0xc4, 0xce,
0x12, 0xde, 0x95, 0x27, 0xc1, 0xde, 0xc3, 0xd4, 0xc1, 0xfe, 0x67, 0x15, 0xa7, 0xbd, 0xdc, 0xd0, 0x0f, 0x0d, 0xfa, 0x27, 0x18, 0x21, 0xf5, 0x19, 0x7a, 0xf8, 0x39, 0xc3, 0x74, 0x51, 0xb6, 0x42,
0xdf, 0x57, 0xcd, 0x60, 0xea, 0x60, 0x76, 0x55, 0xfc, 0xcb, 0x83, 0xe0, 0xb4, 0xd4, 0x97, 0x78, 0x08, 0xbd, 0x2c, 0xc4, 0xf3, 0x92, 0x10, 0x86, 0x10, 0x62, 0xaf, 0x26, 0x44, 0x0d, 0x77, 0x95,
0x0e, 0x23, 0x67, 0x19, 0x1f, 0x77, 0xd6, 0x75, 0x0e, 0x3a, 0x7f, 0x72, 0x6b, 0xdf, 0xb2, 0xb2, 0x20, 0xe4, 0x36, 0x98, 0xb9, 0xe4, 0x1f, 0x2a, 0xf6, 0xdb, 0xc8, 0x2f, 0x8f, 0xc5, 0xdd, 0x9f,
0x23, 0x3c, 0x83, 0x81, 0x35, 0x85, 0x0f, 0x3b, 0xe0, 0xd6, 0x49, 0xe6, 0x8f, 0x6e, 0xe9, 0x5e, 0xa9, 0x76, 0x04, 0x83, 0xab, 0x66, 0xd2, 0x24, 0x8e, 0x52, 0x24, 0xf7, 0xa1, 0xed, 0xe7, 0x9b,
0x25, 0xb2, 0x92, 0xaf, 0x11, 0xb5, 0x0c, 0x5f, 0x23, 0x6a, 0xfb, 0x64, 0x47, 0x5f, 0x07, 0xe6, 0x12, 0x18, 0xdd, 0xd1, 0xd6, 0xf2, 0x3d, 0x7a, 0xaa, 0xcc, 0x79, 0x07, 0x1b, 0x27, 0xd4, 0x8f,
0x07, 0x9f, 0xfc, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x34, 0xce, 0x17, 0xf1, 0x03, 0x00, 0x00, 0x98, 0xd2, 0x89, 0x40, 0x83, 0x4b, 0xa1, 0xf4, 0xe7, 0x67, 0x72, 0x00, 0x1d, 0x2a, 0xf7, 0x23,
0x4d, 0xf6, 0x5f, 0x0d, 0x56, 0xad, 0xcf, 0x2b, 0x0a, 0x9d, 0x3e, 0x98, 0x12, 0x38, 0xef, 0xcd,
0x99, 0x81, 0xf9, 0x16, 0x69, 0x78, 0x3e, 0x57, 0x54, 0xbf, 0xdd, 0xec, 0xf5, 0x1a, 0x19, 0x40,
0x4f, 0xf1, 0xca, 0x4e, 0xde, 0x83, 0xe9, 0xe1, 0x2c, 0x9e, 0xe0, 0x5f, 0x1f, 0x7a, 0x00, 0x3d,
0x85, 0x2c, 0xb9, 0xee, 0x42, 0xef, 0x45, 0x94, 0x26, 0x18, 0x14, 0x0a, 0x2f, 0xfd, 0xaa, 0x39,
0xcf, 0xa0, 0x5f, 0xd4, 0x5d, 0x7b, 0x99, 0xaf, 0x38, 0xfd, 0x39, 0xc5, 0xf4, 0x42, 0x91, 0x6d,
0x15, 0x5f, 0x87, 0x9c, 0x4d, 0x7d, 0x07, 0x6e, 0xc1, 0x86, 0xe0, 0x55, 0xee, 0xd4, 0x85, 0x3b,
0xbb, 0xe2, 0x2e, 0x37, 0xa7, 0xf3, 0x18, 0xfa, 0x05, 0x98, 0xec, 0xe8, 0x5e, 0xb9, 0xf5, 0x55,
0x9f, 0x9a, 0xbc, 0x64, 0xf4, 0xcd, 0x80, 0xc6, 0x61, 0xc6, 0x2e, 0xc8, 0x29, 0x74, 0x94, 0x4f,
0xc9, 0xce, 0xaf, 0x7f, 0x4d, 0xf6, 0xcd, 0x95, 0x79, 0x29, 0xe7, 0x1a, 0x39, 0x82, 0xa6, 0xf0,
0x15, 0xf9, 0xbf, 0x5e, 0x5b, 0xb2, 0xb1, 0x7d, 0x63, 0x79, 0xb2, 0x40, 0x39, 0x81, 0x56, 0x6e,
0x0a, 0x52, 0xaf, 0xac, 0x78, 0xd4, 0xde, 0x5e, 0x91, 0x2d, 0x03, 0xe5, 0x1b, 0x5f, 0x00, 0xaa,
0x58, 0x6c, 0x01, 0xa8, 0x66, 0x93, 0x35, 0xf2, 0x12, 0xda, 0xd2, 0x00, 0xa4, 0x5e, 0x5b, 0x35,
0x90, 0xbd, 0xb3, 0x2a, 0x5d, 0xc6, 0x92, 0xab, 0x23, 0x8b, 0xbc, 0x65, 0x7f, 0x2c, 0x60, 0xd5,
0x36, 0xee, 0xac, 0x9d, 0xb5, 0xc4, 0x9f, 0xf4, 0xc1, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb7,
0xf8, 0x55, 0xb6, 0xc5, 0x07, 0x00, 0x00,
} }

View File

@ -1,5 +1,5 @@
// Code generated by protoc-gen-micro. DO NOT EDIT. // Code generated by protoc-gen-micro. DO NOT EDIT.
// source: micro/go-micro/auth/service/proto/auth.proto // source: auth/service/proto/auth.proto
package go_micro_auth package go_micro_auth
@ -35,8 +35,11 @@ var _ server.Option
type AuthService interface { type AuthService interface {
Generate(ctx context.Context, in *GenerateRequest, opts ...client.CallOption) (*GenerateResponse, error) Generate(ctx context.Context, in *GenerateRequest, opts ...client.CallOption) (*GenerateResponse, error)
Grant(ctx context.Context, in *GrantRequest, opts ...client.CallOption) (*GrantResponse, error)
Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error) Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error)
Revoke(ctx context.Context, in *RevokeRequest, opts ...client.CallOption) (*RevokeResponse, error) Revoke(ctx context.Context, in *RevokeRequest, opts ...client.CallOption) (*RevokeResponse, error)
Inspect(ctx context.Context, in *InspectRequest, opts ...client.CallOption) (*InspectResponse, error)
Refresh(ctx context.Context, in *RefreshRequest, opts ...client.CallOption) (*RefreshResponse, error)
} }
type authService struct { type authService struct {
@ -61,6 +64,16 @@ func (c *authService) Generate(ctx context.Context, in *GenerateRequest, opts ..
return out, nil return out, nil
} }
func (c *authService) Grant(ctx context.Context, in *GrantRequest, opts ...client.CallOption) (*GrantResponse, error) {
req := c.c.NewRequest(c.name, "Auth.Grant", in)
out := new(GrantResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authService) Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error) { func (c *authService) Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error) {
req := c.c.NewRequest(c.name, "Auth.Verify", in) req := c.c.NewRequest(c.name, "Auth.Verify", in)
out := new(VerifyResponse) out := new(VerifyResponse)
@ -81,19 +94,45 @@ func (c *authService) Revoke(ctx context.Context, in *RevokeRequest, opts ...cli
return out, nil return out, nil
} }
func (c *authService) Inspect(ctx context.Context, in *InspectRequest, opts ...client.CallOption) (*InspectResponse, error) {
req := c.c.NewRequest(c.name, "Auth.Inspect", in)
out := new(InspectResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authService) Refresh(ctx context.Context, in *RefreshRequest, opts ...client.CallOption) (*RefreshResponse, error) {
req := c.c.NewRequest(c.name, "Auth.Refresh", in)
out := new(RefreshResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Auth service // Server API for Auth service
type AuthHandler interface { type AuthHandler interface {
Generate(context.Context, *GenerateRequest, *GenerateResponse) error Generate(context.Context, *GenerateRequest, *GenerateResponse) error
Grant(context.Context, *GrantRequest, *GrantResponse) error
Verify(context.Context, *VerifyRequest, *VerifyResponse) error Verify(context.Context, *VerifyRequest, *VerifyResponse) error
Revoke(context.Context, *RevokeRequest, *RevokeResponse) error Revoke(context.Context, *RevokeRequest, *RevokeResponse) error
Inspect(context.Context, *InspectRequest, *InspectResponse) error
Refresh(context.Context, *RefreshRequest, *RefreshResponse) error
} }
func RegisterAuthHandler(s server.Server, hdlr AuthHandler, opts ...server.HandlerOption) error { func RegisterAuthHandler(s server.Server, hdlr AuthHandler, opts ...server.HandlerOption) error {
type auth interface { type auth interface {
Generate(ctx context.Context, in *GenerateRequest, out *GenerateResponse) error Generate(ctx context.Context, in *GenerateRequest, out *GenerateResponse) error
Grant(ctx context.Context, in *GrantRequest, out *GrantResponse) error
Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error
Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error
Inspect(ctx context.Context, in *InspectRequest, out *InspectResponse) error
Refresh(ctx context.Context, in *RefreshRequest, out *RefreshResponse) error
} }
type Auth struct { type Auth struct {
auth auth
@ -110,6 +149,10 @@ func (h *authHandler) Generate(ctx context.Context, in *GenerateRequest, out *Ge
return h.AuthHandler.Generate(ctx, in, out) return h.AuthHandler.Generate(ctx, in, out)
} }
func (h *authHandler) Grant(ctx context.Context, in *GrantRequest, out *GrantResponse) error {
return h.AuthHandler.Grant(ctx, in, out)
}
func (h *authHandler) Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error { func (h *authHandler) Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error {
return h.AuthHandler.Verify(ctx, in, out) return h.AuthHandler.Verify(ctx, in, out)
} }
@ -117,3 +160,11 @@ func (h *authHandler) Verify(ctx context.Context, in *VerifyRequest, out *Verify
func (h *authHandler) Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error { func (h *authHandler) Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error {
return h.AuthHandler.Revoke(ctx, in, out) return h.AuthHandler.Revoke(ctx, in, out)
} }
func (h *authHandler) Inspect(ctx context.Context, in *InspectRequest, out *InspectResponse) error {
return h.AuthHandler.Inspect(ctx, in, out)
}
func (h *authHandler) Refresh(ctx context.Context, in *RefreshRequest, out *RefreshResponse) error {
return h.AuthHandler.Refresh(ctx, in, out)
}

View File

@ -4,47 +4,81 @@ package go.micro.auth;
service Auth { service Auth {
rpc Generate(GenerateRequest) returns (GenerateResponse) {}; rpc Generate(GenerateRequest) returns (GenerateResponse) {};
rpc Grant(GrantRequest) returns (GrantResponse) {};
rpc Verify(VerifyRequest) returns (VerifyResponse) {}; rpc Verify(VerifyRequest) returns (VerifyResponse) {};
rpc Revoke(RevokeRequest) returns (RevokeResponse) {}; rpc Revoke(RevokeRequest) returns (RevokeResponse) {};
rpc Inspect(InspectRequest) returns (InspectResponse) {};
rpc Refresh(RefreshRequest) returns (RefreshResponse) {};
} }
message Account{ message Token {
string id = 1; string token = 1;
string token = 2; string type = 2;
int64 created = 3; int64 created = 3;
int64 expiry = 4; int64 expiry = 4;
repeated Role roles = 5; string subject = 5;
map<string, string> metadata = 6; repeated string roles = 6;
map<string, string> metadata = 7;
} }
message Role { message Account {
string name = 1; string id = 1;
Resource resource = 2; Token secret = 2;
repeated string roles = 3;
map<string, string> metadata = 4;
} }
message Resource{ message Resource{
string name = 1; string name = 1;
string type = 2; string type = 2;
string endpoint = 3;
} }
message GenerateRequest { message GenerateRequest {
Account account = 1; string id = 1;
repeated string roles = 2;
map<string, string> metadata = 3;
int64 secret_expiry = 4;
} }
message GenerateResponse { message GenerateResponse {
Account account = 1; Account account = 1;
} }
message VerifyRequest { message GrantRequest {
string token = 1; string role = 1;
Resource resource = 2;
} }
message VerifyResponse { message GrantResponse {}
message VerifyRequest {
Account account = 1; Account account = 1;
Resource resource = 2;
} }
message VerifyResponse {}
message RevokeRequest { message RevokeRequest {
string token = 1; string role = 1;
Resource resource = 2;
} }
message RevokeResponse {} message RevokeResponse {}
message InspectRequest {
string token = 1;
}
message InspectResponse {
Account account = 1;
}
message RefreshRequest {
string secret = 1;
int64 token_expiry = 2;
}
message RefreshResponse {
Token token = 1;
}

View File

@ -2,10 +2,13 @@ package service
import ( import (
"context" "context"
"strings"
"time" "time"
"github.com/micro/go-micro/v2/auth" "github.com/micro/go-micro/v2/auth"
pb "github.com/micro/go-micro/v2/auth/service/proto" pb "github.com/micro/go-micro/v2/auth/service/proto"
"github.com/micro/go-micro/v2/auth/token"
"github.com/micro/go-micro/v2/auth/token/jwt"
"github.com/micro/go-micro/v2/client" "github.com/micro/go-micro/v2/client"
) )
@ -20,13 +23,14 @@ func NewAuth(opts ...auth.Option) auth.Auth {
type svc struct { type svc struct {
options auth.Options options auth.Options
auth pb.AuthService auth pb.AuthService
jwt token.Provider
} }
func (s *svc) String() string { func (s *svc) String() string {
return "service" return "service"
} }
func (s *svc) Init(opts ...auth.Option) error { func (s *svc) Init(opts ...auth.Option) {
for _, o := range opts { for _, o := range opts {
o(&s.options) o(&s.options)
} }
@ -34,99 +38,140 @@ func (s *svc) Init(opts ...auth.Option) error {
dc := client.DefaultClient dc := client.DefaultClient
s.auth = pb.NewAuthService("go.micro.auth", dc) s.auth = pb.NewAuthService("go.micro.auth", dc)
return nil // if we have a JWT public key passed as an option,
// we can decode tokens with the type "JWT" locally
// and not have to make an RPC call
if key := s.options.PublicKey; len(key) > 0 {
s.jwt = jwt.NewTokenProvider(token.WithPublicKey(key))
}
} }
func (s *svc) Options() auth.Options { func (s *svc) Options() auth.Options {
return s.options return s.options
} }
// Generate a new auth account // Generate a new account
func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) { func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
// construct the request
options := auth.NewGenerateOptions(opts...) options := auth.NewGenerateOptions(opts...)
sa := &auth.Account{
rsp, err := s.auth.Generate(context.TODO(), &pb.GenerateRequest{
Id: id, Id: id,
Roles: options.Roles, Roles: options.Roles,
Metadata: options.Metadata, Metadata: options.Metadata,
} SecretExpiry: int64(options.SecretExpiry.Seconds()),
req := &pb.GenerateRequest{Account: serializeAccount(sa)} })
// execute the request
resp, err := s.auth.Generate(context.Background(), req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// format the response return serializeAccount(rsp.Account), nil
return deserializeAccount(resp.Account), nil
} }
// Revoke an authorization account // Grant access to a resource
func (s *svc) Revoke(token string) error { func (s *svc) Grant(role string, res *auth.Resource) error {
// contruct the request _, err := s.auth.Grant(context.TODO(), &pb.GrantRequest{
req := &pb.RevokeRequest{Token: token} Role: role,
Resource: &pb.Resource{
// execute the request Type: res.Type,
_, err := s.auth.Revoke(context.Background(), req) Name: res.Name,
Endpoint: res.Endpoint,
},
})
return err return err
} }
// Verify an account token // Revoke access to a resource
func (s *svc) Verify(token string) (*auth.Account, error) { func (s *svc) Revoke(role string, res *auth.Resource) error {
resp, err := s.auth.Verify(context.Background(), &pb.VerifyRequest{Token: token}) _, err := s.auth.Revoke(context.TODO(), &pb.RevokeRequest{
Role: role,
Resource: &pb.Resource{
Type: res.Type,
Name: res.Name,
Endpoint: res.Endpoint,
},
})
return err
}
// Verify an account has access to a resource
func (s *svc) Verify(acc *auth.Account, res *auth.Resource) error {
_, err := s.auth.Verify(context.TODO(), &pb.VerifyRequest{
Account: &pb.Account{
Id: acc.ID,
Roles: acc.Roles,
},
Resource: &pb.Resource{
Type: res.Type,
Name: res.Name,
Endpoint: res.Endpoint,
},
})
return err
}
// 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
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
}
}
rsp, err := s.auth.Inspect(context.TODO(), &pb.InspectRequest{
Token: token,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return deserializeAccount(resp.Account), nil return serializeAccount(rsp.Account), nil
} }
func serializeAccount(sa *auth.Account) *pb.Account { // Refresh an account using a secret
roles := make([]*pb.Role, len(sa.Roles)) func (s *svc) Refresh(secret string, opts ...auth.RefreshOption) (*auth.Token, error) {
for i, r := range sa.Roles { options := auth.NewRefreshOptions(opts...)
roles[i] = &pb.Role{
Name: r.Name, rsp, err := s.auth.Refresh(context.Background(), &pb.RefreshRequest{
Secret: secret,
TokenExpiry: int64(options.TokenExpiry.Seconds()),
})
if err != nil {
return nil, err
} }
if r.Resource != nil { return serializeToken(rsp.Token), nil
roles[i].Resource = &pb.Resource{ }
Name: r.Resource.Name,
Type: r.Resource.Type,
}
}
}
return &pb.Account{ func serializeToken(t *pb.Token) *auth.Token {
Id: sa.Id, return &auth.Token{
Roles: roles, Token: t.Token,
Metadata: sa.Metadata, Type: t.Type,
Created: time.Unix(t.Created, 0),
Expiry: time.Unix(t.Expiry, 0),
Subject: t.Subject,
Roles: t.Roles,
Metadata: t.Metadata,
} }
} }
func deserializeAccount(a *pb.Account) *auth.Account { func serializeAccount(a *pb.Account) *auth.Account {
// format the response var secret *auth.Token
sa := &auth.Account{ if a.Secret != nil {
Id: a.Id, secret = serializeToken(a.Secret)
Token: a.Token, }
Created: time.Unix(a.Created, 0),
Expiry: time.Unix(a.Expiry, 0), return &auth.Account{
ID: a.Id,
Roles: a.Roles,
Metadata: a.Metadata, Metadata: a.Metadata,
Secret: secret,
} }
sa.Roles = make([]*auth.Role, len(a.Roles))
for i, r := range a.Roles {
sa.Roles[i] = &auth.Role{
Name: r.Name,
}
if r.Resource != nil {
sa.Roles[i].Resource = &auth.Resource{
Name: r.Resource.Name,
Type: r.Resource.Type,
}
}
}
return sa
} }

72
auth/store/rules.go Normal file
View File

@ -0,0 +1,72 @@
package store
import (
"encoding/json"
"strings"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/store"
)
// Rule is an access control rule
type Rule struct {
Role string `json:"rule"`
Resource *auth.Resource `json:"resource"`
}
// Key to be used when written to the store
func (r *Rule) Key() string {
comps := []string{r.Resource.Type, r.Resource.Name, r.Resource.Endpoint, r.Role}
return strings.Join(comps, "/")
}
// Bytes returns json encoded bytes
func (r *Rule) Bytes() []byte {
bytes, _ := json.Marshal(r)
return bytes
}
// isValidRule returns a bool, indicating if a rule permits access to a
// resource for a given account
func isValidRule(rule Rule, acc *auth.Account, res *auth.Resource) bool {
if rule.Role == "*" {
return true
}
for _, role := range acc.Roles {
if rule.Role == role {
return true
}
// allow user.anything if role is user.*
if strings.HasSuffix(rule.Role, ".*") && strings.HasPrefix(rule.Role, role+".") {
return true
}
}
return false
}
// listRules gets all the rules from the store which have a key
// prefix matching the filters
func (s *Store) listRules(filters ...string) ([]Rule, error) {
// get the records from the store
prefix := strings.Join(filters, "/")
recs, err := s.opts.Store.Read(prefix, store.ReadPrefix())
if err != nil {
return nil, err
}
// unmarshal the records
rules := make([]Rule, 0, len(recs))
for _, rec := range recs {
var r Rule
if err := json.Unmarshal(rec.Value, &r); err != nil {
return nil, err
}
rules = append(rules, r)
}
// return the rules
return rules, nil
}

View File

@ -1,130 +1,159 @@
package store package store
import ( import (
"bytes"
"encoding/gob"
"time"
"github.com/google/uuid"
"github.com/micro/go-micro/v2/auth" "github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/errors" "github.com/micro/go-micro/v2/auth/token"
"github.com/micro/go-micro/v2/auth/token/basic"
"github.com/micro/go-micro/v2/store" "github.com/micro/go-micro/v2/store"
memStore "github.com/micro/go-micro/v2/store/memory"
) )
type Auth struct { // NewAuth returns a new default registry which is store
store store.Store func NewAuth(opts ...auth.Option) auth.Auth {
var s Store
s.Init(opts...)
return &s
}
// Store implementation of auth
type Store struct {
secretProvider token.Provider
tokenProvider token.Provider
opts auth.Options opts auth.Options
} }
// NewAuth returns an instance of store auth // String returns store
func NewAuth(opts ...auth.Option) auth.Auth { func (s *Store) String() string {
var options auth.Options return "store"
}
// Init the auth
func (s *Store) Init(opts ...auth.Option) {
for _, o := range opts { for _, o := range opts {
o(&options) o(&s.opts)
} }
return &Auth{ // use the default store as a fallback
store: store.DefaultStore, if s.opts.Store == nil {
opts: options, s.opts.Store = store.DefaultStore
}
// noop will not work for auth
if s.opts.Store.String() == "noop" {
s.opts.Store = memStore.NewStore()
}
if s.tokenProvider == nil {
s.tokenProvider = basic.NewTokenProvider(token.WithStore(s.opts.Store))
}
if s.secretProvider == nil {
s.secretProvider = basic.NewTokenProvider(token.WithStore(s.opts.Store))
} }
} }
// Init the auth package // Options returns the options
func (a *Auth) Init(opts ...auth.Option) error { func (s *Store) Options() auth.Options {
for _, o := range opts { return s.opts
o(&a.opts)
}
return nil
} }
// Options returns the options set // Generate a new account
func (a *Auth) Options() auth.Options { func (s *Store) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
return a.opts
}
// Generate a new auth Account
func (a *Auth) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
// generate the token
token, err := uuid.NewUUID()
if err != nil {
return nil, err
}
// parse the options // parse the options
options := auth.NewGenerateOptions(opts...) options := auth.NewGenerateOptions(opts...)
// construct the account // Generate a long-lived secret
sa := auth.Account{ secretOpts := []token.GenerateOption{
Id: id, token.WithExpiry(options.SecretExpiry),
Token: token.String(), token.WithMetadata(options.Metadata),
Created: time.Now(), token.WithRoles(options.Roles),
Metadata: options.Metadata,
Roles: options.Roles,
} }
secret, err := s.secretProvider.Generate(id, secretOpts...)
// encode the data to bytes
// TODO: replace with json
buf := &bytes.Buffer{}
e := gob.NewEncoder(buf)
if err := e.Encode(sa); err != nil {
return nil, err
}
// write to the store
err = a.store.Write(&store.Record{
Key: token.String(),
Value: buf.Bytes(),
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
// return the result // return the account
return &sa, nil return &auth.Account{
ID: id,
Roles: options.Roles,
Metadata: options.Metadata,
Secret: secret,
}, nil
} }
// Revoke an authorization Account // Grant access to a resource
func (a *Auth) Revoke(token string) error { func (s *Store) Grant(role string, res *auth.Resource) error {
records, err := a.store.Read(token, store.ReadSuffix()) r := Rule{role, res}
return s.opts.Store.Write(&store.Record{Key: r.Key(), Value: r.Bytes()})
}
// Revoke access to a resource
func (s *Store) Revoke(role string, res *auth.Resource) error {
r := Rule{role, res}
err := s.opts.Store.Delete(r.Key())
if err == store.ErrNotFound {
return auth.ErrNotFound
}
return err
}
// Verify an account has access to a resource
func (s *Store) Verify(acc *auth.Account, res *auth.Resource) error {
queries := [][]string{
{res.Type, "*"}, // check for wildcard resource type, e.g. service.*
{res.Type, res.Name, "*"}, // check for wildcard name, e.g. service.foo*
{res.Type, res.Name, res.Endpoint, "*"}, // check for wildcard endpoints, e.g. service.foo.ListFoo:*
{res.Type, res.Name, res.Endpoint}, // check for specific role, e.g. service.foo.ListFoo:admin
}
for _, q := range queries {
rules, err := s.listRules(q...)
if err != nil { if err != nil {
return err return err
} }
if len(records) == 0 {
return errors.BadRequest("go.micro.auth", "token not found")
}
for _, r := range records {
if err := a.store.Delete(r.Key); err != nil {
return errors.InternalServerError("go.micro.auth", "error deleting from store")
}
}
for _, rule := range rules {
if isValidRule(rule, acc, res) {
return nil return nil
} }
}
// Verify an account token
func (a *Auth) Verify(token string) (*auth.Account, error) {
// lookup the record by token
records, err := a.store.Read(token, store.ReadSuffix())
if err == store.ErrNotFound || len(records) == 0 {
return nil, errors.Unauthorized("go.micro.auth", "invalid token")
} else if err != nil {
return nil, errors.InternalServerError("go.micro.auth", "error reading store")
} }
// decode the result return auth.ErrForbidden
// TODO: replace with json
b := bytes.NewBuffer(records[0].Value)
decoder := gob.NewDecoder(b)
var sa auth.Account
err = decoder.Decode(&sa)
// return the result
return &sa, err
} }
// String returns the implementation // Inspect a token
func (a *Auth) String() string { func (s *Store) Inspect(t string) (*auth.Account, error) {
return "store" tok, err := s.tokenProvider.Inspect(t)
if err == token.ErrInvalidToken || err == token.ErrNotFound {
return nil, auth.ErrInvalidToken
} else if err != nil {
return nil, err
}
return &auth.Account{
ID: tok.Subject,
Roles: tok.Roles,
Metadata: tok.Metadata,
}, nil
}
// Refresh an account using a secret
func (s *Store) Refresh(secret string, opts ...auth.RefreshOption) (*auth.Token, error) {
sec, err := s.secretProvider.Inspect(secret)
if err == token.ErrInvalidToken || err == token.ErrNotFound {
return nil, auth.ErrInvalidToken
} else if err != nil {
return nil, err
}
options := auth.NewRefreshOptions(opts...)
return s.tokenProvider.Generate(sec.Subject,
token.WithExpiry(options.TokenExpiry),
token.WithMetadata(sec.Metadata),
token.WithRoles(sec.Roles),
)
} }

287
auth/store/store_test.go Normal file
View File

@ -0,0 +1,287 @@
package store
import (
"log"
"testing"
"github.com/micro/go-micro/v2/auth"
memStore "github.com/micro/go-micro/v2/store/memory"
)
func TestGenerate(t *testing.T) {
s := memStore.NewStore()
a := NewAuth(auth.Store(s))
id := "test"
roles := []string{"admin"}
metadata := map[string]string{"foo": "bar"}
opts := []auth.GenerateOption{
auth.WithRoles(roles),
auth.WithMetadata(metadata),
}
// generate the account
acc, err := a.Generate(id, opts...)
if err != nil {
t.Fatalf("Generate returned an error: %v, expected nil", err)
}
// validate the account attributes were set correctly
if acc.ID != id {
t.Errorf("Generate returned %v as the ID, expected %v", acc.ID, id)
}
if len(acc.Roles) != len(roles) {
t.Errorf("Generate returned %v as the roles, expected %v", acc.Roles, roles)
}
if len(acc.Metadata) != len(metadata) {
t.Errorf("Generate returned %v as the metadata, expected %v", acc.Metadata, metadata)
}
// validate the secret is valid
if _, err := a.Refresh(acc.Secret.Token); err != nil {
t.Errorf("Generate returned an invalid secret, error: %v", err)
}
}
func TestGrant(t *testing.T) {
s := memStore.NewStore()
a := NewAuth(auth.Store(s))
res := &auth.Resource{Type: "service", Name: "Test", Endpoint: "Foo.Bar"}
if err := a.Grant("users.*", res); err != nil {
t.Fatalf("Grant returned an error: %v, expected nil", err)
}
recs, err := s.List()
if err != nil {
t.Fatalf("Could not read from the store: %v", err)
}
if len(recs) != 1 {
t.Errorf("Expected Grant to write 1 record, actually wrote %v", len(recs))
}
}
func TestRevoke(t *testing.T) {
s := memStore.NewStore()
a := NewAuth(auth.Store(s))
res := &auth.Resource{Type: "service", Name: "Test", Endpoint: "Foo.Bar"}
if err := a.Grant("users.*", res); err != nil {
t.Fatalf("Grant returned an error: %v, expected nil", err)
}
recs, err := s.List()
if err != nil {
t.Fatalf("Could not read from the store: %v", err)
}
if len(recs) != 1 {
t.Fatalf("Expected Grant to write 1 record, actually wrote %v", len(recs))
}
if err := a.Revoke("users.*", res); err != nil {
t.Fatalf("Revoke returned an error: %v, expected nil", err)
}
recs, err = s.List()
if err != nil {
t.Fatalf("Could not read from the store: %v", err)
}
if len(recs) != 0 {
t.Fatalf("Expected Revoke to delete 1 record, actually deleted %v", 1-len(recs))
}
}
func TestInspect(t *testing.T) {
a := NewAuth()
t.Run("Valid Token", func(t *testing.T) {
id := "test"
roles := []string{"admin"}
metadata := map[string]string{"foo": "bar"}
opts := []auth.GenerateOption{
auth.WithRoles(roles),
auth.WithMetadata(metadata),
}
// generate and inspect the token
acc, err := a.Generate("test", opts...)
if err != nil {
log.Fatalf("Generate returned an error: %v, expected nil", err)
}
tok, err := a.Refresh(acc.Secret.Token)
if err != nil {
log.Fatalf("Refresh returned an error: %v, expected nil", err)
}
acc2, err := a.Inspect(tok.Token)
if err != nil {
log.Fatalf("Inspect returned an error: %v, expected nil", err)
}
// validate the account attributes were retrieved correctly
if acc2.ID != id {
t.Errorf("Generate returned %v as the ID, expected %v", acc.ID, id)
}
if len(acc2.Roles) != len(roles) {
t.Errorf("Generate returned %v as the roles, expected %v", acc.Roles, roles)
}
if len(acc2.Metadata) != len(metadata) {
t.Errorf("Generate returned %v as the metadata, expected %v", acc.Metadata, metadata)
}
})
t.Run("Invalid Token", func(t *testing.T) {
_, err := a.Inspect("invalid token")
if err != auth.ErrInvalidToken {
t.Errorf("Inspect returned %v error, expected %v", err, auth.ErrInvalidToken)
}
})
}
func TestRefresh(t *testing.T) {
a := NewAuth()
t.Run("Valid Secret", func(t *testing.T) {
roles := []string{"admin"}
metadata := map[string]string{"foo": "bar"}
opts := []auth.GenerateOption{
auth.WithRoles(roles),
auth.WithMetadata(metadata),
}
// generate the account
acc, err := a.Generate("test", opts...)
if err != nil {
log.Fatalf("Generate returned an error: %v, expected nil", err)
}
// refresh the token
tok, err := a.Refresh(acc.Secret.Token)
if err != nil {
log.Fatalf("Refresh returned an error: %v, expected nil", err)
}
// validate the account attributes were set correctly
if acc.ID != tok.Subject {
t.Errorf("Refresh returned %v as the ID, expected %v", acc.ID, tok.Subject)
}
if len(acc.Roles) != len(tok.Roles) {
t.Errorf("Refresh returned %v as the roles, expected %v", acc.Roles, tok.Subject)
}
if len(acc.Metadata) != len(tok.Metadata) {
t.Errorf("Refresh returned %v as the metadata, expected %v", acc.Metadata, tok.Metadata)
}
})
t.Run("Invalid Secret", func(t *testing.T) {
_, err := a.Refresh("invalid secret")
if err != auth.ErrInvalidToken {
t.Errorf("Inspect returned %v error, expected %v", err, auth.ErrInvalidToken)
}
})
}
func TestVerify(t *testing.T) {
testRules := []struct {
Role string
Resource *auth.Resource
}{
{
Role: "*",
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.PublicList"},
},
{
Role: "user.*",
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.List"},
},
{
Role: "user.developer",
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.Update"},
},
{
Role: "admin",
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.Delete"},
},
{
Role: "admin",
Resource: &auth.Resource{Type: "service", Name: "*", Endpoint: "*"},
},
}
a := NewAuth()
for _, r := range testRules {
if err := a.Grant(r.Role, r.Resource); err != nil {
t.Fatalf("Grant returned an error: %v, expected nil", err)
}
}
testTable := []struct {
Name string
Roles []string
Resource *auth.Resource
Error error
}{
{
Name: "An account with no roles accessing a public endpoint",
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.PublicList"},
},
{
Name: "An account with no roles accessing a private endpoint",
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.Update"},
Error: auth.ErrForbidden,
},
{
Name: "An account with the user role accessing a user* endpoint",
Roles: []string{"user"},
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.List"},
},
{
Name: "An account with the user role accessing a user.admin endpoint",
Roles: []string{"user"},
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.Delete"},
Error: auth.ErrForbidden,
},
{
Name: "An account with the developer role accessing a user.developer endpoint",
Roles: []string{"user.developer"},
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.Update"},
},
{
Name: "An account with the developer role accessing an admin endpoint",
Roles: []string{"user.developer"},
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.Delete"},
Error: auth.ErrForbidden,
},
{
Name: "An admin account accessing an admin endpoint",
Roles: []string{"admin"},
Resource: &auth.Resource{Type: "service", Name: "go.micro.apps", Endpoint: "Apps.Delete"},
},
{
Name: "An admin account accessing a generic service endpoint",
Roles: []string{"admin"},
Resource: &auth.Resource{Type: "service", Name: "go.micro.foo", Endpoint: "Foo.Bar"},
},
{
Name: "An admin account accessing an unauthorised endpoint",
Roles: []string{"admin"},
Resource: &auth.Resource{Type: "infra", Name: "go.micro.foo", Endpoint: "Foo.Bar"},
Error: auth.ErrForbidden,
},
{
Name: "A account with no roles accessing an unauthorised endpoint",
Resource: &auth.Resource{Type: "infra", Name: "go.micro.foo", Endpoint: "Foo.Bar"},
Error: auth.ErrForbidden,
},
}
for _, tc := range testTable {
t.Run(tc.Name, func(t *testing.T) {
acc := &auth.Account{Roles: tc.Roles}
if err := a.Verify(acc, tc.Resource); err != tc.Error {
t.Errorf("Verify returned %v error, expected %v", err, tc.Error)
}
})
}
}

95
auth/token/basic/basic.go Normal file
View File

@ -0,0 +1,95 @@
package basic
import (
"encoding/json"
"time"
"github.com/google/uuid"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/auth/token"
"github.com/micro/go-micro/v2/store"
)
// Basic implementation of token provider, backed by the store
type Basic struct {
store store.Store
}
// NewTokenProvider returns an initialized basic provider
func NewTokenProvider(opts ...token.Option) token.Provider {
options := token.NewOptions(opts...)
if options.Store == nil {
options.Store = store.DefaultStore
}
return &Basic{
store: options.Store,
}
}
// Generate a token for an account
func (b *Basic) Generate(subject string, opts ...token.GenerateOption) (*auth.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,
}
// marshal the account to bytes
bytes, err := json.Marshal(token)
if err != nil {
return nil, err
}
// write to the store
err = b.store.Write(&store.Record{
Key: token.Token,
Value: bytes,
Expiry: options.Expiry,
})
if err != nil {
return nil, err
}
// return the token
return &token, nil
}
// Inspect a token
func (b *Basic) Inspect(t string) (*auth.Token, error) {
// lookup the token in the store
recs, err := b.store.Read(t)
if err == store.ErrNotFound {
return nil, token.ErrInvalidToken
} else if err != nil {
return nil, err
}
bytes := recs[0].Value
// unmarshal the bytes
var tok *auth.Token
if err := json.Unmarshal(bytes, &tok); 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
}
// String returns basic
func (b *Basic) String() string {
return "basic"
}

View File

@ -0,0 +1,80 @@
package basic
import (
"testing"
"time"
"github.com/micro/go-micro/v2/auth/token"
"github.com/micro/go-micro/v2/store/memory"
)
func TestGenerate(t *testing.T) {
store := memory.NewStore()
b := NewTokenProvider(token.WithStore(store))
_, err := b.Generate("test")
if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err)
}
recs, err := store.List()
if err != nil {
t.Fatalf("Unable to read from store: %v", err)
}
if len(recs) != 1 {
t.Errorf("Generate didn't write to the store, expected 1 record, got %v", len(recs))
}
}
func TestInspect(t *testing.T) {
store := memory.NewStore()
b := NewTokenProvider(token.WithStore(store))
t.Run("Valid token", func(t *testing.T) {
md := map[string]string{"foo": "bar"}
roles := []string{"admin"}
subject := "test"
opts := []token.GenerateOption{
token.WithMetadata(md),
token.WithRoles(roles),
}
tok, err := b.Generate(subject, opts...)
if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err)
}
tok2, err := b.Inspect(tok.Token)
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 len(tok2.Roles) != len(roles) {
t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles))
}
if len(tok2.Metadata) != len(md) {
t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md)
}
})
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 {
t.Fatalf("Inspect returned %v error, expected %v", err, token.ErrInvalidToken)
}
})
}

111
auth/token/jwt/jwt.go Normal file
View File

@ -0,0 +1,111 @@
package jwt
import (
"encoding/base64"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/auth/token"
)
// authClaims to be encoded in the JWT
type authClaims struct {
Roles []string `json:"roles"`
Metadata map[string]string `json:"metadata"`
jwt.StandardClaims
}
// JWT implementation of token provider
type JWT struct {
opts token.Options
}
// NewTokenProvider returns an initialized basic provider
func NewTokenProvider(opts ...token.Option) token.Provider {
return &JWT{
opts: token.NewOptions(opts...),
}
}
// Generate a new JWT
func (j *JWT) Generate(subject string, opts ...token.GenerateOption) (*auth.Token, error) {
// decode the private key
priv, err := base64.StdEncoding.DecodeString(j.opts.PrivateKey)
if err != nil {
return nil, err
}
// parse the private key
key, err := jwt.ParseRSAPrivateKeyFromPEM(priv)
if err != nil {
return nil, token.ErrEncodingToken
}
// parse the options
options := token.NewGenerateOptions(opts...)
// generate the JWT
expiry := time.Now().Add(options.Expiry)
t := jwt.NewWithClaims(jwt.SigningMethodRS256, authClaims{
options.Roles, options.Metadata, jwt.StandardClaims{
Subject: subject,
ExpiresAt: expiry.Unix(),
},
})
tok, err := t.SignedString(key)
if err != nil {
return nil, err
}
// return the token
return &auth.Token{
Subject: subject,
Token: tok,
Type: j.String(),
Created: time.Now(),
Expiry: expiry,
Roles: options.Roles,
Metadata: options.Metadata,
}, nil
}
// Inspect a JWT
func (j *JWT) Inspect(t string) (*auth.Token, error) {
// decode the public key
pub, err := base64.StdEncoding.DecodeString(j.opts.PublicKey)
if err != nil {
return nil, err
}
// parse the public key
res, err := jwt.ParseWithClaims(t, &authClaims{}, func(token *jwt.Token) (interface{}, error) {
return jwt.ParseRSAPublicKeyFromPEM(pub)
})
if err != nil {
return nil, token.ErrInvalidToken
}
// validate the token
if !res.Valid {
return nil, token.ErrInvalidToken
}
claims, ok := res.Claims.(*authClaims)
if !ok {
return nil, token.ErrInvalidToken
}
// return the token
return &auth.Token{
Token: t,
Subject: claims.Subject,
Metadata: claims.Metadata,
Roles: claims.Roles,
}, nil
}
// String returns JWT
func (j *JWT) String() string {
return "jwt"
}

View File

@ -0,0 +1,90 @@
package jwt
import (
"io/ioutil"
"testing"
"time"
"github.com/micro/go-micro/v2/auth/token"
)
func TestGenerate(t *testing.T) {
privKey, err := ioutil.ReadFile("test/sample_key")
if err != nil {
t.Fatalf("Unable to read private key: %v", err)
}
j := NewTokenProvider(
token.WithPrivateKey(string(privKey)),
)
_, err = j.Generate("test")
if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err)
}
}
func TestInspect(t *testing.T) {
pubKey, err := ioutil.ReadFile("test/sample_key.pub")
if err != nil {
t.Fatalf("Unable to read public key: %v", err)
}
privKey, err := ioutil.ReadFile("test/sample_key")
if err != nil {
t.Fatalf("Unable to read private key: %v", err)
}
j := NewTokenProvider(
token.WithPublicKey(string(pubKey)),
token.WithPrivateKey(string(privKey)),
)
t.Run("Valid token", func(t *testing.T) {
md := map[string]string{"foo": "bar"}
roles := []string{"admin"}
subject := "test"
opts := []token.GenerateOption{
token.WithMetadata(md),
token.WithRoles(roles),
}
tok, err := j.Generate(subject, opts...)
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.Subject != subject {
t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.Subject, subject)
}
if len(tok2.Roles) != len(roles) {
t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles))
}
if len(tok2.Metadata) != len(md) {
t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md)
}
})
t.Run("Expired token", func(t *testing.T) {
tok, err := j.Generate("foo", token.WithExpiry(-10*time.Second))
if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err)
}
if _, err = j.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 := j.Inspect("Invalid token")
if err != token.ErrInvalidToken {
t.Fatalf("Inspect returned %v error, expected %v", err, token.ErrInvalidToken)
}
})
}

View File

@ -0,0 +1 @@
LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS3dJQkFBS0NBZ0VBOFNiSlA1WGJFaWRSbTViMnNOcExHbzJlV2ZVNU9KZTBpemdySHdEOEg3RjZQa1BkCi9SbDkvMXBNVjdNaU8zTEh3dGhIQzJCUllxcisxd0Zkb1pDR0JZckxhWHVYRnFLMHZ1WmhQcUUzYXpqdUlIUXUKMEJIL2xYUU1xeUVxRjVNSTJ6ZWpDNHpNenIxNU9OK2dFNEpuaXBqcC9DZGpPUEFEbUpHK0JKOXFlRS9RUGVtLwptVWRJVC9MYUY3a1F4eVlLNVZLbitOZ09Xek1sektBQXBDbjdUVEtCVWU4RlpHNldTWDdMVjBlTEdIc29pYnhsCm85akRqbFk1b0JPY3pmcWVOV0hLNUdYQjdRd3BMTmg5NDZQelpucW9hcFdVZStZL1JPaUhpekpUY3I1Wk1TTDUKd2xFcThoTmhtaG01Tk5lL08rR2dqQkROU2ZVaDA2K3E0bmdtYm1OWDVoODM4QmJqUmN5YzM2ZHd6NkpVK2R1bwpSdFFoZ2lZOTEwcFBmOWJhdVhXcXdVQ1VhNHFzSHpqS1IwTC9OMVhYQXlsQ0RqeWVnWnp6Y093MkNIOFNrZkZVCnJnTHJQYkVCOWVnY0drMzgrYnBLczNaNlJyNSt0bkQxQklQSUZHTGVJMFVPQzAreGlCdjBvenhJRE9GbldhOVUKVEdEeFV4OG9qOFZJZVJuV0RxNk1jMWlKcDhVeWNpQklUUnR3NGRabzcweG1mbmVJV3pyM0tTTmFoU29nSmRSMApsYVF6QXVQM2FpV1hJTXAyc2M4U2MrQmwrTGpYbUJveEJyYUJIaDlLa0pKRWNnQUZ3czJib2pDbEpPWXhvRi9YCmdGS1NzSW5IRHJIVk95V1BCZTNmYWRFYzc3YituYi9leE96cjFFcnhoR2c5akZtcmtPK3M0eEdodjZNQ0F3RUEKQVFLQ0FnRUFqUzc1Q2VvUlRRcUtBNzZaaFNiNGEzNVlKRENtcEpSazFsRTNKYnFzNFYxRnhXaDBjZmJYeG9VMgpSdTRRYjUrZWhsdWJGSFQ2a1BxdG9uRWhRVExjMUNmVE9WbHJOb3hocDVZM2ZyUmlQcnNnNXcwK1R3RUtrcFJUCnltanJQTXdQbGxCM2U0NmVaYmVXWGc3R3FFVmptMGcxVFRRK0tocVM4R0w3VGJlTFhRN1ZTem9ydTNCNVRKMVEKeEN6TVB0dnQ2eDYrU3JrcmhvZG1iT3VNRkpDam1TbWxmck9pZzQ4Zkc3NUpERHRObXpLWHBEUVJpYUNodFJhVQpQRHpmUTlTamhYdFFqdkZvWFFFT3BqdkZVRjR2WldNUWNQNUw1VklDM3JRSWp4MFNzQTN6S0FwakVUbjJHNjN2CktZby8zVWttbzhkUCtGRHA3NCs5a3pLNHFFaFJycEl3bEtiN0VOZWtDUXZqUFl1K3pyKzMyUXdQNTJ2L2FveWQKdjJJaUY3M2laTU1vZDhhYjJuQStyVEI2T0cvOVlSYk5kV21tay9VTi9jUHYrN214TmZ6Y1d1ZU1XcThxMXh4eAptNTNpR0NSQ29PQ1lDQk4zcUFkb1JwYW5xd3lCOUxrLzFCQjBHUld3MjgxK3VhNXNYRnZBVDBKeTVURnduMncvClU1MlJKWFlNOXVhMFBvd214b0RDUWRuNFZYVkdNZGdXaHN4aXhHRlYwOUZObWJJQWJaN0xaWGtkS1gzc1ZVbTcKWU1WYWIzVVo2bEhtdXYzT1NzcHNVUlRqN1hiRzZpaVVlaDU1aW91OENWbnRndWtFcnEzQTQwT05FVzhjNDBzOQphVTBGaSs4eWZpQTViaVZHLzF0bWlucUVERkhuQStnWk1xNEhlSkZxcWZxaEZKa1JwRGtDZ2dFQkFQeGR1NGNKCm5Da1duZDdPWFlHMVM3UDdkVWhRUzgwSDlteW9uZFc5bGFCQm84RWRPeTVTZzNOUmsxQ2pNZFZ1a3FMcjhJSnkKeStLWk15SVpvSlJvbllaMEtIUUVMR3ZLbzFOS2NLQ1FJbnYvWHVCdFJpRzBVb1pQNVkwN0RpRFBRQWpYUjlXUwpBc0EzMmQ1eEtFOC91Y3h0MjVQVzJFakNBUmtVeHQ5d0tKazN3bC9JdXVYRlExTDdDWjJsOVlFUjlHeWxUbzhNCmxXUEY3YndtUFV4UVNKaTNVS0FjTzZweTVUU1lkdWQ2aGpQeXJwSXByNU42VGpmTlRFWkVBeU9LbXVpOHVkUkoKMUg3T3RQVEhGZElKQjNrNEJnRDZtRE1HbjB2SXBLaDhZN3NtRUZBbFkvaXlCZjMvOHk5VHVMb1BycEdqR3RHbgp4Y2RpMHFud2p0SGFNbFVDZ2dFQkFQU2Z0dVFCQ2dTU2JLUSswUEFSR2VVeEQyTmlvZk1teENNTmdHUzJ5Ull3CjRGaGV4ZWkwMVJoaFk1NjE3UjduR1dzb0czd1RQa3dvRTJtbE1aQkoxeWEvUU9RRnQ3WG02OVl0RGh0T2FWbDgKL0o4dlVuSTBtWmxtT2pjTlRoYnVPZDlNSDlRdGxIRUMxMlhYdHJNb3Fsb0U2a05TT0pJalNxYm9wcDRXc1BqcApvZTZ0Nkdyd1RhOHBHeUJWWS90Mi85Ym5ORHVPVlpjODBaODdtY2gzcDNQclBqU3h5di9saGxYMFMwYUdHTkhTCk1XVjdUa25OaGo1TWlIRXFnZ1pZemtBWTkyd1JoVENnU1A2M0VNcitUWXFudXVuMXJHbndPYm95TDR2aFRpV0UKcU42UDNCTFlCZ1FpMllDTDludEJrOEl6RHZyd096dW5GVnhhZ0g5SVVoY0NnZ0VCQUwzQXlLa1BlOENWUmR6cQpzL284VkJDZmFSOFhhUGRnSGxTek1BSXZpNXEwNENqckRyMlV3MHZwTVdnM1hOZ0xUT3g5bFJpd3NrYk9SRmxHCmhhd3hRUWlBdkk0SE9WTlBTU0R1WHVNTG5USTQ0S0RFNlMrY2cxU0VMS2pWbDVqcDNFOEpkL1RJMVpLc0xBQUsKZTNHakM5UC9ZbE8xL21ndW4xNjVkWk01cFAwWHBPb2FaeFV2RHFFTktyekR0V1g0RngyOTZlUzdaSFJodFpCNwovQ2t1VUhlcmxrN2RDNnZzdWhTaTh2eTM3c0tPbmQ0K3c4cVM4czhZYVZxSDl3ZzVScUxxakp0bmJBUnc3alVDCm9KQ053M1hNdnc3clhaYzRTbnhVQUNMRGJNV2lLQy9xL1ZGWW9oTEs2WkpUVkJscWd5cjBSYzBRWmpDMlNJb0kKMjRwRWt3VUNnZ0VCQUpqb0FJVVNsVFY0WlVwaExXN3g4WkxPa01UWjBVdFFyd2NPR0hSYndPUUxGeUNGMVFWNQppejNiR2s4SmZyZHpVdk1sTmREZm9uQXVHTHhQa3VTVEUxWlg4L0xVRkJveXhyV3dvZ0cxaUtwME11QTV6em90CjROai9DbUtCQVkvWnh2anA5M2RFS21aZGxWQkdmeUFMeWpmTW5MWUovZXh5L09YSnhPUktZTUttSHg4M08zRWsKMWhvb0FwbTZabTIzMjRGME1iVU1ham5Idld2ZjhHZGJTNk5zcHd4L0dkbk1tYVMrdUJMVUhVMkNLbmc1bEIwVAp4OWJITmY0dXlPbTR0dXRmNzhCd1R5V3UreEdrVW0zZ2VZMnkvR1hqdDZyY2l1ajFGNzFDenZzcXFmZThTcDdJCnd6SHdxcTNzVHR5S2lCYTZuYUdEYWpNR1pKYSt4MVZJV204Q2dnRUJBT001ajFZR25Ba0pxR0czQWJSVDIvNUMKaVVxN0loYkswOGZsSGs5a2YwUlVjZWc0ZVlKY3dIRXJVaE4rdWQyLzE3MC81dDYra0JUdTVZOUg3bkpLREtESQpoeEg5SStyamNlVkR0RVNTRkluSXdDQ1lrOHhOUzZ0cHZMV1U5b0pibGFKMlZsalV2NGRFWGVQb0hkREh1Zk9ZClVLa0lsV2E3Uit1QzNEOHF5U1JrQnFLa3ZXZ1RxcFNmTVNkc1ZTeFIzU2Q4SVhFSHFjTDNUNEtMWGtYNEdEamYKMmZOSTFpZkx6ekhJMTN3Tk5IUTVRNU9SUC9pell2QzVzZkx4U2ZIUXJiMXJZVkpKWkI5ZjVBUjRmWFpHSVFsbApjMG8xd0JmZFlqMnZxVDlpR09IQnNSSTlSL2M2RzJQcUt3aFRpSzJVR2lmVFNEUVFuUkF6b2tpQVkrbE8vUjQ9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

View File

@ -0,0 +1 @@
LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUE4U2JKUDVYYkVpZFJtNWIyc05wTApHbzJlV2ZVNU9KZTBpemdySHdEOEg3RjZQa1BkL1JsOS8xcE1WN01pTzNMSHd0aEhDMkJSWXFyKzF3RmRvWkNHCkJZckxhWHVYRnFLMHZ1WmhQcUUzYXpqdUlIUXUwQkgvbFhRTXF5RXFGNU1JMnplakM0ek16cjE1T04rZ0U0Sm4KaXBqcC9DZGpPUEFEbUpHK0JKOXFlRS9RUGVtL21VZElUL0xhRjdrUXh5WUs1VktuK05nT1d6TWx6S0FBcENuNwpUVEtCVWU4RlpHNldTWDdMVjBlTEdIc29pYnhsbzlqRGpsWTVvQk9jemZxZU5XSEs1R1hCN1F3cExOaDk0NlB6ClpucW9hcFdVZStZL1JPaUhpekpUY3I1Wk1TTDV3bEVxOGhOaG1obTVOTmUvTytHZ2pCRE5TZlVoMDYrcTRuZ20KYm1OWDVoODM4QmJqUmN5YzM2ZHd6NkpVK2R1b1J0UWhnaVk5MTBwUGY5YmF1WFdxd1VDVWE0cXNIempLUjBMLwpOMVhYQXlsQ0RqeWVnWnp6Y093MkNIOFNrZkZVcmdMclBiRUI5ZWdjR2szOCticEtzM1o2UnI1K3RuRDFCSVBJCkZHTGVJMFVPQzAreGlCdjBvenhJRE9GbldhOVVUR0R4VXg4b2o4VkllUm5XRHE2TWMxaUpwOFV5Y2lCSVRSdHcKNGRabzcweG1mbmVJV3pyM0tTTmFoU29nSmRSMGxhUXpBdVAzYWlXWElNcDJzYzhTYytCbCtMalhtQm94QnJhQgpIaDlLa0pKRWNnQUZ3czJib2pDbEpPWXhvRi9YZ0ZLU3NJbkhEckhWT3lXUEJlM2ZhZEVjNzdiK25iL2V4T3pyCjFFcnhoR2c5akZtcmtPK3M0eEdodjZNQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=

96
auth/token/options.go Normal file
View File

@ -0,0 +1,96 @@
package token
import (
"time"
"github.com/micro/go-micro/v2/store"
)
type Options struct {
// Store to persist the tokens
Store store.Store
// PublicKey base64 encoded, used by JWT
PublicKey string
// PrivateKey base64 encoded, used by JWT
PrivateKey string
}
type Option func(o *Options)
// WithStore sets the token providers store
func WithStore(s store.Store) Option {
return func(o *Options) {
o.Store = s
}
}
// WithPublicKey sets the JWT public key
func WithPublicKey(key string) Option {
return func(o *Options) {
o.PublicKey = key
}
}
// WithPrivateKey sets the JWT private key
func WithPrivateKey(key string) Option {
return func(o *Options) {
o.PrivateKey = key
}
}
func NewOptions(opts ...Option) Options {
var options Options
for _, o := range opts {
o(&options)
}
//set default store
if options.Store == nil {
options.Store = store.DefaultStore
}
return 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
}
type GenerateOption func(o *GenerateOptions)
// WithExpiry for the generated account's token expires
func WithExpiry(d time.Duration) GenerateOption {
return func(o *GenerateOptions) {
o.Expiry = d
}
}
// 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
}
}
// NewGenerateOptions from a slice of options
func NewGenerateOptions(opts ...GenerateOption) GenerateOptions {
var options GenerateOptions
for _, o := range opts {
o(&options)
}
//set default Expiry of token
if options.Expiry == 0 {
options.Expiry = time.Minute * 15
}
return options
}

23
auth/token/token.go Normal file
View File

@ -0,0 +1,23 @@
package token
import (
"errors"
"github.com/micro/go-micro/v2/auth"
)
var (
// ErrNotFound is returned when a token cannot be found
ErrNotFound = errors.New("token not found")
// ErrEncodingToken is returned when the service encounters an error during encoding
ErrEncodingToken = errors.New("error encoding the token")
// ErrInvalidToken is returned when the token provided is not valid
ErrInvalidToken = errors.New("invalid token provided")
)
// Provider generates and inspects tokens
type Provider interface {
Generate(subject string, opts ...GenerateOption) (*auth.Token, error)
Inspect(token string) (*auth.Token, error)
String() string
}

View File

@ -70,8 +70,7 @@ import (
memTracer "github.com/micro/go-micro/v2/debug/trace/memory" memTracer "github.com/micro/go-micro/v2/debug/trace/memory"
// auth // auth
jwtAuth "github.com/micro/go-micro/v2/auth/jwt" svcAuth "github.com/micro/go-micro/v2/auth/service"
sAuth "github.com/micro/go-micro/v2/auth/service"
storeAuth "github.com/micro/go-micro/v2/auth/store" storeAuth "github.com/micro/go-micro/v2/auth/store"
// auth providers // auth providers
@ -271,11 +270,6 @@ var (
EnvVars: []string{"MICRO_AUTH_PRIVATE_KEY"}, EnvVars: []string{"MICRO_AUTH_PRIVATE_KEY"},
Usage: "Private key for JWT auth (base64 encoded PEM)", Usage: "Private key for JWT auth (base64 encoded PEM)",
}, },
&cli.StringSliceFlag{
Name: "auth_exclude",
EnvVars: []string{"MICRO_AUTH_EXCLUDE"},
Usage: "Comma-separated list of endpoints excluded from authentication, e.g. Users.ListUsers",
},
&cli.StringFlag{ &cli.StringFlag{
Name: "auth_provider", Name: "auth_provider",
EnvVars: []string{"MICRO_AUTH_PROVIDER"}, EnvVars: []string{"MICRO_AUTH_PROVIDER"},
@ -365,9 +359,8 @@ var (
} }
DefaultAuths = map[string]func(...auth.Option) auth.Auth{ DefaultAuths = map[string]func(...auth.Option) auth.Auth{
"service": sAuth.NewAuth, "service": svcAuth.NewAuth,
"store": storeAuth.NewAuth, "store": storeAuth.NewAuth,
"jwt": jwtAuth.NewAuth,
} }
DefaultAuthProviders = map[string]func(...provider.Option) provider.Provider{ DefaultAuthProviders = map[string]func(...provider.Option) provider.Provider{
@ -665,7 +658,7 @@ func (c *cmd) Before(ctx *cli.Context) error {
} }
if len(ctx.String("auth_token")) > 0 { if len(ctx.String("auth_token")) > 0 {
authOpts = append(authOpts, auth.Token(ctx.String("auth_token"))) authOpts = append(authOpts, auth.ServiceToken(ctx.String("auth_token")))
} }
if len(ctx.String("auth_public_key")) > 0 { if len(ctx.String("auth_public_key")) > 0 {
@ -676,10 +669,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key"))) authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key")))
} }
if len(ctx.StringSlice("auth_exclude")) > 0 {
authOpts = append(authOpts, auth.Exclude(ctx.StringSlice("auth_exclude")...))
}
if name := ctx.String("auth_provider"); len(name) > 0 { if name := ctx.String("auth_provider"); len(name) > 0 {
p, ok := DefaultAuthProviders[name] p, ok := DefaultAuthProviders[name]
if !ok { if !ok {
@ -707,9 +696,7 @@ func (c *cmd) Before(ctx *cli.Context) error {
} }
if len(authOpts) > 0 { if len(authOpts) > 0 {
if err := (*c.opts.Auth).Init(authOpts...); err != nil { (*c.opts.Auth).Init(authOpts...)
logger.Fatalf("Error configuring auth: %v", err)
}
} }
if ctx.String("config") == "service" { if ctx.String("config") == "service" {

View File

@ -118,7 +118,7 @@ func (s *service) Init(opts ...Option) {
// May need to re-read value on change // May need to re-read value on change
// TODO: should be scoped to micro/auth/token // TODO: should be scoped to micro/auth/token
if tk, _ := config.Get("token"); len(tk) > 0 { if tk, _ := config.Get("token"); len(tk) > 0 {
s.opts.Auth.Init(auth.Token(tk)) s.opts.Auth.Init(auth.ServiceToken(tk))
} }
}) })
} }

View File

@ -164,6 +164,11 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
return h(ctx, req, rsp) return h(ctx, req, rsp)
} }
// Check for auth service endpoints which should be excluded from auth
if strings.HasPrefix(req.Endpoint(), "Auth.") {
return h(ctx, req, rsp)
}
// Extract the token if present. Note: if noop is being used // Extract the token if present. Note: if noop is being used
// then the token can be blank without erroring // then the token can be blank without erroring
var token string var token string
@ -177,29 +182,16 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
} }
// Verify the token // Verify the token
account, authErr := a.Verify(token) account, err := a.Inspect(token)
if err != nil {
return errors.Unauthorized("go.micro.auth", err.Error())
}
// If there is an account, set it in the context // There is an account, set it in the context
if authErr == nil {
var err error
ctx, err = auth.ContextWithAccount(ctx, account) ctx, err = auth.ContextWithAccount(ctx, account)
if err != nil { if err != nil {
return err return err
} }
}
// Return if the user disabled auth on this endpoint
for _, e := range a.Options().Exclude {
if e == req.Endpoint() {
return h(ctx, req, rsp)
}
}
// If the authErr is set, prevent the user from calling the endpoint
if authErr != nil {
return errors.Unauthorized("go.micro.auth", authErr.Error())
}
// The user is authorised, allow the call // The user is authorised, allow the call
return h(ctx, req, rsp) return h(ctx, req, rsp)