| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2016-11-08 03:43:35 +08:00
										 |  |  |  * Minio Cloud Storage, (C) 2016 Minio, Inc. | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +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 ( | 
					
						
							|  |  |  | 	"path" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-08 03:43:35 +08:00
										 |  |  | // Login handler implements JWT login token generator, which upon login request
 | 
					
						
							|  |  |  | // along with username and password is generated.
 | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | func (br *browserPeerAPIHandlers) Login(args *LoginRPCArgs, reply *LoginRPCReply) error { | 
					
						
							|  |  |  | 	// Validate LoginRPCArgs
 | 
					
						
							|  |  |  | 	if err := args.IsValid(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Authenticate using JWT.
 | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 	token, err := authenticateWeb(args.Username, args.Password) | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 	// Return the token.
 | 
					
						
							|  |  |  | 	reply.AuthToken = token | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetAuthPeerArgs - Arguments collection for SetAuth RPC call
 | 
					
						
							|  |  |  | type SetAuthPeerArgs struct { | 
					
						
							|  |  |  | 	// For Auth
 | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 	AuthRPCArgs | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// New credentials that receiving peer should update to.
 | 
					
						
							|  |  |  | 	Creds credential | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetAuthPeer - Update to new credentials sent from a peer Minio
 | 
					
						
							|  |  |  | // server. Since credentials are already validated on the sending
 | 
					
						
							|  |  |  | // peer, here we just persist to file and update in-memory config. All
 | 
					
						
							| 
									
										
										
										
											2016-12-28 00:28:10 +08:00
										 |  |  | // subsequently running isAuthTokenValid() calls will fail, and clients
 | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | // will be forced to re-establish connections. Connections will be
 | 
					
						
							|  |  |  | // re-established only when the sending client has also updated its
 | 
					
						
							|  |  |  | // credentials.
 | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | func (br *browserPeerAPIHandlers) SetAuthPeer(args SetAuthPeerArgs, reply *AuthRPCReply) error { | 
					
						
							|  |  |  | 	if err := args.IsAuthenticated(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | 	if err := validateAuthKeys(args.Creds.AccessKey, args.Creds.SecretKey); err != nil { | 
					
						
							| 
									
										
										
										
											2017-01-27 08:51:51 +08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 	// Update credentials in memory
 | 
					
						
							| 
									
										
										
										
											2017-02-08 04:51:43 +08:00
										 |  |  | 	serverConfig.SetCredential(args.Creds) | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Save credentials to config file
 | 
					
						
							|  |  |  | 	if err := serverConfig.Save(); err != nil { | 
					
						
							|  |  |  | 		errorIf(err, "Error updating config file with new credentials sent from browser RPC.") | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Sends SetAuthPeer RPCs to all peers in the Minio cluster
 | 
					
						
							|  |  |  | func updateCredsOnPeers(creds credential) map[string]error { | 
					
						
							| 
									
										
										
										
											2016-11-08 04:09:24 +08:00
										 |  |  | 	// Get list of peer addresses (from globalS3Peers)
 | 
					
						
							|  |  |  | 	peers := []string{} | 
					
						
							|  |  |  | 	for _, p := range globalS3Peers { | 
					
						
							|  |  |  | 		peers = append(peers, p.addr) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Array of errors for each peer
 | 
					
						
							|  |  |  | 	errs := make([]error, len(peers)) | 
					
						
							|  |  |  | 	var wg sync.WaitGroup | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 	serverCred := serverConfig.GetCredential() | 
					
						
							| 
									
										
										
										
											2016-11-08 03:43:35 +08:00
										 |  |  | 	// Launch go routines to send request to each peer in parallel.
 | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 	for ix := range peers { | 
					
						
							|  |  |  | 		wg.Add(1) | 
					
						
							|  |  |  | 		go func(ix int) { | 
					
						
							|  |  |  | 			defer wg.Done() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Exclude self to avoid race with
 | 
					
						
							|  |  |  | 			// invalidating the RPC token.
 | 
					
						
							|  |  |  | 			if peers[ix] == globalMinioAddr { | 
					
						
							|  |  |  | 				errs[ix] = nil | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Initialize client
 | 
					
						
							| 
									
										
										
										
											2016-12-23 23:12:19 +08:00
										 |  |  | 			client := newAuthRPCClient(authConfig{ | 
					
						
							|  |  |  | 				accessKey:       serverCred.AccessKey, | 
					
						
							|  |  |  | 				secretKey:       serverCred.SecretKey, | 
					
						
							|  |  |  | 				serverAddr:      peers[ix], | 
					
						
							| 
									
										
										
										
											2017-01-12 05:59:51 +08:00
										 |  |  | 				secureConn:      globalIsSSL, | 
					
						
							| 
									
										
										
										
											2017-02-17 06:52:14 +08:00
										 |  |  | 				serviceEndpoint: path.Join(minioReservedBucketPath, browserPeerPath), | 
					
						
							| 
									
										
										
										
											2017-01-15 06:06:23 +08:00
										 |  |  | 				serviceName:     "BrowserPeer", | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Construct RPC call arguments.
 | 
					
						
							|  |  |  | 			args := SetAuthPeerArgs{Creds: creds} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Make RPC call - we only care about error
 | 
					
						
							|  |  |  | 			// response and not the reply.
 | 
					
						
							| 
									
										
										
										
											2017-01-15 06:06:23 +08:00
										 |  |  | 			err := client.Call("BrowserPeer.SetAuthPeer", &args, &AuthRPCReply{}) | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-08 03:43:35 +08:00
										 |  |  | 			// We try a bit hard (3 attempts with 1 second delay)
 | 
					
						
							|  |  |  | 			// to set creds on peers in case of failure.
 | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				for i := 0; i < 2; i++ { | 
					
						
							| 
									
										
										
										
											2016-11-08 03:43:35 +08:00
										 |  |  | 					time.Sleep(1 * time.Second) // 1 second delay.
 | 
					
						
							| 
									
										
										
										
											2017-01-15 06:06:23 +08:00
										 |  |  | 					err = client.Call("BrowserPeer.SetAuthPeer", &args, &AuthRPCReply{}) | 
					
						
							| 
									
										
										
										
											2016-10-18 11:18:08 +08:00
										 |  |  | 					if err == nil { | 
					
						
							|  |  |  | 						break | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Send result down the channel
 | 
					
						
							|  |  |  | 			errs[ix] = err | 
					
						
							|  |  |  | 		}(ix) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Wait for requests to complete.
 | 
					
						
							|  |  |  | 	wg.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Put errors into map.
 | 
					
						
							|  |  |  | 	errsMap := make(map[string]error) | 
					
						
							|  |  |  | 	for i, err := range errs { | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errsMap[peers[i]] = err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return errsMap | 
					
						
							|  |  |  | } |