auth

package
v0.0.0-...-51f9457 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2021 License: Apache-2.0 Imports: 47 Imported by: 0

Documentation

Overview

Package auth implements authentication and authorization framework for HTTP servers.

Index

Constants

View Source
const (
	// InternalServicesGroup is a name of a group with service accounts of LUCI
	// microservices of the current LUCI deployment (and only them!).
	//
	// Accounts in this group are allowed to use X-Luci-Project header to specify
	// that RPCs are done in a context of some particular project. For such
	// requests CurrentIdentity() == 'project:<X-Luci-Project value>'.
	//
	// This group should contain only **fully trusted** services, deployed and
	// managed by the LUCI deployment administrators. Adding "random" services
	// here is a security risk, since they will be able to impersonate any LUCI
	// project.
	InternalServicesGroup = "auth-luci-services"
)
View Source
const (
	// MaxDelegationTokenTTL is maximum allowed token lifetime that can be
	// requested via MintDelegationToken.
	MaxDelegationTokenTTL = 3 * time.Hour
)
View Source
const (
	// MaxScopedTokenTTL is maximum allowed token lifetime that can be
	// requested via MintScopedToken.
	MaxScopedTokenTTL = 15 * time.Minute
)
View Source
const XLUCIProjectHeader = "X-Luci-Project"

XLUCIProjectHeader is a header with the current project for internal LUCI RPCs done via AsProject authority.

Variables

View Source
var (

	// ErrNotConfigured is returned by Authenticate and other functions if the
	// context wasn't previously initialized via 'Initialize'.
	ErrNotConfigured = errors.New("auth: the library is not properly configured", grpcutil.InternalTag)

	// 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", grpcutil.PermissionDeniedTag)

	// ErrBadAudience is returned by Authenticate if token's audience is unknown.
	ErrBadAudience = errors.New("auth: bad token audience", grpcutil.PermissionDeniedTag)

	// ErrBadRemoteAddr is returned by Authenticate if request's remote_addr can't
	// be parsed.
	ErrBadRemoteAddr = errors.New("auth: bad remote addr", grpcutil.InternalTag)

	// 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", grpcutil.PermissionDeniedTag)

	// ErrProjectHeaderForbidden is returned by Authenticate if an unknown caller
	// tries to use X-Luci-Project header. Only a whitelisted set of callers
	// are allowed to use this header, see InternalServicesGroup.
	ErrProjectHeaderForbidden = errors.New("auth: the caller is not allowed to use X-Luci-Project", grpcutil.PermissionDeniedTag)

	// 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")

	// ErrNoForwardableCreds is returned by GetRPCTransport when attempting to
	// forward credentials (via AsCredentialsForwarder) that are not forwardable.
	ErrNoForwardableCreds = errors.New("auth: no forwardable credentials in the context")
)
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)")

	// ErrBadTokenTTL is returned by MintDelegationToken and MintProjectToken if requested
	// token lifetime is outside of the allowed range.
	ErrBadTokenTTL = fmt.Errorf("auth: requested 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 is returned by GoogleOAuth2Method if the access token it
	// checks either totally invalid, expired or has a wrong list of scopes.
	ErrBadOAuthToken = errors.New("oauth: bad access token", grpcutil.UnauthenticatedTag)

	// ErrBadAuthorizationHeader is returned by GoogleOAuth2Method if it doesn't
	// recognize the format of Authorization header.
	ErrBadAuthorizationHeader = errors.New("oauth: bad Authorization header", grpcutil.UnauthenticatedTag)
)
View Source
var CloudOAuthScopes = []string{
	"https://www.googleapis.com/auth/cloud-platform",
	"https://www.googleapis.com/auth/userinfo.email",
}

CloudOAuthScopes is a list of OAuth scopes recommended to use when authenticating to Google Cloud services.

Besides the actual cloud-platform scope also includes userinfo.email scope, so that it is possible to examine the token email.

Note that it is preferable to use the exact same list of scopes in all Cloud API clients. That way when the server runs locally in a development mode, we need to go through the login flow only once. Using different scopes for different clients would require to "login" for each unique set of scopes.

Functions

func Authenticate

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

Authenticate returns a middleware that performs authentication.

All given methods will be tried in order until the first applicable one. Typically there's only one method.

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 'Initialize' or '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 GetFrontendClientID

func GetFrontendClientID(c context.Context) (string, error)

GetFrontendClientID returns an OAuth 2.0 client ID to use from the frontend.

If it is not configured returns an empty string. May return an error if it could not be fetched. Such error should be treated as transient.

This client ID is served via /auth/api/v1/server/client_id endpoint (so that the frontend can grab it), and the auth library permits access tokens with this client as an audience when authenticating requests.

func GetPerRPCCredentials

func GetPerRPCCredentials(ctx context.Context, 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(ctx 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(ctx context.Context, kind RPCAuthorityKind, opts ...RPCOption) (oauth2.TokenSource, error)

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

Supports only AsSelf, AsCredentialsForwarder and AsActor authority kinds, since they are the only ones that exclusively use only Authorization header.

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

func HasPermission

func HasPermission(c context.Context, perm realms.Permission, realm string) (bool, error)

HasPermission returns true if the current caller has the given permission in the realm.

A non-existing realm is replaced with the corresponding root realm (e.g. if "projectA:some/realm" doesn't exist, "projectA:@root" will be used in its place). If the project doesn't exist or is not using realms yet, all its realms (including the root realm) are considered empty. HasPermission returns false in this case.

Returns an error only if the check itself failed due to a misconfiguration or transient issues. This should usually result in an Internal error.

func Initialize

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

Initialize inserts authentication configuration into the context.

An initialized context is required by any other function in the package. They return ErrNotConfigured otherwise.

Calling Initialize twice causes a panic.

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 IsInWhitelist

func IsInWhitelist(c context.Context, whitelist string) (bool, error)

IsInWhitelist returns true if the current caller is in the given IP whitelist.

Unknown whitelists are considered empty (the function returns false).

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

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

May 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 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 ShouldEnforceRealmACL

func ShouldEnforceRealmACL(c context.Context, realm string) (bool, error)

ShouldEnforceRealmACL is true if the service should enforce the realm's ACLs.

Based on `enforce_in_service` realm data. Exists temporarily during the realms migration.

TODO(crbug.com/1051724): Remove when no longer used.

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 tokens for the service account belonging to the server itself.

type ActorTokensProvider

type ActorTokensProvider interface {
	// GenerateAccessToken generates an access token for the given account.
	GenerateAccessToken(c context.Context, serviceAccount string, scopes []string) (*oauth2.Token, error)
	// GenerateIDToken generates an ID token for the given account.
	GenerateIDToken(c context.Context, serviceAccount, audience string) (string, error)
}

ActorTokensProvider knows how to produce OAuth and ID tokens for service accounts the server "act as".

Errors returned by its method may be tagged with transient.Tag to indicate they are transient. All other errors are assumed to be fatal.

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(ctx context.Context, r *http.Request) (_ context.Context, err 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 CurrentIdentity() returns AnonymousIdentity.

The returned error may be tagged with an grpcutil error tag. Its code should be used to derive the response status code. Internal error messages (e.g. ones tagged with grpcutil.InternalTag or similar) should be logged, but not sent to clients. All other errors should be sent to clients as is.

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(ctx 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(ctx 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 tokens for the
	// service account belonging to the server itself.
	AccessTokenProvider AccessTokenProvider

	// IDTokenProvider knows how to generate ID tokens for the service account
	// belonging to the server itself.
	//
	// Optional. If not set the server will fall back to using the generateIdToken
	// IAM RPC targeting its own account. This fallback requires the service
	// account to have iam.serviceAccountTokenCreator role on *itself*, which is
	// a bit weird and not default.
	IDTokenProvider IDTokenProvider

	// ActorTokensProvider knows how to produce OAuth and ID tokens for service
	// accounts the server "act as".
	//
	// If nil, a default generic implementation based on HTTP POST request to
	// Cloud IAM Credentials service will be used.
	ActorTokensProvider ActorTokensProvider

	// 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

	// EndUserIP takes a request and returns IP address of a user that sent it.
	//
	// If nil, a default implementation is used. It simply returns r.RemoteAddr.
	//
	// A custom implementation may parse X-Forwarded-For header (or other headers)
	// depending on how load balancers and proxies in front the server populate
	// them.
	EndUserIP func(r *http.Request) string

	// FrontendClientID returns an OAuth 2.0 client ID to use from the frontend.
	//
	// It will be served via /auth/api/v1/server/client_id endpoint (so that the
	// frontend can grab it), and the auth library will permit access tokens with
	// this client as an audience when authenticating requests.
	//
	// May return an empty string if the client ID is not configured. All errors
	// are treated as transient.
	//
	// Should be fast. Will be called each time a token needs to be authenticated.
	FrontendClientID func(context.Context) (string, error)

	// 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 via Google's OAuth2 token info endpoint.

Note that it uses the endpoint which "has no SLA and is not intended for production use". The closest alternative is /userinfo endpoint, but it doesn't return the token expiration time (so we can't cache the result of the check) nor the list of OAuth scopes the token has, nor the client ID to check against a whitelist.

The general Google's recommendation is to use access tokens only for accessing Google APIs and use OpenID Connect Identity tokens for authentication in your own services instead (they are locally verifiable JWTs).

Unfortunately, using OpenID tokens for LUCI services and OAuth2 access token for Google services significantly complicates clients, especially in non-trivial cases (like authenticating from a Swarming job): they now must support two token kinds and know which one to use when.

There's no solution currently that preserves all of correctness, performance, usability and availability:

  • Using /tokeninfo (like is done currently) sacrifices availability.
  • Using /userinfo sacrifices correctness (no client ID or scopes check).
  • Using OpenID ID tokens scarifies usability for the clients.

func (*GoogleOAuth2Method) Authenticate

func (m *GoogleOAuth2Method) Authenticate(ctx context.Context, r *http.Request) (*User, Session, error)

Authenticate implements Method.

func (*GoogleOAuth2Method) GetUserCredentials

func (m *GoogleOAuth2Method) GetUserCredentials(c context.Context, r *http.Request) (*oauth2.Token, error)

GetUserCredentials implements UserCredentialsGetter.

type HasHandlers

type HasHandlers interface {
	// InstallHandlers installs necessary HTTP handlers into the router.
	InstallHandlers(r *router.Router, base router.MiddlewareChain)
}

HasHandlers may be additionally implemented by Method if it needs to install HTTP handlers.

type HasPermissionDryRun

type HasPermissionDryRun struct {
	ExpectedResult bool   // the expected result of this dry run
	TrackingBug    string // identifier of a particular migration, for logs
	AdminGroup     string // if given, implicitly grant all permissions to its members
}

HasPermissionDryRun compares result of HasPermission to 'expected'.

Intended to be used during the migration between the old and new ACL models.

func (HasPermissionDryRun) Execute

func (dr HasPermissionDryRun) Execute(c context.Context, perm realms.Permission, realm string)

Execute calls HasPermission and compares the result to the expectations.

Logs information about the call and any errors or discrepancies found.

Accepts same arguments as HasPermission. Intentionally returns nothing.

type IDTokenProvider

type IDTokenProvider func(c context.Context, audience string) (*oauth2.Token, error)

IDTokenProvider knows how to generate ID tokens for the service account belonging to the server itself.

type Method

type Method interface {
	// Authenticate extracts user information from the incoming request.
	//
	// It returns:
	//   * (*User, Session or nil, nil) on success.
	//   * (nil, nil, nil) if the method is not applicable.
	//   * (nil, nil, error) if the method is applicable, but credentials are bad.
	//
	// The returned error may be tagged with an grpcutil error tag. Its code will
	// be used to derive the response status code. Internal error messages (e.g.
	// ones tagged with grpcutil.InternalTag or similar) are logged, but not sent
	// to clients. All other errors are sent to clients as is.
	Authenticate(context.Context, *http.Request) (*User, Session, error)
}

Method implements a particular low-level authentication mechanism.

It may also optionally implement a bunch of other interfaces:

UsersAPI: if the method supports login and logout URLs.
Warmable: if the method supports warm up.
HasHandlers: if the method needs to install HTTP handlers.

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 MintIDTokenParams

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

	// Audience is a target audience of the token.
	Audience 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
}

MintIDTokenParams is passed to MintIDTokenForServiceAccount.

type ProjectTokenParams

type ProjectTokenParams struct {
	// LuciProject is the name of the LUCI project for which a token will be obtained.
	LuciProject string

	// OAuthScopes resemble the requested OAuth scopes for which the token is valid.
	OAuthScopes []string

	// MinTTL defines a minimally acceptable token lifetime.
	//
	// The returned token will be valid for at least MinTTL, but no longer than
	// MaxScopedTokenTTL (which is 15min).
	//
	// Default is 2 min.
	MinTTL time.Duration
	// contains filtered or unexported fields
}

ProjectTokenParams defines the parameters to create project scoped service account OAuth2 tokens.

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
	// either an OAuth2 access token or an ID token, depending on a presence of
	// WithIDTokenAudience option.
	//
	// If WithIDTokenAudience is not given, RPCs will be authenticated with
	// an OAuth2 access token of the service's own service account. The set of
	// OAuth scopes can be customized via WithScopes option, and by default it
	// is ["https://www.googleapis.com/auth/userinfo.email"].
	//
	// If WithIDTokenAudience is given, RPCs will be authenticated with an ID
	// token that has `aud` claim set to the supplied value. WithScopes can't be
	// used in this case, providing it will cause an error.
	//
	// In LUCI services AsSelf should be used very sparingly, only for internal
	// "maintenance" RPCs that happen outside of the context of any LUCI project.
	// Using AsSelf to authorize RPCs that touch project data leads to "confused
	// deputy" problems. Prefer to use AsProject when possible.
	AsSelf

	// AsUser is used for outbound RPCs that inherit the authority of a user
	// that initiated the request that is currently being handled, regardless of
	// how exactly the user was authenticated.
	//
	// DEPRECATED.
	//
	// The implementation is based on LUCI-specific protocol that uses special
	// delegation tokens. Only LUCI backends can understand them.
	//
	// If you need to call non-LUCI services, and incoming requests are
	// authenticated via OAuth access tokens, use AsCredentialsForwarder instead.
	//
	// 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)).
	AsUser

	// AsSessionUser is used for outbound RPCs that inherit the authority of
	// an end-user by using credentials stored in the current auth session.
	//
	// Works only if the method used to authenticate the incoming request supports
	// this mechanism. Currently this is only go.chromium.org/luci/server/encryptedcookies.
	//
	// Unlike deprecated AsUser, which uses LUCI delegation tokens, AsSessionUser
	// authenticates outbound RPCs using standard OAuth2 or ID tokens, making this
	// mechanism more widely applicable.
	//
	// On a flip side, the implementation relies on OpenID Connect refresh tokens,
	// which limits it only to real human accounts that can click buttons in the
	// browser to go through the OpenID Connect sign in flow to get a refresh
	// token and establish a session (i.e. service accounts are not supported).
	// Thus this mechanism is primarily useful when implementing Web UIs that use
	// session cookies for authentication and want to call other services on
	// user's behalf from the backend side.
	//
	// By default RPCs performed with AsSessionUser use email-scoped OAuth2 access
	// tokens with the client ID matching the current service OAuth2 client ID.
	// There's no way to ask for more scopes (using WithScopes option would result
	// in an error).
	//
	// If WithIDToken option is specified, RPCs use ID tokens with the audience
	// matching the current service OAuth2 client ID. There's no way to customize
	// the audience.
	AsSessionUser

	// AsCredentialsForwarder is used for outbound RPCs that just forward the
	// user credentials, exactly as they were received by the service.
	//
	// For authenticated calls, works only if the current request was
	// authenticated via a forwardable token, e.g. an OAuth2 access token.
	//
	// If the current request was initiated by an anonymous caller, the RPC will
	// have no auth headers (just like in NoAuth mode).
	//
	// An attempt to use GetRPCTransport(ctx, AsCredentialsForwarder) with
	// unsupported credentials results in an error.
	AsCredentialsForwarder

	// AsActor is used for outbound RPCs sent with the authority of some service
	// account that the current service has "iam.serviceAccountTokenCreator" role
	// in.
	//
	// RPC requests done in this mode will have 'Authorization' header set to
	// either an OAuth2 access token or an ID token of the service account
	// specified by WithServiceAccount option.
	//
	// What kind of token is used depends on a presence of WithIDTokenAudience
	// option and it follows the rules described in AsSelf comment.
	//
	// TODO(crbug.com/1081932): Implement WithIDTokenAudience mode.
	AsActor

	// AsProject is used for outbounds RPCs sent with the authority of some LUCI
	// project (specified via WithProject option).
	//
	// When used to call external services (anything that is not a part of the
	// current LUCI deployment), uses 'Authorization' header with either an OAuth2
	// access token or an ID token of the project-specific service account
	// (specified in the LUCI project definition in 'projects.cfg' deployment
	// configuration file).
	//
	// What kind of token is used in this case depends on a presence of
	// WithIDTokenAudience option and it follows the rules described in AsSelf
	// comment.
	//
	// When used to call LUCI services belonging the same LUCI deployment (per
	// 'internal_service_regexp' setting in 'security.cfg' deployment
	// configuration file) uses the current service's OAuth2 access token plus
	// 'X-Luci-Project' header with the project name. Such calls are authenticated
	// by the peer as coming from 'project:<name>' identity. Options WithScopes
	// and WithIDTokenAudience are ignored in this case.
	//
	// TODO(crbug.com/1081932): Implement WithIDTokenAudience mode.
	AsProject
)

type RPCOption

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

RPCOption is an option for GetRPCTransport, GetPerRPCCredentials and GetTokenSource functions.

func WithDelegationTags

func WithDelegationTags(tags ...string) RPCOption

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

DEPRECATED.

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.

DEPRECATED.

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 WithIDToken

func WithIDToken() RPCOption

WithIDToken indicates to use ID tokens instead of OAuth2 tokens.

If no audience is given via WithIDTokenAudience, uses "https://${host}" by default.

func WithIDTokenAudience

func WithIDTokenAudience(aud string) RPCOption

WithIDTokenAudience indicates to use ID tokens with a specific audience instead of OAuth2 tokens.

Implies WithIDToken.

The token's `aud` claim will be set to the given value. It can be customized per-request by using `${host}` which will be substituted with a host name of the request URI.

Usage example:

tr, err := auth.GetRPCTransport(ctx,
  auth.AsSelf,
  auth.WithIDTokenAudience("https://${host}"),
)
if err != nil {
  return err
}
client := &http.Client{Transport: tr}
...

Not compatible with WithScopes.

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 to GetPerRPCCredentials() or GetTokenSource(). It applies only to GetRPCTransport().

func WithProject

func WithProject(project string) RPCOption

WithProject can be used to generate an OAuth token with an identity of that particular LUCI project.

See AsProject for more info.

func WithScopes

func WithScopes(scopes ...string) RPCOption

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

Not compatible with WithIDTokenAudience.

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 interface {
	// AccessToken returns an OAuth access token identifying the session user.
	AccessToken(ctx context.Context) (*oauth2.Token, error)
	// IDToken returns an ID token identifying the session user.
	IDToken(ctx context.Context) (*oauth2.Token, error)
}

Session holds some extra information pertaining to the request.

It is stored in the context as part of State. Used by AsSessionUser RPC authority kind.

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 an authentication method used for the current request or nil
	// if the 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
	// the delegation is used.
	//
	// This field is never nil. For anonymous call it contains User with identity
	// AnonymousIdentity.
	//
	// Do not modify it.
	User() *User

	// Session is the session object produced by the authentication method.
	//
	// It may hold some extra information pertaining to the request. It may be nil
	// if there's no extra information. The session can be used to transfer
	// information from the authentication method to other parts of the auth
	// stack that execute later.
	Session() Session

	// 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

	// UserCredentials is an end-user credentials as they were received if they
	// are allowed to be forwarded.
	//
	// Includes the primary OAuth token and any extra LUCI-specific headers.
	UserCredentials() (*oauth2.Token, map[string]string, error)
}

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 by 'Authenticate' call, the background state if 'Authenticate' wasn't used or nil if the auth library wasn't configured.

The background state roughly is similar to the state of anonymous call. Various background non user-facing handlers (crons, task queues) that do not use 'Authenticate' see this state by default. Its most important role is to provide access to authdb.DB (and all functionality that depends on it) to background handlers.

type Token

type Token struct {
	Token  string    // an opaque base64-encoded token
	Expiry time.Time // when it expires
}

Token is some opaque token and its expiration time.

Returned by various MintXToken calls.

func MintAccessTokenForServiceAccount

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

MintAccessTokenForServiceAccount produces an access token for some service account that the current service has "iam.serviceAccountTokenCreator" 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) (_ *Token, err 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.

DEPRECATED.

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 MintIDTokenForServiceAccount

func MintIDTokenForServiceAccount(ctx context.Context, params MintIDTokenParams) (_ *Token, err error)

MintIDTokenForServiceAccount produces an ID token for some service account that the current service has "iam.serviceAccountTokenCreator" 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 MintProjectToken

func MintProjectToken(ctx context.Context, p ProjectTokenParams) (_ *Token, err error)

MintProjectToken returns a LUCI project-scoped OAuth2 token that can be used to access external resources on behalf of the project.

It protects against accidental cross-project resource access. A token is targeted to some single specific LUCI project. The token is cached internally. Same token may be returned by multiple calls, if its lifetime allows.

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 UserCredentialsGetter

type UserCredentialsGetter interface {
	// GetUserCredentials extracts an OAuth access token from the incoming request
	// or returns an error if it isn't possible.
	//
	// May omit token's expiration time if it isn't known.
	//
	// Guaranteed to be called only after the successful authentication, so it
	// doesn't have to recheck the validity of the token.
	GetUserCredentials(context.Context, *http.Request) (*oauth2.Token, error)
}

UserCredentialsGetter may be additionally implemented by Method if it knows how to extract end-user credentials from the incoming request. Currently understands only OAuth2 tokens.

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(ctx 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(ctx context.Context, dest string) (string, error)
}

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

type Warmable

type Warmable interface {
	// Warmup may be called to precache the data needed by the method.
	//
	// There's no guarantee when it will be called or if it will be called at all.
	// Should always do best-effort initialization. Errors are logged and ignored.
	Warmup(ctx context.Context) error
}

Warmable may be additionally implemented by Method if it supports warm up.

Directories

Path Synopsis
Package authdb contains definition of Authentication Database (aka AuthDB).
Package authdb contains definition of Authentication Database (aka AuthDB).
dump
Package dump implements loading AuthDB from dumps in Google Storage.
Package dump implements loading AuthDB from dumps in Google Storage.
internal/certs
Package certs knows how to fetch certificate bundles of trusted services.
Package certs knows how to fetch certificate bundles of trusted services.
internal/globset
Package globset preprocesses []identity.Glob for faster querying.
Package globset preprocesses []identity.Glob for faster querying.
internal/graph
Package graph implements handling of the groups graph.
Package graph implements handling of the groups graph.
internal/ipaddr
Package ipaddr implements IP whitelist check.
Package ipaddr implements IP whitelist check.
internal/legacy
Package legacy contains older implementation of IsMember check.
Package legacy contains older implementation of IsMember check.
internal/oauthid
Package oauthid implements OAuth client ID whitelist check.
Package oauthid implements OAuth client ID whitelist check.
internal/realmset
Package realmset provides queryable representation of LUCI Realms DB.
Package realmset provides queryable representation of LUCI Realms DB.
internal/seccfg
Package seccfg interprets SecurityConfig proto message.
Package seccfg interprets SecurityConfig proto message.
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 deprecated contains code that should not be used in new applications.
Package deprecated contains code that should not be used in new applications.
Package iap implements auth.Method for GCP's Identity Aware Proxy.
Package iap implements auth.Method for GCP's Identity Aware Proxy.
Package openid contains functionality related to OpenID Connect protocol.
Package openid contains functionality related to OpenID Connect protocol.
Package realms contains functionality related to LUCI Realms.
Package realms contains functionality related to LUCI Realms.
Package service implements a wrapper around API exposed by auth_service: https://github.com/luci/luci-py/tree/master/appengine/auth_service The main focus is AuthDB replication protocol used to propagate changes to database of groups.
Package service implements a wrapper around API exposed by auth_service: https://github.com/luci/luci-py/tree/master/appengine/auth_service The main focus is AuthDB replication protocol used to propagate changes to database of groups.
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