1
0
mirror of https://github.com/minio/minio.git synced 2025-04-09 06:00:12 -04:00

Honor envs properly for access and secret key. ()

Also changes the behavior of `secretKeyHash` which is
not necessary to be sent over the network, each node
has its own secretKeyHash to validate.

Fixes 
Partial(fix)  (More changes needed with some code cleanup)
This commit is contained in:
Harshavardhana 2017-02-07 12:51:43 -08:00 committed by GitHub
parent fd72c21e0e
commit 31dff87903
19 changed files with 237 additions and 314 deletions

@ -14,7 +14,7 @@ env:
script: script:
- make - make
- make test GOFLAGS="-timeout 15m -race -v" - make test GOFLAGS="-timeout 20m -race -v"
- make coverage - make coverage
after_success: after_success:

@ -35,9 +35,9 @@ test_script:
# Unit tests # Unit tests
- ps: Add-AppveyorTest "Unit Tests" -Outcome Running - ps: Add-AppveyorTest "Unit Tests" -Outcome Running
- mkdir build\coverage - mkdir build\coverage
- go test -timeout 15m -v -race github.com/minio/minio/cmd... - go test -timeout 20m -v -race github.com/minio/minio/cmd...
- go test -v -race github.com/minio/minio/pkg... - go test -v -race github.com/minio/minio/pkg...
- go test -coverprofile=build\coverage\coverage.txt -covermode=atomic github.com/minio/minio/cmd - go test -timeout 15m -coverprofile=build\coverage\coverage.txt -covermode=atomic github.com/minio/minio/cmd
- ps: Update-AppveyorTest "Unit Tests" -Outcome Passed - ps: Update-AppveyorTest "Unit Tests" -Outcome Passed
after_test: after_test:

