auth

package
v2.5.0 Latest Latest
Warning

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

Go to latest
Published: Mar 21, 2024 License: Apache-2.0 Imports: 17 Imported by: 74

Documentation

Overview

Package auth provides authentication for a client to a remote registry.

Index

Examples

Constants

View Source
const (
	// ActionPull represents generic read access for resources of the repository
	// type.
	ActionPull = "pull"

	// ActionPush represents generic write access for resources of the
	// repository type.
	ActionPush = "push"

	// ActionDelete represents the delete permission for resources of the
	// repository type.
	ActionDelete = "delete"
)

Actions used in scopes. Reference: https://docs.docker.com/registry/spec/auth/scope/

View Source
const ScopeRegistryCatalog = "registry:catalog:*"

ScopeRegistryCatalog is the scope for registry catalog access.

Variables

View Source
var DefaultClient = &Client{
	Client: retry.DefaultClient,
	Header: http.Header{
		"User-Agent": {"oras-go"},
	},
	Cache: DefaultCache,
}

DefaultClient is the default auth-decorated client.

View Source
var ErrBasicCredentialNotFound = errors.New("basic credential not found")

ErrBasicCredentialNotFound is returned when the credential is not found for basic auth.

Functions

func AppendRepositoryScope added in v2.4.0

func AppendRepositoryScope(ctx context.Context, ref registry.Reference, actions ...string) context.Context

AppendRepositoryScope returns a new context containing scope hints for the auth client to fetch bearer tokens with the given actions on the repository. If called multiple times, the new scopes will be appended to the existing scopes. The resulted scopes are de-duplicated.

For example, uploading blob to the repository "hello-world" does HEAD request first then POST and PUT. The HEAD request will return a challenge for scope `repository:hello-world:pull`, and the auth client will fetch a token for that challenge. Later, the POST request will return a challenge for scope `repository:hello-world:push`, and the auth client will fetch a token for that challenge again. By invoking AppendRepositoryScope with the actions ActionPull and ActionPush for the repository `hello-world`, the auth client with cache is hinted to fetch a token via a single token fetch request for all the HEAD, POST, PUT requests.

func AppendScopes

func AppendScopes(ctx context.Context, scopes ...string) context.Context

AppendScopes appends additional scopes to the existing scopes in the context and returns a new context. The resulted scopes are de-duplicated. The append operation does modify the existing scope in the context passed in.

func AppendScopesForHost added in v2.4.0

func AppendScopesForHost(ctx context.Context, host string, scopes ...string) context.Context

AppendScopesForHost appends additional scopes to the existing scopes in the context for the given host and returns a new context. The resulted scopes are de-duplicated. The append operation does modify the existing scope in the context passed in.

func CleanScopes

func CleanScopes(scopes []string) []string

CleanScopes merges and sort the actions in ascending order if the scopes have the same resource type and name. The final scopes are sorted in ascending order. In other words, the scopes passed in are de-duplicated and sorted. Therefore, the output of this function is deterministic.

If there is a wildcard `*` in the action, other actions in the same resource type and name are ignored.

func GetAllScopesForHost added in v2.4.0

func GetAllScopesForHost(ctx context.Context, host string) []string

GetAllScopesForHost returns the scopes in the context for the given host, including global scopes added by WithScopes and AppendScopes.

func GetScopes

func GetScopes(ctx context.Context) []string

GetScopes returns the scopes in the context.

func GetScopesForHost added in v2.4.0

func GetScopesForHost(ctx context.Context, host string) []string

GetScopesForHost returns the scopes in the context for the given host, excluding global scopes added by WithScopes and AppendScopes.

func ScopeRepository

func ScopeRepository(repository string, actions ...string) string

ScopeRepository returns a repository scope with given actions. Reference: https://docs.docker.com/registry/spec/auth/scope/

func WithScopes

func WithScopes(ctx context.Context, scopes ...string) context.Context

WithScopes returns a context with scopes added. Scopes are de-duplicated. Scopes are used as hints for the auth client to fetch bearer tokens with larger scopes.

For example, uploading blob to the repository "hello-world" does HEAD request first then POST and PUT. The HEAD request will return a challenge for scope `repository:hello-world:pull`, and the auth client will fetch a token for that challenge. Later, the POST request will return a challenge for scope `repository:hello-world:push`, and the auth client will fetch a token for that challenge again. By invoking WithScopes with the scope `repository:hello-world:pull,push`, the auth client with cache is hinted to fetch a token via a single token fetch request for all the HEAD, POST, PUT requests.

Passing an empty list of scopes will virtually remove the scope hints in the context.

Reference: https://docs.docker.com/registry/spec/auth/scope/

func WithScopesForHost added in v2.4.0

func WithScopesForHost(ctx context.Context, host string, scopes ...string) context.Context

WithScopesForHost returns a context with per-host scopes added. Scopes are de-duplicated. Scopes are used as hints for the auth client to fetch bearer tokens with larger scopes.

