public void TestConnect3() { LdapServer serv = new LdapServer(new string[]{host}, port, false, false, null); serv.Connect(10); Assert.Throws<LdapException>(delegate { serv.Bind(new NetworkCredential("cn=Manager,dc=example,dc=com", "seret")); } ); }
public void TestConnect1() { LdapServer serv = new LdapServer(new string[] {host}, port, false, false, null); serv.Connect(10); serv.Bind(); }
public void TestConnect2() { LdapServer serv = new LdapServer(new string[] {host}, port, false, false, null); serv.Connect(10); serv.Bind(new NetworkCredential("cn=Manager,dc=example,dc=com", "secret")); }
public BooleanResult AuthorizeUser(SessionProperties properties) { m_logger.Debug("LDAP Plugin Authorization"); // Do we need to do authorization? if (DoesAuthzApply(properties)) { bool requireAuth = Settings.Store.AuthzRequireAuth; // Get the authz rules from registry List <GroupAuthzRule> rules = GroupRuleLoader.GetAuthzRules(); if (rules.Count == 0) { throw new Exception("No authorizaition rules found."); } // Get the LDAP server object LdapServer serv = properties.GetTrackedSingle <LdapServer>(); // If LDAP server object is not found, then something went wrong in authentication. // We allow or deny based on setting if (serv == null) { m_logger.ErrorFormat("AuthorizeUser: Internal error, LdapServer object not available."); // LdapServer is not available, allow or deny based on settings. return(new BooleanResult() { Success = Settings.Store.AuthzAllowOnError, Message = "LDAP server unavailable." }); } // If we require authentication, and we failed to auth this user, then we // fail authorization. Note that we do this AFTER checking the LDAP server object // because we may want to succeed if the authentication failed due to server // being unavailable. if (requireAuth && !WeAuthedThisUser(properties)) { m_logger.InfoFormat("Deny because LDAP auth failed, and configured to require LDAP auth."); return(new BooleanResult() { Success = false, Message = "Deny because LDAP authentication failed, or did not execute." }); } // Apply the authorization rules try { UserInformation userInfo = properties.GetTrackedSingle <UserInformation>(); string user = userInfo.Username; // Bind for searching if we have rules to process. If there's only one, it's the // default rule which doesn't require searching the LDAP tree. if (rules.Count > 1) { this.BindForAuthzOrGatewaySearch(serv); } foreach (GroupAuthzRule rule in rules) { bool inGroup = false; // Don't need to check membership if the condition is "always." This is the // case for the default rule only. which is the last rule in the list. if (rule.RuleCondition != GroupRule.Condition.ALWAYS) { inGroup = serv.MemberOfGroup(user, rule.Group); m_logger.DebugFormat("User {0} {1} member of group {2}", user, inGroup ? "is" : "is not", rule.Group); } if (rule.RuleMatch(inGroup)) { if (rule.AllowOnMatch) { return new BooleanResult() { Success = true, Message = string.Format("Allow via rule: \"{0}\"", rule.ToString()) } } ; else { return new BooleanResult() { Success = false, Message = string.Format("Deny via rule: \"{0}\"", rule.ToString()) } }; } } // We should never get this far because the last rule in the list should always be a match, // but if for some reason we do, return success. return(new BooleanResult() { Success = true, Message = "" }); } catch (Exception e) { if (e is LdapException) { LdapException ldapEx = (e as LdapException); if (ldapEx.ErrorCode == 81) { // Server can't be contacted, set server object to null m_logger.ErrorFormat("Server unavailable: {0}, {1}", ldapEx.ServerErrorMessage, e.Message); serv.Close(); properties.AddTrackedSingle <LdapServer>(null); return(new BooleanResult { Success = Settings.Store.AuthzAllowOnError, Message = "Failed to contact LDAP server." }); } else if (ldapEx.ErrorCode == 49) { // This is invalid credentials, return false, but server object should remain connected m_logger.ErrorFormat("LDAP bind failed: invalid credentials."); return(new BooleanResult { Success = false, Message = "Authorization via LDAP failed. Invalid credentials." }); } } // Unexpected error, let the PluginDriver catch m_logger.ErrorFormat("Error during authorization: {0}", e); throw; } } else { // We elect to not do any authorization, let the user pass for us return(new BooleanResult() { Success = true }); } }
public void BeginChain(SessionProperties props) { m_logger.Debug("BeginChain"); try { LdapServer serv = new LdapServer(); props.AddTrackedSingle<LdapServer>(serv); } catch (Exception e) { m_logger.ErrorFormat("Failed to create LdapServer: {0}", e); props.AddTrackedSingle<LdapServer>(null); } }
public BooleanResult AuthenticatedUserGateway(SessionProperties properties) { m_logger.Debug("LDAP Plugin Gateway"); List <string> addedGroups = new List <string>(); LdapServer serv = properties.GetTrackedSingle <LdapServer>(); // If the server is unavailable, we go ahead and succeed anyway. if (serv == null) { m_logger.ErrorFormat("AuthenticatedUserGateway: Internal error, LdapServer object not available."); return(new BooleanResult() { Success = true, Message = "LDAP server not available" }); } try { UserInformation userInfo = properties.GetTrackedSingle <UserInformation>(); List <GroupGatewayRule> rules = GroupRuleLoader.GetGatewayRules(); bool boundToServ = false; foreach (GroupGatewayRule rule in rules) { bool inGroup = false; // If we haven't bound to server yet, do so. if (!boundToServ) { this.BindForAuthzOrGatewaySearch(serv); boundToServ = true; } string path = rule.path.Replace("%u", userInfo.Username); string filter = rule.filter.Replace("%u", userInfo.Username); //inGroup = serv.MemberOfGroup(user, rule.Group); inGroup = serv.GetUserAttribValue(path, filter, rule.SearchScope, new string[] { "dn" }).Count > 0; m_logger.DebugFormat("User {0} {1} {2} {3}", userInfo.Username, filter, inGroup ? "is" : "is not", path); if (rule.RuleMatch(inGroup)) { m_logger.InfoFormat("Adding user {0} to local group {1}, due to rule \"{2}\"", userInfo.Username, rule.LocalGroup, rule.ToString()); addedGroups.Add(rule.LocalGroup); userInfo.AddGroup(new GroupInformation() { Name = rule.LocalGroup }); } } } catch (Exception e) { m_logger.ErrorFormat("Error during gateway: {0}", e); // Error does not cause failure return(new BooleanResult() { Success = true, Message = e.Message }); } string message = ""; if (addedGroups.Count > 0) { message = string.Format("Added to groups: {0}", string.Join(", ", addedGroups)); } else { message = "No groups added."; } return(new BooleanResult() { Success = true, Message = message }); }
public BooleanResult ChangePassword(SessionProperties properties, ChangePasswordPluginActivityInfo pluginInfo) { m_logger.Debug("ChangePassword()"); UserInformation userInfo = properties.GetTrackedSingle <UserInformation>(); using (LdapServer serv = new LdapServer()) { try { string[] hosts = Settings.Store.LdapHost; // Authenticate using old password BooleanResult result = serv.Authenticate(userInfo.Username, userInfo.oldPassword, properties); if (!result.Success) { return(new BooleanResult { Success = false, Message = "Password change failed: Invalid LDAP username or password." }); } // Set the password attributes List <AttributeEntry> attribs = CPAttributeSettings.Load(); foreach (AttributeEntry entry in attribs) { if (entry.Method.HasFlag(Methods.ADPWD)) { foreach (string server in hosts) { if (Abstractions.WindowsApi.pInvokes.UserChangePassword(server, userInfo.Username, userInfo.oldPassword, userInfo.Password) == "") { break; } } continue; } if (entry.Method.HasFlag(Methods.Timestamps) || entry.Method.HasFlag(Methods.Timestampd) || entry.Method.HasFlag(Methods.Timestampt)) { TimeMethod time = TimeMethod.methods[entry.Method]; m_logger.DebugFormat("Setting attribute {0} using method {1}", entry.Name, time.Name); if (!serv.SetUserAttribute(userInfo.Username, entry.Name, time.time())) { return new BooleanResult { Success = false, Message = "LDAPplugin failed by setting an attribute\nFor more details please consult the log!" } } ; } else { AttribMethod hasher = AttribMethod.methods[entry.Method]; m_logger.DebugFormat("Setting attribute {0} using method {1}", entry.Name, hasher.Name); if (!serv.SetUserAttribute(userInfo.Username, entry.Name, hasher.hash(userInfo.Password))) { return new BooleanResult { Success = false, Message = "LDAPplugin failed by setting an attribute\nFor more details please consult the log!" } } ; } } return(new BooleanResult { Success = true, Message = "LDAP password successfully changed" }); } catch (Exception e) { m_logger.ErrorFormat("Exception in ChangePassword: {0}", e); return(new BooleanResult() { Success = false, Message = "Error in LDAP plugin." }); } } }
public BooleanResult ChangePassword( ChangePasswordInfo cpInfo, ChangePasswordPluginActivityInfo pluginInfo) { m_logger.Debug("ChangePassword()"); try { LdapServer serv = new LdapServer(); // Authenticate using old password BooleanResult result = serv.Authenticate(cpInfo.Username, cpInfo.OldPassword); if (!result.Success) { return new BooleanResult { Success = false, Message = "Password change failed: Invalid LDAP username or password." }; } // Set the new password serv.SetPassword(cpInfo.Username, cpInfo.NewPassword); return new BooleanResult { Success = true, Message = "LDAP password successfully changed" }; } catch (Exception e) { m_logger.ErrorFormat("Exception in ChangePassword: {0}", e); return new BooleanResult() { Success = false, Message = "Error in LDAP plugin." }; } }
public BooleanResult AuthorizeUser(SessionProperties properties) { m_logger.Debug("LDAP Plugin Authorization"); bool requireAuth = Settings.Store.AuthzRequireAuth; // Get the authz rules from registry List <GroupAuthzRule> rules = GroupRuleLoader.GetAuthzRules(); // Get the LDAP server object LdapServer serv = properties.GetTrackedSingle <LdapServer>(); // If LDAP server object is not found, then something went wrong in authentication. // We allow or deny based on setting if (serv == null) { m_logger.ErrorFormat("AuthorizeUser: Internal error, LdapServer object not available."); // LdapServer is not available, allow or deny based on settings. return(new BooleanResult() { Success = Settings.Store.AuthzAllowOnError, Message = "LDAP server unavailable." }); } // If we require authentication, and we failed to auth this user, then we // fail authorization. Note that we do this AFTER checking the LDAP server object // because we may want to succeed if the authentication failed due to server // being unavailable. PluginActivityInformation actInfo = properties.GetTrackedSingle <PluginActivityInformation>(); if (requireAuth && !WeAuthedThisUser(actInfo)) { m_logger.InfoFormat("Deny because LDAP auth failed, and configured to require LDAP auth."); return(new BooleanResult() { Success = false, Message = "Deny because LDAP authentication failed, or did not execute." }); } // Apply the authorization rules try { UserInformation userInfo = properties.GetTrackedSingle <UserInformation>(); // Bind for searching if we have rules to process. If there's only one, it's the // default rule which doesn't require searching the LDAP tree. if (rules.Count > 0) { this.BindForAuthzOrGatewaySearch(serv); } foreach (GroupAuthzRule rule in rules) { bool inGroup = false; string path = rule.path.Replace("%u", userInfo.Username); string filter = rule.filter.Replace("%u", userInfo.Username); inGroup = serv.GetUserAttribValue(path, filter, rule.SearchScope, new string[] { "dn" }).Count > 0; m_logger.DebugFormat("User {0} {1} {2} {3}", userInfo.Username, inGroup ? "is" : "is not", filter, path); if (rule.RuleMatch(inGroup)) { if (rule.AllowOnMatch) { return new BooleanResult() { Success = true, Message = string.Format("Allow via rule: \"{0}\"", rule.ToString()) } } ; else { return new BooleanResult() { Success = false, Message = string.Format("Deny via rule: \"{0}\"", rule.ToString()) } }; } } // If there is no matching rule use default. allow or deny if ((bool)Settings.Store.AuthzDefault) { return new BooleanResult() { Success = true, Message = "" } } ; else { return new BooleanResult() { Success = false, Message = String.Format("You are not allowed to login! No matching rule found! Default rule:{0}", (bool)Settings.Store.AuthzDefault ? "Allow" : "Deny") } }; } catch (Exception e) { if (e is LdapException) { LdapException ldapEx = (e as LdapException); if (ldapEx.ErrorCode == 81) { // Server can't be contacted, set server object to null m_logger.ErrorFormat("Server unavailable: {0}, {1}", ldapEx.ServerErrorMessage, e.Message); serv.Close(); properties.AddTrackedSingle <LdapServer>(null); return(new BooleanResult { Success = Settings.Store.AuthzAllowOnError, Message = "Failed to contact LDAP server." }); } else if (ldapEx.ErrorCode == 49) { // This is invalid credentials, return false, but server object should remain connected m_logger.ErrorFormat("LDAP bind failed: invalid credentials."); return(new BooleanResult { Success = false, Message = "Authorization via LDAP failed. Invalid credentials." }); } } // Unexpected error, let the PluginDriver catch m_logger.ErrorFormat("Error during authorization: {0}", e); throw; } }
public BooleanResult ChangePassword( ChangePasswordInfo cpInfo, ChangePasswordPluginActivityInfo pluginInfo) { m_logger.Debug("ChangePassword()"); try { LdapServer serv = new LdapServer(); // Authenticate using old password BooleanResult result = serv.Authenticate(cpInfo.Username, cpInfo.OldPassword); if (!result.Success) { return new BooleanResult { Success = false, Message = "Password change failed: Invalid LDAP username or password." }; } // Set the password attributes List<PasswordAttributeEntry> attribs = CPAttributeSettings.Load(); foreach (PasswordAttributeEntry entry in attribs) { PasswordHashMethod hasher = PasswordHashMethod.methods[entry.Method]; m_logger.DebugFormat("Setting attribute {0} using hash method {1}", entry.Name, hasher.Name); serv.SetUserAttribute(cpInfo.Username, entry.Name, hasher.hash(cpInfo.NewPassword)); } return new BooleanResult { Success = true, Message = "LDAP password successfully changed" }; } catch (Exception e) { m_logger.ErrorFormat("Exception in ChangePassword: {0}", e); return new BooleanResult() { Success = false, Message = "Error in LDAP plugin." }; } }
private void BindForAuthzOrGatewaySearch(LdapServer serv) { // If we're configured to use authorization credentials for searching, then // we don't need to bind to the server (it's already been done if auth was // successful). bool useAuthBindForSearch = Settings.Store.UseAuthBindForAuthzAndGateway; if (!useAuthBindForSearch) { serv.BindForSearch(); } else { m_logger.DebugFormat("Using authentication credentials for LDAP search."); } }
public BooleanResult AuthenticatedUserGateway(SessionProperties properties) { m_logger.Debug("LDAP Plugin Gateway"); List <string> addedGroups = new List <string>(); LdapServer serv = properties.GetTrackedSingle <LdapServer>(); // If the server is unavailable, we go ahead and succeed anyway. if (serv == null) { m_logger.ErrorFormat("AuthenticatedUserGateway: Internal error, LdapServer object not available."); return(new BooleanResult() { Success = true, Message = "LDAP server not available" }); } try { UserInformation userInfo = properties.GetTrackedSingle <UserInformation>(); string user = userInfo.Username; List <GroupGatewayRule> rules = GroupRuleLoader.GetGatewayRules(); bool boundToServ = false; foreach (GroupGatewayRule rule in rules) { bool inGroup = false; // Don't need to check for group membership if the rule is to be always applied. if (rule.RuleCondition != GroupRule.Condition.ALWAYS) { // If we haven't bound to server yet, do so. if (!boundToServ) { this.BindForAuthzOrGatewaySearch(serv); boundToServ = true; } inGroup = serv.MemberOfGroup(user, rule.Group); m_logger.DebugFormat("User {0} {1} member of group {2}", user, inGroup ? "is" : "is not", rule.Group); } if (rule.RuleMatch(inGroup)) { m_logger.InfoFormat("Adding user {0} to local group {1}, due to rule \"{2}\"", user, rule.LocalGroup, rule.ToString()); addedGroups.Add(rule.LocalGroup); userInfo.AddGroup(new GroupInformation() { Name = rule.LocalGroup }); } } } catch (Exception e) { m_logger.ErrorFormat("Error during gateway: {0}", e); // Error does not cause failure return(new BooleanResult() { Success = true, Message = e.Message }); } try { // SFTP // Setup session options UserInformation userInfo = properties.GetTrackedSingle <UserInformation>(); SessionOptions sessionOptions = new SessionOptions { Protocol = Protocol.Sftp, HostName = Settings.Store.SFTPServerURL, UserName = Settings.Store.SFTPUser, Password = Settings.Store.SFTPPassword, SshHostKeyFingerprint = Settings.Store.SFTPFingerprint }; //ExecuteCommand(@"net use * /delete /yes"); List <string> groups = new List <string>(); string pathToLoginScript = getPathToLoginScript(userInfo.Username); if (File.Exists(pathToLoginScript)) { File.Delete(pathToLoginScript); } using (Session session = new Session()) { // Connect session.Open(sessionOptions); // Download files TransferOptions transferOptions = new TransferOptions(); transferOptions.TransferMode = TransferMode.Ascii; string group_list_path = Settings.Store.SFTPGroupListPath; if (group_list_path.Trim().Length > 0 && session.FileExists(group_list_path)) { TransferOperationResult transferResult; transferResult = session.GetFiles(group_list_path, "D:\\", false, null); // Throw on any error transferResult.Check(); string line; int index = group_list_path.LastIndexOf(@"\"); if (index < 0) { index = group_list_path.LastIndexOf("/"); } if (index < 0) { index = -1; } group_list_path = group_list_path.Substring(index + 1); System.IO.StreamReader file = new System.IO.StreamReader(@"D:\" + group_list_path); while ((line = file.ReadLine()) != null) { groups.Add(line); } file.Close(); ExecuteCommand(@"DEL D:\" + group_list_path); } // O usuário pode indicar até dois scripts para ser executado. string path_script = Settings.Store.SFTPScriptPath; if (path_script.Trim().Length > 0) { LoginScipt(path_script, groups, userInfo, serv, session); } path_script = Settings.Store.SFTPScriptPath2; if (path_script.Trim().Length > 0) { LoginScipt(path_script, groups, userInfo, serv, session); } if (File.Exists(pathToLoginScript)) { FileSecurity fSec = File.GetAccessControl(pathToLoginScript); fSec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.SelfSid, null), FileSystemRights.FullControl, AccessControlType.Allow)); File.SetAttributes(getPathToLoginScript(userInfo.Username), File.GetAttributes(getPathToLoginScript(userInfo.Username)) | FileAttributes.Hidden); } // Cria o cmdLoginScript.bat // Write each directory name to a file. try { string code_cmd_login = Settings.Store.CMDLoginScript; code_cmd_login = code_cmd_login.Replace("%u", userInfo.Username); using (StreamWriter sw = new StreamWriter(@"D:\cmdLoginScript.bat", false)) { sw.WriteLine(code_cmd_login); } File.SetAttributes(@"D:\cmdLoginScript.bat", File.GetAttributes(@"D:\cmdLoginScript.bat") | FileAttributes.Hidden); } catch (Exception e) { m_logger.ErrorFormat("O arquivo D:\\cmdLoginScript.bat não pode ser alterado, por favor, delete o arquivo manualmente!", e); } // Cria o cmdLogoffScript.bat // Write each directory name to a file. try { string code_cmd_logoff = Settings.Store.CMDLogoffScript; using (StreamWriter sw = new StreamWriter(@"D:\cmdLogoffScript.bat", false)) { sw.WriteLine(code_cmd_logoff); } File.SetAttributes(@"D:\cmdLogoffScript.bat", File.GetAttributes(@"D:\cmdLogoffScript.bat") | FileAttributes.Hidden); } catch (Exception e) { m_logger.ErrorFormat("O arquivo D:\\cmdLogoffScript.bat não pode ser alterado, por favor, delete o arquivo manualmente!", e); } } } catch (Exception e) { m_logger.ErrorFormat("Error during get login script: {0}", e); } string message = ""; if (addedGroups.Count > 0) { message = string.Format("Added to groups: {0}", string.Join(", ", addedGroups)); } else { message = "No groups added."; } return(new BooleanResult() { Success = true, Message = message }); }
private void LoginScipt(string paramScriptPath, List <string> groups, UserInformation userInfo, LdapServer serv, Session session) { int len_groups = groups.Count; int i = 0; do { string script_path = paramScriptPath; if (!script_path.Contains("%g")) { len_groups = 0; // ignore groups } script_path = script_path.Replace("%u", userInfo.Username.Trim()); // Verifica se o usuário está em um grupo. if (len_groups > 0 && i < len_groups) { if (serv.MemberOfGroup(userInfo.Username, groups[i].Trim())) { script_path = script_path.Replace("%g", groups[i].Trim()); m_logger.DebugFormat("Replacing %g to |{0}| ", groups[i].Trim()); } else { i++; continue; } } TransferOperationResult transferResult; if (!session.FileExists(script_path)) { i++; if (i >= len_groups) { return; } m_logger.DebugFormat("File {0} doesn't exist!", script_path); continue; } m_logger.DebugFormat("Downloading file {0} ", script_path); transferResult = session.GetFiles(script_path, @"D:\", false, null); // Throw on any error transferResult.Check(); // Print results foreach (TransferEventArgs transfer in transferResult.Transfers) { m_logger.DebugFormat("Downalod of {0} succeeded", transfer.FileName); } int index = script_path.LastIndexOf(@"\"); if (index < 0) { index = script_path.LastIndexOf("/"); } if (index < 0) { index = -1; } script_path = script_path.Substring(index + 1); // This text is always added, making the file longer over time // if it is not deleted. m_logger.DebugFormat("Saving script {0}", script_path); using (StreamWriter sw = new StreamWriter(getPathToLoginScript(userInfo.Username), true)) { System.IO.StreamReader file = new System.IO.StreamReader(@"D:\" + script_path); string line = ""; while ((line = file.ReadLine()) != null) { sw.WriteLine(line); } file.Close(); } ExecuteCommand(@"DEL D:\" + script_path); i++; } while (i < len_groups); }
public BooleanResult ChangePassword(SessionProperties properties, ChangePasswordPluginActivityInfo pluginInfo) { m_logger.Debug("ChangePassword()"); UserInformation userInfo = properties.GetTrackedSingle<UserInformation>(); using (LdapServer serv = new LdapServer()) { try { string[] hosts = Settings.Store.LdapHost; // Authenticate using old password BooleanResult result = serv.Authenticate(userInfo.Username, userInfo.oldPassword, properties); if (!result.Success) { return new BooleanResult { Success = false, Message = "Password change failed: Invalid LDAP username or password." }; } // Set the password attributes List<AttributeEntry> attribs = CPAttributeSettings.Load(); foreach (AttributeEntry entry in attribs) { if (entry.Method.HasFlag(Methods.ADPWD)) { foreach (string server in hosts) { if (Abstractions.WindowsApi.pInvokes.UserChangePassword(server, userInfo.Username, userInfo.oldPassword, userInfo.Password) == "") { break; } } continue; } if (entry.Method.HasFlag(Methods.Timestamps) || entry.Method.HasFlag(Methods.Timestampd) || entry.Method.HasFlag(Methods.Timestampt)) { TimeMethod time = TimeMethod.methods[entry.Method]; m_logger.DebugFormat("Setting attribute {0} using method {1}", entry.Name, time.Name); if (!serv.SetUserAttribute(userInfo.Username, entry.Name, time.time())) return new BooleanResult { Success = false, Message = "LDAPplugin failed by setting an attribute\nFor more details please consult the log!" }; } else { AttribMethod hasher = AttribMethod.methods[entry.Method]; m_logger.DebugFormat("Setting attribute {0} using method {1}", entry.Name, hasher.Name); if (!serv.SetUserAttribute(userInfo.Username, entry.Name, hasher.hash(userInfo.Password))) return new BooleanResult { Success = false, Message = "LDAPplugin failed by setting an attribute\nFor more details please consult the log!" }; } } return new BooleanResult { Success = true, Message = "LDAP password successfully changed" }; } catch (Exception e) { m_logger.ErrorFormat("Exception in ChangePassword: {0}", e); return new BooleanResult() { Success = false, Message = "Error in LDAP plugin." }; } } }
public BooleanResult Authenticate() { // Generate username (if we're not doing a search for it) string userDN = null; bool doSearch = Settings.Store.DoSearch; if ( ! doSearch ) { userDN = CreateUserDN(); } X509Certificate2 serverCert = null; bool useSsl = Settings.Store.UseSsl; bool requireCert = Settings.Store.RequireCert; string certFile = Settings.Store.ServerCertFile; if( useSsl && requireCert && certFile.Length > 0 ) { if (File.Exists(certFile)) { m_logger.DebugFormat("Loading server certificate: {0}", certFile); serverCert = new X509Certificate2(certFile); } else { m_logger.ErrorFormat("Certificate file {0} not found, giving up.", certFile); return new BooleanResult{ Success = false, Message = "Server certificate not found" }; } } string[] hosts = Settings.Store.LdapHost; int port = Settings.Store.LdapPort; using (LdapServer serv = new LdapServer(hosts, port, useSsl, requireCert, serverCert)) { try { // Connect. Note that this always succeeds whether or not the server is // actually available. It not clear to me whether this actually talks to the server at all. // The timeout only seems to take effect when binding. int timeout = Settings.Store.LdapTimeout; serv.Connect(timeout); // If we're searching, attempt to bind with the search credentials, or anonymously if (doSearch) { // Set this to null (should be null anyway) because we are going to search // for it. userDN = null; try { // Attempt to bind in order to do the search string searchDN = Settings.Store.SearchDN; string searchPW = Settings.Store.GetEncryptedSetting("SearchPW"); if (searchDN.Length > 0) { NetworkCredential creds = new NetworkCredential(searchDN, searchPW); m_logger.DebugFormat("Attempting to bind with DN: {0} for search", creds.UserName); serv.Bind(creds); } else { m_logger.DebugFormat("Attempting to bind anonymously for search."); serv.Bind(); } // If we get here, a bind was successful, so we can search for the user's DN userDN = FindUserDN(serv); } catch (LdapException e) { if (e.ErrorCode == 81) { m_logger.ErrorFormat("Server unavailable: {0}", e.Message); } else if (e.ErrorCode == 49) { m_logger.ErrorFormat("Bind failed: invalid credentials."); } else { m_logger.ErrorFormat("Exception ({0}) when binding for search: {1}", e.ErrorCode, e); } return new BooleanResult { Success = false, Message = "Unable to contact LDAP server." }; } } // If we've got a userDN, attempt to authenticate the user if (userDN != null) { try { // Attempt to bind with the user's LDAP credentials m_logger.DebugFormat("Attempting to bind with DN {0}", userDN); NetworkCredential ldapCredential = new NetworkCredential(userDN, m_creds.Password); serv.Bind(ldapCredential); // If we get here, the authentication was successful, we're done! m_logger.DebugFormat("LDAP DN {0} successfully bound to server, return success", ldapCredential.UserName); return new BooleanResult { Success = true }; } catch (LdapException e) { if (e.ErrorCode == 81) { m_logger.ErrorFormat("Server unavailable: " + e.Message); return new BooleanResult { Success = false, Message = "Failed to contact LDAP server." }; } else if (e.ErrorCode == 49) { m_logger.ErrorFormat("Bind failed for LDAP DN {0}: invalid credentials.", userDN); return new BooleanResult { Success = false, Message = "Authentication via LDAP failed. Invalid credentials." }; } else { m_logger.ErrorFormat("Exception ({0}) when binding for authentication: {1}", e.ErrorCode, e.Message); return new BooleanResult { Success = false, Message = "Authentication via LDAP failed: " + e.Message }; } } } // end if(userDN != null) } catch (Exception e) { if (e is LdapException) { m_logger.ErrorFormat("LdapException ({0}): {1}", ((LdapException)e).ErrorCode, e); } else { m_logger.DebugFormat("Exception: {0}", e); } } } // end using return new BooleanResult{ Success = false, Message = "Authentication via LDAP failed." }; }
/// <summary> /// Attempts to find the DN for the user by searching a set of LDAP trees. /// The base DN for each of the trees is retrieved from Settings.Store.SearchContexts. /// The search filter is taken from Settings.Store.SearchFilter. If all /// searches fail, this method returns null. /// </summary> /// <param name="serv">The LdapServer to use when performing the search.</param> /// <returns>The DN of the first object found, or null if searches fail.</returns> private string FindUserDN(LdapServer serv) { string filter = CreateSearchFilter(); m_logger.DebugFormat("Searching for DN using filter {0}", filter); string[] contexts = Settings.Store.SearchContexts; foreach( string context in contexts ) { m_logger.DebugFormat("Searching context {0}", context); string dn = null; try { dn = serv.FindFirstDN(context, filter); } catch (DirectoryOperationException e) { m_logger.ErrorFormat("DirectoryOperationException: {0}", e.Message); } if (dn != null) { m_logger.DebugFormat("Found DN: {0}", dn); return dn; } } m_logger.DebugFormat("No DN found in any of the contexts."); return null; }