2

I have an IIS application (AngularJS and PHP), authentication is done with Windows Authentication (Anonymous Authentication is disabled). I would like to have a button that whenever clicked, will lookup active directory users. It works successfully with the code below:

$ldap_server = "ldap://MyDomain.local";
$auth_user = "MyUser@MyDomain";
$auth_pass = "myPass";
$base_dn = "OU=MyDomain, DC=MyDomain, DC=local";
$filter = "(&(objectClass=user)(objectCategory=person)(cn=*))";

if (!($connect=@ldap_connect($ldap_server))) {
    die("Could not connect to ldap server");
}

if (!($bind=@ldap_bind($connect, $auth_user, $auth_pass))) {
     die("Unable to bind to server: ". ldap_error($connect) . " (" . ldap_errno($connect) . ")");
}

if (!($search=@ldap_search($connect, $base_dn, $filter))) {
     die("Unable to search ldap server: ". ldap_error($connect) . " (" . ldap_errno($connect) . ")");
}

However, the user has already supplied credentials when logging in (through IIS Windows Authentication) and I would like to use the same user credentials (or actually impersonating the user). Can I do so without asking for username and password?

I was trying to get server's variables ({$_SERVER['AUTH_USER']} and {$_SERVER['AUTH_PASSWORD']}). Only the user is populated (makes sense...).

I also tried skipping ldap_bind(), calling it only with the $connect parameter but I always get the same error: Unable to search ldap server: Operations error (1)

Of course I can store a dedicated user+pass in PHP, but would like to avoid that and use the logged in user authentication.

Thanks!

Elad
  • 123
  • 1
  • 7
  • Ouch. Usually, the server does not even see the users password (depending on the configuration of the IIS, browser, client machine), instead Kerberos is used. At this point things start to get tricky. You can grant the user that IIS runs under (usually the computer) the flag "trusted for delegation". But even then, PHP does not support GSSAPI binds. So you are out of luck there. – Johannes Kuhn May 04 '16 at 08:24
  • Thanks @Johannes. It just feels odd that I'm running with an authenticated user context that has all the rights to search active directory, but I need to ask for credentials again. Feels like we're missing something... – Elad May 04 '16 at 09:03
  • I have the same need & I feel that I have walked this path before. The first step was to configure IIS to use impersonation. That allowed the php programs running on the web server to use the security token from the client workstation where they user was already windows authenticated instead of the generic security context that the web server was running under. It allowed the web server to "impersonate" the workstation user. It worked for resources on the web server itself. The next step is called "delegation" and is described in many places on the web. Search "double hop delegation kerberos" – Ted Cohen Jun 29 '16 at 09:47
  • The first hop is from the work station to the web server and allows access to local resources on the web server using impersonation. The second hop is from the web server to another server using delegation and allows access to "network resources" on other servers. At the time that I set this up, it was only supported using kerberos. It was easy to configure once I enabled kerberos. That allowed php applications to talk to other servers, in particular file servers using the security token from the original work station. It works great for talking to remote files servers with ie. – Ted Cohen Jun 29 '16 at 09:55
  • There is an additional tweak to get it to work chrome. where you have to white list the additional servers that you want to be able to use delegation. It is not difficult to do using a group policy or by individual registry entries on each chrome workstation. It is my understanding that I can get the double hop to work from the file server to SQL servers and exchange servers as well but I have not tried it yet. My gut tells me that it should also work with an active directory server. There is an anonymous bind in LDAP (leave the user id and password parameters off the regular bind. – Ted Cohen Jun 29 '16 at 09:59
  • People are advised to disable anonymous binds to active directory and by now, that may be the default. I think that you need to do a bid when using LDAP to get to AD, but as you have stated, you can know the UID of the logged in user but never the PW. What would be ideal is if you can enable delegation using kerberos, do an anonomous bind in LDAP and then only see in AD the resources that the user logged into the client workstation are allowed to see. I have never tried this but will do so this week. For now, you may want to review: https://msdn.microsoft.com/en-us/library/ff647465.aspx – Ted Cohen Jun 29 '16 at 10:10
  • http://windowsitpro.com/active-directory/q-how-do-i-enable-anonymous-ldap-binds-windows-server-2008-active-directory-ad deals with enabling anonymous binds. In itself, not an ideal solution. but may be part of a larger solution that is ideal. http://stackoverflow.com/questions/25039083/php-ldap-binding-ad-with-the-servers-user-account?rq=1 is a similar question. The accepted answer is to use an anonymous bind as I have suggested above. – Ted Cohen Jun 29 '16 at 10:16
  • @TedCohen, thank you so much!! I bet this will work. However, unfortunately, I do not control the AD (it's the customer's), so I can't really change to anonymous binding... – Elad Jul 04 '16 at 08:05
  • My testing was inconclusive but I did discover something disconcerting in the process. Before I get into that, I tested anonymous bind and it did not do what I hoped. That either means that it won't work or that I have something misconfigured. I also tried without a bind at all and as expected, that did not work. I did not want to put my user id and password in a PHP script where any one that was allowed to run web pages on our intranet could open and read it. So I asked our sysadmins to create a windows login that could not do anything but read the active directory ... – Ted Cohen Jul 05 '16 at 15:06
  • I stored that user id and PWD in the script and have been living with it. What I found out during testing is that once I bind to LDAP, I am no longer running under the security context (think user id) of the logged in user for anything. I am now running under the user id of the stripped down AD Reader user id. In the current application, I only needed to look up LDAP data , display it and end the script so there was no adverse effect. But what if I needed to create a file or access a database etc. I would not be able to do that. ... – Ted Cohen Jul 05 '16 at 15:16
  • I don't know how to return the the security context of the actual user when done with LDAP access. This brings to mind a long shot. In old dos command line UI when prompted for a User Id to access a file if you put in a UID for which the OS did not hold a security token, it asked for a PW and got one from the domain controller. If you specified that you wanted to access the resource using a UID that you had already used to login, it did not ask for a PW and just used the existing one. We know the UID of the current user. What if we issue the required LDAP bind with the current UID and no PWD. – Ted Cohen Jul 05 '16 at 15:22
  • You wrote in the OP that you wanted to try that but that the web server provided the UID but not the PWD. You did not say if you tried and got and error or if you did not try because the PWD was blank. So I tried that and learned that I was able to bind. If I omited the the PWD parm or passed an empty PWD, the bind worked (as did the anon bind). If I supplied the UID and valid PWD, the bind also worked. If I supplied the UID and an invalid PWD, the bind failed with the msg " Invalid credentials". Even though the bind worked, the subsequent search only worked when I passed in my explicit PWD. – Ted Cohen Jul 05 '16 at 15:34
  • Without the PWD, the search failed with the msg "Operations Error". I will Google search that in the context of LDAP and see if I can learn more about what that means. – Ted Cohen Jul 05 '16 at 15:37

1 Answers1

1

You can achieve LDAP and other types of communication on the server-side by using the following PHP + Powershell solution. The code sample below lets me show or hide the web page content based on LOGON_USER (ng-if is AngularJS directive, which I use to show/hide the contents of ):

PHP:

<span ng-if="<?php $ADUserName = $_SERVER['LOGON_USER'];$output = shell_exec('powershell -file chkgrp.ps1 -ADUserName "'.$ADUserName.'"');echo $output; ?>">YOUR HTML CODE</span>

chkgrp.ps1:

Param([string]$ADUserName); Import-Module ActiveDirectory; $User=$ADUserName.split("\")[1]; $Group="YOUR GROUP"; $Members = Get-ADGroupMember -Identity $Group -Recursive | Select -ExpandProperty SamAccountName; If ($Members -contains $User) {write-output "true"} Else {write-output "false"}

-CJ

CyberJam
  • 11
  • 2
  • Thanks @CyberJam. This is somewhat useful but a bit clumsy and introduces a security risk (shell_exec). Besides, spawning a PowerShell process each time a server side call happens will introduce performance issues. – Elad Feb 06 '17 at 09:48
  • Oh, btw, I just realized that passing the LOGON_USER variable is not even needed since the impersonation is in play here, so Powershell will be aware of the Domain\username. And I agree the security and performance must be considered and prioritized as well. – CyberJam Feb 06 '17 at 23:04