[SERVER-33993] (kerberos) failed to connect if the principle name has '@' character Created: 20/Mar/18  Updated: 27/Nov/18  Resolved: 27/Nov/18

Status: Closed
Project: Core Server
Component/s: Security
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: winnie_quest Assignee: Benjamin Caimano (Inactive)
Resolution: Duplicate Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: PNG File addUser.png     PNG File add_to_kdc.png     PNG File add_user.png     PNG File connect.png     PNG File log_shell.png    
Issue Links:
Related
related to SERVER-36456 MongoD does not support kerberos on W... Closed
is related to CDRIVER-2549 (kerberos) failed to connect if the p... Closed
Operating System: ALL
Sprint: Service Arch 2018-10-08, Service Arch 2018-10-22, Service Arch 2018-11-05, Service Arch 2018-11-19, Service Arch 2018-12-03
Participants:

 Description   

hi
I made following test:
firstly, I added user1@a@KER.COM into KDC, see

(note: for escape purpose, we have to add a back-slash before @ if the principle name has @)
and then I added the user "user1@a@KER.COM" into mongodb server. see
then try to connect from mongo shell

I can't login successfully from mongo shell



 Comments   
Comment by Gregory McKeon (Inactive) [ 27/Nov/18 ]

Closing as a duplicate, since there were two tasks that came out of this that were both filed as separate tickets.

Comment by A. Jesse Jiryu Davis [ 30/Apr/18 ]

Yes, we're tracking that in CDRIVER-2549.

Comment by Andrew Morrow (Inactive) [ 30/Apr/18 ]

Hi winnie_quest - Just an FYI, but the C++ driver wraps the C driver and delegates all URI interpretation to the C driver. If there is an issue, I recommend opening a ticket in the CDRIVER project: https://jira.mongodb.org/projects/CDRIVER.

Comment by winnie_quest [ 28/Apr/18 ]

hi Ben,

I have tried with :

auto client = mongocxx::client{ mongocxx::uri{ "mongodb://user1%5C%5C%40a%40TICQUEST.CLOUDAPP.NET:123@db-mongo-kerberos.cloudapp.net:27017/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:mongodb" } };

but it still doesn't work.
so I think it looks like it's CXX driver's issue.
Thank you so much for your help

Comment by Benjamin Caimano (Inactive) [ 27/Apr/18 ]

Hmmmmmm, so I'm not a CXX driver expert by any means. (The shell falls to one team and the cxx to another.)

I am curious if perhaps the driver escapes the html and then escapes special characters. Does it work with this:

auto client = mongocxx::client{ mongocxx::uri{ "mongodb://user1%5C%5C%40a%40TICQUEST.CLOUDAPP.NET:123@db-mongo-kerberos.cloudapp.net:27017/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:mongodb" } };

Any verbose output would be appreciated.

(Also, apologies if I'm taking us down the wrong path, jesse.)

Comment by winnie_quest [ 27/Apr/18 ]

hi Ben,
thank you so much for your detailed explanation, it makes sense to me. so could I make a conclusion for the solution?
for kerberos authentication, if we want to use username called 'user1@a@TICQUEST.CLOUDAPP.NET' , we should add the user to kdc server firstly, like this:
,
then we should add the username with a backslash before at-sign into mongoDB, like this: ,
when connect from mongo shell, I should add double back-slash before at-sign, like this:

Am I correct?

if so, I found I tried to connect by mongodb CXX driver, like this:
auto client = mongocxx::client{ mongocxx::uri{ "mongodb://user1%5C%40a%40TICQUEST.CLOUDAPP.NET:123@db-mongo-kerberos.cloudapp.net:27017/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:mongodb" } };
(note: %5C is the percent-encoding of back-slash, %40 is percent-encoding of at-sign),

connection would get failed.
that means with "user1\@a@TICQUEST.CLOUDAPP.NET" I still can't connect to server by mongocxx driver in my program, should I open a ticket to the driver module?
hi @A. Jesse Jiryu Davis, could you please help to confirm as well?

Comment by Benjamin Caimano (Inactive) [ 24/Apr/18 ]

Hey winnie_quest,

So the mongod server stores usernames in pure bytes. When you add a user via the mongo shell, it uses javascript to interpret your string which means that to get a backslash into a username you need to escape that slash. The reason the kdc server rejects a principal that has multiple at-signs in it is due to the internal special character rules of kerberos. It needs that backslash in the byte string to escape all at-signs that are in the principal name portion.

Going a little deeper, to connect a mongodb user to a kerberos principal, the mongodb user needs to reflect the "canonical" name of the principal. Specifically for MIT kerberos, that means that all at-signs that aren't the one that separates name and domain must be escaped by a backslash. I say specifically for MIT kerberos because the standard is very unhelpful (see section 4.2 for how they leave this up to the OS and thus the implementation).

When you use the mongo shell to connect to the mongod server via gss-api/libkrb5, the shell uses your ticket from kinit. The ticket you use in the images above to authenticate is using a principal that does have the backslash, the escape character. You then send the string from the --username argument as the user you want to be in the mongod server. There are two issues here:

  • A database user must bytewise match, including escape characters, the principal from your ticket. We can't auth a user with multiple unescaped at-signs in its username because we can't predict how the specific kerberos implementation will escape the principal.
  • The username used by any one of our clients (the shell included) must match a user document stored in the database. If the client presents a username without necessary escape characters, it can only match user documents for which kerberos cannot issue tickets.

Apologies if I seem to be restating things you know, I'm trying to make sure we're on the same page here. This isn't something we can really fix--we don't control and cannot predict what the rules are for how characters are escaped. In general, we'd recommend you look at the naming rules for your specific GSS-API implementation and make sure your usernames conform to them.

P.S. If you're curious about how kerberos does its escaping, you can see how it works here. You can also see how it prints out principles here. I've specifically linked the lines where it deals with escape characters. Importantly, the "krb5_parse_name" function is used just about anywhere a principle is considered, including login. This means that the byte representation passed to kerberos must include escape characters.

Comment by winnie_quest [ 24/Apr/18 ]

hi Ben,
thanks for you reply, but I am still confused. From what your said, it looks like mongodb server uses javascript to read username info, but javascript doesn't converse at-sign to backslash+at-sign, and then send "user1@a@KER.COM" to kdc server to do query, and get "not-found this user" result. is my understanding correct? If so, can mongodb server do such escape before sending the username to kdc server?

According to your suggestion, I had a test, if I added a user like this:

but I can only connect successfully with the following username

I think it's strange for the client to put two backslash signs before '@'.

Well, I created this JIRA item because of https://jira.mongodb.org/browse/CDRIVER-2549, in my program, I was trying to connect to mongo db server with mongodb cxx driver, but I couldn't connect to it with "user@a@KER.COM", this issue was found by our QA, I just want to report this issue to mongDB.
this issue is not urgent, but I just want to know if you can solve it.

Comment by Benjamin Caimano (Inactive) [ 18/Apr/18 ]

Hi winnie_quest,

This appears to be a frustrating result of how javascript--and thus the Mongo Shell officially handle strings. Kerberos actually stores the backslash as a raw character for the principal. However, javascript string parsing resolves an at-sign input string as an at-sign raw string without a backslash. (The process of escaping a string for our shell is less than obvious.)

Would you mind trying to add your test user like so:

> use $external
> db.createUser({
  user: String.raw`user1\@a@KER.COM`,
  roles: [
    { role: "userAdminAnyDatabase", db: "admin" },
    { role: "readWrite", db: "quest_stage" }
  ]
})

Generated at Thu Feb 08 04:35:14 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.