I'd like to discuss the proposed change to the authentication plugin system (http://www.mediawiki.org/wiki/ExternalAuth). As proposed, I don't see how I'll be able to keep most of the functionality in the LDAP extension.
I don't disagree that policy and implementation shouldn't be mixed, but core shouldn't be making all policy decisions. For instance, there is an option in the LDAP extension ($wgLDAPDisableAutoCreate) that disables auto-creation, but still allows auto-authentication. Essentially, it says, if the user exists in LDAP, but not in the local directory, don't automatically create the local account. Some administrators want to create accounts for users in the wiki locally, even though they already have accounts in LDAP.
Will getGroups() assign users to whatever groups the backend returns? The way I'm currently doing this is adding users to groups if they are available groups in the wiki (if they've been defined in $wgGroupPermissions). I don't use auto-promote at all.
The LDAP plugin can add users to the LDAP database. Is this also going to support that?
The LDAP plugin allows a user to authenticate with one username, but have the username created be something else. This is absolutely a must-have for auto-authentication, where a user might authenticate with Kerberos or an SSL certificate. If a user authenticates with an SSL certificate, their username may be something insane, like a numeric ID with special characters. The LDAP plugin would search the LDAP directory for another attribute that should be used for the username. Notice that you don't necessarily want to treat the auto-auth name as an ID either. You may pull both a new username, and a unique ID from the LDAP server; this is an especially likely scenario in a large organization, where a user may have a global unique ID, but in some places they may have a locally unique ID (think mergers).
There are situations where newFromId( $id ) and getId() won't work. Active Directory (AD) is a case where it is unlikely to work for most people. By default AD does not allow anonymous searches. There are two ways to handle this:
1. Use a proxy agent (AD administrators *hate* this) 2. Bind as the user first
In the second case, newFromId( $id ), and getId() will only work if authenticate( $password ) is called first. In fact, many things require the user to be authenticated before another action can happen.
From the LDAP server's perspective, MediaWiki *is* the user binding.
A few things I'd really like to see fixed with any new system are:
1. Extensions being able to display error messages (bug 16524) 2. Ability to rename a local account when the external account is renamed 3. Local group name size increased in the schema (bug 11057) so that all external groups can be synced properly
Respectfully,
Ryan Lane
On Thu, Mar 25, 2010 at 12:27 AM, Ryan Lane rlane32@gmail.com wrote:
I'd like to discuss the proposed change to the authentication plugin system (http://www.mediawiki.org/wiki/ExternalAuth). As proposed, I don't see how I'll be able to keep most of the functionality in the LDAP extension.
It isn't a change, it's an addition. AuthPlugin will be kept indefinitely, certainly at least until all users in trunk are obsoleted by equivalent ExtAuth plugins (which may well be never).
I don't disagree that policy and implementation shouldn't be mixed, but core shouldn't be making all policy decisions. For instance, there is an option in the LDAP extension ($wgLDAPDisableAutoCreate) that disables auto-creation, but still allows auto-authentication. Essentially, it says, if the user exists in LDAP, but not in the local directory, don't automatically create the local account. Some administrators want to create accounts for users in the wiki locally, even though they already have accounts in LDAP.
First off, if this is desirable for LDAP, it's desirable for other auth systems too. Therefore, in ExtAuth, this feature would be added to the core code, *not* individual extensions, so that it could be used by *all* backends. The LDAP-specific stuff should only deal with stuff that is *really* specific to LDAP, like connecting to the LDAP server and mapping MediaWiki auth info to however LDAP stores things.
Second, I'm not sure what you mean by "disables auto-creation, but still allows auto-authentication". The user must be authenticated as *some* user that exists in the MediaWiki database, no? How does auto-authentication work in this case?
This might be the same as $wgAutocreatePolicy. The default is 'login', which autocreates accounts if a user logs in, their auth information doesn't match any local account, and it does match an external account. You can also set it to 'never', which never autocreates local accounts (so they have to be manually linked, which doesn't work yet); and 'view', which will try to autocreate from cookies or such if supported by the backend.
Will getGroups() assign users to whatever groups the backend returns? The way I'm currently doing this is adding users to groups if they are available groups in the wiki (if they've been defined in $wgGroupPermissions). I don't use auto-promote at all.
You mean, you just take the group name strings returned by LDAP and assign them to the user as MediaWiki groups? That's an interesting idea, provided there are no conflicts. It would be a lot simpler than using auto-promote. However, it could cause problems if group names were weird, like with spaces or something, since a lot of code probably assumes they look like typical MediaWiki group names.
Still, I think this is a better approach. Currently this isn't actually implemented at all in ExtAuth, so it could be changed to the method you describe easily enough.
The LDAP plugin can add users to the LDAP database. Is this also going to support that?
That's a possible feature, although I don't think it's in any of my design documents. For many backends it would be impractical, but it would make sense for LDAP. I mostly designed this to allow authentication on my site's wiki from vBulletin, another web app, so the design is probably skewed toward that, but I'm pretty sure it's flexible enough that it could be adjusted to support LDAP well.
The LDAP plugin allows a user to authenticate with one username, but have the username created be something else. This is absolutely a must-have for auto-authentication, where a user might authenticate with Kerberos or an SSL certificate. If a user authenticates with an SSL certificate, their username may be something insane, like a numeric ID with special characters. The LDAP plugin would search the LDAP directory for another attribute that should be used for the username. Notice that you don't necessarily want to treat the auto-auth name as an ID either. You may pull both a new username, and a unique ID from the LDAP server; this is an especially likely scenario in a large organization, where a user may have a global unique ID, but in some places they may have a locally unique ID (think mergers).
This is part of the design for ExternalAuth, although it hasn't yet been implemented. It's necessary for any backend that doesn't have username restrictions as rigid as MediaWiki, or that uses incomprehensible usernames. Even if you're just authenticating to an external MediaWiki, it's necessary to resolve conflicts. (In particular, this is necessary for vBulletin, since that permits characters like / in names, but it's not so essential, since most names don't have them -- which is why it's not implemented yet.)
There are situations where newFromId( $id ) and getId() won't work. Active Directory (AD) is a case where it is unlikely to work for most people. By default AD does not allow anonymous searches. There are two ways to handle this:
- Use a proxy agent (AD administrators *hate* this)
- Bind as the user first
In the second case, newFromId( $id ), and getId() will only work if authenticate( $password ) is called first. In fact, many things require the user to be authenticated before another action can happen. From the LDAP server's perspective, MediaWiki *is* the user binding.
From ExternalAuth's perspective, an "id" can be any unique, stable
identifier. It's used to store the information "MediaWiki user 13099 is associated to external user 32769". A "username" is expected to be something human-readable, which is actually used for login, but which may change from time to time (due to renaming). id's are stored in a varchar(255) and are not required to be numeric.
In particular, I think LDAP could just use an id equal to the username, since LDAP usernames are supposed to be stable, right?
A few things I'd really like to see fixed with any new system are:
- Extensions being able to display error messages (bug 16524)
This sounds like a good idea. An implementation idea would be to add a new method ExternalUser::getAuthenticationErrors(), like Title::getUserPermissionsErrors(), and use that in core code instead of authenticate(). The new method could wrap authenticate() in the base class, so classes that didn't need such fancy control could still just use authenticate().
- Ability to rename a local account when the external account is renamed
Sounds like a good idea, but how would you detect that the external account was renamed? Would you expect the external auth source to push this info to MediaWiki, or should MediaWiki detect it when the user next logs in? How should MediaWiki detect it -- remember the external username, and update the local one if the external one is different from what was remembered? Presumably it would just abort silently if there's some conflict (e.g., new name not usable by MediaWiki, or already taken).
The current ExtAuth implementation only stores the foreign id locally, not the name. If the external name changes, and the new external name isn't taken locally, you can log in to MediaWiki using either the new or old name, IIRC -- if you try the new one, it will authenticate you as the external user, then notice that that already has a local account and log you in as that. But your MediaWiki username will remain the same as the old name unless you're renamed on MediaWiki. This works for now, but would be nice to change.
- Local group name size increased in the schema (bug 11057) so that
all external groups can be synced properly
I forgot that MediaWiki group names have to be so short. Maybe autopromote is a better idea after all for backends that might have long group names. But that should be fixable, anyway, I hope.
I'd like to discuss the proposed change to the authentication plugin system (http://www.mediawiki.org/wiki/ExternalAuth). As proposed, I don't see how I'll be able to keep most of the functionality in the LDAP extension.
It isn't a change, it's an addition. AuthPlugin will be kept indefinitely, certainly at least until all users in trunk are obsoleted by equivalent ExtAuth plugins (which may well be never).
Ah. That's good. I have a good feeling I'll be moving to the new system as I definitely like some of the ideas in it so far. I especially like that the extension will be passed the exact username string typed by the user. I have some open bugs regarding that.
I don't disagree that policy and implementation shouldn't be mixed, but core shouldn't be making all policy decisions. For instance, there is an option in the LDAP extension ($wgLDAPDisableAutoCreate) that disables auto-creation, but still allows auto-authentication. Essentially, it says, if the user exists in LDAP, but not in the local directory, don't automatically create the local account. Some administrators want to create accounts for users in the wiki locally, even though they already have accounts in LDAP.
First off, if this is desirable for LDAP, it's desirable for other auth systems too. Therefore, in ExtAuth, this feature would be added to the core code, *not* individual extensions, so that it could be used by *all* backends. The LDAP-specific stuff should only deal with stuff that is *really* specific to LDAP, like connecting to the LDAP server and mapping MediaWiki auth info to however LDAP stores things.
That makes sense. My only concern is that this will require extension developers to dive into core to add features they'd normally add to their own extension. This isn't necessarily a bad thing, as their changes could benefit everyone.
Second, I'm not sure what you mean by "disables auto-creation, but still allows auto-authentication". The user must be authenticated as *some* user that exists in the MediaWiki database, no? How does auto-authentication work in this case?
This might be the same as $wgAutocreatePolicy. The default is 'login', which autocreates accounts if a user logs in, their auth information doesn't match any local account, and it does match an external account. You can also set it to 'never', which never autocreates local accounts (so they have to be manually linked, which doesn't work yet); and 'view', which will try to autocreate from cookies or such if supported by the backend.
Setting it to 'never' would likely fit this situation; I believe this is the correct use case (I've never used this functionality personally).
You mean, you just take the group name strings returned by LDAP and assign them to the user as MediaWiki groups? That's an interesting idea, provided there are no conflicts. It would be a lot simpler than using auto-promote. However, it could cause problems if group names were weird, like with spaces or something, since a lot of code probably assumes they look like typical MediaWiki group names.
Still, I think this is a better approach. Currently this isn't actually implemented at all in ExtAuth, so it could be changed to the method you describe easily enough.
I add users into the groups; I don't add groups to users. I do this by:
1. Getting a list of all groups ($user->getAllGroups()), and a list of groups the user is in ($user->getEffectiveGroups()) 2. I iterate through the list of all groups and: 2a. Add the user into the wiki group if they are in the external group 2b. Remove the user from the wiki group if they are in the wiki group, but no longer in the external group
Effectively, I'm synchronizing the groups every login.
This means the admin must choose which groups they want to synchronize by creating them in LocalSettings.php using $wgGroupPermissions, by adding permissions to the group.
I do have functionality to add all groups to $wgGroupPermissions (via $wgLDAPGroupsPrevail), so that other extensions can use the groups, but that code is *really* expensive, as sometimes users are in hundreds of groups; I'm unfortunately not exaggerating about the hundreds of groups, I've done a support request where someone had users that had 500+ groups.
The LDAP plugin can add users to the LDAP database. Is this
also going
to support that?
That's a possible feature, although I don't think it's in any of my design documents. For many backends it would be impractical, but it would make sense for LDAP. I mostly designed this to allow authentication on my site's wiki from vBulletin, another web app, so the design is probably skewed toward that, but I'm pretty sure it's flexible enough that it could be adjusted to support LDAP well.
Some extensions use this to manage an external database that all their applications use. It is a fairly esoteric feature, but I have users that use it in production. I personally have never used the feature past testing.
The LDAP plugin allows a user to authenticate with one username, but have the username created be something else. This is absolutely a must-have for auto-authentication, where a user might authenticate with Kerberos or an SSL certificate. If a user authenticates with an SSL certificate, their username may be something insane, like a numeric ID with special characters. The LDAP plugin would search the LDAP directory for another attribute that should be used for the username. Notice that you don't necessarily want to treat the auto-auth name as an ID either. You may pull both a new
username, and
a unique ID from the LDAP server; this is an especially likely scenario in a large organization, where a user may have a global unique ID, but in some places they may have a locally
unique ID (think
mergers).
This is part of the design for ExternalAuth, although it hasn't yet been implemented. It's necessary for any backend that doesn't have username restrictions as rigid as MediaWiki, or that uses incomprehensible usernames. Even if you're just authenticating to an external MediaWiki, it's necessary to resolve conflicts. (In particular, this is necessary for vBulletin, since that permits characters like / in names, but it's not so essential, since most names don't have them -- which is why it's not implemented yet.)
Well, the proposal mentions allowing the user to choose their own username. That is fine for some extensions (OpenID does this, for instance), and it may even be useful for the LDAP plugin, but I'd like to ensure the plugin can choose the name without giving the user an option.
It would be *really* nice if this worked for both regular, and auto-authentication, as right now it only works for auto-authentication; I use this for a semi-anonymous user feature, but it only works for auto-auth:
http://ryandlane.com/blog/2009/06/18/semi-anonymous-users-in-mediawiki-using -the-ldap-authentication-extension/
There are situations where newFromId( $id ) and getId() won't work. Active Directory (AD) is a case where it is unlikely to
work for most
people. By default AD does not allow anonymous searches.
There are two
ways to handle this:
- Use a proxy agent (AD administrators *hate* this)
- Bind as the user first
In the second case, newFromId( $id ), and getId() will only work if authenticate( $password ) is called first. In fact, many things require the user to be authenticated before another action
can happen.
From the LDAP server's perspective, MediaWiki *is* the user binding.
From ExternalAuth's perspective, an "id" can be any unique, stable identifier. It's used to store the information "MediaWiki user 13099 is associated to external user 32769". A "username" is expected to be something human-readable, which is actually used for login, but which may change from time to time (due to renaming). id's are stored in a varchar(255) and are not required to be numeric.
In particular, I think LDAP could just use an id equal to the username, since LDAP usernames are supposed to be stable, right?
Actually, no. LDAP usernames are not assumed to be unique, or stable. Generally, usernames are based on some combination of a person's name. People's names can change for various reasons (marriage, legal name change, etc.). When a person's name changes, their username changes with it. LDAP entries are assumed to have some unique identifier that is often different than the username. In the Posix schema, this is uidNumber. In Active Directory, it is often the Security Identifier (SID), but may also be the userAlternativeName attribute, which is often the case in smart card infrastructures.
In the Posix schema, this is guaranteed to be an integer, but in Active Directory, it will most likely be a string, and can be fairly long.
A few things I'd really like to see fixed with any new system are:
- Extensions being able to display error messages (bug 16524)
This sounds like a good idea. An implementation idea would be to add a new method ExternalUser::getAuthenticationErrors(), like Title::getUserPermissionsErrors(), and use that in core code instead of authenticate(). The new method could wrap authenticate() in the base class, so classes that didn't need such fancy control could still just use authenticate().
That sounds like a good idea.
- Ability to rename a local account when the external
account is renamed
Sounds like a good idea, but how would you detect that the external account was renamed? Would you expect the external auth source to push this info to MediaWiki, or should MediaWiki detect it when the user next logs in? How should MediaWiki detect it -- remember the external username, and update the local one if the external one is different from what was remembered? Presumably it would just abort silently if there's some conflict (e.g., new name not usable by MediaWiki, or already taken).
The current ExtAuth implementation only stores the foreign id locally, not the name. If the external name changes, and the new external name isn't taken locally, you can log in to MediaWiki using either the new or old name, IIRC -- if you try the new one, it will authenticate you as the external user, then notice that that already has a local account and log you in as that. But your MediaWiki username will remain the same as the old name unless you're renamed on MediaWiki. This works for now, but would be nice to change.
I implemented this in my extension, and tested it, but never publisized it, since it relied on the rename user extension, and I wasn't totally sure I wasn't going to cause massive data corruption if there was some incompatibility I didn't foresee.
The LDAP plugin detects the external account was renamed the following way:
On account creation, the plugin records the external ID. On authentication, the plugin queries LDAP, and gets the username back. If the username is different than the local account, the plugin renames the account, or blocks login, which should inform the user to contact the site admin. If the new username is already taken, the plugin blocks login, which should inform the user to contact the site admin.
Allowing the user to choose a new name in this situation wouldn't really make sense, as the extension is assuming the external username matches the local one. Keeping the name the same is also really problematic for most organizations using LDAP, as usernames may be re-used.
This actually makes me think of another case that needs to be handled. If the local database has a username that is the same as a username in LDAP, but has an external ID recorded that is different from what is in LDAP, the account in LDAP was likely deleted, but the username was re-used. The plugin should block login in this situation, so that the admin can rename the account to something like "Username (deleted)" or "Username (was <uid>)". This is important from an auditing perspective.
All of this assumes that account renaming can be initiated reliably from an authentication extension. This isn't currently possible. Why isn't RenameUser part of core?
User renaming, blocking, etc. should likely be a configurable option, as some features (such as the semi-anonymous example above), assume the username to be different.
- Local group name size increased in the schema (bug 11057) so that
all external groups can be synced properly
I forgot that MediaWiki group names have to be so short. Maybe autopromote is a better idea after all for backends that might have long group names. But that should be fixable, anyway, I hope.
Well, from the bug, it looks like the schema was set to be modified to have 255 character names, but it never happened. It is really unlikely for groups to be longer than 255 characters.
Respectfully,
Ryan Lane
On Thu, Mar 25, 2010 at 11:36 AM, Lane, Ryan Ryan.Lane@ocean.navo.navy.mil wrote:
Actually, no. LDAP usernames are not assumed to be unique, or stable. Generally, usernames are based on some combination of a person's name. People's names can change for various reasons (marriage, legal name change, etc.). When a person's name changes, their username changes with it. LDAP entries are assumed to have some unique identifier that is often different than the username. In the Posix schema, this is uidNumber. In Active Directory, it is often the Security Identifier (SID), but may also be the userAlternativeName attribute, which is often the case in smart card infrastructures.
In the Posix schema, this is guaranteed to be an integer, but in Active Directory, it will most likely be a string, and can be fairly long.
Wouldn't varchar(255) generally be enough to handle the SID from AD? IIRC (feel free to call me out badly if I'm wrong), Microsoft uses their standard GUID format, so it'd be something along the lines of "C8535E2E-148D-494d-8E9A-71FC46649B5E?"
-Chad
Wouldn't varchar(255) generally be enough to handle the SID from AD? IIRC (feel free to call me out badly if I'm wrong), Microsoft uses their standard GUID format, so it'd be something along the lines of "C8535E2E-148D-494d-8E9A-71FC46649B5E?"
Yeah, I seriously doubt any system is going to have a unique identifier longer than 255 characters. I know after this is implemented I'll find some crazy organization doing this though ;) (like the one that had a user with over 500 groups - crazy).
Respectfully,
Ryan Lane
On Thu, Mar 25, 2010 at 11:36 AM, Lane, Ryan Ryan.Lane@ocean.navo.navy.mil wrote:
That makes sense. My only concern is that this will require extension developers to dive into core to add features they'd normally add to their own extension. This isn't necessarily a bad thing, as their changes could benefit everyone.
My goal is to not have this done in extensions at all. Everything should be in core, ideally. This encourages people to write clean, reasonable code -- current AuthPlugins duplicate code massively, with all the problems that entails. Each one supports a different set of functionality in different ways. Of course, the interface should also be stable and suitable for extensions, but any ExtAuth plugin in SVN should be in core, not extensions, IMO.
I add users into the groups; I don't add groups to users. I do this by:
- Getting a list of all groups ($user->getAllGroups()), and a list of
groups the user is in ($user->getEffectiveGroups()) 2. I iterate through the list of all groups and: 2a. Add the user into the wiki group if they are in the external group 2b. Remove the user from the wiki group if they are in the wiki group, but no longer in the external group
Effectively, I'm synchronizing the groups every login.
I see. This sounds like it would have a couple of notable issues:
* Special:UserRights would be pretty confusing. Additions and removals would seem to work, but only until the user next logged in. * Group changes would only take effect on login. Users might only log in once a month.
I was thinking that the groups should be implicit, like autoconfirmed, not explicit. This would require a query to the backend on every permissions check, however, for linked accounts. Some type of caching could be optionally used -- maybe just storing the list of groups in the User object and relying on the fact that that's cached.
Well, the proposal mentions allowing the user to choose their own username. That is fine for some extensions (OpenID does this, for instance), and it may even be useful for the LDAP plugin, but I'd like to ensure the plugin can choose the name without giving the user an option.
What are the use-cases for this? What sorts of names would you want to auto-assign? It sounds like this would best be done by exposing some kind of hook, if it's meant to be for stuff as narrow as semi-anonymous users. E.g., just have a hook somewhere in account autocreation that gets passed the User and ExternalUser objects, and let it choose a name if it likes.
It would be *really* nice if this worked for both regular, and auto-authentication, as right now it only works for auto-authentication; I use this for a semi-anonymous user feature, but it only works for auto-auth:
http://ryandlane.com/blog/2009/06/18/semi-anonymous-users-in-mediawiki-using -the-ldap-authentication-extension/
I'm not sure what the difference is between regular and auto-authentication.
Actually, no. LDAP usernames are not assumed to be unique, or stable. Generally, usernames are based on some combination of a person's name. People's names can change for various reasons (marriage, legal name change, etc.). When a person's name changes, their username changes with it. LDAP entries are assumed to have some unique identifier that is often different than the username. In the Posix schema, this is uidNumber. In Active Directory, it is often the Security Identifier (SID), but may also be the userAlternativeName attribute, which is often the case in smart card infrastructures.
In the Posix schema, this is guaranteed to be an integer, but in Active Directory, it will most likely be a string, and can be fairly long.
Okay, now I'm confused. So you're saying that there is no stable, unique identifier that can be used for querying information about a user? The only identifier you can use is the username, and that's unstable? That seems decidedly inconvenient. How is any external system supposed to integrate with the authentication system if there are no stable identifiers?
The LDAP plugin detects the external account was renamed the following way:
On account creation, the plugin records the external ID. On authentication, the plugin queries LDAP, and gets the username back. If the username is different than the local account, the plugin renames the account, or blocks login, which should inform the user to contact the site admin. If the new username is already taken, the plugin blocks login, which should inform the user to contact the site admin.
Allowing the user to choose a new name in this situation wouldn't really make sense, as the extension is assuming the external username matches the local one. Keeping the name the same is also really problematic for most organizations using LDAP, as usernames may be re-used.
ExtAuth takes the philosophy that the wiki name may be totally disconnected from the external name. It would certainly make sense to allow admins to require them to always be the same, though -- as long as the backend doesn't have usernames that MediaWiki doesn't allow.
This actually makes me think of another case that needs to be handled. If the local database has a username that is the same as a username in LDAP, but has an external ID recorded that is different from what is in LDAP, the account in LDAP was likely deleted, but the username was re-used. The plugin should block login in this situation, so that the admin can rename the account to something like "Username (deleted)" or "Username (was <uid>)". This is important from an auditing perspective.
This is only an issue if backends don't expose a stable user id that's guaranteed not to be reused. If LDAP really doesn't expose such a thing, it's crazy :), but I guess it will need to be handled.
All of this assumes that account renaming can be initiated reliably from an authentication extension. This isn't currently possible. Why isn't RenameUser part of core?
I don't know. If it's necessary, it can always be merged to core, IMO. That's the nice thing about developing in core. ;)
On Thu, Mar 25, 2010 at 12:08 PM, Lane, Ryan Ryan.Lane@ocean.navo.navy.mil wrote:
Yeah, I seriously doubt any system is going to have a unique identifier longer than 255 characters. I know after this is implemented I'll find some crazy organization doing this though ;) (like the one that had a user with over 500 groups - crazy).
If they do, they can ALTER TABLE to change it to a larger size if they like.
Effectively, I'm synchronizing the groups every login.
I see. This sounds like it would have a couple of notable issues:
- Special:UserRights would be pretty confusing. Additions and
removals would seem to work, but only until the user next logged in.
This wouldn't be an issue if it updated the external database when adding users. Some backends may not support this... This may be one spot where policy should be decided by the backend.
- Group changes would only take effect on login. Users might only log
in once a month.
This is actually fairly normal for most applications. Operating systems work exactly like this. Web SSO systems are also like this. In most web SSO systems, admins have the ability to invalidate a session when they change something for a user. Maybe an interface could be added to invalidate user sessions? It might also be possible to force a group check on sessions older than a specified time.
I was thinking that the groups should be implicit, like autoconfirmed, not explicit. This would require a query to the backend on every permissions check, however, for linked accounts. Some type of caching could be optionally used -- maybe just storing the list of groups in the User object and relying on the fact that that's cached.
This could work too, but it could be really expensive depending on the length of the cache.
Can you explain how this implementation might be configured? I'm not terribly familiar with the auto-promote stuff.
What are the use-cases for this? What sorts of names would you want to auto-assign? It sounds like this would best be done by exposing some kind of hook, if it's meant to be for stuff as narrow as semi-anonymous users. E.g., just have a hook somewhere in account autocreation that gets passed the User and ExternalUser objects, and let it choose a name if it likes.
It isn't as narrow as that. The LDAP extension may use it for any form of auto-auth, like Kerberos or SSL authentication, where the username provided is something odd like "ryan.lane@example.org", or "Example_Organization__RYAN.LANE.12345". In those cases, the MediaWiki admin probably wants to use an attribute like sAMAccountName (for AD), or uid (which is actually the username, not the uid, in the Posix schema).
I do actually handle this via a hook in my extension, but that hook passes the user's LDAP object to pull attributes from. See this smartcard configuration as an example:
http://www.mediawiki.org/wiki/Extension:LDAP_Authentication/Smartcard_Config uration_Examples#Basic_LDAP_extension_configuration
I'm not sure what the difference is between regular and auto-authentication.
Auto-authentication occurs without user interaction, generally because something else has already done the authentication (like the web server); it is currently provided via the UserLoadAfterLoadFromSession hook. Regular authentication is when the user logs in through SpecialUserlogin.
Okay, now I'm confused. So you're saying that there is no stable, unique identifier that can be used for querying information about a user? The only identifier you can use is the username, and that's unstable? That seems decidedly inconvenient. How is any external system supposed to integrate with the authentication system if there are no stable identifiers?
No. I'm saying there is a stable identifier that is generally not used for authentication. A username is a user friendly identifier that is unique, but not stable. Generally, you integrate with the user friendly identifier, and keep track of the stable identifier, in case the user friendly one changes.
ExtAuth takes the philosophy that the wiki name may be totally disconnected from the external name. It would certainly make sense to allow admins to require them to always be the same, though -- as long as the backend doesn't have usernames that MediaWiki doesn't allow.
This would work well as a configuration option.
Most enterprise wiki admins want to ensure users can't pick their own usernames.
I don't know. If it's necessary, it can always be merged to core, IMO. That's the nice thing about developing in core. ;)
Heh. Good point. I think it will likely need to be merged.
Respectfully,
Ryan Lane
On Thu, Mar 25, 2010 at 7:23 PM, Lane, Ryan Ryan.Lane@ocean.navo.navy.mil wrote:
This wouldn't be an issue if it updated the external database when adding users. Some backends may not support this... This may be one spot where policy should be decided by the backend.
Policy should still be decided in core, but backends would just ignore configuration they don't support. For instance, an autocreate setting of 'view' is unlikely to be supported by backends that don't have cookies (or similar) to autocreate from, so it should be treated as 'login'.
This could work too, but it could be really expensive depending on the length of the cache.
Yes, it depends. If you're authenticating to some MySQL-based forum on the same server, then it's typically just one extra query per view, which is no big deal. In other situations it might be different.
Can you explain how this implementation might be configured? I'm not terribly familiar with the auto-promote stuff.
I don't think autopromote is a good way to go, actually, since it's hard to configure. I think your idea of adding the groups magically is a better one overall. The way it would work is we'd modify User::getEffectiveGroups() to retrieve a list of all external groups (if the user is linked to an external account), then add those to the list of returned groups. It shouldn't be a big issue if someone has 500 groups in this scheme -- although it will make [[Special:Preferences]] a little long. :) So we could just do what you do and only return groups that have keys set in $wgGroupPermissions.
It isn't as narrow as that. The LDAP extension may use it for any form of auto-auth, like Kerberos or SSL authentication, where the username provided is something odd like "ryan.lane@example.org", or "Example_Organization__RYAN.LANE.12345". In those cases, the MediaWiki admin probably wants to use an attribute like sAMAccountName (for AD), or uid (which is actually the username, not the uid, in the Posix schema).
I do actually handle this via a hook in my extension, but that hook passes the user's LDAP object to pull attributes from. See this smartcard configuration as an example:
http://www.mediawiki.org/wiki/Extension:LDAP_Authentication/Smartcard_Config uration_Examples#Basic_LDAP_extension_configuration
We could have a hook that gets passed the ExternalUser object, and add a getProperty() method or such to it. We could also have a $wgExternalAuthUsePropertyForName or something to set the name to a particular property instead of username.
No. I'm saying there is a stable identifier that is generally not used for authentication. A username is a user friendly identifier that is unique, but not stable. Generally, you integrate with the user friendly identifier, and keep track of the stable identifier, in case the user friendly one changes.
Hmm. That means you can't actually retrieve any data about the user at all if they don't enter their password, right? That would explain why nothing would update until the next login, because you can't retrieve the new data until the next login. So LDAP will have to store a lot of things that could just be retrieved on demand with a simple database backend, for instance.
We could add a eu_cache column that's just a blob that backends can throw anything in that they need to cache. Then the LDAP id could be used for eu_external_id, and anything that relies on creating an ExternalUser from id will use the cached data. At a minimum, usergroups would need to be cached, it sounds like.
This could work too, but it could be really expensive depending on the length of the cache.
Yes, it depends. If you're authenticating to some MySQL-based forum on the same server, then it's typically just one extra query per view, which is no big deal. In other situations it might be different.
In a really large LDAP database, you may be doing hundreds of queries, to multiple LDAP servers (if replicated directory trees are being used). The number of queries can vary drastically depending on if nested groups are supported, if memberOf is supported, how you implement the searches, and how accurate you want to be. In environments this large, you are likely to have hundreds or thousands of people logged in simultaneously. On most small to medium LDAP directories, this will range from 1-10 queries per person.
We could have a hook that gets passed the ExternalUser object, and add a getProperty() method or such to it. We could also have a $wgExternalAuthUsePropertyForName or something to set the name to a particular property instead of username.
Hook/getProperty() sounds perfect. I like it more than the global approach, because it may be possible to set more than one property if need be.
Hmm. That means you can't actually retrieve any data about the user at all if they don't enter their password, right? That would explain why nothing would update until the next login, because you can't retrieve the new data until the next login. So LDAP will have to store a lot of things that could just be retrieved on demand with a simple database backend, for instance.
It isn't impossible. If a proxyagent is used, data can be fetched without the user being authenticated. In the LDAP plugin, a proxyagent is required for auto-auth, since the user never actually logs in, in the traditional sense. A proxyagent is supported in regular authentication as well. Some admins don't want to create proxyagents though, for security reasons; since it is possible to operate without one, I allow both solutions.
We could add a eu_cache column that's just a blob that backends can throw anything in that they need to cache. Then the LDAP id could be used for eu_external_id, and anything that relies on creating an ExternalUser from id will use the cached data. At a minimum, usergroups would need to be cached, it sounds like.
Well, user groups are already cached, in a way. When a user is added to a group via $user->addGroup(), it gets added to the local database. As far as I know everything is stored locally for users, in some way. I treat the external database as something to be synced with, not as a real backing store.
Respectfully,
Ryan Lane
wikitech-l@lists.wikimedia.org