Extension:NTLMActiveDirectory

The NTLMActiveDirectory extension (and wiki page) is a fork of the AutomaticREMOTE USER extension written specifically for Windows server. Thus this is a Windows only extension, using the php_com_dotnet extension to create ADSI COM objects.

For AD users on Windows servers, that means there is zero configuration required. The extension uses ADSI to find your Global Catalog and search the directory for users.

LocalSettings.php
Place the following two lines in your LocalSettings.php file:

Configure REMOTE_USER
Depending on your version of Internet Information Services (IIS) Manager, your navigation may be slightly different. The instructions below are specified for a corporate server running IIS v8 on Windows Server 2012. It's very similar to Windows Server 2008. Windows 2003 might be different.

To enable simple authentication navigate to the following paths:
 * 1) Open IIS Manager
 * 2) (Server Name) &rarr; Sites &rarr; Your Website &rarr; Your wiki directory (if not in the root)
 * 3) From "Features View" double click, "Authentication"
 * 4) * Disable Anonymous Authentication
 * 5) * Enable Windows Authentication (HTTP 401 Challenge)
 * 6) * Enable Basic Authentication (optional)

Windows authentication is an IIS feature in server 2012. To enable it, use the following steps:
 * 1) Open server manager
 * 2) Click Add roles and features
 * 3) Click Next until you get to server roles
 * 4) Expand Web Server (IIS) &rarr; Web Server &rarr; Security
 * 5) *Check off Windows Authentication
 * 6) *Check off Basic Authentication (optional - if you need to support ancient browsers or cURL)
 * 7) Click next and finish through the wizard

Compatibility Matrix
This extension was developed on MW 1.20, Windows 2012 and PHP 5.3. If anyone else has it working on a different configuration, please let me know.

Configuration
The default configuration is as follows:
 * Authenticated users will automatically have wiki users created in the form of DOMAIN\username
 * Local logins will be impossible

Sample Configuration
Though a zero configuration module, the below config shows you how to leverage some of the advanced features

User format
The extension takes the REMOTE_USER variable passed in from the webserver, and does a lookup in AD to get the user object. This gives you some different options for how the wiki user should be formatted. The options are:

Custom Function
If the above defaults are not suitable, you can set this property to the name of a callback function. The function must return a string, and accept an array as a parameter. Your local settings might have something like this: The structure of the array is as follows:

Exempt Users
You can exempt certain users from participating in automatic login. These users will fall through to the default MW login. This list is Wiki users who should not be checked against the REMOTE_USER variable. The default is WikiSysop. Additional users can be added thusly:

Wiki Users
By default, every user who connects will have a wiki account created, and will be automatically signed into that account. You can override this behavior with the WikiUserGroups array. Users who are a member of any of these groups will have an account created. All other users will not have an account, and will not be able to create a local user. See Wiki Local Users below for local users. Groups must be in the DOMAIN\GroupName format, and are added as follows:

Allow local login
By default, no one is allowed to login with a local account. Users which are in groups added to the WikiLocalUserGroups array will have the full suite of login tools available. This is useful for some support users, but in most cases is not desirable. Groups must be in the DOMAIN\GroupName format, and are added as follows:

Group Mapping
Using Lockdown you can control access to different namespaces by wiki group. Using group mapping, you can map domain groups to wiki groups. The syntax is as follows

How It Works
When the user first hits the wiki, the web server authenticates the user and sets the REMOTE_USER variable. The MediaWiki code is then invoked. At the end of Setup.php, before any real processing begins, the extension's hook is called. This code depends primarily on the fact that user is always authenticated by the web server prior to any MediaWiki code being executed.

If the user already has an existing, valid MediaWiki session and account, the hook takes no further action. MediaWiki already has what it needs.

If the user has an existing valid MediaWiki account, but not a session, the hook simply ensures that MediaWiki uses the username in REMOTE_USER in creating a session, cookies, etc, and takes no further action.

If the user has not created an account, the hook uses MediaWiki's initUser function to create an account, and sets various default user-options. See the hook's initUser function to change these default options. The hook then issues a Location directive to the browser, using the same URL that was called. When the browser reloads, the user account has been created, a session is now created, and MediaWiki behaves as normal.

Cookies
If the user has cookies turned off, they will probably find themselves in an endless redirection loop.

Password
Contrary to previous versions of Mediawiki, the authenticateUserData function will automatically fail if an empty password is provided, e.g., within a faux login call; for MediaWiki v1.17.0, try using just a space instead.

Backups
If your backups don't work, try setting the REMOTE_USER environment variable manually:

Secure Server Settings
Make sure your server sets HTTPS_KEYSIZE only when in SSL/https mode. If not, change the hooking function accordingly.

Implementation Details
Parts of this section may be out-of-date.

Initialization
This extension makes use of the "Hook" at the end of Setup.php. This allows the extension to perform initialisation in the fully initialized environment.

The extension's initialization code adds the name of the extension's primary workhorse function to $wgExtensionFunctions. If the array doesn't exist or is not an array, it is assumed that it is a single string and then converted into an array. All this is done only if REMOTE_USER is actually set. If it's not set, there is no point to the extension.

AuthPlugin routines
Several routines from AuthPlugin must be overridden for correct operation to occur.


 * userExists must return true always. The method is misleading. It's only called by MediaWiki in determining whether the user exists in the security context, not whether the user is in the MediaWiki database.
 * authenticate is a tricky one. My code returns true whenever REMOTE_USER is set, false otherwise. One might want anonymous users to see the site, but not be authenticated to make changes. This is why this depends on the REMOTE_USER setting.
 * autoCreate should always be true. This gets checked only within initUser, ie, when the Web Server has authenticated a user unknown to the Wiki.
 * strict is set to true based on the word of the author of the previous version of this extension.
 * modifyUITemplate configures the user interface so that the user does not see configuration options which don't apply to him. I'm not certain this works correctly.

initUser

 * initUser -- configure this routine according to your particular environment to update the email address and other information in the MediaWiki database to match the authentication source.

The hooking function

 * 1) If the page requested is either Special:Userlogout or Special:Userlogin, do nothing.
 * 2) Try to load the User session. If successful, and the User is logged in, do nothing.
 * 3) Call User::newFromName ( REMOTE_USER ). If the username is invalid, just do nothing.
 * 4) Set $wgUser to the user info returned from newFromName.
 * 5) If the getID is non-zero, the user is already known to MediaWiki:
 * 6) set _REQUEST['wpName'] to the REMOTE_USER (This seems to be necessary from LoginForm)
 * 7) return
 * 8) Create a New Wiki User
 * 9) Create a new LoginForm. A form isn't actually displayed, but the constructor includes code that sets up a quasi-global user variable.
 * 10) Call initUser
 * 11) * wgUser->initUser will invoke wgAuth->initUser.
 * 12) * That's where the user defaults are set. You can also set them here after the call to initUser
 * 13) Call wgUser->saveSettings. This is required to save the settings from above to the database and appears to be a bug in LoginForm::initUser.
 * 14) Re-create the calling URL and redirect the browser to it.  Note: the HTTPS portion has not been tested and may be server-specific!

Known Issues
Some issues are known, and aren't really "issues", but may eventually get workarounds.

Built-in groups don't expand
Built in groups like Domain Users and Domain Admins don't seem to expand properly with ADSI.

UPN is optional
Even now, the UPN is optional, and at least in server 2012 is not set for built-in users like Administrator. The adUserGet function uses the UPN to find the user, and will fail if one isn't specified. A workaround for this is to query for samAccountName and then filter the result set based on DC=netbiosdomain, in the same way that adGroupGet works (since groups don't have a UPN).

Local groups are not checked
Even though domain entities can be part of local security groups, the local groups do not appear in the domain objects "memberOf" property, so they will not be expanded.

Case sensitive username
MW usernames are case sensitive, but AD usernames are not. If CONTOSO\John.Smith becomes CONTOSO\john.smith, MW will create a new user object for this person. Use Extension:MergeAndDelete.