move credentials as separate package (#5115)

This commit is contained in:
Bala FA 2017-10-31 11:54:32 -07:00 committed by Dee Koder
parent 8d584bd819
commit 32c6b62932
26 changed files with 307 additions and 277 deletions

View File

@ -28,6 +28,8 @@ import (
"strconv" "strconv"
"sync" "sync"
"time" "time"
"github.com/minio/minio/pkg/auth"
) )
const ( const (
@ -168,7 +170,7 @@ func (adminAPI adminAPIHandlers) ServiceCredentialsHandler(w http.ResponseWriter
return return
} }
creds, err := createCredential(req.Username, req.Password) creds, err := auth.CreateCredentials(req.Username, req.Password)
if err != nil { if err != nil {
writeErrorResponse(w, toAPIErrorCode(err), r.URL) writeErrorResponse(w, toAPIErrorCode(err), r.URL)
return return

View File

@ -32,6 +32,7 @@ import (
"time" "time"
router "github.com/gorilla/mux" router "github.com/gorilla/mux"
"github.com/minio/minio/pkg/auth"
) )
var configJSON = []byte(`{ var configJSON = []byte(`{
@ -263,7 +264,7 @@ func testServiceSignalReceiver(cmd cmdType, t *testing.T) {
// getServiceCmdRequest - Constructs a management REST API request for service // getServiceCmdRequest - Constructs a management REST API request for service
// subcommands for a given cmdType value. // subcommands for a given cmdType value.
func getServiceCmdRequest(cmd cmdType, cred credential, body []byte) (*http.Request, error) { func getServiceCmdRequest(cmd cmdType, cred auth.Credentials, body []byte) (*http.Request, error) {
req, err := newTestRequest(cmd.apiMethod(), "/?service", 0, nil) req, err := newTestRequest(cmd.apiMethod(), "/?service", 0, nil)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -20,6 +20,7 @@ import (
"encoding/xml" "encoding/xml"
"net/http" "net/http"
"github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/hash" "github.com/minio/minio/pkg/hash"
) )
@ -687,9 +688,9 @@ func toAPIErrorCode(err error) (apiErr APIErrorCode) {
apiErr = ErrEntityTooLarge apiErr = ErrEntityTooLarge
case errDataTooSmall: case errDataTooSmall:
apiErr = ErrEntityTooSmall apiErr = ErrEntityTooSmall
case errInvalidAccessKeyLength: case auth.ErrInvalidAccessKeyLength:
apiErr = ErrAdminInvalidAccessKey apiErr = ErrAdminInvalidAccessKey
case errInvalidSecretKeyLength: case auth.ErrInvalidSecretKeyLength:
apiErr = ErrAdminInvalidSecretKey apiErr = ErrAdminInvalidSecretKey
} }

View File

@ -23,6 +23,8 @@ import (
"net/url" "net/url"
"os" "os"
"testing" "testing"
"github.com/minio/minio/pkg/auth"
) )
// Test get request auth type. // Test get request auth type.
@ -327,7 +329,7 @@ func TestIsReqAuthenticated(t *testing.T) {
} }
defer os.RemoveAll(path) defer os.RemoveAll(path)
creds, err := createCredential("myuser", "mypassword") creds, err := auth.CreateCredentials("myuser", "mypassword")
if err != nil { if err != nil {
t.Fatalf("unable create credential, %s", err) t.Fatalf("unable create credential, %s", err)
} }

View File

@ -21,6 +21,8 @@ import (
"path" "path"
"sync" "sync"
"time" "time"
"github.com/minio/minio/pkg/auth"
) )
// SetAuthPeerArgs - Arguments collection for SetAuth RPC call // SetAuthPeerArgs - Arguments collection for SetAuth RPC call
@ -29,7 +31,7 @@ type SetAuthPeerArgs struct {
AuthRPCArgs AuthRPCArgs
// New credentials that receiving peer should update to. // New credentials that receiving peer should update to.
Creds credential Creds auth.Credentials
} }
// SetAuthPeer - Update to new credentials sent from a peer Minio // SetAuthPeer - Update to new credentials sent from a peer Minio
@ -64,7 +66,7 @@ func (br *browserPeerAPIHandlers) SetAuthPeer(args SetAuthPeerArgs, reply *AuthR
} }
// Sends SetAuthPeer RPCs to all peers in the Minio cluster // Sends SetAuthPeer RPCs to all peers in the Minio cluster
func updateCredsOnPeers(creds credential) map[string]error { func updateCredsOnPeers(creds auth.Credentials) map[string]error {
// Get list of peer addresses (from globalS3Peers) // Get list of peer addresses (from globalS3Peers)
peers := []string{} peers := []string{}
for _, p := range globalS3Peers { for _, p := range globalS3Peers {

View File

@ -19,6 +19,8 @@ package cmd
import ( import (
"path" "path"
"testing" "testing"
"github.com/minio/minio/pkg/auth"
) )
// API suite container common to both FS and XL. // API suite container common to both FS and XL.
@ -61,7 +63,7 @@ func TestBrowserPeerRPC(t *testing.T) {
// Tests for browser peer rpc. // Tests for browser peer rpc.
func (s *TestRPCBrowserPeerSuite) testBrowserPeerRPC(t *testing.T) { func (s *TestRPCBrowserPeerSuite) testBrowserPeerRPC(t *testing.T) {
// Construct RPC call arguments. // Construct RPC call arguments.
creds, err := createCredential("abcd1", "abcd1234") creds, err := auth.CreateCredentials("abcd1", "abcd1234")
if err != nil { if err != nil {
t.Fatalf("unable to create credential. %v", err) t.Fatalf("unable to create credential. %v", err)
} }

View File

@ -24,6 +24,8 @@ import (
"net/http/httptest" "net/http/httptest"
"strconv" "strconv"
"testing" "testing"
"github.com/minio/minio/pkg/auth"
) )
// Wrapper for calling GetBucketPolicy HTTP handler tests for both XL multiple disks and single node setup. // Wrapper for calling GetBucketPolicy HTTP handler tests for both XL multiple disks and single node setup.
@ -32,7 +34,7 @@ func TestGetBucketLocationHandler(t *testing.T) {
} }
func testGetBucketLocationHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testGetBucketLocationHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
initBucketPolicies(obj) initBucketPolicies(obj)
// test cases with sample input and expected output. // test cases with sample input and expected output.
@ -177,7 +179,7 @@ func TestHeadBucketHandler(t *testing.T) {
} }
func testHeadBucketHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testHeadBucketHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
initBucketPolicies(obj) initBucketPolicies(obj)
// test cases with sample input and expected output. // test cases with sample input and expected output.
@ -284,7 +286,7 @@ func TestListMultipartUploadsHandler(t *testing.T) {
// testListMultipartUploadsHandler - Tests validate listing of multipart uploads. // testListMultipartUploadsHandler - Tests validate listing of multipart uploads.
func testListMultipartUploadsHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testListMultipartUploadsHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
initBucketPolicies(obj) initBucketPolicies(obj)
// Collection of non-exhaustive ListMultipartUploads test cases, valid errors // Collection of non-exhaustive ListMultipartUploads test cases, valid errors
@ -522,7 +524,7 @@ func TestListBucketsHandler(t *testing.T) {
// testListBucketsHandler - Tests validate listing of buckets. // testListBucketsHandler - Tests validate listing of buckets.
func testListBucketsHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testListBucketsHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
testCases := []struct { testCases := []struct {
bucketName string bucketName string
@ -615,7 +617,7 @@ func TestAPIDeleteMultipleObjectsHandler(t *testing.T) {
} }
func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
initBucketPolicies(obj) initBucketPolicies(obj)
var err error var err error
@ -805,7 +807,7 @@ func TestIsBucketActionAllowed(t *testing.T) {
} }
func testIsBucketActionAllowedHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testIsBucketActionAllowedHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
testCases := []struct { testCases := []struct {
// input. // input.

View File

@ -28,6 +28,8 @@ import (
"os" "os"
"reflect" "reflect"
"testing" "testing"
"github.com/minio/minio/pkg/auth"
) )
// Implement a dummy flush writer. // Implement a dummy flush writer.
@ -181,7 +183,7 @@ func TestGetBucketNotificationHandler(t *testing.T) {
} }
func testGetBucketNotificationHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testGetBucketNotificationHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
// declare sample configs // declare sample configs
filterRules := []filterRule{ filterRules := []filterRule{
{ {
@ -254,7 +256,7 @@ func TestPutBucketNotificationHandler(t *testing.T) {
} }
func testPutBucketNotificationHandler(obj ObjectLayer, instanceType, func testPutBucketNotificationHandler(obj ObjectLayer, instanceType,
bucketName string, apiRouter http.Handler, credentials credential, bucketName string, apiRouter http.Handler, credentials auth.Credentials,
t *testing.T) { t *testing.T) {
// declare sample configs // declare sample configs
@ -344,7 +346,7 @@ func TestListenBucketNotificationNilHandler(t *testing.T) {
} }
func testListenBucketNotificationNilHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testListenBucketNotificationNilHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
// get random bucket name. // get random bucket name.
randBucket := getRandomBucketName() randBucket := getRandomBucketName()
@ -371,7 +373,7 @@ func testListenBucketNotificationNilHandler(obj ObjectLayer, instanceType, bucke
} }
func testRemoveNotificationConfig(obj ObjectLayer, instanceType, func testRemoveNotificationConfig(obj ObjectLayer, instanceType,
bucketName string, apiRouter http.Handler, credentials credential, bucketName string, apiRouter http.Handler, credentials auth.Credentials,
t *testing.T) { t *testing.T) {
invalidBucket := "Invalid\\Bucket" invalidBucket := "Invalid\\Bucket"

View File

@ -27,6 +27,7 @@ import (
"github.com/minio/minio-go/pkg/policy" "github.com/minio/minio-go/pkg/policy"
"github.com/minio/minio-go/pkg/set" "github.com/minio/minio-go/pkg/set"
"github.com/minio/minio/pkg/auth"
) )
// Tests validate Bucket policy resource matcher. // Tests validate Bucket policy resource matcher.
@ -248,7 +249,7 @@ func TestPutBucketPolicyHandler(t *testing.T) {
// testPutBucketPolicyHandler - Test for Bucket policy end point. // testPutBucketPolicyHandler - Test for Bucket policy end point.
func testPutBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testPutBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
initBucketPolicies(obj) initBucketPolicies(obj)
bucketName1 := fmt.Sprintf("%s-1", bucketName) bucketName1 := fmt.Sprintf("%s-1", bucketName)
@ -455,7 +456,7 @@ func TestGetBucketPolicyHandler(t *testing.T) {
// testGetBucketPolicyHandler - Test for end point which fetches the access policy json of the given bucket. // testGetBucketPolicyHandler - Test for end point which fetches the access policy json of the given bucket.
func testGetBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testGetBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
// initialize bucket policy. // initialize bucket policy.
initBucketPolicies(obj) initBucketPolicies(obj)
@ -644,7 +645,7 @@ func TestDeleteBucketPolicyHandler(t *testing.T) {
// testDeleteBucketPolicyHandler - Test for Delete bucket policy end point. // testDeleteBucketPolicyHandler - Test for Delete bucket policy end point.
func testDeleteBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testDeleteBucketPolicyHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
// initialize bucket policy. // initialize bucket policy.
initBucketPolicies(obj) initBucketPolicies(obj)

View File

@ -24,6 +24,7 @@ import (
"time" "time"
"github.com/minio/cli" "github.com/minio/cli"
"github.com/minio/minio/pkg/auth"
) )
// Check for updates and print a notification message // Check for updates and print a notification message
@ -95,7 +96,7 @@ func handleCommonEnvVars() {
accessKey := os.Getenv("MINIO_ACCESS_KEY") accessKey := os.Getenv("MINIO_ACCESS_KEY")
secretKey := os.Getenv("MINIO_SECRET_KEY") secretKey := os.Getenv("MINIO_SECRET_KEY")
if accessKey != "" && secretKey != "" { if accessKey != "" && secretKey != "" {
cred, err := createCredential(accessKey, secretKey) cred, err := auth.CreateCredentials(accessKey, secretKey)
fatalIf(err, "Invalid access/secret Key set in environment.") fatalIf(err, "Invalid access/secret Key set in environment.")
// credential Envs are set globally. // credential Envs are set globally.

View File

@ -21,6 +21,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/quick" "github.com/minio/minio/pkg/quick"
) )
@ -190,7 +191,7 @@ func migrateV2ToV3() error {
return nil return nil
} }
cred, err := createCredential(cv2.Credentials.AccessKey, cv2.Credentials.SecretKey) cred, err := auth.CreateCredentials(cv2.Credentials.AccessKey, cv2.Credentials.SecretKey)
if err != nil { if err != nil {
return fmt.Errorf("Invalid credential in V2 configuration file. %v", err) return fmt.Errorf("Invalid credential in V2 configuration file. %v", err)
} }

View File

@ -16,7 +16,11 @@
package cmd package cmd
import "sync" import (
"sync"
"github.com/minio/minio/pkg/auth"
)
/////////////////// Config V1 /////////////////// /////////////////// Config V1 ///////////////////
type configV1 struct { type configV1 struct {
@ -92,7 +96,7 @@ type configV3 struct {
Addr string `json:"address"` Addr string `json:"address"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -122,7 +126,7 @@ type configV4 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -179,7 +183,7 @@ type configV5 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -209,7 +213,7 @@ type configV6 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -246,7 +250,7 @@ type serverConfigV7 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -265,7 +269,7 @@ type serverConfigV8 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -284,7 +288,7 @@ type serverConfigV9 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -310,7 +314,7 @@ type serverConfigV10 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -338,7 +342,7 @@ type serverConfigV11 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -354,7 +358,7 @@ type serverConfigV12 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -370,7 +374,7 @@ type serverConfigV13 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
// Additional error logging configuration. // Additional error logging configuration.
@ -386,7 +390,7 @@ type serverConfigV14 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
Browser BrowserFlag `json:"browser"` Browser BrowserFlag `json:"browser"`
@ -403,7 +407,7 @@ type serverConfigV15 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
Browser BrowserFlag `json:"browser"` Browser BrowserFlag `json:"browser"`
@ -420,7 +424,7 @@ type serverConfigV16 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
Browser BrowserFlag `json:"browser"` Browser BrowserFlag `json:"browser"`
@ -439,7 +443,7 @@ type serverConfigV17 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
Browser BrowserFlag `json:"browser"` Browser BrowserFlag `json:"browser"`
@ -458,7 +462,7 @@ type serverConfigV18 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
Browser BrowserFlag `json:"browser"` Browser BrowserFlag `json:"browser"`

View File

@ -22,6 +22,7 @@ import (
"io/ioutil" "io/ioutil"
"sync" "sync"
"github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/quick" "github.com/minio/minio/pkg/quick"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
) )
@ -42,7 +43,7 @@ type serverConfigV19 struct {
Version string `json:"version"` Version string `json:"version"`
// S3 API configuration. // S3 API configuration.
Credential credential `json:"credential"` Credential auth.Credentials `json:"credential"`
Region string `json:"region"` Region string `json:"region"`
Browser BrowserFlag `json:"browser"` Browser BrowserFlag `json:"browser"`
@ -79,7 +80,7 @@ func (s *serverConfigV19) GetRegion() string {
} }
// SetCredentials set new credentials. SetCredential returns the previous credential. // SetCredentials set new credentials. SetCredential returns the previous credential.
func (s *serverConfigV19) SetCredential(creds credential) (prevCred credential) { func (s *serverConfigV19) SetCredential(creds auth.Credentials) (prevCred auth.Credentials) {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
@ -94,7 +95,7 @@ func (s *serverConfigV19) SetCredential(creds credential) (prevCred credential)
} }
// GetCredentials get current credentials. // GetCredentials get current credentials.
func (s *serverConfigV19) GetCredential() credential { func (s *serverConfigV19) GetCredential() auth.Credentials {
s.RLock() s.RLock()
defer s.RUnlock() defer s.RUnlock()
@ -130,7 +131,7 @@ func (s *serverConfigV19) Save() error {
func newServerConfigV19() *serverConfigV19 { func newServerConfigV19() *serverConfigV19 {
srvCfg := &serverConfigV19{ srvCfg := &serverConfigV19{
Version: v19, Version: v19,
Credential: mustGetNewCredential(), Credential: auth.MustGetNewCredentials(),
Region: globalMinioDefaultRegion, Region: globalMinioDefaultRegion,
Browser: true, Browser: true,
Logger: &loggers{}, Logger: &loggers{},

View File

@ -1,100 +0,0 @@
/*
* Minio Cloud Storage, (C) 2017 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmd
import "testing"
func TestMustGetNewCredential(t *testing.T) {
cred := mustGetNewCredential()
if !cred.IsValid() {
t.Fatalf("Failed to get new valid credential")
}
if len(cred.SecretKey) != secretKeyMaxLen {
t.Fatalf("Invalid length %d of the secretKey credential generated, expected %d", len(cred.SecretKey), secretKeyMaxLen)
}
}
func TestCreateCredential(t *testing.T) {
cred := mustGetNewCredential()
testCases := []struct {
accessKey string
secretKey string
expectedResult bool
expectedErr error
}{
// Access key too small (min 5 chars).
{"user", "pass", false, errInvalidAccessKeyLength},
// Long access key is ok.
{"user123456789012345678901234567890", "password", true, nil},
// Secret key too small (min 8 chars).
{"myuser", "pass", false, errInvalidSecretKeyLength},
// Long secret key is ok.
{"myuser", "pass1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", true, nil},
{"myuser", "mypassword", true, nil},
{cred.AccessKey, cred.SecretKey, true, nil},
}
for _, testCase := range testCases {
cred, err := createCredential(testCase.accessKey, testCase.secretKey)
if testCase.expectedErr == nil {
if err != nil {
t.Fatalf("error: expected = <nil>, got = %v", err)
}
} else if err == nil {
t.Fatalf("error: expected = %v, got = <nil>", testCase.expectedErr)
} else if testCase.expectedErr.Error() != err.Error() {
t.Fatalf("error: expected = %v, got = %v", testCase.expectedErr, err)
}
if testCase.expectedResult != cred.IsValid() {
t.Fatalf("cred: expected: %v, got: %v", testCase.expectedResult, cred.IsValid())
}
}
}
func TestCredentialEqual(t *testing.T) {
cred := mustGetNewCredential()
testCases := []struct {
cred credential
ccred credential
expectedResult bool
}{
// Empty compare credential
{cred, credential{}, false},
// Empty credential
{credential{}, cred, false},
// Two different credentials
{cred, mustGetNewCredential(), false},
// Access key is different in compare credential.
{cred, credential{AccessKey: "myuser", SecretKey: cred.SecretKey}, false},
// Secret key is different in compare credential.
{cred, credential{AccessKey: cred.AccessKey, SecretKey: "mypassword"}, false},
// secretHashKey is missing in compare credential.
{cred, credential{AccessKey: cred.AccessKey, SecretKey: cred.SecretKey}, true},
// secretHashKey is missing in credential.
{credential{AccessKey: cred.AccessKey, SecretKey: cred.SecretKey}, cred, true},
// Same credentials.
{cred, cred, true},
}
for _, testCase := range testCases {
result := testCase.cred.Equal(testCase.ccred)
if result != testCase.expectedResult {
t.Fatalf("cred: expected: %v, got: %v", testCase.expectedResult, result)
}
}
}

View File

@ -31,6 +31,7 @@ import (
b2 "github.com/minio/blazer/base" b2 "github.com/minio/blazer/base"
"github.com/minio/cli" "github.com/minio/cli"
"github.com/minio/minio-go/pkg/policy" "github.com/minio/minio-go/pkg/policy"
"github.com/minio/minio/pkg/auth"
h2 "github.com/minio/minio/pkg/hash" h2 "github.com/minio/minio/pkg/hash"
) )
@ -101,7 +102,7 @@ func (g *B2Gateway) NewGatewayLayer() (GatewayLayer, error) {
type b2Objects struct { type b2Objects struct {
gatewayUnsupported gatewayUnsupported
mu sync.Mutex mu sync.Mutex
creds credential creds auth.Credentials
b2Client *b2.B2 b2Client *b2.B2
anonClient *http.Client anonClient *http.Client
ctx context.Context ctx context.Context

View File

@ -25,6 +25,7 @@ import (
humanize "github.com/dustin/go-humanize" humanize "github.com/dustin/go-humanize"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/minio/minio/pkg/auth"
miniohttp "github.com/minio/minio/pkg/http" miniohttp "github.com/minio/minio/pkg/http"
) )
@ -142,7 +143,7 @@ var (
// Time when object layer was initialized on start up. // Time when object layer was initialized on start up.
globalBootTime time.Time globalBootTime time.Time
globalActiveCred credential globalActiveCred auth.Credentials
globalPublicCerts []*x509.Certificate globalPublicCerts []*x509.Certificate
globalXLObjCacheDisabled bool globalXLObjCacheDisabled bool
// Add new variable global values here. // Add new variable global values here.

View File

@ -24,6 +24,7 @@ import (
jwtgo "github.com/dgrijalva/jwt-go" jwtgo "github.com/dgrijalva/jwt-go"
jwtreq "github.com/dgrijalva/jwt-go/request" jwtreq "github.com/dgrijalva/jwt-go/request"
"github.com/minio/minio/pkg/auth"
) )
const ( const (
@ -47,7 +48,7 @@ var (
) )
func authenticateJWT(accessKey, secretKey string, expiry time.Duration) (string, error) { func authenticateJWT(accessKey, secretKey string, expiry time.Duration) (string, error) {
passedCredential, err := createCredential(accessKey, secretKey) passedCredential, err := auth.CreateCredentials(accessKey, secretKey)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -20,6 +20,8 @@ import (
"net/http" "net/http"
"os" "os"
"testing" "testing"
"github.com/minio/minio/pkg/auth"
) )
func testAuthenticate(authType string, t *testing.T) { func testAuthenticate(authType string, t *testing.T) {
@ -28,11 +30,7 @@ func testAuthenticate(authType string, t *testing.T) {
t.Fatalf("unable initialize config file, %s", err) t.Fatalf("unable initialize config file, %s", err)
} }
defer os.RemoveAll(testPath) defer os.RemoveAll(testPath)
// Create access and secret keys in length, 300 and 600 cred := auth.MustGetNewCredentials()
cred, err := getNewCredential(300, 600)
if err != nil {
t.Fatalf("unable to get new credential, %v", err)
}
serverConfig.SetCredential(cred) serverConfig.SetCredential(cred)
// Define test cases. // Define test cases.
@ -42,9 +40,9 @@ func testAuthenticate(authType string, t *testing.T) {
expectedErr error expectedErr error
}{ }{
// Access key (less than 5 chrs) too small. // Access key (less than 5 chrs) too small.
{"user", cred.SecretKey, errInvalidAccessKeyLength}, {"user", cred.SecretKey, auth.ErrInvalidAccessKeyLength},
// Secret key (less than 8 chrs) too small. // Secret key (less than 8 chrs) too small.
{cred.AccessKey, "pass", errInvalidSecretKeyLength}, {cred.AccessKey, "pass", auth.ErrInvalidSecretKeyLength},
// Authentication error. // Authentication error.
{"myuser", "mypassword", errInvalidAccessKeyID}, {"myuser", "mypassword", errInvalidAccessKeyID},
// Authentication error. // Authentication error.

View File

@ -17,7 +17,6 @@
package cmd package cmd
import ( import (
"crypto/rand"
"fmt" "fmt"
"time" "time"
) )
@ -258,13 +257,5 @@ func (n *nsLockMap) deleteLockInfoEntryForOps(param nsParam, opsID string) error
// Return randomly generated string ID // Return randomly generated string ID
func getOpsID() string { func getOpsID() string {
const opsIDLen = 16 return mustGetUUID()
opsIDBytes := make([]byte, opsIDLen)
if _, err := rand.Read(opsIDBytes); err != nil {
panic(err)
}
for i := 0; i < opsIDLen; i++ {
opsIDBytes[i] = alphaNumericTable[opsIDBytes[i]%alphaNumericTableLen]
}
return string(opsIDBytes)
} }

View File

@ -179,25 +179,6 @@ func verifyLockState(l lockStateCase, t *testing.T, testNum int) {
verifyLockStats(l, t, testNum) verifyLockStats(l, t, testNum)
} }
func TestGetOpsID(t *testing.T) {
// Ensure that it returns an alphanumeric result of length 16.
var id = getOpsID()
if len(id) != 16 {
t.Fail()
}
var e rune
for _, char := range id {
e = rune(char)
// Ensure that it is alphanumeric, in this case, between 0-9 and A-Z.
if !(('0' <= e && e <= '9') || ('A' <= e && e <= 'Z')) {
t.Fail()
}
}
}
// TestNewDebugLockInfoPerVolumePath - Validates the values initialized by newDebugLockInfoPerVolumePath(). // TestNewDebugLockInfoPerVolumePath - Validates the values initialized by newDebugLockInfoPerVolumePath().
func TestNewDebugLockInfoPerVolumePath(t *testing.T) { func TestNewDebugLockInfoPerVolumePath(t *testing.T) {
lockInfo := &debugLockInfoPerVolumePath{ lockInfo := &debugLockInfoPerVolumePath{

View File

@ -30,6 +30,7 @@ import (
"testing" "testing"
humanize "github.com/dustin/go-humanize" humanize "github.com/dustin/go-humanize"
"github.com/minio/minio/pkg/auth"
) )
// Type to capture different modifications to API request to simulate failure cases. // Type to capture different modifications to API request to simulate failure cases.
@ -51,7 +52,7 @@ func TestAPIHeadObjectHandler(t *testing.T) {
} }
func testAPIHeadObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIHeadObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
objectName := "test-object" objectName := "test-object"
// set of byte data for PutObject. // set of byte data for PutObject.
// object has to be created before running tests for HeadObject. // object has to be created before running tests for HeadObject.
@ -197,7 +198,7 @@ func TestAPIGetObjectHandler(t *testing.T) {
} }
func testAPIGetObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIGetObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
objectName := "test-object" objectName := "test-object"
// set of byte data for PutObject. // set of byte data for PutObject.
// object has to be created before running tests for GetObject. // object has to be created before running tests for GetObject.
@ -470,7 +471,7 @@ func TestAPIPutObjectStreamSigV4Handler(t *testing.T) {
} }
func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
objectName := "test-object" objectName := "test-object"
bytesDataLen := 65 * humanize.KiByte bytesDataLen := 65 * humanize.KiByte
@ -784,7 +785,7 @@ func TestAPIPutObjectHandler(t *testing.T) {
} }
func testAPIPutObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIPutObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
// register event notifier. // register event notifier.
err := initEventNotifier(obj) err := initEventNotifier(obj)
@ -1023,7 +1024,7 @@ func TestAPICopyObjectPartHandlerSanity(t *testing.T) {
} }
func testAPICopyObjectPartHandlerSanity(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPICopyObjectPartHandlerSanity(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
objectName := "test-object" objectName := "test-object"
// register event notifier. // register event notifier.
@ -1138,7 +1139,7 @@ func TestAPICopyObjectPartHandler(t *testing.T) {
} }
func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
objectName := "test-object" objectName := "test-object"
// register event notifier. // register event notifier.
@ -1468,7 +1469,7 @@ func TestAPICopyObjectHandler(t *testing.T) {
} }
func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
objectName := "test-object" objectName := "test-object"
// object used for anonymous HTTP request test. // object used for anonymous HTTP request test.
@ -1886,7 +1887,7 @@ func TestAPINewMultipartHandler(t *testing.T) {
} }
func testAPINewMultipartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPINewMultipartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
objectName := "test-object-new-multipart" objectName := "test-object-new-multipart"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
@ -2032,7 +2033,7 @@ func TestAPINewMultipartHandlerParallel(t *testing.T) {
} }
func testAPINewMultipartHandlerParallel(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPINewMultipartHandlerParallel(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
// used for storing the uploadID's parsed on concurrent HTTP requests for NewMultipart upload on the same object. // used for storing the uploadID's parsed on concurrent HTTP requests for NewMultipart upload on the same object.
testUploads := struct { testUploads := struct {
sync.Mutex sync.Mutex
@ -2092,7 +2093,7 @@ func TestAPICompleteMultipartHandler(t *testing.T) {
} }
func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
var err error var err error
// register event notifier. // register event notifier.
@ -2447,7 +2448,7 @@ func TestAPIAbortMultipartHandler(t *testing.T) {
} }
func testAPIAbortMultipartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIAbortMultipartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
var err error var err error
// register event notifier. // register event notifier.
@ -2616,7 +2617,7 @@ func TestAPIDeleteObjectHandler(t *testing.T) {
} }
func testAPIDeleteObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIDeleteObjectHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
// register event notifier. // register event notifier.
err := initEventNotifier(obj) err := initEventNotifier(obj)
@ -2783,7 +2784,7 @@ func TestAPIPutObjectPartHandlerPreSign(t *testing.T) {
} }
func testAPIPutObjectPartHandlerPreSign(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIPutObjectPartHandlerPreSign(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
testObject := "testobject" testObject := "testobject"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
req, err := newTestSignedRequestV4("POST", getNewMultipartURL("", bucketName, "testobject"), req, err := newTestSignedRequestV4("POST", getNewMultipartURL("", bucketName, "testobject"),
@ -2850,7 +2851,7 @@ func TestAPIPutObjectPartHandlerStreaming(t *testing.T) {
} }
func testAPIPutObjectPartHandlerStreaming(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIPutObjectPartHandlerStreaming(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
testObject := "testobject" testObject := "testobject"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
req, err := newTestSignedRequestV4("POST", getNewMultipartURL("", bucketName, "testobject"), req, err := newTestSignedRequestV4("POST", getNewMultipartURL("", bucketName, "testobject"),
@ -2938,7 +2939,7 @@ func TestAPIPutObjectPartHandler(t *testing.T) {
} }
func testAPIPutObjectPartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIPutObjectPartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
// Initiate Multipart upload for testing PutObjectPartHandler. // Initiate Multipart upload for testing PutObjectPartHandler.
testObject := "testobject" testObject := "testobject"
@ -3255,7 +3256,7 @@ func TestAPIListObjectPartsHandlerPreSign(t *testing.T) {
} }
func testAPIListObjectPartsHandlerPreSign(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIListObjectPartsHandlerPreSign(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
testObject := "testobject" testObject := "testobject"
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
req, err := newTestSignedRequestV4("POST", getNewMultipartURL("", bucketName, testObject), req, err := newTestSignedRequestV4("POST", getNewMultipartURL("", bucketName, testObject),
@ -3343,7 +3344,7 @@ func TestAPIListObjectPartsHandler(t *testing.T) {
} }
func testAPIListObjectPartsHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, func testAPIListObjectPartsHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler,
credentials credential, t *testing.T) { credentials auth.Credentials, t *testing.T) {
testObject := "testobject" testObject := "testobject"
// PutObjectPart API HTTP Handler has to be tested in isolation, // PutObjectPart API HTTP Handler has to be tested in isolation,

View File

@ -20,6 +20,8 @@ import (
"net/url" "net/url"
"strings" "strings"
"time" "time"
"github.com/minio/minio/pkg/auth"
) )
// credentialHeader data type represents structured form of Credential // credentialHeader data type represents structured form of Credential
@ -57,7 +59,7 @@ func parseCredentialHeader(credElement string) (ch credentialHeader, aec APIErro
if len(credElements) != 5 { if len(credElements) != 5 {
return ch, ErrCredMalformed return ch, ErrCredMalformed
} }
if !isAccessKeyValid(credElements[0]) { if !auth.IsAccessKeyValid(credElements[0]) {
return ch, ErrInvalidAccessKeyID return ch, ErrInvalidAccessKeyID
} }
// Save access key id. // Save access key id.

View File

@ -54,6 +54,7 @@ import (
router "github.com/gorilla/mux" router "github.com/gorilla/mux"
"github.com/minio/minio-go/pkg/policy" "github.com/minio/minio-go/pkg/policy"
"github.com/minio/minio-go/pkg/s3signer" "github.com/minio/minio-go/pkg/s3signer"
"github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/hash" "github.com/minio/minio/pkg/hash"
) )
@ -1962,7 +1963,7 @@ func ExecObjectLayerAPITest(t *testing.T, objAPITest objAPITestType, endpoints [
// function to be passed to ExecObjectLayerAPITest, for executing object layr API handler tests. // function to be passed to ExecObjectLayerAPITest, for executing object layr API handler tests.
type objAPITestType func(obj ObjectLayer, instanceType string, bucketName string, type objAPITestType func(obj ObjectLayer, instanceType string, bucketName string,
apiRouter http.Handler, credentials credential, t *testing.T) apiRouter http.Handler, credentials auth.Credentials, t *testing.T)
// Regular object test type. // Regular object test type.
type objTestType func(obj ObjectLayer, instanceType string, t TestErrHandler) type objTestType func(obj ObjectLayer, instanceType string, t TestErrHandler)

View File

@ -36,6 +36,7 @@ import (
"github.com/gorilla/rpc/v2/json2" "github.com/gorilla/rpc/v2/json2"
"github.com/minio/minio-go/pkg/policy" "github.com/minio/minio-go/pkg/policy"
"github.com/minio/minio/browser" "github.com/minio/minio/browser"
"github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/hash" "github.com/minio/minio/pkg/hash"
) )
@ -368,7 +369,7 @@ func (web webAPIHandlers) GenerateAuth(r *http.Request, args *WebGenericArgs, re
if !isHTTPRequestValid(r) { if !isHTTPRequestValid(r) {
return toJSONError(errAuthentication) return toJSONError(errAuthentication)
} }
cred := mustGetNewCredential() cred := auth.MustGetNewCredentials()
reply.AccessKey = cred.AccessKey reply.AccessKey = cred.AccessKey
reply.SecretKey = cred.SecretKey reply.SecretKey = cred.SecretKey
reply.UIVersion = browser.UIVersion reply.UIVersion = browser.UIVersion
@ -399,7 +400,7 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se
return toJSONError(errChangeCredNotAllowed) return toJSONError(errChangeCredNotAllowed)
} }
creds, err := createCredential(args.AccessKey, args.SecretKey) creds, err := auth.CreateCredentials(args.AccessKey, args.SecretKey)
if err != nil { if err != nil {
return toJSONError(err) return toJSONError(err)
} }
@ -1016,13 +1017,13 @@ func toWebAPIError(err error) APIError {
HTTPStatusCode: http.StatusServiceUnavailable, HTTPStatusCode: http.StatusServiceUnavailable,
Description: err.Error(), Description: err.Error(),
} }
} else if err == errInvalidAccessKeyLength { } else if err == auth.ErrInvalidAccessKeyLength {
return APIError{ return APIError{
Code: "AccessDenied", Code: "AccessDenied",
HTTPStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,
Description: err.Error(), Description: err.Error(),
} }
} else if err == errInvalidSecretKeyLength { } else if err == auth.ErrInvalidSecretKeyLength {
return APIError{ return APIError{
Code: "AccessDenied", Code: "AccessDenied",
HTTPStatusCode: http.StatusForbidden, HTTPStatusCode: http.StatusForbidden,

View File

@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package cmd package auth
import ( import (
"crypto/rand" "crypto/rand"
"crypto/subtle" "crypto/subtle"
"encoding/base64" "encoding/base64"
"errors" "fmt"
) )
const ( const (
@ -48,12 +48,12 @@ const (
// Common errors generated for access and secret key validation. // Common errors generated for access and secret key validation.
var ( var (
errInvalidAccessKeyLength = errors.New("Invalid access key, access key should be minimum 5 characters in length") ErrInvalidAccessKeyLength = fmt.Errorf("access key must be minimum %v or more characters long", accessKeyMinLen)
errInvalidSecretKeyLength = errors.New("Invalid secret key, secret key should be minimum 8 characters in length") ErrInvalidSecretKeyLength = fmt.Errorf("secret key must be minimum %v or more characters long", secretKeyMinLen)
) )
// isAccessKeyValid - validate access key for right length. // IsAccessKeyValid - validate access key for right length.
func isAccessKeyValid(accessKey string) bool { func IsAccessKeyValid(accessKey string) bool {
return len(accessKey) >= accessKeyMinLen return len(accessKey) >= accessKeyMinLen
} }
@ -62,67 +62,62 @@ func isSecretKeyValid(secretKey string) bool {
return len(secretKey) >= secretKeyMinLen return len(secretKey) >= secretKeyMinLen
} }
// credential container for access and secret keys. // Credentials holds access and secret keys.
type credential struct { type Credentials struct {
AccessKey string `json:"accessKey,omitempty"` AccessKey string `json:"accessKey,omitempty"`
SecretKey string `json:"secretKey,omitempty"` SecretKey string `json:"secretKey,omitempty"`
} }
// IsValid - returns whether credential is valid or not. // IsValid - returns whether credential is valid or not.
func (cred credential) IsValid() bool { func (cred Credentials) IsValid() bool {
return isAccessKeyValid(cred.AccessKey) && isSecretKeyValid(cred.SecretKey) return IsAccessKeyValid(cred.AccessKey) && isSecretKeyValid(cred.SecretKey)
} }
// Equals - returns whether two credentials are equal or not. // Equal - returns whether two credentials are equal or not.
func (cred credential) Equal(ccred credential) bool { func (cred Credentials) Equal(ccred Credentials) bool {
if !ccred.IsValid() { if !ccred.IsValid() {
return false return false
} }
return cred.AccessKey == ccred.AccessKey && subtle.ConstantTimeCompare([]byte(cred.SecretKey), []byte(ccred.SecretKey)) == 1 return cred.AccessKey == ccred.AccessKey && subtle.ConstantTimeCompare([]byte(cred.SecretKey), []byte(ccred.SecretKey)) == 1
} }
// createCredential returns new credentials from the given access key and secret key. // MustGetNewCredentials generates and returns new credential.
// It returns an error if the access key or secret key are too long or short. func MustGetNewCredentials() (cred Credentials) {
func createCredential(accessKey, secretKey string) (credential, error) { readBytes := func(size int) (data []byte) {
if !isAccessKeyValid(accessKey) { data = make([]byte, size)
return credential{}, errInvalidAccessKeyLength if n, err := rand.Read(data); err != nil {
panic(err)
} else if n != size {
panic(fmt.Errorf("not enough data read. expected: %v, got: %v", size, n))
} }
if !isSecretKeyValid(secretKey) { return
return credential{}, errInvalidSecretKeyLength
} }
return credential{
AccessKey: accessKey,
SecretKey: secretKey,
}, nil
}
// Initialize a new credential object // Generate access key.
func getNewCredential(accessKeyLen, secretKeyLen int) (cred credential, err error) { keyBytes := readBytes(accessKeyMaxLen)
keyBytes := make([]byte, accessKeyLen) for i := 0; i < accessKeyMaxLen; i++ {
_, err = rand.Read(keyBytes)
if err != nil {
return cred, err
}
for i := 0; i < accessKeyLen; i++ {
keyBytes[i] = alphaNumericTable[keyBytes[i]%alphaNumericTableLen] keyBytes[i] = alphaNumericTable[keyBytes[i]%alphaNumericTableLen]
} }
accessKey := string(keyBytes) cred.AccessKey = string(keyBytes)
// Generate secret key. // Generate secret key.
keyBytes = make([]byte, secretKeyLen) keyBytes = readBytes(secretKeyMaxLen)
_, err = rand.Read(keyBytes) cred.SecretKey = string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyMaxLen])
if err != nil {
return cred, err
}
secretKey := string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyLen])
cred, err = createCredential(accessKey, secretKey)
return cred, err
}
func mustGetNewCredential() credential {
// Generate Minio credentials with Minio key max lengths.
cred, err := getNewCredential(accessKeyMaxLen, secretKeyMaxLen)
fatalIf(err, "Unable to generate new credentials.")
return cred return cred
} }
// CreateCredentials returns new credential with the given access key and secret key.
// Error is returned if given access key or secret key are invalid length.
func CreateCredentials(accessKey, secretKey string) (cred Credentials, err error) {
if !IsAccessKeyValid(accessKey) {
return cred, ErrInvalidAccessKeyLength
}
if !isSecretKeyValid(secretKey) {
return cred, ErrInvalidSecretKeyLength
}
cred.AccessKey = accessKey
cred.SecretKey = secretKey
return cred, nil
}

View File

@ -0,0 +1,135 @@
/*
* Minio Cloud Storage, (C) 2017 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package auth
import "testing"
func TestIsAccessKeyValid(t *testing.T) {
testCases := []struct {
accessKey string
expectedResult bool
}{
{alphaNumericTable[:accessKeyMinLen], true},
{alphaNumericTable[:accessKeyMinLen+1], true},
{alphaNumericTable[:accessKeyMinLen-1], false},
}
for i, testCase := range testCases {
result := IsAccessKeyValid(testCase.accessKey)
if result != testCase.expectedResult {
t.Fatalf("test %v: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}
func TestIsSecretKeyValid(t *testing.T) {
testCases := []struct {
secretKey string
expectedResult bool
}{
{alphaNumericTable[:secretKeyMinLen], true},
{alphaNumericTable[:secretKeyMinLen+1], true},
{alphaNumericTable[:secretKeyMinLen-1], false},
}
for i, testCase := range testCases {
result := isSecretKeyValid(testCase.secretKey)
if result != testCase.expectedResult {
t.Fatalf("test %v: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}
func TestMustGetNewCredentials(t *testing.T) {
cred := MustGetNewCredentials()
if !cred.IsValid() {
t.Fatalf("Failed to get new valid credential")
}
if len(cred.AccessKey) != accessKeyMaxLen {
t.Fatalf("access key length: expected: %v, got: %v", secretKeyMaxLen, len(cred.AccessKey))
}
if len(cred.SecretKey) != secretKeyMaxLen {
t.Fatalf("secret key length: expected: %v, got: %v", secretKeyMaxLen, len(cred.SecretKey))
}
}
func TestCreateCredentials(t *testing.T) {
testCases := []struct {
accessKey string
secretKey string
valid bool
expectedErr error
}{
// Valid access and secret keys with minimum length.
{alphaNumericTable[:accessKeyMinLen], alphaNumericTable[:secretKeyMinLen], true, nil},
// Valid access and/or secret keys are longer than minimum length.
{alphaNumericTable[:accessKeyMinLen+1], alphaNumericTable[:secretKeyMinLen+1], true, nil},
// Smaller access key.
{alphaNumericTable[:accessKeyMinLen-1], alphaNumericTable[:secretKeyMinLen], false, ErrInvalidAccessKeyLength},
// Smaller secret key.
{alphaNumericTable[:accessKeyMinLen], alphaNumericTable[:secretKeyMinLen-1], false, ErrInvalidSecretKeyLength},
}
for i, testCase := range testCases {
cred, err := CreateCredentials(testCase.accessKey, testCase.secretKey)
if err != nil {
if testCase.expectedErr == nil {
t.Fatalf("test %v: error: expected = <nil>, got = %v", i+1, err)
}
if testCase.expectedErr.Error() != err.Error() {
t.Fatalf("test %v: error: expected = %v, got = %v", i+1, testCase.expectedErr, err)
}
} else {
if testCase.expectedErr != nil {
t.Fatalf("test %v: error: expected = %v, got = <nil>", i+1, testCase.expectedErr)
}
if !cred.IsValid() {
t.Fatalf("test %v: got invalid credentials", i+1)
}
}
}
}
func TestCredentialsEqual(t *testing.T) {
cred := MustGetNewCredentials()
testCases := []struct {
cred Credentials
ccred Credentials
expectedResult bool
}{
// Same Credentialss.
{cred, cred, true},
// Empty credentials to compare.
{cred, Credentials{}, false},
// Empty credentials.
{Credentials{}, cred, false},
// Two different credentialss
{cred, MustGetNewCredentials(), false},
// Access key is different in credentials to compare.
{cred, Credentials{AccessKey: "myuser", SecretKey: cred.SecretKey}, false},
// Secret key is different in credentials to compare.
{cred, Credentials{AccessKey: cred.AccessKey, SecretKey: "mypassword"}, false},
}
for i, testCase := range testCases {
result := testCase.cred.Equal(testCase.ccred)
if result != testCase.expectedResult {
t.Fatalf("test %v: expected: %v, got: %v", i+1, testCase.expectedResult, result)
}
}
}