refactor: use new rule engine package
Cadoles/bouncer/pipeline/head Something is wrong with the build of this commit Details

This commit is contained in:
wpetit 2024-06-26 13:52:49 +02:00
parent 114608931b
commit 1881f27928
3 changed files with 48 additions and 90 deletions

View File

@ -36,16 +36,28 @@ Le comportement des règles par défaut est le suivant:
Interdire l'accès à l'utilisateur.
#### `set_header(name string, value string)`
##### `add_header(name string, value string)`
Définir la valeur d'une entête HTTP via son nom `name` et sa valeur `value`.
Ajouter une valeur à un entête HTTP via son nom `name` et sa valeur `value`.
#### `del_headers(pattern string)`
##### `set_header(name string, value string)`
Définir la valeur d'un entête HTTP via son nom `name` et sa valeur `value`. La valeur précédente est écrasée.
##### `del_headers(pattern string)`
Supprimer un ou plusieurs entêtes HTTP dont le nom correspond au patron `pattern`.
Le patron est défini par une chaîne comprenant un ou plusieurs caractères `*`, signifiant un ou plusieurs caractères arbitraires.
##### `set_host(host string)`
Modifier la valeur de l'entête `Host` de la requête.
##### `set_url(url string)`
Modifier l'URL du serveur cible.
### Environnement
Les règles ont accès aux variables suivantes pendant leur exécution.

View File

@ -1,70 +1,16 @@
package authn
import (
"fmt"
"net/http"
"strconv"
"strings"
"time"
"forge.cadoles.com/Cadoles/go-proxy/wildcard"
"forge.cadoles.com/cadoles/bouncer/internal/rule"
ruleHTTP "forge.cadoles.com/cadoles/bouncer/internal/rule/http"
"github.com/expr-lang/expr"
"github.com/pkg/errors"
)
func (l *Layer) getHeaderRuleOptions(r *http.Request) []expr.Option {
options := make([]expr.Option, 0)
setHeader := expr.Function(
"set_header",
func(params ...any) (any, error) {
name := params[0].(string)
rawValue := params[1]
var value string
switch v := rawValue.(type) {
case []string:
value = strings.Join(v, ",")
case time.Time:
value = strconv.FormatInt(v.UTC().Unix(), 10)
case time.Duration:
value = strconv.FormatInt(int64(v.Seconds()), 10)
default:
value = fmt.Sprintf("%v", rawValue)
}
r.Header.Set(name, value)
return true, nil
},
new(func(string, string) bool),
)
options = append(options, setHeader)
delHeaders := expr.Function(
"del_headers",
func(params ...any) (any, error) {
pattern := params[0].(string)
deleted := false
for key := range r.Header {
if !wildcard.Match(key, pattern) {
continue
}
r.Header.Del(key)
deleted = true
}
return deleted, nil
},
new(func(string) bool),
)
options = append(options, delHeaders)
return options
type Env struct {
User *User `expr:"user"`
}
func (l *Layer) applyRules(r *http.Request, options *LayerOptions, user *User) error {
@ -73,38 +19,39 @@ func (l *Layer) applyRules(r *http.Request, options *LayerOptions, user *User) e
return nil
}
env := map[string]any{
"user": user,
}
rulesOptions := l.getHeaderRuleOptions(r)
var ruleErr error
forbidden := expr.Function(
"forbidden",
func(params ...any) (any, error) {
ruleErr = errors.WithStack(ErrForbidden)
return true, nil
},
new(func() bool),
engine, err := rule.NewEngine[*Env](
rule.WithRules(options.Rules...),
rule.WithExpr(getAuthnAPI()...),
ruleHTTP.WithRequestFuncs(r),
)
rulesOptions = append(rulesOptions, forbidden)
for i, r := range rules {
program, err := expr.Compile(r, rulesOptions...)
if err != nil {
return errors.Wrapf(err, "could not compile rule #%d", i)
return errors.WithStack(err)
}
if _, err := expr.Run(program, env); err != nil {
return errors.Wrapf(err, "could not execute rule #%d", i)
env := &Env{
User: user,
}
if ruleErr != nil {
return errors.WithStack(ruleErr)
}
if _, err := engine.Apply(env); err != nil {
return errors.WithStack(err)
}
return nil
}
func getAuthnAPI() []expr.Option {
options := make([]expr.Option, 0)
// forbidden() allows the layer to hijack the current request and return a 403 Forbidden HTTP status
forbidden := expr.Function(
"forbidden",
func(params ...any) (any, error) {
return true, errors.WithStack(ErrForbidden)
},
new(func() bool),
)
options = append(options, forbidden)
return options
}

View File

@ -32,7 +32,6 @@ func NewEngine[E any](funcs ...OptionFunc) (*Engine[E], error) {
}
for i, r := range opts.Rules {
program, err := expr.Compile(r, opts.Expr...)
if err != nil {
return nil, errors.Wrapf(err, "could not compile rule #%d", i)