Skip to content

Commit

Permalink
force basicAuth and headerLookup to use /custom-data/ etcd prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
Samu Tamminen committed Jan 12, 2022
1 parent c681d42 commit 3888bb6
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 22 deletions.
10 changes: 6 additions & 4 deletions pkg/filter/headerlookup/headerlookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package headerlookup
import (
"fmt"
"net/http"
"strings"

"github.com/megaease/easegress/pkg/cluster"
"github.com/megaease/easegress/pkg/context"
Expand All @@ -31,6 +32,8 @@ import (
const (
// Kind is the kind of HeaderLookup.
Kind = "HeaderLookup"
// customDataPrefix is prefix for lookup data.
customDataPrefix = "/custom-data/"
)

var results = []string{}
Expand All @@ -54,8 +57,8 @@ type (
HeaderKey string `yaml:"headerKey,omitempty" jsonschema:"omitempty"`
}

// Spec defines header key and etcd prefix that form etcd key like {etcdPrefix}/{headerKey's value}.
// This {etcdPrefix}/{headerKey's value} is retrieved from etcd and HeaderSetters extract keys from the
// Spec defines header key and etcd prefix that form etcd key like /custom-data/{etcdPrefix}/{headerKey's value}.
// This /custom-data/{etcdPrefix}/{headerKey's value} is retrieved from etcd and HeaderSetters extract keys from the
// from the retrieved etcd item.
Spec struct {
HeaderKey string `yaml:"headerKey" jsonschema:"required"`
Expand Down Expand Up @@ -133,8 +136,7 @@ func parseYamlCreds(entry string) (map[string]string, error) {
}

func (hl *HeaderLookup) lookup(headerVal string) (map[string]string, error) {
etcdKey := hl.spec.EtcdPrefix + headerVal
fmt.Println(etcdKey)
etcdKey := customDataPrefix + strings.TrimPrefix(hl.spec.EtcdPrefix, "/") + headerVal
etcdVal, err := hl.cluster.Get(etcdKey)
if err != nil {
return nil, err
Expand Down
6 changes: 3 additions & 3 deletions pkg/filter/headerlookup/headerlookup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestValidate(t *testing.T) {
name: headerLookup
kind: HeaderLookup
headerKey: "X-AUTH-USER"
etcdPrefix: "/credentials/"
etcdPrefix: "credentials/"
headerSetters:
- etcdKey: "ext-id"
headerKey: "user-ext-id"
Expand Down Expand Up @@ -123,7 +123,7 @@ func TestHandle(t *testing.T) {
nil, clusterInstance, mockMap, mockMap, nil, nil, false, nil, nil)

// let's put data to 'foobar'
clusterInstance.Put("/credentials/foobar",
clusterInstance.Put("/custom-data/credentials/foobar",
`
ext-id: 123456789
extra-entry: "extra"
Expand All @@ -133,7 +133,7 @@ extra-entry: "extra"
name: headerLookup
kind: HeaderLookup
headerKey: "X-AUTH-USER"
etcdPrefix: "/credentials/"
etcdPrefix: "credentials/"
headerSetters:
- etcdKey: "ext-id"
headerKey: "user-ext-id"
Expand Down
24 changes: 14 additions & 10 deletions pkg/filter/validator/basicauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,23 @@ type (
// prefix: "/creds/"
// usernameKey: "user"
// passwordKey: "pw"
// expects the yaml to be stored with key /creds/{id} in following yaml (extra keys are allowed)
// expects the yaml to be stored with key /custom-data/creds/{id} in following yaml (extra keys are allowed)
// user: doge
// pw: {encrypted password}
// pw: {encrypted or plain text password}
EtcdSpec struct {
Prefix string `yaml:"prefix" jsonschema:"onitempty"`
UsernameKey string `yaml:"usernameKey" jsonschema:"omitempty"`
PasswordKey string `yaml:"passwordKey" jsonschema:"omitempty"`
}
// BasicAuthValidatorSpec defines the configuration of Basic Auth validator.
// Only one of UserFile or EtcdYamlFormat should be defined.
// Only one of UserFile or Etcd should be defined.
BasicAuthValidatorSpec struct {
// UserFile is path to file containing encrypted user credentials in apache2-utils/htpasswd format.
// To add user `userY`, use `sudo htpasswd /etc/apache2/.htpasswd userY`
// Reference: https://manpages.debian.org/testing/apache2-utils/htpasswd.1.en.html#EXAMPLES
UserFile string `yaml:"userFile" jsonschema:"omitempty"`
// When etcdYamlFormat is specified, verify user credentials from etcd. Etcd stores them:
// key: /credentials/{username}
// When etcd is specified, verify user credentials from etcd. Etcd stores them:
// key: /custom-data/{etcd.prefix}/{username}
// value: {yaml string in format of etcd}
Etcd *EtcdSpec `yaml:"etcd" jsonschema:"omitempty"`
}
Expand Down Expand Up @@ -101,7 +101,7 @@ type (
}
)

const credsPrefix = "/credentials/"
const customDataPrefix = "/custom-data/"

func parseCredentials(creds string) (string, string, error) {
parts := strings.Split(creds, ":")
Expand Down Expand Up @@ -188,10 +188,13 @@ func (huc *htpasswdUserCache) Match(username string, password string) bool {
}

func newEtcdUserCache(cluster cluster.Cluster, etcdConfig *EtcdSpec) *etcdUserCache {
prefix := etcdConfig.Prefix
if prefix == "" {
prefix = "/custom-data/credentials/"
prefix := customDataPrefix
if etcdConfig.Prefix == "" {
prefix += "credentials/"
} else {
prefix += strings.TrimPrefix(etcdConfig.Prefix, "/")
}
logger.Infof("credentials etcd prefix %s", prefix)
kvs, err := cluster.GetPrefix(prefix)
if err != nil {
panic(err)
Expand Down Expand Up @@ -269,7 +272,7 @@ func (euc *etcdUserCache) WatchChanges() error {
syncer, err = euc.cluster.Syncer(euc.syncInterval)
if err != nil {
logger.Errorf("failed to create syncer: %v", err)
} else if ch, err = syncer.SyncPrefix(credsPrefix); err != nil {
} else if ch, err = syncer.SyncPrefix(euc.prefix); err != nil {
logger.Errorf("failed to sync prefix: %v", err)
syncer.Close()
} else {
Expand All @@ -289,6 +292,7 @@ func (euc *etcdUserCache) WatchChanges() error {
case <-euc.stopCtx.Done():
return nil
case kvs := <-ch:
logger.Infof("basic auth credentials update")
pwReader, err := kvsToReader(kvs, euc.usernameKey, euc.passwordKey)
if err != nil {
logger.Errorf(err.Error())
Expand Down
26 changes: 21 additions & 5 deletions pkg/filter/validator/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,17 +379,33 @@ basicAuth:
os.Remove(userFile.Name())
v.Close()
})

t.Run("credentials from etcd", func(t *testing.T) {
etcdDirName, err := ioutil.TempDir("", "etcd-validator-test")
check(err)
defer os.RemoveAll(etcdDirName)
clusterInstance := cluster.CreateClusterForTest(etcdDirName)

// Test newEtcdUserCache
if euc := newEtcdUserCache(clusterInstance, &EtcdSpec{
UsernameKey: "user",
PasswordKey: "pass",
}); euc.prefix != "/custom-data/credentials/" {
t.Errorf("newEtcdUserCache failed")
}
if euc := newEtcdUserCache(clusterInstance, &EtcdSpec{
Prefix: "/extra-slash/",
UsernameKey: "user",
PasswordKey: "pass",
}); euc.prefix != "/custom-data/extra-slash/" {
t.Errorf("newEtcdUserCache failed")
}

pwToYaml := func(user string, pw string) string {
return fmt.Sprintf("username: %s\npassword: %s", user, pw)
}
clusterInstance.Put("/credentials/1", pwToYaml(userIds[0], encryptedPasswords[0]))
clusterInstance.Put("/credentials/2", pwToYaml(userIds[2], encryptedPasswords[2]))
clusterInstance.Put("/custom-data/credentials/1", pwToYaml(userIds[0], encryptedPasswords[0]))
clusterInstance.Put("/custom-data/credentials/2", pwToYaml(userIds[2], encryptedPasswords[2]))

var mockMap sync.Map
supervisor := supervisor.NewMock(
Expand All @@ -400,7 +416,7 @@ kind: Validator
name: validator
basicAuth:
etcd:
prefix: /credentials/
prefix: credentials/
usernameKey: "username"
passwordKey: "password"`

Expand All @@ -422,8 +438,8 @@ basicAuth:
}
}

clusterInstance.Delete("/credentials/1") // first user is not authorized anymore
clusterInstance.Put("/credentials/doge",
clusterInstance.Delete("/custom-data/credentials/1") // first user is not authorized anymore
clusterInstance.Put("/custom-data/credentials/doge",
`
randomEntry1: 21
nestedEntry:
Expand Down

0 comments on commit 3888bb6

Please sign in to comment.