change some interfaces
This commit is contained in:
parent
bfbd4adb1c
commit
eaf47fde8e
10 changed files with 130 additions and 20 deletions
|
@ -36,6 +36,18 @@ type AuthorizeValidator interface {
|
||||||
//Deprecated: ValidationAuthorizer exists for historical compatibility. Use ValidationAuthorizer itself
|
//Deprecated: ValidationAuthorizer exists for historical compatibility. Use ValidationAuthorizer itself
|
||||||
type ValidationAuthorizer AuthorizeValidator
|
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
|
//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) {
|
||||||
|
@ -152,7 +164,7 @@ func ValidateAuthReqIDTokenHint(ctx context.Context, idTokenHint string, verifie
|
||||||
if idTokenHint == "" {
|
if idTokenHint == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
claims, err := verifier.VerifyIDToken(ctx, idTokenHint)
|
claims, err := VerifyIDTokenHint(ctx, idTokenHint, verifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", ErrInvalidRequest("The id_token_hint is invalid. If you have any questions, you may contact the administrator of the application.")
|
return "", ErrInvalidRequest("The id_token_hint is invalid. If you have any questions, you may contact the administrator of the application.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,12 +279,11 @@ func (p *DefaultOP) ClientJWTVerifier() rp.Verifier {
|
||||||
return p.verifier
|
return p.verifier
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DefaultOP) HandleReady(w http.ResponseWriter, r *http.Request) {
|
func (p *DefaultOP) Probes() []ProbesFn {
|
||||||
probes := []ProbesFn{
|
return []ProbesFn{
|
||||||
ReadySigner(p.Signer()),
|
ReadySigner(p.Signer()),
|
||||||
ReadyStorage(p.Storage()),
|
ReadyStorage(p.Storage()),
|
||||||
}
|
}
|
||||||
Readiness(w, r, probes...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DefaultOP) HandleKeys(w http.ResponseWriter, r *http.Request) {
|
func (p *DefaultOP) HandleKeys(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -10,6 +10,12 @@ type KeyProvider interface {
|
||||||
Storage() Storage
|
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) {
|
func Keys(w http.ResponseWriter, r *http.Request, k KeyProvider) {
|
||||||
keySet, err := k.Storage().GetKeySet(r.Context())
|
keySet, err := k.Storage().GetKeySet(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
20
pkg/op/op.go
20
pkg/op/op.go
|
@ -16,15 +16,9 @@ const (
|
||||||
|
|
||||||
type OpenIDProvider interface {
|
type OpenIDProvider interface {
|
||||||
Configuration
|
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)
|
HandleKeys(w http.ResponseWriter, r *http.Request)
|
||||||
HttpHandler() http.Handler
|
HttpHandler() http.Handler
|
||||||
|
Authorizer
|
||||||
SessionEnder
|
SessionEnder
|
||||||
Signer() Signer
|
Signer() Signer
|
||||||
Probes() []ProbesFn
|
Probes() []ProbesFn
|
||||||
|
@ -47,12 +41,12 @@ func CreateRouter(o OpenIDProvider, interceptors ...HttpInterceptor) *mux.Router
|
||||||
router.HandleFunc(healthzEndpoint, Healthz)
|
router.HandleFunc(healthzEndpoint, Healthz)
|
||||||
router.HandleFunc(readinessEndpoint, Ready(o.Probes()))
|
router.HandleFunc(readinessEndpoint, Ready(o.Probes()))
|
||||||
router.HandleFunc(oidc.DiscoveryEndpoint, DiscoveryHandler(o, o.Signer()))
|
router.HandleFunc(oidc.DiscoveryEndpoint, DiscoveryHandler(o, o.Signer()))
|
||||||
router.Handle(o.AuthorizationEndpoint().Relative(), intercept(o.HandleAuthorize))
|
router.Handle(o.AuthorizationEndpoint().Relative(), intercept(authorizeHandler(o)))
|
||||||
router.Handle(o.AuthorizationEndpoint().Relative()+"/{id}", intercept(o.HandleAuthorizeCallback))
|
router.Handle(o.AuthorizationEndpoint().Relative()+"/{id}", intercept(authorizeCallbackHandler(o)))
|
||||||
router.Handle(o.TokenEndpoint().Relative(), intercept(o.HandleExchange))
|
router.Handle(o.TokenEndpoint().Relative(), intercept(tokenHandler(o)))
|
||||||
router.HandleFunc(o.UserinfoEndpoint().Relative(), o.HandleUserinfo)
|
router.HandleFunc(o.UserinfoEndpoint().Relative(), userinfoHandler(o))
|
||||||
router.Handle(o.EndSessionEndpoint().Relative(), intercept(EndSessionHandler(o)))
|
router.Handle(o.EndSessionEndpoint().Relative(), intercept(endSessionHandler(o)))
|
||||||
router.HandleFunc(o.KeysEndpoint().Relative(), o.HandleKeys)
|
router.HandleFunc(o.KeysEndpoint().Relative(), keysHandler(o))
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ type SessionEnder interface {
|
||||||
DefaultLogoutRedirectURI() string
|
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) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
EndSession(w, r, ender)
|
EndSession(w, r, ender)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,26 @@ type VerifyExchanger interface {
|
||||||
ClientJWTVerifier() rp.Verifier
|
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) {
|
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 {
|
||||||
|
|
|
@ -15,6 +15,12 @@ type UserinfoProvider interface {
|
||||||
Storage() Storage
|
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) {
|
func Userinfo(w http.ResponseWriter, r *http.Request, userinfoProvider UserinfoProvider) {
|
||||||
accessToken, err := getAccessToken(r, userinfoProvider.Decoder())
|
accessToken, err := getAccessToken(r, userinfoProvider.Decoder())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
73
pkg/op/verifier.go
Normal file
73
pkg/op/verifier.go
Normal 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
|
||||||
|
}
|
|
@ -145,7 +145,7 @@ func (v *DefaultVerifier) Verify(ctx context.Context, accessToken, idTokenString
|
||||||
//Verify implements the `VerifyIDToken` method of the `Verifier` interface
|
//Verify implements the `VerifyIDToken` method of the `Verifier` interface
|
||||||
//according to https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
//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) {
|
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 {
|
func (v *DefaultVerifier) now() time.Time {
|
||||||
|
|
|
@ -65,7 +65,7 @@ func VerifyIDToken(ctx context.Context, token string, v IDTokenVerifier) (*oidc.
|
||||||
//6. check signature by keys
|
//6. check signature by keys
|
||||||
//7. check alg default is rs256
|
//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
|
//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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue