| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-24 23:41:04 +08:00
										 |  |  | 	jwtgo "github.com/golang-jwt/jwt" | 
					
						
							|  |  |  | 	jwtreq "github.com/golang-jwt/jwt/request" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/auth" | 
					
						
							|  |  |  | 	xjwt "github.com/minio/minio/internal/jwt" | 
					
						
							|  |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							| 
									
										
										
										
											2021-08-21 02:32:01 +08:00
										 |  |  | 	iampolicy "github.com/minio/pkg/iam/policy" | 
					
						
							| 
									
										
										
										
											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 ( | 
					
						
							| 
									
										
										
										
											2021-06-18 11:27:04 +08:00
										 |  |  | 	errInvalidAccessKeyID = errors.New("The access key ID you provided does not exist in our records") | 
					
						
							|  |  |  | 	errAuthentication     = errors.New("Authentication failed, check your access credentials") | 
					
						
							|  |  |  | 	errNoAuthToken        = errors.New("JWT token missing") | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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() | 
					
						
							| 
									
										
										
										
											2021-08-21 02:32:01 +08:00
										 |  |  | 	if err := xjwt.ParseWithClaims(token, claims, func(claims *xjwt.MapClaims) ([]byte, error) { | 
					
						
							|  |  |  | 		if claims.AccessKey == globalActiveCred.AccessKey { | 
					
						
							|  |  |  | 			return []byte(globalActiveCred.SecretKey), nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		cred, ok := globalIAMSys.GetUser(claims.AccessKey) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			return nil, errInvalidAccessKeyID | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return []byte(cred.SecretKey), nil | 
					
						
							|  |  |  | 	}); err != nil { | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 		return claims, false, errAuthentication | 
					
						
							| 
									
										
										
										
											2017-01-12 05:26:42 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-21 02:32:01 +08:00
										 |  |  | 	owner := true | 
					
						
							|  |  |  | 	if globalActiveCred.AccessKey != claims.AccessKey { | 
					
						
							|  |  |  | 		// Check if the access key is part of users credentials.
 | 
					
						
							|  |  |  | 		ucred, ok := globalIAMSys.GetUser(claims.AccessKey) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			return nil, false, errInvalidAccessKeyID | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// get embedded claims
 | 
					
						
							|  |  |  | 		eclaims, s3Err := checkClaimsFromToken(req, ucred) | 
					
						
							|  |  |  | 		if s3Err != ErrNone { | 
					
						
							|  |  |  | 			return nil, false, errAuthentication | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for k, v := range eclaims { | 
					
						
							|  |  |  | 			claims.MapClaims[k] = v | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Now check if we have a sessionPolicy.
 | 
					
						
							|  |  |  | 		if _, ok = eclaims[iampolicy.SessionPolicyName]; ok { | 
					
						
							|  |  |  | 			owner = false | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			owner = globalActiveCred.AccessKey == ucred.ParentUser | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:59:22 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | } |