Skip to content

Commit

Permalink
Add option to strip prefixes upon checking user or acl.
Browse files Browse the repository at this point in the history
  • Loading branch information
iegomez committed Sep 23, 2021
1 parent 1207622 commit fa99ba6
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 6 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand Down
21 changes: 16 additions & 5 deletions backends/backends.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Backends struct {
superuserCheckers []string

checkPrefix bool
stripPrefix bool
prefixes map[string]string

disableSuperuser bool
Expand Down Expand Up @@ -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),
}

Expand Down Expand Up @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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+"_")
}
Expand Down Expand Up @@ -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+"_")
}
Expand Down
48 changes: 48 additions & 0 deletions backends/backends_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=

0 comments on commit fa99ba6

Please sign in to comment.