0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

SERVER-579 support copyDatabase from source running with security

This commit is contained in:
Aaron 2010-02-16 15:20:35 -08:00
parent 2b7dd6ad05
commit 7ed81cdf6b
5 changed files with 86 additions and 11 deletions

View File

@ -46,6 +46,7 @@ namespace mongo {
snapshot - use $snapshot mode for copying collections. note this should not be used when it isn't required, as it will be slower.
for example repairDatabase need not use it.
*/
void setConnection( DBClientWithCommands *c ) { conn.reset( c ); }
bool go(const char *masterHost, string& errmsg, const string& fromdb, bool logForRepl, bool slaveOk, bool useReplAuth, bool snapshot);
bool startCloneCollection( const char *fromhost, const char *ns, const BSONObj &query, string& errmsg, bool logForRepl, bool copyIndexes, int logSizeMb, long long &cursorId );
bool finishCloneCollection( const char *fromhost, const char *ns, const BSONObj &query, long long cursorId, string &errmsg );
@ -191,7 +192,9 @@ namespace mongo {
auto_ptr<DBClientCursor> c;
{
if ( !masterSameProcess ) {
if ( conn.get() ) {
// nothing to do
} else if ( !masterSameProcess ) {
auto_ptr< DBClientConnection > c( new DBClientConnection() );
if ( !c->connect( masterHost, errmsg ) )
return false;
@ -231,12 +234,11 @@ namespace mongo {
continue;
}
}
else if( strchr(from_name, '$') ) {
if( strchr(from_name, '$') ) {
// don't clone index namespaces -- we take care of those separately below.
log(2) << "\t\t not cloning because has $ " << endl;
continue;
}
toClone.push_back( collection.getOwned() );
}
}
@ -571,8 +573,41 @@ namespace mongo {
}
} cmdfinishclonecollection;
thread_specific_ptr< DBClientConnection > authConn_;
/* Usage:
admindb.$cmd.findOne( { copydb: 1, fromhost: <hostname>, fromdb: <db>, todb: <db> } );
admindb.$cmd.findOne( { copydbgetnonce: 1, fromhost: <hostname> } );
*/
class CmdCopyDbGetNonce : public Command {
public:
CmdCopyDbGetNonce() : Command("copydbgetnonce") { }
virtual bool adminOnly() {
return true;
}
virtual bool slaveOk() {
return false;
}
virtual void help( stringstream &help ) const {
help << "get a nonce for subsequent copy db request from secure server\n";
help << "usage: {copydbgetnonce: 1, fromhost: <hostname>}";
}
virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
string fromhost = cmdObj.getStringField("fromhost");
uassert( 13009, "fromhost must be specified", !fromhost.empty() );
authConn_.reset( new DBClientConnection() );
if ( !authConn_->connect( fromhost, errmsg ) )
return false;
BSONObj ret;
if( !authConn_->runCommand( "admin", BSON( "getnonce" << 1 ), ret ) ) {
errmsg = "couldn't get nonce " + string( ret );
return false;
}
result.appendElements( ret );
return true;
}
} cmdcopydbgetnonce;
/* Usage:
admindb.$cmd.findOne( { copydb: 1, fromhost: <hostname>, fromdb: <db>, todb: <db>[, username: <username>, nonce: <nonce>, key: <key>] } );
*/
class CmdCopyDb : public Command {
public:
@ -585,7 +620,7 @@ namespace mongo {
}
virtual void help( stringstream &help ) const {
help << "copy a database from antoher host to this host\n";
help << "usage: {copydb: 1, fromhost: <hostname>, fromdb: <db>, todb: <db>}";
help << "usage: {copydb: 1, fromhost: <hostname>, fromdb: <db>, todb: <db>[, username: <username>, nonce: <nonce>, key: <key>]}";
}
virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
string fromhost = cmdObj.getStringField("fromhost");
@ -601,8 +636,21 @@ namespace mongo {
errmsg = "parms missing - {copydb: 1, fromhost: <hostname>, fromdb: <db>, todb: <db>}";
return false;
}
Cloner c;
string username = cmdObj.getStringField( "username" );
string nonce = cmdObj.getStringField( "nonce" );
string key = cmdObj.getStringField( "key" );
if ( !username.empty() && !nonce.empty() && !key.empty() ) {
uassert( 13008, "must call copydbgetnonce first", authConn_.get() );
BSONObj ret;
if ( !authConn_->runCommand( fromdb, BSON( "authenticate" << 1 << "user" << username << "nonce" << nonce << "key" << key ), ret ) ) {
errmsg = "unable to login " + string( ret );
return false;
}
c.setConnection( authConn_.release() );
}
Client::Context ctx(todb);
bool res = cloneFrom(fromhost.c_str(), errmsg, fromdb, /*logForReplication=*/!fromRepl, /*slaveok*/false, /*replauth*/false, /*snapshot*/true);
bool res = c.go(fromhost.c_str(), errmsg, fromdb, /*logForReplication=*/!fromRepl, /*slaveok*/false, /*replauth*/false, /*snapshot*/true);
return res;
}
} cmdcopydb;

