VictoriaMetrics/lib/flagutil/password_test.go

82 lines
2.4 KiB
Go
Raw Normal View History

package flagutil
import (
"path/filepath"
"testing"
)
func TestPassword(t *testing.T) {
p := Password{
flagname: "foo",
}
// Verify that String returns "secret"
expectedSecret := "secret"
if s := p.String(); s != expectedSecret {
t.Fatalf("unexpected value returned from Password.String; got %q; want %q", s, expectedSecret)
}
// set regular password
expectedPassword := "top-secret-password"
if err := p.Set(expectedPassword); err != nil {
t.Fatalf("cannot set password: %s", err)
}
for i := 0; i < 5; i++ {
if s := p.Get(); s != expectedPassword {
t.Fatalf("unexpected password; got %q; want %q", s, expectedPassword)
}
if s := p.String(); s != expectedSecret {
t.Fatalf("unexpected value returned from Password.String; got %q; want %q", s, expectedSecret)
}
}
// read the password from file by relative path
localPassFile := "testdata/password.txt"
lib/fs/fscore: do not trim content from path (#6503) ### Describe Your Changes Trimming content which is loaded from an external pass leads to obscure issues in case user-defined input contained trimmed chars. For example. user-defined password "foo\n" will become "foo" while user will expect it to contain a new line. --- For example, a user defines a password which ends with `\n`. This often happens when user Kubernetes secrets and manually encodes value as base64-encoded string. In this case vmauth configuration might look like: ``` users: - url_prefix: - http://vminsert:8480/insert/0/prometheus/api/v1/write name: foo username: foo password: "foobar\n" ``` vmagent configuration for this setup will use the following flags: ``` -remoteWrite.url=http://vmauth:8427/ -remoteWrite.basicAuth.passwordFile=/tmp/vmagent-password -remoteWrite.basicAuth.username="foo" ``` Where `/tmp/vmagent-password` is a file with `foobar\n` password. Before this change such configuration will result in `401 Unauthorized` response received by vmagent since after file content will become `foobar`. --- An example with Kubernetes operator which uses a secret to reference the same password in multiple configurations. <details> <summary>See full manifests</summary> `Secret`: ``` apiVersion: v1 data: name: Zm9v # foo password: Zm9vYmFy # foobar\n username: Zm9v= # foo kind: Secret metadata: name: vmuser ``` `VMUser`: ``` apiVersion: operator.victoriametrics.com/v1beta1 kind: VMUser metadata: name: vmagents spec: generatePassword: false name: vmagents targetRefs: - crd: kind: VMAgent name: some-other-agent namespace: example username: foo # note - the secret above is referenced to provide password passwordRef: name: vmagent key: password ``` `VMAgent`: ``` apiVersion: operator.victoriametrics.com/v1beta1 kind: VMAgent metadata: name: example spec: selectAllByDefault: true scrapeInterval: 5s replicaCount: 1 remoteWrite: - url: "http://vmauth-vmauth-example:8427/api/v1/write" # note - the secret above is referenced as well basicAuth: username: name: vmagent key: username password: name: vmagent key: password ``` </details> Since both config target exactly the same `Secret` object it is expected to work, but apparently the result will be `401 Unauthrized` error. ### Checklist The following checks are **mandatory**: - [x] My change adheres [VictoriaMetrics contributing guidelines](https://docs.victoriametrics.com/contributing/). --------- Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com> Signed-off-by: hagen1778 <roman@victoriametrics.com> Co-authored-by: hagen1778 <roman@victoriametrics.com>
2024-06-19 10:31:48 +02:00
expectedPassword = "foo-bar-baz\n\n\n"
path := "file://" + localPassFile
if err := p.Set(path); err != nil {
t.Fatalf("cannot set password to file: %s", err)
}
for i := 0; i < 5; i++ {
if s := p.Get(); s != expectedPassword {
t.Fatalf("unexpected password; got %q; want %q", s, expectedPassword)
}
if s := p.String(); s != expectedSecret {
t.Fatalf("unexpected value returned from Password.String; got %q; want %q", s, expectedSecret)
}
}
// read the password from file by absolute path
var err error
localPassFile, err = filepath.Abs("testdata/password.txt")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
lib/fs/fscore: do not trim content from path (#6503) ### Describe Your Changes Trimming content which is loaded from an external pass leads to obscure issues in case user-defined input contained trimmed chars. For example. user-defined password "foo\n" will become "foo" while user will expect it to contain a new line. --- For example, a user defines a password which ends with `\n`. This often happens when user Kubernetes secrets and manually encodes value as base64-encoded string. In this case vmauth configuration might look like: ``` users: - url_prefix: - http://vminsert:8480/insert/0/prometheus/api/v1/write name: foo username: foo password: "foobar\n" ``` vmagent configuration for this setup will use the following flags: ``` -remoteWrite.url=http://vmauth:8427/ -remoteWrite.basicAuth.passwordFile=/tmp/vmagent-password -remoteWrite.basicAuth.username="foo" ``` Where `/tmp/vmagent-password` is a file with `foobar\n` password. Before this change such configuration will result in `401 Unauthorized` response received by vmagent since after file content will become `foobar`. --- An example with Kubernetes operator which uses a secret to reference the same password in multiple configurations. <details> <summary>See full manifests</summary> `Secret`: ``` apiVersion: v1 data: name: Zm9v # foo password: Zm9vYmFy # foobar\n username: Zm9v= # foo kind: Secret metadata: name: vmuser ``` `VMUser`: ``` apiVersion: operator.victoriametrics.com/v1beta1 kind: VMUser metadata: name: vmagents spec: generatePassword: false name: vmagents targetRefs: - crd: kind: VMAgent name: some-other-agent namespace: example username: foo # note - the secret above is referenced to provide password passwordRef: name: vmagent key: password ``` `VMAgent`: ``` apiVersion: operator.victoriametrics.com/v1beta1 kind: VMAgent metadata: name: example spec: selectAllByDefault: true scrapeInterval: 5s replicaCount: 1 remoteWrite: - url: "http://vmauth-vmauth-example:8427/api/v1/write" # note - the secret above is referenced as well basicAuth: username: name: vmagent key: username password: name: vmagent key: password ``` </details> Since both config target exactly the same `Secret` object it is expected to work, but apparently the result will be `401 Unauthrized` error. ### Checklist The following checks are **mandatory**: - [x] My change adheres [VictoriaMetrics contributing guidelines](https://docs.victoriametrics.com/contributing/). --------- Signed-off-by: Zakhar Bessarab <z.bessarab@victoriametrics.com> Signed-off-by: hagen1778 <roman@victoriametrics.com> Co-authored-by: hagen1778 <roman@victoriametrics.com>
2024-06-19 10:31:48 +02:00
expectedPassword = "foo-bar-baz\n\n\n"
path = "file://" + localPassFile
if err := p.Set(path); err != nil {
t.Fatalf("unexpected error: %s", err)
}
for i := 0; i < 5; i++ {
if s := p.Get(); s != expectedPassword {
t.Fatalf("unexpected password; got %q; want %q", s, expectedPassword)
}
if s := p.String(); s != expectedSecret {
t.Fatalf("unexpected value returned from Password.String; got %q; want %q", s, expectedSecret)
}
}
// try reading the password from non-existing url
if err := p.Set("http://127.0.0.1:56283/aaa/bb?cc=dd"); err != nil {
t.Fatalf("unexpected error: %s", err)
}
for i := 0; i < 5; i++ {
if s := p.Get(); len(s) != 64 {
t.Fatalf("unexpected password obtained: %q; must be random 64-byte password", s)
}
if s := p.String(); s != expectedSecret {
t.Fatalf("unexpected value returned from Password.String; got %q; want %q", s, expectedSecret)
}
}
}