Documentation ¶
Overview ¶
Package auth enables an Ensign client to authenticate with Ensign's Authn and Authz service called Quarterdeck. Every Ensign RPC must include access tokens with the ProjectID and permissions assigned to the API key; the access tokens are signed by Quarterdeck's private keys which can be verified on an Ensign server using Quarterdeck's public keys. If the RPC credentials have incorrect permissions or attempt to access a resource that does not belong to the project then a gRPC Unauthorized error is returned.
Note: API Keys have access to all the topics in the specified project with the permissions assigned to the key; you cannot limit topics other than by creating new projects.
This package provides a Client that wraps APIKeys and makes requests to Quarterdeck in order to authenticate and refresh Ensign credentials. The client is intended to be used by the Ensign client to maintain an authenticated connection to Ensign for long-running processes (e.g. publishers and subscribers) and will make requests to Quarterdeck in an on-demand fashion to maintain authentication without logging out. The Ensign SDK must ensure that it requests credentials for every RPC call that it makes.
Index ¶
- Constants
- Variables
- func ExpiresAt(tks string) (_ time.Time, err error)
- func NotBefore(tks string) (_ time.Time, err error)
- func Parse(tks string) (claims *jwt.RegisteredClaims, err error)
- func PerRPCToken(accessToken string, insecure bool) grpc.CallOption
- func WithPerRPCToken(accessToken string, insecure bool) grpc.DialOption
- type APIKey
- type Client
- func (c *Client) Authenticate(ctx context.Context, apikey *APIKey) (tokens *Tokens, err error)
- func (c *Client) Credentials(ctx context.Context) (_ credentials.PerRPCCredentials, err error)
- func (c *Client) Login(ctx context.Context, clientID, clientSecret string) (creds credentials.PerRPCCredentials, err error)
- func (c *Client) Refresh(ctx context.Context, refresh *Tokens) (tokens *Tokens, err error)
- func (c *Client) Reset()
- func (c *Client) SetAPIKey(key *APIKey)
- func (c *Client) SetTokens(tokens *Tokens)
- func (c *Client) Status(ctx context.Context) (status *Status, err error)
- func (c *Client) StreamAuthenticate(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, ...) (_ grpc.ClientStream, err error)
- func (c *Client) UnaryAuthenticate(ctx context.Context, method string, req, reply interface{}, ...) (err error)
- func (c *Client) WaitForReady(ctx context.Context) (err error)
- type Credentials
- type Reply
- type Status
- type StatusError
- type Tokens
Constants ¶
const ( AuthenticateEP = "/v1/authenticate" RefreshEP = "/v1/refresh" StatusEP = "/v1/status" )
Variables ¶
var ( ErrIncompleteCreds = errors.New("both client id and secret are required") ErrNoAPIKeys = errors.New("no api keys available: must login the client first") )
Functions ¶
func PerRPCToken ¶
func PerRPCToken(accessToken string, insecure bool) grpc.CallOption
PerRPCToken returns a CallOption to attach access tokens to a single RPC call. Because access tokens expire and need to be refreshed; this is the preferred way of attaching credentials to an RPC call.
func WithPerRPCToken ¶
func WithPerRPCToken(accessToken string, insecure bool) grpc.DialOption
WithPerRPCToken returns a DialOption to ensure that the credentials are attached to every RPC call but only have to be specified once by the dialer. The issue with using this method is that access tokens expire; so unless you're expecting your Ensign session to be shorter than the access token duration (about an hour), then using the PerRPCToken CallOption is usually a better choice.
Types ¶
type APIKey ¶
type APIKey struct { ClientID string `json:"client_id"` ClientSecret string `json:"client_secret"` }
APIKey wraps per-project Ensign credentials and can be stored as JSON on disk. This struct is also used to POST JSON requests to the Quarterdeck service.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client connects to the Quarterdeck authentication service in order to authenticate API Keys and to refresh access tokens for Ensign access. The Client maintains the API Keys and tokens so that it can hand out credentials in long running processes, ensuring that the Ensign client can stay logged into Ensign for as long as possible.
func New ¶
Create a new authentication client to connect to Quarterdeck. The authURL should be the endpoint of the Quarterdeck service and must be a parseable URL. The insecure flag tells the client to create Ensign credentials that are insecure; e.g. not requiring a TLS connection. The insecure flag should only be true in development. After creating a Quarterdeck client, ensure to call Login() to prepare it to hand out credentials to connect to Ensign.
func (*Client) Authenticate ¶
Authenticate makes a request to the Quarterdeck server with the available API keys in order to fetch new access and refresh tokens. The tokens are returned directly.
func (*Client) Credentials ¶ added in v0.6.0
func (c *Client) Credentials(ctx context.Context) (_ credentials.PerRPCCredentials, err error)
Credentials returns the PerRPC credentials to make a gRPC request. If the tokens are expired, this method will refresh them by making a request to Quarterdeck. An error is returned if the client is not logged in. This method should be called before every Ensign RPC in order to ensure the RPC has valid credentials.
func (*Client) Login ¶
func (c *Client) Login(ctx context.Context, clientID, clientSecret string) (creds credentials.PerRPCCredentials, err error)
Login to Quarterdeck, storing the API credentials on the client and making a login request to Quarterdeck to fetch access and refresh tokens. Ensure that a context with a deadline is specified in order to reduce how long the client attempts to login for. Once logged in, the authentication client can hand out credentials on demand. Credentials are returned from this method in case users want to add the credentials as a DialOption; however this is only good for short duration process (e.g. processes that will stop before the access token expires). Long running processes should use the UnaryInterceptor and StreamInterceptor methods or call Credentials to get a PerRPCCredentials CallOption to add to every RPC call.
func (*Client) Refresh ¶
Refresh makes a request to the Quarterdeck server with the refresh token in order to fetch a new access token. If the refresh token is expired an error is returned. The new tokens are returned directly.
func (*Client) Reset ¶ added in v0.6.0
func (c *Client) Reset()
Reset removes the apikeys and tokens from the client (used for testing).
func (*Client) SetAPIKey ¶ added in v0.6.0
SetAPIKey allows the test suite to set the apikey on the client.
func (*Client) SetTokens ¶ added in v0.6.0
SetTokens allows the test suite to set the tokens on the client.
func (*Client) Status ¶ added in v0.6.0
Status makes a request to the Quarterdeck server to check if the service is online and ready to make requests. The status check is returned directly.
func (*Client) StreamAuthenticate ¶ added in v0.6.0
func (c *Client) StreamAuthenticate(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (_ grpc.ClientStream, err error)
An interceptor that adds credentials to every streaming request made by the gRPC client.
func (*Client) UnaryAuthenticate ¶ added in v0.6.0
func (c *Client) UnaryAuthenticate(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) (err error)
An interceptor that adds credentials on every unary request made by the gRPC client.
func (*Client) WaitForReady ¶ added in v0.6.0
Wait for ready polls the Quarterdeck status endpoint until it responds with a 200, retrying with exponential backoff or until the context deadline is expired. If the input context does not have a deadline, then a default deadline of 5 minutes is used so this method does not block indefinitely. When the Quarterdeck service is ready then no error is returned; if the Quartdeck does not respond within the retry window an error is returned.
type Credentials ¶
type Credentials struct {
// contains filtered or unexported fields
}
Credentials implement the credentials.PerRPCCredentials interface so that the access token can be embedded in the metadata of each RPC call for authentication and authorization. The credentials wrap an access token and whether or not the credentials can be used in insecure mode. Insecure should almost always be false; the only exception is when doing local development with an Ensign service running in docker compose or in CI tests. For staging and production, insecure should be false.
func (*Credentials) Equals ¶ added in v0.6.0
func (t *Credentials) Equals(o *Credentials) bool
Equals compares credentials (primarily used for testing).
func (*Credentials) GetRequestMetadata ¶
func (t *Credentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
GetRequestMetadata attaches the bearer access token to the authorization header.
func (*Credentials) RequireTransportSecurity ¶
func (t *Credentials) RequireTransportSecurity() bool
RequireTransportSecurity should almost always return true unless accessing a local Ensign server in development or CI environments.
type Status ¶ added in v0.6.0
type Status struct { Status string `json:"status"` Uptime string `json:"uptime,omitempty"` Version string `json:"version,omitempty"` }
Status describes the current state of the Quarterdeck service. This struct is used to GET JSON requests from the Quarterdeck service.
type StatusError ¶
StatusError decodes an error response from Quarterdeck.
func (*StatusError) Error ¶
func (e *StatusError) Error() string
type Tokens ¶
type Tokens struct { AccessToken string `json:"access_token,omitempty"` RefreshToken string `json:"refresh_token,omitempty"` LastLogin string `json:"last_login,omitempty"` // contains filtered or unexported fields }
Tokens are handed out by Quarterdeck to login to the Ensign service. The AccessToken is used to create gRPC per-RPC credentials and the refresh token is used to fetch a new access token when it expires. Tokens can be cached as JSON on disk. This struct is also used to GET/POST JSON requests from/to the Quarterdeck service.
func (*Tokens) AccessValid ¶ added in v0.6.0
AccessValid returns true if the access token has not expired
func (*Tokens) RefreshValid ¶ added in v0.6.0
RefreshValid returns true if the refresh token has not expired and it is after the not before time when the token cannot yet be used.