auth

package
v0.0.0-...-d60a78d Latest Latest
Warning

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

Go to latest
Published: Jul 29, 2023 License: Apache-2.0 Imports: 42 Imported by: 63

Documentation

Overview

Package auth implements authentication and authorization framework for HTTP servers.

Index

Constants

View Source
const (
	// MaxDelegationTokenTTL is maximum allowed token lifetime that can be
	// requested via MintDelegationToken.
	MaxDelegationTokenTTL = 3 * time.Hour
)

Variables

View Source
var (
	// ErrNotConfigured is returned by Authenticate if auth library wasn't
	// properly initialized (see SetConfig).
	ErrNotConfigured = errors.New("auth: the library is not properly configured")

	// ErrNoUsersAPI is returned by LoginURL and LogoutURL if none of
	// the authentication methods support UsersAPI.
	ErrNoUsersAPI = errors.New("auth: methods do not support login or logout URL")

	// ErrBadClientID is returned by Authenticate if caller is using
	// non-whitelisted OAuth2 client. More info is in the log.
	ErrBadClientID = errors.New("auth: OAuth client_id is not whitelisted")

	// ErrIPNotWhitelisted is returned when an account is restricted by an IP
	// whitelist and request's remote_addr is not in it.
	ErrIPNotWhitelisted = errors.New("auth: IP is not whitelisted")
)
View Source
var (
	// ErrTokenServiceNotConfigured is returned by MintDelegationToken if the
	// token service URL is not configured. This usually means the corresponding
	// auth service is not paired with a token server.
	ErrTokenServiceNotConfigured = fmt.Errorf("auth: token service URL is not configured")

	// ErrBrokenTokenService is returned by MintDelegationToken if the RPC to the
	// token service succeeded, but response doesn't make sense. This should not
	// generally happen.
	ErrBrokenTokenService = fmt.Errorf("auth: unrecognized response from the token service")

	// ErrAnonymousDelegation is returned by MintDelegationToken if it is used in
	// a context of handling of an anonymous call.
	//
	// There's no identity to delegate in this case.
	ErrAnonymousDelegation = fmt.Errorf("auth: can't get delegation token for anonymous user")

	// ErrBadTargetHost is returned by MintDelegationToken if it receives invalid
	// TargetHost parameter.
	ErrBadTargetHost = fmt.Errorf("auth: invalid TargetHost (doesn't look like a hostname:port pair)")

	// ErrBadDelegationTokenTTL is returned by MintDelegationToken if requested
	// token lifetime is outside of the allowed range.
	ErrBadDelegationTokenTTL = fmt.Errorf("auth: requested delegation token TTL is invalid")

	// ErrBadDelegationTag is returned by MintDelegationToken if some of the
	// passed tags are malformed.
	ErrBadDelegationTag = fmt.Errorf("auth: provided delegation tags are invalid")
)
View Source
var ErrBadOAuthToken = errors.New("oauth: bad access token")

ErrBadOAuthToken is returned by GoogleOAuth2Method if the access token it checks is bad.

View Source
var ErrNoAuthState = errors.New("auth: auth.State is not in the context")

ErrNoAuthState is returned when a function requires State to be in the context, but it is not there. In particular `IsMember` requires an existing state.

Functions

func Authenticate

func Authenticate(m ...Method) router.Middleware

Authenticate returns a middleware that performs authentication.

Typically you only one one Method, but you may specify multiple Methods to be tried in order (see Authenticator).

This middleware either updates the context by injecting the authentication state into it (enabling functions like CurrentIdentity and IsMember), or aborts the request with an HTTP 401 or HTTP 500 error.

Note that it passes through anonymous requests. CurrentIdentity returns identity.AnonymousIdentity in this case. Use separate authorization layer to further restrict the access, if necessary.

func CurrentIdentity

func CurrentIdentity(c context.Context) identity.Identity

CurrentIdentity return identity of the current caller.

Shortcut for GetState(c).User().Identity(). Returns AnonymousIdentity if the context doesn't have State.

func GetDB

func GetDB(c context.Context) (authdb.DB, error)

GetDB returns most recent snapshot of authorization database using DBProvider installed in the context via 'ModifyConfig'.

If no factory is installed, returns DB that forbids everything and logs errors. It is often good enough for unit tests that do not care about authorization, and still not horribly bad if accidentally used in production.

func GetPerRPCCredentials

func GetPerRPCCredentials(kind RPCAuthorityKind, opts ...RPCOption) (credentials.PerRPCCredentials, error)

GetPerRPCCredentials returns gRPC's PerRPCCredentials implementation.

It can be used to authenticate outbound gPRC RPC's.

func GetRPCTransport

func GetRPCTransport(c context.Context, kind RPCAuthorityKind, opts ...RPCOption) (http.RoundTripper, error)

GetRPCTransport returns http.RoundTripper to use for outbound HTTP RPC requests.

Usage:

tr, err := auth.GetRPCTransport(c, auth.AsSelf, auth.WithScopes("..."))
if err != nil {
  return err
}
client := &http.Client{Transport: tr}
...

func GetSigner

func GetSigner(c context.Context) signing.Signer

GetSigner returns the signing.Signer instance representing the service.

It is injected into the context as part of Config. It can be used to grab a service account the service is running as or its current public certificates.

Returns nil if the signer is not available.

func GetTokenSource

func GetTokenSource(c context.Context, kind RPCAuthorityKind, opts ...RPCOption) (oauth2.TokenSource, error)

GetTokenSource returns an oauth2.TokenSource bound to the supplied Context.

Supports only AsSelf and AsActor authorization kinds, since they are only ones that exclusively use OAuth2 tokens and no other extra headers.

While GetPerRPCCredentials is preferred, this can be used by packages that cannot or do not properly handle this gRPC option.

func InstallHandlers

func InstallHandlers(r *router.Router, base router.MiddlewareChain)

InstallHandlers installs authentication related HTTP handlers.

All new HTTP routes live under '/auth/api/' prefix.

If you are using appengine/gaeauth/server, these handlers are already installed.

func IsMember

func IsMember(c context.Context, groups ...string) (bool, error)

IsMember returns true if the current caller is in any of the given groups.

Unknown groups are considered empty (the function returns false). If the context doesn't have State installed returns ErrNoAuthState.

May also return errors if the check can not be performed (e.g. on datastore issues).

func LoginURL

func LoginURL(c context.Context, dest string) (string, error)

LoginURL returns a URL that, when visited, prompts the user to sign in, then redirects the user to the URL specified by dest.

Shortcut for GetState(c).Authenticator().LoginURL(...).

func LogoutURL

func LogoutURL(c context.Context, dest string) (string, error)

LogoutURL returns a URL that, when visited, signs the user out, then redirects the user to the URL specified by dest.

Shortcut for GetState(c).Authenticator().LogoutURL(...).

func MintAccessTokenForServiceAccount

func MintAccessTokenForServiceAccount(ctx context.Context, params MintAccessTokenParams) (*oauth2.Token, error)

MintAccessTokenForServiceAccount produces an access token for some service account that the current service has "iam.serviceAccountActor" role in.

Used to implement AsActor authorization kind, but can also be used directly, if needed. The token is cached internally. Same token may be returned by multiple calls, if its lifetime allows.

Recognizes transient errors and marks them, but does not automatically retry. Has internal timeout of 10 sec.

func MintDelegationToken

func MintDelegationToken(ctx context.Context, p DelegationTokenParams) (*delegation.Token, error)

MintDelegationToken returns a delegation token that can be used by the current service to "pretend" to be the current caller (as returned by CurrentIdentity(...)) when sending requests to some other LUCI service.

The delegation token is essentially a signed assertion that the current service is allowed to access some other service on behalf of the current user.

A token can be targeted to some single specific service or usable by any allowed LUCI service (aka 'untargeted'). See TargetHost and Untargeted fields in DelegationTokenParams.

The token is cached internally. Same token may be returned by multiple calls, if its lifetime allows.

func ModifyConfig

func ModifyConfig(c context.Context, cb func(Config) Config) context.Context

