Authenticate against ldap using PHP, active directory, while using IE/Firefox - php

This code below checks for the user's credentials against ldap
<?php
$ldaphost = "ldap.domain.com";
$ldapport = 389;
$ds = ldap_connect($ldaphost, $ldapport)
or die("Could not connect to $ldaphost");
if ($ds)
{
$username = "johndoe#domain.com";
$upasswd = "pass";
$ldapbind = ldap_bind($ds, $username, $upasswd);
if ($ldapbind)
{print "Congratulations! $username is authenticated.";}
else
{print "Access Denied!";}
}
?>
My users use Firefox and IE, and I know that can pass their ActiveDirectory credentials seamlessly.
I just want to check the AD group to see if that username is found in there, if so, display the page, otherwise prompt to enter in credentials.
Since our users are already logged into the domain controller, I want to grab their username, check to see if it was found in the specific group, then let them in, otherwise prompt user to input credentials. How is this possible?

You actually do not need to communicate with the Active Directory server from your PP code to achieve what you want given the fact that you use IIS as your web server.
The key word here is Integrated Windows Authentication - that's the wording djn looked for. If this option is turned on (and anonymous access is denied) IIS will check the supplied credentials against the Active Directory and the NTFS filesystem privileges of the requested resources. You can therefore control access to your files using simple NTFS access control mechanisms.
If your users use IE they even don't have to type in their credentials as this is done automatically via so called SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) and its underlying mechanisms Kerberos or NTLMSSP depending on what your client and server is capable of processing.
As far as I know Firefox is able to hand over the Windows logon credentials to your server automatically too. You ony have to adjust a configuration option to turn on that feature - don't know if this information is still valid with Firefox 3.5.x.
If you're running Apache on a *nix-system you'll have to resort to some server-side-module to handle a Integrated Windows Authentication-like system. Possible options are (don't know whether they are actually still maintained or stable):
mod_auth_ntlm_winbind
mod_auth_kerb
mod_ntlm
For Apache on Windows there are:
mod_ntlm (outdated; not the same as mod_ntlm above)
mod_auth_sspi (successor of mod_ntlm)
Please be aware that most of these modules seem to be very old.

Working just now on a similar setup: I skipped all of that LDAP stuff having the web server authenticating the client with AD before letting him in (sorry, I can't remember what's this called in the M$ alternate universe).
If the client reaches the PHP script he's in AD and I have his username both in $_SERVER["AUTH_USER"] and in $_SERVER["LOGON_USER"], otherwise he never gets to the script.

Related

Using built-in IIS AD authentication by PHP CGI under an IdentityPool

I have a PHP website running as an App on IIS.
The app is using a specific Identity that runs all php-cgi.exe processes under NetworkService user that has access to the AD server.
There's also another .NET app in the IIS where it's using the same identity and can log into the AD using the class System.Web.Security.FormsAuthentication and uses Forms Authentication in the Authentication settings in IIS. I tried copying the settings over but to no avail.
The .NET code:
...
using System.Web.Security.Membership.ValidateUser;
...
public ActionResult Login(Login model, string route)
{
if (Membership.ValidateUser(model.Username, model.Password)) {
FormsAuthentication.SetAuthCookie(model.Username);
return Redirect(route);
}
return RedirectHome();
}
My code running on IIS with PHP CGI, impersonate is on on IIS level and php.ini level:
public function login()
{
$ldapHost = 'ldap://spacemudd-ad';
// PHP should use server's (iis) credentials when connecting. (impersonate)
$connection = ldap_connect($ldapHost);
// This always fails.
//
// "ldap_bind(): Unable to bind to server: Can't contact LDAP server"
//
// I believe due to the php-cgi.exe not sending the request
// to the AD server through the IdentityPool's user (NetworkService)
// even though in the TaskManager, the php-cgi.exe shows the owner is
// NetworkService?
//
$ldapBind = ldap_bind($connection);
// TODO: Search the AD directory for the user to be authenticated.
}
php.ini configuration:
fastcgi.impersonate = 1
ref. questions:
Setting permission for PHP (or I_USER [I'm not sure here...]) to connect to iisweb.vbs
Impersonate Domain User with Integrated Pipeline
https://serverfault.com/questions/313100/iis-forms-authentication-php-asp-net-server-side-login (didn't attempt but looks promising -- will attempt tomorrow)
PHP LDAP binding AD with the server's user account (doing ldap_bind() without setting credentials)
Update 24-11-2018: The sysadmin gave me these information:
config.md:
<add name="ADConnectionString" connectionString="LDAP://spacelantern-central/DC=spacelantern,DC=com" />
<membership defaultProvider="ADMembershipProvider">
<providers>
<clear />
<add name="ADMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider" connectionStringName="ADConnectionString" attributeMapUsername="sAMAccountName" />
</providers>
</membership>
code.md:
if (Membership.ValidateUser("userid", "password"))
{
//
}
I suspect you have two problems. First, this:
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, $ldapPort);
What is the value in $ldapPort? The name of that variable suggests that it contains the TCP port to connect to, but that is not what LDAP_OPT_PROTOCOL_VERSION is for.
LDAP_OPT_PROTOCOL_VERSION is for the LDAP version to use when communicating. For AD, you can set it to 3, since AD supports LDAPv3:
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3);
Second, if you need to connect to a different port than the default (389), then you need to pass it in the call to ldap_connect:
$connection = #ldap_connect($ldapHost, $ldapPort);

Single-Sign-On from Windows Workstation to PHP script running on Linux server that is not part of the same domain

Edit: After researching further this morning I have tried to make my post more specific:
I have a php script running on a web server in my company's data centre. A client of ours needs to access that script from their user's windows workstations using single-sign-on. The php server does not have access to the domain that the windows users are logged on to.
Is there a way for the users to open Internet Explorer (or similar), go to the website I am developing and the website 'know' their username? The site will also need to deny access to anyone that is not part of the client's domain.
So to be clear, the main issue I am experiencing is that the server the php script runs on IS NOT part of the domain that the users accessing it are on.
Side note: if true SSO is not possible and the user has to retype their username and password again, that is ok, but I guess this would mean the authentication is done by the php script, which would be impossible because it cannot access the clients AD server.
Thanks :)
Original post:
Just after some links or general information to begin with. I am building a php based website on example1.com but to access it, users need to authenticate against active directory on example2.local. The domain controller for example2.local is not accessible on the internet. Users will be logged on to Windows workstations in example2.local domain and have internet accessibility though.
Is there any way this can work? I have been told to look into 'single sign on', but everything I've found so far suggests the ad domain should be example2.com (not .local). A colleague here assures me that domain controllers are not normally accessible to the wider internet.. so how is this normally done?
Also the client this is for has emphasized the need for security.
Thanks
Edit: After reading some more about SSO I'm possibly more confused, but I would like to add that all my php application needs to know is that 1) the user is authenticated in their domain and 2) their username. What is the simplest way to achieve this? Thanks!
http://www.php.net/manual/en/book.ldap.php
I actually just implemented a basic LDAP authentication script. This was my first draft of the script before I changed and messed with it to fit with my setup. This basically connects to the server, if not the scrpt is killed. Then tries to authenticate the given username and password, if not, it fails. Quick and simple.
$ldapHost = "example2.com";
$ldapPort = 666;
$ldapBaseDn = "ldap base dn here";
$username = "username";
$password = "password";
$ldapUserDn = "uid=$username,".$ldapBaseDn;
echo "LDAP query test\n";
echo "Connecting ...\n";
$ldapConn = ldap_connect($ldapHost, $ldapPort)
or die("Unable to connect to LDAP server: $ldapHost\n");
echo "Authenticating user ...\n";
$isValid = ldap_bind($ldapConn, $ldapUserDn, $password)
or die("Unable to authenticate user: $username\n");
echo "User $username is successfully authenticated!\n";
echo "Closing connection ...\n";
ldap_close($ldapConn);
exit();
?>

