[SERVER-10318] getLastError() always returns "getLastError command failed: need to login" Created: 24/Jul/13 Updated: 10/Mar/23 Resolved: 29/Jul/13 |
|
| Status: | Closed |
| Project: | Core Server |
| Component/s: | Internal Client |
| Affects Version/s: | 2.2.4, 2.2.5 |
| Fix Version/s: | None |
| Type: | Bug | Priority: | Major - P3 |
| Reporter: | Balint Szente | Assignee: | Spencer Brody (Inactive) |
| Resolution: | Done | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Environment: |
Debian Linux 7 x86_64, mongodb-10gen=2.2.5 |
||
| Issue Links: |
|
|||||||||||||||||||||||||||||||||||||||||
| Operating System: | Linux | |||||||||||||||||||||||||||||||||||||||||
| Steps To Reproduce: | Steps to reproduce:
Current result:
Expected result:
Some notes:
|
|||||||||||||||||||||||||||||||||||||||||
| Participants: | ||||||||||||||||||||||||||||||||||||||||||
| Description |
|
Starting from the version 2.2.4 of the Mongo Client C++ driver calling the getLastError() after a successful operation always results in "getLastError command failed: need to login" error when authentication is enabled. |
| Comments |
| Comment by Spencer Brody (Inactive) [ 30/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
My pleasure! Glad I could help. | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Balint Szente [ 30/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
I'm sorry, I was not online today. It is OK that you have closed the issue. Everything is clear now. Thank you very much for your support. | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Spencer Brody (Inactive) [ 29/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
Hi Balint, Cheers, | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Spencer Brody (Inactive) [ 29/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
Yep, that's right. | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Balint Szente [ 29/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
I'm sorry, it is my mistake at point 2.2. Copy paste typo: it should be without db, like this:
I think this way it makes sense So for fixing the conclusion:
| ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Spencer Brody (Inactive) [ 29/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
I'm not sure I understand point 2.2, you say to use the same call for getLastError both for clients older and newer than 2.2.1. Given that the default form of getLastError that defaults to the admin database is the only form available to clients before 2.2.1, and the dbname is necessary for GLE when talking to a 2.2.x server, I don't think you can use the built-in helper for calling GLE when using a client <= 2.2.0 with a server that is 2.2.x. In those cases, I think you'll have to use runCommand to issue the getLastError command manually. You can see an example of how to do this by looking at DBClientWithCommands::getLastErrorDetailed. So I think your conclusion is correct except that I would change the last point to say to use runCommand directly when the client is <= 2.2.0 and you're talking to a 2.2.x server. | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Balint Szente [ 29/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
Thank you for the detailed explanation. Yes, I was using mongodb-10gen=2.2.5 server for all the above C++ client tests. I made a new set of tests with mongodb-10gen=2.4.5 and all the above C++ clients. Everything was fine: both getLastError() and getLastError(db) return success with every client version. So, as a conclusion:
Unfortunately there is no way to determine the client version at compile time in order to call the correct function prototype, thus I filed the | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Spencer Brody (Inactive) [ 26/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
Hi Balint, I assume you were using something in the 2.2 series for the server for all the tests, is that correct? I'm a bit surprised about the Let's see if I can give you some context around what happened here. Historically, the GLE command did not require authorization to run. Anyone could run GLE, even on an unauthenticated connection, and it would work. Because it only shows errors from previous writes on this same connection, this wasn't a security hole, because to get a meaningful error you must have been authenticated and authorized to perform a write. In 2.2, GLE was changed to require authorization, as part of an attempt to have better security practice in general. This, however, caused a lot of problems for drivers and broke what was then the only way to call GLE in the C++ driver, as it defaulted to the "admin" database, but now you had to send GLE to a database you actually had authorization for. That is why in 2.2.1 we added the version of GLE to the C++ driver that takes a database name. In 2.4, however, we removed the authorization requirement from GLE, bringing it back to its pre-2.2 behavior, since it wasn't really a security hole to begin with and only succeeded in complicating the logic for clients and drivers. So all these problems should only matter on 2.2 versions of the server, all other versions, past and future, should work with sending GLE to any database and thus the default driver call should work fine. I filed I'm sorry about the confusion around this, we've been investing a lot into security recently and this was a case were we traded off usability for a false sense of security (which was rectified in the next major release, but is still frustrating to those who are still actively using v2.2). Hopefully this explanation cleared some things up around what happened here and why - please let me know if you have any further questions. -Spencer | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Balint Szente [ 26/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
Very good catch! I was aware of the two function prototypes, but the implicit char* to bool conversion is so illogical that I never thought about it. Unfortunately the implicit type conversions in C++ are black magic. I can confirm the proposed solution works:
In order to avoid this very confusing situation please add also a signature with char*:
There is one more thing to clarify regarding the getLastError() API:
Function behavior summary:
Legend: So as a summary – the correct call of getLastError function to obtain the error for last operation on this connection would be:
Questions:
MongoDB is really a great project and I would like to understand the above decisions. I'm sure there were good reasons that are not obvious at first sight, especially for a non MongoDB developer. Thank you for your time and understanding. | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Spencer Brody (Inactive) [ 25/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
Okay, I was able to reproduce the behavior you saw. The problem is that the getLastError method is overloaded. There are two signatures for it:
and
When you call getLastError("testdb"), "testdb" is a char* under the hood. char* can be implicitly converted to a std::string, but it can also be implicitly converted to a bool. It is the latter conversion that is happening here, causing the second form of getLastError to be called, thus setting the fync parameter to true, but not changing the db away from the default of "admin". If you change your call from getLastError("testdb") to getLastError(std::string("testdb")), that should tell the compiler to interpret the first argument to getLastError as a string not a bool, so it should then do the right thing. Please try that out and let me know if it fixes things for you. Sorry for the confusion. | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Balint Szente [ 25/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
I'm afraid this is not the case. Using
does not help. The error is the same. Using connection.getLastError() produces the following server log:
Specifying the database connection.getLastError("testdb") generates the very same log:
Notes:
Could you please test the steps described and reopen the issue? Thank you. | ||||||||||||||||||||||||||||||||||||||||||||
| Comment by Spencer Brody (Inactive) [ 24/Jul/13 ] | ||||||||||||||||||||||||||||||||||||||||||||
|
This is because getLastError defaults to being sent to the "admin" database, but you're writing to the "testdb" database. If you use
|