Spring Security LDAP "bind must be completed on the connection" - php

I need to create a SpringBoot service and provide an authentication service using LDAP.
I followed this example and it works fine for me using an embedded local ldap server (as suggested into the tutorial)
Now I tried to use the official company LDAP server but I got this error:
Uncategorized exception occured during LDAP processing; nested exception is javax.naming.NamingException: [LDAP: error code 1 - 000004DC: LdapErr: DSID-0C090A5C, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v4563];
This error seems related to a LDAP bind request that it's necessary. But how can I add this into the Spring Security LDAP?
This is the code where I tried to integrate the company LDAP connection:
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userDnPatterns("userPrincipalName={0},ou=users")
.groupSearchBase("ou=users")
.contextSource()
.url("ldap://companyhost:389/dc=aa,dc=company,dc=com")
.and()
.passwordCompare()
.passwordEncoder(new BCryptPasswordEncoder())
.passwordAttribute("userPassword");
}
I tried also with my PHP example (using the official company active directory and this works fine)
// connect to ldap server
$ad = ldap_connect("ldap://".LDAP_HOST, LDAP_PORT)
or die("Could not connect to LDAP server.");
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ad, LDAP_OPT_REFERRALS, 0);
$user = $_POST['username'];
$password = $_POST['password'];
if (ldap_bind($ad, "$user"."#".LDAP_HOST, $password)) {
// User authenticated
}

The Directory Server you are connecting to does not allow 'anonymous' access, i.e. your application first has to authenticate beforehand (via and LDAP BIND operation) before performing queries. LdapContextSource
Furthermore Using password comparision ('passwordCompare()') is not LDAP best practice (I don't know why this is still in the Spring docs), itstead an LDAP BIND operation should be used to authenticate users. This lets the server compare the password as only the server knows which password storage scheme was used on the server side when the password was saved.
Using 'userDnPattern' is also not LDAP best practices as this means you have to know the Directory Information Tree (DIT) of the LDAP Directory Server. Instead let the Directory Server determine the Distinguished Name (DN) by performa search leveraging 'userSearchBase', 'userSearchFilter' LdapAuthenticationProviderConfigurer

Related

LDAP CHANGE PASSWORD PHP

I want to change user's password [unicodePwd] on Windows Active Directory using PHP LDAP.
I am using Windows Active Directory via PHP LDAP.
I don't have any issues connection to it.
I don't have any issues collecting data.
I don't have any issues changing attributes using ldap_mod_replace or ldap_modify
except for the "unicodePwd".
*note that this works
$user['telephonenumber'] = '1234567890';
*note that this does'nt work
$user['unicodePwd'] = mb_convert_encoding('my_new_password', "UTF-16LE");
// CODE
$result = ldap_modify($ldap, $dn, $user);
return ldap_error($ldap);
// CODE
// ERROR ON CHANGING unicodePwd
ldap_modify(): Modify: Server is unwilling to perform
// NO ERROR FOR telephonenumber
06/11/2018 Problem,
I can't setup my server to have ldap over ssl.
Already tried installing AD CS, nothing worked so far. Still configuring my server any idea about installing CA(Certificate Authority) to be used in LDAP over SSL?
06/20/2018 Problem, NEW PROBLEM
Already setup LDAP OVER SSL, i can also use ldap using the
cmd->ldp; port 389, and 636 with ssl is good.
but when i run it in my php using port 636 or ldaps://servername this is the error,
ldap_bind(): Unable to bind to server: Can't contact LDAP server
You need to be on a secured connection to modify a password (and probably other security related options).
Add the following before you call ldap_bind():
ldap_start_tls($ldap);
This is a good idea even if you aren't trying to change a password as otherwise your bind operation is cleartext and can be sniffed.
If you see this error:
Warning: ldap_start_tls(): Unable to start TLS: Connect error in ...
You can workaround the issue by adding the following line before you call ldap_connect:
putenv('LDAPTLS_REQCERT=never');
WARNING: This disables checking the validity of the LDAP server certificate! Ideally you should add the server certificate (or its signing CA) to your trusted store.

Authenticate users against Azure Active Directory from PHP web application

I have a website in PHP and want to authentificate users against Azure Active Directory. With ldap_connect and bind I have no problems to do this to a local AD-Server in our company.
function checkADAccount($username, $password)
{
$adServer = "myADServer";
$ldaprdn = 'myDomain' . "\\" . $username;
$ldap = ldap_connect($adServer);
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
$bind = #ldap_bind($ldap, $ldaprdn, $password);
if ($bind) {
#ldap_close($ldap); // Verbindung schließen
return true;
} else {
return false;
}
}
But my application is hosted at Amazon Web Services (AWS) and is not in the same domain, so I can't use this way.
With ldap_connect and bind this functions to a local AD-Server in our company. But my application is hosted at Amazon Web Services (AWS) and is not in the same domain, so I can't use this way.
I tested graphapi with the ClientId and key for my company from Azure. So I can read the users-data, but I don't see any possibility to check a user/password combination. I only want to check, if there exists a user with this password, I don't need to read it from there.
So I tried to modify the LDAP-solution from above by changing the parameter of the adServer and of the user
$ldaprdn = 'sAMAccountname=' . $username . ',cn=users' . ',dc=myDomain,dc=com';
But I allwaws get: "Warning: ldap_bind(): Unable to bind to server: Can't contact LDAP server ". I tried for this multiple versions for the adServer but any delievers a binding.
Do you have any idea where is the error. I suggest with ldap_connect is the wron way, espacially I don't know which server-adress is the right one and how I had to tell the ClientId and key.
Currently, Azure AD doesn't support LDAP connection. It provides OAuth2 authentication and authorization. You can refer to Authentication Scenarios for Azure AD for detailed Azure AD scenarios.
For your requirement to authenticate users in your domain, you can leverage this code sample to implement authentication via Azure AD.
Otherwise, you can follow Authorization Code Grant Flow build your custom code to authenticate your users.
Any further concern, please feel free to let me know.

PHP LDAP Connection to Authenticate against Active Directory from External Server

I have an external web server trying to authenticate against Active Directory on an internal server via LDAP. I am able to connect and authenticate locally, though using the same code (switching out host and port) am not able to authenticate externally. We have other services that are able to connect and authenticate such as Attask (http://www.attask.com/).
The external server is currently a Linux (gs) on Media Temple running PHP 5.3.15 with LDAP support enabled.
The internal server is currently a Windows Server 2008 box with LDAP and Active Directory.
The code below is the current PHP I am using that was able to connect locally, but having problems on the external server. It basically uses the PHP LDAP connection string and tries to bind. If it fails, it tries to bind anonymously. Both of which aren't working externally and returns the error: Can't contact LDAP server.
<?php
$username = 'username';
$password = 'password';
$ldapconfig['host'] = '00.000.000.000';
$ldapconfig['port'] = '636';
$ldapconfig['basedn'] = 'dc=client,dc=eqc,dc=local';
$ds=ldap_connect($ldapconfig['host'], $ldapconfig['port']);
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
ldap_set_option($ds, LDAP_OPT_NETWORK_TIMEOUT, 10);
$dn="".$username."";
if ($bind=ldap_bind($ds, $dn, $password)) {
echo("Login correct");
} else {
echo("Unable to bind to server.</br>");
echo("msg:'".ldap_error($ds)."'</br>".ldap_errno($ds)."");
if ($bind=ldap_bind($ds)) {
$filter = "(cn=*)";
if (!($search=#ldap_search($ds, $ldapconfig['basedn'], $filter))) {
echo("Unable to search ldap server<br>");
echo("msg:'".ldap_error($ds)."'</br>");
} else {
$number_returned = ldap_count_entries($ds,$search);
$info = ldap_get_entries($ds, $search);
echo "The number of entries returned is ". $number_returned."<p>";
for ($i=0; $i<$info["count"]; $i++) {
var_dump($info[$i]);
}
}
} else {
echo("Unable to bind anonymously<br>");
echo("msg:".ldap_error($ds)."<br>");
}
}
?>
A few notes:
The external LDAP server is using LDAPS so the suggested host is ldaps://00.000.000.000 on port 636
I've tried binding with 'username' as well as 'username#00.000.000.000' already
There is a firewall, however, the external server can successfully ping the internal LDAP server so there is connection taking place on that level.
Any help would be greatly appreciated. If there are server settings or things of that nature, would love to know. Also, I've checked out ADFS though could not find a simple script to setup to test without spending a lot time to no end if it didn't work.
When connecting to AD using LDAPS from a Linux box, I've always had to add the line
TLS_REQCERT never
in /etc/ldap.conf or equivalent (might require an apache restart - not sure). You can also try the format "ldaps://server.domain.tld:636" for the host, though I don't think that's the issue.
I found some decent documentation at http://en.gentoo-wiki.com/wiki/Active_Directory_Authentication_using_LDAP, though it appears to be down at the moment. Google's cached version: http://webcache.googleusercontent.com/search?q=cache:http://en.gentoo-wiki.com/wiki/Active_Directory_Authentication_using_LDAP
Have you checked if it is an SSL certificate error? Are you using a self signed cert or an official one?
"If you're using SSL (e.g. ldaps) and ldap_bind is throwing 'Unable to bind to server:' errors, check that the hostname used in the ldap_connect matches the 'CN' in the SSL certificate on the LDAP server" Source

How to bind to AD server in PHP with credentials from trusted domain?

We have several AD servers with established forest trust between them, so Windows users from different domains are able to get access to restricted resources. Suppose we have domainA.com and domainB.com, so any user from the domain domainB.com can login to resource on domainA.com. For security reasons anonymous access to LDAP servers is disabled by administrators.
Now we need to list all users from all LDAP servers in our PHP code with the help of OpenLDAP client. Below is PHP code to get info about all users from domainB.com
define('USER', 'user#domainA.com'); // User from domainA.com here
$ldap = ldap_connect('domainB.com') or die('Bad connection');
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
ldap_bind($ldap, USER, PASS) or die('Cannot bind');
My script dies with message "Cannot bind" with ldap error "49 Invalid credentials". Additional info from AD:
80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1
I think that the problem is with simple authentication mechanism, because when I use GSS Negotiate authentication in the Ldap Administrator client with the same credentials for user#domainA.com everything is ok.
What can I do to make successful bind on domainB.com with credentials from user#domainA.com?
UPD1 Authentication with SASL DIGEST-MD5
ldap_sasl_bind ( $ldap, '', $pass, 'DIGEST-MD5', null, 'user#domainA.com');
Logs from AD:
The computer attempted to validate the credentials for an account.
Authentication Package: WDigest
Logon Account: user
Source Workstation: DOMAINA
Error Code: 0xc000006a
An account failed to log on.
Subject:
Security ID: NULL SID
Account Name: -
Account Domain: -
Logon ID: 0x0
Logon Type: 3
Account For Which Logon Failed:
Security ID: NULL SID
Account Name: user#domainA.com
Account Domain: domainA.com
Failure Information:
Failure Reason: An Error occured during Logon.
Status: 0xc000006d
Sub Status: 0xc000006d
Process Information:
Caller Process ID: 0x0
Caller Process Name: -
Network Information:
Workstation Name: -
Source Network Address:
Source Port:
Detailed Authentication Information:
Logon Process: WDIGEST
Authentication Package: WDigest
Transited Services: -
Package Name (NTLM only): -
Key Length: 0
This event is generated when a logon request fails. It is generated on the computer where access was attempted.
The Subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe.
The Logon Type field indicates the kind of logon that was requested. The most common types are 2 (interactive) and 3 (network).
The Process Information fields indicate which account and process on the system requested the logon.
The Network Information fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases.
The authentication information fields provide detailed information about this specific logon request.
- Transited services indicate which intermediate services have participated in this logon request.
- Package name indicates which sub-protocol was used among the NTLM protocols.
I've experienced this issue when configuring Moodle, which uses PHP LDAP libs and OpenLDAP to connect to AD servers. The solution was pretty simple, and one of two things, (which really just boiled down to one thing):
Use the unscoped username (i.e. no '#example.com' after the username)
Use the DOMAIN\username
Basically, the one thing it boiled down to was getting the correct, expected username syntax. I think this is dependent on the particular AD configuration, because I have seen four types of usernames that work, on various AD servers: Full DN, scoped username (i.e. looks like an email address), DOMAIN\username, and plain username.
When you specifiy the user in ldap_bind, can you try to put your user DN like this :
$bind = ldap_bind($resource, 'cn=jpb,cn=users,dc=dom,dc=fr', '***');
Another thing, in your 'Active-Directory Forest' you've got one or more domain controler which support a directory called 'Global Catalog' (GC). The GC contains all the object of all the Directories of your forest.
Edited
You can try to bind with SASL
$ldap = ldap_connect('domainB.com');
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
ldap_sasl_bind ( $conn, NULL,"password",'DIGEST-MD5',NULL,'user#domainA.com',NULL);

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

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.

Categories