Authenticate users against LDAP.
using System;
using System.Collections.Generic;
using System.Text;
using System.DirectoryServices.Protocols;
using System.Net;
namespace DotNetDevGuide.DirectoryServices.Chapter12
{
public class LdapAuth : IDisposable
{
LdapConnection _authConnect;
string _server;
bool _fastBind;
bool _useSSL;
bool _isADAM;
public LdapAuth(string server, bool useSSL)
{
_useSSL = useSSL;
_fastBind = false;
_isADAM = false;
_server = server;
CheckCapabilities();
_authConnect = new LdapConnection(
new LdapDirectoryIdentifier(server),
null,
AuthType.Basic
);
_authConnect.SessionOptions.SecureSocketLayer = _useSSL;
_authConnect.SessionOptions.ProtocolVersion = 3;
if (_fastBind)
{
try
{
_authConnect.SessionOptions.FastConcurrentBind();
}
catch (PlatformNotSupportedException)
{
//this will happen when server is not W2K3
_fastBind = false;
}
}
if (_fastBind && !_useSSL)
{
//we are using a non-encrypted channel
//to pass credentials in cleartext - bad!
throw new NotSupportedException("We don't support sending credentials in the clear");
}
if (!(_fastBind || _useSSL || _isADAM))
{
//we did not get a fast bind or
//SSL so we can try to at least
//encrypt the credentials
_authConnect.AuthType = AuthType.Negotiate;
_authConnect.SessionOptions.Sealing = true;
_authConnect.SessionOptions.Signing = true;
}
if (_isADAM && !(_useSSL || _fastBind))
{
//we are using ADAM with no SSL
//try to use Digest to secure bind
//Requires Win2k3 R2 ADAM
_authConnect.AuthType = AuthType.Digest;
}
}
public bool Authenticate(NetworkCredential credentials)
{
try
{
_authConnect.Bind(credentials);
return true;
}
catch (LdapException ex)
{
if (ex.ErrorCode != 49)
throw;
return false;
}
}
/// <summary>
/// Check the capabilities of our target server using
/// a RootDSE base search. Bootstraps the authentication
/// process.
/// </summary>
private void CheckCapabilities()
{
string ext = "supportedExtension";
string cap = "supportedCapabilities";
LdapConnection connect = new LdapConnection(
new LdapDirectoryIdentifier(_server),
null,
AuthType.Basic
);
using (connect)
{
connect.Bind();
connect.SessionOptions.ProtocolVersion = 3;
connect.SessionOptions.SecureSocketLayer = _useSSL;
SearchRequest request = new SearchRequest(
null, //read the rootDSE
"(objectClass=*)",
SearchScope.Base,
new string[] { ext, cap }
);
//set 120 second timelimit
request.TimeLimit = TimeSpan.FromSeconds(120);
SearchResponse response =
(SearchResponse)connect.SendRequest(request);
if (response.ResultCode != ResultCode.Success)
throw new Exception(response.ErrorMessage);
SearchResultEntry entry = response.Entries[0];
object[] vals = new object[] { };
if (entry.Attributes.Contains(ext))
{
vals = entry.Attributes[ext].GetValues(typeof(string));
foreach (string s in vals)
{
//OID for Fast Concurrent Bind support
if (s == "1.2.840.113556.1.4.1781")
{
_fastBind = true;
break;
}
}
}
//all LDAP servers should support 'supportedCapabilities'
vals = entry.Attributes[cap].GetValues(typeof(string));
foreach (string s in vals)
{
//OID for ADAM
if (s == "1.2.840.113556.1.4.1851")
{
_isADAM = true;
break;
}
}
}
}
#region IDisposable Members
public void Dispose()
{
_authConnect.Dispose();
}
#endregion
}
}
/// <summary>
/// Shows how to use Listing 12.3, .4, .5 - see LdapAuth.cs
/// If you are using ADAM - make sure you have SSL or Digest working
/// </summary>
[Test]
public void LdapAuthenticate()
{
LdapAuth auth = new LdapAuth(TestUtils.Settings.Server, false);
using (auth)
{
bool truth = auth.Authenticate(
new System.Net.NetworkCredential("username", "password")
);
Assert.IsTrue(truth);
}
}