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:
parent
2b7dd6ad05
commit
7ed81cdf6b
@ -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;
|
||||
|
@ -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
17
jstests/auth/copyauth.js
Normal 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 );
|
@ -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 */,
|
||||
|
16
shell/db.js
16
shell/db.js
@ -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 } );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user