Exchange 2010 SP2 provisioning separated through a new provider Exchange 2010 SP2 now compliant with product group guidelines Support for Database Availability Group Fixed Distribution List view scope to only tenant Consumer support (individual mailboxes as hotmail) added Mailbox configuration moved to mailbox plans concept CN creation is now based on UPN sAMAccountName generation revised and decoupled from tenant name 2007 (ACL Based), 2010 (ACL Bases), 2010 SP2 (ABP) supported Automated Hosted Organization provisioning added to create hosting space Enterprise Server webservice extended with ImportMethod Mobile tab fixed Added more information to users listview
416 lines
14 KiB
C#
416 lines
14 KiB
C#
// Copyright (c) 2011, Outercurve Foundation.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without modification,
|
|
// are permitted provided that the following conditions are met:
|
|
//
|
|
// - Redistributions of source code must retain the above copyright notice, this
|
|
// list of conditions and the following disclaimer.
|
|
//
|
|
// - Redistributions in binary form must reproduce the above copyright notice,
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
// and/or other materials provided with the distribution.
|
|
//
|
|
// - Neither the name of the Outercurve Foundation nor the names of its
|
|
// contributors may be used to endorse or promote products derived from this
|
|
// software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.DirectoryServices;
|
|
using System.DirectoryServices.ActiveDirectory;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
|
|
namespace WebsitePanel.Providers.HostedSolution
|
|
{
|
|
public class ActiveDirectoryUtils
|
|
{
|
|
public static DirectoryEntry GetADObject(string path)
|
|
{
|
|
DirectoryEntry de = new DirectoryEntry(path);
|
|
de.RefreshCache();
|
|
return de;
|
|
}
|
|
|
|
public static bool IsUserInGroup(string samAccountName, string group)
|
|
{
|
|
bool res = false;
|
|
DirectorySearcher deSearch = new DirectorySearcher
|
|
{
|
|
Filter =
|
|
("(&(objectClass=user)(samaccountname=" + samAccountName + "))")
|
|
};
|
|
|
|
//get the group result
|
|
SearchResult results = deSearch.FindOne();
|
|
DirectoryEntry de = results.GetDirectoryEntry();
|
|
PropertyValueCollection props = de.Properties["memberOf"];
|
|
|
|
foreach (string str in props)
|
|
{
|
|
if (str.IndexOf(group) != -1)
|
|
{
|
|
res = true;
|
|
break;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
public static string CreateOrganizationalUnit(string name, string parentPath)
|
|
{
|
|
string ret;
|
|
DirectoryEntry ou = null;
|
|
DirectoryEntry parent = null;
|
|
|
|
try
|
|
{
|
|
parent = GetADObject(parentPath);
|
|
|
|
ou = parent.Children.Add(
|
|
string.Format("OU={0}", name),
|
|
parent.SchemaClassName);
|
|
|
|
ret = ou.Path;
|
|
ou.CommitChanges();
|
|
}
|
|
finally
|
|
{
|
|
if (ou != null)
|
|
ou.Close();
|
|
if (parent != null)
|
|
parent.Close();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
public static void DeleteADObject(string path, bool removeChild)
|
|
{
|
|
DirectoryEntry entry = GetADObject(path);
|
|
|
|
if (removeChild && entry.Children != null)
|
|
foreach (DirectoryEntry child in entry.Children)
|
|
{
|
|
entry.Children.Remove(child);
|
|
}
|
|
|
|
DirectoryEntry parent = entry.Parent;
|
|
if (parent != null)
|
|
{
|
|
parent.Children.Remove(entry);
|
|
parent.CommitChanges();
|
|
}
|
|
}
|
|
|
|
|
|
public static void DeleteADObject(string path)
|
|
{
|
|
DirectoryEntry entry = GetADObject(path);
|
|
DirectoryEntry parent = entry.Parent;
|
|
if (parent != null)
|
|
{
|
|
parent.Children.Remove(entry);
|
|
parent.CommitChanges();
|
|
}
|
|
}
|
|
|
|
public static void SetADObjectProperty(DirectoryEntry oDE, string name, string value)
|
|
{
|
|
if (!string.IsNullOrEmpty(value))
|
|
{
|
|
if (oDE.Properties.Contains(name))
|
|
{
|
|
oDE.Properties[name][0] = value;
|
|
}
|
|
else
|
|
{
|
|
oDE.Properties[name].Add(value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (oDE.Properties.Contains(name))
|
|
{
|
|
oDE.Properties[name].Remove(oDE.Properties[name][0]);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
public static void SetADObjectPropertyValue(DirectoryEntry oDE, string name, string value)
|
|
{
|
|
PropertyValueCollection collection = oDE.Properties[name];
|
|
collection.Value = value;
|
|
}
|
|
|
|
public static void SetADObjectPropertyValue(DirectoryEntry oDE, string name, Guid value)
|
|
{
|
|
PropertyValueCollection collection = oDE.Properties[name];
|
|
collection.Value = value.ToByteArray();
|
|
}
|
|
|
|
public static void ClearADObjectPropertyValue(DirectoryEntry oDE, string name)
|
|
{
|
|
PropertyValueCollection collection = oDE.Properties[name];
|
|
collection.Clear();
|
|
}
|
|
|
|
|
|
public static object GetADObjectProperty(DirectoryEntry entry, string name)
|
|
{
|
|
return entry.Properties.Contains(name) ? entry.Properties[name][0] : null;
|
|
}
|
|
|
|
public static string GetADObjectStringProperty(DirectoryEntry entry, string name)
|
|
{
|
|
object ret = GetADObjectProperty(entry, name);
|
|
return ret != null ? ret.ToString() : string.Empty;
|
|
}
|
|
|
|
public static string ConvertADPathToCanonicalName(string name)
|
|
{
|
|
|
|
if (string.IsNullOrEmpty(name))
|
|
return null;
|
|
|
|
StringBuilder ret = new StringBuilder();
|
|
List<string> cn = new List<string>();
|
|
List<string> dc = new List<string>();
|
|
|
|
name = RemoveADPrefix(name);
|
|
|
|
string[] parts = name.Split(',');
|
|
for (int i = 0; i < parts.Length; i++)
|
|
{
|
|
if (parts[i].StartsWith("DC="))
|
|
{
|
|
dc.Add(parts[i].Substring(3));
|
|
}
|
|
else if (parts[i].StartsWith("OU=") || parts[i].StartsWith("CN="))
|
|
{
|
|
cn.Add(parts[i].Substring(3));
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < dc.Count; i++)
|
|
{
|
|
ret.Append(dc[i]);
|
|
if (i < dc.Count - 1)
|
|
ret.Append(".");
|
|
}
|
|
for (int i = cn.Count - 1; i != -1; i--)
|
|
{
|
|
ret.Append("/");
|
|
ret.Append(cn[i]);
|
|
}
|
|
return ret.ToString();
|
|
}
|
|
|
|
public static string ConvertDomainName(string name)
|
|
{
|
|
|
|
if (string.IsNullOrEmpty(name))
|
|
return null;
|
|
|
|
StringBuilder ret = new StringBuilder("LDAP://");
|
|
|
|
string[] parts = name.Split('.');
|
|
for (int i = 0; i < parts.Length; i++)
|
|
{
|
|
ret.Append("DC=");
|
|
ret.Append(parts[i]);
|
|
if (i < parts.Length - 1)
|
|
ret.Append(",");
|
|
}
|
|
return ret.ToString();
|
|
}
|
|
|
|
public static string GetNETBIOSDomainName(string rootDomain)
|
|
{
|
|
string ret = string.Empty;
|
|
|
|
string path = string.Format("LDAP://{0}/RootDSE", rootDomain);
|
|
DirectoryEntry rootDSE = GetADObject(path);
|
|
string contextPath = GetADObjectProperty(rootDSE, "ConfigurationNamingContext").ToString();
|
|
string defaultContext = GetADObjectProperty(rootDSE, "defaultNamingContext").ToString();
|
|
DirectoryEntry partitions = GetADObject("LDAP://cn=Partitions," + contextPath);
|
|
|
|
DirectorySearcher searcher = new DirectorySearcher();
|
|
searcher.SearchRoot = partitions;
|
|
searcher.Filter = string.Format("(&(objectCategory=crossRef)(nCName={0}))", defaultContext);
|
|
searcher.SearchScope = SearchScope.OneLevel;
|
|
|
|
//find the first instance
|
|
SearchResult result = searcher.FindOne();
|
|
if (result != null)
|
|
{
|
|
DirectoryEntry partition = GetADObject(result.Path);
|
|
ret = GetADObjectProperty(partition, "nETBIOSName").ToString();
|
|
partition.Close();
|
|
}
|
|
partitions.Close();
|
|
rootDSE.Close();
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
public static string CreateUser(string path, string user, string displayName, string password, bool enabled)
|
|
{
|
|
return CreateUser(path, "", user, displayName, password, enabled);
|
|
}
|
|
|
|
public static string CreateUser(string path, string upn, string user, string displayName, string password, bool enabled)
|
|
{
|
|
DirectoryEntry currentADObject = new DirectoryEntry(path);
|
|
|
|
string cn = string.Empty;
|
|
if (string.IsNullOrEmpty(upn)) cn = user; else cn = upn;
|
|
|
|
DirectoryEntry newUserObject = currentADObject.Children.Add("CN=" + cn, "User");
|
|
|
|
newUserObject.Properties[ADAttributes.SAMAccountName].Add(user);
|
|
SetADObjectProperty(newUserObject, ADAttributes.DisplayName, displayName);
|
|
newUserObject.CommitChanges();
|
|
newUserObject.Invoke(ADAttributes.SetPassword, password);
|
|
newUserObject.InvokeSet(ADAttributes.AccountDisabled, !enabled);
|
|
|
|
newUserObject.CommitChanges();
|
|
|
|
return newUserObject.Path;
|
|
}
|
|
|
|
public static void CreateGroup(string path, string group)
|
|
{
|
|
DirectoryEntry currentADObject = new DirectoryEntry(path);
|
|
|
|
DirectoryEntry newGroupObject = currentADObject.Children.Add("CN=" + group, "Group");
|
|
|
|
newGroupObject.Properties[ADAttributes.SAMAccountName].Add(group);
|
|
|
|
newGroupObject.Properties[ADAttributes.GroupType].Add(-2147483640);
|
|
newGroupObject.CommitChanges();
|
|
}
|
|
|
|
public static void AddUserToGroup(string userPath, string groupPath)
|
|
{
|
|
DirectoryEntry user = new DirectoryEntry(userPath);
|
|
DirectoryEntry group = new DirectoryEntry(groupPath);
|
|
|
|
group.Invoke("Add", user.Path);
|
|
}
|
|
|
|
public static bool AdObjectExists(string path)
|
|
{
|
|
return DirectoryEntry.Exists(path);
|
|
}
|
|
|
|
public static string RemoveADPrefix(string path)
|
|
{
|
|
string dn = path;
|
|
if (dn.ToUpper().StartsWith("LDAP://"))
|
|
{
|
|
dn = dn.Substring(7);
|
|
}
|
|
int index = dn.IndexOf("/");
|
|
|
|
if (index != -1)
|
|
{
|
|
dn = dn.Substring(index + 1);
|
|
}
|
|
return dn;
|
|
}
|
|
|
|
public static string AddADPrefix(string path, string primaryDomainController)
|
|
{
|
|
string dn = path;
|
|
if (!dn.ToUpper().StartsWith("LDAP://"))
|
|
{
|
|
if (string.IsNullOrEmpty(primaryDomainController))
|
|
{
|
|
dn = string.Format("LDAP://{0}", dn);
|
|
|
|
}
|
|
else
|
|
dn = string.Format("LDAP://{0}/{1}", primaryDomainController, dn);
|
|
}
|
|
return dn;
|
|
}
|
|
|
|
public static string AddADPrefix(string path)
|
|
{
|
|
return AddADPrefix(path, null);
|
|
}
|
|
|
|
private static void AddADObjectProperty(DirectoryEntry oDE, string name, string value)
|
|
{
|
|
if (!string.IsNullOrEmpty(value))
|
|
{
|
|
oDE.Properties[name].Add(value);
|
|
|
|
}
|
|
}
|
|
|
|
public static void AddUPNSuffix(string ouPath, string suffix)
|
|
{
|
|
//Add UPN Suffix to the OU
|
|
DirectoryEntry ou = GetADObject(ouPath);
|
|
AddADObjectProperty(ou, "uPNSuffixes", suffix);
|
|
ou.CommitChanges();
|
|
ou.Close();
|
|
}
|
|
|
|
public static void RemoveUPNSuffix(string ouPath, string suffix)
|
|
{
|
|
if (DirectoryEntry.Exists(ouPath))
|
|
{
|
|
DirectoryEntry ou = GetADObject(ouPath);
|
|
PropertyValueCollection prop = null;
|
|
|
|
prop = ou.Properties["uPNSuffixes"];
|
|
|
|
if (prop != null)
|
|
{
|
|
if (ou.Properties["uPNSuffixes"].Contains(suffix))
|
|
{
|
|
ou.Properties["uPNSuffixes"].Remove(suffix);
|
|
ou.CommitChanges();
|
|
}
|
|
ou.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public static string GetDomainName(string userName)
|
|
{
|
|
string str4;
|
|
string filter = string.Format(CultureInfo.InvariantCulture, "(&(objectClass=user)(Name={0}))", new object[] { userName });
|
|
using (DirectoryEntry entry = Domain.GetComputerDomain().GetDirectoryEntry())
|
|
{
|
|
using (DirectorySearcher searcher = new DirectorySearcher(entry, filter))
|
|
{
|
|
searcher.PropertiesToLoad.Add("sAMAccountName");
|
|
string str2 = searcher.FindOne().Properties["sAMAccountName"][0] as string;
|
|
str4 = string.Format(CultureInfo.InvariantCulture, @"{0}\{1}", new object[] { entry.Properties["Name"].Value as string, str2 });
|
|
}
|
|
}
|
|
return str4;
|
|
}
|
|
|
|
|
|
}
|
|
}
|