new packaging
This commit is contained in:
parent
4a91d34f2e
commit
6b4b8f20a5
5 changed files with 60 additions and 45 deletions
|
@ -1,4 +1,4 @@
|
|||
package defaults
|
||||
package rp
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -12,8 +12,6 @@ import (
|
|||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
grants_tx "github.com/caos/oidc/pkg/oidc/grants/tokenexchange"
|
||||
"github.com/caos/oidc/pkg/rp"
|
||||
"github.com/caos/oidc/pkg/rp/tokenexchange"
|
||||
"github.com/caos/oidc/pkg/utils"
|
||||
)
|
||||
|
||||
|
@ -23,18 +21,18 @@ const (
|
|||
)
|
||||
|
||||
type DefaultRP struct {
|
||||
endpoints rp.Endpoints
|
||||
endpoints Endpoints
|
||||
|
||||
oauthConfig oauth2.Config
|
||||
config *rp.Config
|
||||
config *Config
|
||||
|
||||
httpClient *http.Client
|
||||
cookieHandler *utils.CookieHandler
|
||||
|
||||
verifier rp.Verifier
|
||||
verifier Verifier
|
||||
}
|
||||
|
||||
func NewDefaultRelayingParty(rpConfig *rp.Config, rpOpts ...DefaultReplayingPartyOpts) (tokenexchange.DelegationTokenExchangeRP, error) {
|
||||
func NewDefaultRelayingParty(rpConfig *Config, rpOpts ...DefaultRPOpts) (DelegationTokenExchangeRP, error) {
|
||||
p := &DefaultRP{
|
||||
config: rpConfig,
|
||||
httpClient: utils.DefaultHTTPClient,
|
||||
|
@ -55,15 +53,15 @@ func NewDefaultRelayingParty(rpConfig *rp.Config, rpOpts ...DefaultReplayingPart
|
|||
return p, nil
|
||||
}
|
||||
|
||||
type DefaultReplayingPartyOpts func(p *DefaultRP)
|
||||
type DefaultRPOpts func(p *DefaultRP)
|
||||
|
||||
func WithCookieHandler(cookieHandler *utils.CookieHandler) DefaultReplayingPartyOpts {
|
||||
func WithCookieHandler(cookieHandler *utils.CookieHandler) DefaultRPOpts {
|
||||
return func(p *DefaultRP) {
|
||||
p.cookieHandler = cookieHandler
|
||||
}
|
||||
}
|
||||
|
||||
func WithHTTPClient(client *http.Client) DefaultReplayingPartyOpts {
|
||||
func WithHTTPClient(client *http.Client) DefaultRPOpts {
|
||||
return func(p *DefaultRP) {
|
||||
p.httpClient = client
|
||||
}
|
||||
|
@ -169,7 +167,7 @@ func (p *DefaultRP) discover() error {
|
|||
return err
|
||||
}
|
||||
|
||||
p.endpoints = rp.GetEndpoints(discoveryConfig)
|
||||
p.endpoints = GetEndpoints(discoveryConfig)
|
||||
p.oauthConfig = oauth2.Config{
|
||||
ClientID: p.config.ClientID,
|
||||
ClientSecret: p.config.ClientSecret,
|
|
@ -1,4 +1,4 @@
|
|||
package defaults
|
||||
package rp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -15,11 +15,24 @@ import (
|
|||
"gopkg.in/square/go-jose.v2"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/caos/oidc/pkg/rp"
|
||||
str_utils "github.com/caos/utils/strings"
|
||||
)
|
||||
|
||||
func NewVerifier(issuer, clientID string, keySet oidc.KeySet, confOpts ...ConfFunc) rp.Verifier {
|
||||
//DefaultVerifier implements the `Verifier` interface
|
||||
type DefaultVerifier struct {
|
||||
config *verifierConfig
|
||||
keySet oidc.KeySet
|
||||
}
|
||||
|
||||
//ConfFunc is the type for providing dynamic verifierConfig
|
||||
type ConfFunc func(*verifierConfig)
|
||||
|
||||
//ACRVerifier specifies the function to be used by the `DefaultVerifier` for validating the acr claim
|
||||
type ACRVerifier func(string) error
|
||||
|
||||
//NewDefaultVerifier creates `DefaultVerifier` with the given
|
||||
//issuer, clientID, keyset and possible configOptions
|
||||
func NewDefaultVerifier(issuer, clientID string, keySet oidc.KeySet, confOpts ...ConfFunc) Verifier {
|
||||
conf := &verifierConfig{
|
||||
issuer: issuer,
|
||||
clientID: clientID,
|
||||
|
@ -33,52 +46,53 @@ func NewVerifier(issuer, clientID string, keySet oidc.KeySet, confOpts ...ConfFu
|
|||
opt(conf)
|
||||
}
|
||||
}
|
||||
return &Verifier{config: conf, keySet: keySet}
|
||||
return &DefaultVerifier{config: conf, keySet: keySet}
|
||||
}
|
||||
|
||||
type Verifier struct {
|
||||
config *verifierConfig
|
||||
keySet oidc.KeySet
|
||||
}
|
||||
|
||||
type ConfFunc func(*verifierConfig)
|
||||
|
||||
//WithIgnoreIssuedAt will turn off iat claim verification
|
||||
func WithIgnoreIssuedAt() func(*verifierConfig) {
|
||||
return func(conf *verifierConfig) {
|
||||
conf.iat.ignore = true
|
||||
}
|
||||
}
|
||||
|
||||
//WithIssuedAtOffset mitigates the risk of iat to be in the future
|
||||
//because of clock skews with the ability to add an offset to the current time
|
||||
func WithIssuedAtOffset(offset time.Duration) func(*verifierConfig) {
|
||||
return func(conf *verifierConfig) {
|
||||
conf.iat.offset = offset
|
||||
}
|
||||
}
|
||||
|
||||
//WithIssuedAtMaxAge provides the ability to define the maximum duration between iat and now
|
||||
func WithIssuedAtMaxAge(maxAge time.Duration) func(*verifierConfig) {
|
||||
return func(conf *verifierConfig) {
|
||||
conf.iat.maxAge = maxAge
|
||||
}
|
||||
}
|
||||
|
||||
//WithNonce TODO: ?
|
||||
func WithNonce(nonce string) func(*verifierConfig) {
|
||||
return func(conf *verifierConfig) {
|
||||
conf.nonce = nonce
|
||||
}
|
||||
}
|
||||
|
||||
//WithACRVerifier sets the verifier for the acr claim
|
||||
func WithACRVerifier(verifier ACRVerifier) func(*verifierConfig) {
|
||||
return func(conf *verifierConfig) {
|
||||
conf.acr = verifier
|
||||
}
|
||||
}
|
||||
|
||||
//WithAuthTimeMaxAge provides the ability to define the maximum duration between auth_time and now
|
||||
func WithAuthTimeMaxAge(maxAge time.Duration) func(*verifierConfig) {
|
||||
return func(conf *verifierConfig) {
|
||||
conf.maxAge = maxAge
|
||||
}
|
||||
}
|
||||
|
||||
//WithSupportedSigningAlgorithms overwrites the default RS256 signing algorithm
|
||||
func WithSupportedSigningAlgorithms(algs ...string) func(*verifierConfig) {
|
||||
return func(conf *verifierConfig) {
|
||||
conf.supportedSignAlgs = algs
|
||||
|
@ -111,9 +125,9 @@ type iatConfig struct {
|
|||
maxAge time.Duration
|
||||
}
|
||||
|
||||
type ACRVerifier func(string) error
|
||||
|
||||
func DefaultACRVerifier(possibleValues []string) func(string) error {
|
||||
//DefaultACRVerifier implements `ACRVerifier` returning an error
|
||||
//if non of the provided values matches the acr claim
|
||||
func DefaultACRVerifier(possibleValues []string) ACRVerifier {
|
||||
return func(acr string) error {
|
||||
if !str_utils.Contains(possibleValues, acr) {
|
||||
return ErrAcrInvalid(possibleValues, acr)
|
||||
|
@ -122,7 +136,10 @@ func DefaultACRVerifier(possibleValues []string) func(string) error {
|
|||
}
|
||||
}
|
||||
|
||||
func (v *Verifier) Verify(ctx context.Context, accessToken, idTokenString string) (*oidc.IDTokenClaims, error) {
|
||||
//Verify implements the `Verify` method of the `Verifier` interface
|
||||
//according to https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
||||
//and https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowTokenValidation
|
||||
func (v *DefaultVerifier) Verify(ctx context.Context, accessToken, idTokenString string) (*oidc.IDTokenClaims, error) {
|
||||
v.config.now = time.Now().UTC()
|
||||
idToken, err := v.VerifyIDToken(ctx, idTokenString)
|
||||
if err != nil {
|
||||
|
@ -134,14 +151,15 @@ func (v *Verifier) Verify(ctx context.Context, accessToken, idTokenString string
|
|||
return idToken, nil
|
||||
}
|
||||
|
||||
func (v *Verifier) now() time.Time {
|
||||
func (v *DefaultVerifier) now() time.Time {
|
||||
if v.config.now.IsZero() {
|
||||
v.config.now = time.Now().UTC().Round(time.Second)
|
||||
}
|
||||
return v.config.now
|
||||
}
|
||||
|
||||
func (v *Verifier) VerifyIDToken(ctx context.Context, idTokenString string) (*oidc.IDTokenClaims, error) {
|
||||
//VerifyIDToken: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
||||
func (v *DefaultVerifier) VerifyIDToken(ctx context.Context, idTokenString string) (*oidc.IDTokenClaims, error) {
|
||||
//1. if encrypted --> decrypt
|
||||
decrypted, err := v.decryptToken(idTokenString)
|
||||
if err != nil {
|
||||
|
@ -206,7 +224,7 @@ func (v *Verifier) VerifyIDToken(ctx context.Context, idTokenString string) (*oi
|
|||
// return err
|
||||
}
|
||||
|
||||
func (v *Verifier) parseToken(tokenString string) (*oidc.IDTokenClaims, []byte, error) {
|
||||
func (v *DefaultVerifier) parseToken(tokenString string) (*oidc.IDTokenClaims, []byte, error) {
|
||||
parts := strings.Split(tokenString, ".")
|
||||
if len(parts) != 3 {
|
||||
return nil, nil, ValidationError("token contains an invalid number of segments") //TODO: err NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
|
||||
|
@ -220,14 +238,14 @@ func (v *Verifier) parseToken(tokenString string) (*oidc.IDTokenClaims, []byte,
|
|||
return idToken, payload, err
|
||||
}
|
||||
|
||||
func (v *Verifier) checkIssuer(issuer string) error {
|
||||
func (v *DefaultVerifier) checkIssuer(issuer string) error {
|
||||
if v.config.issuer != issuer {
|
||||
return ErrIssuerInvalid(v.config.issuer, issuer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Verifier) checkAudience(audiences []string) error {
|
||||
func (v *DefaultVerifier) checkAudience(audiences []string) error {
|
||||
if !str_utils.Contains(audiences, v.config.clientID) {
|
||||
return ErrAudienceMissingClientID(v.config.clientID)
|
||||
}
|
||||
|
@ -238,7 +256,7 @@ func (v *Verifier) checkAudience(audiences []string) error {
|
|||
|
||||
//4. if multiple aud strings --> check if azp
|
||||
//5. if azp --> check azp == client_id
|
||||
func (v *Verifier) checkAuthorizedParty(audiences []string, authorizedParty string) error {
|
||||
func (v *DefaultVerifier) checkAuthorizedParty(audiences []string, authorizedParty string) error {
|
||||
if len(audiences) > 1 {
|
||||
if authorizedParty == "" {
|
||||
return ErrAzpMissing()
|
||||
|
@ -250,7 +268,7 @@ func (v *Verifier) checkAuthorizedParty(audiences []string, authorizedParty stri
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *Verifier) checkSignature(ctx context.Context, idTokenString string, payload []byte) (jose.SignatureAlgorithm, error) {
|
||||
func (v *DefaultVerifier) checkSignature(ctx context.Context, idTokenString string, payload []byte) (jose.SignatureAlgorithm, error) {
|
||||
jws, err := jose.ParseSigned(idTokenString)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -344,7 +362,7 @@ func (v *Verifier) checkSignature(ctx context.Context, idTokenString string, pay
|
|||
// return nil
|
||||
// }
|
||||
|
||||
func (v *Verifier) checkExpiration(expiration time.Time) error {
|
||||
func (v *DefaultVerifier) checkExpiration(expiration time.Time) error {
|
||||
expiration = expiration.Round(time.Second)
|
||||
if !v.now().Before(expiration) {
|
||||
return ErrExpInvalid(expiration)
|
||||
|
@ -352,7 +370,7 @@ func (v *Verifier) checkExpiration(expiration time.Time) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *Verifier) checkIssuedAt(issuedAt time.Time) error {
|
||||
func (v *DefaultVerifier) checkIssuedAt(issuedAt time.Time) error {
|
||||
if v.config.iat.ignore {
|
||||
return nil
|
||||
}
|
||||
|
@ -370,7 +388,7 @@ func (v *Verifier) checkIssuedAt(issuedAt time.Time) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
func (v *Verifier) checkNonce(nonce string) error {
|
||||
func (v *DefaultVerifier) checkNonce(nonce string) error {
|
||||
if v.config.nonce == "" {
|
||||
return nil
|
||||
}
|
||||
|
@ -379,13 +397,13 @@ func (v *Verifier) checkNonce(nonce string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
func (v *Verifier) checkAuthorizationContextClassReference(acr string) error {
|
||||
func (v *DefaultVerifier) checkAuthorizationContextClassReference(acr string) error {
|
||||
if v.config.acr != nil {
|
||||
return v.config.acr(acr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (v *Verifier) checkAuthTime(authTime time.Time) error {
|
||||
func (v *DefaultVerifier) checkAuthTime(authTime time.Time) error {
|
||||
if v.config.maxAge == 0 {
|
||||
return nil
|
||||
}
|
||||
|
@ -400,7 +418,7 @@ func (v *Verifier) checkAuthTime(authTime time.Time) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *Verifier) decryptToken(tokenString string) (string, error) {
|
||||
func (v *DefaultVerifier) decryptToken(tokenString string) (string, error) {
|
||||
return tokenString, nil //TODO: impl
|
||||
}
|
||||
|
||||
|
@ -423,7 +441,7 @@ func (v *Verifier) decryptToken(tokenString string) (string, error) {
|
|||
// return token, nil //TODO: impl
|
||||
// }
|
||||
|
||||
func (v *Verifier) verifyAccessToken(accessToken, atHash string, sigAlgorithm jose.SignatureAlgorithm) error {
|
||||
func (v *DefaultVerifier) verifyAccessToken(accessToken, atHash string, sigAlgorithm jose.SignatureAlgorithm) error {
|
||||
if atHash == "" {
|
||||
return nil //TODO: return error
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package defaults
|
||||
package rp
|
||||
|
||||
import (
|
||||
"github.com/caos/oidc/pkg/oidc/grants/tokenexchange"
|
|
@ -1,4 +1,4 @@
|
|||
package defaults
|
||||
package rp
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +1,4 @@
|
|||
package tokenexchange
|
||||
package rp
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -6,12 +6,11 @@ import (
|
|||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/caos/oidc/pkg/oidc/grants/tokenexchange"
|
||||
"github.com/caos/oidc/pkg/rp"
|
||||
)
|
||||
|
||||
//TokenExchangeRP extends the `RelayingParty` interface for the *draft* oauth2 `Token Exchange`
|
||||
type TokenExchangeRP interface {
|
||||
rp.RelayingParty
|
||||
RelayingParty
|
||||
|
||||
//TokenExchange implement the `Token Echange Grant` exchanging some token for an other
|
||||
TokenExchange(context.Context, *tokenexchange.TokenExchangeRequest) (*oauth2.Token, error)
|
Loading…
Add table
Add a link
Reference in a new issue