Merge branch 'next' into main-next
prepare the merge of next into main by resolving merge conflicts.
This commit is contained in:
commit
0476b5946e
122 changed files with 8195 additions and 2858 deletions
100
pkg/op/client.go
100
pkg/op/client.go
|
@ -1,13 +1,19 @@
|
|||
package op
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/oidc/pkg/oidc"
|
||||
httphelper "github.com/zitadel/oidc/v2/pkg/http"
|
||||
"github.com/zitadel/oidc/v2/pkg/oidc"
|
||||
)
|
||||
|
||||
//go:generate go get github.com/dmarkham/enumer
|
||||
//go:generate go run github.com/dmarkham/enumer -linecomment -sql -json -text -yaml -gqlgen -type=ApplicationType,AccessTokenType
|
||||
//go:generate go mod tidy
|
||||
|
||||
const (
|
||||
ApplicationTypeWeb ApplicationType = iota // web
|
||||
|
@ -67,3 +73,95 @@ func ContainsResponseType(types []oidc.ResponseType, responseType oidc.ResponseT
|
|||
func IsConfidentialType(c Client) bool {
|
||||
return c.ApplicationType() == ApplicationTypeWeb
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidAuthHeader = errors.New("invalid basic auth header")
|
||||
ErrNoClientCredentials = errors.New("no client credentials provided")
|
||||
ErrMissingClientID = errors.New("client_id missing from request")
|
||||
)
|
||||
|
||||
type ClientJWTProfile interface {
|
||||
JWTProfileVerifier(context.Context) JWTProfileVerifier
|
||||
}
|
||||
|
||||
func ClientJWTAuth(ctx context.Context, ca oidc.ClientAssertionParams, verifier ClientJWTProfile) (clientID string, err error) {
|
||||
if ca.ClientAssertion == "" {
|
||||
return "", oidc.ErrInvalidClient().WithParent(ErrNoClientCredentials)
|
||||
}
|
||||
|
||||
profile, err := VerifyJWTAssertion(ctx, ca.ClientAssertion, verifier.JWTProfileVerifier(ctx))
|
||||
if err != nil {
|
||||
return "", oidc.ErrUnauthorizedClient().WithParent(err).WithDescription("JWT assertion failed")
|
||||
}
|
||||
return profile.Issuer, nil
|
||||
}
|
||||
|
||||
func ClientBasicAuth(r *http.Request, storage Storage) (clientID string, err error) {
|
||||
clientID, clientSecret, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
return "", oidc.ErrInvalidClient().WithParent(ErrNoClientCredentials)
|
||||
}
|
||||
clientID, err = url.QueryUnescape(clientID)
|
||||
if err != nil {
|
||||
return "", oidc.ErrInvalidClient().WithParent(ErrInvalidAuthHeader)
|
||||
}
|
||||
clientSecret, err = url.QueryUnescape(clientSecret)
|
||||
if err != nil {
|
||||
return "", oidc.ErrInvalidClient().WithParent(ErrInvalidAuthHeader)
|
||||
}
|
||||
if err := storage.AuthorizeClientIDSecret(r.Context(), clientID, clientSecret); err != nil {
|
||||
return "", oidc.ErrUnauthorizedClient().WithParent(err)
|
||||
}
|
||||
return clientID, nil
|
||||
}
|
||||
|
||||
type ClientProvider interface {
|
||||
Decoder() httphelper.Decoder
|
||||
Storage() Storage
|
||||
}
|
||||
|
||||
type clientData struct {
|
||||
ClientID string `schema:"client_id"`
|
||||
oidc.ClientAssertionParams
|
||||
}
|
||||
|
||||
// ClientIDFromRequest parses the request form and tries to obtain the client ID
|
||||
// and reports if it is authenticated, using a JWT or static client secrets over
|
||||
// http basic auth.
|
||||
//
|
||||
// If the Provider implements IntrospectorJWTProfile and "client_assertion" is
|
||||
// present in the form data, JWT assertion will be verified and the
|
||||
// client ID is taken from there.
|
||||
// If any of them is absent, basic auth is attempted.
|
||||
// In absence of basic auth data, the unauthenticated client id from the form
|
||||
// data is returned.
|
||||
//
|
||||
// If no client id can be obtained by any method, oidc.ErrInvalidClient
|
||||
// is returned with ErrMissingClientID wrapped in it.
|
||||
func ClientIDFromRequest(r *http.Request, p ClientProvider) (clientID string, authenticated bool, err error) {
|
||||
err = r.ParseForm()
|
||||
if err != nil {
|
||||
return "", false, oidc.ErrInvalidRequest().WithDescription("cannot parse form").WithParent(err)
|
||||
}
|
||||
|
||||
data := new(clientData)
|
||||
if err = p.Decoder().Decode(data, r.PostForm); err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
JWTProfile, ok := p.(ClientJWTProfile)
|
||||
if ok {
|
||||
clientID, err = ClientJWTAuth(r.Context(), data.ClientAssertionParams, JWTProfile)
|
||||
}
|
||||
if !ok || errors.Is(err, ErrNoClientCredentials) {
|
||||
clientID, err = ClientBasicAuth(r, p.Storage())
|
||||
}
|
||||
if err == nil {
|
||||
return clientID, true, nil
|
||||
}
|
||||
|
||||
if data.ClientID == "" {
|
||||
return "", false, oidc.ErrInvalidClient().WithParent(ErrMissingClientID)
|
||||
}
|
||||
return data.ClientID, false, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue