| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  |  * Minio Cloud Storage, (C) 2016, 2017 Minio, Inc. | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +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 ( | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	jwtgo "github.com/dgrijalva/jwt-go" | 
					
						
							|  |  |  | 	jwtreq "github.com/dgrijalva/jwt-go/request" | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 	"github.com/minio/minio/cmd/logger" | 
					
						
							| 
									
										
										
										
											2017-11-01 02:54:32 +08:00
										 |  |  | 	"github.com/minio/minio/pkg/auth" | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	jwtAlgorithm = "Bearer" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Default JWT token for web handlers is one day.
 | 
					
						
							|  |  |  | 	defaultJWTExpiry = 24 * time.Hour | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Inter-node JWT token expiry is 100 years approx.
 | 
					
						
							|  |  |  | 	defaultInterNodeJWTExpiry = 100 * 365 * 24 * time.Hour | 
					
						
							| 
									
										
										
										
											2017-07-25 03:46:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// URL JWT token expiry is one minute (might be exposed).
 | 
					
						
							|  |  |  | 	defaultURLJWTExpiry = time.Minute | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	errInvalidAccessKeyID   = errors.New("The access key ID you provided does not exist in our records") | 
					
						
							|  |  |  | 	errChangeCredNotAllowed = errors.New("Changing access key and secret key not allowed") | 
					
						
							|  |  |  | 	errAuthentication       = errors.New("Authentication failed, check your access credentials") | 
					
						
							|  |  |  | 	errNoAuthToken          = errors.New("JWT token missing") | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func authenticateJWT(accessKey, secretKey string, expiry time.Duration) (string, error) { | 
					
						
							| 
									
										
										
										
											2017-11-01 02:54:32 +08:00
										 |  |  | 	passedCredential, err := auth.CreateCredentials(accessKey, secretKey) | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", err | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-30 05:12:47 +08:00
										 |  |  | 	serverCred := globalServerConfig.GetCredential() | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	if serverCred.AccessKey != passedCredential.AccessKey { | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 		return "", errInvalidAccessKeyID | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 15:16:06 +08:00
										 |  |  | 	if !serverCred.Equal(passedCredential) { | 
					
						
							|  |  |  | 		return "", errAuthentication | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 02:34:00 +08:00
										 |  |  | 	jwt := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, jwtgo.StandardClaims{ | 
					
						
							|  |  |  | 		ExpiresAt: UTCNow().Add(expiry).Unix(), | 
					
						
							| 
									
										
										
										
											2017-09-20 03:37:56 +08:00
										 |  |  | 		Subject:   accessKey, | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2018-01-11 02:34:00 +08:00
										 |  |  | 	return jwt.SignedString([]byte(serverCred.SecretKey)) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func authenticateNode(accessKey, secretKey string) (string, error) { | 
					
						
							|  |  |  | 	return authenticateJWT(accessKey, secretKey, defaultInterNodeJWTExpiry) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func authenticateWeb(accessKey, secretKey string) (string, error) { | 
					
						
							|  |  |  | 	return authenticateJWT(accessKey, secretKey, defaultJWTExpiry) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-25 03:46:37 +08:00
										 |  |  | func authenticateURL(accessKey, secretKey string) (string, error) { | 
					
						
							|  |  |  | 	return authenticateJWT(accessKey, secretKey, defaultURLJWTExpiry) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | func keyFuncCallback(jwtToken *jwtgo.Token) (interface{}, error) { | 
					
						
							|  |  |  | 	if _, ok := jwtToken.Method.(*jwtgo.SigningMethodHMAC); !ok { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("Unexpected signing method: %v", jwtToken.Header["alg"]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-30 05:12:47 +08:00
										 |  |  | 	return []byte(globalServerConfig.GetCredential().SecretKey), nil | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func isAuthTokenValid(tokenString string) bool { | 
					
						
							| 
									
										
										
										
											2017-10-18 13:44:27 +08:00
										 |  |  | 	if tokenString == "" { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-20 03:37:56 +08:00
										 |  |  | 	var claims jwtgo.StandardClaims | 
					
						
							|  |  |  | 	jwtToken, err := jwtgo.ParseWithClaims(tokenString, &claims, keyFuncCallback) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 		logger.LogIf(context.Background(), err) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-20 03:37:56 +08:00
										 |  |  | 	if err = claims.Valid(); err != nil { | 
					
						
							| 
									
										
										
										
											2018-04-06 06:04:40 +08:00
										 |  |  | 		logger.LogIf(context.Background(), err) | 
					
						
							| 
									
										
										
										
											2017-09-20 03:37:56 +08:00
										 |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-30 05:12:47 +08:00
										 |  |  | 	return jwtToken.Valid && claims.Subject == globalServerConfig.GetCredential().AccessKey | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func isHTTPRequestValid(req *http.Request) bool { | 
					
						
							| 
									
										
										
										
											2017-02-03 02:45:00 +08:00
										 |  |  | 	return webRequestAuthenticate(req) == nil | 
					
						
							| 
									
										
										
										
											2017-01-12 05:26:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Check if the request is authenticated.
 | 
					
						
							|  |  |  | // Returns nil if the request is authenticated. errNoAuthToken if token missing.
 | 
					
						
							|  |  |  | // Returns errAuthentication for all other errors.
 | 
					
						
							| 
									
										
										
										
											2017-02-03 02:45:00 +08:00
										 |  |  | func webRequestAuthenticate(req *http.Request) error { | 
					
						
							| 
									
										
										
										
											2017-09-20 03:37:56 +08:00
										 |  |  | 	var claims jwtgo.StandardClaims | 
					
						
							|  |  |  | 	jwtToken, err := jwtreq.ParseFromRequestWithClaims(req, jwtreq.AuthorizationHeaderExtractor, &claims, keyFuncCallback) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-12 05:26:42 +08:00
										 |  |  | 		if err == jwtreq.ErrNoTokenInRequest { | 
					
						
							|  |  |  | 			return errNoAuthToken | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return errAuthentication | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-20 03:37:56 +08:00
										 |  |  | 	if err = claims.Valid(); err != nil { | 
					
						
							| 
									
										
										
										
											2018-01-11 02:34:00 +08:00
										 |  |  | 		return errAuthentication | 
					
						
							| 
									
										
										
										
											2017-09-20 03:37:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-30 05:12:47 +08:00
										 |  |  | 	if claims.Subject != globalServerConfig.GetCredential().AccessKey { | 
					
						
							| 
									
										
										
										
											2017-09-20 03:37:56 +08:00
										 |  |  | 		return errInvalidAccessKeyID | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-12 05:26:42 +08:00
										 |  |  | 	if !jwtToken.Valid { | 
					
						
							|  |  |  | 		return errAuthentication | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func newAuthToken() string { | 
					
						
							|  |  |  | 	cred := globalServerConfig.GetCredential() | 
					
						
							|  |  |  | 	token, err := authenticateNode(cred.AccessKey, cred.SecretKey) | 
					
						
							|  |  |  | 	logger.CriticalIf(context.Background(), err) | 
					
						
							|  |  |  | 	return token | 
					
						
							|  |  |  | } |