minio/cmd/rpc-common.go
Harshavardhana 861550446a
Allow upto 15 minutes of timeskew for RPC calls as well (#5774)
Default installations of cloned VMs on VMware like env
might experience serious problems with time skewing,
allow for a higher value instead of 3 seconds we are
moving to 15 minutes just like API level skew.

Access to internet and configuring ntp might not be possible,
in such situations providing atleast a 15 minute skew could
cater for majority of situations.
2018-04-05 23:55:31 -07:00

158 lines
4.3 KiB
Go

/*
* Minio Cloud Storage, (C) 2016, 2017, 2018 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 (
"strconv"
"time"
"github.com/minio/dsync"
)
// Allow any RPC call request time should be no more/less than 15 minutes.
// 15 minute is chosen to be best for majority use cases.
const rpcSkewTimeAllowed = 15 * time.Minute
// RPC V1 - Initial version
// RPC V2 - format.json XL version changed to 2
// RPC V3 - format.json XL version changed to 3
// Current RPC version
var globalRPCAPIVersion = semVersion{3, 0, 0}
func isRequestTimeAllowed(requestTime time.Time) bool {
// Check whether request time is within acceptable skew time.
utcNow := UTCNow()
return !(requestTime.Sub(utcNow) > rpcSkewTimeAllowed ||
utcNow.Sub(requestTime) > rpcSkewTimeAllowed)
}
// semVersion - RPC semantic versioning.
type semVersion struct {
Major uint64
Minor uint64
Patch uint64
}
// semver comparator implementation based on the semver 2.0.0 https://semver.org/.
func (v semVersion) Compare(o semVersion) int {
if v.Major != o.Major {
if v.Major > o.Major {
return 1
}
return -1
}
if v.Minor != o.Minor {
if v.Minor > o.Minor {
return 1
}
return -1
}
if v.Patch != o.Patch {
if v.Patch > o.Patch {
return 1
}
return -1
}
return 0
}
func (v semVersion) String() string {
b := make([]byte, 0, 5)
b = strconv.AppendUint(b, v.Major, 10)
b = append(b, '.')
b = strconv.AppendUint(b, v.Minor, 10)
b = append(b, '.')
b = strconv.AppendUint(b, v.Patch, 10)
return string(b)
}
// AuthRPCArgs represents minimum required arguments to make any authenticated RPC call.
type AuthRPCArgs struct {
// Authentication token to be verified by the server for every RPC call.
AuthToken string
Version semVersion
}
// SetAuthToken - sets the token to the supplied value.
func (args *AuthRPCArgs) SetAuthToken(authToken string) {
args.AuthToken = authToken
}
// SetRPCAPIVersion - sets the rpc version to the supplied value.
func (args *AuthRPCArgs) SetRPCAPIVersion(version semVersion) {
args.Version = version
}
// IsAuthenticated - validated whether this auth RPC args are already authenticated or not.
func (args AuthRPCArgs) IsAuthenticated() error {
// checks if rpc Version is not equal to current server rpc version.
// this is fine for now, but in future when we add backward compatible
// APIs we need to make sure to allow lesser versioned clients to
// talk over RPC, until then we are fine with this check.
if args.Version.Compare(globalRPCAPIVersion) != 0 {
return errRPCAPIVersionUnsupported
}
// Check whether the token is valid
if !isAuthTokenValid(args.AuthToken) {
return errInvalidToken
}
// Good to go.
return nil
}
// AuthRPCReply represents minimum required reply for any authenticated RPC call.
type AuthRPCReply struct{}
// LoginRPCArgs - login username and password for RPC.
type LoginRPCArgs struct {
AuthToken string
Version semVersion
RequestTime time.Time
}
// IsValid - validates whether this LoginRPCArgs are valid for authentication.
func (args LoginRPCArgs) IsValid() error {
// checks if rpc Version is not equal to current server rpc version.
// this is fine for now, but in future when we add backward compatible
// APIs we need to make sure to allow lesser versioned clients to
// talk over RPC, until then we are fine with this check.
if args.Version.Compare(globalRPCAPIVersion) != 0 {
return errRPCAPIVersionUnsupported
}
if !isRequestTimeAllowed(args.RequestTime) {
return errServerTimeMismatch
}
return nil
}
// LoginRPCReply - login reply is a dummy struct perhaps for future use.
type LoginRPCReply struct{}
// LockArgs represents arguments for any authenticated lock RPC call.
type LockArgs struct {
AuthRPCArgs
LockArgs dsync.LockArgs
}
func newLockArgs(args dsync.LockArgs) LockArgs {
return LockArgs{LockArgs: args}
}