| 
									
										
										
										
											2016-12-27 02:21:23 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  |  * Minio Cloud Storage, (C) 2015, 2016, 2017 Minio, Inc. | 
					
						
							| 
									
										
										
										
											2016-12-27 02:21:23 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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 ( | 
					
						
							|  |  |  | 	"crypto/rand" | 
					
						
							|  |  |  | 	"encoding/base64" | 
					
						
							| 
									
										
										
										
											2017-03-16 07:30:34 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 	"golang.org/x/crypto/bcrypt" | 
					
						
							| 
									
										
										
										
											2016-12-27 02:21:23 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | 	accessKeyMinLen       = 5 | 
					
						
							|  |  |  | 	accessKeyMaxLen       = 20 | 
					
						
							|  |  |  | 	secretKeyMinLen       = 8 | 
					
						
							|  |  |  | 	secretKeyMaxLenAmazon = 40 | 
					
						
							|  |  |  | 	alphaNumericTable     = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" | 
					
						
							|  |  |  | 	alphaNumericTableLen  = byte(len(alphaNumericTable)) | 
					
						
							| 
									
										
										
										
											2016-12-27 02:21:23 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	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") | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2017-03-17 03:21:58 +08:00
										 |  |  | var secretKeyMaxLen = secretKeyMaxLenAmazon | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-27 02:21:23 +08:00
										 |  |  | // isAccessKeyValid - validate access key for right length.
 | 
					
						
							|  |  |  | func isAccessKeyValid(accessKey string) bool { | 
					
						
							|  |  |  | 	return len(accessKey) >= accessKeyMinLen && len(accessKey) <= accessKeyMaxLen | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // isSecretKeyValid - validate secret key for right length.
 | 
					
						
							|  |  |  | func isSecretKeyValid(secretKey string) bool { | 
					
						
							|  |  |  | 	return len(secretKey) >= secretKeyMinLen && len(secretKey) <= secretKeyMaxLen | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // credential container for access and secret keys.
 | 
					
						
							|  |  |  | type credential struct { | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 	AccessKey     string `json:"accessKey,omitempty"` | 
					
						
							|  |  |  | 	SecretKey     string `json:"secretKey,omitempty"` | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | 	secretKeyHash []byte | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | // IsValid - returns whether credential is valid or not.
 | 
					
						
							|  |  |  | func (cred credential) IsValid() bool { | 
					
						
							|  |  |  | 	return isAccessKeyValid(cred.AccessKey) && isSecretKeyValid(cred.SecretKey) | 
					
						
							| 
									
										
										
										
											2017-03-16 07:30:34 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | // Equals - returns whether two credentials are equal or not.
 | 
					
						
							|  |  |  | func (cred credential) Equal(ccred credential) bool { | 
					
						
							|  |  |  | 	if !ccred.IsValid() { | 
					
						
							|  |  |  | 		return false | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-27 02:21:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	if cred.secretKeyHash == nil { | 
					
						
							|  |  |  | 		secretKeyHash, err := bcrypt.GenerateFromPassword([]byte(cred.SecretKey), bcrypt.DefaultCost) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errorIf(err, "Unable to generate hash of given password") | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cred.secretKeyHash = secretKeyHash | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	return (cred.AccessKey == ccred.AccessKey && | 
					
						
							|  |  |  | 		bcrypt.CompareHashAndPassword(cred.secretKeyHash, []byte(ccred.SecretKey)) == nil) | 
					
						
							| 
									
										
										
										
											2016-12-27 02:21:23 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | func createCredential(accessKey, secretKey string) (cred credential, err error) { | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	if !isAccessKeyValid(accessKey) { | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 		err = errInvalidAccessKeyLength | 
					
						
							|  |  |  | 	} else if !isSecretKeyValid(secretKey) { | 
					
						
							|  |  |  | 		err = errInvalidSecretKeyLength | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		var secretKeyHash []byte | 
					
						
							|  |  |  | 		secretKeyHash, err = bcrypt.GenerateFromPassword([]byte(secretKey), bcrypt.DefaultCost) | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			cred.AccessKey = accessKey | 
					
						
							|  |  |  | 			cred.SecretKey = secretKey | 
					
						
							|  |  |  | 			cred.secretKeyHash = secretKeyHash | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	return cred, err | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | // Initialize a new credential object
 | 
					
						
							|  |  |  | func mustGetNewCredential() credential { | 
					
						
							|  |  |  | 	// Generate access key.
 | 
					
						
							|  |  |  | 	keyBytes := make([]byte, accessKeyMaxLen) | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	_, err := rand.Read(keyBytes) | 
					
						
							|  |  |  | 	fatalIf(err, "Unable to generate access key.") | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	for i := 0; i < accessKeyMaxLen; i++ { | 
					
						
							|  |  |  | 		keyBytes[i] = alphaNumericTable[keyBytes[i]%alphaNumericTableLen] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	accessKey := string(keyBytes) | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	// Generate secret key.
 | 
					
						
							|  |  |  | 	keyBytes = make([]byte, secretKeyMaxLen) | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	_, err = rand.Read(keyBytes) | 
					
						
							|  |  |  | 	fatalIf(err, "Unable to generate secret key.") | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	secretKey := string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyMaxLen]) | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	cred, err := createCredential(accessKey, secretKey) | 
					
						
							| 
									
										
										
										
											2017-03-24 07:36:00 +08:00
										 |  |  | 	fatalIf(err, "Unable to generate new credential.") | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	return cred | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | } |