Problem with usernames and custom Auth/UserProvider in Wildfire 3.2 beta

I’'m having a problem with my Auth, User and Group providers when running under wildfire 3.2 versions.

The problem is connected with a change in Wildfire that now assumes that the username I login with is the front part of my jid. This was not necessarily the case with versions prior to 3.2, since a custom UserProvider can return a User object that has a different username from the one passed to the UserProvider.

In previous versions this was supported and was quite useful for keeping a the username used for authentication hidden from other users. For example, I may want to login with a username used for my corporate identity, but don’'t necessarily want all my jabber contacts to know my corporate username by looking at my JID.

Is there any chance that the final version of 3.2 will support this? (i.e. behave like previous releases)

Or perhaps someone has an idea for a workround?

Chris.

Chris,

This was not an intended change, although I’‘m not sure the old behavior was on purpose either. Have you been able to find what change broke the behavior you’'re looking for? We could look into fixing that if so.

Regards,

Matt

Chris-

How are the clients authenticating/authorizing? Do they provide the authorized ID at login? Or do they just provided the authentication ID and have the Auth/User provider switch it out?

Hey Matt-

Related to this thread is some work Im doing in my “free time” (ha!)

The state of SASL authentication in Wildfire is a bit conveluted. Since originally there was not a seperation between authentication and authorization it was possible to run into issues like this. Im in the process of fixing up all the SASL code to properly use the Java Sasl objects, which includes using the AuthorizationCallback’'s which can make it easier for custom providers to allow differences in the authenticated ID and the authorized ID. I have some code that compiles, but is largely untested at this point. Its a fairly invasive change, so I wouldnt expect it to just show up, but perhaps for 3.3.x?

Hey, Matt and slushpupie, thanks for your replies.

I haven’'t really looked at the sources much to investigate what changed after Wildire 3.1.1 that might have caused my custom Auth/User provider to stop working properly, I may look deeper this week.

I did notice however that there was evidence that what I am doing was (as you say Matt) probably not intentionally supported. That’'s because I noticed that UserManager class was caching the User object using the authenticated username as a key rather the return value of user.getUsername(). Which of course would make a bit of a confusion over of caching users since the username passed to UserManager would be called with different usernames for the same user depending on whether the user was logging in, or the user was being loaded for other purposes in wildfire.

Ideally, I would say that the authentication provider ought to be able to provide the jabber username that is used to load the user during login. For example, if I login with username ‘‘ano2’’ and I want my jabber username in my jid to be ‘‘36362’’ then the login process would call userManager.getUser(’‘36362’’) to load my User object. The ‘‘36363’’ being calculated by the AuthProvider while authenticating ‘‘ano2’’.

slushpupie! hope your mod’'s make it into a future version.

Thanks.

Chris.

Chris-

Take a look at org.jivesoftware.wildfire.sasl classes. Here is the basic idea of how the authentication and authorization works out of the box:

The user provides some SASL credentials and the SASLAuthentication object handles it. If the SASL mechanism is the right one, SASLAuthentication creates a Java SaslServer object with the callback object as XMPPCallback. The SaslServer uses XMPPCallback to send callbacks for getting the username, password verification, and finally authorization. Authorization is then managed by the AuthorizationManager class, which has allows a user to select various classes to perform this check. You could write your own AuthorizationProvider class that handles the logic of what username/authenticationID is authorized to what principal/authorizationID.

You would still have a few problems, though. This provider still cant change what was given to it (it can only give a yes/no response). XMPPCallback could be modifed easily enough to handle a change in ID’'s, though. The other issue is not all authentication methods go through this object.

Moving forward, if my changes are good enough, ALL authentication methods would use the SaslServer objects, and would thus have the ability to pass through the AuthenticationManager’'s process. Seperating the authentication and the authorization is a bit hard with the existing codebase, though. I hope Gato wont be too upset with some of the changes. Here is a quick list of what is on my mind so far:

  • Create new PLAIN, ANONYMOUS, EXTERNAL, and JIVE-SHAREDSECRET SaslServer objects (done)

  • Create new SaslServerFactory object to create the above SaslServer objects (done)

  • Modify SASLAuthentication so all authentication in that object uses proper SaslServer objects (done)

  • Modify rest of server code so s2s and any other authentication gets “converted” into a SASL conversation

  • Move SASLAuthentication out of the net package and into the sasl package

  • Rename AuthProvider as AuthenticationProvider (scary, I know. But “auth” just dosnt say enough)

  • Modify XMPPCallback and AuthenticationManager to allow the AuthorizationProvider to force an authorizationID

  • Modify the s2s outgoing code to use SaslClient objects (lower priority, but would make GSSAPI s2s work)

  • Write a “conversion plugin” of some sort to handle the older custom Auth/User providers

