Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to strip prefixes upon checking user or acl. #200

Merged
merged 1 commit into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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=