[CSHARP-402] Better support for authorization in server commands (like GetDatabaseNames) Created: 21/Feb/12  Updated: 20/Mar/14  Resolved: 07/Mar/12

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: 1.3.1
Fix Version/s: 1.4

Type: Improvement Priority: Minor - P4
Reporter: Robert Stam Assignee: Robert Stam
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

The following properties and methods of MongoServer only work if the DefaultCredentials are valid for the admin database. There should probably be a better way to provide admin credentials without making them the default credentials.

The properties and methods affected are:

AdminDatabase
DatabaseExists
DropDatabase
FetchDBRef
GetAdminDatabase
GetDatabaseNames
GetLastError
RunAdminCommand
Shutdown



 Comments   
Comment by Craig Wilson [ 30/Aug/12 ]

Added documentation here: http://www.mongodb.org/display/DOCS/CSharp+Driver+Tutorial#CSharpDriverTutorial-Authentication

Comment by Blake Niemyjski [ 29/Aug/12 ]

Thanks for the clarification, it makes sense. Could someone please update the documentation to reflect this? So a newbie like myself doesn't run into this..

Comment by Robert Stam [ 29/Aug/12 ]

The default credentials and the credentials store serve two different purposes. The credentials store is used to store credentials for particular databases (keyed by the database name). The default credentials are used when the credentials store doesn't happen to have the required credentials. The connection string format only supports supplying default credentials. The credentials store has to be set up in code.

Whether a user is an admin or not is a separate issue from whether they are read-only or not. An admin user is one whose credentials have been added to the admin database. Being an admin user automatically gives you access to all the databases on the system (kind of like root).

Putting the database name on the connections string is somewhat deprecated. It implies the concept of a "current database", which practically none of the drivers have (but the shell does). The way the C# driver supports the database name is to allow you to pass a connection string containing a database name to MongoDatabase.Create. This will also create a server instance at the same time.

var connectionString = "mongodb://localhost/test/?safe=true";
var database = MongoDatabase.Create(connectionString); // database.Name == "test"
var server = database.Server; // the automatically created server

Comment by Blake Niemyjski [ 29/Aug/12 ]

Please see my updated comment. I'm saying that when you call MongoServer.Create(string), it should pass the default credentials to the credential store (I haven't debugged this that far to see if that is the case. But I do see that it's populated on the MongoUrlBuilder.DefaultCredentials..

Also, I'm not sure if this is a bug that needs to be logged. But if you call MongoServer.Create(string) the default database name is completely lost as it's not part of MongoServerSettings that is passed to the overload for Create().

You could then get away with not needing to pass in a database name (http://stackoverflow.com/questions/7201847/how-to-get-the-mongo-database-specified-in-connection-string-in-c-sharp) as that information was already passed in.

Comment by Robert Stam [ 29/Aug/12 ]

Can you elaborate? Are you saying that we should remove the overloads that take admin credentials?

Comment by Blake Niemyjski [ 29/Aug/12 ]

I believe this is a bug as any connection string credentials should be added to the credential store.

Also, You can create a user for a new database. You can make this user read-only or not. I think the library should look to see if they are marked as read-only. If they are not, then treat them as admin. Also. All of the methods listed in this post like DatabaseExists, pass in "admin" to the MongoServerSettings.GetCredentials(string database name). Shouldn't it be passing in the current active database to see if the user exists and is not read-only? As a user might be a local admin database user and not a global (to the admin database).

Comment by Robert Stam [ 07/Mar/12 ]

The RenameCollection method in MongoDatabase also needs admin credentials, so I've added some overloads to handle that.

Comment by Robert Stam [ 07/Mar/12 ]

This turned out to be rather involved. There are now three ways you can provide admin credentials for admin related methods:

1. Set the default credentials to admin credentials (potentially dangerous, provides access to all databases)
2. Pass admin credentials directly to new overloads of the admin related methods
3. Store admin credentials in the new credentials store (which can be used for other databases as well)

The first would look like this:

var connectionString = "mongodb://adminusername(admin):adminpassword@localhost/?safe=true";
var server = MongoServer.Create(connectionString);
var databaseNames = server.GetDatabaseNames(); // uses the default credentials

The second would look like this:

var connectionString = "mongodb://localhost/?safe=true";
var server = MongoServer.Create(connectionString);
var adminCredentials = new MongoCredentials("adminusername", "adminpassword", true);
var databaseNames = server.GetDatabaseNames(adminCredentials); // uses the provided admin credentials

The third would look like this:

var connectionString = "mongodb://localhost/?safe=true";
var url = new MongoUrlBuilder(connectionString);
var serverSettings = url.ToServerSettings();
var adminCredentials = new MongoCredentials("adminusername", "adminpassword", true);
serverSettings.CredentialsStore.AddCredentials("admin", adminCredentials);
// can add credentials for other databases to the credentials store here as well
var server = MongoServer.Create(serverSettings); // serverSettings, including the credentials store, are now frozen for thread safety
var databaseNames = server.GetDatabaseNames(); // uses the admin credentials from the credentials store

Note that there is no support in the connection string for initializing the credentials store, so you must use a hybrid approach that uses the connection string to get the initial MongoServerSettings and then fill in the credentials store before calling MongoServer.Create.

Generated at Wed Feb 07 21:36:43 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.