Skip to content

Commit

Permalink
Merge pull request #1100 from nats-io/auth_config_file
Browse files Browse the repository at this point in the history
[ADDED] Authentication fields in streaming configuration block
  • Loading branch information
kozlovic committed Oct 8, 2020
2 parents e4cd72f + 113066d commit f785c72
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 22 deletions.
15 changes: 15 additions & 0 deletions server/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,21 @@ func ProcessConfigFile(configFile string, opts *Options) error {
}
opts.Encrypt = true
opts.EncryptionKey = []byte(v.(string))
case "username", "user":
if err := checkType(k, reflect.String, v); err != nil {
return err
}
opts.Username = v.(string)
case "password", "pass":
if err := checkType(k, reflect.String, v); err != nil {
return err
}
opts.Password = v.(string)
case "token":
if err := checkType(k, reflect.String, v); err != nil {
return err
}
opts.Token = v.(string)
}
}
return nil
Expand Down
12 changes: 12 additions & 0 deletions server/conf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ func TestParseConfig(t *testing.T) {
if opts.NATSCredentials != "credentials.creds" {
t.Fatalf("Expected Credentials to be %q, got %q", "credentials.creds", opts.NATSCredentials)
}
if opts.Username != "user" {
t.Fatalf("Expected Username to be %q, got %q", "user", opts.Username)
}
if opts.Password != "password" {
t.Fatalf("Expected Password to be %q, got %q", "password", opts.Password)
}
if opts.Token != "token" {
t.Fatalf("Expected Token to be %q, got %q", "token", opts.Token)
}
if !opts.FileStoreOpts.CompactEnabled {
t.Fatalf("Expected CompactEnabled to be true, got false")
}
Expand Down Expand Up @@ -497,6 +506,9 @@ func TestParseWrongTypes(t *testing.T) {
expectFailureFor(t, "encryption_cipher: 123", wrongTypeErr)
expectFailureFor(t, "encryption_key: 123", wrongTypeErr)
expectFailureFor(t, "credentials: 123", wrongTypeErr)
expectFailureFor(t, "username: 123", wrongTypeErr)
expectFailureFor(t, "password: 123", wrongTypeErr)
expectFailureFor(t, "token: 123", wrongTypeErr)
}

func expectFailureFor(t *testing.T, content, errorMatch string) {
Expand Down
14 changes: 14 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,9 @@ type Options struct {
IOSleepTime int64 // Duration (in micro-seconds) the server waits for more message to fill up a batch.
NATSServerURL string // URL for external NATS Server to connect to. If empty, NATS Server is embedded.
NATSCredentials string // Credentials file for connecting to external NATS Server.
Username string // Username to use if not provided from command line
Password string // Password to use if not provided from command line
Token string // Authentication token to use if not provided from command line
ClientHBInterval time.Duration // Interval at which server sends heartbeat to a client.
ClientHBTimeout time.Duration // How long server waits for a heartbeat response.
ClientHBFailCount int // Number of failed heartbeats before server closes client connection.
Expand Down Expand Up @@ -1495,9 +1498,20 @@ func (s *StanServer) createNatsClientConn(name string) (*nats.Conn, error) {
if err != nil {
return nil, err
}
// From executable, these are provided through the command line `-user ...`,
// so they take precedence over streaming's configuration file
ncOpts.User = s.natsOpts.Username
if ncOpts.User == "" {
ncOpts.User = s.opts.Username
}
ncOpts.Password = s.natsOpts.Password
if ncOpts.Password == "" {
ncOpts.Password = s.opts.Password
}
ncOpts.Token = s.natsOpts.Authorization
if ncOpts.Token == "" {
ncOpts.Token = s.opts.Token
}

ncOpts.Name = fmt.Sprintf("_NSS-%s-%s", s.opts.ID, name)

Expand Down
112 changes: 112 additions & 0 deletions server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,28 @@ func createConnectionWithNatsOpts(t tLogger, clientName string,
return sc, nc
}

func createConfFile(t *testing.T, content []byte) string {
t.Helper()
conf, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("Error creating conf file: %v", err)
}
fName := conf.Name()
conf.Close()
if err := ioutil.WriteFile(fName, content, 0666); err != nil {
os.Remove(fName)
t.Fatalf("Error writing conf file: %v", err)
}
return fName
}

func changeCurrentConfigContentWithNewContent(t *testing.T, curConfig string, content []byte) {
t.Helper()
if err := ioutil.WriteFile(curConfig, content, 0666); err != nil {
t.Fatalf("Error writing config: %v", err)
}
}

func NewDefaultConnection(t tLogger) stan.Conn {
sc, err := stan.Connect(clusterName, clientName)
if err != nil {
Expand Down Expand Up @@ -1443,3 +1465,93 @@ func TestServerRandomClientURL(t *testing.T) {
t.Fatal("options port did not match clientURL port")
}
}

func TestServerAuthInConfig(t *testing.T) {
conf := createConfFile(t, []byte(`
authorization {
users [
{user: foo, password: bar}
]
}
streaming {
username: foo
password: bar
}
`))
defer os.Remove(conf)

fs := flag.NewFlagSet("test", flag.ContinueOnError)
noPrint := func() {}
sopts, nopts, err := ConfigureOptions(fs, []string{"-c", conf}, noPrint, noPrint, noPrint)
if err != nil {
t.Fatalf("Error on configure: %v", err)
}
s := runServerWithOpts(t, sopts, nopts)
s.Shutdown()
s = nil

// Check that command line still takes precedence
fs = flag.NewFlagSet("test", flag.ContinueOnError)
sopts, nopts, err = ConfigureOptions(fs, []string{"-c", conf, "-user", "foo", "-pass", "wrong"}, noPrint, noPrint, noPrint)
if err != nil {
t.Fatalf("Error on configure: %v", err)
}
s, err = RunServerWithOpts(sopts, nopts)
if err == nil {
if s != nil {
s.Shutdown()
}
t.Fatal("Expected to fail to start")
}

conf = createConfFile(t, []byte(`
authorization {
token: mytoken
}
streaming {
token: mytoken
}
`))
defer os.Remove(conf)

fs = flag.NewFlagSet("test", flag.ContinueOnError)
sopts, nopts, err = ConfigureOptions(fs, []string{"-c", conf}, noPrint, noPrint, noPrint)
if err != nil {
t.Fatalf("Error on configure: %v", err)
}
s = runServerWithOpts(t, sopts, nopts)
s.Shutdown()

// For token, the authorization{ token: <value> } is replaced with value passed by `-auth`
// and also used to connect. So the test here shows that if `-auth` is specified, it
// will both use this as the authentication token and use that to create the connections.
// We show that streaming { token: wrong } does not prevent from running.
conf = createConfFile(t, []byte(`
streaming {
token: ignored_because_command_line_is_used
}
`))
defer os.Remove(conf)

fs = flag.NewFlagSet("test", flag.ContinueOnError)
sopts, nopts, err = ConfigureOptions(fs, []string{"-c", conf, "-auth", "realtoken"}, noPrint, noPrint, noPrint)
if err != nil {
t.Fatalf("Error on configure: %v", err)
}
s = runServerWithOpts(t, sopts, nopts)
defer s.Shutdown()

// Check that NATS connection really need to provide "realtoken" as authentication token.
nc, err := nats.Connect(nats.DefaultURL)
if err == nil {
if nc != nil {
nc.Close()
}
t.Fatal("Should not have connected")
}
nc, err = nats.Connect(nats.DefaultURL, nats.Token("realtoken"))
if err != nil {
t.Fatalf("Error connecting: %v", err)
}
nc.Close()
}
22 changes: 0 additions & 22 deletions server/signal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,28 +156,6 @@ func TestSignalTrapsSIGTERM(t *testing.T) {
}
}

func createConfFile(t *testing.T, content []byte) string {
t.Helper()
conf, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("Error creating conf file: %v", err)
}
fName := conf.Name()
conf.Close()
if err := ioutil.WriteFile(fName, content, 0666); err != nil {
os.Remove(fName)
t.Fatalf("Error writing conf file: %v", err)
}
return fName
}

func changeCurrentConfigContentWithNewContent(t *testing.T, curConfig string, content []byte) {
t.Helper()
if err := ioutil.WriteFile(curConfig, content, 0666); err != nil {
t.Fatalf("Error writing config: %v", err)
}
}

func TestSignalReload(t *testing.T) {
conf := createConfFile(t, []byte(`debug: false`))
defer os.Remove(conf)
Expand Down
3 changes: 3 additions & 0 deletions test/configs/test_parse.conf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ streaming: {
encryption_cipher: "AES"
encryption_key: "key"
credentials: "credentials.creds"
username: "user"
password: "password"
token: "token"

store_limits: {
max_channels: 11
Expand Down

0 comments on commit f785c72

Please sign in to comment.