How to perform a LDAP SASL bind to Active Directory using GSS-API mech in PHP from Windows?

I have an Active Directory server and a Windows WAMP server hosting PHP web applications that need to be able to authenticate to Active Directory using Kerberos.
I was able to easily connect and bind to the Active Directory host using some sample PHP code, but I'm not sure how to do so with Kerberos. I have see many forums and blogs detailing how to do this on *NIX machines, but that doesn't help me with my situation.
I did use Wireshark and Fiddler to confirm that there is no Kerberos or NTLM negotiating happening.
Sample code I used to connect and bind to LDAP:
<?php
$ldaphost = "example.domain.com";
$ldapport = 389;
$ldapuser = "user";
$ldappass = "password";
$ldapconn = ldap_connect( $ldaphost, $ldapport )
or die( "Unable to connect to the LDAP server {$ldaphost}" );
if ($ldapconn)
{
$ldapbind = ldap_bind($ldapconn, $ldapuser, $ldappass);
if ($ldapbind)
{
echo "LDAP connection successful";
}
else
{
echo "LDAP connction failed";
}
}
?>
Any help will be greatly appreciated, thanks!
Update: I've been wrestling with this all day and I think I need to use ldap_sasl_bind(), possibly using GSSAPI as the mechanism... No matter what parameters I put in to ldap_sasl_bind(), I get the following error: 'Unable to bind to server: Unknown authentication method'
I'm not sure how to implement GSSAPI, but some examples I've seen show using ldap_start_tls(), but I keep getting a 'Unable to start TLS: Server is unavailable' error.
I don't know if anyone knows anything about ldap_sasl_bind() (which is undocumented by PHP) or ldap_start_tls, but if this is the way I should be going, please point me in the right direction.
I cannot help with the Kerberos issue yet, as I am still struggling with it myself. However, I can point you in the right direction for TLS. TLS will at least prevent your credentials from being transmitted over the network in clear text. TLS requires proper configuration of OpenLDAP. At the very least, you can configure your client to not request or check any server certificates. You do this by adding the following line to the top of your ldap.conf configuration file.
TLS_REQCERT never
Your ldap.conf file should be located in C:\ or C:\openldap\sysconf, depending on your version of PHP and OpenLDAP. The file most likely does not yet exist in your setup. You may also be able to set the configuration via an environment variable as well putenv(TLS_REQCERT=never);, but I have not tried that myself, and there appear to be mixed results reported by others.
What you need to do: Make sure that the LDAP interface in PHP is compiled against SASL, supports GSS-API mech and either uses keytabs or the Windows-own SSPI interface. Good luck.
I solved this problem on windows by creating executable based on c++ ldap_bind_s. I use this executable as a command line with the parameters: host, username,password. This is the only way I got it work for GSSAPI.
WINLDAPAPI ULONG LDAPAPI ldap_bind_s(
LDAP *ld,
const PSTR dn,
const PCHAR cred,
ULONG method
);
I used LDAP_AUTH_NEGOTIATE.

