change some interfaces

This commit is contained in:
Livio Amstutz 2020-09-09 16:00:19 +02:00
parent bfbd4adb1c
commit eaf47fde8e
10 changed files with 130 additions and 20 deletions

View file

@ -36,6 +36,18 @@ type AuthorizeValidator interface {
//Deprecated: ValidationAuthorizer exists for historical compatibility. Use ValidationAuthorizer itself
type ValidationAuthorizer AuthorizeValidator
func authorizeHandler(authorizer Authorizer) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
Authorize(w, r, authorizer)
}
}
func authorizeCallbackHandler(authorizer Authorizer) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
AuthorizeCallback(w, r, authorizer)
}
}
//Authorize handles the authorization request, including
//parsing, validating, storing and finally redirecting to the login handler
func Authorize(w http.ResponseWriter, r *http.Request, authorizer Authorizer) {
@ -152,7 +164,7 @@ func ValidateAuthReqIDTokenHint(ctx context.Context, idTokenHint string, verifie
if idTokenHint == "" {
return "", nil
}
claims, err := verifier.VerifyIDToken(ctx, idTokenHint)
claims, err := VerifyIDTokenHint(ctx, idTokenHint, verifier)
if err != nil {
return "", ErrInvalidRequest("The id_token_hint is invalid. If you have any questions, you may contact the administrator of the application.")
}

View file

@ -279,12 +279,11 @@ func (p *DefaultOP) ClientJWTVerifier() rp.Verifier {
return p.verifier
}
func (p *DefaultOP) HandleReady(w http.ResponseWriter, r *http.Request) {
probes := []ProbesFn{
func (p *DefaultOP) Probes() []ProbesFn {
return []ProbesFn{
ReadySigner(p.Signer()),
ReadyStorage(p.Storage()),
}
Readiness(w, r, probes...)
}
func (p *DefaultOP) HandleKeys(w http.ResponseWriter, r *http.Request) {

View file

@ -10,6 +10,12 @@ type KeyProvider interface {
Storage() Storage
}
func keysHandler(k KeyProvider) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
Keys(w, r, k)
}
}
func Keys(w http.ResponseWriter, r *http.Request, k KeyProvider) {
keySet, err := k.Storage().GetKeySet(r.Context())
if err != nil {

View file

@ -16,15 +16,9 @@ const (
type OpenIDProvider interface {
Configuration
HandleReady(w http.ResponseWriter, r *http.Request)
HandleDiscovery(w http.ResponseWriter, r *http.Request)
HandleAuthorize(w http.ResponseWriter, r *http.Request)
HandleAuthorizeCallback(w http.ResponseWriter, r *http.Request)
HandleExchange(w http.ResponseWriter, r *http.Request)
HandleUserinfo(w http.ResponseWriter, r *http.Request)
//HandleEndSession(w http.ResponseWriter, r *http.Request)
HandleKeys(w http.ResponseWriter, r *http.Request)
HttpHandler() http.Handler
Authorizer
SessionEnder
Signer() Signer
Probes() []ProbesFn
@ -47,12 +41,12 @@ func CreateRouter(o OpenIDProvider, interceptors ...HttpInterceptor) *mux.Router
router.HandleFunc(healthzEndpoint, Healthz)
router.HandleFunc(readinessEndpoint, Ready(o.Probes()))
router.HandleFunc(oidc.DiscoveryEndpoint, DiscoveryHandler(o, o.Signer()))
router.Handle(o.AuthorizationEndpoint().Relative(), intercept(o.HandleAuthorize))
router.Handle(o.AuthorizationEndpoint().Relative()+"/{id}", intercept(o.HandleAuthorizeCallback))
router.Handle(o.TokenEndpoint().Relative(), intercept(o.HandleExchange))
router.HandleFunc(o.UserinfoEndpoint().Relative(), o.HandleUserinfo)
router.Handle(o.EndSessionEndpoint().Relative(), intercept(EndSessionHandler(o)))
router.HandleFunc(o.KeysEndpoint().Relative(), o.HandleKeys)
router.Handle(o.AuthorizationEndpoint().Relative(), intercept(authorizeHandler(o)))
router.Handle(o.AuthorizationEndpoint().Relative()+"/{id}", intercept(authorizeCallbackHandler(o)))
router.Handle(o.TokenEndpoint().Relative(), intercept(tokenHandler(o)))
router.HandleFunc(o.UserinfoEndpoint().Relative(), userinfoHandler(o))
router.Handle(o.EndSessionEndpoint().Relative(), intercept(endSessionHandler(o)))
router.HandleFunc(o.KeysEndpoint().Relative(), keysHandler(o))
return router
}

View file

@ -16,7 +16,7 @@ type SessionEnder interface {
DefaultLogoutRedirectURI() string
}
func EndSessionHandler(ender SessionEnder) func(http.ResponseWriter, *http.Request) {
func endSessionHandler(ender SessionEnder) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
EndSession(w, r, ender)
}

View file

@ -27,6 +27,26 @@ type VerifyExchanger interface {
ClientJWTVerifier() rp.Verifier
}
func tokenHandler(exchanger Exchanger) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
switch r.FormValue("grant_type") {
case string(oidc.GrantTypeCode):
CodeExchange(w, r, exchanger)
return
case string(oidc.GrantTypeBearer):
JWTExchange(w, r, exchanger)
return
case "excahnge":
TokenExchange(w, r, exchanger)
case "":
RequestError(w, r, ErrInvalidRequest("grant_type missing"))
return
default:
}
}
}
func CodeExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
tokenReq, err := ParseAccessTokenRequest(r, exchanger.Decoder())
if err != nil {

View file

@ -15,6 +15,12 @@ type UserinfoProvider interface {
Storage() Storage
}
func userinfoHandler(userinfoProvider UserinfoProvider) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
Userinfo(w, r, userinfoProvider)
}
}
func Userinfo(w http.ResponseWriter, r *http.Request, userinfoProvider UserinfoProvider) {
accessToken, err := getAccessToken(r, userinfoProvider.Decoder())
if err != nil {

73
pkg/op/verifier.go Normal file
View file

@ -0,0 +1,73 @@
package op
import (
"context"
"github.com/caos/oidc/pkg/oidc"
)
type IDTokenHintVerifier interface {
}
//VerifyIDToken validates the id token according to
//https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
func VerifyIDTokenHint(ctx context.Context, token string, v IDTokenHintVerifier) (*oidc.IDTokenClaims, error) {
claims := new(oidc.IDTokenClaims)
decrypted, err := oidc.DecryptToken(token)
if err != nil {
return nil, err
}
payload, err := oidc.ParseToken(decrypted, claims)
if err != nil {
return nil, err
}
//2, check issuer (exact match)
if err := oidc.CheckIssuer(claims.GetIssuer(), v); err != nil {
return nil, err
}
//3. check aud (aud must contain client_id, all aud strings must be allowed)
if err = oidc.CheckAudience(claims.GetAudience(), v); err != nil {
return nil, err
}
if err = oidc.CheckAuthorizedParty(claims.GetAudience(), claims.GetAuthorizedParty(), v); err != nil {
return nil, err
}
//6. check signature by keys
//7. check alg default is rs256
//8. check if alg is mac based (hs...) -> audience contains client_id. for validation use utf-8 representation of your client_secret
if err = oidc.CheckSignature(ctx, decrypted, payload, claims, v.SupportedSignAlgs(), v.KeySet()); err != nil {
return nil, err
}
//9. check exp before now
if err = oidc.CheckExpiration(claims.GetExpiration(), v); err != nil {
return nil, err
}
//10. check iat duration is optional (can be checked)
if err = oidc.CheckIssuedAt(claims.GetIssuedAt(), v); err != nil {
return nil, err
}
/*
//11. check nonce (check if optional possible) id_token.nonce == sentNonce
if err = oidc.CheckNonce(claims.GetNonce()); err != nil {
return nil, err
}
*/
//12. if acr requested check acr
if err = oidc.CheckAuthorizationContextClassReference(claims.GetAuthenticationContextClassReference(), v); err != nil {
return nil, err
}
//13. if auth_time requested check if auth_time is less than max age
if err = oidc.CheckAuthTime(claims.GetAuthTime(), v); err != nil {
return nil, err
}
return claims, nil
}

View file

@ -145,7 +145,7 @@ func (v *DefaultVerifier) Verify(ctx context.Context, accessToken, idTokenString
//Verify implements the `VerifyIDToken` method of the `Verifier` interface
//according to https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
func (v *DefaultVerifier) VerifyIDToken(ctx context.Context, idTokenString string) (*oidc.IDTokenClaims, error) {
return VerifyIDToken(ctx, idTokenString, v)
return VerifywIDToken(ctx, idTokenString, v)
}
func (v *DefaultVerifier) now() time.Time {

View file

@ -65,7 +65,7 @@ func VerifyIDToken(ctx context.Context, token string, v IDTokenVerifier) (*oidc.
//6. check signature by keys
//7. check alg default is rs256
//8. check if alg is mac based (hs...) -> audience contains client_id. for validation use utf-8 representation of your client_secret
if err = oidc.CheckSignature(ctx, decrypted, payload, claims, v); err != nil {
if err = oidc.CheckSignature(ctx, decrypted, payload, claims, v.SupportedSignAlgs(), v.KeySet()); err != nil {
return nil, err
}