@ -154,24 +154,25 @@ func (adminAPI adminAPIHandlers) ServiceCredentialsHandler(w http.ResponseWriter
} }
// Check passed credentials // Check passed credentials
cred, err := getCredential(req.Username, req.Password) err = validateAuthKeys(req.Username, req.Password)
switch err { if err != nil {
case errInvalidAccessKeyLength: writeErrorResponse(w, toAPIErrorCode(err), r.URL)
writeErrorResponse(w, ErrAdminInvalidAccessKey, r.URL)
return
case errInvalidSecretKeyLength:
writeErrorResponse(w, ErrAdminInvalidSecretKey, r.URL)
return return
} }
creds := credential{
AccessKey: req.Username,
SecretKey: req.Password,
}
// Notify all other Minio peers to update credentials // Notify all other Minio peers to update credentials
updateErrs := updateCredsOnPeers(cred) updateErrs := updateCredsOnPeers(creds)
for peer, err := range updateErrs { for peer, err := range updateErrs {
errorIf(err, "Unable to update credentials on peer %s.", peer) errorIf(err, "Unable to update credentials on peer %s.", peer)
} }
// Update local credentials // Update local credentials in memory.
serverConfig.SetCredential(cred) serverConfig.SetCredential(creds)
if err = serverConfig.Save(); err != nil { if err = serverConfig.Save(); err != nil {
writeErrorResponse(w, ErrInternalError, r.URL) writeErrorResponse(w, ErrInternalError, r.URL)
return return

@ -43,6 +43,7 @@ type adminXLTestBed struct {
func prepareAdminXLTestBed() (*adminXLTestBed, error) { func prepareAdminXLTestBed() (*adminXLTestBed, error) {
// reset global variables to start afresh. // reset global variables to start afresh.
resetTestGlobals() resetTestGlobals()
// Initialize minio server config. // Initialize minio server config.
rootPath, err := newTestConfig(globalMinioDefaultRegion) rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil { if err != nil {

@ -610,7 +610,10 @@ func toAPIErrorCode(err error) (apiErr APIErrorCode) {
apiErr = ErrEntityTooLarge apiErr = ErrEntityTooLarge
case errDataTooSmall: case errDataTooSmall:
apiErr = ErrEntityTooSmall apiErr = ErrEntityTooSmall
case errInvalidAccessKeyLength:
apiErr = ErrAdminInvalidAccessKey
case errInvalidSecretKeyLength:
apiErr = ErrAdminInvalidSecretKey
} }
if apiErr != ErrNone { if apiErr != ErrNone {

@ -315,11 +315,7 @@ func TestIsReqAuthenticated(t *testing.T) {
} }
defer removeAll(path) defer removeAll(path)
creds, err := getCredential("myuser", "mypassword") creds := newCredentialWithKeys("myuser", "mypassword")
if err != nil {
t.Fatal(err)
}
serverConfig.SetCredential(creds) serverConfig.SetCredential(creds)
// List of test cases for validating http request authentication. // List of test cases for validating http request authentication.

@ -63,13 +63,12 @@ func (br *browserPeerAPIHandlers) SetAuthPeer(args SetAuthPeerArgs, reply *AuthR
return err return err
} }
creds, err := getCredential(args.Creds.AccessKey, args.Creds.SecretKey) if err := validateAuthKeys(args.Creds.AccessKey, args.Creds.SecretKey); err != nil {
if err != nil {
return err return err
} }
// Update credentials in memory // Update credentials in memory
serverConfig.SetCredential(creds) serverConfig.SetCredential(args.Creds)
// Save credentials to config file // Save credentials to config file
if err := serverConfig.Save(); err != nil { if err := serverConfig.Save(); err != nil {

@ -50,7 +50,7 @@ func TestServerConfigMigrateV1(t *testing.T) {
} }
// Initialize server config and check again if everything is fine // Initialize server config and check again if everything is fine
if _, err := initConfig(); err != nil { if err := loadConfig(credential{}); err != nil {
t.Fatalf("Unable to initialize from updated config file %s", err) t.Fatalf("Unable to initialize from updated config file %s", err)
} }
} }
@ -143,7 +143,7 @@ func TestServerConfigMigrateV2toV12(t *testing.T) {
} }
// Initialize server config and check again if everything is fine // Initialize server config and check again if everything is fine
if _, err := initConfig(); err != nil { if err := loadConfig(credential{}); err != nil {
t.Fatalf("Unable to initialize from updated config file %s", err) t.Fatalf("Unable to initialize from updated config file %s", err)
} }
@ -160,11 +160,6 @@ func TestServerConfigMigrateV2toV12(t *testing.T) {
if serverConfig.Credential.SecretKey != secretKey { if serverConfig.Credential.SecretKey != secretKey {
t.Fatalf("Secret key lost during migration, expected: %v, found: %v", secretKey, serverConfig.Credential.SecretKey) t.Fatalf("Secret key lost during migration, expected: %v, found: %v", secretKey, serverConfig.Credential.SecretKey)
} }
// Initialize server config and check again if everything is fine
if _, err := initConfig(); err != nil {
t.Fatalf("Unable to initialize from updated config file %s", err)
}
} }
// Test if all migrate code returns error with corrupted config files // Test if all migrate code returns error with corrupted config files

@ -42,77 +42,88 @@ type serverConfigV13 struct {
Notify notifier `json:"notify"` Notify notifier `json:"notify"`
} }
// initConfig - initialize server config and indicate if we are // newConfig - initialize a new server config, saves creds from env
// creating a new file or we are just loading // if globalIsEnvCreds is set otherwise generates a new set of keys
func initConfig() (bool, error) { // and those are saved.
if !isConfigFileExists() { func newConfig(envCreds credential) error {
// Initialize server config. // Initialize server config.
srvCfg := &serverConfigV13{} srvCfg := &serverConfigV13{}
srvCfg.Version = globalMinioConfigVersion srvCfg.Version = globalMinioConfigVersion
srvCfg.Region = globalMinioDefaultRegion srvCfg.Region = globalMinioDefaultRegion
srvCfg.Credential = newCredential()
// Enable console logger by default on a fresh run. // If env is set for a fresh start, save them to config file.
srvCfg.Logger.Console = consoleLogger{ if globalIsEnvCreds {
Enable: true, srvCfg.SetCredential(envCreds)
Level: "error", } else {
} srvCfg.SetCredential(newCredential())
// Make sure to initialize notification configs.
srvCfg.Notify.AMQP = make(map[string]amqpNotify)
srvCfg.Notify.AMQP["1"] = amqpNotify{}
srvCfg.Notify.ElasticSearch = make(map[string]elasticSearchNotify)
srvCfg.Notify.ElasticSearch["1"] = elasticSearchNotify{}
srvCfg.Notify.Redis = make(map[string]redisNotify)
srvCfg.Notify.Redis["1"] = redisNotify{}
srvCfg.Notify.NATS = make(map[string]natsNotify)
srvCfg.Notify.NATS["1"] = natsNotify{}
srvCfg.Notify.PostgreSQL = make(map[string]postgreSQLNotify)
srvCfg.Notify.PostgreSQL["1"] = postgreSQLNotify{}
srvCfg.Notify.Kafka = make(map[string]kafkaNotify)
srvCfg.Notify.Kafka["1"] = kafkaNotify{}
srvCfg.Notify.Webhook = make(map[string]webhookNotify)
srvCfg.Notify.Webhook["1"] = webhookNotify{}
// Create config path.
err := createConfigPath()
if err != nil {
return false, err
}
// hold the mutex lock before a new config is assigned.
// Save the new config globally.
// unlock the mutex.
serverConfigMu.Lock()
serverConfig = srvCfg
serverConfigMu.Unlock()
// Save config into file.
return true, serverConfig.Save()
} }
// Enable console logger by default on a fresh run.
srvCfg.Logger.Console = consoleLogger{
Enable: true,
Level: "error",
}
// Make sure to initialize notification configs.
srvCfg.Notify.AMQP = make(map[string]amqpNotify)
srvCfg.Notify.AMQP["1"] = amqpNotify{}
srvCfg.Notify.ElasticSearch = make(map[string]elasticSearchNotify)
srvCfg.Notify.ElasticSearch["1"] = elasticSearchNotify{}
srvCfg.Notify.Redis = make(map[string]redisNotify)
srvCfg.Notify.Redis["1"] = redisNotify{}
srvCfg.Notify.NATS = make(map[string]natsNotify)
srvCfg.Notify.NATS["1"] = natsNotify{}
srvCfg.Notify.PostgreSQL = make(map[string]postgreSQLNotify)
srvCfg.Notify.PostgreSQL["1"] = postgreSQLNotify{}
srvCfg.Notify.Kafka = make(map[string]kafkaNotify)
srvCfg.Notify.Kafka["1"] = kafkaNotify{}
srvCfg.Notify.Webhook = make(map[string]webhookNotify)
srvCfg.Notify.Webhook["1"] = webhookNotify{}
// Create config path.
if err := createConfigPath(); err != nil {
return err
}
// hold the mutex lock before a new config is assigned.
// Save the new config globally.
// unlock the mutex.
serverConfigMu.Lock()
serverConfig = srvCfg
serverConfigMu.Unlock()
// Save config into file.
return serverConfig.Save()
}
// loadConfig - loads a new config from disk, overrides creds from env
// if globalIsEnvCreds is set otherwise serves the creds from loaded
// from the disk.
func loadConfig(envCreds credential) error {
configFile, err := getConfigFile() configFile, err := getConfigFile()
if err != nil { if err != nil {
return false, err return err
} }
if _, err = os.Stat(configFile); err != nil { if _, err = os.Stat(configFile); err != nil {
return false, err return err
} }
srvCfg := &serverConfigV13{} srvCfg := &serverConfigV13{}
srvCfg.Version = globalMinioConfigVersion srvCfg.Version = globalMinioConfigVersion
qc, err := quick.New(srvCfg) qc, err := quick.New(srvCfg)
if err != nil { if err != nil {
return false, err return err
} }
if err = qc.Load(configFile); err != nil { if err = qc.Load(configFile); err != nil {
return false, err return err
} }
srvCfg.Credential, err = getCredential(srvCfg.Credential.AccessKey, srvCfg.Credential.SecretKey) // If env is set override the credentials from config file.
if err != nil { if globalIsEnvCreds {
return false, err srvCfg.SetCredential(envCreds)
} else {
srvCfg.SetCredential(srvCfg.Credential)
} }
// hold the mutex lock before a new config is assigned. // hold the mutex lock before a new config is assigned.
@ -123,8 +134,7 @@ func initConfig() (bool, error) {
// Set the version properly after the unmarshalled json is loaded. // Set the version properly after the unmarshalled json is loaded.
serverConfig.Version = globalMinioConfigVersion serverConfig.Version = globalMinioConfigVersion
return nil
return false, nil
} }
// serverConfig server config. // serverConfig server config.
@ -347,7 +357,7 @@ func (s *serverConfigV13) SetCredential(creds credential) {
defer serverConfigMu.Unlock() defer serverConfigMu.Unlock()
// Set updated credential. // Set updated credential.
s.Credential = creds s.Credential = newCredentialWithKeys(creds.AccessKey, creds.SecretKey)
} }
// GetCredentials get current credentials. // GetCredentials get current credentials.

@ -106,7 +106,7 @@ func TestServerConfig(t *testing.T) {
setGlobalConfigPath(rootPath) setGlobalConfigPath(rootPath)
// Initialize server config. // Initialize server config.
if _, err := initConfig(); err != nil { if err := loadConfig(credential{}); err != nil {
t.Fatalf("Unable to initialize from updated config file %s", err) t.Fatalf("Unable to initialize from updated config file %s", err)
} }
} }

@ -19,6 +19,9 @@ package cmd
import ( import (
"crypto/rand" "crypto/rand"
"encoding/base64" "encoding/base64"
"os"
"github.com/minio/mc/pkg/console"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@ -36,7 +39,7 @@ const (
func mustGetAccessKey() string { func mustGetAccessKey() string {
keyBytes := make([]byte, accessKeyMaxLen) keyBytes := make([]byte, accessKeyMaxLen)
if _, err := rand.Read(keyBytes); err != nil { if _, err := rand.Read(keyBytes); err != nil {
panic(err) console.Fatalf("Unable to generate access key. Err: %s.\n", err)
} }
for i := 0; i < accessKeyMaxLen; i++ { for i := 0; i < accessKeyMaxLen; i++ {
@ -49,7 +52,7 @@ func mustGetAccessKey() string {
func mustGetSecretKey() string { func mustGetSecretKey() string {
keyBytes := make([]byte, secretKeyMaxLen) keyBytes := make([]byte, secretKeyMaxLen)
if _, err := rand.Read(keyBytes); err != nil { if _, err := rand.Read(keyBytes); err != nil {
panic(err) console.Fatalf("Unable to generate secret key. Err: %s.\n", err)
} }
return string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyMaxLen]) return string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyMaxLen])
@ -69,38 +72,68 @@ func isSecretKeyValid(secretKey string) bool {
type credential struct { type credential struct {
AccessKey string `json:"accessKey,omitempty"` AccessKey string `json:"accessKey,omitempty"`
SecretKey string `json:"secretKey,omitempty"` SecretKey string `json:"secretKey,omitempty"`
SecretKeyHash []byte `json:"secretKeyHash,omitempty"` secretKeyHash []byte
} }
// Generate a bcrypt hashed key for input secret key. // Generate a bcrypt hashed key for input secret key.
func mustGetHashedSecretKey(secretKey string) []byte { func mustGetHashedSecretKey(secretKey string) []byte {
hashedSecretKey, err := bcrypt.GenerateFromPassword([]byte(secretKey), bcrypt.DefaultCost) hashedSecretKey, err := bcrypt.GenerateFromPassword([]byte(secretKey), bcrypt.DefaultCost)
if err != nil { if err != nil {
panic(err) console.Fatalf("Unable to generate secret hash for secret key. Err: %s.\n", err)
} }
return hashedSecretKey return hashedSecretKey
} }
// Initialize a new credential object. // Initialize a new credential object
func newCredential() credential { func newCredential() credential {
secretKey := mustGetSecretKey() return newCredentialWithKeys(mustGetAccessKey(), mustGetSecretKey())
accessKey := mustGetAccessKey() }
func newCredentialWithKeys(accessKey, secretKey string) credential {
secretHash := mustGetHashedSecretKey(secretKey) secretHash := mustGetHashedSecretKey(secretKey)
return credential{accessKey, secretKey, secretHash} return credential{accessKey, secretKey, secretHash}
} }
// Validate incoming auth keys.
func validateAuthKeys(accessKey, secretKey string) error {
// Validate the env values before proceeding.
if !isAccessKeyValid(accessKey) {
return errInvalidAccessKeyLength
}
if !isSecretKeyValid(secretKey) {
return errInvalidSecretKeyLength
}
return nil
}
// Variant of getCredentialFromEnv but upon error fails right here.
func mustGetCredentialFromEnv() credential {
creds, err := getCredentialFromEnv()
if err != nil {
console.Fatalf("Unable to load credentials from environment. Err: %s.\n", err)
}
return creds
}
// Converts accessKey and secretKeys into credential object which // Converts accessKey and secretKeys into credential object which
// contains bcrypt secret key hash for future validation. // contains bcrypt secret key hash for future validation.
func getCredential(accessKey, secretKey string) (credential, error) { func getCredentialFromEnv() (credential, error) {
if !isAccessKeyValid(accessKey) { // Fetch access keys from environment variables and update the config.
return credential{}, errInvalidAccessKeyLength accessKey := os.Getenv("MINIO_ACCESS_KEY")
secretKey := os.Getenv("MINIO_SECRET_KEY")
// Envs are set globally.
globalIsEnvCreds = accessKey != "" && secretKey != ""
if globalIsEnvCreds {
// Validate the env values before proceeding.
if err := validateAuthKeys(accessKey, secretKey); err != nil {
return credential{}, err
}
// Return credential object.
return newCredentialWithKeys(accessKey, secretKey), nil
} }
if !isSecretKeyValid(secretKey) { return credential{}, nil
return credential{}, errInvalidSecretKeyLength
}
secretHash := mustGetHashedSecretKey(secretKey)
return credential{accessKey, secretKey, secretHash}, nil
} }

@ -38,12 +38,15 @@ const (
defaultInterNodeJWTExpiry = 100 * 365 * 24 * time.Hour defaultInterNodeJWTExpiry = 100 * 365 * 24 * time.Hour
) )
var errInvalidAccessKeyLength = errors.New("Invalid access key, access key should be 5 to 20 characters in length") var (
var errInvalidSecretKeyLength = errors.New("Invalid secret key, secret key should be 8 to 40 characters in length") errInvalidAccessKeyLength = errors.New("Invalid access key, access key should be 5 to 20 characters in length")
errInvalidSecretKeyLength = errors.New("Invalid secret key, secret key should be 8 to 40 characters in length")
var errInvalidAccessKeyID = errors.New("The access key ID you provided does not exist in our records") errInvalidAccessKeyID = errors.New("The access key ID you provided does not exist in our records")
var errAuthentication = errors.New("Authentication failed, check your access credentials") errChangeCredNotAllowed = errors.New("Changing access key and secret key not allowed")
var errNoAuthToken = errors.New("JWT token missing") errAuthentication = errors.New("Authentication failed, check your access credentials")
errNoAuthToken = errors.New("JWT token missing")
)
func authenticateJWT(accessKey, secretKey string, expiry time.Duration) (string, error) { func authenticateJWT(accessKey, secretKey string, expiry time.Duration) (string, error) {
// Trim spaces. // Trim spaces.
@ -65,8 +68,15 @@ func authenticateJWT(accessKey, secretKey string, expiry time.Duration) (string,
// Validate secret key. // Validate secret key.
// Using bcrypt to avoid timing attacks. // Using bcrypt to avoid timing attacks.
if bcrypt.CompareHashAndPassword(serverCred.SecretKeyHash, []byte(secretKey)) != nil { if serverCred.secretKeyHash != nil {
return "", errAuthentication if bcrypt.CompareHashAndPassword(serverCred.secretKeyHash, []byte(secretKey)) != nil {
return "", errAuthentication
}
} else {
// Secret key hash not set then generate and validate.
if bcrypt.CompareHashAndPassword(mustGetHashedSecretKey(serverCred.SecretKey), []byte(secretKey)) != nil {
return "", errAuthentication
}
} }
utcNow := time.Now().UTC() utcNow := time.Now().UTC()

@ -163,6 +163,29 @@ func checkUpdate() {
} }
} }
// Initializes a new config if it doesn't exist, else migrates any old config
// to newer config and finally loads the config to memory.
func initConfig() {
envCreds := mustGetCredentialFromEnv()
// Config file does not exist, we create it fresh and return upon success.
if !isConfigFileExists() {
if err := newConfig(envCreds); err != nil {
console.Fatalf("Unable to initialize minio config for the first time. Err: %s.\n", err)
}
console.Println("Created minio configuration file successfully at " + mustGetConfigPath())
return
}
// Migrate any old version of config / state files to newer format.
migrate()
// Once we have migrated all the old config, now load them.
if err := loadConfig(envCreds); err != nil {
console.Fatalf("Unable to initialize minio config. Err: %s.\n", err)
}
}
// Generic Minio initialization to create/load config, prepare loggers, etc.. // Generic Minio initialization to create/load config, prepare loggers, etc..
func minioInit(ctx *cli.Context) { func minioInit(ctx *cli.Context) {
// Set global variables after parsing passed arguments // Set global variables after parsing passed arguments
@ -174,32 +197,12 @@ func minioInit(ctx *cli.Context) {
// Is TLS configured?. // Is TLS configured?.
globalIsSSL = isSSL() globalIsSSL = isSSL()
// Migrate any old version of config / state files to newer format. // Initialize minio server config.
migrate() initConfig()
// Initialize config.
configCreated, err := initConfig()
if err != nil {
console.Fatalf("Unable to initialize minio config. Err: %s.\n", err)
}
if configCreated {
console.Println("Created minio configuration file at " + mustGetConfigPath())
}
// Enable all loggers by now so we can use errorIf() and fatalIf() // Enable all loggers by now so we can use errorIf() and fatalIf()
enableLoggers() enableLoggers()
// Fetch access keys from environment variables and update the config.
accessKey := os.Getenv("MINIO_ACCESS_KEY")
secretKey := os.Getenv("MINIO_SECRET_KEY")
if accessKey != "" && secretKey != "" {
creds, err := getCredential(accessKey, secretKey)
fatalIf(err, "Credentials are invalid, please set proper credentials `minio server --help`")
// Set new credentials.
serverConfig.SetCredential(creds)
}
// Init the error tracing module. // Init the error tracing module.
initError() initError()

@ -21,7 +21,6 @@ import (
"fmt" "fmt"
"net" "net"
"net/url" "net/url"
"os"
"path" "path"
"sort" "sort"
"strconv" "strconv"
@ -128,22 +127,17 @@ func parseStorageEndpoints(eps []string) (endpoints []*url.URL, err error) {
return endpoints, nil return endpoints, nil
} }
// initServerConfig initialize server config. // initServer initialize server config.
func initServerConfig(c *cli.Context) { func initServerConfig(c *cli.Context) {
// Initialization such as config generating/loading config, enable logging, ..
minioInit(c)
// Create certs path. // Create certs path.
err := createCertsPath() fatalIf(createCertsPath(), "Unable to create \"certs\" directory.")
fatalIf(err, "Unable to create \"certs\" directory.")
// Load user supplied root CAs // Load user supplied root CAs
loadRootCAs() loadRootCAs()
// When credentials inherited from the env, server cmd has to save them in the disk
if os.Getenv("MINIO_ACCESS_KEY") != "" && os.Getenv("MINIO_SECRET_KEY") != "" {
// Env credentials are already loaded in serverConfig, just save in the disk
err = serverConfig.Save()
fatalIf(err, "Unable to save credentials in the disk.")
}
// Set maxOpenFiles, This is necessary since default operating // Set maxOpenFiles, This is necessary since default operating
// system limits of 1024, 2048 are not enough for Minio server. // system limits of 1024, 2048 are not enough for Minio server.
setMaxOpenFiles() setMaxOpenFiles()
@ -372,8 +366,8 @@ func serverMain(c *cli.Context) {
cli.ShowCommandHelpAndExit(c, "server", 1) cli.ShowCommandHelpAndExit(c, "server", 1)
} }
// Initialization routine, such as config loading, enable logging, .. // Initializes server config, certs, logging and system settings.
minioInit(c) initServerConfig(c)
// Check for new updates from dl.minio.io. // Check for new updates from dl.minio.io.
checkUpdate() checkUpdate()
@ -390,9 +384,6 @@ func serverMain(c *cli.Context) {
// as parseStorageEndpoints() depends on it. // as parseStorageEndpoints() depends on it.
checkServerSyntax(c) checkServerSyntax(c)
// Initialize server config.
initServerConfig(c)
// Disks to be used in server init. // Disks to be used in server init.
endpoints, err := parseStorageEndpoints(c.Args()) endpoints, err := parseStorageEndpoints(c.Args())
fatalIf(err, "Unable to parse storage endpoints %s", c.Args()) fatalIf(err, "Unable to parse storage endpoints %s", c.Args())

@ -452,8 +452,14 @@ func TestIsDistributedSetup(t *testing.T) {
globalMinioHost = "" globalMinioHost = ""
} }
func TestInitServerConfig(t *testing.T) { // Tests init server.
ctx := &cli.Context{} func TestInitServer(t *testing.T) {
app := cli.NewApp()
app.Commands = []cli.Command{serverCmd}
serverFlagSet := flag.NewFlagSet("server", 0)
serverFlagSet.String("address", ":9000", "")
ctx := cli.NewContext(app, serverFlagSet, serverFlagSet)
root, err := newTestConfig(globalMinioDefaultRegion) root, err := newTestConfig(globalMinioDefaultRegion)
if err != nil { if err != nil {
t.Fatal("Failed to set up test config") t.Fatal("Failed to set up test config")
@ -473,6 +479,7 @@ func TestInitServerConfig(t *testing.T) {
t.Fatalf("Test %d failed with %v", i+1, tErr) t.Fatalf("Test %d failed with %v", i+1, tErr)
} }
initServerConfig(ctx) initServerConfig(ctx)
os.Unsetenv(test.envVar)
} }
} }

@ -119,17 +119,13 @@ func TestDoesPresignedV2SignatureMatch(t *testing.T) {
// TestValidateV2AuthHeader - Tests validate the logic of V2 Authorization header validator. // TestValidateV2AuthHeader - Tests validate the logic of V2 Authorization header validator.
func TestValidateV2AuthHeader(t *testing.T) { func TestValidateV2AuthHeader(t *testing.T) {
// Initialize server config. root, err := newTestConfig(globalMinioDefaultRegion)
if _, err := initConfig(); err != nil { if err != nil {
t.Fatal(err) t.Fatal("Unable to initialize test config.")
} }
defer removeAll(root)
// Save config.
if err := serverConfig.Save(); err != nil {
t.Fatal(err)
}
accessID := serverConfig.GetCredential().AccessKey accessID := serverConfig.GetCredential().AccessKey
testCases := []struct { testCases := []struct {
authString string authString string
expectedError APIErrorCode expectedError APIErrorCode
@ -194,13 +190,11 @@ func TestValidateV2AuthHeader(t *testing.T) {
} }
func TestDoesPolicySignatureV2Match(t *testing.T) { func TestDoesPolicySignatureV2Match(t *testing.T) {
if _, err := initConfig(); err != nil { root, err := newTestConfig(globalMinioDefaultRegion)
t.Fatal(err) if err != nil {
} t.Fatal("Unable to initialize test config.")
if err := serverConfig.Save(); err != nil {
t.Fatal(err)
} }
defer removeAll(root)
creds := serverConfig.GetCredential() creds := serverConfig.GetCredential()
policy := "policy" policy := "policy"
testCases := []struct { testCases := []struct {

@ -496,6 +496,10 @@ func resetGlobalIsXL() {
globalIsXL = false globalIsXL = false
} }
func resetGlobalIsEnvs() {
globalIsEnvCreds = false
}
// Resets all the globals used modified in tests. // Resets all the globals used modified in tests.
// Resetting ensures that the changes made to globals by one test doesn't affect others. // Resetting ensures that the changes made to globals by one test doesn't affect others.
func resetTestGlobals() { func resetTestGlobals() {
@ -513,6 +517,8 @@ func resetTestGlobals() {
resetGlobalEndpoints() resetGlobalEndpoints()
// Reset global isXL flag. // Reset global isXL flag.
resetGlobalIsXL() resetGlobalIsXL()
// Reset global isEnvCreds flag.
resetGlobalIsEnvs()
} }
// Configure the server for the test run. // Configure the server for the test run.
@ -527,7 +533,7 @@ func newTestConfig(bucketLocation string) (rootPath string, err error) {
setGlobalConfigPath(rootPath) setGlobalConfigPath(rootPath)
// Initialize server config. // Initialize server config.
if _, err = initConfig(); err != nil { if err = newConfig(credential{}); err != nil {
return "", err return "", err
} }
@ -1790,6 +1796,7 @@ func ExecObjectLayerAPIAnonTest(t *testing.T, testName, bucketName, objectName,
failTestStr := func(testType, failMsg string) string { failTestStr := func(testType, failMsg string) string {
return fmt.Sprintf("Minio %s: %s fail for \"%s\": \n<Error> %s", instanceType, testType, testName, failMsg) return fmt.Sprintf("Minio %s: %s fail for \"%s\": \n<Error> %s", instanceType, testType, testName, failMsg)
} }
// httptest Recorder to capture all the response by the http handler. // httptest Recorder to capture all the response by the http handler.
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
// reading the body to preserve it so that it can be used again for second attempt of sending unsigned HTTP request. // reading the body to preserve it so that it can be used again for second attempt of sending unsigned HTTP request.
@ -1941,8 +1948,10 @@ func ExecObjectLayerAPITest(t *testing.T, objAPITest objAPITestType, endpoints [
// reset globals. // reset globals.
// this is to make sure that the tests are not affected by modified value. // this is to make sure that the tests are not affected by modified value.
resetTestGlobals() resetTestGlobals()
// initialize NSLock. // initialize NSLock.
initNSLock(false) initNSLock(false)
// initialize the server and obtain the credentials and root. // initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request. // credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion) rootPath, err := newTestConfig(globalMinioDefaultRegion)
@ -2025,6 +2034,7 @@ func ExecObjectLayerDiskAlteredTest(t *testing.T, objTest objTestDiskNotFoundTyp
if err != nil { if err != nil {
t.Fatalf("Initialization of object layer failed for XL setup: %s", err) t.Fatalf("Initialization of object layer failed for XL setup: %s", err)
} }
// Executing the object layer tests for XL. // Executing the object layer tests for XL.
objTest(objLayer, XLTestStr, fsDirs, t) objTest(objLayer, XLTestStr, fsDirs, t)
defer removeRoots(fsDirs) defer removeRoots(fsDirs)

@ -362,12 +362,21 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se
return toJSONError(errAuthentication) return toJSONError(errAuthentication)
} }
// If creds are set through ENV disallow changing credentials.
if globalIsEnvCreds {
return toJSONError(errChangeCredNotAllowed)
}
// As we already validated the authentication, we save given access/secret keys. // As we already validated the authentication, we save given access/secret keys.
creds, err := getCredential(args.AccessKey, args.SecretKey) if err := validateAuthKeys(args.AccessKey, args.SecretKey); err != nil {
if err != nil {
return toJSONError(err) return toJSONError(err)
} }
creds := credential{
AccessKey: args.AccessKey,
SecretKey: args.SecretKey,
}
// Notify all other Minio peers to update credentials // Notify all other Minio peers to update credentials
errsMap := updateCredsOnPeers(creds) errsMap := updateCredsOnPeers(creds)
@ -375,7 +384,7 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se
serverConfig.SetCredential(creds) serverConfig.SetCredential(creds)
// Persist updated credentials. // Persist updated credentials.
if err = serverConfig.Save(); err != nil { if err := serverConfig.Save(); err != nil {
errsMap[globalMinioAddr] = err errsMap[globalMinioAddr] = err
} }
@ -397,7 +406,7 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se
} }
// As we have updated access/secret key, generate new auth token. // As we have updated access/secret key, generate new auth token.
token, err := authenticateWeb(args.AccessKey, args.SecretKey) token, err := authenticateWeb(creds.AccessKey, creds.SecretKey)
if err != nil { if err != nil {
// Did we have peer errors? // Did we have peer errors?
if len(errsMap) > 0 { if len(errsMap) > 0 {
@ -829,8 +838,13 @@ func toWebAPIError(err error) APIError {
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
Description: err.Error(), Description: err.Error(),
} }
} else if err == errChangeCredNotAllowed {
return APIError{
Code: "MethodNotAllowed",
HTTPStatusCode: http.StatusMethodNotAllowed,
Description: err.Error(),
}
} }
// Convert error type to api error code. // Convert error type to api error code.
var apiErrCode APIErrorCode var apiErrCode APIErrorCode
switch err.(type) { switch err.(type) {

@ -128,15 +128,6 @@ func TestWebHandlerLogin(t *testing.T) {
func testLoginWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testLoginWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
// test cases with sample input and expected output. // test cases with sample input and expected output.
@ -177,15 +168,6 @@ func testStorageInfoWebHandler(obj ObjectLayer, instanceType string, t TestErrHa
// get random bucket name. // get random bucket name.
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
@ -223,15 +205,6 @@ func TestWebHandlerServerInfo(t *testing.T) {
func testServerInfoWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testServerInfoWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
@ -269,15 +242,6 @@ func TestWebHandlerMakeBucket(t *testing.T) {
func testMakeBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testMakeBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
@ -329,15 +293,6 @@ func TestWebHandlerListBuckets(t *testing.T) {
func testListBucketsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testListBucketsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
@ -386,15 +341,6 @@ func TestWebHandlerListObjects(t *testing.T) {
func testListObjectsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testListObjectsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
@ -490,15 +436,6 @@ func TestWebHandlerRemoveObject(t *testing.T) {
func testRemoveObjectWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testRemoveObjectWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
@ -566,15 +503,6 @@ func TestWebHandlerGenerateAuth(t *testing.T) {
func testGenerateAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testGenerateAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
@ -612,15 +540,6 @@ func TestWebHandlerSetAuth(t *testing.T) {
func testSetAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testSetAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
@ -673,15 +592,6 @@ func TestWebHandlerGetAuth(t *testing.T) {
func testGetAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testGetAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
@ -718,18 +628,9 @@ func TestWebHandlerUpload(t *testing.T) {
func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
content := []byte("temporary file's content")
content := []byte("temporary file's content")
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
if err != nil { if err != nil {
t.Fatal("Cannot authenticate") t.Fatal("Cannot authenticate")
@ -820,15 +721,6 @@ func TestWebHandlerDownload(t *testing.T) {
func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
@ -912,15 +804,6 @@ func TestWebHandlerPresignedGetHandler(t *testing.T) {
func testWebPresignedGetHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testWebPresignedGetHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
@ -1025,15 +908,6 @@ func TestWebHandlerGetBucketPolicyHandler(t *testing.T) {
func testWebGetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testWebGetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
@ -1108,15 +982,6 @@ func TestWebHandlerListAllBucketPoliciesHandler(t *testing.T) {
func testWebListAllBucketPoliciesHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testWebListAllBucketPoliciesHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)
@ -1214,15 +1079,6 @@ func TestWebHandlerSetBucketPolicyHandler(t *testing.T) {
func testWebSetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { func testWebSetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrHandler) {
// Register the API end points with XL/FS object layer. // Register the API end points with XL/FS object layer.
apiRouter := initTestWebRPCEndPoint(obj) apiRouter := initTestWebRPCEndPoint(obj)
// initialize the server and obtain the credentials and root.
// credentials are necessary to sign the HTTP request.
rootPath, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
// remove the root directory after the test ends.
defer removeAll(rootPath)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey)