| 
									
										
										
										
											2025-03-02 16:42:51 +01:00
										 |  |  | package manage | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-25 12:05:45 +02:00
										 |  |  | 	"code.superseriousbusiness.org/oauth2/v4" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/oauth2/v4/errors" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/oauth2/v4/generates" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/oauth2/v4/models" | 
					
						
							| 
									
										
										
										
											2025-03-02 16:42:51 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewDefaultManager create to default authorization management instance | 
					
						
							|  |  |  | func NewDefaultManager() *Manager { | 
					
						
							|  |  |  | 	m := NewManager() | 
					
						
							|  |  |  | 	// default implementation | 
					
						
							|  |  |  | 	m.MapAuthorizeGenerate(generates.NewAuthorizeGenerate()) | 
					
						
							|  |  |  | 	m.MapAccessGenerate(generates.NewAccessGenerate()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return m | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewManager create to authorization management instance | 
					
						
							|  |  |  | func NewManager() *Manager { | 
					
						
							|  |  |  | 	return &Manager{ | 
					
						
							|  |  |  | 		gtcfg:       make(map[oauth2.GrantType]*Config), | 
					
						
							|  |  |  | 		validateURI: DefaultValidateURI, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Manager provide authorization management | 
					
						
							|  |  |  | type Manager struct { | 
					
						
							|  |  |  | 	codeExp           time.Duration | 
					
						
							|  |  |  | 	gtcfg             map[oauth2.GrantType]*Config | 
					
						
							|  |  |  | 	rcfg              *RefreshingConfig | 
					
						
							|  |  |  | 	validateURI       ValidateURIHandler | 
					
						
							|  |  |  | 	authorizeGenerate oauth2.AuthorizeGenerate | 
					
						
							|  |  |  | 	accessGenerate    oauth2.AccessGenerate | 
					
						
							|  |  |  | 	tokenStore        oauth2.TokenStore | 
					
						
							|  |  |  | 	clientStore       oauth2.ClientStore | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // get grant type config | 
					
						
							|  |  |  | func (m *Manager) grantConfig(gt oauth2.GrantType) *Config { | 
					
						
							|  |  |  | 	if c, ok := m.gtcfg[gt]; ok && c != nil { | 
					
						
							|  |  |  | 		return c | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch gt { | 
					
						
							|  |  |  | 	case oauth2.AuthorizationCode: | 
					
						
							|  |  |  | 		return DefaultAuthorizeCodeTokenCfg | 
					
						
							|  |  |  | 	case oauth2.Implicit: | 
					
						
							|  |  |  | 		return DefaultImplicitTokenCfg | 
					
						
							|  |  |  | 	case oauth2.PasswordCredentials: | 
					
						
							|  |  |  | 		return DefaultPasswordTokenCfg | 
					
						
							|  |  |  | 	case oauth2.ClientCredentials: | 
					
						
							|  |  |  | 		return DefaultClientTokenCfg | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return &Config{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetAuthorizeCodeExp set the authorization code expiration time | 
					
						
							|  |  |  | func (m *Manager) SetAuthorizeCodeExp(exp time.Duration) { | 
					
						
							|  |  |  | 	m.codeExp = exp | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetAuthorizeCodeTokenCfg set the authorization code grant token config | 
					
						
							|  |  |  | func (m *Manager) SetAuthorizeCodeTokenCfg(cfg *Config) { | 
					
						
							|  |  |  | 	m.gtcfg[oauth2.AuthorizationCode] = cfg | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetImplicitTokenCfg set the implicit grant token config | 
					
						
							|  |  |  | func (m *Manager) SetImplicitTokenCfg(cfg *Config) { | 
					
						
							|  |  |  | 	m.gtcfg[oauth2.Implicit] = cfg | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetPasswordTokenCfg set the password grant token config | 
					
						
							|  |  |  | func (m *Manager) SetPasswordTokenCfg(cfg *Config) { | 
					
						
							|  |  |  | 	m.gtcfg[oauth2.PasswordCredentials] = cfg | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetClientTokenCfg set the client grant token config | 
					
						
							|  |  |  | func (m *Manager) SetClientTokenCfg(cfg *Config) { | 
					
						
							|  |  |  | 	m.gtcfg[oauth2.ClientCredentials] = cfg | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetRefreshTokenCfg set the refreshing token config | 
					
						
							|  |  |  | func (m *Manager) SetRefreshTokenCfg(cfg *RefreshingConfig) { | 
					
						
							|  |  |  | 	m.rcfg = cfg | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetValidateURIHandler set the validates that RedirectURI is contained in baseURI | 
					
						
							|  |  |  | func (m *Manager) SetValidateURIHandler(handler ValidateURIHandler) { | 
					
						
							|  |  |  | 	m.validateURI = handler | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MapAuthorizeGenerate mapping the authorize code generate interface | 
					
						
							|  |  |  | func (m *Manager) MapAuthorizeGenerate(gen oauth2.AuthorizeGenerate) { | 
					
						
							|  |  |  | 	m.authorizeGenerate = gen | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MapAccessGenerate mapping the access token generate interface | 
					
						
							|  |  |  | func (m *Manager) MapAccessGenerate(gen oauth2.AccessGenerate) { | 
					
						
							|  |  |  | 	m.accessGenerate = gen | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MapClientStorage mapping the client store interface | 
					
						
							|  |  |  | func (m *Manager) MapClientStorage(stor oauth2.ClientStore) { | 
					
						
							|  |  |  | 	m.clientStore = stor | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MustClientStorage mandatory mapping the client store interface | 
					
						
							|  |  |  | func (m *Manager) MustClientStorage(stor oauth2.ClientStore, err error) { | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	m.clientStore = stor | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MapTokenStorage mapping the token store interface | 
					
						
							|  |  |  | func (m *Manager) MapTokenStorage(stor oauth2.TokenStore) { | 
					
						
							|  |  |  | 	m.tokenStore = stor | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MustTokenStorage mandatory mapping the token store interface | 
					
						
							|  |  |  | func (m *Manager) MustTokenStorage(stor oauth2.TokenStore, err error) { | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		panic(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	m.tokenStore = stor | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetClient get the client information | 
					
						
							|  |  |  | func (m *Manager) GetClient(ctx context.Context, clientID string) (cli oauth2.ClientInfo, err error) { | 
					
						
							|  |  |  | 	cli, err = m.clientStore.GetByID(ctx, clientID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} else if cli == nil { | 
					
						
							|  |  |  | 		err = errors.ErrInvalidClient | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GenerateAuthToken generate the authorization token(code) | 
					
						
							|  |  |  | func (m *Manager) GenerateAuthToken(ctx context.Context, rt oauth2.ResponseType, tgr *oauth2.TokenGenerateRequest) (oauth2.TokenInfo, error) { | 
					
						
							|  |  |  | 	cli, err := m.GetClient(ctx, tgr.ClientID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else if tgr.RedirectURI != "" { | 
					
						
							|  |  |  | 		if err := m.validateURI(cli.GetDomain(), tgr.RedirectURI); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ti := models.NewToken() | 
					
						
							|  |  |  | 	ti.SetClientID(tgr.ClientID) | 
					
						
							|  |  |  | 	ti.SetUserID(tgr.UserID) | 
					
						
							|  |  |  | 	ti.SetRedirectURI(tgr.RedirectURI) | 
					
						
							|  |  |  | 	ti.SetScope(tgr.Scope) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	createAt := time.Now() | 
					
						
							|  |  |  | 	td := &oauth2.GenerateBasic{ | 
					
						
							|  |  |  | 		Client:    cli, | 
					
						
							|  |  |  | 		UserID:    tgr.UserID, | 
					
						
							|  |  |  | 		CreateAt:  createAt, | 
					
						
							|  |  |  | 		TokenInfo: ti, | 
					
						
							|  |  |  | 		Request:   tgr.Request, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch rt { | 
					
						
							|  |  |  | 	case oauth2.Code: | 
					
						
							|  |  |  | 		codeExp := m.codeExp | 
					
						
							|  |  |  | 		if codeExp == 0 { | 
					
						
							|  |  |  | 			codeExp = DefaultCodeExp | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ti.SetCodeCreateAt(createAt) | 
					
						
							|  |  |  | 		ti.SetCodeExpiresIn(codeExp) | 
					
						
							|  |  |  | 		if exp := tgr.AccessTokenExp; exp > 0 { | 
					
						
							|  |  |  | 			ti.SetAccessExpiresIn(exp) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tgr.CodeChallenge != "" { | 
					
						
							|  |  |  | 			ti.SetCodeChallenge(tgr.CodeChallenge) | 
					
						
							|  |  |  | 			ti.SetCodeChallengeMethod(tgr.CodeChallengeMethod) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tv, err := m.authorizeGenerate.Token(ctx, td) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ti.SetCode(tv) | 
					
						
							|  |  |  | 	case oauth2.Token: | 
					
						
							|  |  |  | 		// set access token expires | 
					
						
							|  |  |  | 		icfg := m.grantConfig(oauth2.Implicit) | 
					
						
							|  |  |  | 		aexp := icfg.AccessTokenExp | 
					
						
							|  |  |  | 		if exp := tgr.AccessTokenExp; exp > 0 { | 
					
						
							|  |  |  | 			aexp = exp | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ti.SetAccessCreateAt(createAt) | 
					
						
							|  |  |  | 		ti.SetAccessExpiresIn(aexp) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if icfg.IsGenerateRefresh { | 
					
						
							|  |  |  | 			ti.SetRefreshCreateAt(createAt) | 
					
						
							|  |  |  | 			ti.SetRefreshExpiresIn(icfg.RefreshTokenExp) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tv, rv, err := m.accessGenerate.Token(ctx, td, icfg.IsGenerateRefresh) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ti.SetAccess(tv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if rv != "" { | 
					
						
							|  |  |  | 			ti.SetRefresh(rv) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = m.tokenStore.Create(ctx, ti) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ti, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // get authorization code data | 
					
						
							|  |  |  | func (m *Manager) getAuthorizationCode(ctx context.Context, code string) (oauth2.TokenInfo, error) { | 
					
						
							|  |  |  | 	ti, err := m.tokenStore.GetByCode(ctx, code) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else if ti == nil || ti.GetCode() != code || ti.GetCodeCreateAt().Add(ti.GetCodeExpiresIn()).Before(time.Now()) { | 
					
						
							|  |  |  | 		err = errors.ErrInvalidAuthorizeCode | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidAuthorizeCode | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ti, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // delete authorization code data | 
					
						
							|  |  |  | func (m *Manager) delAuthorizationCode(ctx context.Context, code string) error { | 
					
						
							|  |  |  | 	return m.tokenStore.RemoveByCode(ctx, code) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // get and delete authorization code data | 
					
						
							|  |  |  | func (m *Manager) getAndDelAuthorizationCode(ctx context.Context, tgr *oauth2.TokenGenerateRequest) (oauth2.TokenInfo, error) { | 
					
						
							|  |  |  | 	code := tgr.Code | 
					
						
							|  |  |  | 	ti, err := m.getAuthorizationCode(ctx, code) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else if ti.GetClientID() != tgr.ClientID { | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidAuthorizeCode | 
					
						
							|  |  |  | 	} else if codeURI := ti.GetRedirectURI(); codeURI != "" && codeURI != tgr.RedirectURI { | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidAuthorizeCode | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = m.delAuthorizationCode(ctx, code) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ti, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *Manager) validateCodeChallenge(ti oauth2.TokenInfo, ver string) error { | 
					
						
							|  |  |  | 	cc := ti.GetCodeChallenge() | 
					
						
							|  |  |  | 	// early return | 
					
						
							|  |  |  | 	if cc == "" && ver == "" { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if cc == "" { | 
					
						
							|  |  |  | 		return errors.ErrMissingCodeVerifier | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ver == "" { | 
					
						
							|  |  |  | 		return errors.ErrMissingCodeVerifier | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ccm := ti.GetCodeChallengeMethod() | 
					
						
							|  |  |  | 	if ccm.String() == "" { | 
					
						
							|  |  |  | 		ccm = oauth2.CodeChallengePlain | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if !ccm.Validate(cc, ver) { | 
					
						
							|  |  |  | 		return errors.ErrInvalidCodeChallenge | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GenerateAccessToken generate the access token | 
					
						
							|  |  |  | func (m *Manager) GenerateAccessToken(ctx context.Context, gt oauth2.GrantType, tgr *oauth2.TokenGenerateRequest) (oauth2.TokenInfo, error) { | 
					
						
							|  |  |  | 	cli, err := m.GetClient(ctx, tgr.ClientID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if cliPass, ok := cli.(oauth2.ClientPasswordVerifier); ok { | 
					
						
							|  |  |  | 		if !cliPass.VerifyPassword(tgr.ClientSecret) { | 
					
						
							|  |  |  | 			return nil, errors.ErrInvalidClient | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if len(cli.GetSecret()) > 0 && tgr.ClientSecret != cli.GetSecret() { | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidClient | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if tgr.RedirectURI != "" { | 
					
						
							|  |  |  | 		if err := m.validateURI(cli.GetDomain(), tgr.RedirectURI); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if gt == oauth2.AuthorizationCode { | 
					
						
							|  |  |  | 		ti, err := m.getAndDelAuthorizationCode(ctx, tgr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err := m.validateCodeChallenge(ti, tgr.CodeVerifier); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		tgr.UserID = ti.GetUserID() | 
					
						
							|  |  |  | 		tgr.Scope = ti.GetScope() | 
					
						
							|  |  |  | 		if exp := ti.GetAccessExpiresIn(); exp > 0 { | 
					
						
							|  |  |  | 			tgr.AccessTokenExp = exp | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ti := models.NewToken() | 
					
						
							|  |  |  | 	ti.SetClientID(tgr.ClientID) | 
					
						
							|  |  |  | 	ti.SetUserID(tgr.UserID) | 
					
						
							|  |  |  | 	ti.SetRedirectURI(tgr.RedirectURI) | 
					
						
							|  |  |  | 	ti.SetScope(tgr.Scope) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	createAt := time.Now() | 
					
						
							|  |  |  | 	ti.SetAccessCreateAt(createAt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// set access token expires | 
					
						
							|  |  |  | 	gcfg := m.grantConfig(gt) | 
					
						
							|  |  |  | 	aexp := gcfg.AccessTokenExp | 
					
						
							|  |  |  | 	if exp := tgr.AccessTokenExp; exp > 0 { | 
					
						
							|  |  |  | 		aexp = exp | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ti.SetAccessExpiresIn(aexp) | 
					
						
							|  |  |  | 	if gcfg.IsGenerateRefresh { | 
					
						
							|  |  |  | 		ti.SetRefreshCreateAt(createAt) | 
					
						
							|  |  |  | 		ti.SetRefreshExpiresIn(gcfg.RefreshTokenExp) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	td := &oauth2.GenerateBasic{ | 
					
						
							|  |  |  | 		Client:    cli, | 
					
						
							|  |  |  | 		UserID:    tgr.UserID, | 
					
						
							|  |  |  | 		CreateAt:  createAt, | 
					
						
							|  |  |  | 		TokenInfo: ti, | 
					
						
							|  |  |  | 		Request:   tgr.Request, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	av, rv, err := m.accessGenerate.Token(ctx, td, gcfg.IsGenerateRefresh) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ti.SetAccess(av) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if rv != "" { | 
					
						
							|  |  |  | 		ti.SetRefresh(rv) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = m.tokenStore.Create(ctx, ti) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ti, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RefreshAccessToken refreshing an access token | 
					
						
							|  |  |  | func (m *Manager) RefreshAccessToken(ctx context.Context, tgr *oauth2.TokenGenerateRequest) (oauth2.TokenInfo, error) { | 
					
						
							|  |  |  | 	cli, err := m.GetClient(ctx, tgr.ClientID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else if cliPass, ok := cli.(oauth2.ClientPasswordVerifier); ok { | 
					
						
							|  |  |  | 		if !cliPass.VerifyPassword(tgr.ClientSecret) { | 
					
						
							|  |  |  | 			return nil, errors.ErrInvalidClient | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if tgr.ClientSecret != cli.GetSecret() { | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidClient | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ti, err := m.LoadRefreshToken(ctx, tgr.Refresh) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else if ti.GetClientID() != tgr.ClientID { | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidRefreshToken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	oldAccess, oldRefresh := ti.GetAccess(), ti.GetRefresh() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	td := &oauth2.GenerateBasic{ | 
					
						
							|  |  |  | 		Client:    cli, | 
					
						
							|  |  |  | 		UserID:    ti.GetUserID(), | 
					
						
							|  |  |  | 		CreateAt:  time.Now(), | 
					
						
							|  |  |  | 		TokenInfo: ti, | 
					
						
							|  |  |  | 		Request:   tgr.Request, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcfg := DefaultRefreshTokenCfg | 
					
						
							|  |  |  | 	if v := m.rcfg; v != nil { | 
					
						
							|  |  |  | 		rcfg = v | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ti.SetAccessCreateAt(td.CreateAt) | 
					
						
							|  |  |  | 	if v := rcfg.AccessTokenExp; v > 0 { | 
					
						
							|  |  |  | 		ti.SetAccessExpiresIn(v) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if v := rcfg.RefreshTokenExp; v > 0 { | 
					
						
							|  |  |  | 		ti.SetRefreshExpiresIn(v) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if rcfg.IsResetRefreshTime { | 
					
						
							|  |  |  | 		ti.SetRefreshCreateAt(td.CreateAt) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if scope := tgr.Scope; scope != "" { | 
					
						
							|  |  |  | 		ti.SetScope(scope) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tv, rv, err := m.accessGenerate.Token(ctx, td, rcfg.IsGenerateRefresh) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ti.SetAccess(tv) | 
					
						
							|  |  |  | 	if rv != "" { | 
					
						
							|  |  |  | 		ti.SetRefresh(rv) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := m.tokenStore.Create(ctx, ti); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if rcfg.IsRemoveAccess { | 
					
						
							|  |  |  | 		// remove the old access token | 
					
						
							|  |  |  | 		if err := m.tokenStore.RemoveByAccess(ctx, oldAccess); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if rcfg.IsRemoveRefreshing && rv != "" { | 
					
						
							|  |  |  | 		// remove the old refresh token | 
					
						
							|  |  |  | 		if err := m.tokenStore.RemoveByRefresh(ctx, oldRefresh); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if rv == "" { | 
					
						
							|  |  |  | 		ti.SetRefresh("") | 
					
						
							|  |  |  | 		ti.SetRefreshCreateAt(time.Now()) | 
					
						
							|  |  |  | 		ti.SetRefreshExpiresIn(0) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ti, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RemoveAccessToken use the access token to delete the token information | 
					
						
							|  |  |  | func (m *Manager) RemoveAccessToken(ctx context.Context, access string) error { | 
					
						
							|  |  |  | 	if access == "" { | 
					
						
							|  |  |  | 		return errors.ErrInvalidAccessToken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return m.tokenStore.RemoveByAccess(ctx, access) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RemoveRefreshToken use the refresh token to delete the token information | 
					
						
							|  |  |  | func (m *Manager) RemoveRefreshToken(ctx context.Context, refresh string) error { | 
					
						
							|  |  |  | 	if refresh == "" { | 
					
						
							|  |  |  | 		return errors.ErrInvalidAccessToken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return m.tokenStore.RemoveByRefresh(ctx, refresh) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LoadAccessToken according to the access token for corresponding token information | 
					
						
							|  |  |  | func (m *Manager) LoadAccessToken(ctx context.Context, access string) (oauth2.TokenInfo, error) { | 
					
						
							|  |  |  | 	if access == "" { | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidAccessToken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ct := time.Now() | 
					
						
							|  |  |  | 	ti, err := m.tokenStore.GetByAccess(ctx, access) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else if ti == nil || ti.GetAccess() != access { | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidAccessToken | 
					
						
							|  |  |  | 	} else if ti.GetRefresh() != "" && ti.GetRefreshExpiresIn() != 0 && | 
					
						
							|  |  |  | 		ti.GetRefreshCreateAt().Add(ti.GetRefreshExpiresIn()).Before(ct) { | 
					
						
							|  |  |  | 		return nil, errors.ErrExpiredRefreshToken | 
					
						
							|  |  |  | 	} else if ti.GetAccessExpiresIn() != 0 && | 
					
						
							|  |  |  | 		ti.GetAccessCreateAt().Add(ti.GetAccessExpiresIn()).Before(ct) { | 
					
						
							|  |  |  | 		return nil, errors.ErrExpiredAccessToken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ti, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LoadRefreshToken according to the refresh token for corresponding token information | 
					
						
							|  |  |  | func (m *Manager) LoadRefreshToken(ctx context.Context, refresh string) (oauth2.TokenInfo, error) { | 
					
						
							|  |  |  | 	if refresh == "" { | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidRefreshToken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ti, err := m.tokenStore.GetByRefresh(ctx, refresh) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} else if ti == nil || ti.GetRefresh() != refresh { | 
					
						
							|  |  |  | 		return nil, errors.ErrInvalidRefreshToken | 
					
						
							|  |  |  | 	} else if ti.GetRefreshExpiresIn() != 0 && // refresh token set to not expire | 
					
						
							|  |  |  | 		ti.GetRefreshCreateAt().Add(ti.GetRefreshExpiresIn()).Before(time.Now()) { | 
					
						
							|  |  |  | 		return nil, errors.ErrExpiredRefreshToken | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ti, nil | 
					
						
							|  |  |  | } |