Matt (and Gato, if you are reading this too)-

I know these are some fairly significant changes that will break some of the public API’'s that some customers may be relying on. Once I get my proof-of-concept completed, I will show you guys what I have, and what the benefits are moving forward (there are several). If anyone wants to see this code early, just let me know. But right now the only testing its had is compiling

Getting SSO in place is a pretty high priority, so we’‘re really interested in seeing the changes. The current SASL code is a bit messy, so it’'s inevitable that a refactoring is going to cause some disruptions.

Regards,

Matt

Slushpupie-

Ah ha, yes I must admit I hadn’‘t looked at the SASL stuff. In fact, shamefully, I didn’‘t even know what SASL stood for until a very recent visit to wikipedia. Sound’'s like ‘‘just the job’’!

If I understand you correctly though, are you saying that the current SASL implementation in wildfire would not quite solve my problem? I wasn’‘t sure, as what you desribe as a ‘‘change in ID’’ sounds like ‘‘almost’’ what I want. I suppose my dumb question is "What’'s the practical difference between a ‘‘change in ID’’ and working out an authorized username from an authentciated username?

In fact I’'ve just realised, (as matt just mentioned it) the connection with SSO is almost the same issue for me, since I am also kludging my way round SSO by passing encoded browser cookies from my jabber web client to wildfire via the username. Does anyone want to shoot me now?

Chris.

Chris-

The “correct” way to have the username change is to have the client pass it along. This is the seperation between authentication and authorization. The idea is that user 0221452 proves to the system he is the correct user (authentication). But no one wants a jabber ID like that, so 0221452 requests john.doe@domain . The the system authorizes him, then all is good. This is often more critical with SSO systems, because your principal (authentication ID) is in the form of user@REALM which dosnt map exactly to a jabber ID. The simplest form is to just cut off the @REALM part (which is what essentially happens now) but that dosnt work in every case.

So there are a few ways to deal with this. The best way is to have the client request authorization to use a name and have the SASL/Authorization systems give the thumbs up or down. But right now there are so few clients that allow a difference in author/authz IDs that the system itself needs to have a way to handle an internal mapping (ie 0221452 always gets john.doe). Im going to try and get the system to this point, but some work will need to be done on client systems to improve the situation some.

I wasnt sure if my previous post really answered your question directly. The practical difference you are talking about is really active vs passive. Do we let the client tell us what ID he/she wants? Or do we just assign it. I think both need to be availible. In the current code, the only way to make it really work correctly is if you use GSSAPI with a custom AuthorizationProvider and a client that can supply a different authentication and authorization ID. Since that is a pretty narrow view, I would say for all practical purposes its not possible right now. If you are willing to be a guinea pig for me, contact me in private with your setup and I’'ll see what I can do for you.

Slushpupie,

Thanks for the detailed explanations. In my setup I would not want the client to be responsible for supplying the user ID, particularly as we are trying to support as many clients as possible. So I think I need the server end to provide the mapping between authenicated id and user id.

What I am doing is providing integration between our VLE system (i.e. Moodle…argggg) and Wildfire. I want users to be able to login to any jabber client using their Moodle username, but I do not want this ‘‘private’’ username in their JID. In my case, the JID username is currently provided by my custom UserProvider which requests it from a Moodle service.

So, from my perspective I really don’'t want the client to need to support anything new in order to achieve this.

If you can help me achieve that, I’'d be happy to be a ginea pig

Though it may be that you have already given me enough pointers to have a crack at it myself (well, once I’'ve absorbed them properly).

Thanks again.

Chris.

I found the difference between 3.1 & 3.2 that caused my problem!

In org.jivesoftware.wildfire.session.ClientSession

The method setAuthToken in 3.1.1 used to get the username by calling userManager.getUser() but in 3.2.2 just uses the AuthToken.getUsename(). I reverted this function in 3.2.2 to something more equivalent to 3.1.1 and all seems ok now (running my patched 3.2.2)

In case it’‘s useful to anyone, here’'s my patch to ClientSession class.

If this code isn’'t rubbish, maybe it would be possible to have the bit in the try block below switched on and off by some server setting in a future version?

public void setAuthToken(AuthToken auth, String resource) {

String username = auth.getUsername();

try {

org.jivesoftware.wildfire.user.User user =

org.jivesoftware.wildfire.user.UserManager.getInstance().getUser(username);

username = user.getUsername();

} catch (UserNotFoundException e) { }

setAddress(new JID(username, getServerName(), resource));

authToken = auth;

sessionManager.addSession(this);

setStatus(Session.STATUS_AUTHENTICATED);

// Set default privacy list for this session

setDefaultList(PrivacyListManager.getInstance().getDefaultPrivacyList(username)) ;

}