Documentation
¶
Index ¶
- Variables
- type AuthTemplate
- type Authenticator
- type Client
- func (c *Client) CompareSecret(testSecret string) bool
- func (c *Client) DecideAcrValues(requested []string) (decided []string)
- func (c *Client) DecideMaxAge(requested oidc.MaxAge) (decided oidc.MaxAge)
- func (c *Client) DecideRedirectUri(requested oidc.RedirectUri) (decided oidc.RedirectUri, err error)
- func (c *Client) DecideSectorIdentifierURI() (string, error)
- func (c *Client) HasGrantType(grantType oidc.GrantType) bool
- func (c *Client) HasRequestUri(requestUri string) bool
- func (c *Client) HasResponseType(responseType oidc.ResponseType) bool
- func (c *Client) HasScope(scope oidc.Scope) bool
- func (c *Client) RequestObjectByRef(ref string) (string, bool)
- func (c *Client) ResolveJSONWebKeySet(ctx context.Context, strategy KeySetStrategy) (jwks *gojosev2.JSONWebKeySet, err error)
- func (c *Client) ZeroFields() *Client
- type KeySetStrategy
- type Lookup
- type RedisStorage
- func (s *RedisStorage) Delete(ctx context.Context, clientId string) error
- func (s *RedisStorage) FindById(ctx context.Context, clientId string) (*Client, error)
- func (s *RedisStorage) Insert(ctx context.Context, client *Client) error
- func (s *RedisStorage) Update(ctx context.Context, updated *Client, ref *Client) error
- type Storage
Constants ¶
This section is empty.
Variables ¶
var ( ErrUnsupportedClientAuth = fmt.Errorf("%w: client does not support authentication", oidc.ErrInvalidClient) ErrNonPublicClientNeedAuth = fmt.Errorf("%w: non-public client require authentication", oidc.ErrInvalidClient) ErrClientAuthFailed = fmt.Errorf("%w: client failed authentication", oidc.ErrInvalidClient) ErrMalformedAuthHeader = fmt.Errorf("%w: malformed authorization header", oidc.ErrInvalidRequest) ErrMultipleClientInAuth = fmt.Errorf("%w: multiple client_id discovered during authentication", oidc.ErrInvalidClient) )
var ( // ErrUndecidedRedirectUri is returned when client cannot decide which redirect uri to use. ErrUndecidedRedirectUri = fmt.Errorf(`%w: "redirect_uri" cannot be decided`, oidc.ErrInvalidRequest) ErrUndecidedSectorIdentifierURI = fmt.Errorf(`%w: "sector_identifier_uri" cannot be inferred from the registerted "redirect_uri"`, oidc.ErrInvalidClient) )
var ( ErrClientNotFound = fmt.Errorf(`%w: client is not found`, oidc.ErrInvalidClient) ErrClientExists = fmt.Errorf(`%w: client already exists`, oidc.ErrInvalidClient) )
Functions ¶
This section is empty.
Types ¶
type AuthTemplate ¶
type AuthTemplate interface {
// contains filtered or unexported methods
}
AuthTemplate makes it easier to implement Authenticator by providing a determined processing flow.
func NewClientSecretBasic ¶
func NewClientSecretBasic() AuthTemplate
NewClientSecretBasic returns an AuthTemplate that is capable of performing client_secret_basic.
func NewClientSecretPost ¶
func NewClientSecretPost() AuthTemplate
NewClientSecretPost returns an AuthTemplate capable of performing client_secret_post.
func NewNoneAuth ¶
func NewNoneAuth() AuthTemplate
NewNoneAuth returns an AuthTemplate for handling public client with none as auth method.
type Authenticator ¶
type Authenticator interface { // Authenticate authenticates the client against credentials provided in the http.Request. Authenticate(ctx context.Context, rw http.ResponseWriter, r *http.Request) (*Client, error) }
Authenticator abstracts the authentication behaviour of a client.
func NewAuthenticator ¶
func NewAuthenticator(lookup Lookup, templates ...AuthTemplate) Authenticator
NewAuthenticator returns an Authenticator implementation that is capable of performing the authentication methods supported by the given templates
type Client ¶
type Client struct { Id string `json:"id"` Name string `json:"name,omitempty"` HashedSecret string `json:"hashed_secret,omitempty"` Public bool `json:"public"` RedirectUris oidc.RedirectUriSet `json:"redirect_uris,omitempty"` ResponseTypes oidc.ResponseTypeSet `json:"response_types,omitempty"` GrantTypes oidc.GrantTypeSet `json:"grant_types,omitempty"` Scopes map[oidc.Scope]json.RawMessage `json:"scopes,omitempty"` AppType oidc.AppType `json:"app_type,omitempty"` Contacts []string `json:"contacts,omitempty"` LogoUri string `json:"logo_uri,omitempty"` ClientUri string `json:"client_uri,omitempty"` PolicyUri string `json:"policy_uri,omitempty"` TosUri string `json:"tos_uri,omitempty"` JwksRef string `json:"jwks_ref,omitempty"` JwksValue string `json:"jwks_value,omitempty"` SectorIdUri string `json:"sector_id_uri,omitempty"` SubjectType oidc.SubjectType `json:"subject_type,omitempty"` IdTokenSignedResponseAlg jose.SignatureAlgorithm `json:"id_token_signed_response_alg,omitempty"` IdTokenEncryptedResponseAlg jose.EncryptionAlgorithm `json:"id_token_encrypted_response_alg,omitempty"` IdTokenEncryptedResponseEnc jose.ContentEncodingAlgorithm `json:"id_token_encrypted_response_enc,omitempty"` UserInfoSignedResponseAlg jose.SignatureAlgorithm `json:"user_info_signed_response_alg,omitempty"` UserInfoEncryptedResponseAlg jose.EncryptionAlgorithm `json:"user_info_encrypted_response_alg,omitempty"` UserInfoEncryptedResponseEnc jose.ContentEncodingAlgorithm `json:"user_info_encrypted_response_enc,omitempty"` RequestObjectSignedResponseAlg jose.SignatureAlgorithm `json:"request_object_signed_response_alg,omitempty"` RequestObjectEncryptedResponseAlg jose.EncryptionAlgorithm `json:"request_object_encrypted_response_alg,omitempty"` RequestObjectEncryptedResponseEnc jose.ContentEncodingAlgorithm `json:"request_object_encrypted_response_enc,omitempty"` TokenEndpointAuthMethod oidc.AuthMethod `json:"token_endpoint_auth_method,omitempty"` TokenEndpointAuthSigningAlg jose.SignatureAlgorithm `json:"token_endpoint_auth_signing_alg,omitempty"` DefaultMaxAge oidc.MaxAge `json:"default_max_age,omitempty"` DefaultAcrValues []string `json:"default_acr_values,omitempty"` RequestUris map[string]json.RawMessage `json:"request_uris,omitempty"` InteractionProvider string `json:"interaction_provider,omitempty"` }
Client models an OpenID Connect client. It contains only the properties relevant to the actual OpenID Connect processing.
Client secret is BCrypt hashed and therefore unable to be processed in its original form. Therefore, client does not support token_endpoint_authentication_method of client_secret_jwt, which requires using verifying a JWT token using the client's plain text secret. Other forms of authentication methods are supported. Client secrets can be compared using the CompareSecret method.
Scopes are indexed scope text to a raw json payload of cosmetics data. The cosmetics data is sent to the UI when asking for End-User authorization. The server does not need to understand it. Client registration service will work with the Authorization server companion UI to figure out the actual JSON data format.
Similarly, RequestUris are indexed request_uri mapping to an opaque JSON payload. For the most part, the authorization server does not need to understand its semantics. However, the payload may contain cached request object, which can save download efforts. The authorization server shall refer to client registration API to properly parse the payload if saving network round-trip is desired.
The client also contains several sets of JOSE signature and JOSE encryption algorithm combinations. Among these, encryption methods are only valid when encryption algorithm and content encoding algorithm are specified together. This applies to IdTokenEncryptedResponseAlg/IdTokenEncryptedResponseEnc, UserInfoEncryptedResponseAlg/UserInfoEncryptedResponseEnc, and RequestObjectEncryptedResponseAlg/RequestObjectEncryptedResponseEnc.
In addition, when an algorithm is empty, it will be regarded as none. This logic is different with the OpenID Connect specification where some absent algorithms are defaulted. For example, absent id_token_signed_response_alg is defaulted to RS256. However, because this Client is merely a snapshot of the client maintained by the client registration service, we took comfort in the fact that it is already validated and properly defaulted. Hence, treating absent algorithms as none makes the life easier.
func (*Client) CompareSecret ¶
CompareSecret returns true if the testSecret is comparable to the hashed truth.
func (*Client) DecideAcrValues ¶
DecideAcrValues defaults to the registered acr_values if the requested value is absent.
func (*Client) DecideMaxAge ¶
DecideMaxAge defaults to the registered max age if requested value is absent.
func (*Client) DecideRedirectUri ¶
func (c *Client) DecideRedirectUri(requested oidc.RedirectUri) (decided oidc.RedirectUri, err error)
DecideRedirectUri follows the specification rules to decide an effective redirect_uri to be used in the OpenID Connect processing. When client registers no redirect_uris, the requested redirect_uri must be present; When client registers a single redirect_uri, the requested redirect_uri is optional, but when present, must match the registered value; When client registers multiple redirect_uris, the requested redirect_uri must be present and matches one of the registered value. If an effective redirect uri cannot be decided, the ErrUndecidedRedirectUri error is returned.
func (*Client) DecideSectorIdentifierURI ¶
DecideSectorIdentifierURI follows the specification rules and decide the sector identifier uri used in pseudonymous subject identifier calculation. If the subject type is public, pseudo calculation is not needed, and an empty string is returned; if subject type is pairwise, the registered sector_identifier_uri is returned, or is inferred from the the host portion of registered redirect_uris who must then all from the same host.
func (*Client) HasGrantType ¶
HasGrantType returns true if client had registered the grant type.
func (*Client) HasRequestUri ¶
HasRequestUri returns true if client had registered the request_uri. The comparison is made with string comparison, hence caller is responsible to strip any fragments before calling this method.
func (*Client) HasResponseType ¶
func (c *Client) HasResponseType(responseType oidc.ResponseType) bool
HasResponseTypes returns true if client had registered the response type combo.
func (*Client) RequestObjectByRef ¶
RequestObjectByRef looks up the pre-registered request objects. The string value indicates the cached raw object and the bool value indicates cache hit. When cache hit is false, cache is not present. When cache hit is true, the cached raw object can still be empty if its SHA-256 hash does not match the reference URI's fragment component (if any).
func (*Client) ResolveJSONWebKeySet ¶
func (c *Client) ResolveJSONWebKeySet(ctx context.Context, strategy KeySetStrategy) (jwks *gojosev2.JSONWebKeySet, err error)
ResolveJSONWebKeySet resolves the client's JSON Web Key Set either by value or by reference. When client registered the JWKS by value, it is directly parsed and resolved; if client had registered it by reference, it is resolved using the KeySetStrategy.
func (*Client) ZeroFields ¶
type KeySetStrategy ¶
type KeySetStrategy interface {
Resolve(ctx context.Context, client *Client) (raw string, err error)
}
KeySetStrategy is the algorithm deployed to resolve client's JSON Web Key Set.
func FetchKeySetStrategy ¶
func FetchKeySetStrategy() KeySetStrategy
FetchKeySetStrategy returns a KeySetStrategy that directly fetches from remote JWKS URI when it is defined. The resolution process respects context cancellation and deadline signals.
type Lookup ¶
type Lookup interface { // FindById finds a client by its id from underlying persistence. If client is not found, return ErrClientNotFound FindById(ctx context.Context, clientId string) (*Client, error) }
Lookup finds a client.
type RedisStorage ¶
func (*RedisStorage) Delete ¶
func (s *RedisStorage) Delete(ctx context.Context, clientId string) error
type Storage ¶
type Storage interface { Lookup // Save a new client Insert(ctx context.Context, client *Client) error // Update an existing client Update(ctx context.Context, updated *Client, ref *Client) error // Delete a client by its id Delete(ctx context.Context, clientId string) error }
Storage persists a client.
Implementation Notes: it is unlikely that the authorization server will shoulder the responsibility of maintaining client registration itself. Hence, the Storage interface may only be needed for development and testing purposes where having an external service dependency is unnecessary.
func NewMemoryStorage ¶
func NewMemoryStorage() Storage
NewMemoryStorage returns a memory implementation of Storage. The implementation is not thread safe and not designed for production use.