feat: denied
Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>feat-oidc-policies
parent
2f9da2b7e0
commit
f290fd90b1
|
@ -66,8 +66,8 @@ func validateOIDCPolicies(config *schema.OpenIDConnect, val *schema.StructValida
|
|||
switch name {
|
||||
case "":
|
||||
val.Push(fmt.Errorf("policy must have a name"))
|
||||
case policyOneFactor, policyTwoFactor:
|
||||
val.Push(fmt.Errorf("policy names can't be named one_factor or two_factor"))
|
||||
case policyOneFactor, policyTwoFactor, policyDeny:
|
||||
val.Push(fmt.Errorf("policy names can't be named any of %s", strJoinAnd([]string{policyOneFactor, policyTwoFactor, policyDeny})))
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -75,10 +75,10 @@ func validateOIDCPolicies(config *schema.OpenIDConnect, val *schema.StructValida
|
|||
switch policy.DefaultPolicy {
|
||||
case "":
|
||||
policy.DefaultPolicy = policyTwoFactor
|
||||
case policyOneFactor, policyTwoFactor:
|
||||
case policyOneFactor, policyTwoFactor, policyDeny:
|
||||
break
|
||||
default:
|
||||
val.Push(fmt.Errorf("policy must be one of one_factor or two_factor"))
|
||||
val.Push(fmt.Errorf("policy must be one of %s", strJoinAnd([]string{policyOneFactor, policyTwoFactor, policyDeny})))
|
||||
}
|
||||
|
||||
if len(policy.Rules) == 0 {
|
||||
|
@ -89,10 +89,10 @@ func validateOIDCPolicies(config *schema.OpenIDConnect, val *schema.StructValida
|
|||
switch rule.Policy {
|
||||
case "":
|
||||
policy.Rules[i].Policy = policyTwoFactor
|
||||
case policyOneFactor, policyTwoFactor:
|
||||
case policyOneFactor, policyTwoFactor, policyDeny:
|
||||
break
|
||||
default:
|
||||
val.Push(fmt.Errorf("policy must be one of one_factor or two_factor"))
|
||||
val.Push(fmt.Errorf("policy must be one of %s", strJoinAnd([]string{policyOneFactor, policyTwoFactor, policyDeny})))
|
||||
}
|
||||
|
||||
if len(rule.Subjects) == 0 {
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/authorization"
|
||||
"github.com/ory/fosite"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/authorization"
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/authorization"
|
||||
"github.com/google/uuid"
|
||||
"github.com/ory/fosite"
|
||||
|
||||
|
@ -30,10 +29,12 @@ func handleOIDCAuthorizationConsent(ctx *middlewares.AutheliaCtx, issuer *url.UR
|
|||
|
||||
var handler handlerAuthorizationConsent
|
||||
|
||||
policy := client.GetAuthorizationPolicy(authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()})
|
||||
|
||||
switch {
|
||||
case userSession.IsAnonymous():
|
||||
handler = handleOIDCAuthorizationConsentNotAuthenticated
|
||||
case client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel, authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()}):
|
||||
case authorization.IsAuthLevelSufficient(userSession.AuthenticationLevel, policy):
|
||||
if subject, err = ctx.Providers.OpenIDConnect.GetSubject(ctx, client.GetSectorIdentifier(), userSession.Username); err != nil {
|
||||
ctx.Logger.Errorf(logFmtErrConsentCantGetSubject, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.Username, client.GetSectorIdentifier(), err)
|
||||
|
||||
|
@ -57,6 +58,14 @@ func handleOIDCAuthorizationConsent(ctx *middlewares.AutheliaCtx, issuer *url.UR
|
|||
return nil, true
|
||||
}
|
||||
default:
|
||||
if policy == authorization.Denied {
|
||||
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: the user '%s' is not authorized to use this client", requester.GetID(), client.GetID(), userSession.Username)
|
||||
|
||||
ctx.Providers.OpenIDConnect.WriteAuthorizeError(ctx, rw, requester, oidc.ErrClientAuthorizationUserAccessDenied)
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
if subject, err = ctx.Providers.OpenIDConnect.GetSubject(ctx, client.GetSectorIdentifier(), userSession.Username); err != nil {
|
||||
ctx.Logger.Errorf(logFmtErrConsentCantGetSubject, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.Username, client.GetSectorIdentifier(), err)
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/authorization"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/authorization"
|
||||
|
@ -88,6 +87,14 @@ func OpenIDConnectConsentPOST(ctx *middlewares.AutheliaCtx) {
|
|||
return
|
||||
}
|
||||
|
||||
if !client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel, authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()}) {
|
||||
ctx.Logger.Errorf("User '%s' can't consent to authorization request for client with id '%s' as they are not sufficiently authenticated",
|
||||
userSession.Username, consent.ClientID)
|
||||
ctx.SetJSONError(messageOperationFailed)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if bodyJSON.Consent {
|
||||
consent.Grant()
|
||||
|
||||
|
|
|
@ -221,34 +221,37 @@ func handleOIDCWorkflowResponseWithID(ctx *middlewares.AutheliaCtx, id string) {
|
|||
return
|
||||
}
|
||||
|
||||
if !client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel, authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()}) {
|
||||
policy := client.GetAuthorizationPolicy(authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()})
|
||||
|
||||
switch {
|
||||
case authorization.IsAuthLevelSufficient(userSession.AuthenticationLevel, policy), policy == authorization.Denied:
|
||||
var (
|
||||
targetURL *url.URL
|
||||
form url.Values
|
||||
)
|
||||
|
||||
targetURL = ctx.RootURL()
|
||||
|
||||
if form, err = consent.GetForm(); err != nil {
|
||||
ctx.Error(fmt.Errorf("unable to get authorization form values from consent session with challenge id '%s': %w", consent.ChallengeID, err), messageAuthenticationFailed)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
form.Set(queryArgConsentID, workflowID.String())
|
||||
|
||||
targetURL.Path = path.Join(targetURL.Path, oidc.EndpointPathAuthorization)
|
||||
targetURL.RawQuery = form.Encode()
|
||||
|
||||
if err = ctx.SetJSONBody(redirectResponse{Redirect: targetURL.String()}); err != nil {
|
||||
ctx.Logger.Errorf("Unable to set default redirection URL in body: %s", err)
|
||||
}
|
||||
default:
|
||||
ctx.Logger.Warnf("OpenID Connect client '%s' requires 2FA, cannot be redirected yet", client.GetID())
|
||||
ctx.ReplyOK()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
targetURL *url.URL
|
||||
form url.Values
|
||||
)
|
||||
|
||||
targetURL = ctx.RootURL()
|
||||
|
||||
if form, err = consent.GetForm(); err != nil {
|
||||
ctx.Error(fmt.Errorf("unable to get authorization form values from consent session with challenge id '%s': %w", consent.ChallengeID, err), messageAuthenticationFailed)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
form.Set(queryArgConsentID, workflowID.String())
|
||||
|
||||
targetURL.Path = path.Join(targetURL.Path, oidc.EndpointPathAuthorization)
|
||||
targetURL.RawQuery = form.Encode()
|
||||
|
||||
if err = ctx.SetJSONBody(redirectResponse{Redirect: targetURL.String()}); err != nil {
|
||||
ctx.Logger.Errorf("Unable to set default redirection URL in body: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func markAuthenticationAttempt(ctx *middlewares.AutheliaCtx, successful bool, bannedUntil *time.Time, username string, authType string, errAuth error) (err error) {
|
||||
|
|
|
@ -32,4 +32,6 @@ var (
|
|||
|
||||
// ErrPAREnforcedClientMissingPAR is sent when a client has EnforcePAR configured but the Authorization Request was not Pushed.
|
||||
ErrPAREnforcedClientMissingPAR = fosite.ErrInvalidRequest.WithHint("Pushed Authorization Requests are enforced for this client but no such request was sent.")
|
||||
|
||||
ErrClientAuthorizationUserAccessDenied = fosite.ErrAccessDenied.WithHint("The user was denied access to this client.")
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue