Chapter 04

[型定義]fositeの提供するAPI

abcb2
abcb2
2023.02.03に更新

fositeフレームワークが提供するAPI

OAuth2Provider

自らOAuth2のhttpハンドラーを実装する人向けにfositeが提供しているinterface

interface定義は大別して5つのグループに分けられる。

interface定義
type OAuth2Provider interface {
	NewAuthorizeRequest(ctx context.Context, req *http.Request) (AuthorizeRequester, error)
	NewAuthorizeResponse(ctx context.Context, requester AuthorizeRequester, session Session) (AuthorizeResponder, error)
	WriteAuthorizeError(ctx context.Context, rw http.ResponseWriter, requester AuthorizeRequester, err error)
	WriteAuthorizeResponse(ctx context.Context, rw http.ResponseWriter, requester AuthorizeRequester, responder AuthorizeResponder)
	
	NewAccessRequest(ctx context.Context, req *http.Request, session Session) (AccessRequester, error)
	NewAccessResponse(ctx context.Context, requester AccessRequester) (AccessResponder, error)
	WriteAccessError(ctx context.Context, rw http.ResponseWriter, requester AccessRequester, err error)
	WriteAccessResponse(ctx context.Context, rw http.ResponseWriter, requester AccessRequester, responder AccessResponder)
	
	NewRevocationRequest(ctx context.Context, r *http.Request) error
	WriteRevocationResponse(ctx context.Context, rw http.ResponseWriter, err error)
	
	IntrospectToken(ctx context.Context, token string, tokenUse TokenUse, session Session, scope ...string) (TokenUse, AccessRequester, error)
	NewIntrospectionRequest(ctx context.Context, r *http.Request, session Session) (IntrospectionResponder, error)
	WriteIntrospectionError(ctx context.Context, rw http.ResponseWriter, err error)
	WriteIntrospectionResponse(ctx context.Context, rw http.ResponseWriter, r IntrospectionResponder)
	
	NewPushedAuthorizeRequest(ctx context.Context, r *http.Request) (AuthorizeRequester, error)
	NewPushedAuthorizeResponse(ctx context.Context, ar AuthorizeRequester, session Session) (PushedAuthorizeResponder, error)
	WritePushedAuthorizeResponse(ctx context.Context, rw http.ResponseWriter, ar AuthorizeRequester, resp PushedAuthorizeResponder)
	WritePushedAuthorizeError(ctx context.Context, rw http.ResponseWriter, ar AuthorizeRequester, err error)
}

PushedAuthorizeはひとまず置いておくと、上から

  • 認可エンドポイント
  • トークンエンドポイント
  • revokeエンドポイント
  • introspectエンドポイント

に分けることができる

oauth2.goで定義されている。

自らOAuth2のhttpハンドラーを実装する人はFosite型をインスタンス化して使うことになるが、このOAuth2Providerインターフェースの具象型としてFositeを取り扱うことになる。

FositeとOAuth2Providerのインスタンス化
// compose/compose.go
func Compose(config *fosite.Config, storage interface{}, strategy interface{}, factories ...Factory) fosite.OAuth2Provider {
	// ここでFositeを作る
	f := fosite.NewOAuth2Provider(storage.(fosite.Storage), config)
	for _, factory := range factories {
		res := factory(config, storage, strategy)
		if ah, ok := res.(fosite.AuthorizeEndpointHandler); ok {
			config.AuthorizeEndpointHandlers.Append(ah)
		}
		if th, ok := res.(fosite.TokenEndpointHandler); ok {
			config.TokenEndpointHandlers.Append(th)
		}
		if tv, ok := res.(fosite.TokenIntrospector); ok {
			config.TokenIntrospectionHandlers.Append(tv)
		}
		if rh, ok := res.(fosite.RevocationHandler); ok {
			config.RevocationHandlers.Append(rh)
		}
		if ph, ok := res.(fosite.PushedAuthorizeEndpointHandler); ok {
			config.PushedAuthorizeEndpointHandlers.Append(ph)
		}
	}

	return f // 返り値の型はfosite.OAuth2Provider
}

// fosite.go
func NewOAuth2Provider(s Storage, c Configurator) *Fosite {
	return &Fosite{Store: s, Config: c}
}

Fosite

fositeフレームワークを使う場合はこの型をインスタンス化して使う。

fosite.goで定義されている

構造体定義
var _ OAuth2Provider = (*Fosite)(nil)

type Fosite struct {
	Store Storage

	Config Configurator
}

StoreConfigだけを保持している。また、Fosite型はOAuth2Providerインターフェースを満たしている。

Config

config_default.goで定義されている

この型を通してfositeはフレームワークとして提供する機能にアクセスする

下記のように、提供するhttpハンドラーもここに内包されている

	// AuthorizeEndpointHandlers is a list of handlers that are called before the authorization endpoint is served.
	AuthorizeEndpointHandlers AuthorizeEndpointHandlers

	// TokenEndpointHandlers is a list of handlers that are called before the token endpoint is served.
	TokenEndpointHandlers TokenEndpointHandlers

	// TokenIntrospectionHandlers is a list of handlers that are called before the token introspection endpoint is served.
	TokenIntrospectionHandlers TokenIntrospectionHandlers

	// RevocationHandlers is a list of handlers that are called before the revocation endpoint is served.
	RevocationHandlers RevocationHandlers

	// PushedAuthorizeEndpointHandlers is a list of handlers that are called before the PAR endpoint is served.
	PushedAuthorizeEndpointHandlers PushedAuthorizeEndpointHandlers
構造体定義
type Config struct {
	// AccessTokenLifespan sets how long an access token is going to be valid. Defaults to one hour.
	AccessTokenLifespan time.Duration

	// RefreshTokenLifespan sets how long a refresh token is going to be valid. Defaults to 30 days. Set to -1 for
	// refresh tokens that never expire.
	RefreshTokenLifespan time.Duration

	// AuthorizeCodeLifespan sets how long an authorize code is going to be valid. Defaults to fifteen minutes.
	AuthorizeCodeLifespan time.Duration

	// IDTokenLifespan sets the default id token lifetime. Defaults to one hour.
	IDTokenLifespan time.Duration

	// IDTokenIssuer sets the default issuer of the ID Token.
	IDTokenIssuer string

	// HashCost sets the cost of the password hashing cost. Defaults to 12.
	HashCost int

	// DisableRefreshTokenValidation sets the introspection endpoint to disable refresh token validation.
	DisableRefreshTokenValidation bool

	// SendDebugMessagesToClients if set to true, includes error debug messages in response payloads. Be aware that sensitive
	// data may be exposed, depending on your implementation of Fosite. Such sensitive data might include database error
	// codes or other information. Proceed with caution!
	SendDebugMessagesToClients bool

	// ScopeStrategy sets the scope strategy that should be supported, for example fosite.WildcardScopeStrategy.
	ScopeStrategy ScopeStrategy

	// AudienceMatchingStrategy sets the audience matching strategy that should be supported, defaults to fosite.DefaultsAudienceMatchingStrategy.
	AudienceMatchingStrategy AudienceMatchingStrategy

	// EnforcePKCE, if set to true, requires clients to perform authorize code flows with PKCE. Defaults to false.
	EnforcePKCE bool

	// EnforcePKCEForPublicClients requires only public clients to use PKCE with the authorize code flow. Defaults to false.
	EnforcePKCEForPublicClients bool

	// EnablePKCEPlainChallengeMethod sets whether or not to allow the plain challenge method (S256 should be used whenever possible, plain is really discouraged). Defaults to false.
	EnablePKCEPlainChallengeMethod bool

	// AllowedPromptValues sets which OpenID Connect prompt values the server supports. Defaults to []string{"login", "none", "consent", "select_account"}.
	AllowedPromptValues []string

	// TokenURL is the the URL of the Authorization Server's Token Endpoint. If the authorization server is intended
	// to be compatible with the private_key_jwt client authentication method (see http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth),
	// this value MUST be set.
	TokenURL string

	// JWKSFetcherStrategy is responsible for fetching JSON Web Keys from remote URLs. This is required when the private_key_jwt
	// client authentication method is used. Defaults to fosite.DefaultJWKSFetcherStrategy.
	JWKSFetcherStrategy JWKSFetcherStrategy

	// TokenEntropy indicates the entropy of the random string, used as the "message" part of the HMAC token.
	// Defaults to 32.
	TokenEntropy int

	// RedirectSecureChecker is a function that returns true if the provided URL can be securely used as a redirect URL.
	RedirectSecureChecker func(context.Context, *url.URL) bool

	// RefreshTokenScopes defines which OAuth scopes will be given refresh tokens during the authorization code grant exchange. This defaults to "offline" and "offline_access". When set to an empty array, all exchanges will be given refresh tokens.
	RefreshTokenScopes []string

	// MinParameterEntropy controls the minimum size of state and nonce parameters. Defaults to fosite.MinParameterEntropy.
	MinParameterEntropy int

	// UseLegacyErrorFormat controls whether the legacy error format (with `error_debug`, `error_hint`, ...)
	// should be used or not.
	UseLegacyErrorFormat bool

	// GrantTypeJWTBearerCanSkipClientAuth indicates, if client authentication can be skipped, when using jwt as assertion.
	GrantTypeJWTBearerCanSkipClientAuth bool

	// GrantTypeJWTBearerIDOptional indicates, if jti (JWT ID) claim required or not in JWT.
	GrantTypeJWTBearerIDOptional bool

	// GrantTypeJWTBearerIssuedDateOptional indicates, if "iat" (issued at) claim required or not in JWT.
	GrantTypeJWTBearerIssuedDateOptional bool

	// GrantTypeJWTBearerMaxDuration sets the maximum time after JWT issued date, during which the JWT is considered valid.
	GrantTypeJWTBearerMaxDuration time.Duration

	// ClientAuthenticationStrategy indicates the Strategy to authenticate client requests
	ClientAuthenticationStrategy ClientAuthenticationStrategy

	// ResponseModeHandlerExtension provides a handler for custom response modes
	ResponseModeHandlerExtension ResponseModeHandler

	// MessageCatalog is the message bundle used for i18n
	MessageCatalog i18n.MessageCatalog

	// FormPostHTMLTemplate sets html template for rendering the authorization response when the request has response_mode=form_post.
	FormPostHTMLTemplate *template.Template

	// OmitRedirectScopeParam indicates whether the "scope" parameter should be omitted from the redirect URL.
	OmitRedirectScopeParam bool

	// SanitationWhiteList is a whitelist of form values that are required by the token endpoint. These values
	// are safe for storage in a database (cleartext).
	SanitationWhiteList []string

	// JWTScopeClaimKey defines the claim key to be used to set the scope in. Valid fields are "scope" or "scp" or both.
	JWTScopeClaimKey jwt.JWTScopeFieldEnum

	// AccessTokenIssuer is the issuer to be used when generating access tokens.
	AccessTokenIssuer string

	// ClientSecretsHasher is the hasher used to hash OAuth2 Client Secrets.
	ClientSecretsHasher Hasher

	// HTTPClient is the HTTP client to use for requests.
	HTTPClient *retryablehttp.Client

	// AuthorizeEndpointHandlers is a list of handlers that are called before the authorization endpoint is served.
	AuthorizeEndpointHandlers AuthorizeEndpointHandlers

	// TokenEndpointHandlers is a list of handlers that are called before the token endpoint is served.
	TokenEndpointHandlers TokenEndpointHandlers

	// TokenIntrospectionHandlers is a list of handlers that are called before the token introspection endpoint is served.
	TokenIntrospectionHandlers TokenIntrospectionHandlers

	// RevocationHandlers is a list of handlers that are called before the revocation endpoint is served.
	RevocationHandlers RevocationHandlers

	// PushedAuthorizeEndpointHandlers is a list of handlers that are called before the PAR endpoint is served.
	PushedAuthorizeEndpointHandlers PushedAuthorizeEndpointHandlers

	// GlobalSecret is the global secret used to sign and verify signatures.
	GlobalSecret []byte

	// RotatedGlobalSecrets is a list of global secrets that are used to verify signatures.
	RotatedGlobalSecrets [][]byte

	// HMACHasher is the hasher used to generate HMAC signatures.
	HMACHasher func() hash.Hash

	// PushedAuthorizeRequestURIPrefix is the URI prefix for the PAR request_uri.
	// This is defaulted to 'urn:ietf:params:oauth:request_uri:'.
	PushedAuthorizeRequestURIPrefix string

	// PushedAuthorizeContextLifespan is the lifespan of the PAR context
	PushedAuthorizeContextLifespan time.Duration

	// IsPushedAuthorizeEnforced enforces pushed authorization request for /authorize
	IsPushedAuthorizeEnforced bool
}

