intermediate commit with some methods implemented
This commit is contained in:
parent
4fcda01738
commit
2902a81161
6 changed files with 214 additions and 46 deletions
|
@ -2,23 +2,97 @@ package op
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
)
|
||||
|
||||
type LegacyServer struct {
|
||||
UnimplementedServer
|
||||
op *Provider
|
||||
provider OpenIDProvider
|
||||
|
||||
readyProbes []ProbesFn
|
||||
}
|
||||
|
||||
func (s *LegacyServer) Health(_ context.Context, r *Request[struct{}]) (*Response, error) {
|
||||
return NewResponse(Status{Status: "ok"}), nil
|
||||
}
|
||||
|
||||
func (s *LegacyServer) Ready(ctx context.Context, r *Request[struct{}]) (*Response, error) {
|
||||
for _, probe := range s.readyProbes {
|
||||
// shouldn't we run probes in Go routines?
|
||||
if err := probe(ctx); err != nil {
|
||||
return nil, NewStatusError(err, http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
return NewResponse(Status{Status: "ok"}), nil
|
||||
}
|
||||
|
||||
func (s *LegacyServer) Discovery(ctx context.Context, r *Request[struct{}]) (*Response, error) {
|
||||
return NewResponse(
|
||||
CreateDiscoveryConfig(ctx, s.provider, s.provider.Storage()),
|
||||
), nil
|
||||
}
|
||||
|
||||
var (
|
||||
ErrAuthReqMissingClientID = errors.New("auth request is missing client_id")
|
||||
ErrAuthReqMissingRedirectURI = errors.New("auth request is missing redirect_uri")
|
||||
)
|
||||
|
||||
func (s *LegacyServer) Authorize(ctx context.Context, r *Request[oidc.AuthRequest]) (_ *Redirect, err error) {
|
||||
authReq := r.Data
|
||||
if authReq.RequestParam != "" && s.provider.RequestObjectSupported() {
|
||||
authReq, err = ParseRequestObject(ctx, authReq, s.provider.Storage(), IssuerFromContext(ctx))
|
||||
if err != nil {
|
||||
return nil, NewStatusError(err, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
if authReq.ClientID == "" {
|
||||
return TryErrorRedirect(ctx, authReq, ErrAuthReqMissingClientID, s.provider.Encoder(), s.provider.Logger())
|
||||
}
|
||||
if authReq.RedirectURI == "" {
|
||||
return TryErrorRedirect(ctx, authReq, ErrAuthReqMissingRedirectURI, s.provider.Encoder(), s.provider.Logger())
|
||||
}
|
||||
validation := ValidateAuthRequest
|
||||
if validater, ok := s.provider.(AuthorizeValidator); ok {
|
||||
validation = validater.ValidateAuthRequest
|
||||
}
|
||||
userID, err := validation(ctx, authReq, s.provider.Storage(), s.provider.IDTokenHintVerifier(ctx))
|
||||
if err != nil {
|
||||
return TryErrorRedirect(ctx, authReq, err, s.provider.Encoder(), s.provider.Logger())
|
||||
}
|
||||
if authReq.RequestParam != "" {
|
||||
return TryErrorRedirect(ctx, authReq, oidc.ErrRequestNotSupported(), s.provider.Encoder(), s.provider.Logger())
|
||||
}
|
||||
req, err := s.provider.Storage().CreateAuthRequest(ctx, authReq, userID)
|
||||
if err != nil {
|
||||
return TryErrorRedirect(ctx, authReq, oidc.DefaultToServerError(err, "unable to save auth request"), s.provider.Encoder(), s.provider.Logger())
|
||||
}
|
||||
client, err := s.provider.Storage().GetClientByClientID(ctx, req.GetClientID())
|
||||
if err != nil {
|
||||
return TryErrorRedirect(ctx, authReq, oidc.DefaultToServerError(err, "unable to retrieve client by id"), s.provider.Encoder(), s.provider.Logger())
|
||||
}
|
||||
return NewRedirect(client.LoginURL(req.GetID())), nil
|
||||
}
|
||||
|
||||
func (s *LegacyServer) DeviceAuthorization(ctx context.Context, r *ClientRequest[oidc.DeviceAuthorizationRequest]) (*Response, error) {
|
||||
response, err := createDeviceAuthorization(ctx, r.Data, r.Client.GetID(), s.provider)
|
||||
if err != nil {
|
||||
return nil, NewStatusError(err, http.StatusInternalServerError)
|
||||
}
|
||||
return NewResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *LegacyServer) VerifyClient(ctx context.Context, r *Request[ClientCredentials]) (Client, error) {
|
||||
if r.Data.ClientAssertionType == oidc.ClientAssertionTypeJWTAssertion {
|
||||
if !s.op.AuthMethodPrivateKeyJWTSupported() {
|
||||
jwtExchanger, ok := s.provider.(JWTAuthorizationGrantExchanger)
|
||||
if !ok || !s.provider.AuthMethodPrivateKeyJWTSupported() {
|
||||
return nil, oidc.ErrInvalidClient().WithDescription("auth_method private_key_jwt not supported")
|
||||
}
|
||||
return AuthorizePrivateJWTKey(ctx, r.Data.ClientAssertion, s.op)
|
||||
return AuthorizePrivateJWTKey(ctx, r.Data.ClientAssertion, jwtExchanger)
|
||||
}
|
||||
client, err := s.op.Storage().GetClientByClientID(ctx, r.Data.ClientID)
|
||||
client, err := s.provider.Storage().GetClientByClientID(ctx, r.Data.ClientID)
|
||||
if err != nil {
|
||||
return nil, oidc.ErrInvalidClient().WithParent(err)
|
||||
}
|
||||
|
@ -29,12 +103,12 @@ func (s *LegacyServer) VerifyClient(ctx context.Context, r *Request[ClientCreden
|
|||
case oidc.AuthMethodPrivateKeyJWT:
|
||||
return nil, oidc.ErrInvalidClient().WithDescription("private_key_jwt not allowed for this client")
|
||||
case oidc.AuthMethodPost:
|
||||
if !s.op.AuthMethodPostSupported() {
|
||||
if !s.provider.AuthMethodPostSupported() {
|
||||
return nil, oidc.ErrInvalidClient().WithDescription("auth_method post not supported")
|
||||
}
|
||||
}
|
||||
|
||||
err = AuthorizeClientIDSecret(ctx, r.Data.ClientID, r.Data.ClientSecret, s.op.storage)
|
||||
err = AuthorizeClientIDSecret(ctx, r.Data.ClientID, r.Data.ClientSecret, s.provider.Storage())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -43,7 +117,7 @@ func (s *LegacyServer) VerifyClient(ctx context.Context, r *Request[ClientCreden
|
|||
}
|
||||
|
||||
func (s *LegacyServer) CodeExchange(ctx context.Context, r *ClientRequest[oidc.AccessTokenRequest]) (*Response, error) {
|
||||
authReq, err := AuthRequestByCode(ctx, s.op.storage, r.Data.Code)
|
||||
authReq, err := AuthRequestByCode(ctx, s.provider.Storage(), r.Data.Code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -52,7 +126,7 @@ func (s *LegacyServer) CodeExchange(ctx context.Context, r *ClientRequest[oidc.A
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
resp, err := CreateTokenResponse(ctx, authReq, r.Client, s.op, true, r.Data.Code, "")
|
||||
resp, err := CreateTokenResponse(ctx, authReq, r.Client, s.provider, true, r.Data.Code, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -63,7 +137,7 @@ func (s *LegacyServer) RefreshToken(ctx context.Context, r *ClientRequest[oidc.R
|
|||
if !ValidateGrantType(r.Client, oidc.GrantTypeRefreshToken) {
|
||||
return nil, oidc.ErrUnauthorizedClient()
|
||||
}
|
||||
request, err := RefreshTokenRequestByRefreshToken(ctx, s.op.storage, r.Data.RefreshToken)
|
||||
request, err := RefreshTokenRequestByRefreshToken(ctx, s.provider.Storage(), r.Data.RefreshToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -73,9 +147,64 @@ func (s *LegacyServer) RefreshToken(ctx context.Context, r *ClientRequest[oidc.R
|
|||
if err = ValidateRefreshTokenScopes(r.Data.Scopes, request); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := CreateTokenResponse(ctx, request, r.Client, s.op, true, "", r.Data.RefreshToken)
|
||||
resp, err := CreateTokenResponse(ctx, request, r.Client, s.provider, true, "", r.Data.RefreshToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewResponse(resp), nil
|
||||
}
|
||||
|
||||
func (s *LegacyServer) JWTProfile(_ context.Context, r *Request[oidc.JWTProfileGrantRequest]) (*Response, error) {
|
||||
return nil, unimplementedError(r)
|
||||
}
|
||||
|
||||
func (s *LegacyServer) TokenExchange(_ context.Context, r *ClientRequest[oidc.TokenExchangeRequest]) (*Response, error) {
|
||||
return nil, unimplementedError(r.Request)
|
||||
}
|
||||
|
||||
func (s *LegacyServer) ClientCredentialsExchange(_ context.Context, r *ClientRequest[oidc.ClientCredentialsRequest]) (*Response, error) {
|
||||
return nil, unimplementedError(r.Request)
|
||||
}
|
||||
|
||||
func (s *LegacyServer) DeviceToken(_ context.Context, r *ClientRequest[oidc.DeviceAccessTokenRequest]) (*Response, error) {
|
||||
return nil, unimplementedError(r.Request)
|
||||
}
|
||||
|
||||
func (s *LegacyServer) Introspect(ctx context.Context, r *ClientRequest[oidc.IntrospectionRequest]) (*Response, error) {
|
||||
response := new(oidc.IntrospectionResponse)
|
||||
tokenID, subject, ok := getTokenIDAndSubject(ctx, s.provider, r.Data.Token)
|
||||
if !ok {
|
||||
return NewResponse(response), nil
|
||||
}
|
||||
err := s.provider.Storage().SetIntrospectionFromToken(ctx, response, tokenID, subject, r.Client.GetID())
|
||||
if err != nil {
|
||||
return NewResponse(response), nil
|
||||
}
|
||||
response.Active = true
|
||||
return NewResponse(response), nil
|
||||
}
|
||||
|
||||
func (s *LegacyServer) UserInfo(ctx context.Context, r *Request[oidc.UserInfoRequest]) (*Response, error) {
|
||||
tokenID, subject, ok := getTokenIDAndSubject(ctx, s.provider, r.Data.AccessToken)
|
||||
if !ok {
|
||||
return nil, NewStatusError(oidc.ErrAccessDenied().WithDescription("access token invalid"), http.StatusUnauthorized)
|
||||
}
|
||||
info := new(oidc.UserInfo)
|
||||
err := s.provider.Storage().SetUserinfoFromToken(ctx, info, tokenID, subject, r.Header.Get("origin"))
|
||||
if err != nil {
|
||||
return nil, NewStatusError(err, http.StatusForbidden)
|
||||
}
|
||||
return NewResponse(info), nil
|
||||
}
|
||||
|
||||
func (s *LegacyServer) Revocation(_ context.Context, r *Request[oidc.RevocationRequest]) (*Response, error) {
|
||||
return nil, unimplementedError(r)
|
||||
}
|
||||
|
||||
func (s *LegacyServer) EndSession(_ context.Context, r *Request[oidc.EndSessionRequest]) (*Response, error) {
|
||||
return nil, unimplementedError(r)
|
||||
}
|
||||
|
||||
func (s *LegacyServer) Keys(_ context.Context, r *Request[struct{}]) (*Response, error) {
|
||||
return nil, unimplementedError(r)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue