fix(oidc): pre-conf consent skipped entirely for anon users (#3250)

This fixes an issue where pre-configured consent is entirely skipped if the process was initiated via an anonymous user.
pull/3290/head
James Elliott 2022-05-03 15:28:58 +10:00 committed by GitHub
parent 556a115c83
commit 1db00717ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 16 deletions

View File

@ -101,8 +101,6 @@ func OpenIDConnectAuthorizationGET(ctx *middlewares.AutheliaCtx, rw http.Respons
ctx.Logger.Tracef("Authorization Request with id '%s' on client with id '%s' creating session for Authorization Response for subject '%s' with username '%s' with claims: %+v", ctx.Logger.Tracef("Authorization Request with id '%s' on client with id '%s' creating session for Authorization Response for subject '%s' with username '%s' with claims: %+v",
requester.GetID(), oidcSession.ClientID, oidcSession.Subject, oidcSession.Username, oidcSession.Claims) requester.GetID(), oidcSession.ClientID, oidcSession.Subject, oidcSession.Username, oidcSession.Claims)
ctx.Logger.Tracef("Authorization Request with id '%s' on client with id '%s' creating session for Authorization Response for subject '%s' with username '%s' with headers: %+v",
requester.GetID(), oidcSession.ClientID, oidcSession.Subject, oidcSession.Username, oidcSession.Headers)
if responder, err = ctx.Providers.OpenIDConnect.Fosite.NewAuthorizeResponse(ctx, requester, oidcSession); err != nil { if responder, err = ctx.Providers.OpenIDConnect.Fosite.NewAuthorizeResponse(ctx, requester, oidcSession); err != nil {
rfc := fosite.ErrorToRFC6749Error(err) rfc := fosite.ErrorToRFC6749Error(err)

View File

@ -117,9 +117,9 @@ func handleOIDCAuthorizationConsentOrGenerate(ctx *middlewares.AutheliaCtx, root
err error err error
) )
scopes, audience := getExpectedScopesAndAudience(requester) scopes, audience := getOIDCExpectedScopesAndAudienceFromRequest(requester)
if consent, err = getOIDCPreconfiguredConsent(ctx, client.GetID(), subject.UUID, scopes, audience); err != nil { if consent, err = getOIDCPreConfiguredConsent(ctx, client.GetID(), subject.UUID, scopes, audience); err != nil {
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' had error looking up pre-configured consent sessions: %+v", requester.GetID(), requester.GetClient().GetID(), err) ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' had error looking up pre-configured consent sessions: %+v", requester.GetID(), requester.GetClient().GetID(), err)
ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, requester, fosite.ErrServerError.WithHint("Could not lookup the consent session.")) ctx.Providers.OpenIDConnect.Fosite.WriteAuthorizeError(rw, requester, fosite.ErrServerError.WithHint("Could not lookup the consent session."))
@ -182,16 +182,32 @@ func handleOIDCAuthorizationConsentRedirect(destination string, client *oidc.Cli
http.Redirect(rw, r, destination, http.StatusFound) http.Redirect(rw, r, destination, http.StatusFound)
} }
func getExpectedScopesAndAudience(requester fosite.Requester) (scopes, audience []string) { func getOIDCExpectedScopesAndAudienceFromRequest(requester fosite.Requester) (scopes, audience []string) {
audience = requester.GetRequestedAudience() return getOIDCExpectedScopesAndAudience(requester.GetClient().GetID(), requester.GetRequestedScopes(), requester.GetRequestedAudience())
if !utils.IsStringInSlice(requester.GetClient().GetID(), audience) {
audience = append(audience, requester.GetClient().GetID())
}
return requester.GetRequestedScopes(), audience
} }
func getOIDCPreconfiguredConsent(ctx *middlewares.AutheliaCtx, clientID string, subject uuid.UUID, scopes, audience []string) (consent *model.OAuth2ConsentSession, err error) { func getOIDCExpectedScopesAndAudience(clientID string, scopes, audience []string) (expectedScopes, expectedAudience []string) {
if !utils.IsStringInSlice(clientID, audience) {
audience = append(audience, clientID)
}
return scopes, audience
}
func getOIDCPreConfiguredConsentFromClientAndConsent(ctx *middlewares.AutheliaCtx, client fosite.Client, consent *model.OAuth2ConsentSession) (preConfigConsent *model.OAuth2ConsentSession, err error) {
if consent == nil || !consent.Subject.Valid {
return nil, fmt.Errorf("invalid consent provided for pre-configured consent lookup")
}
scopes, audience := getOIDCExpectedScopesAndAudience(client.GetID(), consent.RequestedScopes, consent.RequestedAudience)
// We can skip this error as it's handled at the authorization endpoint.
preConfigConsent, _ = getOIDCPreConfiguredConsent(ctx, client.GetID(), consent.Subject.UUID, scopes, audience)
return preConfigConsent, nil
}
func getOIDCPreConfiguredConsent(ctx *middlewares.AutheliaCtx, clientID string, subject uuid.UUID, scopes, audience []string) (consent *model.OAuth2ConsentSession, err error) {
var ( var (
rows *storage.ConsentSessionRows rows *storage.ConsentSessionRows
) )

View File

@ -9,6 +9,7 @@ import (
"github.com/authelia/authelia/v4/internal/authorization" "github.com/authelia/authelia/v4/internal/authorization"
"github.com/authelia/authelia/v4/internal/middlewares" "github.com/authelia/authelia/v4/internal/middlewares"
"github.com/authelia/authelia/v4/internal/model"
"github.com/authelia/authelia/v4/internal/oidc" "github.com/authelia/authelia/v4/internal/oidc"
"github.com/authelia/authelia/v4/internal/utils" "github.com/authelia/authelia/v4/internal/utils"
) )
@ -59,15 +60,49 @@ func handleOIDCWorkflowResponse(ctx *middlewares.AutheliaCtx) {
return return
} }
if userSession.ConsentChallengeID != nil { if consent.Subject.UUID, err = ctx.Providers.OpenIDConnect.Store.GetSubject(ctx, client.GetSectorIdentifier(), userSession.Username); err != nil {
ctx.Logger.Errorf("Unable to find subject for the consent session: %v", err)
respondUnauthorized(ctx, messageOperationFailed)
return
}
consent.Subject.Valid = true
var preConsent *model.OAuth2ConsentSession
if preConsent, err = getOIDCPreConfiguredConsentFromClientAndConsent(ctx, client, consent); err != nil {
ctx.Logger.Errorf("Unable to lookup pre-configured consent for the consent session: %v", err)
respondUnauthorized(ctx, messageOperationFailed)
return
}
if userSession.ConsentChallengeID != nil && preConsent == nil {
if err = ctx.SetJSONBody(redirectResponse{Redirect: fmt.Sprintf("%s/consent", externalRootURL)}); err != nil { if err = ctx.SetJSONBody(redirectResponse{Redirect: fmt.Sprintf("%s/consent", externalRootURL)}); err != nil {
ctx.Logger.Errorf("Unable to set default redirection URL in body: %s", err) ctx.Logger.Errorf("Unable to set default redirection URL in body: %s", err)
} }
} else {
if err = ctx.SetJSONBody(redirectResponse{Redirect: fmt.Sprintf("%s%s?%s", externalRootURL, oidc.AuthorizationPath, consent.Form)}); err != nil { return
ctx.Logger.Errorf("Unable to set default redirection URL in body: %s", err) }
if userSession.ConsentChallengeID != nil {
userSession.ConsentChallengeID = nil
if err = ctx.SaveSession(userSession); err != nil {
ctx.Logger.Errorf("Unable to update user session: %v", err)
respondUnauthorized(ctx, messageOperationFailed)
return
} }
} }
if err = ctx.SetJSONBody(redirectResponse{Redirect: fmt.Sprintf("%s%s?%s", externalRootURL, oidc.AuthorizationPath, consent.Form)}); err != nil {
ctx.Logger.Errorf("Unable to set default redirection URL in body: %s", err)
}
} }
// Handle1FAResponse handle the redirection upon 1FA authentication. // Handle1FAResponse handle the redirection upon 1FA authentication.