client

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2020 License: MIT Imports: 16 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
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)
)
View Source
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)
)
View Source
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

func (c *Client) CompareSecret(testSecret string) bool

CompareSecret returns true if the testSecret is comparable to the hashed truth.

func (*Client) DecideAcrValues

func (c *Client) DecideAcrValues(requested []string) (decided []string)

DecideAcrValues defaults to the registered acr_values if the requested value is absent.

func (*Client) DecideMaxAge

func (c *Client) DecideMaxAge(requested oidc.MaxAge) (decided oidc.MaxAge)

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

func (c *Client) DecideSectorIdentifierURI() (string, error)

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

func (c *Client) HasGrantType(grantType oidc.GrantType) bool

HasGrantType returns true if client had registered the grant type.

func (*Client) HasRequestUri

func (c *Client) HasRequestUri(requestUri string) bool

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) HasScope

func (c *Client) HasScope(scope oidc.Scope) bool

HasScope returns true if client had registered the scope.

func (*Client) RequestObjectByRef

func (c *Client) RequestObjectByRef(ref string) (string, bool)

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

func (c *Client) ZeroFields() *Client

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

type RedisStorage struct {
	RedisClient redis.UniversalClient
	Logger      *zerolog.Logger
}

func (*RedisStorage) Delete

func (s *RedisStorage) Delete(ctx context.Context, clientId string) error

func (*RedisStorage) FindById

func (s *RedisStorage) FindById(ctx context.Context, clientId string) (*Client, error)

func (*RedisStorage) Insert

func (s *RedisStorage) Insert(ctx context.Context, client *Client) error

func (*RedisStorage) Update

func (s *RedisStorage) Update(ctx context.Context, updated *Client, ref *Client) 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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL