ContainerImage.Pinniped/internal/fositestorage/pkce/pkce.go

116 lines
3.2 KiB
Go
Raw Normal View History

// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package pkce
import (
"context"
"fmt"
"github.com/ory/fosite"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/handler/pkce"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"go.pinniped.dev/internal/constable"
"go.pinniped.dev/internal/crud"
)
const (
ErrInvalidPKCERequestType = constable.Error("requester must be of type fosite.Request")
pkceStorageVersion = "1"
)
var _ pkce.PKCERequestStorage = &pkceStorage{}
type pkceStorage struct {
storage crud.Storage
}
type session struct {
Request *fosite.Request `json:"request"`
Version string `json:"version"`
}
func New(secrets corev1client.SecretInterface) pkce.PKCERequestStorage {
return &pkceStorage{storage: crud.New("pkce", secrets)}
}
// TODO test what happens when we pass nil as the requester.
func (a *pkceStorage) CreatePKCERequestSession(ctx context.Context, signature string, requester fosite.Requester) error {
request, err := validateAndExtractAuthorizeRequest(requester)
if err != nil {
return err
}
_, err = a.storage.Create(ctx, signature, &session{Request: request, Version: pkceStorageVersion})
return err
}
func (a *pkceStorage) GetPKCERequestSession(ctx context.Context, signature string, _ fosite.Session) (fosite.Requester, error) {
session, _, err := a.getSession(ctx, signature)
if err != nil {
return nil, err
}
return session.Request, err
}
func (a *pkceStorage) DeletePKCERequestSession(ctx context.Context, signature string) error {
return a.storage.Delete(ctx, signature)
}
func (a *pkceStorage) getSession(ctx context.Context, signature string) (*session, string, error) {
session := newValidEmptyPKCESession()
rv, err := a.storage.Get(ctx, signature, session)
// TODO we do want this
// if errors.IsNotFound(err) {
// return nil, "", fosite.ErrNotFound.WithCause(err).WithDebug(err.Error())
// }
if err != nil {
return nil, "", fmt.Errorf("failed to get authorization code session for %s: %w", signature, err)
}
// TODO we probably want this
// if version := session.Version; version != pkceStorageVersion {
// return nil, "", fmt.Errorf("%w: authorization code session for %s has version %s instead of %s",
// ErrInvalidAuthorizeRequestVersion, signature, version, pkceStorageVersion)
// }
// TODO maybe we want this. it would only apply when a human has edited the secret.
// if session.Request == nil {
// return nil, "", fmt.Errorf("malformed authorization code session for %s: %w", signature, ErrInvalidAuthorizeRequestData)
// }
return session, rv, nil
}
func newValidEmptyPKCESession() *session {
return &session{
Request: &fosite.Request{
Client: &fosite.DefaultOpenIDConnectClient{},
Session: &openid.DefaultSession{},
},
}
}
func validateAndExtractAuthorizeRequest(requester fosite.Requester) (*fosite.Request, error) {
request, ok1 := requester.(*fosite.Request)
if !ok1 {
return nil, ErrInvalidPKCERequestType
}
_, ok2 := request.Client.(*fosite.DefaultOpenIDConnectClient)
_, ok3 := request.Session.(*openid.DefaultSession)
valid := ok2 && ok3
if !valid {
return nil, ErrInvalidPKCERequestType
}
return request, nil
}