Add option to strip prefixes upon checking user or acl.

This commit is contained in:
Ignacio Gómez 2021-09-23 20:40:32 -03:00
parent 1207622cb2
commit fa99ba6583
4 changed files with 75 additions and 6 deletions

View File

@ -405,10 +405,18 @@ The above example will do up to 2 retries (3 calls in total considering the orig
#### Prefixes
Though the plugin may have multiple backends enabled, there's a way to specify which backend must be used for a given user: prefixes. When enabled, `prefixes` allow to check if the username contains a predefined prefix in the form prefix_username and use the configured backend for that prefix. Options to enable and set prefixes are the following:
Though the plugin may have multiple backends enabled, there's a way to specify which backend must be used for a given user: prefixes.
When enabled, `prefixes` allow to check if the username contains a predefined prefix in the form prefix_username and use the configured backend for that prefix.
There's also an option to strip the prefix upon checking user or acl,
so that if a record for `username` exists on a backend with prefix `prefix`,
then both `username` and `prefix_username` would be authenticated/authorized. Notice that the former would
need to loop through all the backends since it carries no prefix, while the latter will only be checked by the correct backend.
Options to enable and set prefixes are the following:
```
auth_opt_check_prefix true
auth_opt_strip_prefix true
auth_opt_prefixes filesprefix, pgprefix, jwtprefix
```

View File

@ -25,6 +25,7 @@ type Backends struct {
superuserCheckers []string
checkPrefix bool
stripPrefix bool
prefixes map[string]string
disableSuperuser bool
@ -76,7 +77,6 @@ func Initialize(authOpts map[string]string, logLevel log.Level, version string)
aclCheckers: make([]string, 0),
userCheckers: make([]string, 0),
superuserCheckers: make([]string, 0),
checkPrefix: false,
prefixes: make(map[string]string),
}
@ -273,6 +273,7 @@ func (b *Backends) setPrefixes(authOpts map[string]string, backends []string) {
if !ok || strings.Replace(checkPrefix, " ", "", -1) != "true" {
b.checkPrefix = false
b.stripPrefix = false
return
}
@ -282,6 +283,7 @@ func (b *Backends) setPrefixes(authOpts map[string]string, backends []string) {
if !ok {
log.Warn("Error: prefixes enabled but no options given, defaulting to prefixes disabled.")
b.checkPrefix = false
b.stripPrefix = false
return
}
@ -291,10 +293,15 @@ func (b *Backends) setPrefixes(authOpts map[string]string, backends []string) {
if len(prefixes) != len(backends) {
log.Errorf("Error: got %d backends and %d prefixes, defaulting to prefixes disabled.", len(backends), len(prefixes))
b.checkPrefix = false
b.stripPrefix = false
return
}
if authOpts["strip_prefix"] == "true" {
b.stripPrefix = true
}
for i, backend := range backends {
b.prefixes[prefixes[i]] = backend
}
@ -355,8 +362,10 @@ func (b *Backends) AuthUnpwdCheck(username, password, clientid string) (bool, er
return false, fmt.Errorf("backend %s not registered to check users", bename)
}
// If the backend is JWT and the token was prefixed, then strip the token. If the token was passed without a prefix it will be handled in the common case.
if bename == jwtBackend {
// If the backend is JWT and the token was prefixed, then strip the token.
// If the token was passed without a prefix it will be handled in the common case.
// Also strip the prefix if the strip_prefix option was set.
if bename == jwtBackend || b.stripPrefix {
prefix := b.getPrefixForBackend(bename)
username = strings.TrimPrefix(username, prefix+"_")
}
@ -414,8 +423,10 @@ func (b *Backends) AuthAclCheck(clientid, username, topic string, acc int) (bool
return b.checkAcl(username, topic, clientid, acc)
}
// If the backend is JWT and the token was prefixed, then strip the token. If the token was passed without a prefix then let it be handled in the common case.
if bename == jwtBackend {
// If the backend is JWT and the token was prefixed, then strip the token.
// If the token was passed without a prefix then let it be handled in the common case.
// Also strip the prefix if the strip_prefix option was set.
if bename == jwtBackend || b.stripPrefix {
prefix := b.getPrefixForBackend(bename)
username = strings.TrimPrefix(username, prefix+"_")
}

View File

@ -444,5 +444,53 @@ func TestBackends(t *testing.T) {
redis.Halt()
})
Convey("When strip_prefix is true, the prefix will be stripped from the username prior to conducting checks", func() {
authOpts["backends"] = "redis"
authOpts["redis_register"] = "user, acl"
authOpts["check_prefix"] = "true"
authOpts["strip_prefix"] = "true"
authOpts["prefixes"] = "redis"
delete(authOpts, "disable_superuser")
username := "redis_test1"
stripUsername := "test1"
password := username
passwordHash := "PBKDF2$sha512$100000$hgodnayqjfs0AOCxvsU+Zw==$dfc4LBGmZ/wB128NOD48qF5fCS+r/bsjU+oCXgT3UksAik73vIkXcPFydtbJKoIgnepNXP9t+zGIaR5wyRmXaA=="
redis, err := NewRedis(authOpts, log.DebugLevel, hashing.NewHasher(authOpts, "redis"))
assert.Nil(t, err)
ctx := context.Background()
// Insert a user to test auth.
redis.conn.Set(ctx, stripUsername, passwordHash, 0)
redis.conn.Set(ctx, fmt.Sprintf("%s:su", stripUsername), "true", 0)
b, err := Initialize(authOpts, log.DebugLevel, version)
So(err, ShouldBeNil)
userCheck, err := b.AuthUnpwdCheck(username, password, clientid)
So(err, ShouldBeNil)
So(userCheck, ShouldBeTrue)
redis.conn.SAdd(ctx, stripUsername+":racls", "test/redis")
aclCheck, err := b.AuthAclCheck(clientid, stripUsername, "test/redis", 1)
So(err, ShouldBeNil)
So(aclCheck, ShouldBeTrue)
userCheck, err = b.AuthUnpwdCheck(username, password, clientid)
So(err, ShouldBeNil)
So(userCheck, ShouldBeTrue)
aclCheck, err = b.AuthAclCheck(clientid, stripUsername, "test/redis", 1)
So(err, ShouldBeNil)
So(aclCheck, ShouldBeTrue)
redis.Halt()
})
})
}

2
go.sum
View File

@ -182,6 +182,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
@ -318,6 +319,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=