Skip to content
Permalink
Browse files
base64 encode passwords and simplify .brooklyn_cli structure
Includes support for old style .brooklyn_cli format such that it will
read credentials from the old style and use them, but overwrite with
the new style on next login.

New style looks like:
{
  "credentials": {
    "password": "cGFzc3dvcmQ=",
    "username": "geoff"
  },
  "skipSslChecks": false,
  "target": "http://geoffs-macbook-pro.local:8081"
}
  • Loading branch information
geomacy committed Jul 4, 2017
1 parent 6b7970e commit 2ec78dd09b5b342a219bc085028ae78c5bcfc73c
Showing 3 changed files with 158 additions and 50 deletions.
@@ -30,27 +30,14 @@ import (
"path/filepath"
)

func getNetworkCredentialsFromConfig(yamlMap map[string]interface{}) (string, string, string, bool) {
var target, username, password string
var skipSslChecks bool
target, found := yamlMap["target"].(string)
if found {
auth, found := yamlMap["auth"].(map[string]interface{})
if found {
creds := auth[target].(map[string]interface{})
username, found = creds["username"].(string)
if found {
password, found = creds["password"].(string)
}
}
skipSslChecks, _ = yamlMap["skipSslChecks"].(bool)
}
return target, username, password, skipSslChecks
}

func main() {
config := io.GetConfig()
target, username, password, skipSslChecks := getNetworkCredentialsFromConfig(config.Map)
skipSslChecks := config.GetSkipSslChecks()
target, username, password, err := config.GetNetworkCredentials()
if err != nil {
error_handler.ErrorExit(err)
}

//target, username, password := "http://192.168.50.101:8081", "brooklyn", "Sns4Hh9j7l"
network := net.NewNetwork(target, username, password, skipSslChecks)
cmdFactory := command_factory.NewFactory(network, config)
@@ -58,6 +58,30 @@ func (cmd *Login) Metadata() command_metadata.CommandMetadata {
}
}


func (cmd *Login) promptAndReadUsername() (username string) {
for username == "" {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter Username: ")
user, err := reader.ReadString('\n')
if err != nil {
error_handler.ErrorExit(err)
}
username = strings.TrimSpace(user)
}
return username
}

func (cmd *Login) promptAndReadPassword() (password string) {
fmt.Print("Enter Password: ")
bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
error_handler.ErrorExit(err)
}
fmt.Printf("\n")
return string(bytePassword)
}

