| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  |  * MinIO Cloud Storage, (C) 2016-2020 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 ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	jwtgo "github.com/dgrijalva/jwt-go" | 
					
						
							|  |  |  | 	jwtreq "github.com/dgrijalva/jwt-go/request" | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	xjwt "github.com/minio/minio/cmd/jwt" | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	// Inter-node JWT token expiry is 15 minutes.
 | 
					
						
							|  |  |  | 	defaultInterNodeJWTExpiry = 15 * time.Minute | 
					
						
							| 
									
										
										
										
											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") | 
					
						
							| 
									
										
										
										
											2019-05-30 04:18:46 +08:00
										 |  |  | 	errIncorrectCreds       = errors.New("Current access key or secret key is incorrect") | 
					
						
							| 
									
										
										
										
											2020-05-18 14:38:52 +08:00
										 |  |  | 	errPresignedNotAllowed  = errors.New("Unable to generate shareable URL due to lack of read permissions") | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 09:44:58 +08:00
										 |  |  | func authenticateJWTUsers(accessKey, secretKey string, expiry time.Duration) (string, error) { | 
					
						
							|  |  |  | 	passedCredential, err := auth.CreateCredentials(accessKey, secretKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	expiresAt := UTCNow().Add(expiry) | 
					
						
							|  |  |  | 	return authenticateJWTUsersWithCredentials(passedCredential, expiresAt) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-17 09:44:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | func authenticateJWTUsersWithCredentials(credentials auth.Credentials, expiresAt time.Time) (string, error) { | 
					
						
							|  |  |  | 	serverCred := globalActiveCred | 
					
						
							|  |  |  | 	if serverCred.AccessKey != credentials.AccessKey { | 
					
						
							| 
									
										
										
										
											2018-10-17 09:44:58 +08:00
										 |  |  | 		var ok bool | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		serverCred, ok = globalIAMSys.GetUser(credentials.AccessKey) | 
					
						
							| 
									
										
										
										
											2018-10-17 09:44:58 +08:00
										 |  |  | 		if !ok { | 
					
						
							|  |  |  | 			return "", errInvalidAccessKeyID | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if !serverCred.Equal(credentials) { | 
					
						
							| 
									
										
										
										
											2018-10-17 09:44:58 +08:00
										 |  |  | 		return "", errAuthentication | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	claims := xjwt.NewMapClaims() | 
					
						
							|  |  |  | 	claims.SetExpiry(expiresAt) | 
					
						
							|  |  |  | 	claims.SetAccessKey(credentials.AccessKey) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	jwt := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims) | 
					
						
							| 
									
										
										
										
											2018-10-17 09:44:58 +08:00
										 |  |  | 	return jwt.SignedString([]byte(serverCred.SecretKey)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | func authenticateNode(accessKey, secretKey, audience string) (string, error) { | 
					
						
							|  |  |  | 	claims := xjwt.NewStandardClaims() | 
					
						
							|  |  |  | 	claims.SetExpiry(UTCNow().Add(defaultInterNodeJWTExpiry)) | 
					
						
							|  |  |  | 	claims.SetAccessKey(accessKey) | 
					
						
							|  |  |  | 	claims.SetAudience(audience) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	jwt := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims) | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	return jwt.SignedString([]byte(secretKey)) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func authenticateWeb(accessKey, secretKey string) (string, error) { | 
					
						
							| 
									
										
										
										
											2018-10-17 09:44:58 +08:00
										 |  |  | 	return authenticateJWTUsers(accessKey, secretKey, defaultJWTExpiry) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-25 03:46:37 +08:00
										 |  |  | func authenticateURL(accessKey, secretKey string) (string, error) { | 
					
						
							| 
									
										
										
										
											2018-10-17 09:44:58 +08:00
										 |  |  | 	return authenticateJWTUsers(accessKey, secretKey, defaultURLJWTExpiry) | 
					
						
							| 
									
										
										
										
											2017-07-25 03:46:37 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | // Callback function used for parsing
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | func webTokenCallback(claims *xjwt.MapClaims) ([]byte, error) { | 
					
						
							|  |  |  | 	if claims.AccessKey == globalActiveCred.AccessKey { | 
					
						
							|  |  |  | 		return []byte(globalActiveCred.SecretKey), nil | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	if globalIAMSys == nil { | 
					
						
							|  |  |  | 		return nil, errInvalidAccessKeyID | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	ok, err := globalIAMSys.IsTempUser(claims.AccessKey) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if err == errNoSuchUser { | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 			return nil, errInvalidAccessKeyID | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2017-10-18 13:44:27 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	if ok { | 
					
						
							|  |  |  | 		return []byte(globalActiveCred.SecretKey), nil | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	cred, ok := globalIAMSys.GetUser(claims.AccessKey) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return nil, errInvalidAccessKeyID | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	return []byte(cred.SecretKey), nil | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func isAuthTokenValid(token string) bool { | 
					
						
							|  |  |  | 	_, _, err := webTokenAuthenticate(token) | 
					
						
							|  |  |  | 	return err == nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | func webTokenAuthenticate(token string) (*xjwt.MapClaims, bool, error) { | 
					
						
							| 
									
										
										
										
											2018-10-10 05:00:01 +08:00
										 |  |  | 	if token == "" { | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 		return nil, false, errNoAuthToken | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	claims := xjwt.NewMapClaims() | 
					
						
							|  |  |  | 	if err := xjwt.ParseWithClaims(token, claims, webTokenCallback); err != nil { | 
					
						
							|  |  |  | 		return claims, false, errAuthentication | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	owner := claims.AccessKey == globalActiveCred.AccessKey | 
					
						
							|  |  |  | 	return claims, owner, nil | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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.
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | func webRequestAuthenticate(req *http.Request) (*xjwt.MapClaims, bool, error) { | 
					
						
							|  |  |  | 	token, err := jwtreq.AuthorizationHeaderExtractor.ExtractToken(req) | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-12 05:26:42 +08:00
										 |  |  | 		if err == jwtreq.ErrNoTokenInRequest { | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 			return nil, false, errNoAuthToken | 
					
						
							| 
									
										
										
										
											2017-01-12 05:26:42 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 		return nil, false, err | 
					
						
							| 
									
										
										
										
											2017-09-20 03:37:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	claims := xjwt.NewMapClaims() | 
					
						
							|  |  |  | 	if err := xjwt.ParseWithClaims(token, claims, webTokenCallback); err != nil { | 
					
						
							|  |  |  | 		return claims, false, errAuthentication | 
					
						
							| 
									
										
										
										
											2017-01-12 05:26:42 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	owner := claims.AccessKey == globalActiveCred.AccessKey | 
					
						
							|  |  |  | 	return claims, owner, nil | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | func newAuthToken(audience string) string { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	cred := globalActiveCred | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	token, err := authenticateNode(cred.AccessKey, cred.SecretKey, audience) | 
					
						
							| 
									
										
										
										
											2020-04-10 00:30:02 +08:00
										 |  |  | 	logger.CriticalIf(GlobalContext, err) | 
					
						
							| 
									
										
										
										
											2018-06-06 16:51:56 +08:00
										 |  |  | 	return token | 
					
						
							|  |  |  | } |