For example, uploading blob to the repository "hello-world" does HEAD request first then POST and PUT. The HEAD request will return a challenge for scope `repository:hello-world:pull`, and the auth client will fetch a token for that challenge. Later, the POST request will return a challenge for scope `repository:hello-world:push`, and the auth client will fetch a token for that challenge again. By invoking WithScopesForHost with the scope `repository:hello-world:pull,push`, the auth client with cache is hinted to fetch a token via a single token fetch request for all the HEAD, POST, PUT requests.

Passing an empty list of scopes will virtually remove the scope hints in the context for the given host.

Reference: https://docs.docker.com/registry/spec/auth/scope/

Types

type Cache

type Cache interface {
	// GetScheme returns the auth-scheme part cached for the given registry.
	// A single registry is assumed to have a consistent scheme.
	// If a registry has different schemes per path, the auth client is still
	// workable. However, the cache may not be effective as the cache cannot
	// correctly guess the scheme.
	GetScheme(ctx context.Context, registry string) (Scheme, error)

	// GetToken returns the auth-token part cached for the given registry of a
	// given scheme.
	// The underlying implementation MAY cache the token for all schemes for the
	// given registry.
	GetToken(ctx context.Context, registry string, scheme Scheme, key string) (string, error)

	// Set fetches the token using the given fetch function and caches the token
	// for the given scheme with the given key for the given registry.
	// The return values of the fetch function is returned by this function.
	// The underlying implementation MAY combine the fetch operation if the Set
	// function is invoked multiple times at the same time.
	Set(ctx context.Context, registry string, scheme Scheme, key string, fetch func(context.Context) (string, error)) (string, error)
}

Cache caches the auth-scheme and auth-token for the "Authorization" header in accessing the remote registry. Precisely, the header is `Authorization: auth-scheme auth-token`. The `auth-token` is a generic term as `token68` in RFC 7235 section 2.1.

var DefaultCache Cache = NewCache()

DefaultCache is the sharable cache used by DefaultClient.

func NewCache

func NewCache() Cache

NewCache creates a new go-routine safe cache instance.

func NewSingleContextCache added in v2.4.0

func NewSingleContextCache() Cache

NewSingleContextCache creates a host-based cache for optimizing the auth flow for non-compliant registries. It is intended to be used in a single context, such as pulling from a single repository. This cache should not be shared.

Note: NewCache should be used for compliant registries as it can be shared across context and will generally make less re-authentication requests.

type Client

type Client struct {
	// Client is the underlying HTTP client used to access the remote
	// server.
	// If nil, http.DefaultClient is used.
	// It is possible to use the default retry client from the package
	// `oras.land/oras-go/v2/registry/remote/retry`. That client is already available
	// in the DefaultClient.
	// It is also possible to use a custom client. For example, github.com/hashicorp/go-retryablehttp
	// is a popular HTTP client that supports retries.
	Client *http.Client

	// Header contains the custom headers to be added to each request.
	Header http.Header

	// Credential specifies the function for resolving the credential for the
	// given registry (i.e. host:port).
	// EmptyCredential is a valid return value and should not be considered as
	// an error.
	// If nil, the credential is always resolved to EmptyCredential.
	Credential CredentialFunc

	// Cache caches credentials for direct accessing the remote registry.
	// If nil, no cache is used.
	Cache Cache

	// ClientID used in fetching OAuth2 token as a required field.
	// If empty, a default client ID is used.
	// Reference: https://docs.docker.com/registry/spec/auth/oauth/#getting-a-token
	ClientID string

	// ForceAttemptOAuth2 controls whether to follow OAuth2 with password grant
	// instead the distribution spec when authenticating using username and
	// password.
	// References:
	// - https://docs.docker.com/registry/spec/auth/jwt/
	// - https://docs.docker.com/registry/spec/auth/oauth/
	ForceAttemptOAuth2 bool
}

Client is an auth-decorated HTTP client. Its zero value is a usable client that uses http.DefaultClient with no cache.

func (*Client) Do

func (c *Client) Do(originalReq *http.Request) (*http.Response, error)

Do sends the request to the remote server, attempting to resolve authentication if 'Authorization' header is not set.

On authentication failure due to bad credential,

  • Do returns error if it fails to fetch token for bearer auth.
  • Do returns the registry response without error for basic auth.
Example (BasicAuth)

ExampleClient_Do_basicAuth gives an example of using client with credentials.

client := &auth.Client{
	// expectedHostAddress is of form ipaddr:port
	Credential: auth.StaticCredential(expectedHostAddress, auth.Credential{
		Username: username,
		Password: password,
	}),
}
// basicAuthTargetURL can be any URL. For example, https://registry.wabbit-networks.io/v2/
req, err := http.NewRequest(http.MethodGet, basicAuthTargetURL, nil)
if err != nil {
	panic(err)
}
resp, err := client.Do(req)
if err != nil {
	panic(err)
}

fmt.Println(resp.StatusCode)
Output:

200
Example (ClientConfigurations)