func (cmd *Login) Run(scope scope.Scope, c *cli.Context) {
if !c.Args().Present() {
error_handler.ErrorExit("A URL must be provided as the first argument", error_handler.CLIUsageErrorExitCode)
@@ -83,44 +107,17 @@ func (cmd *Login) Run(scope scope.Scope, c *cli.Context) {

// Prompt for username if not supplied
if cmd.network.BrooklynUser == "" {
var userName string
for userName == "" {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter Username: ")
user, err := reader.ReadString('\n')
if err != nil {
error_handler.ErrorExit(err)
}
userName = strings.TrimSpace(user)
}
cmd.network.BrooklynUser = userName
cmd.network.BrooklynUser = cmd.promptAndReadUsername()
}

// Prompt for password if not supplied (password is not echoed to screen
if cmd.network.BrooklynUser != "" && cmd.network.BrooklynPass == "" {
fmt.Print("Enter Password: ")
bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
error_handler.ErrorExit(err)
}
fmt.Printf("\n")
cmd.network.BrooklynPass = string(bytePassword)
cmd.network.BrooklynPass = cmd.promptAndReadPassword()
}

if cmd.config.Map == nil {
cmd.config.Map = make(map[string]interface{})
}
// now persist these credentials to the yaml file
auth := make(map[string]interface{})
cmd.config.Map["auth"] = auth

auth[cmd.network.BrooklynUrl] = map[string]string{
"username": cmd.network.BrooklynUser,
"password": cmd.network.BrooklynPass,
}

cmd.config.Map["target"] = cmd.network.BrooklynUrl
cmd.config.Map["skipSslChecks"] = cmd.network.SkipSslChecks
cmd.config.SetNetworkCredentials(cmd.network.BrooklynUrl, cmd.network.BrooklynUser, cmd.network.BrooklynPass)
cmd.config.SetSkipSslChecks(cmd.network.SkipSslChecks)
cmd.config.Write()

loginVersion, code, err := version.Version(cmd.network)
@@ -24,8 +24,19 @@ import (
"path/filepath"

"github.com/apache/brooklyn-client/cli/error_handler"
"encoding/base64"
"errors"
)

// Deprecated: support old style of .brooklyn_cli format for version <= 0.11.0
const authKey = "auth"

const credentialsKey = "credentials"
const usernameKey = "username"
const secretKey = "password"
const targetKey = "target"
const skipSslChecksKey = "skipSslChecks"

type Config struct {
FilePath string
Map map[string]interface{}
@@ -78,3 +89,116 @@ func (config *Config) Read() {
dec := json.NewDecoder(fileToRead)
dec.Decode(&config.Map)
}


// getCredentials reads credentials from .brooklyn_cli data formatted for versions > 0.11.0
// Note that the password is base64 encoded to avoid json formatting problems
//{
// "credentials": {
// "password": "cGFzc3dvcmQ=",
// "username": "geoff"
// },
// "skipSslChecks": false,
// "target": "http://geoffs-macbook-pro.local:8081"
//}
func (config *Config) getCredentials(target string) (username string, password string, err error) {
credentials, found := config.Map[credentialsKey].(map[string]interface{})
if !found {
err = errors.New("No credentials found for " + target)
return
}

if username, found = credentials["username"].(string); !found {
err = errors.New("No credentials for " + target)
return
}

if password, found = credentials["password"].(string); !found {
err = errors.New("No credentials for " + target)
return
}

if decodedPassword, err := base64.StdEncoding.DecodeString(password); err != nil {
err = errors.New("Could not decode password for " + username)
} else {
password = string(decodedPassword)
}
return username, password, err
}

// Deprecated:
// getCredentialsOldStyle provides backward support for .brooklyn_cli format for version <= 0.11.0:
// {
// "auth": {
// "http://geoffs-macbook-pro.local:8081": {
// "password": "password",
// "username": "geoff"
// }
// },
// "skipSslChecks": false,
// "target": "http://geoffs-macbook-pro.local:8081"
//}
func (config *Config) getCredentialsOldStyle(target string) (username string, password string, err error) {
auth, found := config.Map[authKey].(map[string]interface{})
if !found {
err = errors.New("No credentials for " + target)
return
}

creds, found := auth[target].(map[string]interface{})
if !found {
err = errors.New("No credentials found for " + target)
return
}

if username, found = creds[usernameKey].(string); !found {
err = errors.New("No credentials for " + username)
return
}

if password, found = creds[secretKey].(string); !found {
err = errors.New("No credentials for " + username)
return
}

return username, password, err
}

func (config *Config) SetNetworkCredentials(target string, username string, password string) {
if config.Map == nil {
config.Map = make(map[string]interface{})
}
encodedPassword := base64.StdEncoding.EncodeToString([]byte(password))
config.Map[credentialsKey] = map[string]interface{}{
usernameKey: username,
secretKey: encodedPassword,
}
config.Map[targetKey] = target

// Overwrite old style format from version <= 0.11.0
delete(config.Map, authKey)
}

func (config *Config) GetNetworkCredentials() (target string, username string, password string, err error) {
target, found := config.Map[targetKey].(string)
if found {
if username, password, err = config.getCredentials(target); nil != err {
username, password, err = config.getCredentialsOldStyle(target)
}
} else {
err = errors.New("No target defined in config file")
}
return target, username, password, err
}

func (config *Config) GetSkipSslChecks() bool {
if config.Map == nil {
config.Map = make(map[string]interface{})
}
skipSslChecks, _ := config.Map[skipSslChecksKey].(bool)
return skipSslChecks
}

func (config *Config) SetSkipSslChecks(skipSslChecks bool) {
config.Map["skipSslChecks"] = skipSslChecks
}

0 comments on commit 2ec78dd

Please sign in to comment.