ModifyConfig makes a context with a derived configuration.

It grabs current configuration from the context (if any), passes it to the callback, and puts whatever callback returns into a derived context.

func SetConfig

func SetConfig(c context.Context, cfg *Config) context.Context

SetConfig completely replaces the configuration in the context.

func WithState

func WithState(c context.Context, s State) context.Context

WithState injects State into the context.

Mostly useful from tests. Must not be normally used from production code, Authenticate sets the state itself.

Types

type AccessTokenProvider

type AccessTokenProvider func(c context.Context, scopes []string) (*oauth2.Token, error)

AccessTokenProvider knows how to generate OAuth2 access token for the service account belonging to the server itself.

type AnonymousTransportProvider

type AnonymousTransportProvider func(c context.Context) http.RoundTripper

AnonymousTransportProvider returns http.RoundTriper that can make unauthenticated HTTP requests.

The returned round tripper is assumed to be bound to the context and won't outlive it.

type Authenticator

type Authenticator struct {
	Methods []Method // a list of authentication methods to try
}

Authenticator performs authentication of incoming requests.

It is a stateless object configured with a list of methods to try when authenticating incoming requests. It implements Authenticate method that performs high-level authentication logic using the provided list of low-level auth methods.

Note that most likely you don't need to instantiate this object directly. Use Authenticate middleware instead. Authenticator is exposed publicly only to be used in advanced cases, when you need to fine-tune authentication behavior.

func (*Authenticator) Authenticate

func (a *Authenticator) Authenticate(c context.Context, r *http.Request) (context.Context, error)

Authenticate authenticates the requests and adds State into the context.

Returns an error if credentials are provided, but invalid. If no credentials are provided (i.e. the request is anonymous), finishes successfully, but in that case State.Identity() returns AnonymousIdentity.

func (*Authenticator) GetMiddleware

func (a *Authenticator) GetMiddleware() router.Middleware

GetMiddleware returns a middleware that uses this Authenticator for authentication.

It uses a.Authenticate internally and handles errors appropriately.

func (*Authenticator) LoginURL

func (a *Authenticator) LoginURL(c context.Context, dest string) (string, error)

LoginURL returns a URL that, when visited, prompts the user to sign in, then redirects the user to the URL specified by dest.

Returns ErrNoUsersAPI if none of the authentication methods support login URLs.

func (*Authenticator) LogoutURL

func (a *Authenticator) LogoutURL(c context.Context, dest string) (string, error)

LogoutURL returns a URL that, when visited, signs the user out, then redirects the user to the URL specified by dest.

Returns ErrNoUsersAPI if none of the authentication methods support login URLs.

type Config

type Config struct {
	// DBProvider is a callback that returns most recent DB instance.
	DBProvider DBProvider

	// Signer possesses the service's private key and can sign blobs with it.
	//
	// It provides the bundle with corresponding public keys and information about
	// the service account they belong too (the service's own identity).
	//
	// Used to implement '/auth/api/v1/server/(certificates|info)' routes.
	Signer signing.Signer

	// AccessTokenProvider knows how to generate OAuth2 access token for the
	// service account belonging to the server itself.
	AccessTokenProvider AccessTokenProvider

	// AnonymousTransport returns http.RoundTriper that can make unauthenticated
	// HTTP requests.
	//
	// The returned round tripper is assumed to be bound to the context and won't
	// outlive it.
	AnonymousTransport AnonymousTransportProvider

	// IsDevMode is true when running the server locally during development.
	//
	// Setting this to true changes default deadlines. For instance, GAE dev
	// server is known to be very slow and deadlines tuned for production
	// environment are too limiting.
	IsDevMode bool
}

Config contains global configuration of the auth library.

This configuration adjusts the library to the particular execution environment (GAE, Flex, whatever). It contains concrete implementations of various interfaces used by the library.

It lives in the context and must be installed there by some root middleware (via ModifyConfig call).

type DBProvider

type DBProvider func(c context.Context) (authdb.DB, error)

DBProvider is a callback that returns most recent DB instance.