ExampleClient_Do_clientConfigurations shows the client configurations available, including using cache, setting user agent and configuring OAuth2.

client := &auth.Client{
	// expectedHostAddress is of form ipaddr:port
	Credential: auth.StaticCredential(expectedHostAddress, auth.Credential{
		Username: username,
		Password: password,
	}),
	// ForceAttemptOAuth2 controls whether to follow OAuth2 with password grant.
	ForceAttemptOAuth2: true,
	// Cache caches credentials for accessing the remote registry.
	Cache: auth.NewCache(),
}
// SetUserAgent sets the user agent for all out-going requests.
client.SetUserAgent("example user agent")
// Tokens carry restrictions about what resources they can access and how.
// Such restrictions are represented and enforced as Scopes.
// Reference: https://docs.docker.com/registry/spec/auth/scope/
scopes := []string{
	"repository:dst:pull,push",
	"repository:src:pull",
}
// WithScopes returns a context with scopes added.
ctx := auth.WithScopes(context.Background(), scopes...)

// clientConfigTargetURL can be any URL. For example, https://registry.wabbit-networks.io/v2/
req, err := http.NewRequestWithContext(ctx, http.MethodGet, clientConfigTargetURL, nil)
if err != nil {
	panic(err)
}
resp, err := client.Do(req)
if err != nil {
	panic(err)
}

fmt.Println(resp.StatusCode)
Output:

200
Example (MinimalClient)

ExampleClient_Do_minimalClient gives an example of a minimal working client.

var client auth.Client
// targetURL can be any URL. For example, https://registry.wabbit-networks.io/v2/
req, err := http.NewRequest(http.MethodGet, targetURL, nil)
if err != nil {
	panic(err)
}
resp, err := client.Do(req)
if err != nil {
	panic(err)
}

fmt.Println(resp.StatusCode)
Output:

200
Example (WithAccessToken)

ExampleClient_Do_withAccessToken gives an example of using client with an access token.

client := &auth.Client{
	// expectedHostAddress is of form ipaddr:port
	Credential: auth.StaticCredential(expectedHostAddress, auth.Credential{
		AccessToken: accessToken,
	}),
}
// accessTokenTargetURL can be any URL. For example, https://registry.wabbit-networks.io/v2/
req, err := http.NewRequest(http.MethodGet, accessTokenTargetURL, nil)
if err != nil {
	panic(err)
}
resp, err := client.Do(req)
if err != nil {
	panic(err)
}

fmt.Println(resp.StatusCode)
Output:

200
Example (WithRefreshToken)

ExampleClient_Do_withRefreshToken gives an example of using client with a refresh token.

client := &auth.Client{
	// expectedHostAddress is of form ipaddr:port
	Credential: auth.StaticCredential(expectedHostAddress, auth.Credential{
		RefreshToken: refreshToken,
	}),
}

// refreshTokenTargetURL can be any URL. For example, https://registry.wabbit-networks.io/v2/
req, err := http.NewRequest(http.MethodGet, refreshTokenTargetURL, nil)
if err != nil {
	panic(err)
}
resp, err := client.Do(req)
if err != nil {
	panic(err)
}

fmt.Println(resp.StatusCode)
Output:

200

func (*Client) SetUserAgent

func (c *Client) SetUserAgent(userAgent string)

SetUserAgent sets the user agent for all out-going requests.

type Credential

type Credential struct {
	// Username is the name of the user for the remote registry.
	Username string

	// Password is the secret associated with the username.
	Password string

	// RefreshToken is a bearer token to be sent to the authorization service
	// for fetching access tokens.
	// A refresh token is often referred as an identity token.
	// Reference: https://docs.docker.com/registry/spec/auth/oauth/
	RefreshToken string

	// AccessToken is a bearer token to be sent to the registry.
	// An access token is often referred as a registry token.
	// Reference: https://docs.docker.com/registry/spec/auth/token/
	AccessToken string
}

Credential contains authentication credentials used to access remote registries.

var EmptyCredential Credential

EmptyCredential represents an empty credential.

type CredentialFunc added in v2.4.0

type CredentialFunc func(ctx context.Context, hostport string) (Credential, error)

CredentialFunc represents a function that resolves the credential for the given registry (i.e. host:port).

EmptyCredential is a valid return value and should not be considered as an error.

func StaticCredential

func StaticCredential(registry string, cred Credential) CredentialFunc

StaticCredential specifies static credentials for the given host.

type Scheme

type Scheme byte

Scheme define the authentication method.

const (
	// SchemeUnknown represents unknown or unsupported schemes
	SchemeUnknown Scheme = iota

	// SchemeBasic represents the "Basic" HTTP authentication scheme.
	// Reference: https://tools.ietf.org/html/rfc7617
	SchemeBasic

	// SchemeBearer represents the Bearer token in OAuth 2.0.
	// Reference: https://tools.ietf.org/html/rfc6750
	SchemeBearer
)

func (Scheme) String

func (s Scheme) String() string

String return the string for the scheme.

Jump to

Keyboard shortcuts

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