php access to remote database

Help!
I have a PHP (PHP 5.2.5) script on HOST1 trying to connect to an MySql database HOST2. Both hosts are in Shared Host environments controlled through CPanel.
HOST2 is set to allow remote database connections from HOST1.
The PHP connect I'm using is:-
$h2 = IPADDRESS;
$dbu = DBUSER;
$dbp = DBPASS;
$DBlink = mysql_connect($h2, $dbu, $dbp);
This always fails with:-
Access denied for user '<dbusername>'#'***SOMESTRING***' (using password: YES)
nb: SOMESTRING looks like it could be something to do with the shared host environment.
Any ideas???
BTW: I can make remote connections to HOST2 from my laptop using OpenOffice via ODBC, and SQLyog. The SQLyog and ODBC settings are exactly the same as the PHP script is trying to use.
somestring is probably the reverse-lookup for your web-server.
Can you modify privileges from your cPanel? Have you done anything to allow access from your workstation (ODBC)?
The error-message seems to indicate that you have network-access to the mysql-server, but not privileges for your username from that specific host.
If you're allowed to grant privileges for your database, invoking:
GRANT SELECT ON database.* TO username#ip.address.of.host1 IDENTIFIED BY 'password'
might work for you. I just wrote this out of my head, you might want to doublecheck the syntax in mysql-docs.
Have you read the MySQL documentation on Causes of Access denied Errors?
Have you contacted support for your hosting provider? They should have access to troubleshoot the database connection. People on the internet do not have access.
Do you need to specify the database name? Your account might have access to connect only to a specific database. The mysql_connect() function does not allow you do specify the database, but new mysqli() does. I'm not sure if this is relevant -- it might allow you to connect but give you errors when you try to query tables that aren't in your database.
Are you sure you're using the right password? MySQL allows each account to have a different password per client host. Admittedly, this is not a common configuration, but it's possible. Your hosting provider should be able to tell you.
Just some ideas:
HOST1 does not have remote access to HOST2 (shared host is disallowing)
MySQL account does not have access from HOST1 (IP address specified on account creation, or wildcard)
Edit:
In response to your comment, I meant that HOST1 cannot get to the MySQL port on HOST2. Web services will work, of course, because port 80 is open to the public. As another user pointed out though, you are getting a response, so you are reaching it. I would try specifying the DB, and double checking the account creation command you ran.
For the second piece, I meant this: http://dev.mysql.com/doc/refman/5.0/en/adding-users.html
You can specify what host the username can connect from. If it isn't set to HOST2's IP or the wildcard, HOST2 can't log in with those credentials.
The error message means that you can contact the mySql server, but the user you are trying to log in as, does not have access.
Either the user does not have access at all, or it has access locally, but not from the host you are connecting from.
You should try to use the hostname and port like $h2 = IPADDRESS:3307;

