Documentation
¶
Overview ¶
Package fakeprovider holds in-process fakes of the identity providers the library talks to (an OIDC issuer with the Keycloak admin API, and GitHub) for unit and end-to-end tests. It is test support: excluded from coverage and never imported by library code. Its servers are safe for concurrent use.
Index ¶
- type GitHubEndpoint
- type GitHubOptions
- type GitHubServer
- func (s *GitHubServer) APIURL() string
- func (s *GitHubServer) AuthorizeURL() string
- func (s *GitHubServer) Calls(endpoint GitHubEndpoint) int
- func (s *GitHubServer) ClientID() string
- func (s *GitHubServer) ClientSecret() string
- func (s *GitHubServer) FailWith(endpoint GitHubEndpoint, status int)
- func (s *GitHubServer) RevokedTokens() []string
- func (s *GitHubServer) SetTeams(teams []GitHubTeam)
- func (s *GitHubServer) TokenURL() string
- func (s *GitHubServer) URL() string
- type GitHubTeam
- type GitHubUser
- type OIDCHandler
- func (h *OIDCHandler) IDTokenHints() []string
- func (h *OIDCHandler) IssuerURL() string
- func (h *OIDCHandler) KeycloakClientLookups() int
- func (h *OIDCHandler) KeycloakTokenRequests() int
- func (h *OIDCHandler) RevokeKeycloakTokens()
- func (h *OIDCHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request)
- type OIDCOptions
- type OIDCServer
- type OIDCUser
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type GitHubEndpoint ¶
type GitHubEndpoint string
GitHubEndpoint names an endpoint of the fake GitHub for FailWith and Calls.
const ( GitHubEndpointAuthorize GitHubEndpoint = "authorize" // GET /login/oauth/authorize GitHubEndpointToken GitHubEndpoint = "token" // POST /login/oauth/access_token GitHubEndpointUser GitHubEndpoint = "user" // GET /user GitHubEndpointTeams GitHubEndpoint = "teams" // GET /user/teams GitHubEndpointRevoke GitHubEndpoint = "revoke" // DELETE /applications/{client_id}/token )
The endpoints of the fake GitHub.
type GitHubOptions ¶
type GitHubOptions struct {
ClientID string // default "github-client-id"
ClientSecret string // default "github-client-secret"
User GitHubUser // default {ID: 1, Login: "octocat", Name: "The Octocat", Email: "octocat@example.com"}
Teams []GitHubTeam // the user's teams; SetTeams replaces them
}
GitHubOptions configure StartGitHub. The zero value is usable.
type GitHubServer ¶
type GitHubServer struct {
// contains filtered or unexported fields
}
GitHubServer is a fake GitHub on http://127.0.0.1:<port>: the OAuth endpoints (authorize auto-approves, the token endpoint checks the client credentials, PKCE S256 and that redirect_uri is the one the code was issued for) and the REST API parts the github provider uses. It is safe for concurrent use.
func StartGitHub ¶
func StartGitHub(tb testing.TB, options GitHubOptions) *GitHubServer
StartGitHub starts a fake GitHub and closes it when the test ends.
func (*GitHubServer) APIURL ¶
func (s *GitHubServer) APIURL() string
APIURL returns the github.Options.APIURL to use: URL() (the API sits at the root, as on api.github.com).
func (*GitHubServer) AuthorizeURL ¶
func (s *GitHubServer) AuthorizeURL() string
AuthorizeURL returns the github.Options.AuthorizeURL to use: URL() + "/login/oauth/authorize".
func (*GitHubServer) Calls ¶
func (s *GitHubServer) Calls(endpoint GitHubEndpoint) int
Calls returns how many requests endpoint received, failed ones included.
func (*GitHubServer) ClientID ¶
func (s *GitHubServer) ClientID() string
ClientID returns the OAuth app's client ID (GitHubOptions.ClientID or its default).
func (*GitHubServer) ClientSecret ¶
func (s *GitHubServer) ClientSecret() string
ClientSecret returns the OAuth app's client secret (GitHubOptions.ClientSecret or its default).
func (*GitHubServer) FailWith ¶
func (s *GitHubServer) FailWith(endpoint GitHubEndpoint, status int)
FailWith makes endpoint answer status with a GitHub-style JSON error until called again with status 0. The authorize endpoint instead redirects back with error=access_denied (the user declined).
func (*GitHubServer) RevokedTokens ¶
func (s *GitHubServer) RevokedTokens() []string
RevokedTokens returns the access tokens revoked through DELETE /applications/{client_id}/token, in order.
func (*GitHubServer) SetTeams ¶
func (s *GitHubServer) SetTeams(teams []GitHubTeam)
SetTeams replaces the user's teams, e.g. to remove the user from an allowed team.
func (*GitHubServer) TokenURL ¶
func (s *GitHubServer) TokenURL() string
TokenURL returns the github.Options.TokenURL to use: URL() + "/login/oauth/access_token".
func (*GitHubServer) URL ¶
func (s *GitHubServer) URL() string
URL returns the base URL, http://127.0.0.1:<port>.
type GitHubTeam ¶
GitHubTeam is one team of the user as GET /user/teams returns it: organization login and team slug, in the case GitHub reports them.
type GitHubUser ¶
GitHubUser is the user the fake GitHub authenticates (GET /user).
type OIDCHandler ¶
type OIDCHandler struct {
// contains filtered or unexported fields
}
OIDCHandler is the fake issuer as an http.Handler. It serves, below the IssuerURL path: /.well-known/openid-configuration, /jwks, /authorize (auto-approves User: redirects to redirect_uri with code and state; a request without state, nonce or S256 code challenge gets error=invalid_request, an unknown client_id or unregistered redirect_uri a 400 page), /token (client secret, single-use code, redirect_uri and PKCE S256 checked; ID token with the authorize nonce and a JWT access token, RS256) and /end_session (records id_token_hint, redirects to a registered post_logout_redirect_uri with state, else a plain page). It is safe for concurrent use.
func NewOIDCHandler ¶
func NewOIDCHandler(options *OIDCOptions) (*OIDCHandler, error)
NewOIDCHandler returns a fake issuer with a fresh RSA signing key. It keeps a copy of options: changing them afterwards has no effect.
func (*OIDCHandler) IDTokenHints ¶
func (h *OIDCHandler) IDTokenHints() []string
IDTokenHints returns the id_token_hint values /end_session received, oldest first.
func (*OIDCHandler) IssuerURL ¶
func (h *OIDCHandler) IssuerURL() string
IssuerURL returns the issuer as configured: the iss claim and the discovery issuer.
func (*OIDCHandler) KeycloakClientLookups ¶
func (h *OIDCHandler) KeycloakClientLookups() int
KeycloakClientLookups returns how many client lookups (GET /clients?clientId=) the Admin API answered.
func (*OIDCHandler) KeycloakTokenRequests ¶
func (h *OIDCHandler) KeycloakTokenRequests() int
KeycloakTokenRequests returns how many requests reached the Keycloak token endpoint.
func (*OIDCHandler) RevokeKeycloakTokens ¶
func (h *OIDCHandler) RevokeKeycloakTokens()
RevokeKeycloakTokens invalidates every admin token issued so far, as Keycloak does before their expiry (key rotation, a logout of the service account): the Admin API answers 401 to them.
func (*OIDCHandler) ServeHTTP ¶
func (h *OIDCHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request)
ServeHTTP serves the issuer's endpoints.
type OIDCOptions ¶
type OIDCOptions struct {
IssuerURL string // required by NewOIDCHandler, set by StartOIDC: the iss claim; endpoints are served below its path
ClientID string // required
ClientSecret string // required; accepted by HTTP Basic and in the form
RedirectURIs []string // registered redirect URIs; empty accepts any
PostLogoutRedirectURIs []string // registered post-logout redirect URIs; empty accepts any
User OIDCUser
OmitEndSessionEndpoint bool // discovery without end_session_endpoint
OmitIDToken bool // token response without id_token
OpaqueAccessToken bool // a random access token instead of a JWT, as Google issues
AccessTokenSubject string // sub of the JWT access token in place of User.Subject: a token issued to another user
WrongNonce bool // the ID token carries another nonce than the authorize request
BadSignature bool // ID and access token signatures do not verify
ExpiredIDToken bool // the ID token expired a minute ago
TokenAnswer http.Handler // when set, answers every /token request in place of the fake: an IdP's error or broken answers
JWKSAnswer http.Handler // when set, answers every /jwks request in place of the fake: a key set outage or a broken key set
KeycloakRealm string // when set, also serves the Keycloak token endpoint and Admin API of this realm (keycloak.go)
KeycloakAuthenticationRealm string // realm whose token endpoint issues admin tokens; default KeycloakRealm
KeycloakClientID string // service account client for the client credentials grant
KeycloakClientSecret string
KeycloakUsername string // admin user for the password grant
KeycloakPassword string
}
OIDCOptions configures the fake issuer. Faults (the bool fields after User) make every token response broken in one specific way; TokenAnswer and JWKSAnswer replace the token endpoint and the key set altogether.
type OIDCServer ¶
type OIDCServer struct {
*OIDCHandler
// contains filtered or unexported fields
}
OIDCServer is a fake issuer on an httptest server.
func StartOIDC ¶
func StartOIDC(tb testing.TB, options OIDCOptions) *OIDCServer
StartOIDC serves a fake issuer on a loopback httptest server until the test ends. It sets IssuerURL to the server URL, or to <server URL>/realms/<KeycloakRealm> when a Keycloak realm is configured (the Keycloak layout). Construction errors fail the test.
func (*OIDCServer) URL ¶
func (s *OIDCServer) URL() string
URL returns the server's base URL: the Keycloak URL when a Keycloak realm is configured.
type OIDCUser ¶
type OIDCUser struct {
Subject string // ID token sub and Keycloak user ID; default "fake-user"
PreferredUsername string // preferred_username claim
Name string // name claim
Email string // email claim
EmailVerified bool // email_verified claim
Picture string // picture claim
SessionID string // sid claim of the ID token; omitted when empty
RealmRoles []string // access token realm_access.roles; Keycloak composite realm roles
ClientRoles []string // access token resource_access.<ClientID>.roles; Keycloak composite roles of client ClientID
Groups []string // access token groups; Keycloak group paths
Attributes map[string][]string // Keycloak user attributes
}
OIDCUser is the one user the fake issuer logs in. With a Keycloak realm the Admin API answers with the same roles and groups the access token carries.