* Rename GenericArgs to AuthRPCArgs * Rename GenericReply to AuthRPCReply * Remove authConfig.loginMethod and add authConfig.ServiceName * Rename loginServer to AuthRPCServer * Rename RPCLoginArgs to LoginRPCArgs * Rename RPCLoginReply to LoginRPCReply * Version and RequestTime are added to LoginRPCArgs and verified by server side, not client side. * Fix data race in lockMaintainence loop.master
parent
cde6496172
commit
6d10f4c19a
@ -0,0 +1,117 @@ |
||||
/* |
||||
* 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 ( |
||||
"testing" |
||||
"time" |
||||
) |
||||
|
||||
func TestLogin(t *testing.T) { |
||||
rootPath, err := newTestConfig("us-east-1") |
||||
if err != nil { |
||||
t.Fatalf("Failed to create test config - %v", err) |
||||
} |
||||
defer removeAll(rootPath) |
||||
creds := serverConfig.GetCredential() |
||||
ls := AuthRPCServer{} |
||||
testCases := []struct { |
||||
args LoginRPCArgs |
||||
skewTime time.Duration |
||||
expectedErr error |
||||
}{ |
||||
// Valid case.
|
||||
{ |
||||
args: LoginRPCArgs{ |
||||
Username: creds.AccessKey, |
||||
Password: creds.SecretKey, |
||||
Version: Version, |
||||
}, |
||||
skewTime: 0, |
||||
expectedErr: nil, |
||||
}, |
||||
// Valid username, password and request time, not version.
|
||||
{ |
||||
args: LoginRPCArgs{ |
||||
Username: creds.AccessKey, |
||||
Password: creds.SecretKey, |
||||
Version: "INVALID-" + Version, |
||||
}, |
||||
skewTime: 0, |
||||
expectedErr: errServerVersionMismatch, |
||||
}, |
||||
// Valid username, password and version, not request time
|
||||
{ |
||||
args: LoginRPCArgs{ |
||||
Username: creds.AccessKey, |
||||
Password: creds.SecretKey, |
||||
Version: Version, |
||||
}, |
||||
skewTime: 20 * time.Minute, |
||||
expectedErr: errServerTimeMismatch, |
||||
}, |
||||
// Invalid username length
|
||||
{ |
||||
args: LoginRPCArgs{ |
||||
Username: "aaa", |
||||
Password: "minio123", |
||||
Version: Version, |
||||
}, |
||||
skewTime: 0, |
||||
expectedErr: errInvalidAccessKeyLength, |
||||
}, |
||||
// Invalid password length
|
||||
{ |
||||
args: LoginRPCArgs{ |
||||
Username: "minio", |
||||
Password: "aaa", |
||||
Version: Version, |
||||
}, |
||||
skewTime: 0, |
||||
expectedErr: errInvalidSecretKeyLength, |
||||
}, |
||||
// Invalid username
|
||||
{ |
||||
args: LoginRPCArgs{ |
||||
Username: "aaaaa", |
||||
Password: creds.SecretKey, |
||||
Version: Version, |
||||
}, |
||||
skewTime: 0, |
||||
expectedErr: errInvalidAccessKeyID, |
||||
}, |
||||
// Invalid password
|
||||
{ |
||||
args: LoginRPCArgs{ |
||||
Username: creds.AccessKey, |
||||
Password: "aaaaaaaa", |
||||
Version: Version, |
||||
}, |
||||
skewTime: 0, |
||||
expectedErr: errAuthentication, |
||||
}, |
||||
} |
||||
for i, test := range testCases { |
||||
reply := LoginRPCReply{} |
||||
test.args.RequestTime = time.Now().Add(test.skewTime).UTC() |
||||
err := ls.Login(&test.args, &reply) |
||||
if err != test.expectedErr { |
||||
t.Errorf("Test %d: Expected error %v but received %v", |
||||
i+1, test.expectedErr, err) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,71 @@ |
||||
/* |
||||
* 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 "github.com/minio/dsync" |
||||
|
||||
// LockRPCClient is authenticable lock RPC client compatible to dsync.NetLocker
|
||||
type LockRPCClient struct { |
||||
*AuthRPCClient |
||||
} |
||||
|
||||
// newLockRPCClient returns new lock RPC client object.
|
||||
func newLockRPCClient(config authConfig) *LockRPCClient { |
||||
return &LockRPCClient{newAuthRPCClient(config)} |
||||
} |
||||
|
||||
// RLock calls read lock RPC.
|
||||
func (lockRPCClient *LockRPCClient) RLock(args dsync.LockArgs) (reply bool, err error) { |
||||
lockArgs := newLockArgs(args) |
||||
err = lockRPCClient.AuthRPCClient.Call("Dsync.RLock", &lockArgs, &reply) |
||||
return reply, err |
||||
} |
||||
|
||||
// Lock calls write lock RPC.
|
||||
func (lockRPCClient *LockRPCClient) Lock(args dsync.LockArgs) (reply bool, err error) { |
||||
lockArgs := newLockArgs(args) |
||||
err = lockRPCClient.AuthRPCClient.Call("Dsync.Lock", &lockArgs, &reply) |
||||
return reply, err |
||||
} |
||||
|
||||
// RUnlock calls read unlock RPC.
|
||||
func (lockRPCClient *LockRPCClient) RUnlock(args dsync.LockArgs) (reply bool, err error) { |
||||
lockArgs := newLockArgs(args) |
||||
err = lockRPCClient.AuthRPCClient.Call("Dsync.RUnlock", &lockArgs, &reply) |
||||
return reply, err |
||||
} |
||||
|
||||
// Unlock calls write unlock RPC.
|
||||
func (lockRPCClient *LockRPCClient) Unlock(args dsync.LockArgs) (reply bool, err error) { |
||||
lockArgs := newLockArgs(args) |
||||
err = lockRPCClient.AuthRPCClient.Call("Dsync.Unlock", &lockArgs, &reply) |
||||
return reply, err |
||||
} |
||||
|
||||
// ForceUnlock calls force unlock RPC.
|
||||
func (lockRPCClient *LockRPCClient) ForceUnlock(args dsync.LockArgs) (reply bool, err error) { |
||||
lockArgs := newLockArgs(args) |
||||
err = lockRPCClient.AuthRPCClient.Call("Dsync.ForceUnlock", &lockArgs, &reply) |
||||
return reply, err |
||||
} |
||||
|
||||
// Expired calls expired RPC.
|
||||
func (lockRPCClient *LockRPCClient) Expired(args dsync.LockArgs) (reply bool, err error) { |
||||
lockArgs := newLockArgs(args) |
||||
err = lockRPCClient.AuthRPCClient.Call("Dsync.Expired", &lockArgs, &reply) |
||||
return reply, err |
||||
} |
@ -1,67 +0,0 @@ |
||||
/* |
||||
* 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 "testing" |
||||
|
||||
func TestLoginHandler(t *testing.T) { |
||||
rootPath, err := newTestConfig("us-east-1") |
||||
if err != nil { |
||||
t.Fatalf("Failed to create test config - %v", err) |
||||
} |
||||
defer removeAll(rootPath) |
||||
creds := serverConfig.GetCredential() |
||||
ls := loginServer{} |
||||
testCases := []struct { |
||||
args RPCLoginArgs |
||||
expectedErr error |
||||
}{ |
||||
// Valid username and password
|
||||
{ |
||||
args: RPCLoginArgs{Username: creds.AccessKey, Password: creds.SecretKey}, |
||||
expectedErr: nil, |
||||
}, |
||||
// Invalid username length
|
||||
{ |
||||
args: RPCLoginArgs{Username: "aaa", Password: "minio123"}, |
||||
expectedErr: errInvalidAccessKeyLength, |
||||
}, |
||||
// Invalid password length
|
||||
{ |
||||
args: RPCLoginArgs{Username: "minio", Password: "aaa"}, |
||||
expectedErr: errInvalidSecretKeyLength, |
||||
}, |
||||
// Invalid username
|
||||
{ |
||||
args: RPCLoginArgs{Username: "aaaaa", Password: creds.SecretKey}, |
||||
expectedErr: errInvalidAccessKeyID, |
||||
}, |
||||
// Invalid password
|
||||
{ |
||||
args: RPCLoginArgs{Username: creds.AccessKey, Password: "aaaaaaaa"}, |
||||
expectedErr: errAuthentication, |
||||
}, |
||||
} |
||||
for i, test := range testCases { |
||||
reply := RPCLoginReply{} |
||||
err := ls.LoginHandler(&test.args, &reply) |
||||
if err != test.expectedErr { |
||||
t.Errorf("Test %d: Expected error %v but received %v", |
||||
i+1, test.expectedErr, err) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,111 @@ |
||||
/* |
||||
* 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 ( |
||||
"time" |
||||
|
||||
"github.com/minio/dsync" |
||||
) |
||||
|
||||
// Allow any RPC call request time should be no more/less than 3 seconds.
|
||||
// 3 seconds is chosen arbitrarily.
|
||||
const rpcSkewTimeAllowed = 3 * time.Second |
||||
|
||||
func isRequestTimeAllowed(requestTime time.Time) bool { |
||||
// Check whether request time is within acceptable skew time.
|
||||
utcNow := time.Now().UTC() |
||||
return !(requestTime.Sub(utcNow) > rpcSkewTimeAllowed || |
||||
utcNow.Sub(requestTime) > rpcSkewTimeAllowed) |
||||
} |
||||
|
||||
// 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 |
||||
|
||||
// Request time to be verified by the server for every RPC call.
|
||||
// This is an addition check over Authentication token for time drifting.
|
||||
RequestTime time.Time |
||||
} |
||||
|
||||
// SetAuthToken - sets the token to the supplied value.
|
||||
func (args *AuthRPCArgs) SetAuthToken(authToken string) { |
||||
args.AuthToken = authToken |
||||
} |
||||
|
||||
// SetRequestTime - sets the requestTime to the supplied value.
|
||||
func (args *AuthRPCArgs) SetRequestTime(requestTime time.Time) { |
||||
args.RequestTime = requestTime |
||||
} |
||||
|
||||
// IsAuthenticated - validated whether this auth RPC args are already authenticated or not.
|
||||
func (args AuthRPCArgs) IsAuthenticated() error { |
||||
// Check whether the token is valid
|
||||
if !isAuthTokenValid(args.AuthToken) { |
||||
return errInvalidToken |
||||
} |
||||
|
||||
// Check if the request time is within the allowed skew limit.
|
||||
if !isRequestTimeAllowed(args.RequestTime) { |
||||
return errServerTimeMismatch |
||||
} |
||||
|
||||
// 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 { |
||||
Username string |
||||
Password string |
||||
Version string |
||||
RequestTime time.Time |
||||
} |
||||
|
||||
// IsValid - validates whether this LoginRPCArgs are valid for authentication.
|
||||
func (args LoginRPCArgs) IsValid() error { |
||||
// Check if version matches.
|
||||
if args.Version != Version { |
||||
return errServerVersionMismatch |
||||
} |
||||
|
||||
if !isRequestTimeAllowed(args.RequestTime) { |
||||
return errServerTimeMismatch |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// LoginRPCReply - login reply provides generated token to be used
|
||||
// with subsequent requests.
|
||||
type LoginRPCReply struct { |
||||
AuthToken string |
||||
} |
||||
|
||||
// LockArgs represents arguments for any authenticated lock RPC call.
|
||||
type LockArgs struct { |
||||
AuthRPCArgs |
||||
dsyncLockArgs dsync.LockArgs |
||||
} |
||||
|
||||
func newLockArgs(args dsync.LockArgs) LockArgs { |
||||
return LockArgs{dsyncLockArgs: args} |
||||
} |
Loading…
Reference in new issue