Authenticating in PHP using LDAP through Active Directory

I'm looking for a way to authenticate users through LDAP with PHP (with Active Directory being the provider). Ideally, it should be able to run on IIS 7 (adLDAP does it on Apache). Anyone had done anything similar, with success?
Edit: I'd prefer a library/class with code that's ready to go... It'd be silly to invent the wheel when someone has already done so.
Importing a whole library seems inefficient when all you need is essentially two lines of code...
$ldap = ldap_connect("ldap.example.com");
if ($bind = ldap_bind($ldap, $_POST['username'], $_POST['password'])) {
// log them in!
} else {
// error message
}
You would think that simply authenticating a user in Active Directory would be a pretty simple process using LDAP in PHP without the need for a library. But there are a lot of things that can complicate it pretty fast:
You must validate input. An empty username/password would pass otherwise.
You should ensure the username/password is properly encoded when binding.
You should be encrypting the connection using TLS.
Using separate LDAP servers for redundancy in case one is down.
Getting an informative error message if authentication fails.
It's actually easier in most cases to use a LDAP library supporting the above. I ultimately ended up rolling my own library which handles all the above points: LdapTools (Well, not just for authentication, it can do much more). It can be used like the following:
use LdapTools\Configuration;
use LdapTools\DomainConfiguration;
use LdapTools\LdapManager;
$domain = (new DomainConfiguration('example.com'))
->setUsername('username') # A separate AD service account used by your app
->setPassword('password')
->setServers(['dc1', 'dc2', 'dc3'])
->setUseTls(true);
$config = new Configuration($domain);
$ldap = new LdapManager($config);
if (!$ldap->authenticate($username, $password, $message)) {
echo "Error: $message";
} else {
// Do something...
}
The authenticate call above will:
Validate that neither the username or password is empty.
Ensure the username/password is properly encoded (UTF-8 by default)
Try an alternate LDAP server in case one is down.
Encrypt the authentication request using TLS.
Provide additional information if it failed (ie. locked/disabled account, etc)
There are other libraries to do this too (Such as Adldap2). However, I felt compelled enough to provide some additional information as the most up-voted answer is actually a security risk to rely on with no input validation done and not using TLS.
I do this simply by passing the user credentials to ldap_bind().
http://php.net/manual/en/function.ldap-bind.php
If the account can bind to LDAP, it's valid; if it can't, it's not. If all you're doing is authentication (not account management), I don't see the need for a library.
I like the Zend_Ldap Class, you can use only this class in your project, without the Zend Framework.
PHP has libraries: http://ca.php.net/ldap
PEAR also has a number of packages: http://pear.php.net/search.php?q=ldap&in=packages&x=0&y=0
I haven't used either, but I was going to at one point and they seemed like they should work.
For those looking for a complete example check out http://www.exchangecore.com/blog/how-use-ldap-active-directory-authentication-php/.
I have tested this connecting to both Windows Server 2003 and Windows Server 2008 R2 domain controllers from a Windows Server 2003 Web Server (IIS6) and from a windows server 2012 enterprise running IIS 8.

Categories