Configurator

Configのメンバーにアクセスするためのinterfaceを提供している。

interface定義
type Configurator interface {
	IDTokenIssuerProvider
	IDTokenLifespanProvider
	AllowedPromptsProvider
	EnforcePKCEProvider
	EnforcePKCEForPublicClientsProvider
	EnablePKCEPlainChallengeMethodProvider
	GrantTypeJWTBearerCanSkipClientAuthProvider
	GrantTypeJWTBearerIDOptionalProvider
	GrantTypeJWTBearerIssuedDateOptionalProvider
	GetJWTMaxDurationProvider
	AudienceStrategyProvider
	ScopeStrategyProvider
	RedirectSecureCheckerProvider
	OmitRedirectScopeParamProvider
	SanitationAllowedProvider
	JWTScopeFieldProvider
	AccessTokenIssuerProvider
	DisableRefreshTokenValidationProvider
	RefreshTokenScopesProvider
	AccessTokenLifespanProvider
	RefreshTokenLifespanProvider
	AuthorizeCodeLifespanProvider
	TokenEntropyProvider
	RotatedGlobalSecretsProvider
	GlobalSecretProvider
	JWKSFetcherStrategyProvider
	HTTPClientProvider
	ScopeStrategyProvider
	AudienceStrategyProvider
	MinParameterEntropyProvider
	HMACHashingProvider
	ClientAuthenticationStrategyProvider
	ResponseModeHandlerExtensionProvider
	SendDebugMessagesToClientsProvider
	JWKSFetcherStrategyProvider
	ClientAuthenticationStrategyProvider
	ResponseModeHandlerExtensionProvider
	MessageCatalogProvider
	FormPostHTMLTemplateProvider
	TokenURLProvider
	GetSecretsHashingProvider
	AuthorizeEndpointHandlersProvider
	TokenEndpointHandlersProvider
	TokenIntrospectionHandlersProvider
	RevocationHandlersProvider
	UseLegacyErrorFormatProvider
}

Configuratorの中でさらに別interface定義が使われているのは、Configを使う箇所によってアクセスできるメンバーを制限するためだ。

例えば下記の例ようにHandlerの中ではGetBarにアクセスできないようになっている

Configuratorの利点
package main

import "fmt"

type (
	FooProvider interface {
		GetFoo() string
	}
	BarProvider interface {
		GetBar() string
	}
	Configurator interface {
		FooProvider
		BarProvider
	}
)

var _ Configurator = (*Config)(nil)

type Config struct {
	Foo string
	Bar string
}

func (c *Config) GetFoo() string { return c.Foo }
func (c *Config) GetBar() string { return c.Bar }

type Handler struct {
	Config interface {
		FooProvider
	}
}

func main() {
	cfg := &Config{Foo: "foo", Bar: "bar"}
	handler := Handler{Config: cfg}
	fmt.Println(handler.Config.GetFoo())
	//fmt.Println(handler.Config.GetBar()) // エラー
}