mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
0a970aef8a
This moves the OpenID Connect storage from memory into the SQL storage, making it persistent and allowing it to be used with clustered deployments like the rest of Authelia.
140 lines
4.5 KiB
Go
140 lines
4.5 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"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/session"
|
|
"github.com/authelia/authelia/v4/internal/utils"
|
|
)
|
|
|
|
// OpenIDConnectConsentGET handles requests to provide consent for OpenID Connect.
|
|
func OpenIDConnectConsentGET(ctx *middlewares.AutheliaCtx) {
|
|
userSession, consent, client, handled := oidcConsentGetSessionsAndClient(ctx)
|
|
if handled {
|
|
return
|
|
}
|
|
|
|
if !client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel) {
|
|
ctx.Logger.Errorf("Unable to perform consent without sufficient authentication for user '%s' and client id '%s'", userSession.Username, consent.ClientID)
|
|
ctx.ReplyForbidden()
|
|
|
|
return
|
|
}
|
|
|
|
if err := ctx.SetJSONBody(client.GetConsentResponseBody(consent)); err != nil {
|
|
ctx.Error(fmt.Errorf("unable to set JSON body: %v", err), "Operation failed")
|
|
}
|
|
}
|
|
|
|
// OpenIDConnectConsentPOST handles consent responses for OpenID Connect.
|
|
func OpenIDConnectConsentPOST(ctx *middlewares.AutheliaCtx) {
|
|
var (
|
|
body oidc.ConsentPostRequestBody
|
|
err error
|
|
)
|
|
|
|
if err = json.Unmarshal(ctx.Request.Body(), &body); err != nil {
|
|
ctx.Logger.Errorf("Failed to parse JSON body in consent POST: %+v", err)
|
|
ctx.SetJSONError(messageOperationFailed)
|
|
|
|
return
|
|
}
|
|
|
|
userSession, consent, client, handled := oidcConsentGetSessionsAndClient(ctx)
|
|
if handled {
|
|
return
|
|
}
|
|
|
|
if !client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel) {
|
|
ctx.Logger.Debugf("Insufficient permissions to give consent during POST current level: %d, require 2FA: %d", userSession.AuthenticationLevel, client.Policy)
|
|
ctx.ReplyForbidden()
|
|
|
|
return
|
|
}
|
|
|
|
if consent.ClientID != body.ClientID {
|
|
ctx.Logger.Errorf("User '%s' consented to scopes of another client (%s) than expected (%s). Beware this can be a sign of attack",
|
|
userSession.Username, body.ClientID, consent.ClientID)
|
|
ctx.SetJSONError(messageOperationFailed)
|
|
|
|
return
|
|
}
|
|
|
|
var (
|
|
externalRootURL string
|
|
authorized = true
|
|
)
|
|
|
|
switch body.AcceptOrReject {
|
|
case accept:
|
|
if externalRootURL, err = ctx.ExternalRootURL(); err != nil {
|
|
ctx.Logger.Errorf("Could not determine the external URL during consent session processing with challenge id '%s' for user '%s': %v", consent.ChallengeID.String(), userSession.Username, err)
|
|
ctx.SetJSONError(messageOperationFailed)
|
|
|
|
return
|
|
}
|
|
|
|
consent.GrantedScopes = consent.RequestedScopes
|
|
consent.GrantedAudience = consent.RequestedAudience
|
|
|
|
if !utils.IsStringInSlice(consent.ClientID, consent.GrantedAudience) {
|
|
consent.GrantedAudience = append(consent.GrantedAudience, consent.ClientID)
|
|
}
|
|
case reject:
|
|
authorized = false
|
|
default:
|
|
ctx.Logger.Warnf("User '%s' tried to reply to consent with an unexpected verb", userSession.Username)
|
|
ctx.ReplyBadRequest()
|
|
|
|
return
|
|
}
|
|
|
|
if err = ctx.Providers.StorageProvider.SaveOAuth2ConsentSessionResponse(ctx, *consent, authorized); err != nil {
|
|
ctx.Logger.Errorf("Failed to save the consent session response to the database: %+v", err)
|
|
ctx.SetJSONError(messageOperationFailed)
|
|
|
|
return
|
|
}
|
|
|
|
response := oidc.ConsentPostResponseBody{RedirectURI: fmt.Sprintf("%s%s?%s", externalRootURL, oidc.AuthorizationPath, consent.Form)}
|
|
|
|
if err = ctx.SetJSONBody(response); err != nil {
|
|
ctx.Error(fmt.Errorf("unable to set JSON body in response"), "Operation failed")
|
|
}
|
|
}
|
|
|
|
func oidcConsentGetSessionsAndClient(ctx *middlewares.AutheliaCtx) (userSession session.UserSession, consent *model.OAuth2ConsentSession, client *oidc.Client, handled bool) {
|
|
var (
|
|
err error
|
|
)
|
|
|
|
userSession = ctx.GetSession()
|
|
|
|
if userSession.ConsentChallengeID == nil {
|
|
ctx.Logger.Errorf("Cannot consent for user '%s' when OIDC consent session has not been initiated", userSession.Username)
|
|
ctx.ReplyForbidden()
|
|
|
|
return userSession, nil, nil, true
|
|
}
|
|
|
|
if consent, err = ctx.Providers.StorageProvider.LoadOAuth2ConsentSessionByChallengeID(ctx, *userSession.ConsentChallengeID); err != nil {
|
|
ctx.Logger.Errorf("Unable to load consent session with challenge id '%s': %v", userSession.ConsentChallengeID.String(), err)
|
|
ctx.ReplyForbidden()
|
|
|
|
return userSession, nil, nil, true
|
|
}
|
|
|
|
if client, err = ctx.Providers.OpenIDConnect.Store.GetFullClient(consent.ClientID); err != nil {
|
|
ctx.Logger.Errorf("Unable to find related client configuration with name '%s': %v", consent.ClientID, err)
|
|
ctx.ReplyForbidden()
|
|
|
|
return userSession, nil, nil, true
|
|
}
|
|
|
|
return userSession, consent, client, false
|
|
}
|