chore(linting): apply gofumpt & goimports to all .go files (#225)
This commit is contained in:
parent
c4b7ef9160
commit
b5da6ec29b
45 changed files with 539 additions and 479 deletions
|
@ -34,14 +34,14 @@ func main() {
|
||||||
|
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
|
|
||||||
//public url accessible without any authorization
|
// public url accessible without any authorization
|
||||||
//will print `OK` and current timestamp
|
// will print `OK` and current timestamp
|
||||||
router.HandleFunc(publicURL, func(w http.ResponseWriter, r *http.Request) {
|
router.HandleFunc(publicURL, func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write([]byte("OK " + time.Now().String()))
|
w.Write([]byte("OK " + time.Now().String()))
|
||||||
})
|
})
|
||||||
|
|
||||||
//protected url which needs an active token
|
// protected url which needs an active token
|
||||||
//will print the result of the introspection endpoint on success
|
// will print the result of the introspection endpoint on success
|
||||||
router.HandleFunc(protectedURL, func(w http.ResponseWriter, r *http.Request) {
|
router.HandleFunc(protectedURL, func(w http.ResponseWriter, r *http.Request) {
|
||||||
ok, token := checkToken(w, r)
|
ok, token := checkToken(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -60,9 +60,9 @@ func main() {
|
||||||
w.Write(data)
|
w.Write(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
//protected url which needs an active token and checks if the response of the introspect endpoint
|
// protected url which needs an active token and checks if the response of the introspect endpoint
|
||||||
//contains a requested claim with the required (string) value
|
// contains a requested claim with the required (string) value
|
||||||
//e.g. /protected/username/livio@caos.ch
|
// e.g. /protected/username/livio@caos.ch
|
||||||
router.HandleFunc(protectedClaimURL, func(w http.ResponseWriter, r *http.Request) {
|
router.HandleFunc(protectedClaimURL, func(w http.ResponseWriter, r *http.Request) {
|
||||||
ok, token := checkToken(w, r)
|
ok, token := checkToken(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -48,18 +48,18 @@ func main() {
|
||||||
logrus.Fatalf("error creating provider %s", err.Error())
|
logrus.Fatalf("error creating provider %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
//generate some state (representing the state of the user in your application,
|
// generate some state (representing the state of the user in your application,
|
||||||
//e.g. the page where he was before sending him to login
|
// e.g. the page where he was before sending him to login
|
||||||
state := func() string {
|
state := func() string {
|
||||||
return uuid.New().String()
|
return uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
//register the AuthURLHandler at your preferred path
|
// register the AuthURLHandler at your preferred path
|
||||||
//the AuthURLHandler creates the auth request and redirects the user to the auth server
|
// the AuthURLHandler creates the auth request and redirects the user to the auth server
|
||||||
//including state handling with secure cookie and the possibility to use PKCE
|
// including state handling with secure cookie and the possibility to use PKCE
|
||||||
http.Handle("/login", rp.AuthURLHandler(state, provider))
|
http.Handle("/login", rp.AuthURLHandler(state, provider))
|
||||||
|
|
||||||
//for demonstration purposes the returned userinfo response is written as JSON object onto response
|
// for demonstration purposes the returned userinfo response is written as JSON object onto response
|
||||||
marshalUserinfo := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp rp.RelyingParty, info oidc.UserInfo) {
|
marshalUserinfo := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp rp.RelyingParty, info oidc.UserInfo) {
|
||||||
data, err := json.Marshal(info)
|
data, err := json.Marshal(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -69,9 +69,9 @@ func main() {
|
||||||
w.Write(data)
|
w.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
//you could also just take the access_token and id_token without calling the userinfo endpoint:
|
// you could also just take the access_token and id_token without calling the userinfo endpoint:
|
||||||
//
|
//
|
||||||
//marshalToken := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp rp.RelyingParty) {
|
// marshalToken := func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp rp.RelyingParty) {
|
||||||
// data, err := json.Marshal(tokens)
|
// data, err := json.Marshal(tokens)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
// http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -80,16 +80,16 @@ func main() {
|
||||||
// w.Write(data)
|
// w.Write(data)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//register the CodeExchangeHandler at the callbackPath
|
// register the CodeExchangeHandler at the callbackPath
|
||||||
//the CodeExchangeHandler handles the auth response, creates the token request and calls the callback function
|
// the CodeExchangeHandler handles the auth response, creates the token request and calls the callback function
|
||||||
//with the returned tokens from the token endpoint
|
// with the returned tokens from the token endpoint
|
||||||
//in this example the callback function itself is wrapped by the UserinfoCallback which
|
// in this example the callback function itself is wrapped by the UserinfoCallback which
|
||||||
//will call the Userinfo endpoint, check the sub and pass the info into the callback function
|
// will call the Userinfo endpoint, check the sub and pass the info into the callback function
|
||||||
http.Handle(callbackPath, rp.CodeExchangeHandler(rp.UserinfoCallback(marshalUserinfo), provider))
|
http.Handle(callbackPath, rp.CodeExchangeHandler(rp.UserinfoCallback(marshalUserinfo), provider))
|
||||||
|
|
||||||
//if you would use the callback without calling the userinfo endpoint, simply switch the callback handler for:
|
// if you would use the callback without calling the userinfo endpoint, simply switch the callback handler for:
|
||||||
//
|
//
|
||||||
//http.Handle(callbackPath, rp.CodeExchangeHandler(marshalToken, provider))
|
// http.Handle(callbackPath, rp.CodeExchangeHandler(marshalToken, provider))
|
||||||
|
|
||||||
lis := fmt.Sprintf("127.0.0.1:%s", port)
|
lis := fmt.Sprintf("127.0.0.1:%s", port)
|
||||||
logrus.Infof("listening on http://%s/", lis)
|
logrus.Infof("listening on http://%s/", lis)
|
||||||
|
|
|
@ -16,9 +16,7 @@ import (
|
||||||
"github.com/zitadel/oidc/pkg/client/profile"
|
"github.com/zitadel/oidc/pkg/client/profile"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var client = http.DefaultClient
|
||||||
client = http.DefaultClient
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
keyPath := os.Getenv("KEY_PATH")
|
keyPath := os.Getenv("KEY_PATH")
|
||||||
|
@ -145,7 +143,6 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
lis := fmt.Sprintf("127.0.0.1:%s", port)
|
lis := fmt.Sprintf("127.0.0.1:%s", port)
|
||||||
logrus.Infof("listening on http://%s/", lis)
|
logrus.Infof("listening on http://%s/", lis)
|
||||||
|
|
|
@ -15,20 +15,17 @@ import (
|
||||||
"github.com/zitadel/oidc/pkg/oidc"
|
"github.com/zitadel/oidc/pkg/oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var Encoder = func() httphelper.Encoder {
|
||||||
Encoder = func() httphelper.Encoder {
|
e := schema.NewEncoder()
|
||||||
e := schema.NewEncoder()
|
e.RegisterEncoder(oidc.SpaceDelimitedArray{}, func(value reflect.Value) string {
|
||||||
e.RegisterEncoder(oidc.SpaceDelimitedArray{}, func(value reflect.Value) string {
|
return value.Interface().(oidc.SpaceDelimitedArray).Encode()
|
||||||
return value.Interface().(oidc.SpaceDelimitedArray).Encode()
|
})
|
||||||
})
|
return e
|
||||||
return e
|
}()
|
||||||
}()
|
|
||||||
)
|
|
||||||
|
|
||||||
//Discover calls the discovery endpoint of the provided issuer and returns its configuration
|
// Discover calls the discovery endpoint of the provided issuer and returns its configuration
|
||||||
//It accepts an optional argument "wellknownUrl" which can be used to overide the dicovery endpoint url
|
// It accepts an optional argument "wellknownUrl" which can be used to overide the dicovery endpoint url
|
||||||
func Discover(issuer string, httpClient *http.Client, wellKnownUrl ...string) (*oidc.DiscoveryConfiguration, error) {
|
func Discover(issuer string, httpClient *http.Client, wellKnownUrl ...string) (*oidc.DiscoveryConfiguration, error) {
|
||||||
|
|
||||||
wellKnown := strings.TrimSuffix(issuer, "/") + oidc.DiscoveryEndpoint
|
wellKnown := strings.TrimSuffix(issuer, "/") + oidc.DiscoveryEndpoint
|
||||||
if len(wellKnownUrl) == 1 && wellKnownUrl[0] != "" {
|
if len(wellKnownUrl) == 1 && wellKnownUrl[0] != "" {
|
||||||
wellKnown = wellKnownUrl[0]
|
wellKnown = wellKnownUrl[0]
|
||||||
|
|
|
@ -14,12 +14,12 @@ type keyFile struct {
|
||||||
Type string `json:"type"` // serviceaccount or application
|
Type string `json:"type"` // serviceaccount or application
|
||||||
KeyID string `json:"keyId"`
|
KeyID string `json:"keyId"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Issuer string `json:"issuer"` //not yet in file
|
Issuer string `json:"issuer"` // not yet in file
|
||||||
|
|
||||||
//serviceaccount
|
// serviceaccount
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
|
|
||||||
//application
|
// application
|
||||||
ClientID string `json:"clientId"`
|
ClientID string `json:"clientId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"github.com/zitadel/oidc/pkg/oidc"
|
"github.com/zitadel/oidc/pkg/oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
//jwtProfileTokenSource implement the oauth2.TokenSource
|
// jwtProfileTokenSource implement the oauth2.TokenSource
|
||||||
//it will request a token using the OAuth2 JWT Profile Grant
|
// it will request a token using the OAuth2 JWT Profile Grant
|
||||||
//therefore sending an `assertion` by singing a JWT with the provided private key
|
// therefore sending an `assertion` by singing a JWT with the provided private key
|
||||||
type jwtProfileTokenSource struct {
|
type jwtProfileTokenSource struct {
|
||||||
clientID string
|
clientID string
|
||||||
audience []string
|
audience []string
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"github.com/zitadel/oidc/pkg/oidc/grants/tokenexchange"
|
"github.com/zitadel/oidc/pkg/oidc/grants/tokenexchange"
|
||||||
)
|
)
|
||||||
|
|
||||||
//DelegationTokenRequest is an implementation of TokenExchangeRequest
|
// DelegationTokenRequest is an implementation of TokenExchangeRequest
|
||||||
//it exchanges an "urn:ietf:params:oauth:token-type:access_token" with an optional
|
// it exchanges an "urn:ietf:params:oauth:token-type:access_token" with an optional
|
||||||
//"urn:ietf:params:oauth:token-type:access_token" actor token for an
|
//"urn:ietf:params:oauth:token-type:access_token" actor token for an
|
||||||
//"urn:ietf:params:oauth:token-type:access_token" delegation token
|
//"urn:ietf:params:oauth:token-type:access_token" delegation token
|
||||||
func DelegationTokenRequest(subjectToken string, opts ...tokenexchange.TokenExchangeOption) *tokenexchange.TokenExchangeRequest {
|
func DelegationTokenRequest(subjectToken string, opts ...tokenexchange.TokenExchangeOption) *tokenexchange.TokenExchangeRequest {
|
||||||
|
|
|
@ -21,12 +21,12 @@ func NewRemoteKeySet(client *http.Client, jwksURL string, opts ...func(*remoteKe
|
||||||
return keyset
|
return keyset
|
||||||
}
|
}
|
||||||
|
|
||||||
//SkipRemoteCheck will suppress checking for new remote keys if signature validation fails with cached keys
|
// SkipRemoteCheck will suppress checking for new remote keys if signature validation fails with cached keys
|
||||||
//and no kid header is set in the JWT
|
// and no kid header is set in the JWT
|
||||||
//
|
//
|
||||||
//this might be handy to save some unnecessary round trips in cases where the JWT does not contain a kid header and
|
// this might be handy to save some unnecessary round trips in cases where the JWT does not contain a kid header and
|
||||||
//there is only a single remote key
|
// there is only a single remote key
|
||||||
//please notice that remote keys will then only be fetched if cached keys are empty
|
// please notice that remote keys will then only be fetched if cached keys are empty
|
||||||
func SkipRemoteCheck() func(set *remoteKeySet) {
|
func SkipRemoteCheck() func(set *remoteKeySet) {
|
||||||
return func(set *remoteKeySet) {
|
return func(set *remoteKeySet) {
|
||||||
set.skipRemoteCheck = true
|
set.skipRemoteCheck = true
|
||||||
|
@ -97,15 +97,15 @@ func (r *remoteKeySet) VerifySignature(ctx context.Context, jws *jose.JSONWebSig
|
||||||
return r.verifySignatureRemote(ctx, jws, keyID, alg)
|
return r.verifySignatureRemote(ctx, jws, keyID, alg)
|
||||||
}
|
}
|
||||||
|
|
||||||
//verifySignatureCached checks for a matching key in the cached key list
|
// verifySignatureCached checks for a matching key in the cached key list
|
||||||
//
|
//
|
||||||
//if there is only one possible, it tries to verify the signature and will return the payload if successful
|
// if there is only one possible, it tries to verify the signature and will return the payload if successful
|
||||||
//
|
//
|
||||||
//it only returns an error if signature validation fails and keys exactMatch which is if either:
|
// it only returns an error if signature validation fails and keys exactMatch which is if either:
|
||||||
// - both kid are empty and skipRemoteCheck is set to true
|
// - both kid are empty and skipRemoteCheck is set to true
|
||||||
// - or both (JWT and JWK) kid are equal
|
// - or both (JWT and JWK) kid are equal
|
||||||
//
|
//
|
||||||
//otherwise it will return no error (so remote keys will be loaded)
|
// otherwise it will return no error (so remote keys will be loaded)
|
||||||
func (r *remoteKeySet) verifySignatureCached(jws *jose.JSONWebSignature, keyID, alg string) ([]byte, error) {
|
func (r *remoteKeySet) verifySignatureCached(jws *jose.JSONWebSignature, keyID, alg string) ([]byte, error) {
|
||||||
keys := r.keysFromCache()
|
keys := r.keysFromCache()
|
||||||
if len(keys) == 0 {
|
if len(keys) == 0 {
|
||||||
|
@ -113,7 +113,7 @@ func (r *remoteKeySet) verifySignatureCached(jws *jose.JSONWebSignature, keyID,
|
||||||
}
|
}
|
||||||
key, err := oidc.FindMatchingKey(keyID, oidc.KeyUseSignature, alg, keys...)
|
key, err := oidc.FindMatchingKey(keyID, oidc.KeyUseSignature, alg, keys...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//no key / multiple found, try with remote keys
|
// no key / multiple found, try with remote keys
|
||||||
return nil, nil //nolint:nilerr
|
return nil, nil //nolint:nilerr
|
||||||
}
|
}
|
||||||
payload, err := jws.Verify(&key)
|
payload, err := jws.Verify(&key)
|
||||||
|
@ -121,7 +121,7 @@ func (r *remoteKeySet) verifySignatureCached(jws *jose.JSONWebSignature, keyID,
|
||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
if !r.exactMatch(key.KeyID, keyID) {
|
if !r.exactMatch(key.KeyID, keyID) {
|
||||||
//no exact key match, try getting better match with remote keys
|
// no exact key match, try getting better match with remote keys
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("signature verification failed: %w", err)
|
return nil, fmt.Errorf("signature verification failed: %w", err)
|
||||||
|
@ -213,11 +213,11 @@ func (r *remoteKeySet) fetchRemoteKeys(ctx context.Context) ([]jose.JSONWebKey,
|
||||||
return keySet.Keys, nil
|
return keySet.Keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//jsonWebKeySet is an alias for jose.JSONWebKeySet which ignores unknown key types (kty)
|
// jsonWebKeySet is an alias for jose.JSONWebKeySet which ignores unknown key types (kty)
|
||||||
type jsonWebKeySet jose.JSONWebKeySet
|
type jsonWebKeySet jose.JSONWebKeySet
|
||||||
|
|
||||||
//UnmarshalJSON overrides the default jose.JSONWebKeySet method to ignore any error
|
// UnmarshalJSON overrides the default jose.JSONWebKeySet method to ignore any error
|
||||||
//which might occur because of unknown key types (kty)
|
// which might occur because of unknown key types (kty)
|
||||||
func (k *jsonWebKeySet) UnmarshalJSON(data []byte) (err error) {
|
func (k *jsonWebKeySet) UnmarshalJSON(data []byte) (err error) {
|
||||||
var raw rawJSONWebKeySet
|
var raw rawJSONWebKeySet
|
||||||
err = json.Unmarshal(data, &raw)
|
err = json.Unmarshal(data, &raw)
|
||||||
|
|
|
@ -23,53 +23,49 @@ const (
|
||||||
pkceCode = "pkce"
|
pkceCode = "pkce"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ErrUserInfoSubNotMatching = errors.New("sub from userinfo does not match the sub from the id_token")
|
||||||
ErrUserInfoSubNotMatching = errors.New("sub from userinfo does not match the sub from the id_token")
|
|
||||||
)
|
|
||||||
|
|
||||||
//RelyingParty declares the minimal interface for oidc clients
|
// RelyingParty declares the minimal interface for oidc clients
|
||||||
type RelyingParty interface {
|
type RelyingParty interface {
|
||||||
//OAuthConfig returns the oauth2 Config
|
// OAuthConfig returns the oauth2 Config
|
||||||
OAuthConfig() *oauth2.Config
|
OAuthConfig() *oauth2.Config
|
||||||
|
|
||||||
//Issuer returns the issuer of the oidc config
|
// Issuer returns the issuer of the oidc config
|
||||||
Issuer() string
|
Issuer() string
|
||||||
|
|
||||||
//IsPKCE returns if authorization is done using `Authorization Code Flow with Proof Key for Code Exchange (PKCE)`
|
// IsPKCE returns if authorization is done using `Authorization Code Flow with Proof Key for Code Exchange (PKCE)`
|
||||||
IsPKCE() bool
|
IsPKCE() bool
|
||||||
|
|
||||||
//CookieHandler returns a http cookie handler used for various state transfer cookies
|
// CookieHandler returns a http cookie handler used for various state transfer cookies
|
||||||
CookieHandler() *httphelper.CookieHandler
|
CookieHandler() *httphelper.CookieHandler
|
||||||
|
|
||||||
//HttpClient returns a http client used for calls to the openid provider, e.g. calling token endpoint
|
// HttpClient returns a http client used for calls to the openid provider, e.g. calling token endpoint
|
||||||
HttpClient() *http.Client
|
HttpClient() *http.Client
|
||||||
|
|
||||||
//IsOAuth2Only specifies whether relaying party handles only oauth2 or oidc calls
|
// IsOAuth2Only specifies whether relaying party handles only oauth2 or oidc calls
|
||||||
IsOAuth2Only() bool
|
IsOAuth2Only() bool
|
||||||
|
|
||||||
//Signer is used if the relaying party uses the JWT Profile
|
// Signer is used if the relaying party uses the JWT Profile
|
||||||
Signer() jose.Signer
|
Signer() jose.Signer
|
||||||
|
|
||||||
//GetEndSessionEndpoint returns the endpoint to sign out on a IDP
|
// GetEndSessionEndpoint returns the endpoint to sign out on a IDP
|
||||||
GetEndSessionEndpoint() string
|
GetEndSessionEndpoint() string
|
||||||
|
|
||||||
//UserinfoEndpoint returns the userinfo
|
// UserinfoEndpoint returns the userinfo
|
||||||
UserinfoEndpoint() string
|
UserinfoEndpoint() string
|
||||||
|
|
||||||
//IDTokenVerifier returns the verifier interface used for oidc id_token verification
|
// IDTokenVerifier returns the verifier interface used for oidc id_token verification
|
||||||
IDTokenVerifier() IDTokenVerifier
|
IDTokenVerifier() IDTokenVerifier
|
||||||
//ErrorHandler returns the handler used for callback errors
|
// ErrorHandler returns the handler used for callback errors
|
||||||
|
|
||||||
ErrorHandler() func(http.ResponseWriter, *http.Request, string, string, string)
|
ErrorHandler() func(http.ResponseWriter, *http.Request, string, string, string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrorHandler func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string)
|
type ErrorHandler func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string)
|
||||||
|
|
||||||
var (
|
var DefaultErrorHandler ErrorHandler = func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string) {
|
||||||
DefaultErrorHandler ErrorHandler = func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string) {
|
http.Error(w, errorType+": "+errorDesc, http.StatusInternalServerError)
|
||||||
http.Error(w, errorType+": "+errorDesc, http.StatusInternalServerError)
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type relyingParty struct {
|
type relyingParty struct {
|
||||||
issuer string
|
issuer string
|
||||||
|
@ -138,9 +134,9 @@ func (rp *relyingParty) ErrorHandler() func(http.ResponseWriter, *http.Request,
|
||||||
return rp.errorHandler
|
return rp.errorHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewRelyingPartyOAuth creates an (OAuth2) RelyingParty with the given
|
// NewRelyingPartyOAuth creates an (OAuth2) RelyingParty with the given
|
||||||
//OAuth2 Config and possible configOptions
|
// OAuth2 Config and possible configOptions
|
||||||
//it will use the AuthURL and TokenURL set in config
|
// it will use the AuthURL and TokenURL set in config
|
||||||
func NewRelyingPartyOAuth(config *oauth2.Config, options ...Option) (RelyingParty, error) {
|
func NewRelyingPartyOAuth(config *oauth2.Config, options ...Option) (RelyingParty, error) {
|
||||||
rp := &relyingParty{
|
rp := &relyingParty{
|
||||||
oauthConfig: config,
|
oauthConfig: config,
|
||||||
|
@ -161,9 +157,9 @@ func NewRelyingPartyOAuth(config *oauth2.Config, options ...Option) (RelyingPart
|
||||||
return rp, nil
|
return rp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewRelyingPartyOIDC creates an (OIDC) RelyingParty with the given
|
// NewRelyingPartyOIDC creates an (OIDC) RelyingParty with the given
|
||||||
//issuer, clientID, clientSecret, redirectURI, scopes and possible configOptions
|
// issuer, clientID, clientSecret, redirectURI, scopes and possible configOptions
|
||||||
//it will run discovery on the provided issuer and use the found endpoints
|
// it will run discovery on the provided issuer and use the found endpoints
|
||||||
func NewRelyingPartyOIDC(issuer, clientID, clientSecret, redirectURI string, scopes []string, options ...Option) (RelyingParty, error) {
|
func NewRelyingPartyOIDC(issuer, clientID, clientSecret, redirectURI string, scopes []string, options ...Option) (RelyingParty, error) {
|
||||||
rp := &relyingParty{
|
rp := &relyingParty{
|
||||||
issuer: issuer,
|
issuer: issuer,
|
||||||
|
@ -197,7 +193,7 @@ func NewRelyingPartyOIDC(issuer, clientID, clientSecret, redirectURI string, sco
|
||||||
return rp, nil
|
return rp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Option is the type for providing dynamic options to the relyingParty
|
// Option is the type for providing dynamic options to the relyingParty
|
||||||
type Option func(*relyingParty) error
|
type Option func(*relyingParty) error
|
||||||
|
|
||||||
func WithCustomDiscoveryUrl(url string) Option {
|
func WithCustomDiscoveryUrl(url string) Option {
|
||||||
|
@ -207,7 +203,7 @@ func WithCustomDiscoveryUrl(url string) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithCookieHandler set a `CookieHandler` for securing the various redirects
|
// WithCookieHandler set a `CookieHandler` for securing the various redirects
|
||||||
func WithCookieHandler(cookieHandler *httphelper.CookieHandler) Option {
|
func WithCookieHandler(cookieHandler *httphelper.CookieHandler) Option {
|
||||||
return func(rp *relyingParty) error {
|
return func(rp *relyingParty) error {
|
||||||
rp.cookieHandler = cookieHandler
|
rp.cookieHandler = cookieHandler
|
||||||
|
@ -215,9 +211,9 @@ func WithCookieHandler(cookieHandler *httphelper.CookieHandler) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithPKCE sets the RP to use PKCE (oauth2 code challenge)
|
// WithPKCE sets the RP to use PKCE (oauth2 code challenge)
|
||||||
//it also sets a `CookieHandler` for securing the various redirects
|
// it also sets a `CookieHandler` for securing the various redirects
|
||||||
//and exchanging the code challenge
|
// and exchanging the code challenge
|
||||||
func WithPKCE(cookieHandler *httphelper.CookieHandler) Option {
|
func WithPKCE(cookieHandler *httphelper.CookieHandler) Option {
|
||||||
return func(rp *relyingParty) error {
|
return func(rp *relyingParty) error {
|
||||||
rp.pkce = true
|
rp.pkce = true
|
||||||
|
@ -226,7 +222,7 @@ func WithPKCE(cookieHandler *httphelper.CookieHandler) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithHTTPClient provides the ability to set an http client to be used for the relaying party and verifier
|
// WithHTTPClient provides the ability to set an http client to be used for the relaying party and verifier
|
||||||
func WithHTTPClient(client *http.Client) Option {
|
func WithHTTPClient(client *http.Client) Option {
|
||||||
return func(rp *relyingParty) error {
|
return func(rp *relyingParty) error {
|
||||||
rp.httpClient = client
|
rp.httpClient = client
|
||||||
|
@ -297,7 +293,7 @@ func SignerFromKeyAndKeyID(key []byte, keyID string) SignerFromKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Discover calls the discovery endpoint of the provided issuer and returns the found endpoints
|
// Discover calls the discovery endpoint of the provided issuer and returns the found endpoints
|
||||||
//
|
//
|
||||||
//deprecated: use client.Discover
|
//deprecated: use client.Discover
|
||||||
func Discover(issuer string, httpClient *http.Client) (Endpoints, error) {
|
func Discover(issuer string, httpClient *http.Client) (Endpoints, error) {
|
||||||
|
@ -317,7 +313,7 @@ func Discover(issuer string, httpClient *http.Client) (Endpoints, error) {
|
||||||
return GetEndpoints(discoveryConfig), nil
|
return GetEndpoints(discoveryConfig), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthURL returns the auth request url
|
// AuthURL returns the auth request url
|
||||||
//(wrapping the oauth2 `AuthCodeURL`)
|
//(wrapping the oauth2 `AuthCodeURL`)
|
||||||
func AuthURL(state string, rp RelyingParty, opts ...AuthURLOpt) string {
|
func AuthURL(state string, rp RelyingParty, opts ...AuthURLOpt) string {
|
||||||
authOpts := make([]oauth2.AuthCodeOption, 0)
|
authOpts := make([]oauth2.AuthCodeOption, 0)
|
||||||
|
@ -327,8 +323,8 @@ func AuthURL(state string, rp RelyingParty, opts ...AuthURLOpt) string {
|
||||||
return rp.OAuthConfig().AuthCodeURL(state, authOpts...)
|
return rp.OAuthConfig().AuthCodeURL(state, authOpts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthURLHandler extends the `AuthURL` method with a http redirect handler
|
// AuthURLHandler extends the `AuthURL` method with a http redirect handler
|
||||||
//including handling setting cookie for secure `state` transfer
|
// including handling setting cookie for secure `state` transfer
|
||||||
func AuthURLHandler(stateFn func() string, rp RelyingParty) http.HandlerFunc {
|
func AuthURLHandler(stateFn func() string, rp RelyingParty) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
opts := make([]AuthURLOpt, 0)
|
opts := make([]AuthURLOpt, 0)
|
||||||
|
@ -349,7 +345,7 @@ func AuthURLHandler(stateFn func() string, rp RelyingParty) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//GenerateAndStoreCodeChallenge generates a PKCE code challenge and stores its verifier into a secure cookie
|
// GenerateAndStoreCodeChallenge generates a PKCE code challenge and stores its verifier into a secure cookie
|
||||||
func GenerateAndStoreCodeChallenge(w http.ResponseWriter, rp RelyingParty) (string, error) {
|
func GenerateAndStoreCodeChallenge(w http.ResponseWriter, rp RelyingParty) (string, error) {
|
||||||
codeVerifier := base64.RawURLEncoding.EncodeToString([]byte(uuid.New().String()))
|
codeVerifier := base64.RawURLEncoding.EncodeToString([]byte(uuid.New().String()))
|
||||||
if err := rp.CookieHandler().SetCookie(w, pkceCode, codeVerifier); err != nil {
|
if err := rp.CookieHandler().SetCookie(w, pkceCode, codeVerifier); err != nil {
|
||||||
|
@ -358,8 +354,8 @@ func GenerateAndStoreCodeChallenge(w http.ResponseWriter, rp RelyingParty) (stri
|
||||||
return oidc.NewSHACodeChallenge(codeVerifier), nil
|
return oidc.NewSHACodeChallenge(codeVerifier), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//CodeExchange handles the oauth2 code exchange, extracting and validating the id_token
|
// CodeExchange handles the oauth2 code exchange, extracting and validating the id_token
|
||||||
//returning it parsed together with the oauth2 tokens (access, refresh)
|
// returning it parsed together with the oauth2 tokens (access, refresh)
|
||||||
func CodeExchange(ctx context.Context, code string, rp RelyingParty, opts ...CodeExchangeOpt) (tokens *oidc.Tokens, err error) {
|
func CodeExchange(ctx context.Context, code string, rp RelyingParty, opts ...CodeExchangeOpt) (tokens *oidc.Tokens, err error) {
|
||||||
ctx = context.WithValue(ctx, oauth2.HTTPClient, rp.HttpClient())
|
ctx = context.WithValue(ctx, oauth2.HTTPClient, rp.HttpClient())
|
||||||
codeOpts := make([]oauth2.AuthCodeOption, 0)
|
codeOpts := make([]oauth2.AuthCodeOption, 0)
|
||||||
|
@ -391,9 +387,9 @@ func CodeExchange(ctx context.Context, code string, rp RelyingParty, opts ...Cod
|
||||||
|
|
||||||
type CodeExchangeCallback func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp RelyingParty)
|
type CodeExchangeCallback func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp RelyingParty)
|
||||||
|
|
||||||
//CodeExchangeHandler extends the `CodeExchange` method with a http handler
|
// CodeExchangeHandler extends the `CodeExchange` method with a http handler
|
||||||
//including cookie handling for secure `state` transfer
|
// including cookie handling for secure `state` transfer
|
||||||
//and optional PKCE code verifier checking
|
// and optional PKCE code verifier checking
|
||||||
func CodeExchangeHandler(callback CodeExchangeCallback, rp RelyingParty) http.HandlerFunc {
|
func CodeExchangeHandler(callback CodeExchangeCallback, rp RelyingParty) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
state, err := tryReadStateCookie(w, r, rp)
|
state, err := tryReadStateCookie(w, r, rp)
|
||||||
|
@ -434,9 +430,9 @@ func CodeExchangeHandler(callback CodeExchangeCallback, rp RelyingParty) http.Ha
|
||||||
|
|
||||||
type CodeExchangeUserinfoCallback func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, provider RelyingParty, info oidc.UserInfo)
|
type CodeExchangeUserinfoCallback func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, provider RelyingParty, info oidc.UserInfo)
|
||||||
|
|
||||||
//UserinfoCallback wraps the callback function of the CodeExchangeHandler
|
// UserinfoCallback wraps the callback function of the CodeExchangeHandler
|
||||||
//and calls the userinfo endpoint with the access token
|
// and calls the userinfo endpoint with the access token
|
||||||
//on success it will pass the userinfo into its callback function as well
|
// on success it will pass the userinfo into its callback function as well
|
||||||
func UserinfoCallback(f CodeExchangeUserinfoCallback) CodeExchangeCallback {
|
func UserinfoCallback(f CodeExchangeUserinfoCallback) CodeExchangeCallback {
|
||||||
return func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp RelyingParty) {
|
return func(w http.ResponseWriter, r *http.Request, tokens *oidc.Tokens, state string, rp RelyingParty) {
|
||||||
info, err := Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.GetSubject(), rp)
|
info, err := Userinfo(tokens.AccessToken, tokens.TokenType, tokens.IDTokenClaims.GetSubject(), rp)
|
||||||
|
@ -448,7 +444,7 @@ func UserinfoCallback(f CodeExchangeUserinfoCallback) CodeExchangeCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Userinfo will call the OIDC Userinfo Endpoint with the provided token
|
// Userinfo will call the OIDC Userinfo Endpoint with the provided token
|
||||||
func Userinfo(token, tokenType, subject string, rp RelyingParty) (oidc.UserInfo, error) {
|
func Userinfo(token, tokenType, subject string, rp RelyingParty) (oidc.UserInfo, error) {
|
||||||
req, err := http.NewRequest("GET", rp.UserinfoEndpoint(), nil)
|
req, err := http.NewRequest("GET", rp.UserinfoEndpoint(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -512,7 +508,7 @@ func GetEndpoints(discoveryConfig *oidc.DiscoveryConfiguration) Endpoints {
|
||||||
|
|
||||||
type AuthURLOpt func() []oauth2.AuthCodeOption
|
type AuthURLOpt func() []oauth2.AuthCodeOption
|
||||||
|
|
||||||
//WithCodeChallenge sets the `code_challenge` params in the auth request
|
// WithCodeChallenge sets the `code_challenge` params in the auth request
|
||||||
func WithCodeChallenge(codeChallenge string) AuthURLOpt {
|
func WithCodeChallenge(codeChallenge string) AuthURLOpt {
|
||||||
return func() []oauth2.AuthCodeOption {
|
return func() []oauth2.AuthCodeOption {
|
||||||
return []oauth2.AuthCodeOption{
|
return []oauth2.AuthCodeOption{
|
||||||
|
@ -522,7 +518,7 @@ func WithCodeChallenge(codeChallenge string) AuthURLOpt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithPrompt sets the `prompt` params in the auth request
|
// WithPrompt sets the `prompt` params in the auth request
|
||||||
func WithPrompt(prompt ...string) AuthURLOpt {
|
func WithPrompt(prompt ...string) AuthURLOpt {
|
||||||
return func() []oauth2.AuthCodeOption {
|
return func() []oauth2.AuthCodeOption {
|
||||||
return []oauth2.AuthCodeOption{
|
return []oauth2.AuthCodeOption{
|
||||||
|
@ -533,14 +529,14 @@ func WithPrompt(prompt ...string) AuthURLOpt {
|
||||||
|
|
||||||
type CodeExchangeOpt func() []oauth2.AuthCodeOption
|
type CodeExchangeOpt func() []oauth2.AuthCodeOption
|
||||||
|
|
||||||
//WithCodeVerifier sets the `code_verifier` param in the token request
|
// WithCodeVerifier sets the `code_verifier` param in the token request
|
||||||
func WithCodeVerifier(codeVerifier string) CodeExchangeOpt {
|
func WithCodeVerifier(codeVerifier string) CodeExchangeOpt {
|
||||||
return func() []oauth2.AuthCodeOption {
|
return func() []oauth2.AuthCodeOption {
|
||||||
return []oauth2.AuthCodeOption{oauth2.SetAuthURLParam("code_verifier", codeVerifier)}
|
return []oauth2.AuthCodeOption{oauth2.SetAuthURLParam("code_verifier", codeVerifier)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithClientAssertionJWT sets the `client_assertion` param in the token request
|
// WithClientAssertionJWT sets the `client_assertion` param in the token request
|
||||||
func WithClientAssertionJWT(clientAssertion string) CodeExchangeOpt {
|
func WithClientAssertionJWT(clientAssertion string) CodeExchangeOpt {
|
||||||
return func() []oauth2.AuthCodeOption {
|
return func() []oauth2.AuthCodeOption {
|
||||||
return client.ClientAssertionCodeOptions(clientAssertion)
|
return client.ClientAssertionCodeOptions(clientAssertion)
|
||||||
|
|
|
@ -8,20 +8,20 @@ import (
|
||||||
"github.com/zitadel/oidc/pkg/oidc/grants/tokenexchange"
|
"github.com/zitadel/oidc/pkg/oidc/grants/tokenexchange"
|
||||||
)
|
)
|
||||||
|
|
||||||
//TokenExchangeRP extends the `RelyingParty` interface for the *draft* oauth2 `Token Exchange`
|
// TokenExchangeRP extends the `RelyingParty` interface for the *draft* oauth2 `Token Exchange`
|
||||||
type TokenExchangeRP interface {
|
type TokenExchangeRP interface {
|
||||||
RelyingParty
|
RelyingParty
|
||||||
|
|
||||||
//TokenExchange implement the `Token Exchange Grant` exchanging some token for an other
|
// TokenExchange implement the `Token Exchange Grant` exchanging some token for an other
|
||||||
TokenExchange(context.Context, *tokenexchange.TokenExchangeRequest) (*oauth2.Token, error)
|
TokenExchange(context.Context, *tokenexchange.TokenExchangeRequest) (*oauth2.Token, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
//DelegationTokenExchangeRP extends the `TokenExchangeRP` interface
|
// DelegationTokenExchangeRP extends the `TokenExchangeRP` interface
|
||||||
//for the specific `delegation token` request
|
// for the specific `delegation token` request
|
||||||
type DelegationTokenExchangeRP interface {
|
type DelegationTokenExchangeRP interface {
|
||||||
TokenExchangeRP
|
TokenExchangeRP
|
||||||
|
|
||||||
//DelegationTokenExchange implement the `Token Exchange Grant`
|
// DelegationTokenExchange implement the `Token Exchange Grant`
|
||||||
//providing an access token in request for a `delegation` token for a given resource / audience
|
// providing an access token in request for a `delegation` token for a given resource / audience
|
||||||
DelegationTokenExchange(context.Context, string, ...tokenexchange.TokenExchangeOption) (*oauth2.Token, error)
|
DelegationTokenExchange(context.Context, string, ...tokenexchange.TokenExchangeOption) (*oauth2.Token, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ type IDTokenVerifier interface {
|
||||||
MaxAge() time.Duration
|
MaxAge() time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
//VerifyTokens implement the Token Response Validation as defined in OIDC specification
|
// VerifyTokens implement the Token Response Validation as defined in OIDC specification
|
||||||
//https://openid.net/specs/openid-connect-core-1_0.html#TokenResponseValidation
|
//https://openid.net/specs/openid-connect-core-1_0.html#TokenResponseValidation
|
||||||
func VerifyTokens(ctx context.Context, accessToken, idTokenString string, v IDTokenVerifier) (oidc.IDTokenClaims, error) {
|
func VerifyTokens(ctx context.Context, accessToken, idTokenString string, v IDTokenVerifier) (oidc.IDTokenClaims, error) {
|
||||||
idToken, err := VerifyIDToken(ctx, idTokenString, v)
|
idToken, err := VerifyIDToken(ctx, idTokenString, v)
|
||||||
|
@ -32,7 +32,7 @@ func VerifyTokens(ctx context.Context, accessToken, idTokenString string, v IDTo
|
||||||
return idToken, nil
|
return idToken, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//VerifyIDToken validates the id token according to
|
// VerifyIDToken validates the id token according to
|
||||||
//https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
//https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
||||||
func VerifyIDToken(ctx context.Context, token string, v IDTokenVerifier) (oidc.IDTokenClaims, error) {
|
func VerifyIDToken(ctx context.Context, token string, v IDTokenVerifier) (oidc.IDTokenClaims, error) {
|
||||||
claims := oidc.EmptyIDTokenClaims()
|
claims := oidc.EmptyIDTokenClaims()
|
||||||
|
@ -88,7 +88,7 @@ func VerifyIDToken(ctx context.Context, token string, v IDTokenVerifier) (oidc.I
|
||||||
return claims, nil
|
return claims, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//VerifyAccessToken validates the access token according to
|
// VerifyAccessToken validates the access token according to
|
||||||
//https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowTokenValidation
|
//https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowTokenValidation
|
||||||
func VerifyAccessToken(accessToken, atHash string, sigAlgorithm jose.SignatureAlgorithm) error {
|
func VerifyAccessToken(accessToken, atHash string, sigAlgorithm jose.SignatureAlgorithm) error {
|
||||||
if atHash == "" {
|
if atHash == "" {
|
||||||
|
@ -105,8 +105,8 @@ func VerifyAccessToken(accessToken, atHash string, sigAlgorithm jose.SignatureAl
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewIDTokenVerifier returns an implementation of `IDTokenVerifier`
|
// NewIDTokenVerifier returns an implementation of `IDTokenVerifier`
|
||||||
//for `VerifyTokens` and `VerifyIDToken`
|
// for `VerifyTokens` and `VerifyIDToken`
|
||||||
func NewIDTokenVerifier(issuer, clientID string, keySet oidc.KeySet, options ...VerifierOption) IDTokenVerifier {
|
func NewIDTokenVerifier(issuer, clientID string, keySet oidc.KeySet, options ...VerifierOption) IDTokenVerifier {
|
||||||
v := &idTokenVerifier{
|
v := &idTokenVerifier{
|
||||||
issuer: issuer,
|
issuer: issuer,
|
||||||
|
@ -125,46 +125,46 @@ func NewIDTokenVerifier(issuer, clientID string, keySet oidc.KeySet, options ...
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
//VerifierOption is the type for providing dynamic options to the IDTokenVerifier
|
// VerifierOption is the type for providing dynamic options to the IDTokenVerifier
|
||||||
type VerifierOption func(*idTokenVerifier)
|
type VerifierOption func(*idTokenVerifier)
|
||||||
|
|
||||||
//WithIssuedAtOffset mitigates the risk of iat to be in the future
|
// 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
|
// because of clock skews with the ability to add an offset to the current time
|
||||||
func WithIssuedAtOffset(offset time.Duration) func(*idTokenVerifier) {
|
func WithIssuedAtOffset(offset time.Duration) func(*idTokenVerifier) {
|
||||||
return func(v *idTokenVerifier) {
|
return func(v *idTokenVerifier) {
|
||||||
v.offset = offset
|
v.offset = offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithIssuedAtMaxAge provides the ability to define the maximum duration between iat and now
|
// WithIssuedAtMaxAge provides the ability to define the maximum duration between iat and now
|
||||||
func WithIssuedAtMaxAge(maxAge time.Duration) func(*idTokenVerifier) {
|
func WithIssuedAtMaxAge(maxAge time.Duration) func(*idTokenVerifier) {
|
||||||
return func(v *idTokenVerifier) {
|
return func(v *idTokenVerifier) {
|
||||||
v.maxAge = maxAge
|
v.maxAge = maxAge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithNonce sets the function to check the nonce
|
// WithNonce sets the function to check the nonce
|
||||||
func WithNonce(nonce func(context.Context) string) VerifierOption {
|
func WithNonce(nonce func(context.Context) string) VerifierOption {
|
||||||
return func(v *idTokenVerifier) {
|
return func(v *idTokenVerifier) {
|
||||||
v.nonce = nonce
|
v.nonce = nonce
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithACRVerifier sets the verifier for the acr claim
|
// WithACRVerifier sets the verifier for the acr claim
|
||||||
func WithACRVerifier(verifier oidc.ACRVerifier) VerifierOption {
|
func WithACRVerifier(verifier oidc.ACRVerifier) VerifierOption {
|
||||||
return func(v *idTokenVerifier) {
|
return func(v *idTokenVerifier) {
|
||||||
v.acr = verifier
|
v.acr = verifier
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithAuthTimeMaxAge provides the ability to define the maximum duration between auth_time and now
|
// WithAuthTimeMaxAge provides the ability to define the maximum duration between auth_time and now
|
||||||
func WithAuthTimeMaxAge(maxAge time.Duration) VerifierOption {
|
func WithAuthTimeMaxAge(maxAge time.Duration) VerifierOption {
|
||||||
return func(v *idTokenVerifier) {
|
return func(v *idTokenVerifier) {
|
||||||
v.maxAge = maxAge
|
v.maxAge = maxAge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithSupportedSigningAlgorithms overwrites the default RS256 signing algorithm
|
// WithSupportedSigningAlgorithms overwrites the default RS256 signing algorithm
|
||||||
func WithSupportedSigningAlgorithms(algs ...string) VerifierOption {
|
func WithSupportedSigningAlgorithms(algs ...string) VerifierOption {
|
||||||
return func(v *idTokenVerifier) {
|
return func(v *idTokenVerifier) {
|
||||||
v.supportedSignAlgs = algs
|
v.supportedSignAlgs = algs
|
||||||
|
|
|
@ -43,6 +43,7 @@ func NewResourceServerClientCredentials(issuer, clientID, clientSecret string, o
|
||||||
}
|
}
|
||||||
return newResourceServer(issuer, authorizer, option...)
|
return newResourceServer(issuer, authorizer, option...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewResourceServerJWTProfile(issuer, clientID, keyID string, key []byte, options ...Option) (ResourceServer, error) {
|
func NewResourceServerJWTProfile(issuer, clientID, keyID string, key []byte, options ...Option) (ResourceServer, error) {
|
||||||
signer, err := client.NewSignerFromPrivateKeyByte(key, keyID)
|
signer, err := client.NewSignerFromPrivateKeyByte(key, keyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -91,14 +92,14 @@ func NewResourceServerFromKeyFile(issuer, path string, options ...Option) (Resou
|
||||||
|
|
||||||
type Option func(*resourceServer)
|
type Option func(*resourceServer)
|
||||||
|
|
||||||
//WithClient provides the ability to set an http client to be used for the resource server
|
// WithClient provides the ability to set an http client to be used for the resource server
|
||||||
func WithClient(client *http.Client) Option {
|
func WithClient(client *http.Client) Option {
|
||||||
return func(server *resourceServer) {
|
return func(server *resourceServer) {
|
||||||
server.httpClient = client
|
server.httpClient = client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//WithStaticEndpoints provides the ability to set static token and introspect URL
|
// WithStaticEndpoints provides the ability to set static token and introspect URL
|
||||||
func WithStaticEndpoints(tokenURL, introspectURL string) Option {
|
func WithStaticEndpoints(tokenURL, introspectURL string) Option {
|
||||||
return func(server *resourceServer) {
|
return func(server *resourceServer) {
|
||||||
server.tokenURL = tokenURL
|
server.tokenURL = tokenURL
|
||||||
|
|
|
@ -9,9 +9,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ErrCipherTextBlockSize = errors.New("ciphertext block size is too short")
|
||||||
ErrCipherTextBlockSize = errors.New("ciphertext block size is too short")
|
|
||||||
)
|
|
||||||
|
|
||||||
func EncryptAES(data string, key string) (string, error) {
|
func EncryptAES(data string, key string) (string, error) {
|
||||||
encrypted, err := EncryptBytesAES([]byte(data), key)
|
encrypted, err := EncryptBytesAES([]byte(data), key)
|
||||||
|
|
|
@ -11,9 +11,7 @@ import (
|
||||||
"gopkg.in/square/go-jose.v2"
|
"gopkg.in/square/go-jose.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ErrUnsupportedAlgorithm = errors.New("unsupported signing algorithm")
|
||||||
ErrUnsupportedAlgorithm = errors.New("unsupported signing algorithm")
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetHashAlgorithm(sigAlgorithm jose.SignatureAlgorithm) (hash.Hash, error) {
|
func GetHashAlgorithm(sigAlgorithm jose.SignatureAlgorithm) (hash.Hash, error) {
|
||||||
switch sigAlgorithm {
|
switch sigAlgorithm {
|
||||||
|
|
|
@ -12,15 +12,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var DefaultHTTPClient = &http.Client{
|
||||||
DefaultHTTPClient = &http.Client{
|
Timeout: 30 * time.Second,
|
||||||
Timeout: 30 * time.Second,
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type Decoder interface {
|
type Decoder interface {
|
||||||
Decode(dst interface{}, src map[string][]string) error
|
Decode(dst interface{}, src map[string][]string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Encoder interface {
|
type Encoder interface {
|
||||||
Encode(src interface{}, dst map[string][]string) error
|
Encode(src interface{}, dst map[string][]string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
package oidc
|
package oidc
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//ScopeOpenID defines the scope `openid`
|
// ScopeOpenID defines the scope `openid`
|
||||||
//OpenID Connect requests MUST contain the `openid` scope value
|
// OpenID Connect requests MUST contain the `openid` scope value
|
||||||
ScopeOpenID = "openid"
|
ScopeOpenID = "openid"
|
||||||
|
|
||||||
//ScopeProfile defines the scope `profile`
|
// ScopeProfile defines the scope `profile`
|
||||||
//This (optional) scope value requests access to the End-User's default profile Claims,
|
// This (optional) scope value requests access to the End-User's default profile Claims,
|
||||||
//which are: name, family_name, given_name, middle_name, nickname, preferred_username,
|
// which are: name, family_name, given_name, middle_name, nickname, preferred_username,
|
||||||
//profile, picture, website, gender, birthdate, zoneinfo, locale, and updated_at.
|
// profile, picture, website, gender, birthdate, zoneinfo, locale, and updated_at.
|
||||||
ScopeProfile = "profile"
|
ScopeProfile = "profile"
|
||||||
|
|
||||||
//ScopeEmail defines the scope `email`
|
// ScopeEmail defines the scope `email`
|
||||||
//This (optional) scope value requests access to the email and email_verified Claims.
|
// This (optional) scope value requests access to the email and email_verified Claims.
|
||||||
ScopeEmail = "email"
|
ScopeEmail = "email"
|
||||||
|
|
||||||
//ScopeAddress defines the scope `address`
|
// ScopeAddress defines the scope `address`
|
||||||
//This (optional) scope value requests access to the address Claim.
|
// This (optional) scope value requests access to the address Claim.
|
||||||
ScopeAddress = "address"
|
ScopeAddress = "address"
|
||||||
|
|
||||||
//ScopePhone defines the scope `phone`
|
// ScopePhone defines the scope `phone`
|
||||||
//This (optional) scope value requests access to the phone_number and phone_number_verified Claims.
|
// This (optional) scope value requests access to the phone_number and phone_number_verified Claims.
|
||||||
ScopePhone = "phone"
|
ScopePhone = "phone"
|
||||||
|
|
||||||
//ScopeOfflineAccess defines the scope `offline_access`
|
// ScopeOfflineAccess defines the scope `offline_access`
|
||||||
//This (optional) scope value requests that an OAuth 2.0 Refresh Token be issued that can be used to obtain an Access Token
|
// This (optional) scope value requests that an OAuth 2.0 Refresh Token be issued that can be used to obtain an Access Token
|
||||||
//that grants access to the End-User's UserInfo Endpoint even when the End-User is not present (not logged in).
|
// that grants access to the End-User's UserInfo Endpoint even when the End-User is not present (not logged in).
|
||||||
ScopeOfflineAccess = "offline_access"
|
ScopeOfflineAccess = "offline_access"
|
||||||
|
|
||||||
//ResponseTypeCode for the Authorization Code Flow returning a code from the Authorization Server
|
// ResponseTypeCode for the Authorization Code Flow returning a code from the Authorization Server
|
||||||
ResponseTypeCode ResponseType = "code"
|
ResponseTypeCode ResponseType = "code"
|
||||||
|
|
||||||
//ResponseTypeIDToken for the Implicit Flow returning id and access tokens directly from the Authorization Server
|
// ResponseTypeIDToken for the Implicit Flow returning id and access tokens directly from the Authorization Server
|
||||||
ResponseTypeIDToken ResponseType = "id_token token"
|
ResponseTypeIDToken ResponseType = "id_token token"
|
||||||
|
|
||||||
//ResponseTypeIDTokenOnly for the Implicit Flow returning only id token directly from the Authorization Server
|
// ResponseTypeIDTokenOnly for the Implicit Flow returning only id token directly from the Authorization Server
|
||||||
ResponseTypeIDTokenOnly ResponseType = "id_token"
|
ResponseTypeIDTokenOnly ResponseType = "id_token"
|
||||||
|
|
||||||
DisplayPage Display = "page"
|
DisplayPage Display = "page"
|
||||||
|
@ -45,21 +45,21 @@ const (
|
||||||
ResponseModeQuery ResponseMode = "query"
|
ResponseModeQuery ResponseMode = "query"
|
||||||
ResponseModeFragment ResponseMode = "fragment"
|
ResponseModeFragment ResponseMode = "fragment"
|
||||||
|
|
||||||
//PromptNone (`none`) disallows the Authorization Server to display any authentication or consent user interface pages.
|
// PromptNone (`none`) disallows the Authorization Server to display any authentication or consent user interface pages.
|
||||||
//An error (login_required, interaction_required, ...) will be returned if the user is not already authenticated or consent is needed
|
// An error (login_required, interaction_required, ...) will be returned if the user is not already authenticated or consent is needed
|
||||||
PromptNone = "none"
|
PromptNone = "none"
|
||||||
|
|
||||||
//PromptLogin (`login`) directs the Authorization Server to prompt the End-User for reauthentication.
|
// PromptLogin (`login`) directs the Authorization Server to prompt the End-User for reauthentication.
|
||||||
PromptLogin = "login"
|
PromptLogin = "login"
|
||||||
|
|
||||||
//PromptConsent (`consent`) directs the Authorization Server to prompt the End-User for consent (of sharing information).
|
// PromptConsent (`consent`) directs the Authorization Server to prompt the End-User for consent (of sharing information).
|
||||||
PromptConsent = "consent"
|
PromptConsent = "consent"
|
||||||
|
|
||||||
//PromptSelectAccount (`select_account `) directs the Authorization Server to prompt the End-User to select a user account (to enable multi user / session switching)
|
// PromptSelectAccount (`select_account `) directs the Authorization Server to prompt the End-User to select a user account (to enable multi user / session switching)
|
||||||
PromptSelectAccount = "select_account"
|
PromptSelectAccount = "select_account"
|
||||||
)
|
)
|
||||||
|
|
||||||
//AuthRequest according to:
|
// AuthRequest according to:
|
||||||
//https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
//https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
||||||
type AuthRequest struct {
|
type AuthRequest struct {
|
||||||
Scopes SpaceDelimitedArray `json:"scope" schema:"scope"`
|
Scopes SpaceDelimitedArray `json:"scope" schema:"scope"`
|
||||||
|
@ -82,21 +82,21 @@ type AuthRequest struct {
|
||||||
CodeChallenge string `json:"code_challenge" schema:"code_challenge"`
|
CodeChallenge string `json:"code_challenge" schema:"code_challenge"`
|
||||||
CodeChallengeMethod CodeChallengeMethod `json:"code_challenge_method" schema:"code_challenge_method"`
|
CodeChallengeMethod CodeChallengeMethod `json:"code_challenge_method" schema:"code_challenge_method"`
|
||||||
|
|
||||||
//RequestParam enables OIDC requests to be passed in a single, self-contained parameter (as JWT, called Request Object)
|
// RequestParam enables OIDC requests to be passed in a single, self-contained parameter (as JWT, called Request Object)
|
||||||
RequestParam string `schema:"request"`
|
RequestParam string `schema:"request"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetRedirectURI returns the redirect_uri value for the ErrAuthRequest interface
|
// GetRedirectURI returns the redirect_uri value for the ErrAuthRequest interface
|
||||||
func (a *AuthRequest) GetRedirectURI() string {
|
func (a *AuthRequest) GetRedirectURI() string {
|
||||||
return a.RedirectURI
|
return a.RedirectURI
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetResponseType returns the response_type value for the ErrAuthRequest interface
|
// GetResponseType returns the response_type value for the ErrAuthRequest interface
|
||||||
func (a *AuthRequest) GetResponseType() ResponseType {
|
func (a *AuthRequest) GetResponseType() ResponseType {
|
||||||
return a.ResponseType
|
return a.ResponseType
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetState returns the optional state value for the ErrAuthRequest interface
|
// GetState returns the optional state value for the ErrAuthRequest interface
|
||||||
func (a *AuthRequest) GetState() string {
|
func (a *AuthRequest) GetState() string {
|
||||||
return a.State
|
return a.State
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,143 +9,143 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type DiscoveryConfiguration struct {
|
type DiscoveryConfiguration struct {
|
||||||
//Issuer is the identifier of the OP and is used in the tokens as `iss` claim.
|
// Issuer is the identifier of the OP and is used in the tokens as `iss` claim.
|
||||||
Issuer string `json:"issuer,omitempty"`
|
Issuer string `json:"issuer,omitempty"`
|
||||||
|
|
||||||
//AuthorizationEndpoint is the URL of the OAuth 2.0 Authorization Endpoint where all user interactive login start
|
// AuthorizationEndpoint is the URL of the OAuth 2.0 Authorization Endpoint where all user interactive login start
|
||||||
AuthorizationEndpoint string `json:"authorization_endpoint,omitempty"`
|
AuthorizationEndpoint string `json:"authorization_endpoint,omitempty"`
|
||||||
|
|
||||||
//TokenEndpoint is the URL of the OAuth 2.0 Token Endpoint where all tokens are issued, except when using Implicit Flow
|
// TokenEndpoint is the URL of the OAuth 2.0 Token Endpoint where all tokens are issued, except when using Implicit Flow
|
||||||
TokenEndpoint string `json:"token_endpoint,omitempty"`
|
TokenEndpoint string `json:"token_endpoint,omitempty"`
|
||||||
|
|
||||||
//IntrospectionEndpoint is the URL of the OAuth 2.0 Introspection Endpoint.
|
// IntrospectionEndpoint is the URL of the OAuth 2.0 Introspection Endpoint.
|
||||||
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
|
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
|
||||||
|
|
||||||
//UserinfoEndpoint is the URL where an access_token can be used to retrieve the Userinfo.
|
// UserinfoEndpoint is the URL where an access_token can be used to retrieve the Userinfo.
|
||||||
UserinfoEndpoint string `json:"userinfo_endpoint,omitempty"`
|
UserinfoEndpoint string `json:"userinfo_endpoint,omitempty"`
|
||||||
|
|
||||||
//RevocationEndpoint is the URL of the OAuth 2.0 Revocation Endpoint.
|
// RevocationEndpoint is the URL of the OAuth 2.0 Revocation Endpoint.
|
||||||
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
|
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
|
||||||
|
|
||||||
//EndSessionEndpoint is a URL where the RP can perform a redirect to request that the End-User be logged out at the OP.
|
// EndSessionEndpoint is a URL where the RP can perform a redirect to request that the End-User be logged out at the OP.
|
||||||
EndSessionEndpoint string `json:"end_session_endpoint,omitempty"`
|
EndSessionEndpoint string `json:"end_session_endpoint,omitempty"`
|
||||||
|
|
||||||
//CheckSessionIframe is a URL where the OP provides an iframe that support cross-origin communications for session state information with the RP Client.
|
// CheckSessionIframe is a URL where the OP provides an iframe that support cross-origin communications for session state information with the RP Client.
|
||||||
CheckSessionIframe string `json:"check_session_iframe,omitempty"`
|
CheckSessionIframe string `json:"check_session_iframe,omitempty"`
|
||||||
|
|
||||||
//JwksURI is the URL of the JSON Web Key Set. This site contains the signing keys that RPs can use to validate the signature.
|
// JwksURI is the URL of the JSON Web Key Set. This site contains the signing keys that RPs can use to validate the signature.
|
||||||
//It may also contain the OP's encryption keys that RPs can use to encrypt request to the OP.
|
// It may also contain the OP's encryption keys that RPs can use to encrypt request to the OP.
|
||||||
JwksURI string `json:"jwks_uri,omitempty"`
|
JwksURI string `json:"jwks_uri,omitempty"`
|
||||||
|
|
||||||
//RegistrationEndpoint is the URL for the Dynamic Client Registration.
|
// RegistrationEndpoint is the URL for the Dynamic Client Registration.
|
||||||
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
|
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
|
||||||
|
|
||||||
//ScopesSupported lists an array of supported scopes. This list must not include every supported scope by the OP.
|
// ScopesSupported lists an array of supported scopes. This list must not include every supported scope by the OP.
|
||||||
ScopesSupported []string `json:"scopes_supported,omitempty"`
|
ScopesSupported []string `json:"scopes_supported,omitempty"`
|
||||||
|
|
||||||
//ResponseTypesSupported contains a list of the OAuth 2.0 response_type values that the OP supports (code, id_token, token id_token, ...).
|
// ResponseTypesSupported contains a list of the OAuth 2.0 response_type values that the OP supports (code, id_token, token id_token, ...).
|
||||||
ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
|
ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
|
||||||
|
|
||||||
//ResponseModesSupported contains a list of the OAuth 2.0 response_mode values that the OP supports. If omitted, the default value is ["query", "fragment"].
|
// ResponseModesSupported contains a list of the OAuth 2.0 response_mode values that the OP supports. If omitted, the default value is ["query", "fragment"].
|
||||||
ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
|
ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
|
||||||
|
|
||||||
//GrantTypesSupported contains a list of the OAuth 2.0 grant_type values that the OP supports. If omitted, the default value is ["authorization_code", "implicit"].
|
// GrantTypesSupported contains a list of the OAuth 2.0 grant_type values that the OP supports. If omitted, the default value is ["authorization_code", "implicit"].
|
||||||
GrantTypesSupported []GrantType `json:"grant_types_supported,omitempty"`
|
GrantTypesSupported []GrantType `json:"grant_types_supported,omitempty"`
|
||||||
|
|
||||||
//ACRValuesSupported contains a list of Authentication Context Class References that the OP supports.
|
// ACRValuesSupported contains a list of Authentication Context Class References that the OP supports.
|
||||||
ACRValuesSupported []string `json:"acr_values_supported,omitempty"`
|
ACRValuesSupported []string `json:"acr_values_supported,omitempty"`
|
||||||
|
|
||||||
//SubjectTypesSupported contains a list of Subject Identifier types that the OP supports (pairwise, public).
|
// SubjectTypesSupported contains a list of Subject Identifier types that the OP supports (pairwise, public).
|
||||||
SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
|
SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
|
||||||
|
|
||||||
//IDTokenSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the OP for the ID Token.
|
// IDTokenSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the OP for the ID Token.
|
||||||
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"`
|
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"`
|
||||||
|
|
||||||
//IDTokenEncryptionAlgValuesSupported contains a list of JWE encryption algorithms (alg values) supported by the OP for the ID Token.
|
// IDTokenEncryptionAlgValuesSupported contains a list of JWE encryption algorithms (alg values) supported by the OP for the ID Token.
|
||||||
IDTokenEncryptionAlgValuesSupported []string `json:"id_token_encryption_alg_values_supported,omitempty"`
|
IDTokenEncryptionAlgValuesSupported []string `json:"id_token_encryption_alg_values_supported,omitempty"`
|
||||||
|
|
||||||
//IDTokenEncryptionEncValuesSupported contains a list of JWE encryption algorithms (enc values) supported by the OP for the ID Token.
|
// IDTokenEncryptionEncValuesSupported contains a list of JWE encryption algorithms (enc values) supported by the OP for the ID Token.
|
||||||
IDTokenEncryptionEncValuesSupported []string `json:"id_token_encryption_enc_values_supported,omitempty"`
|
IDTokenEncryptionEncValuesSupported []string `json:"id_token_encryption_enc_values_supported,omitempty"`
|
||||||
|
|
||||||
//UserinfoSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the OP for UserInfo Endpoint.
|
// UserinfoSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the OP for UserInfo Endpoint.
|
||||||
UserinfoSigningAlgValuesSupported []string `json:"userinfo_signing_alg_values_supported,omitempty"`
|
UserinfoSigningAlgValuesSupported []string `json:"userinfo_signing_alg_values_supported,omitempty"`
|
||||||
|
|
||||||
//UserinfoEncryptionAlgValuesSupported contains a list of JWE encryption algorithms (alg values) supported by the OP for the UserInfo Endpoint.
|
// UserinfoEncryptionAlgValuesSupported contains a list of JWE encryption algorithms (alg values) supported by the OP for the UserInfo Endpoint.
|
||||||
UserinfoEncryptionAlgValuesSupported []string `json:"userinfo_encryption_alg_values_supported,omitempty"`
|
UserinfoEncryptionAlgValuesSupported []string `json:"userinfo_encryption_alg_values_supported,omitempty"`
|
||||||
|
|
||||||
//UserinfoEncryptionEncValuesSupported contains a list of JWE encryption algorithms (enc values) supported by the OP for the UserInfo Endpoint.
|
// UserinfoEncryptionEncValuesSupported contains a list of JWE encryption algorithms (enc values) supported by the OP for the UserInfo Endpoint.
|
||||||
UserinfoEncryptionEncValuesSupported []string `json:"userinfo_encryption_enc_values_supported,omitempty"`
|
UserinfoEncryptionEncValuesSupported []string `json:"userinfo_encryption_enc_values_supported,omitempty"`
|
||||||
|
|
||||||
//RequestObjectSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the OP for Request Objects.
|
// RequestObjectSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the OP for Request Objects.
|
||||||
//These algorithms are used both then the Request Object is passed by value (using the request parameter) and when it is passed by reference (using the request_uri parameter).
|
// These algorithms are used both then the Request Object is passed by value (using the request parameter) and when it is passed by reference (using the request_uri parameter).
|
||||||
RequestObjectSigningAlgValuesSupported []string `json:"request_object_signing_alg_values_supported,omitempty"`
|
RequestObjectSigningAlgValuesSupported []string `json:"request_object_signing_alg_values_supported,omitempty"`
|
||||||
|
|
||||||
//RequestObjectEncryptionAlgValuesSupported contains a list of JWE encryption algorithms (alg values) supported by the OP for Request Objects.
|
// RequestObjectEncryptionAlgValuesSupported contains a list of JWE encryption algorithms (alg values) supported by the OP for Request Objects.
|
||||||
//These algorithms are used both when the Request Object is passed by value and by reference.
|
// These algorithms are used both when the Request Object is passed by value and by reference.
|
||||||
RequestObjectEncryptionAlgValuesSupported []string `json:"request_object_encryption_alg_values_supported,omitempty"`
|
RequestObjectEncryptionAlgValuesSupported []string `json:"request_object_encryption_alg_values_supported,omitempty"`
|
||||||
|
|
||||||
//RequestObjectEncryptionEncValuesSupported contains a list of JWE encryption algorithms (enc values) supported by the OP for Request Objects.
|
// RequestObjectEncryptionEncValuesSupported contains a list of JWE encryption algorithms (enc values) supported by the OP for Request Objects.
|
||||||
//These algorithms are used both when the Request Object is passed by value and by reference.
|
// These algorithms are used both when the Request Object is passed by value and by reference.
|
||||||
RequestObjectEncryptionEncValuesSupported []string `json:"request_object_encryption_enc_values_supported,omitempty"`
|
RequestObjectEncryptionEncValuesSupported []string `json:"request_object_encryption_enc_values_supported,omitempty"`
|
||||||
|
|
||||||
//TokenEndpointAuthMethodsSupported contains a list of Client Authentication methods supported by the Token Endpoint. If omitted, the default is client_secret_basic.
|
// TokenEndpointAuthMethodsSupported contains a list of Client Authentication methods supported by the Token Endpoint. If omitted, the default is client_secret_basic.
|
||||||
TokenEndpointAuthMethodsSupported []AuthMethod `json:"token_endpoint_auth_methods_supported,omitempty"`
|
TokenEndpointAuthMethodsSupported []AuthMethod `json:"token_endpoint_auth_methods_supported,omitempty"`
|
||||||
|
|
||||||
//TokenEndpointAuthSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the Token Endpoint
|
// TokenEndpointAuthSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the Token Endpoint
|
||||||
//for the signature of the JWT used to authenticate the Client by private_key_jwt and client_secret_jwt.
|
// for the signature of the JWT used to authenticate the Client by private_key_jwt and client_secret_jwt.
|
||||||
TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
|
TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
|
||||||
|
|
||||||
//RevocationEndpointAuthMethodsSupported contains a list of Client Authentication methods supported by the Revocation Endpoint. If omitted, the default is client_secret_basic.
|
// RevocationEndpointAuthMethodsSupported contains a list of Client Authentication methods supported by the Revocation Endpoint. If omitted, the default is client_secret_basic.
|
||||||
RevocationEndpointAuthMethodsSupported []AuthMethod `json:"revocation_endpoint_auth_methods_supported,omitempty"`
|
RevocationEndpointAuthMethodsSupported []AuthMethod `json:"revocation_endpoint_auth_methods_supported,omitempty"`
|
||||||
|
|
||||||
//RevocationEndpointAuthSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the Revocation Endpoint
|
// RevocationEndpointAuthSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the Revocation Endpoint
|
||||||
//for the signature of the JWT used to authenticate the Client by private_key_jwt and client_secret_jwt.
|
// for the signature of the JWT used to authenticate the Client by private_key_jwt and client_secret_jwt.
|
||||||
RevocationEndpointAuthSigningAlgValuesSupported []string `json:"revocation_endpoint_auth_signing_alg_values_supported,omitempty"`
|
RevocationEndpointAuthSigningAlgValuesSupported []string `json:"revocation_endpoint_auth_signing_alg_values_supported,omitempty"`
|
||||||
|
|
||||||
//IntrospectionEndpointAuthMethodsSupported contains a list of Client Authentication methods supported by the Introspection Endpoint.
|
// IntrospectionEndpointAuthMethodsSupported contains a list of Client Authentication methods supported by the Introspection Endpoint.
|
||||||
IntrospectionEndpointAuthMethodsSupported []AuthMethod `json:"introspection_endpoint_auth_methods_supported,omitempty"`
|
IntrospectionEndpointAuthMethodsSupported []AuthMethod `json:"introspection_endpoint_auth_methods_supported,omitempty"`
|
||||||
|
|
||||||
//IntrospectionEndpointAuthSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the Revocation Endpoint
|
// IntrospectionEndpointAuthSigningAlgValuesSupported contains a list of JWS signing algorithms (alg values) supported by the Revocation Endpoint
|
||||||
//for the signature of the JWT used to authenticate the Client by private_key_jwt and client_secret_jwt.
|
// for the signature of the JWT used to authenticate the Client by private_key_jwt and client_secret_jwt.
|
||||||
IntrospectionEndpointAuthSigningAlgValuesSupported []string `json:"introspection_endpoint_auth_signing_alg_values_supported,omitempty"`
|
IntrospectionEndpointAuthSigningAlgValuesSupported []string `json:"introspection_endpoint_auth_signing_alg_values_supported,omitempty"`
|
||||||
|
|
||||||
//DisplayValuesSupported contains a list of display parameter values that the OP supports (page, popup, touch, wap).
|
// DisplayValuesSupported contains a list of display parameter values that the OP supports (page, popup, touch, wap).
|
||||||
DisplayValuesSupported []Display `json:"display_values_supported,omitempty"`
|
DisplayValuesSupported []Display `json:"display_values_supported,omitempty"`
|
||||||
|
|
||||||
//ClaimTypesSupported contains a list of Claim Types that the OP supports (normal, aggregated, distributed). If omitted, the default is normal Claims.
|
// ClaimTypesSupported contains a list of Claim Types that the OP supports (normal, aggregated, distributed). If omitted, the default is normal Claims.
|
||||||
ClaimTypesSupported []string `json:"claim_types_supported,omitempty"`
|
ClaimTypesSupported []string `json:"claim_types_supported,omitempty"`
|
||||||
|
|
||||||
//ClaimsSupported contains a list of Claim Names the OP may be able to supply values for. This list might not be exhaustive.
|
// ClaimsSupported contains a list of Claim Names the OP may be able to supply values for. This list might not be exhaustive.
|
||||||
ClaimsSupported []string `json:"claims_supported,omitempty"`
|
ClaimsSupported []string `json:"claims_supported,omitempty"`
|
||||||
|
|
||||||
//ClaimsParameterSupported specifies whether the OP supports use of the `claims` parameter. If omitted, the default is false.
|
// ClaimsParameterSupported specifies whether the OP supports use of the `claims` parameter. If omitted, the default is false.
|
||||||
ClaimsParameterSupported bool `json:"claims_parameter_supported,omitempty"`
|
ClaimsParameterSupported bool `json:"claims_parameter_supported,omitempty"`
|
||||||
|
|
||||||
//CodeChallengeMethodsSupported contains a list of Proof Key for Code Exchange (PKCE) code challenge methods supported by the OP.
|
// CodeChallengeMethodsSupported contains a list of Proof Key for Code Exchange (PKCE) code challenge methods supported by the OP.
|
||||||
CodeChallengeMethodsSupported []CodeChallengeMethod `json:"code_challenge_methods_supported,omitempty"`
|
CodeChallengeMethodsSupported []CodeChallengeMethod `json:"code_challenge_methods_supported,omitempty"`
|
||||||
|
|
||||||
//ServiceDocumentation is a URL where developers can get information about the OP and its usage.
|
// ServiceDocumentation is a URL where developers can get information about the OP and its usage.
|
||||||
ServiceDocumentation string `json:"service_documentation,omitempty"`
|
ServiceDocumentation string `json:"service_documentation,omitempty"`
|
||||||
|
|
||||||
//ClaimsLocalesSupported contains a list of BCP47 language tag values that the OP supports for values of Claims returned.
|
// ClaimsLocalesSupported contains a list of BCP47 language tag values that the OP supports for values of Claims returned.
|
||||||
ClaimsLocalesSupported []language.Tag `json:"claims_locales_supported,omitempty"`
|
ClaimsLocalesSupported []language.Tag `json:"claims_locales_supported,omitempty"`
|
||||||
|
|
||||||
//UILocalesSupported contains a list of BCP47 language tag values that the OP supports for the user interface.
|
// UILocalesSupported contains a list of BCP47 language tag values that the OP supports for the user interface.
|
||||||
UILocalesSupported []language.Tag `json:"ui_locales_supported,omitempty"`
|
UILocalesSupported []language.Tag `json:"ui_locales_supported,omitempty"`
|
||||||
|
|
||||||
//RequestParameterSupported specifies whether the OP supports use of the `request` parameter. If omitted, the default value is false.
|
// RequestParameterSupported specifies whether the OP supports use of the `request` parameter. If omitted, the default value is false.
|
||||||
RequestParameterSupported bool `json:"request_parameter_supported,omitempty"`
|
RequestParameterSupported bool `json:"request_parameter_supported,omitempty"`
|
||||||
|
|
||||||
//RequestURIParameterSupported specifies whether the OP supports use of the `request_uri` parameter. If omitted, the default value is true. (therefore no omitempty)
|
// RequestURIParameterSupported specifies whether the OP supports use of the `request_uri` parameter. If omitted, the default value is true. (therefore no omitempty)
|
||||||
RequestURIParameterSupported bool `json:"request_uri_parameter_supported"`
|
RequestURIParameterSupported bool `json:"request_uri_parameter_supported"`
|
||||||
|
|
||||||
//RequireRequestURIRegistration specifies whether the OP requires any `request_uri` to be pre-registered using the request_uris registration parameter. If omitted, the default value is false.
|
// RequireRequestURIRegistration specifies whether the OP requires any `request_uri` to be pre-registered using the request_uris registration parameter. If omitted, the default value is false.
|
||||||
RequireRequestURIRegistration bool `json:"require_request_uri_registration,omitempty"`
|
RequireRequestURIRegistration bool `json:"require_request_uri_registration,omitempty"`
|
||||||
|
|
||||||
//OPPolicyURI is a URL the OP provides to the person registering the Client to read about the OP's requirements on how the RP can use the data provided by the OP.
|
// OPPolicyURI is a URL the OP provides to the person registering the Client to read about the OP's requirements on how the RP can use the data provided by the OP.
|
||||||
OPPolicyURI string `json:"op_policy_uri,omitempty"`
|
OPPolicyURI string `json:"op_policy_uri,omitempty"`
|
||||||
|
|
||||||
//OPTermsOfServiceURI is a URL the OpenID Provider provides to the person registering the Client to read about OpenID Provider's terms of service.
|
// OPTermsOfServiceURI is a URL the OpenID Provider provides to the person registering the Client to read about OpenID Provider's terms of service.
|
||||||
OPTermsOfServiceURI string `json:"op_tos_uri,omitempty"`
|
OPTermsOfServiceURI string `json:"op_tos_uri,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ type clientCredentialsGrant struct {
|
||||||
clientSecret string `schema:"client_secret"`
|
clientSecret string `schema:"client_secret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//ClientCredentialsGrantBasic creates an oauth2 `Client Credentials` Grant
|
// ClientCredentialsGrantBasic creates an oauth2 `Client Credentials` Grant
|
||||||
//sending client_id and client_secret as basic auth header
|
// sending client_id and client_secret as basic auth header
|
||||||
func ClientCredentialsGrantBasic(scopes ...string) *clientCredentialsGrantBasic {
|
func ClientCredentialsGrantBasic(scopes ...string) *clientCredentialsGrantBasic {
|
||||||
return &clientCredentialsGrantBasic{
|
return &clientCredentialsGrantBasic{
|
||||||
grantType: "client_credentials",
|
grantType: "client_credentials",
|
||||||
|
@ -22,8 +22,8 @@ func ClientCredentialsGrantBasic(scopes ...string) *clientCredentialsGrantBasic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ClientCredentialsGrantValues creates an oauth2 `Client Credentials` Grant
|
// ClientCredentialsGrantValues creates an oauth2 `Client Credentials` Grant
|
||||||
//sending client_id and client_secret as form values
|
// sending client_id and client_secret as form values
|
||||||
func ClientCredentialsGrantValues(clientID, clientSecret string, scopes ...string) *clientCredentialsGrant {
|
func ClientCredentialsGrantValues(clientID, clientSecret string, scopes ...string) *clientCredentialsGrant {
|
||||||
return &clientCredentialsGrant{
|
return &clientCredentialsGrant{
|
||||||
clientCredentialsGrantBasic: ClientCredentialsGrantBasic(scopes...),
|
clientCredentialsGrantBasic: ClientCredentialsGrantBasic(scopes...),
|
||||||
|
|
|
@ -6,9 +6,9 @@ type JWTProfileGrantRequest struct {
|
||||||
GrantType GrantType `schema:"grant_type"`
|
GrantType GrantType `schema:"grant_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewJWTProfileGrantRequest creates an oauth2 `JSON Web Token (JWT) Profile` Grant
|
// NewJWTProfileGrantRequest creates an oauth2 `JSON Web Token (JWT) Profile` Grant
|
||||||
//`urn:ietf:params:oauth:grant-type:jwt-bearer`
|
//`urn:ietf:params:oauth:grant-type:jwt-bearer`
|
||||||
//sending a self-signed jwt as assertion
|
// sending a self-signed jwt as assertion
|
||||||
func NewJWTProfileGrantRequest(assertion string, scopes ...string) *JWTProfileGrantRequest {
|
func NewJWTProfileGrantRequest(assertion string, scopes ...string) *JWTProfileGrantRequest {
|
||||||
return &JWTProfileGrantRequest{
|
return &JWTProfileGrantRequest{
|
||||||
GrantType: GrantTypeBearer,
|
GrantType: GrantTypeBearer,
|
||||||
|
|
|
@ -19,16 +19,16 @@ var (
|
||||||
ErrKeyNone = errors.New("no possible keys matches")
|
ErrKeyNone = errors.New("no possible keys matches")
|
||||||
)
|
)
|
||||||
|
|
||||||
//KeySet represents a set of JSON Web Keys
|
// KeySet represents a set of JSON Web Keys
|
||||||
// - remotely fetch via discovery and jwks_uri -> `remoteKeySet`
|
// - remotely fetch via discovery and jwks_uri -> `remoteKeySet`
|
||||||
// - held by the OP itself in storage -> `openIDKeySet`
|
// - held by the OP itself in storage -> `openIDKeySet`
|
||||||
// - dynamically aggregated by request for OAuth JWT Profile Assertion -> `jwtProfileKeySet`
|
// - dynamically aggregated by request for OAuth JWT Profile Assertion -> `jwtProfileKeySet`
|
||||||
type KeySet interface {
|
type KeySet interface {
|
||||||
//VerifySignature verifies the signature with the given keyset and returns the raw payload
|
// VerifySignature verifies the signature with the given keyset and returns the raw payload
|
||||||
VerifySignature(ctx context.Context, jws *jose.JSONWebSignature) (payload []byte, err error)
|
VerifySignature(ctx context.Context, jws *jose.JSONWebSignature) (payload []byte, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetKeyIDAndAlg returns the `kid` and `alg` claim from the JWS header
|
// GetKeyIDAndAlg returns the `kid` and `alg` claim from the JWS header
|
||||||
func GetKeyIDAndAlg(jws *jose.JSONWebSignature) (string, string) {
|
func GetKeyIDAndAlg(jws *jose.JSONWebSignature) (string, string) {
|
||||||
keyID := ""
|
keyID := ""
|
||||||
alg := ""
|
alg := ""
|
||||||
|
@ -40,11 +40,11 @@ func GetKeyIDAndAlg(jws *jose.JSONWebSignature) (string, string) {
|
||||||
return keyID, alg
|
return keyID, alg
|
||||||
}
|
}
|
||||||
|
|
||||||
//FindKey searches the given JSON Web Keys for the requested key ID, usage and key type
|
// FindKey searches the given JSON Web Keys for the requested key ID, usage and key type
|
||||||
//
|
//
|
||||||
//will return the key immediately if matches exact (id, usage, type)
|
// will return the key immediately if matches exact (id, usage, type)
|
||||||
//
|
//
|
||||||
//will return false none or multiple match
|
// will return false none or multiple match
|
||||||
//
|
//
|
||||||
//deprecated: use FindMatchingKey which will return an error (more specific) instead of just a bool
|
//deprecated: use FindMatchingKey which will return an error (more specific) instead of just a bool
|
||||||
//moved implementation already to FindMatchingKey
|
//moved implementation already to FindMatchingKey
|
||||||
|
@ -53,35 +53,35 @@ func FindKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (jose.JSON
|
||||||
return key, err == nil
|
return key, err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//FindMatchingKey searches the given JSON Web Keys for the requested key ID, usage and alg type
|
// FindMatchingKey searches the given JSON Web Keys for the requested key ID, usage and alg type
|
||||||
//
|
//
|
||||||
//will return the key immediately if matches exact (id, usage, type)
|
// will return the key immediately if matches exact (id, usage, type)
|
||||||
//
|
//
|
||||||
//will return a specific error if none (ErrKeyNone) or multiple (ErrKeyMultiple) match
|
// will return a specific error if none (ErrKeyNone) or multiple (ErrKeyMultiple) match
|
||||||
func FindMatchingKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (key jose.JSONWebKey, err error) {
|
func FindMatchingKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (key jose.JSONWebKey, err error) {
|
||||||
var validKeys []jose.JSONWebKey
|
var validKeys []jose.JSONWebKey
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
//ignore all keys with wrong use (let empty use of published key pass)
|
// ignore all keys with wrong use (let empty use of published key pass)
|
||||||
if k.Use != use && k.Use != "" {
|
if k.Use != use && k.Use != "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//ignore all keys with wrong algorithm type
|
// ignore all keys with wrong algorithm type
|
||||||
if !algToKeyType(k.Key, expectedAlg) {
|
if !algToKeyType(k.Key, expectedAlg) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//if we get here, use and alg match, so an equal (not empty) keyID is an exact match
|
// if we get here, use and alg match, so an equal (not empty) keyID is an exact match
|
||||||
if k.KeyID == keyID && keyID != "" {
|
if k.KeyID == keyID && keyID != "" {
|
||||||
return k, nil
|
return k, nil
|
||||||
}
|
}
|
||||||
//keyIDs did not match or at least one was empty (if later, then it could be a match)
|
// keyIDs did not match or at least one was empty (if later, then it could be a match)
|
||||||
if k.KeyID == "" || keyID == "" {
|
if k.KeyID == "" || keyID == "" {
|
||||||
validKeys = append(validKeys, k)
|
validKeys = append(validKeys, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if we get here, no match was possible at all (use / alg) or no exact match due to
|
// if we get here, no match was possible at all (use / alg) or no exact match due to
|
||||||
//the signed JWT and / or the published keys didn't have a kid
|
// the signed JWT and / or the published keys didn't have a kid
|
||||||
//if later applies and only one key could be found, we'll return it
|
// if later applies and only one key could be found, we'll return it
|
||||||
//otherwise a corresponding error will be thrown
|
// otherwise a corresponding error will be thrown
|
||||||
if len(validKeys) == 1 {
|
if len(validKeys) == 1 {
|
||||||
return validKeys[0], nil
|
return validKeys[0], nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package oidc
|
package oidc
|
||||||
|
|
||||||
//EndSessionRequest for the RP-Initiated Logout according to:
|
// EndSessionRequest for the RP-Initiated Logout according to:
|
||||||
//https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout
|
//https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout
|
||||||
type EndSessionRequest struct {
|
type EndSessionRequest struct {
|
||||||
IdTokenHint string `schema:"id_token_hint"`
|
IdTokenHint string `schema:"id_token_hint"`
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//BearerToken defines the token_type `Bearer`, which is returned in a successful token response
|
// BearerToken defines the token_type `Bearer`, which is returned in a successful token response
|
||||||
BearerToken = "Bearer"
|
BearerToken = "Bearer"
|
||||||
|
|
||||||
PrefixBearer = BearerToken + " "
|
PrefixBearer = BearerToken + " "
|
||||||
|
@ -91,62 +91,62 @@ type accessTokenClaims struct {
|
||||||
signatureAlg jose.SignatureAlgorithm `json:"-"`
|
signatureAlg jose.SignatureAlgorithm `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetIssuer implements the Claims interface
|
// GetIssuer implements the Claims interface
|
||||||
func (a *accessTokenClaims) GetIssuer() string {
|
func (a *accessTokenClaims) GetIssuer() string {
|
||||||
return a.Issuer
|
return a.Issuer
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAudience implements the Claims interface
|
// GetAudience implements the Claims interface
|
||||||
func (a *accessTokenClaims) GetAudience() []string {
|
func (a *accessTokenClaims) GetAudience() []string {
|
||||||
return a.Audience
|
return a.Audience
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetExpiration implements the Claims interface
|
// GetExpiration implements the Claims interface
|
||||||
func (a *accessTokenClaims) GetExpiration() time.Time {
|
func (a *accessTokenClaims) GetExpiration() time.Time {
|
||||||
return time.Time(a.Expiration)
|
return time.Time(a.Expiration)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetIssuedAt implements the Claims interface
|
// GetIssuedAt implements the Claims interface
|
||||||
func (a *accessTokenClaims) GetIssuedAt() time.Time {
|
func (a *accessTokenClaims) GetIssuedAt() time.Time {
|
||||||
return time.Time(a.IssuedAt)
|
return time.Time(a.IssuedAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetNonce implements the Claims interface
|
// GetNonce implements the Claims interface
|
||||||
func (a *accessTokenClaims) GetNonce() string {
|
func (a *accessTokenClaims) GetNonce() string {
|
||||||
return a.Nonce
|
return a.Nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthenticationContextClassReference implements the Claims interface
|
// GetAuthenticationContextClassReference implements the Claims interface
|
||||||
func (a *accessTokenClaims) GetAuthenticationContextClassReference() string {
|
func (a *accessTokenClaims) GetAuthenticationContextClassReference() string {
|
||||||
return a.AuthenticationContextClassReference
|
return a.AuthenticationContextClassReference
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthTime implements the Claims interface
|
// GetAuthTime implements the Claims interface
|
||||||
func (a *accessTokenClaims) GetAuthTime() time.Time {
|
func (a *accessTokenClaims) GetAuthTime() time.Time {
|
||||||
return time.Time(a.AuthTime)
|
return time.Time(a.AuthTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthorizedParty implements the Claims interface
|
// GetAuthorizedParty implements the Claims interface
|
||||||
func (a *accessTokenClaims) GetAuthorizedParty() string {
|
func (a *accessTokenClaims) GetAuthorizedParty() string {
|
||||||
return a.AuthorizedParty
|
return a.AuthorizedParty
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetSignatureAlgorithm implements the Claims interface
|
// SetSignatureAlgorithm implements the Claims interface
|
||||||
func (a *accessTokenClaims) SetSignatureAlgorithm(algorithm jose.SignatureAlgorithm) {
|
func (a *accessTokenClaims) SetSignatureAlgorithm(algorithm jose.SignatureAlgorithm) {
|
||||||
a.signatureAlg = algorithm
|
a.signatureAlg = algorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetSubject implements the AccessTokenClaims interface
|
// GetSubject implements the AccessTokenClaims interface
|
||||||
func (a *accessTokenClaims) GetSubject() string {
|
func (a *accessTokenClaims) GetSubject() string {
|
||||||
return a.Subject
|
return a.Subject
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetTokenID implements the AccessTokenClaims interface
|
// GetTokenID implements the AccessTokenClaims interface
|
||||||
func (a *accessTokenClaims) GetTokenID() string {
|
func (a *accessTokenClaims) GetTokenID() string {
|
||||||
return a.JWTID
|
return a.JWTID
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetPrivateClaims implements the AccessTokenClaims interface
|
// SetPrivateClaims implements the AccessTokenClaims interface
|
||||||
func (a *accessTokenClaims) SetPrivateClaims(claims map[string]interface{}) {
|
func (a *accessTokenClaims) SetPrivateClaims(claims map[string]interface{}) {
|
||||||
a.claims = claims
|
a.claims = claims
|
||||||
}
|
}
|
||||||
|
@ -243,97 +243,97 @@ type idTokenClaims struct {
|
||||||
signatureAlg jose.SignatureAlgorithm
|
signatureAlg jose.SignatureAlgorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetIssuer implements the Claims interface
|
// GetIssuer implements the Claims interface
|
||||||
func (t *idTokenClaims) GetIssuer() string {
|
func (t *idTokenClaims) GetIssuer() string {
|
||||||
return t.Issuer
|
return t.Issuer
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAudience implements the Claims interface
|
// GetAudience implements the Claims interface
|
||||||
func (t *idTokenClaims) GetAudience() []string {
|
func (t *idTokenClaims) GetAudience() []string {
|
||||||
return t.Audience
|
return t.Audience
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetExpiration implements the Claims interface
|
// GetExpiration implements the Claims interface
|
||||||
func (t *idTokenClaims) GetExpiration() time.Time {
|
func (t *idTokenClaims) GetExpiration() time.Time {
|
||||||
return time.Time(t.Expiration)
|
return time.Time(t.Expiration)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetIssuedAt implements the Claims interface
|
// GetIssuedAt implements the Claims interface
|
||||||
func (t *idTokenClaims) GetIssuedAt() time.Time {
|
func (t *idTokenClaims) GetIssuedAt() time.Time {
|
||||||
return time.Time(t.IssuedAt)
|
return time.Time(t.IssuedAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetNonce implements the Claims interface
|
// GetNonce implements the Claims interface
|
||||||
func (t *idTokenClaims) GetNonce() string {
|
func (t *idTokenClaims) GetNonce() string {
|
||||||
return t.Nonce
|
return t.Nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthenticationContextClassReference implements the Claims interface
|
// GetAuthenticationContextClassReference implements the Claims interface
|
||||||
func (t *idTokenClaims) GetAuthenticationContextClassReference() string {
|
func (t *idTokenClaims) GetAuthenticationContextClassReference() string {
|
||||||
return t.AuthenticationContextClassReference
|
return t.AuthenticationContextClassReference
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthTime implements the Claims interface
|
// GetAuthTime implements the Claims interface
|
||||||
func (t *idTokenClaims) GetAuthTime() time.Time {
|
func (t *idTokenClaims) GetAuthTime() time.Time {
|
||||||
return time.Time(t.AuthTime)
|
return time.Time(t.AuthTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthorizedParty implements the Claims interface
|
// GetAuthorizedParty implements the Claims interface
|
||||||
func (t *idTokenClaims) GetAuthorizedParty() string {
|
func (t *idTokenClaims) GetAuthorizedParty() string {
|
||||||
return t.AuthorizedParty
|
return t.AuthorizedParty
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetSignatureAlgorithm implements the Claims interface
|
// SetSignatureAlgorithm implements the Claims interface
|
||||||
func (t *idTokenClaims) SetSignatureAlgorithm(alg jose.SignatureAlgorithm) {
|
func (t *idTokenClaims) SetSignatureAlgorithm(alg jose.SignatureAlgorithm) {
|
||||||
t.signatureAlg = alg
|
t.signatureAlg = alg
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetNotBefore implements the IDTokenClaims interface
|
// GetNotBefore implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) GetNotBefore() time.Time {
|
func (t *idTokenClaims) GetNotBefore() time.Time {
|
||||||
return time.Time(t.NotBefore)
|
return time.Time(t.NotBefore)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetJWTID implements the IDTokenClaims interface
|
// GetJWTID implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) GetJWTID() string {
|
func (t *idTokenClaims) GetJWTID() string {
|
||||||
return t.JWTID
|
return t.JWTID
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAccessTokenHash implements the IDTokenClaims interface
|
// GetAccessTokenHash implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) GetAccessTokenHash() string {
|
func (t *idTokenClaims) GetAccessTokenHash() string {
|
||||||
return t.AccessTokenHash
|
return t.AccessTokenHash
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetCodeHash implements the IDTokenClaims interface
|
// GetCodeHash implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) GetCodeHash() string {
|
func (t *idTokenClaims) GetCodeHash() string {
|
||||||
return t.CodeHash
|
return t.CodeHash
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthenticationMethodsReferences implements the IDTokenClaims interface
|
// GetAuthenticationMethodsReferences implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) GetAuthenticationMethodsReferences() []string {
|
func (t *idTokenClaims) GetAuthenticationMethodsReferences() []string {
|
||||||
return t.AuthenticationMethodsReferences
|
return t.AuthenticationMethodsReferences
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetClientID implements the IDTokenClaims interface
|
// GetClientID implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) GetClientID() string {
|
func (t *idTokenClaims) GetClientID() string {
|
||||||
return t.ClientID
|
return t.ClientID
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetSignatureAlgorithm implements the IDTokenClaims interface
|
// GetSignatureAlgorithm implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) GetSignatureAlgorithm() jose.SignatureAlgorithm {
|
func (t *idTokenClaims) GetSignatureAlgorithm() jose.SignatureAlgorithm {
|
||||||
return t.signatureAlg
|
return t.signatureAlg
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetAccessTokenHash implements the IDTokenClaims interface
|
// SetAccessTokenHash implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) SetAccessTokenHash(hash string) {
|
func (t *idTokenClaims) SetAccessTokenHash(hash string) {
|
||||||
t.AccessTokenHash = hash
|
t.AccessTokenHash = hash
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetUserinfo implements the IDTokenClaims interface
|
// SetUserinfo implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) SetUserinfo(info UserInfo) {
|
func (t *idTokenClaims) SetUserinfo(info UserInfo) {
|
||||||
t.UserInfo = info
|
t.UserInfo = info
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetCodeHash implements the IDTokenClaims interface
|
// SetCodeHash implements the IDTokenClaims interface
|
||||||
func (t *idTokenClaims) SetCodeHash(hash string) {
|
func (t *idTokenClaims) SetCodeHash(hash string) {
|
||||||
t.CodeHash = hash
|
t.CodeHash = hash
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,33 +9,34 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//GrantTypeCode defines the grant_type `authorization_code` used for the Token Request in the Authorization Code Flow
|
// GrantTypeCode defines the grant_type `authorization_code` used for the Token Request in the Authorization Code Flow
|
||||||
GrantTypeCode GrantType = "authorization_code"
|
GrantTypeCode GrantType = "authorization_code"
|
||||||
|
|
||||||
//GrantTypeRefreshToken defines the grant_type `refresh_token` used for the Token Request in the Refresh Token Flow
|
// GrantTypeRefreshToken defines the grant_type `refresh_token` used for the Token Request in the Refresh Token Flow
|
||||||
GrantTypeRefreshToken GrantType = "refresh_token"
|
GrantTypeRefreshToken GrantType = "refresh_token"
|
||||||
|
|
||||||
//GrantTypeClientCredentials defines the grant_type `client_credentials` used for the Token Request in the Client Credentials Token Flow
|
// GrantTypeClientCredentials defines the grant_type `client_credentials` used for the Token Request in the Client Credentials Token Flow
|
||||||
GrantTypeClientCredentials GrantType = "client_credentials"
|
GrantTypeClientCredentials GrantType = "client_credentials"
|
||||||
|
|
||||||
//GrantTypeBearer defines the grant_type `urn:ietf:params:oauth:grant-type:jwt-bearer` used for the JWT Authorization Grant
|
// GrantTypeBearer defines the grant_type `urn:ietf:params:oauth:grant-type:jwt-bearer` used for the JWT Authorization Grant
|
||||||
GrantTypeBearer GrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
GrantTypeBearer GrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
|
||||||
|
|
||||||
//GrantTypeTokenExchange defines the grant_type `urn:ietf:params:oauth:grant-type:token-exchange` used for the OAuth Token Exchange Grant
|
// GrantTypeTokenExchange defines the grant_type `urn:ietf:params:oauth:grant-type:token-exchange` used for the OAuth Token Exchange Grant
|
||||||
GrantTypeTokenExchange GrantType = "urn:ietf:params:oauth:grant-type:token-exchange"
|
GrantTypeTokenExchange GrantType = "urn:ietf:params:oauth:grant-type:token-exchange"
|
||||||
|
|
||||||
//GrantTypeImplicit defines the grant type `implicit` used for implicit flows that skip the generation and exchange of an Authorization Code
|
// GrantTypeImplicit defines the grant type `implicit` used for implicit flows that skip the generation and exchange of an Authorization Code
|
||||||
GrantTypeImplicit GrantType = "implicit"
|
GrantTypeImplicit GrantType = "implicit"
|
||||||
|
|
||||||
//ClientAssertionTypeJWTAssertion defines the client_assertion_type `urn:ietf:params:oauth:client-assertion-type:jwt-bearer`
|
// ClientAssertionTypeJWTAssertion defines the client_assertion_type `urn:ietf:params:oauth:client-assertion-type:jwt-bearer`
|
||||||
//used for the OAuth JWT Profile Client Authentication
|
// used for the OAuth JWT Profile Client Authentication
|
||||||
ClientAssertionTypeJWTAssertion = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
|
ClientAssertionTypeJWTAssertion = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AllGrantTypes = []GrantType{
|
var AllGrantTypes = []GrantType{
|
||||||
GrantTypeCode, GrantTypeRefreshToken, GrantTypeClientCredentials,
|
GrantTypeCode, GrantTypeRefreshToken, GrantTypeClientCredentials,
|
||||||
GrantTypeBearer, GrantTypeTokenExchange, GrantTypeImplicit,
|
GrantTypeBearer, GrantTypeTokenExchange, GrantTypeImplicit,
|
||||||
ClientAssertionTypeJWTAssertion}
|
ClientAssertionTypeJWTAssertion,
|
||||||
|
}
|
||||||
|
|
||||||
type GrantType string
|
type GrantType string
|
||||||
|
|
||||||
|
@ -60,12 +61,12 @@ func (a *AccessTokenRequest) GrantType() GrantType {
|
||||||
return GrantTypeCode
|
return GrantTypeCode
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetClientID implements op.AuthenticatedTokenRequest
|
// SetClientID implements op.AuthenticatedTokenRequest
|
||||||
func (a *AccessTokenRequest) SetClientID(clientID string) {
|
func (a *AccessTokenRequest) SetClientID(clientID string) {
|
||||||
a.ClientID = clientID
|
a.ClientID = clientID
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetClientSecret implements op.AuthenticatedTokenRequest
|
// SetClientSecret implements op.AuthenticatedTokenRequest
|
||||||
func (a *AccessTokenRequest) SetClientSecret(clientSecret string) {
|
func (a *AccessTokenRequest) SetClientSecret(clientSecret string) {
|
||||||
a.ClientSecret = clientSecret
|
a.ClientSecret = clientSecret
|
||||||
}
|
}
|
||||||
|
@ -85,12 +86,12 @@ func (a *RefreshTokenRequest) GrantType() GrantType {
|
||||||
return GrantTypeRefreshToken
|
return GrantTypeRefreshToken
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetClientID implements op.AuthenticatedTokenRequest
|
// SetClientID implements op.AuthenticatedTokenRequest
|
||||||
func (a *RefreshTokenRequest) SetClientID(clientID string) {
|
func (a *RefreshTokenRequest) SetClientID(clientID string) {
|
||||||
a.ClientID = clientID
|
a.ClientID = clientID
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetClientSecret implements op.AuthenticatedTokenRequest
|
// SetClientSecret implements op.AuthenticatedTokenRequest
|
||||||
func (a *RefreshTokenRequest) SetClientSecret(clientSecret string) {
|
func (a *RefreshTokenRequest) SetClientSecret(clientSecret string) {
|
||||||
a.ClientSecret = clientSecret
|
a.ClientSecret = clientSecret
|
||||||
}
|
}
|
||||||
|
@ -148,55 +149,55 @@ func (j *JWTTokenRequest) GetCustomClaim(key string) interface{} {
|
||||||
return j.private[key]
|
return j.private[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetIssuer implements the Claims interface
|
// GetIssuer implements the Claims interface
|
||||||
func (j *JWTTokenRequest) GetIssuer() string {
|
func (j *JWTTokenRequest) GetIssuer() string {
|
||||||
return j.Issuer
|
return j.Issuer
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAudience implements the Claims and TokenRequest interfaces
|
// GetAudience implements the Claims and TokenRequest interfaces
|
||||||
func (j *JWTTokenRequest) GetAudience() []string {
|
func (j *JWTTokenRequest) GetAudience() []string {
|
||||||
return j.Audience
|
return j.Audience
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetExpiration implements the Claims interface
|
// GetExpiration implements the Claims interface
|
||||||
func (j *JWTTokenRequest) GetExpiration() time.Time {
|
func (j *JWTTokenRequest) GetExpiration() time.Time {
|
||||||
return time.Time(j.ExpiresAt)
|
return time.Time(j.ExpiresAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetIssuedAt implements the Claims interface
|
// GetIssuedAt implements the Claims interface
|
||||||
func (j *JWTTokenRequest) GetIssuedAt() time.Time {
|
func (j *JWTTokenRequest) GetIssuedAt() time.Time {
|
||||||
return time.Time(j.IssuedAt)
|
return time.Time(j.IssuedAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetNonce implements the Claims interface
|
// GetNonce implements the Claims interface
|
||||||
func (j *JWTTokenRequest) GetNonce() string {
|
func (j *JWTTokenRequest) GetNonce() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthenticationContextClassReference implements the Claims interface
|
// GetAuthenticationContextClassReference implements the Claims interface
|
||||||
func (j *JWTTokenRequest) GetAuthenticationContextClassReference() string {
|
func (j *JWTTokenRequest) GetAuthenticationContextClassReference() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthTime implements the Claims interface
|
// GetAuthTime implements the Claims interface
|
||||||
func (j *JWTTokenRequest) GetAuthTime() time.Time {
|
func (j *JWTTokenRequest) GetAuthTime() time.Time {
|
||||||
return time.Time{}
|
return time.Time{}
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetAuthorizedParty implements the Claims interface
|
// GetAuthorizedParty implements the Claims interface
|
||||||
func (j *JWTTokenRequest) GetAuthorizedParty() string {
|
func (j *JWTTokenRequest) GetAuthorizedParty() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetSignatureAlgorithm implements the Claims interface
|
// SetSignatureAlgorithm implements the Claims interface
|
||||||
func (j *JWTTokenRequest) SetSignatureAlgorithm(_ jose.SignatureAlgorithm) {}
|
func (j *JWTTokenRequest) SetSignatureAlgorithm(_ jose.SignatureAlgorithm) {}
|
||||||
|
|
||||||
//GetSubject implements the TokenRequest interface
|
// GetSubject implements the TokenRequest interface
|
||||||
func (j *JWTTokenRequest) GetSubject() string {
|
func (j *JWTTokenRequest) GetSubject() string {
|
||||||
return j.Subject
|
return j.Subject
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetScopes implements the TokenRequest interface
|
// GetScopes implements the TokenRequest interface
|
||||||
func (j *JWTTokenRequest) GetScopes() []string {
|
func (j *JWTTokenRequest) GetScopes() []string {
|
||||||
return j.Scopes
|
return j.Scopes
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,11 +61,11 @@ type Verifier interface {
|
||||||
Offset() time.Duration
|
Offset() time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
//ACRVerifier specifies the function to be used by the `DefaultVerifier` for validating the acr claim
|
// ACRVerifier specifies the function to be used by the `DefaultVerifier` for validating the acr claim
|
||||||
type ACRVerifier func(string) error
|
type ACRVerifier func(string) error
|
||||||
|
|
||||||
//DefaultACRVerifier implements `ACRVerifier` returning an error
|
// DefaultACRVerifier implements `ACRVerifier` returning an error
|
||||||
//if none of the provided values matches the acr claim
|
// if none of the provided values matches the acr claim
|
||||||
func DefaultACRVerifier(possibleValues []string) ACRVerifier {
|
func DefaultACRVerifier(possibleValues []string) ACRVerifier {
|
||||||
return func(acr string) error {
|
return func(acr string) error {
|
||||||
if !str.Contains(possibleValues, acr) {
|
if !str.Contains(possibleValues, acr) {
|
||||||
|
@ -76,7 +76,7 @@ func DefaultACRVerifier(possibleValues []string) ACRVerifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecryptToken(tokenString string) (string, error) {
|
func DecryptToken(tokenString string) (string, error) {
|
||||||
return tokenString, nil //TODO: impl
|
return tokenString, nil // TODO: impl
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseToken(tokenString string, claims interface{}) ([]byte, error) {
|
func ParseToken(tokenString string, claims interface{}) ([]byte, error) {
|
||||||
|
@ -111,7 +111,7 @@ func CheckAudience(claims Claims, clientID string) error {
|
||||||
return fmt.Errorf("%w: Audience must contain client_id %q", ErrAudience, clientID)
|
return fmt.Errorf("%w: Audience must contain client_id %q", ErrAudience, clientID)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: check aud trusted
|
// TODO: check aud trusted
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,6 +202,7 @@ func CheckAuthorizationContextClassReference(claims Claims, acr ACRVerifier) err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckAuthTime(claims Claims, maxAge time.Duration) error {
|
func CheckAuthTime(claims Claims, maxAge time.Duration) error {
|
||||||
if maxAge == 0 {
|
if maxAge == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -45,8 +45,8 @@ type Authorizer interface {
|
||||||
RequestObjectSupported() bool
|
RequestObjectSupported() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthorizeValidator is an extension of Authorizer interface
|
// AuthorizeValidator is an extension of Authorizer interface
|
||||||
//implementing its own validation mechanism for the auth request
|
// implementing its own validation mechanism for the auth request
|
||||||
type AuthorizeValidator interface {
|
type AuthorizeValidator interface {
|
||||||
Authorizer
|
Authorizer
|
||||||
ValidateAuthRequest(context.Context, *oidc.AuthRequest, Storage, IDTokenHintVerifier) (string, error)
|
ValidateAuthRequest(context.Context, *oidc.AuthRequest, Storage, IDTokenHintVerifier) (string, error)
|
||||||
|
@ -64,8 +64,8 @@ func authorizeCallbackHandler(authorizer Authorizer) func(http.ResponseWriter, *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Authorize handles the authorization request, including
|
// Authorize handles the authorization request, including
|
||||||
//parsing, validating, storing and finally redirecting to the login handler
|
// parsing, validating, storing and finally redirecting to the login handler
|
||||||
func Authorize(w http.ResponseWriter, r *http.Request, authorizer Authorizer) {
|
func Authorize(w http.ResponseWriter, r *http.Request, authorizer Authorizer) {
|
||||||
authReq, err := ParseAuthorizeRequest(r, authorizer.Decoder())
|
authReq, err := ParseAuthorizeRequest(r, authorizer.Decoder())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -113,7 +113,7 @@ func Authorize(w http.ResponseWriter, r *http.Request, authorizer Authorizer) {
|
||||||
RedirectToLogin(req.GetID(), client, w, r)
|
RedirectToLogin(req.GetID(), client, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ParseAuthorizeRequest parsed the http request into an oidc.AuthRequest
|
// ParseAuthorizeRequest parsed the http request into an oidc.AuthRequest
|
||||||
func ParseAuthorizeRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.AuthRequest, error) {
|
func ParseAuthorizeRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.AuthRequest, error) {
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -127,8 +127,8 @@ func ParseAuthorizeRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.A
|
||||||
return authReq, nil
|
return authReq, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ParseRequestObject parse the `request` parameter, validates the token including the signature
|
// ParseRequestObject parse the `request` parameter, validates the token including the signature
|
||||||
//and copies the token claims into the auth request
|
// and copies the token claims into the auth request
|
||||||
func ParseRequestObject(ctx context.Context, authReq *oidc.AuthRequest, storage Storage, issuer string) (*oidc.AuthRequest, error) {
|
func ParseRequestObject(ctx context.Context, authReq *oidc.AuthRequest, storage Storage, issuer string) (*oidc.AuthRequest, error) {
|
||||||
requestObject := new(oidc.RequestObject)
|
requestObject := new(oidc.RequestObject)
|
||||||
payload, err := oidc.ParseToken(authReq.RequestParam, requestObject)
|
payload, err := oidc.ParseToken(authReq.RequestParam, requestObject)
|
||||||
|
@ -156,8 +156,8 @@ func ParseRequestObject(ctx context.Context, authReq *oidc.AuthRequest, storage
|
||||||
return authReq, nil
|
return authReq, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//CopyRequestObjectToAuthRequest overwrites present values from the Request Object into the auth request
|
// CopyRequestObjectToAuthRequest overwrites present values from the Request Object into the auth request
|
||||||
//and clears the `RequestParam` of the auth request
|
// and clears the `RequestParam` of the auth request
|
||||||
func CopyRequestObjectToAuthRequest(authReq *oidc.AuthRequest, requestObject *oidc.RequestObject) {
|
func CopyRequestObjectToAuthRequest(authReq *oidc.AuthRequest, requestObject *oidc.RequestObject) {
|
||||||
if str.Contains(authReq.Scopes, oidc.ScopeOpenID) && len(requestObject.Scopes) > 0 {
|
if str.Contains(authReq.Scopes, oidc.ScopeOpenID) && len(requestObject.Scopes) > 0 {
|
||||||
authReq.Scopes = requestObject.Scopes
|
authReq.Scopes = requestObject.Scopes
|
||||||
|
@ -204,7 +204,7 @@ func CopyRequestObjectToAuthRequest(authReq *oidc.AuthRequest, requestObject *oi
|
||||||
authReq.RequestParam = ""
|
authReq.RequestParam = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateAuthRequest validates the authorize parameters and returns the userID of the id_token_hint if passed
|
// ValidateAuthRequest validates the authorize parameters and returns the userID of the id_token_hint if passed
|
||||||
func ValidateAuthRequest(ctx context.Context, authReq *oidc.AuthRequest, storage Storage, verifier IDTokenHintVerifier) (sub string, err error) {
|
func ValidateAuthRequest(ctx context.Context, authReq *oidc.AuthRequest, storage Storage, verifier IDTokenHintVerifier) (sub string, err error) {
|
||||||
authReq.MaxAge, err = ValidateAuthReqPrompt(authReq.Prompt, authReq.MaxAge)
|
authReq.MaxAge, err = ValidateAuthReqPrompt(authReq.Prompt, authReq.MaxAge)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -227,7 +227,7 @@ func ValidateAuthRequest(ctx context.Context, authReq *oidc.AuthRequest, storage
|
||||||
return ValidateAuthReqIDTokenHint(ctx, authReq.IDTokenHint, verifier)
|
return ValidateAuthReqIDTokenHint(ctx, authReq.IDTokenHint, verifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateAuthReqPrompt validates the passed prompt values and sets max_age to 0 if prompt login is present
|
// ValidateAuthReqPrompt validates the passed prompt values and sets max_age to 0 if prompt login is present
|
||||||
func ValidateAuthReqPrompt(prompts []string, maxAge *uint) (_ *uint, err error) {
|
func ValidateAuthReqPrompt(prompts []string, maxAge *uint) (_ *uint, err error) {
|
||||||
for _, prompt := range prompts {
|
for _, prompt := range prompts {
|
||||||
if prompt == oidc.PromptNone && len(prompts) > 1 {
|
if prompt == oidc.PromptNone && len(prompts) > 1 {
|
||||||
|
@ -240,7 +240,7 @@ func ValidateAuthReqPrompt(prompts []string, maxAge *uint) (_ *uint, err error)
|
||||||
return maxAge, nil
|
return maxAge, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateAuthReqScopes validates the passed scopes
|
// ValidateAuthReqScopes validates the passed scopes
|
||||||
func ValidateAuthReqScopes(client Client, scopes []string) ([]string, error) {
|
func ValidateAuthReqScopes(client Client, scopes []string) ([]string, error) {
|
||||||
if len(scopes) == 0 {
|
if len(scopes) == 0 {
|
||||||
return nil, oidc.ErrInvalidRequest().
|
return nil, oidc.ErrInvalidRequest().
|
||||||
|
@ -274,7 +274,7 @@ func ValidateAuthReqScopes(client Client, scopes []string) ([]string, error) {
|
||||||
return scopes, nil
|
return scopes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateAuthReqRedirectURI validates the passed redirect_uri and response_type to the registered uris and client type
|
// ValidateAuthReqRedirectURI validates the passed redirect_uri and response_type to the registered uris and client type
|
||||||
func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.ResponseType) error {
|
func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.ResponseType) error {
|
||||||
if uri == "" {
|
if uri == "" {
|
||||||
return oidc.ErrInvalidRequestRedirectURI().WithDescription("The redirect_uri is missing in the request. " +
|
return oidc.ErrInvalidRequestRedirectURI().WithDescription("The redirect_uri is missing in the request. " +
|
||||||
|
@ -309,7 +309,7 @@ func ValidateAuthReqRedirectURI(client Client, uri string, responseType oidc.Res
|
||||||
"If you have any questions, you may contact the administrator of the application.")
|
"If you have any questions, you may contact the administrator of the application.")
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateAuthReqRedirectURINative validates the passed redirect_uri and response_type to the registered uris and client type
|
// ValidateAuthReqRedirectURINative validates the passed redirect_uri and response_type to the registered uris and client type
|
||||||
func validateAuthReqRedirectURINative(client Client, uri string, responseType oidc.ResponseType) error {
|
func validateAuthReqRedirectURINative(client Client, uri string, responseType oidc.ResponseType) error {
|
||||||
parsedURL, isLoopback := HTTPLoopbackOrLocalhost(uri)
|
parsedURL, isLoopback := HTTPLoopbackOrLocalhost(uri)
|
||||||
isCustomSchema := !strings.HasPrefix(uri, "http://")
|
isCustomSchema := !strings.HasPrefix(uri, "http://")
|
||||||
|
@ -350,7 +350,7 @@ func HTTPLoopbackOrLocalhost(rawurl string) (*url.URL, bool) {
|
||||||
return parsedURL, hostName == "localhost" || net.ParseIP(hostName).IsLoopback()
|
return parsedURL, hostName == "localhost" || net.ParseIP(hostName).IsLoopback()
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateAuthReqResponseType validates the passed response_type to the registered response types
|
// ValidateAuthReqResponseType validates the passed response_type to the registered response types
|
||||||
func ValidateAuthReqResponseType(client Client, responseType oidc.ResponseType) error {
|
func ValidateAuthReqResponseType(client Client, responseType oidc.ResponseType) error {
|
||||||
if responseType == "" {
|
if responseType == "" {
|
||||||
return oidc.ErrInvalidRequest().WithDescription("The response type is missing in your request. " +
|
return oidc.ErrInvalidRequest().WithDescription("The response type is missing in your request. " +
|
||||||
|
@ -363,8 +363,8 @@ func ValidateAuthReqResponseType(client Client, responseType oidc.ResponseType)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateAuthReqIDTokenHint validates the id_token_hint (if passed as parameter in the request)
|
// ValidateAuthReqIDTokenHint validates the id_token_hint (if passed as parameter in the request)
|
||||||
//and returns the `sub` claim
|
// and returns the `sub` claim
|
||||||
func ValidateAuthReqIDTokenHint(ctx context.Context, idTokenHint string, verifier IDTokenHintVerifier) (string, error) {
|
func ValidateAuthReqIDTokenHint(ctx context.Context, idTokenHint string, verifier IDTokenHintVerifier) (string, error) {
|
||||||
if idTokenHint == "" {
|
if idTokenHint == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
|
@ -377,13 +377,13 @@ func ValidateAuthReqIDTokenHint(ctx context.Context, idTokenHint string, verifie
|
||||||
return claims.GetSubject(), nil
|
return claims.GetSubject(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//RedirectToLogin redirects the end user to the Login UI for authentication
|
// RedirectToLogin redirects the end user to the Login UI for authentication
|
||||||
func RedirectToLogin(authReqID string, client Client, w http.ResponseWriter, r *http.Request) {
|
func RedirectToLogin(authReqID string, client Client, w http.ResponseWriter, r *http.Request) {
|
||||||
login := client.LoginURL(authReqID)
|
login := client.LoginURL(authReqID)
|
||||||
http.Redirect(w, r, login, http.StatusFound)
|
http.Redirect(w, r, login, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthorizeCallback handles the callback after authentication in the Login UI
|
// AuthorizeCallback handles the callback after authentication in the Login UI
|
||||||
func AuthorizeCallback(w http.ResponseWriter, r *http.Request, authorizer Authorizer) {
|
func AuthorizeCallback(w http.ResponseWriter, r *http.Request, authorizer Authorizer) {
|
||||||
params := mux.Vars(r)
|
params := mux.Vars(r)
|
||||||
id := params["id"]
|
id := params["id"]
|
||||||
|
@ -406,7 +406,7 @@ func AuthorizeCallback(w http.ResponseWriter, r *http.Request, authorizer Author
|
||||||
AuthResponse(authReq, authorizer, w, r)
|
AuthResponse(authReq, authorizer, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthResponse creates the successful authentication response (either code or tokens)
|
// AuthResponse creates the successful authentication response (either code or tokens)
|
||||||
func AuthResponse(authReq AuthRequest, authorizer Authorizer, w http.ResponseWriter, r *http.Request) {
|
func AuthResponse(authReq AuthRequest, authorizer Authorizer, w http.ResponseWriter, r *http.Request) {
|
||||||
client, err := authorizer.Storage().GetClientByClientID(r.Context(), authReq.GetClientID())
|
client, err := authorizer.Storage().GetClientByClientID(r.Context(), authReq.GetClientID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -420,7 +420,7 @@ func AuthResponse(authReq AuthRequest, authorizer Authorizer, w http.ResponseWri
|
||||||
AuthResponseToken(w, r, authReq, authorizer, client)
|
AuthResponseToken(w, r, authReq, authorizer, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthResponseCode creates the successful code authentication response
|
// AuthResponseCode creates the successful code authentication response
|
||||||
func AuthResponseCode(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer) {
|
func AuthResponseCode(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer) {
|
||||||
code, err := CreateAuthRequestCode(r.Context(), authReq, authorizer.Storage(), authorizer.Crypto())
|
code, err := CreateAuthRequestCode(r.Context(), authReq, authorizer.Storage(), authorizer.Crypto())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -442,7 +442,7 @@ func AuthResponseCode(w http.ResponseWriter, r *http.Request, authReq AuthReques
|
||||||
http.Redirect(w, r, callback, http.StatusFound)
|
http.Redirect(w, r, callback, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthResponseToken creates the successful token(s) authentication response
|
// AuthResponseToken creates the successful token(s) authentication response
|
||||||
func AuthResponseToken(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer, client Client) {
|
func AuthResponseToken(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer, client Client) {
|
||||||
createAccessToken := authReq.GetResponseType() != oidc.ResponseTypeIDTokenOnly
|
createAccessToken := authReq.GetResponseType() != oidc.ResponseTypeIDTokenOnly
|
||||||
resp, err := CreateTokenResponse(r.Context(), authReq, client, authorizer, createAccessToken, "", "")
|
resp, err := CreateTokenResponse(r.Context(), authReq, client, authorizer, createAccessToken, "", "")
|
||||||
|
@ -458,7 +458,7 @@ func AuthResponseToken(w http.ResponseWriter, r *http.Request, authReq AuthReque
|
||||||
http.Redirect(w, r, callback, http.StatusFound)
|
http.Redirect(w, r, callback, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
//CreateAuthRequestCode creates and stores a code for the auth code response
|
// CreateAuthRequestCode creates and stores a code for the auth code response
|
||||||
func CreateAuthRequestCode(ctx context.Context, authReq AuthRequest, storage Storage, crypto Crypto) (string, error) {
|
func CreateAuthRequestCode(ctx context.Context, authReq AuthRequest, storage Storage, crypto Crypto) (string, error) {
|
||||||
code, err := BuildAuthRequestCode(authReq, crypto)
|
code, err := BuildAuthRequestCode(authReq, crypto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -470,13 +470,13 @@ func CreateAuthRequestCode(ctx context.Context, authReq AuthRequest, storage Sto
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//BuildAuthRequestCode builds the string representation of the auth code
|
// BuildAuthRequestCode builds the string representation of the auth code
|
||||||
func BuildAuthRequestCode(authReq AuthRequest, crypto Crypto) (string, error) {
|
func BuildAuthRequestCode(authReq AuthRequest, crypto Crypto) (string, error) {
|
||||||
return crypto.Encrypt(authReq.GetID())
|
return crypto.Encrypt(authReq.GetID())
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthResponseURL encodes the authorization response (successful and error) and sets it as query or fragment values
|
// AuthResponseURL encodes the authorization response (successful and error) and sets it as query or fragment values
|
||||||
//depending on the response_mode and response_type
|
// depending on the response_mode and response_type
|
||||||
func AuthResponseURL(redirectURI string, responseType oidc.ResponseType, responseMode oidc.ResponseMode, response interface{}, encoder httphelper.Encoder) (string, error) {
|
func AuthResponseURL(redirectURI string, responseType oidc.ResponseType, responseMode oidc.ResponseMode, response interface{}, encoder httphelper.Encoder) (string, error) {
|
||||||
uri, err := url.Parse(redirectURI)
|
uri, err := url.Parse(redirectURI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -486,18 +486,18 @@ func AuthResponseURL(redirectURI string, responseType oidc.ResponseType, respons
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", oidc.ErrServerError().WithParent(err)
|
return "", oidc.ErrServerError().WithParent(err)
|
||||||
}
|
}
|
||||||
//return explicitly requested mode
|
// return explicitly requested mode
|
||||||
if responseMode == oidc.ResponseModeQuery {
|
if responseMode == oidc.ResponseModeQuery {
|
||||||
return mergeQueryParams(uri, params), nil
|
return mergeQueryParams(uri, params), nil
|
||||||
}
|
}
|
||||||
if responseMode == oidc.ResponseModeFragment {
|
if responseMode == oidc.ResponseModeFragment {
|
||||||
return setFragment(uri, params), nil
|
return setFragment(uri, params), nil
|
||||||
}
|
}
|
||||||
//implicit must use fragment mode is not specified by client
|
// implicit must use fragment mode is not specified by client
|
||||||
if responseType == oidc.ResponseTypeIDToken || responseType == oidc.ResponseTypeIDTokenOnly {
|
if responseType == oidc.ResponseTypeIDToken || responseType == oidc.ResponseTypeIDTokenOnly {
|
||||||
return setFragment(uri, params), nil
|
return setFragment(uri, params), nil
|
||||||
}
|
}
|
||||||
//if we get here it's code flow: defaults to query
|
// if we get here it's code flow: defaults to query
|
||||||
return mergeQueryParams(uri, params), nil
|
return mergeQueryParams(uri, params), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
//
|
//
|
||||||
//TOOD: tests will be implemented in branch for service accounts
|
// TOOD: tests will be implemented in branch for service accounts
|
||||||
//func TestAuthorize(t *testing.T) {
|
// func TestAuthorize(t *testing.T) {
|
||||||
// // testCallback := func(t *testing.T, clienID string) callbackHandler {
|
// // testCallback := func(t *testing.T, clienID string) callbackHandler {
|
||||||
// // return func(authReq *oidc.AuthRequest, client oidc.Client, w http.ResponseWriter, r *http.Request) {
|
// // return func(authReq *oidc.AuthRequest, client oidc.Client, w http.ResponseWriter, r *http.Request) {
|
||||||
// // // require.Equal(t, clientID, client.)
|
// // // require.Equal(t, clientID, client.)
|
||||||
|
@ -364,191 +364,245 @@ func TestValidateAuthReqRedirectURI(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"empty fails",
|
"empty fails",
|
||||||
args{"",
|
args{
|
||||||
|
"",
|
||||||
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"unregistered https fails",
|
"unregistered https fails",
|
||||||
args{"https://unregistered.com/callback",
|
args{
|
||||||
|
"https://unregistered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"unregistered http fails",
|
"unregistered http fails",
|
||||||
args{"http://unregistered.com/callback",
|
args{
|
||||||
|
"http://unregistered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered https web ok",
|
"code flow registered https web ok",
|
||||||
args{"https://registered.com/callback",
|
args{
|
||||||
|
"https://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered https native ok",
|
"code flow registered https native ok",
|
||||||
args{"https://registered.com/callback",
|
args{
|
||||||
|
"https://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered https user agent ok",
|
"code flow registered https user agent ok",
|
||||||
args{"https://registered.com/callback",
|
args{
|
||||||
|
"https://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered http confidential (web) ok",
|
"code flow registered http confidential (web) ok",
|
||||||
args{"http://registered.com/callback",
|
args{
|
||||||
|
"http://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeWeb, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered http not confidential (native) fails",
|
"code flow registered http not confidential (native) fails",
|
||||||
args{"http://registered.com/callback",
|
args{
|
||||||
|
"http://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered http not confidential (user agent) fails",
|
"code flow registered http not confidential (user agent) fails",
|
||||||
args{"http://registered.com/callback",
|
args{
|
||||||
|
"http://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered http localhost native ok",
|
"code flow registered http localhost native ok",
|
||||||
args{"http://localhost:4200/callback",
|
args{
|
||||||
|
"http://localhost:4200/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://localhost/callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://localhost/callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered http loopback v4 native ok",
|
"code flow registered http loopback v4 native ok",
|
||||||
args{"http://127.0.0.1:4200/callback",
|
args{
|
||||||
|
"http://127.0.0.1:4200/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://127.0.0.1/callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://127.0.0.1/callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered http loopback v6 native ok",
|
"code flow registered http loopback v6 native ok",
|
||||||
args{"http://[::1]:4200/callback",
|
args{
|
||||||
|
"http://[::1]:4200/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://[::1]/callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://[::1]/callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow unregistered http native fails",
|
"code flow unregistered http native fails",
|
||||||
args{"http://unregistered.com/callback",
|
args{
|
||||||
|
"http://unregistered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://locahost/callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://locahost/callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow unregistered custom native fails",
|
"code flow unregistered custom native fails",
|
||||||
args{"unregistered://callback",
|
args{
|
||||||
|
"unregistered://callback",
|
||||||
mock.NewClientWithConfig(t, []string{"registered://callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"registered://callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow unregistered loopback native fails",
|
"code flow unregistered loopback native fails",
|
||||||
args{"http://[::1]:4200/unregistered",
|
args{
|
||||||
|
"http://[::1]:4200/unregistered",
|
||||||
mock.NewClientWithConfig(t, []string{"http://[::1]:4200/callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://[::1]:4200/callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered custom not native (web) fails",
|
"code flow registered custom not native (web) fails",
|
||||||
args{"custom://callback",
|
args{
|
||||||
|
"custom://callback",
|
||||||
mock.NewClientWithConfig(t, []string{"custom://callback"}, op.ApplicationTypeWeb, nil, false),
|
mock.NewClientWithConfig(t, []string{"custom://callback"}, op.ApplicationTypeWeb, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered custom not native (user agent) fails",
|
"code flow registered custom not native (user agent) fails",
|
||||||
args{"custom://callback",
|
args{
|
||||||
|
"custom://callback",
|
||||||
mock.NewClientWithConfig(t, []string{"custom://callback"}, op.ApplicationTypeUserAgent, nil, false),
|
mock.NewClientWithConfig(t, []string{"custom://callback"}, op.ApplicationTypeUserAgent, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow registered custom native ok",
|
"code flow registered custom native ok",
|
||||||
args{"custom://callback",
|
args{
|
||||||
|
"custom://callback",
|
||||||
mock.NewClientWithConfig(t, []string{"custom://callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"custom://callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code flow dev mode http ok",
|
"code flow dev mode http ok",
|
||||||
args{"http://registered.com/callback",
|
args{
|
||||||
|
"http://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, true),
|
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, true),
|
||||||
oidc.ResponseTypeCode},
|
oidc.ResponseTypeCode,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"implicit flow registered ok",
|
"implicit flow registered ok",
|
||||||
args{"https://registered.com/callback",
|
args{
|
||||||
|
"https://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
||||||
oidc.ResponseTypeIDToken},
|
oidc.ResponseTypeIDToken,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"implicit flow unregistered fails",
|
"implicit flow unregistered fails",
|
||||||
args{"https://unregistered.com/callback",
|
args{
|
||||||
|
"https://unregistered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
mock.NewClientWithConfig(t, []string{"https://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
||||||
oidc.ResponseTypeIDToken},
|
oidc.ResponseTypeIDToken,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"implicit flow registered http localhost native ok",
|
"implicit flow registered http localhost native ok",
|
||||||
args{"http://localhost:9999/callback",
|
args{
|
||||||
|
"http://localhost:9999/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://localhost:9999/callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://localhost:9999/callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeIDToken},
|
oidc.ResponseTypeIDToken,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"implicit flow registered http localhost web fails",
|
"implicit flow registered http localhost web fails",
|
||||||
args{"http://localhost:9999/callback",
|
args{
|
||||||
|
"http://localhost:9999/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://localhost:9999/callback"}, op.ApplicationTypeWeb, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://localhost:9999/callback"}, op.ApplicationTypeWeb, nil, false),
|
||||||
oidc.ResponseTypeIDToken},
|
oidc.ResponseTypeIDToken,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"implicit flow registered http localhost user agent fails",
|
"implicit flow registered http localhost user agent fails",
|
||||||
args{"http://localhost:9999/callback",
|
args{
|
||||||
|
"http://localhost:9999/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://localhost:9999/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://localhost:9999/callback"}, op.ApplicationTypeUserAgent, nil, false),
|
||||||
oidc.ResponseTypeIDToken},
|
oidc.ResponseTypeIDToken,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"implicit flow http non localhost fails",
|
"implicit flow http non localhost fails",
|
||||||
args{"http://registered.com/callback",
|
args{
|
||||||
|
"http://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeIDToken},
|
oidc.ResponseTypeIDToken,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"implicit flow custom fails",
|
"implicit flow custom fails",
|
||||||
args{"custom://callback",
|
args{
|
||||||
|
"custom://callback",
|
||||||
mock.NewClientWithConfig(t, []string{"custom://callback"}, op.ApplicationTypeNative, nil, false),
|
mock.NewClientWithConfig(t, []string{"custom://callback"}, op.ApplicationTypeNative, nil, false),
|
||||||
oidc.ResponseTypeIDToken},
|
oidc.ResponseTypeIDToken,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"implicit flow dev mode http ok",
|
"implicit flow dev mode http ok",
|
||||||
args{"http://registered.com/callback",
|
args{
|
||||||
|
"http://registered.com/callback",
|
||||||
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, true),
|
mock.NewClientWithConfig(t, []string{"http://registered.com/callback"}, op.ApplicationTypeUserAgent, nil, true),
|
||||||
oidc.ResponseTypeIDToken},
|
oidc.ResponseTypeIDToken,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -647,20 +701,26 @@ func TestValidateAuthReqResponseType(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"empty response type",
|
"empty response type",
|
||||||
args{"",
|
args{
|
||||||
mock.NewClientWithConfig(t, nil, op.ApplicationTypeNative, []oidc.ResponseType{oidc.ResponseTypeCode}, true)},
|
"",
|
||||||
|
mock.NewClientWithConfig(t, nil, op.ApplicationTypeNative, []oidc.ResponseType{oidc.ResponseTypeCode}, true),
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"response type missing in client config",
|
"response type missing in client config",
|
||||||
args{oidc.ResponseTypeIDToken,
|
args{
|
||||||
mock.NewClientWithConfig(t, nil, op.ApplicationTypeNative, []oidc.ResponseType{oidc.ResponseTypeCode}, true)},
|
oidc.ResponseTypeIDToken,
|
||||||
|
mock.NewClientWithConfig(t, nil, op.ApplicationTypeNative, []oidc.ResponseType{oidc.ResponseTypeCode}, true),
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"valid response type",
|
"valid response type",
|
||||||
args{oidc.ResponseTypeCode,
|
args{
|
||||||
mock.NewClientWithConfig(t, nil, op.ApplicationTypeNative, []oidc.ResponseType{oidc.ResponseTypeCode}, true)},
|
oidc.ResponseTypeCode,
|
||||||
|
mock.NewClientWithConfig(t, nil, op.ApplicationTypeNative, []oidc.ResponseType{oidc.ResponseTypeCode}, true),
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ func TestValidateIssuer(t *testing.T) {
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
//ensure env is not set
|
// ensure env is not set
|
||||||
//nolint:errcheck
|
//nolint:errcheck
|
||||||
os.Unsetenv(OidcDevMode)
|
os.Unsetenv(OidcDevMode)
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
|
@ -56,7 +56,7 @@ var DefaultSupportedScopes = []string{
|
||||||
}
|
}
|
||||||
|
|
||||||
func Scopes(c Configuration) []string {
|
func Scopes(c Configuration) []string {
|
||||||
return DefaultSupportedScopes //TODO: config
|
return DefaultSupportedScopes // TODO: config
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResponseTypes(c Configuration) []string {
|
func ResponseTypes(c Configuration) []string {
|
||||||
|
@ -64,7 +64,7 @@ func ResponseTypes(c Configuration) []string {
|
||||||
string(oidc.ResponseTypeCode),
|
string(oidc.ResponseTypeCode),
|
||||||
string(oidc.ResponseTypeIDTokenOnly),
|
string(oidc.ResponseTypeIDTokenOnly),
|
||||||
string(oidc.ResponseTypeIDToken),
|
string(oidc.ResponseTypeIDToken),
|
||||||
} //TODO: ok for now, check later if dynamic needed
|
} // TODO: ok for now, check later if dynamic needed
|
||||||
}
|
}
|
||||||
|
|
||||||
func GrantTypes(c Configuration) []oidc.GrantType {
|
func GrantTypes(c Configuration) []oidc.GrantType {
|
||||||
|
@ -88,7 +88,7 @@ func GrantTypes(c Configuration) []oidc.GrantType {
|
||||||
}
|
}
|
||||||
|
|
||||||
func SupportedClaims(c Configuration) []string {
|
func SupportedClaims(c Configuration) []string {
|
||||||
return []string{ //TODO: config
|
return []string{ // TODO: config
|
||||||
"sub",
|
"sub",
|
||||||
"aud",
|
"aud",
|
||||||
"exp",
|
"exp",
|
||||||
|
@ -121,7 +121,7 @@ func SigAlgorithms(s Signer) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func SubjectTypes(c Configuration) []string {
|
func SubjectTypes(c Configuration) []string {
|
||||||
return []string{"public"} //TODO: config
|
return []string{"public"} // TODO: config
|
||||||
}
|
}
|
||||||
|
|
||||||
func AuthMethodsTokenEndpoint(c Configuration) []oidc.AuthMethod {
|
func AuthMethodsTokenEndpoint(c Configuration) []oidc.AuthMethod {
|
||||||
|
|
|
@ -27,7 +27,7 @@ func (e Endpoint) Absolute(host string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Endpoint) Validate() error {
|
func (e Endpoint) Validate() error {
|
||||||
return nil //TODO:
|
return nil // TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
func absoluteEndpoint(host, endpoint string) string {
|
func absoluteEndpoint(host, endpoint string) string {
|
||||||
|
|
|
@ -87,7 +87,7 @@ func TestEndpoint_Absolute(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: impl test
|
// TODO: impl test
|
||||||
func TestEndpoint_Validate(t *testing.T) {
|
func TestEndpoint_Validate(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
@ -68,6 +68,7 @@ type Verifier struct{}
|
||||||
func (v *Verifier) Verify(ctx context.Context, accessToken, idToken string) (*oidc.IDTokenClaims, error) {
|
func (v *Verifier) Verify(ctx context.Context, accessToken, idToken string) (*oidc.IDTokenClaims, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Verifier) VerifyIDToken(ctx context.Context, idToken string) (*oidc.IDTokenClaims, error) {
|
func (v *Verifier) VerifyIDToken(ctx context.Context, idToken string) (*oidc.IDTokenClaims, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@ func NewClientExpectAny(t *testing.T, appType op.ApplicationType) op.Client {
|
||||||
"https://registered.com/callback",
|
"https://registered.com/callback",
|
||||||
"http://registered.com/callback",
|
"http://registered.com/callback",
|
||||||
"http://localhost:9999/callback",
|
"http://localhost:9999/callback",
|
||||||
"custom://callback"})
|
"custom://callback",
|
||||||
|
})
|
||||||
m.EXPECT().ApplicationType().AnyTimes().Return(appType)
|
m.EXPECT().ApplicationType().AnyTimes().Return(appType)
|
||||||
m.EXPECT().LoginURL(gomock.Any()).AnyTimes().DoAndReturn(
|
m.EXPECT().LoginURL(gomock.Any()).AnyTimes().DoAndReturn(
|
||||||
func(id string) string {
|
func(id string) string {
|
||||||
|
|
|
@ -44,6 +44,7 @@ func NewMockStorageSigningKeyInvalid(t *testing.T) op.Storage {
|
||||||
ExpectSigningKeyInvalid(m)
|
ExpectSigningKeyInvalid(m)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMockStorageSigningKey(t *testing.T) op.Storage {
|
func NewMockStorageSigningKey(t *testing.T) op.Storage {
|
||||||
m := NewStorage(t)
|
m := NewStorage(t)
|
||||||
ExpectSigningKey(m)
|
ExpectSigningKey(m)
|
||||||
|
@ -120,6 +121,7 @@ func (c *ConfClient) RedirectURIs() []string {
|
||||||
"custom://callback",
|
"custom://callback",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) PostLogoutRedirectURIs() []string {
|
func (c *ConfClient) PostLogoutRedirectURIs() []string {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
@ -143,34 +145,43 @@ func (c *ConfClient) GetID() string {
|
||||||
func (c *ConfClient) AccessTokenLifetime() time.Duration {
|
func (c *ConfClient) AccessTokenLifetime() time.Duration {
|
||||||
return 5 * time.Minute
|
return 5 * time.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) IDTokenLifetime() time.Duration {
|
func (c *ConfClient) IDTokenLifetime() time.Duration {
|
||||||
return 5 * time.Minute
|
return 5 * time.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) AccessTokenType() op.AccessTokenType {
|
func (c *ConfClient) AccessTokenType() op.AccessTokenType {
|
||||||
return c.accessTokenType
|
return c.accessTokenType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) ResponseTypes() []oidc.ResponseType {
|
func (c *ConfClient) ResponseTypes() []oidc.ResponseType {
|
||||||
return c.responseTypes
|
return c.responseTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) GrantTypes() []oidc.GrantType {
|
func (c *ConfClient) GrantTypes() []oidc.GrantType {
|
||||||
return c.grantTypes
|
return c.grantTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) DevMode() bool {
|
func (c *ConfClient) DevMode() bool {
|
||||||
return c.devMode
|
return c.devMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) AllowedScopes() []string {
|
func (c *ConfClient) AllowedScopes() []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) RestrictAdditionalIdTokenScopes() func(scopes []string) []string {
|
func (c *ConfClient) RestrictAdditionalIdTokenScopes() func(scopes []string) []string {
|
||||||
return func(scopes []string) []string {
|
return func(scopes []string) []string {
|
||||||
return scopes
|
return scopes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) RestrictAdditionalAccessTokenScopes() func(scopes []string) []string {
|
func (c *ConfClient) RestrictAdditionalAccessTokenScopes() func(scopes []string) []string {
|
||||||
return func(scopes []string) []string {
|
return func(scopes []string) []string {
|
||||||
return scopes
|
return scopes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) IsScopeAllowed(scope string) bool {
|
func (c *ConfClient) IsScopeAllowed(scope string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
38
pkg/op/op.go
38
pkg/op/op.go
|
@ -29,17 +29,15 @@ const (
|
||||||
defaultKeysEndpoint = "keys"
|
defaultKeysEndpoint = "keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var DefaultEndpoints = &endpoints{
|
||||||
DefaultEndpoints = &endpoints{
|
Authorization: NewEndpoint(defaultAuthorizationEndpoint),
|
||||||
Authorization: NewEndpoint(defaultAuthorizationEndpoint),
|
Token: NewEndpoint(defaultTokenEndpoint),
|
||||||
Token: NewEndpoint(defaultTokenEndpoint),
|
Introspection: NewEndpoint(defaultIntrospectEndpoint),
|
||||||
Introspection: NewEndpoint(defaultIntrospectEndpoint),
|
Userinfo: NewEndpoint(defaultUserinfoEndpoint),
|
||||||
Userinfo: NewEndpoint(defaultUserinfoEndpoint),
|
Revocation: NewEndpoint(defaultRevocationEndpoint),
|
||||||
Revocation: NewEndpoint(defaultRevocationEndpoint),
|
EndSession: NewEndpoint(defaultEndSessionEndpoint),
|
||||||
EndSession: NewEndpoint(defaultEndSessionEndpoint),
|
JwksURI: NewEndpoint(defaultKeysEndpoint),
|
||||||
JwksURI: NewEndpoint(defaultKeysEndpoint),
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type OpenIDProvider interface {
|
type OpenIDProvider interface {
|
||||||
Configuration
|
Configuration
|
||||||
|
@ -83,7 +81,7 @@ func CreateRouter(o OpenIDProvider, interceptors ...HttpInterceptor) *mux.Router
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthCallbackURL builds the url for the redirect (with the requestID) after a successful login
|
// AuthCallbackURL builds the url for the redirect (with the requestID) after a successful login
|
||||||
func AuthCallbackURL(o OpenIDProvider) func(string) string {
|
func AuthCallbackURL(o OpenIDProvider) func(string) string {
|
||||||
return func(requestID string) string {
|
return func(requestID string) string {
|
||||||
return o.AuthorizationEndpoint().Absolute(o.Issuer()) + authCallbackPathSuffix + "?id=" + requestID
|
return o.AuthorizationEndpoint().Absolute(o.Issuer()) + authCallbackPathSuffix + "?id=" + requestID
|
||||||
|
@ -117,8 +115,8 @@ type endpoints struct {
|
||||||
JwksURI Endpoint
|
JwksURI Endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewOpenIDProvider creates a provider. The provider provides (with HttpHandler())
|
// NewOpenIDProvider creates a provider. The provider provides (with HttpHandler())
|
||||||
//a http.Router that handles a suite of endpoints (some paths can be overridden):
|
// a http.Router that handles a suite of endpoints (some paths can be overridden):
|
||||||
// /healthz
|
// /healthz
|
||||||
// /ready
|
// /ready
|
||||||
// /.well-known/openid-configuration
|
// /.well-known/openid-configuration
|
||||||
|
@ -130,10 +128,10 @@ type endpoints struct {
|
||||||
// /revoke
|
// /revoke
|
||||||
// /end_session
|
// /end_session
|
||||||
// /keys
|
// /keys
|
||||||
//This does not include login. Login is handled with a redirect that includes the
|
// This does not include login. Login is handled with a redirect that includes the
|
||||||
//request ID. The redirect for logins is specified per-client by Client.LoginURL().
|
// request ID. The redirect for logins is specified per-client by Client.LoginURL().
|
||||||
//Successful logins should mark the request as authorized and redirect back to to
|
// Successful logins should mark the request as authorized and redirect back to to
|
||||||
//op.AuthCallbackURL(provider) which is probably /callback. On the redirect back
|
// op.AuthCallbackURL(provider) which is probably /callback. On the redirect back
|
||||||
// to the AuthCallbackURL, the request id should be passed as the "id" parameter.
|
// to the AuthCallbackURL, the request id should be passed as the "id" parameter.
|
||||||
func NewOpenIDProvider(ctx context.Context, config *Config, storage Storage, opOpts ...Option) (OpenIDProvider, error) {
|
func NewOpenIDProvider(ctx context.Context, config *Config, storage Storage, opOpts ...Option) (OpenIDProvider, error) {
|
||||||
err := ValidateIssuer(config.Issuer)
|
err := ValidateIssuer(config.Issuer)
|
||||||
|
@ -354,8 +352,8 @@ type openIDKeySet struct {
|
||||||
Storage
|
Storage
|
||||||
}
|
}
|
||||||
|
|
||||||
//VerifySignature implements the oidc.KeySet interface
|
// VerifySignature implements the oidc.KeySet interface
|
||||||
//providing an implementation for the keys stored in the OP Storage interface
|
// providing an implementation for the keys stored in the OP Storage interface
|
||||||
func (o *openIDKeySet) VerifySignature(ctx context.Context, jws *jose.JSONWebSignature) ([]byte, error) {
|
func (o *openIDKeySet) VerifySignature(ctx context.Context, jws *jose.JSONWebSignature) ([]byte, error) {
|
||||||
keySet, err := o.Storage.GetKeySet(ctx)
|
keySet, err := o.Storage.GetKeySet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -39,6 +39,7 @@ func ReadySigner(s Signer) ProbesFn {
|
||||||
return s.Health(ctx)
|
return s.Health(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadyStorage(s Storage) ProbesFn {
|
func ReadyStorage(s Storage) ProbesFn {
|
||||||
return func(ctx context.Context) error {
|
return func(ctx context.Context) error {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"github.com/zitadel/oidc/pkg/oidc"
|
"github.com/zitadel/oidc/pkg/oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
//ClientCredentialsExchange handles the OAuth 2.0 client_credentials grant, including
|
// ClientCredentialsExchange handles the OAuth 2.0 client_credentials grant, including
|
||||||
//parsing, validating, authorizing the client and finally returning a token
|
// parsing, validating, authorizing the client and finally returning a token
|
||||||
func ClientCredentialsExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
func ClientCredentialsExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||||
request, err := ParseClientCredentialsRequest(r, exchanger.Decoder())
|
request, err := ParseClientCredentialsRequest(r, exchanger.Decoder())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -32,7 +32,7 @@ func ClientCredentialsExchange(w http.ResponseWriter, r *http.Request, exchanger
|
||||||
httphelper.MarshalJSON(w, resp)
|
httphelper.MarshalJSON(w, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ParseClientCredentialsRequest parsed the http request into a oidc.ClientCredentialsRequest
|
// ParseClientCredentialsRequest parsed the http request into a oidc.ClientCredentialsRequest
|
||||||
func ParseClientCredentialsRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.ClientCredentialsRequest, error) {
|
func ParseClientCredentialsRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.ClientCredentialsRequest, error) {
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -63,8 +63,8 @@ func ParseClientCredentialsRequest(r *http.Request, decoder httphelper.Decoder)
|
||||||
return request, nil
|
return request, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateClientCredentialsRequest validates the refresh_token request parameters including authorization check of the client
|
// ValidateClientCredentialsRequest validates the refresh_token request parameters including authorization check of the client
|
||||||
//and returns the data representing the original auth request corresponding to the refresh_token
|
// and returns the data representing the original auth request corresponding to the refresh_token
|
||||||
func ValidateClientCredentialsRequest(ctx context.Context, request *oidc.ClientCredentialsRequest, exchanger Exchanger) (TokenRequest, Client, error) {
|
func ValidateClientCredentialsRequest(ctx context.Context, request *oidc.ClientCredentialsRequest, exchanger Exchanger) (TokenRequest, Client, error) {
|
||||||
storage, ok := exchanger.Storage().(ClientCredentialsStorage)
|
storage, ok := exchanger.Storage().(ClientCredentialsStorage)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"github.com/zitadel/oidc/pkg/oidc"
|
"github.com/zitadel/oidc/pkg/oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
//CodeExchange handles the OAuth 2.0 authorization_code grant, including
|
// CodeExchange handles the OAuth 2.0 authorization_code grant, including
|
||||||
//parsing, validating, authorizing the client and finally exchanging the code for tokens
|
// parsing, validating, authorizing the client and finally exchanging the code for tokens
|
||||||
func CodeExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
func CodeExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||||
tokenReq, err := ParseAccessTokenRequest(r, exchanger.Decoder())
|
tokenReq, err := ParseAccessTokenRequest(r, exchanger.Decoder())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -32,7 +32,7 @@ func CodeExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||||
httphelper.MarshalJSON(w, resp)
|
httphelper.MarshalJSON(w, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ParseAccessTokenRequest parsed the http request into a oidc.AccessTokenRequest
|
// ParseAccessTokenRequest parsed the http request into a oidc.AccessTokenRequest
|
||||||
func ParseAccessTokenRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.AccessTokenRequest, error) {
|
func ParseAccessTokenRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.AccessTokenRequest, error) {
|
||||||
request := new(oidc.AccessTokenRequest)
|
request := new(oidc.AccessTokenRequest)
|
||||||
err := ParseAuthenticatedTokenRequest(r, decoder, request)
|
err := ParseAuthenticatedTokenRequest(r, decoder, request)
|
||||||
|
@ -42,8 +42,8 @@ func ParseAccessTokenRequest(r *http.Request, decoder httphelper.Decoder) (*oidc
|
||||||
return request, nil
|
return request, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateAccessTokenRequest validates the token request parameters including authorization check of the client
|
// ValidateAccessTokenRequest validates the token request parameters including authorization check of the client
|
||||||
//and returns the previous created auth request corresponding to the auth code
|
// and returns the previous created auth request corresponding to the auth code
|
||||||
func ValidateAccessTokenRequest(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (AuthRequest, Client, error) {
|
func ValidateAccessTokenRequest(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (AuthRequest, Client, error) {
|
||||||
authReq, client, err := AuthorizeCodeClient(ctx, tokenReq, exchanger)
|
authReq, client, err := AuthorizeCodeClient(ctx, tokenReq, exchanger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -61,8 +61,8 @@ func ValidateAccessTokenRequest(ctx context.Context, tokenReq *oidc.AccessTokenR
|
||||||
return authReq, client, nil
|
return authReq, client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthorizeCodeClient checks the authorization of the client and that the used method was the one previously registered.
|
// AuthorizeCodeClient checks the authorization of the client and that the used method was the one previously registered.
|
||||||
//It than returns the auth request corresponding to the auth code
|
// It than returns the auth request corresponding to the auth code
|
||||||
func AuthorizeCodeClient(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (request AuthRequest, client Client, err error) {
|
func AuthorizeCodeClient(ctx context.Context, tokenReq *oidc.AccessTokenRequest, exchanger Exchanger) (request AuthRequest, client Client, err error) {
|
||||||
if tokenReq.ClientAssertionType == oidc.ClientAssertionTypeJWTAssertion {
|
if tokenReq.ClientAssertionType == oidc.ClientAssertionTypeJWTAssertion {
|
||||||
jwtExchanger, ok := exchanger.(JWTAuthorizationGrantExchanger)
|
jwtExchanger, ok := exchanger.(JWTAuthorizationGrantExchanger)
|
||||||
|
@ -102,7 +102,7 @@ func AuthorizeCodeClient(ctx context.Context, tokenReq *oidc.AccessTokenRequest,
|
||||||
return request, client, err
|
return request, client, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthRequestByCode returns the AuthRequest previously created from Storage corresponding to the auth code or an error
|
// AuthRequestByCode returns the AuthRequest previously created from Storage corresponding to the auth code or an error
|
||||||
func AuthRequestByCode(ctx context.Context, storage Storage, code string) (AuthRequest, error) {
|
func AuthRequestByCode(ctx context.Context, storage Storage, code string) (AuthRequest, error) {
|
||||||
authReq, err := storage.AuthRequestByCode(ctx, code)
|
authReq, err := storage.AuthRequestByCode(ctx, code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
//TokenExchange will handle the OAuth 2.0 token exchange grant ("urn:ietf:params:oauth:grant-type:token-exchange")
|
// TokenExchange will handle the OAuth 2.0 token exchange grant ("urn:ietf:params:oauth:grant-type:token-exchange")
|
||||||
func TokenExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
func TokenExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||||
RequestError(w, r, errors.New("unimplemented"))
|
RequestError(w, r, errors.New("unimplemented"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ type JWTAuthorizationGrantExchanger interface {
|
||||||
JWTProfileVerifier() JWTProfileVerifier
|
JWTProfileVerifier() JWTProfileVerifier
|
||||||
}
|
}
|
||||||
|
|
||||||
//JWTProfile handles the OAuth 2.0 JWT Profile Authorization Grant https://tools.ietf.org/html/rfc7523#section-2.1
|
// JWTProfile handles the OAuth 2.0 JWT Profile Authorization Grant https://tools.ietf.org/html/rfc7523#section-2.1
|
||||||
func JWTProfile(w http.ResponseWriter, r *http.Request, exchanger JWTAuthorizationGrantExchanger) {
|
func JWTProfile(w http.ResponseWriter, r *http.Request, exchanger JWTAuthorizationGrantExchanger) {
|
||||||
profileRequest, err := ParseJWTProfileGrantRequest(r, exchanger.Decoder())
|
profileRequest, err := ParseJWTProfileGrantRequest(r, exchanger.Decoder())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -53,7 +53,7 @@ func ParseJWTProfileGrantRequest(r *http.Request, decoder httphelper.Decoder) (*
|
||||||
return tokenReq, nil
|
return tokenReq, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//CreateJWTTokenResponse creates
|
// CreateJWTTokenResponse creates
|
||||||
func CreateJWTTokenResponse(ctx context.Context, tokenRequest TokenRequest, creator TokenCreator) (*oidc.AccessTokenResponse, error) {
|
func CreateJWTTokenResponse(ctx context.Context, tokenRequest TokenRequest, creator TokenCreator) (*oidc.AccessTokenResponse, error) {
|
||||||
id, exp, err := creator.Storage().CreateAccessToken(ctx, tokenRequest)
|
id, exp, err := creator.Storage().CreateAccessToken(ctx, tokenRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -71,7 +71,7 @@ func CreateJWTTokenResponse(ctx context.Context, tokenRequest TokenRequest, crea
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ParseJWTProfileRequest has been renamed to ParseJWTProfileGrantRequest
|
// ParseJWTProfileRequest has been renamed to ParseJWTProfileGrantRequest
|
||||||
//
|
//
|
||||||
//deprecated: use ParseJWTProfileGrantRequest
|
//deprecated: use ParseJWTProfileGrantRequest
|
||||||
func ParseJWTProfileRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.JWTProfileGrantRequest, error) {
|
func ParseJWTProfileRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.JWTProfileGrantRequest, error) {
|
||||||
|
|
|
@ -21,8 +21,8 @@ type RefreshTokenRequest interface {
|
||||||
SetCurrentScopes(scopes []string)
|
SetCurrentScopes(scopes []string)
|
||||||
}
|
}
|
||||||
|
|
||||||
//RefreshTokenExchange handles the OAuth 2.0 refresh_token grant, including
|
// RefreshTokenExchange handles the OAuth 2.0 refresh_token grant, including
|
||||||
//parsing, validating, authorizing the client and finally exchanging the refresh_token for new tokens
|
// parsing, validating, authorizing the client and finally exchanging the refresh_token for new tokens
|
||||||
func RefreshTokenExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
func RefreshTokenExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||||
tokenReq, err := ParseRefreshTokenRequest(r, exchanger.Decoder())
|
tokenReq, err := ParseRefreshTokenRequest(r, exchanger.Decoder())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -41,7 +41,7 @@ func RefreshTokenExchange(w http.ResponseWriter, r *http.Request, exchanger Exch
|
||||||
httphelper.MarshalJSON(w, resp)
|
httphelper.MarshalJSON(w, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ParseRefreshTokenRequest parsed the http request into a oidc.RefreshTokenRequest
|
// ParseRefreshTokenRequest parsed the http request into a oidc.RefreshTokenRequest
|
||||||
func ParseRefreshTokenRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.RefreshTokenRequest, error) {
|
func ParseRefreshTokenRequest(r *http.Request, decoder httphelper.Decoder) (*oidc.RefreshTokenRequest, error) {
|
||||||
request := new(oidc.RefreshTokenRequest)
|
request := new(oidc.RefreshTokenRequest)
|
||||||
err := ParseAuthenticatedTokenRequest(r, decoder, request)
|
err := ParseAuthenticatedTokenRequest(r, decoder, request)
|
||||||
|
@ -51,8 +51,8 @@ func ParseRefreshTokenRequest(r *http.Request, decoder httphelper.Decoder) (*oid
|
||||||
return request, nil
|
return request, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateRefreshTokenRequest validates the refresh_token request parameters including authorization check of the client
|
// ValidateRefreshTokenRequest validates the refresh_token request parameters including authorization check of the client
|
||||||
//and returns the data representing the original auth request corresponding to the refresh_token
|
// and returns the data representing the original auth request corresponding to the refresh_token
|
||||||
func ValidateRefreshTokenRequest(ctx context.Context, tokenReq *oidc.RefreshTokenRequest, exchanger Exchanger) (RefreshTokenRequest, Client, error) {
|
func ValidateRefreshTokenRequest(ctx context.Context, tokenReq *oidc.RefreshTokenRequest, exchanger Exchanger) (RefreshTokenRequest, Client, error) {
|
||||||
if tokenReq.RefreshToken == "" {
|
if tokenReq.RefreshToken == "" {
|
||||||
return nil, nil, oidc.ErrInvalidRequest().WithDescription("refresh_token missing")
|
return nil, nil, oidc.ErrInvalidRequest().WithDescription("refresh_token missing")
|
||||||
|
@ -70,9 +70,9 @@ func ValidateRefreshTokenRequest(ctx context.Context, tokenReq *oidc.RefreshToke
|
||||||
return request, client, nil
|
return request, client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateRefreshTokenScopes validates that the requested scope is a subset of the original auth request scope
|
// ValidateRefreshTokenScopes validates that the requested scope is a subset of the original auth request scope
|
||||||
//it will set the requested scopes as current scopes onto RefreshTokenRequest
|
// it will set the requested scopes as current scopes onto RefreshTokenRequest
|
||||||
//if empty the original scopes will be used
|
// if empty the original scopes will be used
|
||||||
func ValidateRefreshTokenScopes(requestedScopes []string, authRequest RefreshTokenRequest) error {
|
func ValidateRefreshTokenScopes(requestedScopes []string, authRequest RefreshTokenRequest) error {
|
||||||
if len(requestedScopes) == 0 {
|
if len(requestedScopes) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -86,8 +86,8 @@ func ValidateRefreshTokenScopes(requestedScopes []string, authRequest RefreshTok
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthorizeRefreshClient checks the authorization of the client and that the used method was the one previously registered.
|
// AuthorizeRefreshClient checks the authorization of the client and that the used method was the one previously registered.
|
||||||
//It than returns the data representing the original auth request corresponding to the refresh_token
|
// It than returns the data representing the original auth request corresponding to the refresh_token
|
||||||
func AuthorizeRefreshClient(ctx context.Context, tokenReq *oidc.RefreshTokenRequest, exchanger Exchanger) (request RefreshTokenRequest, client Client, err error) {
|
func AuthorizeRefreshClient(ctx context.Context, tokenReq *oidc.RefreshTokenRequest, exchanger Exchanger) (request RefreshTokenRequest, client Client, err error) {
|
||||||
if tokenReq.ClientAssertionType == oidc.ClientAssertionTypeJWTAssertion {
|
if tokenReq.ClientAssertionType == oidc.ClientAssertionTypeJWTAssertion {
|
||||||
jwtExchanger, ok := exchanger.(JWTAuthorizationGrantExchanger)
|
jwtExchanger, ok := exchanger.(JWTAuthorizationGrantExchanger)
|
||||||
|
@ -128,8 +128,8 @@ func AuthorizeRefreshClient(ctx context.Context, tokenReq *oidc.RefreshTokenRequ
|
||||||
return request, client, err
|
return request, client, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//RefreshTokenRequestByRefreshToken returns the RefreshTokenRequest (data representing the original auth request)
|
// RefreshTokenRequestByRefreshToken returns the RefreshTokenRequest (data representing the original auth request)
|
||||||
//corresponding to the refresh_token from Storage or an error
|
// corresponding to the refresh_token from Storage or an error
|
||||||
func RefreshTokenRequestByRefreshToken(ctx context.Context, storage Storage, refreshToken string) (RefreshTokenRequest, error) {
|
func RefreshTokenRequestByRefreshToken(ctx context.Context, storage Storage, refreshToken string) (RefreshTokenRequest, error) {
|
||||||
request, err := storage.TokenRequestByRefreshToken(ctx, refreshToken)
|
request, err := storage.TokenRequestByRefreshToken(ctx, refreshToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -29,7 +29,7 @@ func tokenHandler(exchanger Exchanger) func(w http.ResponseWriter, r *http.Reque
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Exchange performs a token exchange appropriate for the grant type
|
// Exchange performs a token exchange appropriate for the grant type
|
||||||
func Exchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
func Exchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||||
grantType := r.FormValue("grant_type")
|
grantType := r.FormValue("grant_type")
|
||||||
switch grantType {
|
switch grantType {
|
||||||
|
@ -63,15 +63,15 @@ func Exchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||||
RequestError(w, r, oidc.ErrUnsupportedGrantType().WithDescription("%s not supported", grantType))
|
RequestError(w, r, oidc.ErrUnsupportedGrantType().WithDescription("%s not supported", grantType))
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthenticatedTokenRequest is a helper interface for ParseAuthenticatedTokenRequest
|
// AuthenticatedTokenRequest is a helper interface for ParseAuthenticatedTokenRequest
|
||||||
//it is implemented by oidc.AuthRequest and oidc.RefreshTokenRequest
|
// it is implemented by oidc.AuthRequest and oidc.RefreshTokenRequest
|
||||||
type AuthenticatedTokenRequest interface {
|
type AuthenticatedTokenRequest interface {
|
||||||
SetClientID(string)
|
SetClientID(string)
|
||||||
SetClientSecret(string)
|
SetClientSecret(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ParseAuthenticatedTokenRequest parses the client_id and client_secret from the HTTP request from either
|
// ParseAuthenticatedTokenRequest parses the client_id and client_secret from the HTTP request from either
|
||||||
//HTTP Basic Auth header or form body and sets them into the provided authenticatedTokenRequest interface
|
// HTTP Basic Auth header or form body and sets them into the provided authenticatedTokenRequest interface
|
||||||
func ParseAuthenticatedTokenRequest(r *http.Request, decoder httphelper.Decoder, request AuthenticatedTokenRequest) error {
|
func ParseAuthenticatedTokenRequest(r *http.Request, decoder httphelper.Decoder, request AuthenticatedTokenRequest) error {
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -98,7 +98,7 @@ func ParseAuthenticatedTokenRequest(r *http.Request, decoder httphelper.Decoder,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthorizeClientIDSecret authorizes a client by validating the client_id and client_secret (Basic Auth and POST)
|
// AuthorizeClientIDSecret authorizes a client by validating the client_id and client_secret (Basic Auth and POST)
|
||||||
func AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string, storage Storage) error {
|
func AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string, storage Storage) error {
|
||||||
err := storage.AuthorizeClientIDSecret(ctx, clientID, clientSecret)
|
err := storage.AuthorizeClientIDSecret(ctx, clientID, clientSecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -107,8 +107,8 @@ func AuthorizeClientIDSecret(ctx context.Context, clientID, clientSecret string,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthorizeCodeChallenge authorizes a client by validating the code_verifier against the previously sent
|
// AuthorizeCodeChallenge authorizes a client by validating the code_verifier against the previously sent
|
||||||
//code_challenge of the auth request (PKCE)
|
// code_challenge of the auth request (PKCE)
|
||||||
func AuthorizeCodeChallenge(tokenReq *oidc.AccessTokenRequest, challenge *oidc.CodeChallenge) error {
|
func AuthorizeCodeChallenge(tokenReq *oidc.AccessTokenRequest, challenge *oidc.CodeChallenge) error {
|
||||||
if tokenReq.CodeVerifier == "" {
|
if tokenReq.CodeVerifier == "" {
|
||||||
return oidc.ErrInvalidRequest().WithDescription("code_challenge required")
|
return oidc.ErrInvalidRequest().WithDescription("code_challenge required")
|
||||||
|
@ -119,8 +119,8 @@ func AuthorizeCodeChallenge(tokenReq *oidc.AccessTokenRequest, challenge *oidc.C
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//AuthorizePrivateJWTKey authorizes a client by validating the client_assertion's signature with a previously
|
// AuthorizePrivateJWTKey authorizes a client by validating the client_assertion's signature with a previously
|
||||||
//registered public key (JWT Profile)
|
// registered public key (JWT Profile)
|
||||||
func AuthorizePrivateJWTKey(ctx context.Context, clientAssertion string, exchanger JWTAuthorizationGrantExchanger) (Client, error) {
|
func AuthorizePrivateJWTKey(ctx context.Context, clientAssertion string, exchanger JWTAuthorizationGrantExchanger) (Client, error) {
|
||||||
jwtReq, err := VerifyJWTAssertion(ctx, clientAssertion, exchanger.JWTProfileVerifier())
|
jwtReq, err := VerifyJWTAssertion(ctx, clientAssertion, exchanger.JWTProfileVerifier())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -136,7 +136,7 @@ func AuthorizePrivateJWTKey(ctx context.Context, clientAssertion string, exchang
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//ValidateGrantType ensures that the requested grant_type is allowed by the Client
|
// ValidateGrantType ensures that the requested grant_type is allowed by the Client
|
||||||
func ValidateGrantType(client Client, grantType oidc.GrantType) bool {
|
func ValidateGrantType(client Client, grantType oidc.GrantType) bool {
|
||||||
if client == nil {
|
if client == nil {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -54,9 +54,9 @@ func ParseTokenRevocationRequest(r *http.Request, revoker Revoker) (token, token
|
||||||
}
|
}
|
||||||
req := new(struct {
|
req := new(struct {
|
||||||
oidc.RevocationRequest
|
oidc.RevocationRequest
|
||||||
oidc.ClientAssertionParams //for auth_method private_key_jwt
|
oidc.ClientAssertionParams // for auth_method private_key_jwt
|
||||||
ClientID string `schema:"client_id"` //for auth_method none and post
|
ClientID string `schema:"client_id"` // for auth_method none and post
|
||||||
ClientSecret string `schema:"client_secret"` //for auth_method post
|
ClientSecret string `schema:"client_secret"` // for auth_method post
|
||||||
})
|
})
|
||||||
err = revoker.Decoder().Decode(req, r.Form)
|
err = revoker.Decoder().Decode(req, r.Form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -23,27 +23,27 @@ type accessTokenVerifier struct {
|
||||||
keySet oidc.KeySet
|
keySet oidc.KeySet
|
||||||
}
|
}
|
||||||
|
|
||||||
//Issuer implements oidc.Verifier interface
|
// Issuer implements oidc.Verifier interface
|
||||||
func (i *accessTokenVerifier) Issuer() string {
|
func (i *accessTokenVerifier) Issuer() string {
|
||||||
return i.issuer
|
return i.issuer
|
||||||
}
|
}
|
||||||
|
|
||||||
//MaxAgeIAT implements oidc.Verifier interface
|
// MaxAgeIAT implements oidc.Verifier interface
|
||||||
func (i *accessTokenVerifier) MaxAgeIAT() time.Duration {
|
func (i *accessTokenVerifier) MaxAgeIAT() time.Duration {
|
||||||
return i.maxAgeIAT
|
return i.maxAgeIAT
|
||||||
}
|
}
|
||||||
|
|
||||||
//Offset implements oidc.Verifier interface
|
// Offset implements oidc.Verifier interface
|
||||||
func (i *accessTokenVerifier) Offset() time.Duration {
|
func (i *accessTokenVerifier) Offset() time.Duration {
|
||||||
return i.offset
|
return i.offset
|
||||||
}
|
}
|
||||||
|
|
||||||
//SupportedSignAlgs implements AccessTokenVerifier interface
|
// SupportedSignAlgs implements AccessTokenVerifier interface
|
||||||
func (i *accessTokenVerifier) SupportedSignAlgs() []string {
|
func (i *accessTokenVerifier) SupportedSignAlgs() []string {
|
||||||
return i.supportedSignAlgs
|
return i.supportedSignAlgs
|
||||||
}
|
}
|
||||||
|
|
||||||
//KeySet implements AccessTokenVerifier interface
|
// KeySet implements AccessTokenVerifier interface
|
||||||
func (i *accessTokenVerifier) KeySet() oidc.KeySet {
|
func (i *accessTokenVerifier) KeySet() oidc.KeySet {
|
||||||
return i.keySet
|
return i.keySet
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ func NewAccessTokenVerifier(issuer string, keySet oidc.KeySet, opts ...AccessTok
|
||||||
return verifier
|
return verifier
|
||||||
}
|
}
|
||||||
|
|
||||||
//VerifyAccessToken validates the access token (issuer, signature and expiration)
|
// VerifyAccessToken validates the access token (issuer, signature and expiration)
|
||||||
func VerifyAccessToken(ctx context.Context, token string, v AccessTokenVerifier) (oidc.AccessTokenClaims, error) {
|
func VerifyAccessToken(ctx context.Context, token string, v AccessTokenVerifier) (oidc.AccessTokenClaims, error) {
|
||||||
claims := oidc.EmptyAccessTokenClaims()
|
claims := oidc.EmptyAccessTokenClaims()
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ func NewIDTokenHintVerifier(issuer string, keySet oidc.KeySet) IDTokenHintVerifi
|
||||||
return verifier
|
return verifier
|
||||||
}
|
}
|
||||||
|
|
||||||
//VerifyIDTokenHint validates the id token according to
|
// VerifyIDTokenHint validates the id token according to
|
||||||
//https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
//https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
||||||
func VerifyIDTokenHint(ctx context.Context, token string, v IDTokenHintVerifier) (oidc.IDTokenClaims, error) {
|
func VerifyIDTokenHint(ctx context.Context, token string, v IDTokenHintVerifier) (oidc.IDTokenClaims, error) {
|
||||||
claims := oidc.EmptyIDTokenClaims()
|
claims := oidc.EmptyIDTokenClaims()
|
||||||
|
|
|
@ -25,7 +25,7 @@ type jwtProfileVerifier struct {
|
||||||
offset time.Duration
|
offset time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewJWTProfileVerifier creates a oidc.Verifier for JWT Profile assertions (authorization grant and client authentication)
|
// NewJWTProfileVerifier creates a oidc.Verifier for JWT Profile assertions (authorization grant and client authentication)
|
||||||
func NewJWTProfileVerifier(storage jwtProfileKeyStorage, issuer string, maxAgeIAT, offset time.Duration, opts ...JWTProfileVerifierOption) JWTProfileVerifier {
|
func NewJWTProfileVerifier(storage jwtProfileKeyStorage, issuer string, maxAgeIAT, offset time.Duration, opts ...JWTProfileVerifierOption) JWTProfileVerifier {
|
||||||
j := &jwtProfileVerifier{
|
j := &jwtProfileVerifier{
|
||||||
storage: storage,
|
storage: storage,
|
||||||
|
@ -70,9 +70,9 @@ func (v *jwtProfileVerifier) CheckSubject(request *oidc.JWTTokenRequest) error {
|
||||||
return v.subjectCheck(request)
|
return v.subjectCheck(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
//VerifyJWTAssertion verifies the assertion string from JWT Profile (authorization grant and client authentication)
|
// VerifyJWTAssertion verifies the assertion string from JWT Profile (authorization grant and client authentication)
|
||||||
//
|
//
|
||||||
//checks audience, exp, iat, signature and that issuer and sub are the same
|
// checks audience, exp, iat, signature and that issuer and sub are the same
|
||||||
func VerifyJWTAssertion(ctx context.Context, assertion string, v JWTProfileVerifier) (*oidc.JWTTokenRequest, error) {
|
func VerifyJWTAssertion(ctx context.Context, assertion string, v JWTProfileVerifier) (*oidc.JWTTokenRequest, error) {
|
||||||
request := new(oidc.JWTTokenRequest)
|
request := new(oidc.JWTTokenRequest)
|
||||||
payload, err := oidc.ParseToken(assertion, request)
|
payload, err := oidc.ParseToken(assertion, request)
|
||||||
|
@ -119,7 +119,7 @@ type jwtProfileKeySet struct {
|
||||||
clientID string
|
clientID string
|
||||||
}
|
}
|
||||||
|
|
||||||
//VerifySignature implements oidc.KeySet by getting the public key from Storage implementation
|
// VerifySignature implements oidc.KeySet by getting the public key from Storage implementation
|
||||||
func (k *jwtProfileKeySet) VerifySignature(ctx context.Context, jws *jose.JSONWebSignature) (payload []byte, err error) {
|
func (k *jwtProfileKeySet) VerifySignature(ctx context.Context, jws *jose.JSONWebSignature) (payload []byte, err error) {
|
||||||
keyID, _ := oidc.GetKeyIDAndAlg(jws)
|
keyID, _ := oidc.GetKeyIDAndAlg(jws)
|
||||||
key, err := k.storage.GetKeyByIDAndUserID(ctx, keyID, k.clientID)
|
key, err := k.storage.GetKeyByIDAndUserID(ctx, keyID, k.clientID)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue