Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ import (

"gopkg.in/oauth2.v3/manage"
"gopkg.in/oauth2.v3/server"
"gopkg.in/oauth2.v3/store/token"
"gopkg.in/oauth2.v3/store"
)

func main() {
manager := manage.NewRedisManager(
&token.RedisConfig{Addr: "192.168.33.70:6379"},
)
manager := manage.NewDefaultManager()
manager.MapTokenStorage(store.NewMemoryTokenStore(0))
// client test store
manager.MapClientStorage(store.NewTestClientStore())

srv := server.NewServer(server.NewConfig(), manager)
srv.SetUserAuthorizationHandler(func(w http.ResponseWriter, r *http.Request) (userID string, err error) {
// validation and to get the user id
Expand Down Expand Up @@ -73,6 +75,12 @@ Example

Simulation examples of authorization code model, please check [example](/example)

Token storage implements
------------------------

* [Redis](https://github.com/go-oauth2/redis)
* [MongoDB](https://github.com/go-oauth2/mongo)

License
-------

Expand Down
29 changes: 0 additions & 29 deletions errors/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,6 @@ package errors

import "errors"

var (
// ErrUnauthorizedClient unauthorized client
ErrUnauthorizedClient = errors.New("unauthorized_client")

// ErrAccessDenied access denied
ErrAccessDenied = errors.New("access_denied")

// ErrUnsupportedResponseType unsupported response type
ErrUnsupportedResponseType = errors.New("unsupported_response_type")

// ErrInvalidScope invalid scope
ErrInvalidScope = errors.New("invalid_scope")

// ErrInvalidRequest invalid request
ErrInvalidRequest = errors.New("invalid_request")

// ErrInvalidClient invalid client
ErrInvalidClient = errors.New("invalid_client")

// ErrInvalidGrant invalid grant
ErrInvalidGrant = errors.New("invalid_grant")

// ErrUnsupportedGrantType unsupported grant type
ErrUnsupportedGrantType = errors.New("unsupported_grant_type")

// ErrServerError server error
ErrServerError = errors.New("server_error")
)

var (
// ErrNilValue Nil Value
ErrNilValue = errors.New("nil value")
Expand Down
57 changes: 57 additions & 0 deletions errors/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package errors

import "errors"

// Response error response
type Response struct {
Error error `json:"error"`
Description string `json:"error_description,omitempty"`
URI string `json:"error_uri,omitempty"`
StatusCode int `json:"-"`
}

var (
// ErrInvalidRequest invalid request
ErrInvalidRequest = errors.New("invalid_request")

// ErrUnauthorizedClient unauthorized client
ErrUnauthorizedClient = errors.New("unauthorized_client")

// ErrAccessDenied access denied
ErrAccessDenied = errors.New("access_denied")

// ErrUnsupportedResponseType unsupported response type
ErrUnsupportedResponseType = errors.New("unsupported_response_type")

// ErrInvalidScope invalid scope
ErrInvalidScope = errors.New("invalid_scope")

// ErrServerError server error
ErrServerError = errors.New("server_error")

// ErrTemporarilyUnavailable temporarily unavailable
ErrTemporarilyUnavailable = errors.New("temporarily_unavailable")

// ErrInvalidClient invalid client
ErrInvalidClient = errors.New("invalid_client")

// ErrInvalidGrant invalid grant
ErrInvalidGrant = errors.New("invalid_grant")

// ErrUnsupportedGrantType unsupported grant type
ErrUnsupportedGrantType = errors.New("unsupported_grant_type")
)

// Descriptions error description
var Descriptions = map[error]string{
ErrInvalidRequest: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed",
ErrUnauthorizedClient: "The client is not authorized to request an authorization code using this method",
ErrAccessDenied: "The resource owner or authorization server denied the request",
ErrUnsupportedResponseType: "The authorization server does not support obtaining an authorization code using this method",
ErrInvalidScope: "The requested scope is invalid, unknown, or malformed",
ErrServerError: "The authorization server encountered an unexpected condition that prevented it from fulfilling the request",
ErrTemporarilyUnavailable: "The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server",
ErrInvalidClient: "Client authentication failed",
ErrInvalidGrant: "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client",
ErrUnsupportedGrantType: "The authorization grant type is not supported by the authorization server",
}
16 changes: 8 additions & 8 deletions example/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
"gopkg.in/oauth2.v3/manage"
"gopkg.in/oauth2.v3/models"
"gopkg.in/oauth2.v3/server"
"gopkg.in/oauth2.v3/store/client"
"gopkg.in/oauth2.v3/store/token"
"gopkg.in/oauth2.v3/store"

"gopkg.in/session.v1"
)

Expand All @@ -25,19 +25,19 @@ func init() {
}

func main() {
manager := manage.NewRedisManager(
&token.RedisConfig{Addr: "192.168.33.70:6379"},
)
// Create the client temporary storage
manager.MapClientStorage(client.NewTempStore(&models.Client{
manager := manage.NewDefaultManager()
// token store
manager.MapTokenStorage(store.NewMemoryTokenStore(0))
// client store
manager.MapClientStorage(store.NewTestClientStore(&models.Client{
ID: "222222",
Secret: "22222222",
Domain: "http://localhost:9094",
}))

srv := server.NewServer(server.NewConfig(), manager)
srv.SetUserAuthorizationHandler(userAuthorizeHandler)
srv.SetErrorHandler(func(err error) {
srv.SetInternalErrorHandler(func(err error) {
fmt.Println("OAuth2 Error:", err.Error())
})

Expand Down
20 changes: 5 additions & 15 deletions manage/manage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,25 @@ import (
"testing"

"gopkg.in/oauth2.v3"
"gopkg.in/oauth2.v3/generates"
"gopkg.in/oauth2.v3/manage"
"gopkg.in/oauth2.v3/models"
"gopkg.in/oauth2.v3/store/client"
"gopkg.in/oauth2.v3/store/token"
"gopkg.in/oauth2.v3/store"

. "github.com/smartystreets/goconvey/convey"
)

func TestManager(t *testing.T) {
Convey("Manager test", t, func() {
manager := manage.NewManager()

manager.MapClientModel(models.NewClient())
manager.MapTokenModel(models.NewToken())
manager.MapAuthorizeGenerate(generates.NewAuthorizeGenerate())
manager.MapAccessGenerate(generates.NewAccessGenerate())
manager.MapClientStorage(client.NewTempStore())
manager := manage.NewDefaultManager()
manager.MapClientStorage(store.NewTestClientStore())

Convey("GetClient test", func() {
cli, err := manager.GetClient("1")
So(err, ShouldBeNil)
So(cli.GetSecret(), ShouldEqual, "11")
})

Convey("Redis store test", func() {
manager.MustTokenStorage(token.NewRedisStore(
&token.RedisConfig{Addr: "192.168.33.70:6379"},
))
Convey("Memory store test", func() {
manager.MapTokenStorage(store.NewMemoryTokenStore(0))
testManager(manager)
})
})
Expand Down
64 changes: 33 additions & 31 deletions manage/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import (

"github.com/LyricTian/inject"

"reflect"

"gopkg.in/oauth2.v3"
"gopkg.in/oauth2.v3/errors"
"gopkg.in/oauth2.v3/generates"
"gopkg.in/oauth2.v3/models"
"gopkg.in/oauth2.v3/store/token"
)

// Config Configuration parameters
Expand All @@ -19,31 +20,30 @@ type Config struct {
IsGenerateRefresh bool // Whether to generate the refreshing token
}

// NewRedisManager Create to based on redis store authorization management instance
func NewRedisManager(redisCfg *token.RedisConfig) *Manager {
// NewDefaultManager Create to default authorization management instance
func NewDefaultManager() *Manager {
m := NewManager()
m.MapClientModel(models.NewClient())

// default config
m.SetAuthorizeCodeExp(time.Minute * 10)
m.SetImplicitTokenExp(time.Hour * 1)
m.SetClientTokenExp(time.Hour * 2)
m.SetAuthorizeCodeTokenCfg(&Config{IsGenerateRefresh: true, AccessTokenExp: time.Hour * 2, RefreshTokenExp: time.Hour * 24 * 3})
m.SetPasswordTokenCfg(&Config{IsGenerateRefresh: true, AccessTokenExp: time.Hour * 2, RefreshTokenExp: time.Hour * 24 * 7})

m.MapTokenModel(models.NewToken())
m.MapAuthorizeGenerate(generates.NewAuthorizeGenerate())
m.MapAccessGenerate(generates.NewAccessGenerate())
m.MustTokenStorage(token.NewRedisStore(redisCfg))

return m
}

// NewManager Create to authorization management instance
func NewManager() *Manager {
m := &Manager{
return &Manager{
injector: inject.New(),
gtcfg: make(map[oauth2.GrantType]*Config),
}
m.SetAuthorizeCodeExp(time.Minute * 10)
m.SetAuthorizeCodeTokenExp(&Config{IsGenerateRefresh: true, AccessTokenExp: time.Hour * 2, RefreshTokenExp: time.Hour * 24 * 3})
m.SetImplicitTokenExp(&Config{AccessTokenExp: time.Hour * 1})
m.SetPasswordTokenExp(&Config{IsGenerateRefresh: true, AccessTokenExp: time.Hour * 2, RefreshTokenExp: time.Hour * 24 * 7})
m.SetClientTokenExp(&Config{AccessTokenExp: time.Hour * 2})

return m
}

// Manager Provide authorization management
Expand All @@ -53,38 +53,38 @@ type Manager struct {
gtcfg map[oauth2.GrantType]*Config // Authorization grant configuration
}

func (m *Manager) newTokenInfo(ti oauth2.TokenInfo) oauth2.TokenInfo {
in := reflect.ValueOf(ti)
if in.IsNil() {
return ti
}
out := reflect.New(in.Type().Elem())
return out.Interface().(oauth2.TokenInfo)
}

// SetAuthorizeCodeExp Set the authorization code expiration time
func (m *Manager) SetAuthorizeCodeExp(exp time.Duration) {
m.codeExp = exp
}

// SetAuthorizeCodeTokenExp Set the authorization code grant token expiration time
func (m *Manager) SetAuthorizeCodeTokenExp(cfg *Config) {
// SetAuthorizeCodeTokenCfg Set the authorization code grant token config
func (m *Manager) SetAuthorizeCodeTokenCfg(cfg *Config) {
m.gtcfg[oauth2.AuthorizationCode] = cfg
}

// SetImplicitTokenExp Set the implicit grant token expiration time
func (m *Manager) SetImplicitTokenExp(cfg *Config) {
m.gtcfg[oauth2.Implicit] = cfg
func (m *Manager) SetImplicitTokenExp(exp time.Duration) {
m.gtcfg[oauth2.Implicit] = &Config{AccessTokenExp: exp}
}

// SetPasswordTokenExp Set the password grant token expiration time
func (m *Manager) SetPasswordTokenExp(cfg *Config) {
// SetPasswordTokenCfg Set the password grant token config
func (m *Manager) SetPasswordTokenCfg(cfg *Config) {
m.gtcfg[oauth2.PasswordCredentials] = cfg
}

// SetClientTokenExp Set the client grant token expiration time
func (m *Manager) SetClientTokenExp(cfg *Config) {
m.gtcfg[oauth2.ClientCredentials] = cfg
}

// MapClientModel Mapping the client information model
func (m *Manager) MapClientModel(cli oauth2.ClientInfo) error {
if cli == nil {
return errors.ErrNilValue
}
m.injector.Map(cli)
return nil
func (m *Manager) SetClientTokenExp(exp time.Duration) {
m.gtcfg[oauth2.ClientCredentials] = &Config{AccessTokenExp: exp}
}

// MapTokenModel Mapping the token information model
Expand Down Expand Up @@ -137,7 +137,7 @@ func (m *Manager) MustClientStorage(stor oauth2.ClientStore, err error) {
// MapTokenStorage Mapping the token store interface
func (m *Manager) MapTokenStorage(stor oauth2.TokenStore) error {
if stor == nil {
return (errors.ErrNilValue)
return errors.ErrNilValue
}
m.injector.Map(stor)
return nil
Expand Down Expand Up @@ -180,6 +180,7 @@ func (m *Manager) GenerateAuthToken(rt oauth2.ResponseType, tgr *oauth2.TokenGen
return
}
_, ierr := m.injector.Invoke(func(ti oauth2.TokenInfo, gen oauth2.AuthorizeGenerate, tgen oauth2.AccessGenerate, stor oauth2.TokenStore) {
ti = m.newTokenInfo(ti)
var (
tv string
terr error
Expand Down Expand Up @@ -247,6 +248,7 @@ func (m *Manager) GenerateAccessToken(gt oauth2.GrantType, tgr *oauth2.TokenGene
return
}
_, ierr := m.injector.Invoke(func(ti oauth2.TokenInfo, gen oauth2.AccessGenerate, stor oauth2.TokenStore) {
ti = m.newTokenInfo(ti)
td := &oauth2.GenerateBasic{
Client: cli,
UserID: tgr.UserID,
Expand Down
5 changes: 0 additions & 5 deletions models/client.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
package models

// NewClient Create to client model instance
func NewClient() *Client {
return &Client{}
}

// Client Client model
type Client struct {
ID string // The client id
Expand Down
7 changes: 5 additions & 2 deletions server/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ type PasswordAuthorizationHandler func(username, password string) (userID string
// RefreshingScopeHandler Check the scope of the refreshing token
type RefreshingScopeHandler func(newScope, oldScope string) (allowed bool)

// ErrorHandler Error handling
type ErrorHandler func(err error)
// ResponseErrorHandler Response error handing
type ResponseErrorHandler func(re *errors.Response)

// InternalErrorHandler Internal error handing
type InternalErrorHandler func(err error)

// ClientFormHandler Get client data from form
func ClientFormHandler(r *http.Request) (clientID, clientSecret string, err error) {
Expand Down
Loading