Documentation
¶
Overview ¶
Package token issues and verifies Access tokens (decision 0005): RS256 JWTs signed with a per-instance key, reference tokens and refresh tokens. Only digests of tokens are stored; the store record (token_id, subject, scope, expiry) is what revocation removes.
Index ¶
- Constants
- Variables
- type Issued
- type Options
- type RefreshCheck
- type RegistryRequest
- type Request
- type Service
- func (s *Service) EncryptedPassword(ctx context.Context, username string) (string, error)
- func (s *Service) Issue(ctx context.Context, r Request) (Issued, error)
- func (s *Service) IssueRegistry(_ context.Context, r RegistryRequest) (Issued, error)
- func (s *Service) Issuer() string
- func (s *Service) Refresh(ctx context.Context, refreshToken string) (Issued, error)
- func (s *Service) RefreshAs(ctx context.Context, refreshToken string, c RefreshCheck) (Issued, error)
- func (s *Service) Revoke(ctx context.Context, id string) error
- func (s *Service) RevokeValue(ctx context.Context, raw string) error
- func (s *Service) Rotate(ctx context.Context) error
- func (s *Service) Verify(ctx context.Context, raw string) (types.Token, error)
- func (s *Service) VerifyExpired(ctx context.Context, raw string) (types.Token, error)
Constants ¶
const (
// DefaultAudience is the audience Access gives a token issued without one.
DefaultAudience = "*@*"
)
const (
// DefaultKeyBits is the RSA key size.
DefaultKeyBits = 2048
)
Variables ¶
var ( // ErrInvalidRequest reports an issue request the service refuses. ErrInvalidRequest = errors.New("invalid token request") // ErrNeverExpiresAdminOnly refuses a token that never expires to a // caller who is not an administrator. It wraps ErrInvalidRequest, which // the OIDC exchange answers 400; the token API tests for it first and // answers 403, as createtoken documents a refused expires_in. ErrNeverExpiresAdminOnly = fmt.Errorf( "%w: only an administrator may issue a token that never expires", ErrInvalidRequest, ) // ErrNotRevocable refuses to revoke a token shorter than the revocable // threshold that was neither forced revocable nor refreshable. ErrNotRevocable = errors.New("token is not revocable") // ErrRefreshOtherUser refuses a refresh token of another user than the // one refreshing: "The authenticated user must match the user of the // access token being refreshed" (createtoken.json, which answers 403). ErrRefreshOtherUser = errors.New("the refresh token belongs to another user") )
Functions ¶
This section is empty.
Types ¶
type Issued ¶
type Issued struct {
Record types.Token
AccessToken string
RefreshToken string
ReferenceToken string
// ExpiresIn is the lifetime in seconds; zero means never.
ExpiresIn int64
}
Issued is a new token and its secrets, which are never stored and so cannot be shown again.
type Options ¶
type Options struct {
// Now supplies the time; nil means time.Now.
Now func() time.Time
// KeyBits is the RSA key size; zero means DefaultKeyBits. Only tests set
// it, to keep key generation cheap.
KeyBits int
}
Options configures New. Zero values mean the defaults.
type RefreshCheck ¶
type RefreshCheck struct {
// Username, when set, must be the refreshed token's user, or the refresh
// fails with ErrRefreshOtherUser.
Username string
// TokenID, when set, must be the refreshed token's id, or the refresh
// fails as an invalid refresh token: the caller presented that token as
// its credential, and it must not vouch for refreshing another.
TokenID string
}
RefreshCheck is what a refresh must match beyond a valid refresh token.
type RegistryRequest ¶
type RegistryRequest struct {
Username string
// ExpiresIn is the lifetime; it must be positive, and at most
// types.RegistryTokenExpiry.
ExpiresIn time.Duration
Access types.RegistryAccess
// Scope is the scope of the credential that obtained the token, which
// the token keeps so it never acts more broadly; it defaults to
// applied-permissions/user, a password's.
Scope types.Scope
// Identity is that credential's identity when it came from an OIDC
// exchange, so the token resolves to the same transient or synthetic
// user it does.
Identity types.TokenIdentity
// Parent is the id of the stored token that obtained it, empty for a
// password or anonymous caller. The token is refused once the parent is
// revoked.
Parent string
}
RegistryRequest asks for a registry token (decision 0005).
type Request ¶
type Request struct {
Username string
// Scope defaults to applied-permissions/user.
Scope types.Scope
// ExpiresIn defaults to token.default_expiry (types.DefaultTokenExpiry
// when unset); zero means never and needs ByAdmin.
ExpiresIn *time.Duration
Refreshable bool
ForceRevocable bool
Audience string
Description string
ProjectKey string
// IncludeReference also issues a reference token.
IncludeReference bool
// ByAdmin is whether the caller is an administrator.
ByAdmin bool
// Purpose marks a token its user holds at most one of
// (types.TokenPurposeEncryptedPassword). Such a token always has a
// reference token, and keeps it sealed so it can be shown again.
Purpose string
// Identity is how the token's subject resolves to a user. An OIDC token
// exchange, and an administrator minting for a name that is no stored
// user, issue a token for a user who need not be stored.
Identity types.TokenIdentity
// NotAfter, when set, is the latest the token may expire; a longer or
// unending lifetime is cut to it. A transient user's token for itself
// sets it to the expiry of the token that minted it: the user exists
// only through that token, so a token outliving it would outlast the
// 24 hours an OIDC mapping allows.
NotAfter time.Time
}
Request asks for a token for a user.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service issues and verifies tokens over a store.
func New ¶
New returns a Service. The instance identity must exist: the issuer is jfac@<the instance's id>. The first signing key is created when there is none.
func (*Service) EncryptedPassword ¶
EncryptedPassword returns the user's encrypted password: the reference token of their types.TokenPurposeEncryptedPassword token, which never expires. A user holds at most one, created on first use and shown again after, so every client given it keeps working until the password changes and the identity service revokes it.
func (*Service) IssueRegistry ¶
IssueRegistry signs a registry token: an access token with the user's applied permissions whose registry claim carries what it grants. Nothing stores it, as Artifactory stores no token below its persistence threshold, so it cannot be listed or revoked; its short life, the grants and the user's current permissions bound it instead (Verify).
func (*Service) Refresh ¶
Refresh exchanges a refresh token for a new token with the same subject, scope, lifetime and options, and revokes the old one. A refresh token stays usable for types.DefaultRefreshGrace after its token expires.
func (*Service) RefreshAs ¶
func (s *Service) RefreshAs( ctx context.Context, refreshToken string, c RefreshCheck, ) (Issued, error)
RefreshAs is Refresh for a refresh token that must pass c. The user is checked before the token, so another user's refresh token is ErrRefreshOtherUser whichever token the caller presented.
func (*Service) RevokeValue ¶
RevokeValue revokes the token whose access or reference token is raw.
func (*Service) Rotate ¶
Rotate makes a new signing key active. The keys it replaces keep verifying until the latest expiry of the tokens stored now, or for ever when one of them never expires, so no token issued before the rotation is refused early.
func (*Service) Verify ¶
Verify resolves an access token (a JWT) or a reference token to its record. A token that is malformed, badly signed, signed by an unknown or retired key, expired, or revoked (no record) fails with an error wrapping auth.ErrInvalidToken.
func (*Service) VerifyExpired ¶
VerifyExpired resolves an access token (a JWT) as Verify does, but accepts one whose only fault is its expiry. Signature, key, revocation and subject are all still checked; a reference token always fails. It serves only the refresh grant, which the JFrog CLI sends with the access token it is replacing, by then often expired. The record outlives its expiry for types.DefaultRefreshGrace (the gc keeps it), which bounds how long after expiry this succeeds.