View File

@ -1302,7 +1302,7 @@ namespace mongo {
*/
DiskLoc DataFileMgr::insert(const char *ns, const void *obuf, int len, bool god, const BSONElement &writeId, bool mayAddIndex) {
bool wouldAddIndex = false;
uassert( 10093 , "cannot insert into reserved $ collection", god || strchr(ns, '$') == 0 );
massert( 10093 , "cannot insert into reserved $ collection", god || strchr(ns, '$') == 0 );
uassert( 10094 , "invalid ns", strchr( ns , '.' ) > 0 );
const char *sys = strstr(ns, "system.");
if ( sys ) {

17
jstests/auth/copyauth.js Normal file
View File

@ -0,0 +1,17 @@
// test copyDatabase from an auth enabled source
ports = allocatePorts( 2 );
var baseName = "jstests_clone_copyauth";
var source = startMongod( "--auth", "--port", ports[ 0 ], "--dbpath", "/data/db/" + baseName + "_source", "--nohttpinterface", "--bind_ip", "127.0.0.1", "--smallfiles" );
var target = startMongod( "--port", ports[ 1 ], "--dbpath", "/data/db/" + baseName + "_target", "--nohttpinterface", "--bind_ip", "127.0.0.1", "--smallfiles" );
source.getDB( baseName )[ baseName ].save( {i:1} );
source.getDB( baseName ).addUser( "foo", "bar" );
source.getDB( "admin" ).addUser( "super", "super" );
assert.throws( function() { source.getDB( baseName )[ baseName ].findOne(); } );
target.getDB( baseName ).copyDatabase( baseName, baseName, source.host, "foo", "bar" );
assert.eq( 1, target.getDB( baseName )[ baseName ].count() );
assert.eq( 1, target.getDB( baseName )[ baseName ].findOne().i );

View File

@ -464,6 +464,7 @@
93B4A8290F1C024C000C862C /* cursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cursor.cpp; sourceTree = "<group>"; };
93B4A82A0F1C0256000C862C /* pdfiletests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pdfiletests.cpp; sourceTree = "<group>"; };
93B9F5A7112B12440066ECD2 /* slavefromsnapshot.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = slavefromsnapshot.js; sourceTree = "<group>"; };
93B9F671112B3AD40066ECD2 /* copyauth.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = copyauth.js; path = auth/copyauth.js; sourceTree = "<group>"; };
93BC2AE10FB87662006BC285 /* cursortests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cursortests.cpp; sourceTree = "<group>"; };
93BC2AE20FB87662006BC285 /* jstests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jstests.cpp; sourceTree = "<group>"; };
93BCE15610F25DFE00FA139B /* arrayfind1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = arrayfind1.js; sourceTree = "<group>"; };
@ -734,6 +735,7 @@
934BEB9A10DFFA9600178102 /* jstests */ = {
isa = PBXGroup;
children = (
93B9F671112B3AD40066ECD2 /* copyauth.js */,
93D5A8921117A1380052C931 /* regex6.js */,
938E639A110FC66900A8760A /* auth */,
93BCE41810F3AF1B00FA139B /* capped2.js */,

View File

@ -64,6 +64,10 @@ DB.prototype.removeUser = function( username ){
this.getCollection( "system.users" ).remove( { user : username } );
}
DB.prototype.__pwHash = function( nonce, username, pass ) {
return hex_md5( nonce + username + hex_md5( username + ":mongo:" + pass ) );
}
DB.prototype.auth = function( username , pass ){
var n = this.runCommand( { getnonce : 1 } );
@ -72,7 +76,7 @@ DB.prototype.auth = function( username , pass ){
authenticate : 1 ,
user : username ,
nonce : n.nonce ,
key : hex_md5( n.nonce + username + hex_md5( username + ":mongo:" + pass ) )
key : this.__pwHash( n.nonce, username, pass )
}
);
@ -221,12 +225,16 @@ DB.prototype.cloneCollection = function(from, collection, query) {
* @return Object returned has member ok set to true if operation succeeds, false otherwise.
* See also: db.clone()
*/
DB.prototype.copyDatabase = function(fromdb, todb, fromhost) {
DB.prototype.copyDatabase = function(fromdb, todb, fromhost, username, password) {
assert( isString(fromdb) && fromdb.length );
assert( isString(todb) && todb.length );
fromhost = fromhost || "";
//this.resetIndexCache();
return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb } );
if ( username && password ) {
var n = this._adminCommand( { copydbgetnonce : 1, fromhost:fromhost } );
return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb, username:username, nonce:n.nonce, key:this.__pwHash( n.nonce, username, password ) } );
} else {
return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb } );
}
}
/**