security

package module
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Nov 6, 2024 License: MIT Imports: 32 Imported by: 8

README

security

Build Status GoDoc Go Report Card codecov License

JWT and HMAC based security primitives for authentication of services and users.

Documentation

Overview

Package security can be used to implement our bearer and hmac security of HTTP requests. Agents can use the HMACAuth to create HMAC secured HTTP requests. The serverside also uses this to pull out the user from the request.

A Dex is used to get a user from a request who is identified by a bearer token. We use a dex backend to load the keys from our service so we can verify the signature of the JWT token. It is up to the client to get a correct bearer token.

Index

Examples

Constants

View Source
const (
	AuthzHeaderKey = "Authorization"
	TsHeaderKey    = "X-Date"
	SaltHeaderKey  = "X-Data-Salt"
)

Our constant header names

Variables

This section is empty.

Functions

func AddUserToken

func AddUserToken(rq *http.Request, token string)

AddUserToken adds the given token as a bearer token to the request.

func AddUserTokenToClientRequest

func AddUserTokenToClientRequest(rq runtime.ClientRequest, token string)

AddUserTokenToClientRequest to support openapi

func CreateToken added in v0.5.0

func CreateToken(signer jose.Signer, cl any, privateClaims ...any) (string, error)

CreateToken creates a jwt token with the given claims

func CreateTokenAndKeys added in v0.5.0

func CreateTokenAndKeys(cfg *TokenCfg) (token string, pubKey jose.JSONWebKey, privKey jose.JSONWebKey, err error)

CreateTokenAndKeys creates a keyset and token

func CreateWebkeyPair added in v0.5.0

func CreateWebkeyPair(alg jose.SignatureAlgorithm, use string, keylenBits int) (jose.JSONWebKey, jose.JSONWebKey, error)

CreateWebkeyPair creates a JSONWebKey-Pair. alg is one of jose signature-algorithm constants, e.g. jose.RS256. use is "sig" for signature or "enc" for encryption, see https://tools.ietf.org/html/rfc7517#page-6 Arbitrary keylenBits are not supported for Elliptic Curve Algs, here the Bits must match the Algorithms.

func ExtractBearer added in v0.5.0

func ExtractBearer(rq *http.Request) (string, error)

ExtractBearer extracts the Bearer Token from the request header

func GenerateSigningKey added in v0.5.0

func GenerateSigningKey(alg jose.SignatureAlgorithm, bits int) (crypto.PublicKey, crypto.PrivateKey, error)

GenerateSigningKey generates a keypair for corresponding SignatureAlgorithm.

func GenerateTokenAndKeyServer added in v0.5.0

func GenerateTokenAndKeyServer(tc *TokenCfg, tokenProvider TokenProvider, opts ...KeyServerOption) (srv *httptest.Server, token string, err error)

GenerateTokenAndKeyServer starts keyserver, patches tokenCfg (issuer), generates token. This method is intended for test purposes, where you need a server that provides '.well-known/openid-configuration' and '/keys' endpoints.

func MustCreateTokenAndKeys added in v0.5.0

func MustCreateTokenAndKeys(cfg *TokenCfg) (token string, pubKey jose.JSONWebKey, privKey jose.JSONWebKey)

MustCreateTokenAndKeys creates a keyset and token, panics on error

func MustMakeSigner added in v0.5.0

func MustMakeSigner(alg jose.SignatureAlgorithm, k any) jose.Signer

MustMakeSigner creates a Signer and panics if an error occurs

func ParseTokenClaimsUnvalidated added in v0.5.0

func ParseTokenClaimsUnvalidated(req *http.Request) (*jwt.Claims, error)

ParseTokenClaimsUnvalidated returns the UNVALIDATED claims from the bearer token in the authentication header.

func PutUserInContext

func PutUserInContext(ctx context.Context, u *User) context.Context

PutUserInContext puts the given user as a value in the context.

Types

type Annotations added in v0.5.0

type Annotations map[string]string

type Claims

type Claims struct {
	jwt.RegisteredClaims
	Audience        any               `json:"aud,omitempty"`
	Groups          []string          `json:"groups"`
	EMail           string            `json:"email"`
	Name            string            `json:"name"`
	FederatedClaims map[string]string `json:"federated_claims"`

	// added for parsing of "new" style tokens
	Roles []string `json:"roles"`
}

Claims we overwrite the Audience because in the current version of the jwt library this is not an array.

type CredsOpt

type CredsOpt func(*UserCreds)

CredsOpt is a option setter for UserCreds

func WithDex

func WithDex(d UserGetter) CredsOpt

WithDex sets the dex auther.

func WithHMAC

func WithHMAC(hma HMACAuth) CredsOpt

WithHMAC appends the given HMACAuth to the list of allowed authers.

type Dex

type Dex struct {
	// contains filtered or unexported fields
}

A Dex ...

func NewDex

func NewDex(baseurl string) (*Dex, error)

NewDex returns a new Dex.

func (*Dex) User

func (dx *Dex) User(rq *http.Request) (*User, error)

User implements the UserGetter to get a user from the request.

func (*Dex) With

func (dx *Dex) With(opts ...Option) *Dex

With sets available Options

type GenericOIDC added in v0.5.0

type GenericOIDC struct {
	// contains filtered or unexported fields
}

GenericOIDC is Token Validator and UserGetter for Tokens issued by generic OIDC-Providers.

func NewGenericOIDC added in v0.5.0

func NewGenericOIDC(ic *IssuerConfig, opts ...GenericOIDCOption) (*GenericOIDC, error)

NewGenericOIDC creates a new GenericOIDC.

func (*GenericOIDC) User added in v0.5.0

func (o *GenericOIDC) User(rq *http.Request) (*User, error)

User implements the UserGetter to get a user from the request.

type GenericOIDCCfg added in v0.5.0

type GenericOIDCCfg struct {
	SupportedSigningAlgs []string
	Timeout              time.Duration
	UserExtractorFn      GenericUserExtractorFn
}

GenericOIDCCfg properties that can be modified by Options

type GenericOIDCClaims added in v0.5.0

type GenericOIDCClaims struct {
	jwt.Claims
	Name              string   `json:"name"`
	PreferredUsername string   `json:"preferred_username"`
	EMail             string   `json:"email"`
	Roles             []string `json:"roles"`
}

GenericOIDCClaims https://openid.net/specs/openid-connect-core-1_0.html Audience(s) that this ID Token is intended for. It MUST contain the OAuth 2.0 client_id of the Relying Party as an audience value. It MAY also contain identifiers for other audiences. In the general case, the aud value is an array of case sensitive strings. In the common special case when there is one audience, the aud value MAY be a single case sensitive string.

func (*GenericOIDCClaims) Username added in v0.5.3

func (g *GenericOIDCClaims) Username() string

type GenericOIDCOption added in v0.5.0

type GenericOIDCOption func(oidc *GenericOIDCCfg)

GenericOIDCOption provides means to configure GenericOIDC

func AllowedSignAlgs added in v0.5.0

func AllowedSignAlgs(algs []string) GenericOIDCOption

AllowedSignAlgs configures the allowed SigningAlgorithms, e.g. RS256, RS512,...

func GenericUserExtractor added in v0.5.0

func GenericUserExtractor(fn GenericUserExtractorFn) GenericOIDCOption

GenericUserExtractor configures the GenericUserExtractorFn to extract the User from a token

func Timeout added in v0.5.0

func Timeout(timeout time.Duration) GenericOIDCOption

type GenericUserExtractorFn added in v0.5.0

type GenericUserExtractorFn func(ic *IssuerConfig, claims *GenericOIDCClaims) (*User, error)

GenericUserExtractorFn extracts the User and Claims

type HMACAuth

type HMACAuth struct {
	Lifetime time.Duration
	Type     string
	AuthUser User
	// contains filtered or unexported fields
}

A HMACAuth is an authenticator which uses a hmac calculation.

Example
u := User{Name: "Bicycle Repair Man"}

// Use the authtype 'mytype' and the shared key (1,2,3)
// we also connect a user and set a lifetime

hm := NewHMACAuth(
	"mytype",
	[]byte{1, 2, 3},
	WithUser(u),
	WithLifetime(10*time.Second))

fmt.Println(hm.AuthUser.Name)
fmt.Println(hm.Lifetime)
fmt.Println(hm.Type)
// the key is not accessible
fmt.Println(hm.key)
Output:

Bicycle Repair Man
10s
mytype
[1 2 3]

func NewHMACAuth

func NewHMACAuth(authtype string, key []byte, opts ...HMACAuthOption) HMACAuth

NewHMACAuth returns a new HMACAuth initialized with the given key. A service implementation and a client must share the same key and authtype. The authtype will be transported as a scheme in the "Authentication" header. The key has to be private and will never be transmitted over the wire.

func (*HMACAuth) AddAuth

func (hma *HMACAuth) AddAuth(rq *http.Request, t time.Time, body []byte)

AddAuth adds the needed headers to the given request so the given values in the vals-array are correctly signed. This function can be used by a client to enhance the request before submitting it.

func (*HMACAuth) AddAuthToClientRequest

func (hma *HMACAuth) AddAuthToClientRequest(rq runtime.ClientRequest, t time.Time)

AddAuthToClientRequest to support openapi too

func (*HMACAuth) AuthHeaders

func (hma *HMACAuth) AuthHeaders(method string, t time.Time) map[string]string

AuthHeaders creates the necessary headers

func (*HMACAuth) User

func (hma *HMACAuth) User(rq *http.Request) (*User, error)

User calculates the hmac from header values. The input-values for the calculation are: Date-Header, Request-Method, Request-Content. If the result does not match the HMAC in the header, this function returns an error. Otherwise it returns the user which is connected to this hmac-auth.

Example
u := User{Name: "Bicycle Repair Man"}

// Use the authtype 'mytype' and the shared key (1,2,3)
// we also set the lifetime to zero so the test will work here
// never do this in production.
hm := NewHMACAuth(
	"mytype",
	[]byte{1, 2, 3},
	WithUser(u),
	WithLifetime(0))

mybody := []byte{4, 5, 6}
rq := httptest.NewRequest(http.MethodGet, "/myurl", bytes.NewReader(mybody))
t := time.Date(2019, time.January, 16, 14, 44, 45, 123, time.UTC)

// now add a HMCA with the given date and the body {4,5,6}
hm.AddAuth(rq, t, mybody)

usr, _ := hm.User(rq)
fmt.Println(usr.Name)
Output:

Bicycle Repair Man

func (*HMACAuth) UserFromRequestData

func (hma *HMACAuth) UserFromRequestData(requestData RequestData) (*User, error)

UserFromRequestData calculates the hmac from header values. The input-values for the calculation are: Date-Header, Request-Method, Request-Content. If the result does not match the HMAC in the header, this function returns an error. Otherwise it returns the user which is connected to this hmac-auth.

type HMACAuthOption

type HMACAuthOption func(*HMACAuth)

HMACAuthOption is a option type for HMACAuth

func WithLifetime

func WithLifetime(max time.Duration) HMACAuthOption

WithLifetime sets the lifetime which is connected to this HMAC auth. If the lifetime is zero, there will be no datetime checking. Do not do this in productive code (only useful in tests).

Example
hm := NewHMACAuth("mytype", []byte{1, 2, 3}, WithLifetime(10*time.Second))
fmt.Println(hm.Lifetime)
Output:

10s

func WithUser

func WithUser(u User) HMACAuthOption

WithUser sets the user which is connected to this HMAC auth.

Example
u := User{Name: "Bicycle Repair Man"}
hm := NewHMACAuth("mytype", []byte{1, 2, 3}, WithUser(u))
fmt.Println(hm.AuthUser.Name)
Output:

Bicycle Repair Man

type Issuer added in v0.5.0

type Issuer struct {
	// contains filtered or unexported fields
}

func (*Issuer) String added in v0.5.0

func (i *Issuer) String() string

type IssuerConfig added in v0.5.0

type IssuerConfig struct {
	Annotations Annotations
	Tenant      string
	Issuer      string
	ClientID    string
}

func (*IssuerConfig) String added in v0.5.0

func (i *IssuerConfig) String() string

type IssuerListProvider added in v0.5.0

type IssuerListProvider func() ([]*IssuerConfig, error)

IssuerListProvider returns the list of allowed IssuerConfigs

type IssuerNotFound added in v0.5.0

type IssuerNotFound struct{}

func NewIssuerNotFound added in v0.5.0

func NewIssuerNotFound() IssuerNotFound

func (IssuerNotFound) Error added in v0.5.0

func (i IssuerNotFound) Error() string

type KeyServerConfig added in v0.5.0

type KeyServerConfig struct {
	// contains filtered or unexported fields
}

type KeyServerOption added in v0.5.0

type KeyServerOption func(cfg *KeyServerConfig)

func KeyResponseTimeDelay added in v0.5.0

func KeyResponseTimeDelay(delay time.Duration) KeyServerOption

type MultiIssuerCache added in v0.5.0

type MultiIssuerCache struct {
	// contains filtered or unexported fields
}

MultiIssuerCache provides a UserGetter that is backed by multiple IssuerConfigs that are cached for a configurable duration.

func NewMultiIssuerCache added in v0.5.0

NewMultiIssuerCache creates a new MultiIssuerCache with given options if log is nil, slog is instantiated

func (*MultiIssuerCache) User added in v0.5.0

func (i *MultiIssuerCache) User(rq *http.Request) (*User, error)

type MultiIssuerUserGetterOption added in v0.5.0

type MultiIssuerUserGetterOption func(mic *MultiIssuerCache) *MultiIssuerCache

Option

func IssuerReloadInterval added in v0.5.0

func IssuerReloadInterval(duration time.Duration) MultiIssuerUserGetterOption

IssuerReloadInterval lets the client set the issuer cache duration

func IssuerRetryInterval added in v0.8.2

func IssuerRetryInterval(duration time.Duration) MultiIssuerUserGetterOption

IssuerRetryInterval lets the client set the issuer cache retry sleep period

type Option

type Option func(dex *Dex) *Dex

Option configures Dex

func AlgorithmsWhitelist added in v0.4.0

func AlgorithmsWhitelist(algNames []string) Option

AlgorithmsWhitelist adds given algorithms as allowed

func JWTParserOptions added in v0.9.0

func JWTParserOptions(opt jwt.ParserOption) Option

func UserExtractor

func UserExtractor(fn UserExtractorFn) Option

UserExtractor extracts the user with the given extractorfunc

type RequestData

type RequestData struct {
	Method          string
	AuthzHeader     string
	TimestampHeader string
	SaltHeader      string
}

RequestData wraps the http request data

type RequestDataGetter

type RequestDataGetter func() RequestData

RequestDataGetter is a supplied func which returns the RequestData

type ResourceAccess

type ResourceAccess string

ResourceAccess is the type for our groups

type TokenCfg added in v0.5.0

type TokenCfg struct {
	Alg           jose.SignatureAlgorithm
	KeyBitlength  int
	IssuerUrl     string
	Audience      []string
	ExpiresAt     time.Time
	IssuedAt      time.Time
	Id            string
	Subject       string
	Name          string
	PreferredName string
	Email         string
	Roles         []string
}

TokenCfg contains the data for filling the token

func DefaultTokenCfg added in v0.5.0

func DefaultTokenCfg() *TokenCfg

DefaultTokenCfg creates a TokenCfg filled with default values

type TokenProvider added in v0.5.0

type TokenProvider func(cfg *TokenCfg) (string, jose.JSONWebKey, jose.JSONWebKey)

TokenProvider creates the token with the given TokenCfg

type User

type User struct {
	EMail   string
	Name    string
	Groups  []ResourceAccess
	Tenant  string
	Issuer  string
	Subject string
}

A User is the current user who is executing a rest function.

func DefaultGenericUserExtractor added in v0.5.0

func DefaultGenericUserExtractor(ic *IssuerConfig, claims *GenericOIDCClaims) (*User, error)

DefaultGenericUserExtractor is the default implementation of how to extract the User from the token.

func GetUser

func GetUser(rq *http.Request) *User

GetUser reads the current user from the request.

func GetUserFromContext

func GetUserFromContext(ctx context.Context) *User

GetUserFromContext returns the current user from the context. If no user is set it returns a guest with no rights.

func (*User) HasGroup

func (u *User) HasGroup(grps ...ResourceAccess) bool

HasGroup returns true if the user has at least one of the given groups.

type UserCreds

type UserCreds struct {
	// contains filtered or unexported fields
}

UserCreds stores different methods for user extraction from a request.

func NewCreds

func NewCreds(opts ...CredsOpt) *UserCreds

NewCreds returns a credential checker which tries to pull out the current user of a request. You can set many different HMAC auth'ers but only one for bearer tokens.

func (*UserCreds) User

func (uc *UserCreds) User(rq *http.Request) (*User, error)

User pulls out a user from the request. It uses all authers which where specified when creating this usercred. the first auther which returns a user wins. if no auther returns a user, a guest with no rights will be returned.

type UserExtractorFn

type UserExtractorFn func(claims *Claims) (*User, error)

UserExtractorFn extracts the User and Claims

type UserGetter

type UserGetter interface {
	User(rq *http.Request) (*User, error)
}

A UserGetter returns the authenticated user from the request.

type UserGetterProvider added in v0.5.0

type UserGetterProvider func(ic *IssuerConfig) (UserGetter, error)

UserGetterProvider creates UserGetter for the given IssuerConfig

type UserGetterProxy added in v0.5.0

type UserGetterProxy struct {
	// contains filtered or unexported fields
}

UserGetterProxy switches between UserGetters depending on issuer/clientid of the token in the request.

func NewUserGetterProxy added in v0.5.0

func NewUserGetterProxy(defaultUG UserGetter, opts ...UserGetterProxyOption) *UserGetterProxy

NewUserGetterProxy creates a new UserGetterProxy with the given default UserGetter which is used if no other match is found.

func (*UserGetterProxy) User added in v0.5.0

func (u *UserGetterProxy) User(rq *http.Request) (*User, error)

type UserGetterProxyOption added in v0.5.0

type UserGetterProxyOption func(ug *UserGetterProxy)

UserGetterProxyOption defines the signature of init option-parameter

func UserGetterProxyMapping added in v0.5.0

func UserGetterProxyMapping(issuer, clientid string, userGetter UserGetter) UserGetterProxyOption

UserGetterProxyMapping adds the given UserGetter for the specified issuer/clientid combination that takes precedence over the default UserGetter if matched.

type WrongHMAC

type WrongHMAC struct {
	Got  string
	Want string
}

WrongHMAC is an error which contains the two hmacs which differ. A caller can use this values to log the computed value.

func (*WrongHMAC) Error

func (w *WrongHMAC) Error() string

Jump to

Keyboard shortcuts

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