Skip to content

Commit 1da29d1

Browse files
committed
fix: handle basic auth provided in nomad address
- allow to have a scheme in the address with basic auth - fix nil point dereference error
1 parent a94eb6d commit 1da29d1

File tree

2 files changed

+155
-13
lines changed

2 files changed

+155
-13
lines changed

internal/cli/helpers.go

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -417,14 +417,29 @@ func clientOptsFromCLI(c *baseCommand) *api.Config {
417417
// format and if it is, it returns user, password and address. It returns "", "",
418418
// address otherwise.
419419
func handleBasicAuth(s string) (string, string, string) {
420-
before, after, found := strings.Cut(s, "@")
421-
if found {
422-
user, pass, found := strings.Cut(before, ":")
423-
if found {
424-
return user, pass, after
425-
}
420+
beforeAt, afterAt, found := strings.Cut(s, "@")
421+
if !found {
422+
return "", "", s
423+
}
424+
425+
scheme, userpass, schemeFound := strings.Cut(beforeAt, "//")
426+
if !schemeFound {
427+
userpass = beforeAt
428+
}
429+
430+
user, pass, found := strings.Cut(userpass, ":")
431+
if !found {
432+
return "", "", s
426433
}
427-
return "", "", before
434+
435+
var addr string
436+
if schemeFound {
437+
addr = fmt.Sprintf("%s//%s", scheme, afterAt)
438+
} else {
439+
addr = afterAt
440+
}
441+
442+
return user, pass, addr
428443
}
429444

430445
// clientOptsFromEnvironment populates api client conf with environment
@@ -434,9 +449,11 @@ func clientOptsFromEnvironment(conf *api.Config) {
434449
// we support user:pass@addr here
435450
user, pass, addr := handleBasicAuth(v)
436451
conf.Address = addr
437-
if user != "" && pass != "" {
438-
conf.HttpAuth.Username = user
439-
conf.HttpAuth.Password = pass
452+
if user != "" || pass != "" {
453+
conf.HttpAuth = &api.HttpBasicAuth{
454+
Username: user,
455+
Password: pass,
456+
}
440457
}
441458
}
442459
if v := os.Getenv("NOMAD_NAMESPACE"); v != "" {
@@ -471,9 +488,11 @@ func clientOptsFromFlags(c *baseCommand, conf *api.Config) {
471488
// we support user:pass@addr here
472489
user, pass, addr := handleBasicAuth(cfg.address)
473490
conf.Address = addr
474-
if user != "" && pass != "" {
475-
conf.HttpAuth.Username = user
476-
conf.HttpAuth.Password = pass
491+
if user != "" || pass != "" {
492+
conf.HttpAuth = &api.HttpBasicAuth{
493+
Username: user,
494+
Password: pass,
495+
}
477496
}
478497
}
479498
if cfg.namespace != "" {

internal/cli/helpers_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package cli
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/nomad/api"
7+
"github.com/shoenig/test/must"
8+
)
9+
10+
func TestHelpers_handleBasicAuth(t *testing.T) {
11+
cases := []struct {
12+
addr string
13+
expectedUser string
14+
expectedPass string
15+
expectedAddr string
16+
}{
17+
{"addr", "", "", "addr"},
18+
{"addr:port", "", "", "addr:port"},
19+
{"user:pass@addr", "user", "pass", "addr"},
20+
{"user:pass@addr:port", "user", "pass", "addr:port"},
21+
{"scheme://addr", "", "", "scheme://addr"},
22+
{"scheme://user:pass@addr", "user", "pass", "scheme://addr"},
23+
{"scheme://user:pass@addr:port", "user", "pass", "scheme://addr:port"},
24+
{"scheme://user:@addr:port", "user", "", "scheme://addr:port"},
25+
{"scheme://:pass@addr:port", "", "pass", "scheme://addr:port"},
26+
{"//user:pass@addr:port", "user", "pass", "//addr:port"},
27+
{"foo@bar", "", "", "foo@bar"},
28+
{"", "", "", ""},
29+
}
30+
31+
for _, c := range cases {
32+
t.Run(c.addr, func(t *testing.T) {
33+
user, pass, addr := handleBasicAuth(c.addr)
34+
35+
must.Eq(t, c.expectedUser, user)
36+
must.Eq(t, c.expectedPass, pass)
37+
must.Eq(t, c.expectedAddr, addr)
38+
})
39+
}
40+
}
41+
42+
func TestHelpers_clientOptsFromEnvironment_Address(t *testing.T) {
43+
cases := []struct {
44+
name string
45+
addr string
46+
expectedAddress string
47+
expectedHttpAuth *api.HttpBasicAuth
48+
}{
49+
{
50+
addr: "addr",
51+
expectedAddress: "addr",
52+
expectedHttpAuth: nil,
53+
},
54+
{
55+
addr: "scheme://user:pass@addr",
56+
expectedAddress: "scheme://addr",
57+
expectedHttpAuth: &api.HttpBasicAuth{Username: "user", Password: "pass"},
58+
},
59+
{
60+
addr: "scheme://user:@addr",
61+
expectedAddress: "scheme://addr",
62+
expectedHttpAuth: &api.HttpBasicAuth{Username: "user", Password: ""},
63+
},
64+
{
65+
addr: "scheme://:pass@addr",
66+
expectedAddress: "scheme://addr",
67+
expectedHttpAuth: &api.HttpBasicAuth{Username: "", Password: "pass"},
68+
},
69+
}
70+
71+
for _, c := range cases {
72+
t.Run(c.name, func(t *testing.T) {
73+
t.Setenv("NOMAD_ADDR", c.addr)
74+
75+
conf := api.Config{HttpAuth: nil}
76+
clientOptsFromEnvironment(&conf)
77+
78+
must.Eq(t, c.expectedAddress, conf.Address)
79+
must.Eq(t, c.expectedHttpAuth, conf.HttpAuth)
80+
})
81+
}
82+
}
83+
84+
func TestHelpers_clientOptsFromFlags_Address(t *testing.T) {
85+
cases := []struct {
86+
addr string
87+
expectedAddress string
88+
expectedHttpAuth *api.HttpBasicAuth
89+
}{
90+
{
91+
addr: "addr",
92+
expectedAddress: "addr",
93+
expectedHttpAuth: nil,
94+
},
95+
{
96+
addr: "scheme://user:pass@addr",
97+
expectedAddress: "scheme://addr",
98+
expectedHttpAuth: &api.HttpBasicAuth{Username: "user", Password: "pass"},
99+
},
100+
{
101+
addr: "scheme://user:@addr",
102+
expectedAddress: "scheme://addr",
103+
expectedHttpAuth: &api.HttpBasicAuth{Username: "user", Password: ""},
104+
},
105+
{
106+
addr: "scheme://:pass@addr",
107+
expectedAddress: "scheme://addr",
108+
expectedHttpAuth: &api.HttpBasicAuth{Username: "", Password: "pass"},
109+
},
110+
}
111+
112+
for _, c := range cases {
113+
t.Run(c.name, func(t *testing.T) {
114+
cmd := baseCommand{nomadConfig: nomadConfig{address: c.addr}}
115+
116+
conf := api.Config{HttpAuth: nil}
117+
clientOptsFromFlags(&cmd, &conf)
118+
119+
must.Eq(t, c.expectedAddress, conf.Address)
120+
must.Eq(t, c.expectedHttpAuth, conf.HttpAuth)
121+
})
122+
}
123+
}

0 commit comments

Comments
 (0)