/* * 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} }