DB represents a snapshot of user groups used for authorization checks.

type DelegationTokenParams

type DelegationTokenParams struct {
	// TargetHost, if given, is hostname (with, possibly, ":port") of a service
	// that the token will be sent to.
	//
	// If this parameter is used, the resulting delegation token is scoped
	// only to the service at TargetHost. All other services will reject it.
	//
	// Must be set if Untargeted is false. Ignored if Untargeted is true.
	TargetHost string

	// Untargeted, if true, indicates that the caller is requesting a token that
	// is not scoped to any particular service.
	//
	// Such token can be sent to any supported LUCI service. Only whitelisted set
	// of callers have such superpower.
	//
	// If Untargeted is true, TargetHost is ignored.
	Untargeted bool

	// MinTTL defines an acceptable token lifetime.
	//
	// The returned token will be valid for at least MinTTL, but no longer than
	// MaxDelegationTokenTTL (which is 3h).
	//
	// Default is 10 min.
	MinTTL time.Duration

	// Intent is a reason why the token is created.
	//
	// Used only for logging purposes on the auth service, will be indexed. Should
	// be a short identifier-like string.
	//
	// Optional.
	Intent string

	// Tags are optional arbitrary key:value pairs embedded into the token.
	//
	// They convey circumstance of why the token is created.
	//
	// Services that accept the token may use them for additional authorization
	// decisions. Please use extremely carefully, only when you control both sides
	// of the delegation link and can guarantee that services involved understand
	// the tags.
	Tags []string
	// contains filtered or unexported fields
}

DelegationTokenParams is passed to MintDelegationToken.

type GoogleOAuth2Method

type GoogleOAuth2Method struct {
	// Scopes is a list of OAuth scopes to check when authenticating the token.
	Scopes []string
	// contains filtered or unexported fields
}

GoogleOAuth2Method implements Method on top of Google's OAuth2 endpoint.

It is useful for development verification (e.g., "dev_appserver") or verification in environments without the User API (e.g., Flex).

func (*GoogleOAuth2Method) Authenticate

func (m *GoogleOAuth2Method) Authenticate(c context.Context, r *http.Request) (user *User, err error)

Authenticate implements Method.

type Method

type Method interface {
	// Authenticate extracts user information from the incoming request.
	//
	// It returns:
	//   * (*User, nil) on success.
	//   * (nil, nil) if the method is not applicable.
	//   * (nil, error) if the method is applicable, but credentials are invalid.
	Authenticate(context.Context, *http.Request) (*User, error)
}

Method implements a particular kind of low-level authentication mechanism.

It may also optionally implement UsersAPI (if the method support login and logout URLs).

Methods are not usually used directly, but passed to Authenticator{...} that knows how to apply them.

type MintAccessTokenParams

type MintAccessTokenParams struct {
	// ServiceAccount is an email of a service account to mint a token for.
	ServiceAccount string

	// Scopes is a list of OAuth scopes the token should have.
	Scopes []string

	// MinTTL defines an acceptable token lifetime.
	//
	// The returned token will be valid for at least MinTTL, but no longer than
	// one hour.
	//
	// Default is 2 min.
	MinTTL time.Duration
}

MintAccessTokenParams is passed to MintAccessTokenForServiceAccount.

type RPCAuthorityKind

type RPCAuthorityKind int

RPCAuthorityKind defines under whose authority RPCs are made.

const (
	// NoAuth is used for outbound RPCs that don't have any implicit auth headers.
	NoAuth RPCAuthorityKind = iota

	// AsSelf is used for outbound RPCs sent with the authority of the current
	// service itself.
	//
	// RPC requests done in this mode will have 'Authorization' header set to the
	// OAuth2 access token of the service's own service account.
	//
	// By default uses "https://www.googleapis.com/auth/userinfo.email" API scope.
	// Can be customized with WithScopes() options.
	AsSelf

	// AsUser is used for outbound RPCs that inherit the authority of a user
	// that initiated the request that is currently being handled.
	//
	// If the current request was initiated by an anonymous caller, the RPC will
	// have no auth headers (just like in NoAuth mode).
	//
	// Can also be used together with MintDelegationToken to make requests on
	// user behalf asynchronously. For example, to associate end-user authority
	// with some delayed task, call MintDelegationToken (in a context of a user
	// initiated request) when this task is created and store the resulting token
	// along with the task. Then, to make an RPC on behalf of the user from the
	// task use GetRPCTransport(ctx, AsUser, WithDelegationToken(token)).
	//
	// The implementation is based on LUCI-specific protocol that uses special
	// delegation tokens. Only LUCI backends can understand them.
	AsUser

	// AsActor is used for outbound RPCs sent with the authority of some service
	// account that the current service has "iam.serviceAccountActor" role in.
	//
	// RPC requests done in this mode will have 'Authorization' header set to
	// the access token of the service account specified by WithServiceAccount()
	// option.
	//
	// By default uses "https://www.googleapis.com/auth/userinfo.email" API scope.
	// Can be customized with WithScopes() options.
	AsActor
)

type RPCOption

type RPCOption interface {
	// contains filtered or unexported methods
}

RPCOption is an option for GetRPCTransport or GetPerRPCCredentials functions.

func WithDelegationTags

func WithDelegationTags(tags ...string) RPCOption

WithDelegationTags can be used to attach tags to the delegation token used internally in AsUser mode.

The recipient of the RPC that uses the delegation will be able to extract them, if necessary. They are also logged in the token server logs.

Each tag is a key:value string.

Note that any delegation tags are ignored if the current request was initiated by an anonymous caller, since delegation protocol is not actually used in this case.

func WithDelegationToken

func WithDelegationToken(token string) RPCOption

WithDelegationToken can be used to attach an existing delegation token to requests made in AsUser mode.

The token can be obtained earlier via MintDelegationToken call. The transport doesn't attempt to validate it and just blindly sends it to the other side.

func WithMonitoringClient

func WithMonitoringClient(client string) RPCOption

WithMonitoringClient allows to override 'client' field that goes into HTTP client monitoring metrics (such as 'http/response_status').

The default value of the field is "luci-go-server".

Note that the metrics also include hostname of the target service (in 'name' field), so in most cases it is fine to use the default client name. Overriding it may be useful if you want to differentiate between requests made to the same host from a bunch of different places in the code.

This option has absolutely no effect when passed GetPerRPCCredentials() or GetTokenSource(). It applies only to GetRPCTransport().

func WithScopes

func WithScopes(scopes ...string) RPCOption

WithScopes can be used to customize OAuth scopes for outbound RPC requests.

If not used, the requests are made with "userinfo.email" scope.

func WithServiceAccount

func WithServiceAccount(email string) RPCOption

WithServiceAccount option must be used with AsActor authority kind to specify what service account to act as.

type Session

type Session struct {
	SessionID string    // same as `sessionID` passed to GetSession()
	UserID    string    // authentication provider specific user id
	User      User      // user profile, including identity string
	Exp       time.Time // when the session expires
}

Session is returned by SessionStore.GetSession(...).

type SessionStore

type SessionStore interface {
	// OpenSession create a new session for a user with given expiration time.
	// It returns unique session ID.
	OpenSession(c context.Context, userID string, u *User, exp time.Time) (string, error)

	// CloseSession closes a session given its ID. Does nothing if session is
	// already closed or doesn't exist. Returns only transient errors.
	CloseSession(c context.Context, sessionID string) error

	// GetSession returns existing non-expired session given its ID. Returns nil
	// if session doesn't exist, closed or expired. Returns only transient errors.
	GetSession(c context.Context, sessionID string) (*Session, error)
}

SessionStore keeps user sessions in some permanent storage. SessionStore is used by some authentication methods (e.g. openid.AuthMethod).

type State

type State interface {
	// Authenticator is an Authenticator used to authenticate the request.
	Authenticator() *Authenticator

	// DB is authdb.DB snapshot with authorization information to use when
	// processing this request.
	//
	// Use directly only when you know what your are doing. Prefer to use wrapping
	// functions (e.g. IsMember) instead.
	DB() authdb.DB

	// Method returns authentication method used for current request or nil if
	// request is anonymous.
	//
	// If non-nil, its one of the methods in Authenticator.Methods.
	Method() Method

	// User holds the identity and profile of the current caller. User.Identity
	// usually matches PeerIdentity(), but can be different if delegation is used.
	// This field is never nil. For anonymous call it contains User with identity
	// AnonymousIdentity. Do not modify it.
	User() *User

	// PeerIdentity identifies whoever is making the request. It's an identity
	// directly extracted from user credentials (ignoring delegation tokens).
	PeerIdentity() identity.Identity

	// PeerIP is IP address (IPv4 or IPv6) of whoever is making the request or
	// nil if not available.
	PeerIP() net.IP
}

State is stored in the context when handling an incoming request. It contains authentication related state of the current request.

func GetState

func GetState(c context.Context) State

GetState return State stored in the context or nil if it is not available.

type User

type User struct {
	// Identity is identity string of the user (may be AnonymousIdentity).
	// If User is returned by Authenticate(...), Identity string is always present
	// and valid.
	Identity identity.Identity `json:"identity,omitempty"`

	// Superuser is true if the user is site-level administrator. For example, on
	// GAE this bit is set for GAE-level administrators. Optional, default false.
	Superuser bool `json:"superuser,omitempty"`

	// Email is email of the user. Optional, default "". Don't use it as a key
	// in various structures. Prefer to use Identity() instead (it is always
	// available).
	Email string `json:"email,omitempty"`

	// Name is full name of the user. Optional, default "".
	Name string `json:"name,omitempty"`

	// Picture is URL of the user avatar. Optional, default "".
	Picture string `json:"picture,omitempty"`

	// ClientID is the ID of the pre-registered OAuth2 client so its identity can
	// be verified. Used only by authentication methods based on OAuth2.
	// See https://developers.google.com/console/help/#generatingoauth2 for more.
	ClientID string `json:"client_id,omitempty"`
}

User represents identity and profile of a user.

func CurrentUser

func CurrentUser(c context.Context) *User

CurrentUser represents the current caller.

Shortcut for GetState(c).User(). Returns user with AnonymousIdentity if the context doesn't have State.

type UsersAPI

type UsersAPI interface {
	// LoginURL returns a URL that, when visited, prompts the user to sign in,
	// then redirects the user to the URL specified by dest.
	LoginURL(c context.Context, dest string) (string, error)

	// LogoutURL returns a URL that, when visited, signs the user out,
	// then redirects the user to the URL specified by dest.
	LogoutURL(c context.Context, dest string) (string, error)
}

UsersAPI may be additionally implemented by Method if it supports login and logout URLs.

Directories

Path Synopsis
Package authdb contains definition of Authentication Database (aka AuthDB).
Package authdb contains definition of Authentication Database (aka AuthDB).
Package authtest implements some interfaces used by auth package to simplify unit testing.
Package authtest implements some interfaces used by auth package to simplify unit testing.
Package delegation contains low-level API for working with delegation tokens.
Package delegation contains low-level API for working with delegation tokens.
Package openid implements OpenID Connect Login protocol (client side).
Package openid implements OpenID Connect Login protocol (client side).
Package service implements a wrapper around API exposed by auth_service: https://github.com/luci/luci-py/tree/master/appengine/auth_service
Package service implements a wrapper around API exposed by auth_service: https://github.com/luci/luci-py/tree/master/appengine/auth_service
Package signing provides interfaces to sign arbitrary small blobs with RSA-SHA256 signature (PKCS1v15) and verify such signatures.
Package signing provides interfaces to sign arbitrary small blobs with RSA-SHA256 signature (PKCS1v15) and verify such signatures.
signingtest
Package signingtest implements signing.Signer interface using small random keys.
Package signingtest implements signing.Signer interface using small random keys.
Package xsrf provides Cross Site Request Forgery prevention middleware.
Package xsrf provides Cross Site Request Forgery prevention middleware.

Jump to

Keyboard shortcuts

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