|
|
/* * Minio Cloud Storage, (C) 2016 Minio, Inc. * * 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" )
// Login handler implements JWT login token generator, which upon login request
// along with username and password is generated.
func (br *browserPeerAPIHandlers) LoginHandler(args *RPCLoginArgs, reply *RPCLoginReply) error { jwt, err := newJWT(defaultInterNodeJWTExpiry) if err != nil { return err } if err = jwt.Authenticate(args.Username, args.Password); err != nil { return err } token, err := jwt.GenerateToken(args.Username) if err != nil { return err } reply.Token = token reply.ServerVersion = Version reply.Timestamp = time.Now().UTC() return nil }
// SetAuthPeerArgs - Arguments collection for SetAuth RPC call
type SetAuthPeerArgs struct { // For Auth
GenericArgs
// 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
// subsequently running isRPCTokenValid() calls will fail, and clients
// will be forced to re-establish connections. Connections will be
// re-established only when the sending client has also updated its
// credentials.
func (br *browserPeerAPIHandlers) SetAuthPeer(args SetAuthPeerArgs, reply *GenericReply) error { // Check auth
if !isRPCTokenValid(args.Token) { return errInvalidToken }
// Update credentials in memory
serverConfig.SetCredential(args.Creds)
// 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 { // Get list of peer addresses (from globalS3Peers)
peers := []string{} for _, p := range globalS3Peers { peers = append(peers, p.addr) }
// Array of errors for each peer
errs := make([]error, len(peers)) var wg sync.WaitGroup
// Launch go routines to send request to each peer in parallel.
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
client := newAuthClient(&authConfig{ accessKey: serverConfig.GetCredential().AccessKeyID, secretKey: serverConfig.GetCredential().SecretAccessKey, address: peers[ix], secureConn: isSSL(), path: path.Join(reservedBucket, browserPeerPath), loginMethod: "Browser.LoginHandler", })
// Construct RPC call arguments.
args := SetAuthPeerArgs{Creds: creds}
// Make RPC call - we only care about error
// response and not the reply.
err := client.Call("Browser.SetAuthPeer", &args, &GenericReply{})
// We try a bit hard (3 attempts with 1 second delay)
// to set creds on peers in case of failure.
if err != nil { for i := 0; i < 2; i++ { time.Sleep(1 * time.Second) // 1 second delay.
err = client.Call("Browser.SetAuthPeer", &args, &GenericReply{}) 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 }
|