Honor envs properly for access and secret key. (#3703)

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 #3696
Partial(fix) #3700 (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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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.

View File

@ -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 {

View File

@ -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

View File

@ -42,15 +42,21 @@ 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()
// If env is set for a fresh start, save them to config file.
if globalIsEnvCreds {
srvCfg.SetCredential(envCreds)
} else {
srvCfg.SetCredential(newCredential())
}
// Enable console logger by default on a fresh run. // Enable console logger by default on a fresh run.
srvCfg.Logger.Console = consoleLogger{ srvCfg.Logger.Console = consoleLogger{
@ -75,9 +81,8 @@ func initConfig() (bool, error) {
srvCfg.Notify.Webhook["1"] = webhookNotify{} srvCfg.Notify.Webhook["1"] = webhookNotify{}
// Create config path. // Create config path.
err := createConfigPath() if err := createConfigPath(); err != nil {
if err != nil { return err
return false, err
} }
// hold the mutex lock before a new config is assigned. // hold the mutex lock before a new config is assigned.
@ -88,31 +93,37 @@ func initConfig() (bool, error) {
serverConfigMu.Unlock() serverConfigMu.Unlock()
// Save config into file. // Save config into file.
return true, serverConfig.Save() 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.

View File

@ -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)
} }
} }

View File

@ -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
} }
if !isSecretKeyValid(secretKey) { // Return credential object.
return credential{}, errInvalidSecretKeyLength return newCredentialWithKeys(accessKey, secretKey), nil
} }
secretHash := mustGetHashedSecretKey(secretKey) return credential{}, nil
return credential{accessKey, secretKey, secretHash}, nil
} }

View File

@ -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,9 +68,16 @@ 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 {
if bcrypt.CompareHashAndPassword(serverCred.secretKeyHash, []byte(secretKey)) != nil {
return "", errAuthentication 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()
token := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, jwtgo.MapClaims{ token := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, jwtgo.MapClaims{

View File

@ -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()

View File

@ -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())

View File

@ -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)
} }
} }

View File

@ -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 {

View File

@ -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)

View File

@ -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) {

View File

@ -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)