C#

Duo Universal C# ASP NET Web Forms

Duo recently released their new Universal two factor authentication method which changes from an iFrame method to using a redirect. Duo provides a C# example using .NET Core and MVC but if you still have old web forms applications you’ve built and aren’t ready, you can still integrate them with Duo Universal.

First, you’ll need to buil the DuoUniversal.dll binary from the project https://github.com/duosecurity/duo_universal_csharp and add it as a reference to your project. You’ll also need to make sure you’re running .NET Framework 4.7.1 or higher for your project.

Second, add the following items from Nuget to the project

  • System.Text.Json
  • System.Net.Http.Json
  • Microsoft.IdentityModel.Tokens
  • Microsoft.IdentityModel.JsonWebTokens

Now you’re ready to start integrating it into your current project.

  1. On your login page, add Using DuoUniversal
  2. Declare string values for Duo Settings
string ClientId = ""; //Setting from Duo
string ClientSecret = ""; //Setting from Duo
string ApiHost = ""; //Setting from Duo
string RedirectUri = "https://localhost:44310/Redirect.aspx"; //This is the URL you will redirect to after authentication. It does not need to be publically accessible.
  1. Create a new method InitiateDuo
public async void InitiateDuo(string User)
{
	//Create client using config settings
	Client duoClient = new DuoUniversal.ClientBuilder(ClientId, ClientSecret, ApiHost, RedirectUri).Build();
	Session["client"] = duoClient;


	// Check if Duo seems to be healthy and able to service authentications.
	// If Duo were unhealthy, you could possibly send user to an error page, or implement a fail mode
	var isDuoHealthy = await duoClient.DoHealthCheck();

	// Generate a random state value to tie the authentication steps together
	string state = DuoUniversal.Client.GenerateState();
	// Save the state and username in the session for later
	Session["STATE_SESSION_KEY"] = state;
	Session["USERNAME_SESSION_KEY"] = User;

	// Get the URI of the Duo prompt from the client.  This includes an embedded authentication request.
	string promptUri = duoClient.GenerateAuthUri(User, state);

	// Redirect the user's browser to the Duo prompt.
	// The Duo prompt, after authentication, will redirect back to the configured Redirect URI to complete the authentication flow.
	// In this example, that is /duo_callback, which is implemented in Callback.cshtml.cs.
	Response.Redirect(promptUri,false);

}
  1. Add the following code to the portion where you want to trigger the Duo prompt.
InitiateDuo(User); //User should be the username trying to login.
  1. On your login.aspx page, add Async=”true” to the top
<%@ Page Async="true" Language="C#"......
  1. Create a new Redirect page which Duo will transfer the user to after authenticating with two factor. Add add Using DuoUniversal to this page.
  2. Create a new method DUOResponse
 public async void DUOResponse(string sessionState, string sessionUsername, string receievedstate, string receivedcode)
{
	Client duoClient = (Client)Session["client"];

	//Confirm the original state(from the session) matches the state sent by Duo; this helps p
	if (!sessionState.Equals(receievedstate))
	{
		throw new DuoException("Session state did not match the expected state");
	}
	//Session.Clear();

	IdToken token = await duoClient.ExchangeAuthorizationCodeFor2faResult(receivedcode, sessionUsername);


	if (token.AuthResult.Result == "allow")
	{
		Session["authenticated"] = true;
		Response.Redirect("Home.aspx");

	}
}
  1. In the Page_Load method of the Redirect page add the following code
string sessionState = string.Empty;
if (Session["STATE_SESSION_KEY"] != null)
	sessionState = Session["STATE_SESSION_KEY"].ToString();
else
	Response.Redirect("login.aspx?Msg=" + HttpUtility.UrlEncode("Duo Session State Key Missing"));

string sessionUsername = string.Empty;
if (Session["userName"] != null)
	sessionUsername = Session["userName"].ToString();
else
	Response.Redirect("login.aspx?Msg=" + HttpUtility.UrlEncode("Duo Session Username Missing"));

string receievedstate = string.Empty;
if (Request.QueryString["state"] != null)
	receievedstate = Request.QueryString["state"];
else
	Response.Redirect("login.aspx?Msg=" + HttpUtility.UrlEncode("Duo State URL Variable Missing"));

string receivedcode = string.Empty;
if (Request.QueryString["code"] != null)
	receivedcode = Request.QueryString["code"];
else
	Response.Redirect("login.aspx?Msg=" + HttpUtility.UrlEncode("Duo Code URL Variable Missing"));

if (string.IsNullOrEmpty(sessionState) || string.IsNullOrEmpty(sessionUsername)
	|| string.IsNullOrEmpty(receievedstate) || string.IsNullOrEmpty(receivedcode))
{
	Response.Redirect("login.aspx?Msg=" + HttpUtility.UrlEncode("Duo null items"));
	return;
}

DUOResponse(sessionState, sessionUsername, receievedstate, receivedcode);
  1. On your Redirect.aspx page, add Async=”true” to the top
<%@ Page Async="true" Language="C#"......

Build and test. When you test it the first time you will see the old prompt. If everything works, you can go into Duo Admin console and turn on the new prompt.

Duo Universal C# ASP NET Web Forms Read More »

Active Directory Federation Services (ADFS) Authentication Adapter

https://github.com/Microsoft/adfsAuthAdapters/tree/master/UsernamePasswordSecondFactor

Microsoft has provided source code to allow a Username and Password to be used as a second factor of authentication in ADFS. You may ask, why would you want to have the usernam and password as a second factor?

  1. Some automated hacking attempts will can lock out your accounts and/or identify a username and password and obtain access through ADFS or another non-authenticated ADFS system. You can setup a different primary authentication like DUO and then username/password seconds.
  2. You may want to allow Windows Integrated Authentication (WIA) for internal connections but require certain relying parties to still require a password for access. Think payroll/financial applications.

The second reason is precisely why I initially was interested, however once it was compiled and deployed to ADFS, clicking the sign in button would not work but hitting the enter key would. After some diagnosing I determined that I was getting Javascript errors on the page referencing InputUtil. I remembered that years ago I had adjusted the onload.js Javascript for the login page of ADFS so that it did not require the domain name within the username text box. https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/advanced-customization-of-ad-fs-sign-in-pages. This Javascript function was still being called during the second factor authentication and causing the Javascript in the authentication adapter to not run.

To fix this, there are two things that need to be adjusted. Open the file StringResources.resx within the Visual Studio project and go to the key AuthPage. Add the following Javascript below, above function Login(), compile and redeploy to ADFS.

function LoginErrors(){
this.userNameFormatError = 'Enter your user ID in the format 
\u0026quot;domain\user\u0026quot;
 or \u0026quot;user@domain\u0026quot;.'; 
this.passwordEmpty = 'Enter your password.'; 
this.passwordTooLong = 'Password must be shorter than 128 characters.';
}; 
var maxPasswordLength = 128;

function InputUtil(errTextElementID, errDisplayElementID) {
if (!errTextElementID)  errTextElementID = 'errorText'; 
if (!errDisplayElementID)  errDisplayElementID = 'error'; 

this.hasFocus = false;
this.errLabel = document.getElementById(errTextElementID);
this.errDisplay = document.getElementById(errDisplayElementID);
};
 InputUtil.prototype.canDisplayError = function () {
     return this.errLabel && this.errDisplay;
 }
 InputUtil.prototype.checkError = function () {
     if (!this.canDisplayError){
         throw new Error ('Error element not present');
     }
     if (this.errLabel && this.errLabel.innerHTML) {
         this.errDisplay.style.display = '';        
         var cause = this.errLabel.getAttribute('for');
         if (cause) {
             var causeNode = document.getElementById(cause);
             if (causeNode && causeNode.value) {
                 causeNode.focus();
                 this.hasFocus = true;
             }
         }
     }
     else {
         this.errDisplay.style.display = 'none';
     }
};
 InputUtil.prototype.setInitialFocus = function (input) {
     if (this.hasFocus) return;
     var node = document.getElementById(input);
     if (node) {
         if ((/^\s*$/).test(node.value)) {
             node.focus();
             this.hasFocus = true;
         }
     }
 };
 InputUtil.prototype.setError = function (input, errorMsg) {
     if (!this.canDisplayError) {
         throw new Error('Error element not present');
     }
     input.focus();
if (errorMsg) {
    this.errLabel.innerHTML = errorMsg;
}
this.errLabel.setAttribute('for', input.id);
this.errDisplay.style.display = '';
};
 InputUtil.makePlaceholder = function (input) {
     var ua = navigator.userAgent;
if (ua != null && 
    (ua.match(/MSIE 9.0/) != null || 
     ua.match(/MSIE 8.0/) != null ||
     ua.match(/MSIE 7.0/) != null)) {
    var node = document.getElementById(input);
    if (node) {
        var placeholder = node.getAttribute("placeholder");
        if (placeholder != null && placeholder != '') {
            var label = document.createElement('input');
            label.type = "text";
            label.value = placeholder;
            label.readOnly = true;
            label.style.position = 'absolute';
            label.style.borderColor = 'transparent';
            label.className = node.className + ' hint';
            label.tabIndex = -1;
            label.onfocus = function () { this.nextSibling.focus(); };

            node.style.position = 'relative';
            node.parentNode.style.position = 'relative';
            node.parentNode.insertBefore(label, node);
            node.onkeyup = function () { InputUtil.showHint(this); };
            node.onblur = function () { InputUtil.showHint(this); };
            node.style.background = 'transparent';

            node.setAttribute("placeholder", "");
            InputUtil.showHint(node);
        }
    }
}
};
 InputUtil.focus = function (inputField) {
     var node = document.getElementById(inputField);
     if (node) node.focus();
 };
 InputUtil.hasClass = function(node, clsName) {
     return node.className.match(new RegExp('(\s|^)' + clsName + '(\s|$)'));
 };
 InputUtil.addClass = function(node, clsName) {
     if (!this.hasClass(node, clsName)) node.className += " " + clsName;
 };
 InputUtil.removeClass = function(node, clsName) {
     if (this.hasClass(node, clsName)) {
         var reg = new RegExp('(\s|^)' + clsName + '(\s|$)');
         node.className = node.className.replace(reg, ' ');
     }
 };
 InputUtil.showHint = function (node, gotFocus) {
     if (node.value && node.value != '') {
         node.previousSibling.style.display = 'none';
     }
     else {
         node.previousSibling.style.display = '';
     }
 };

You’ll also need to adjust the onload.js Javascript you imported into your ADFS theme. Change function if(Login) with the following.

if(Login) {
     Login.submitLoginRequest = function () { 
    //New Line - This checks to see if the user name text box is visible or not
     if(document.getElementById(Login.userNameInput) != null){
         var u = new InputUtil();
         var e = new LoginErrors();
         var userName = document.getElementById(Login.userNameInput);
         var password = document.getElementById(Login.passwordInput);
         if (userName.value && !userName.value.match('[@\\]')) 
         {
             var userNameValue = 'lorettosystem\' + userName.value;
             document.forms['loginForm'].UserName.value = userNameValue;
         }  
  if (!userName.value) {
       u.setError(userName, e.userNameFormatError);
       return false;
    }


    if (!password.value) 
    {
        u.setError(password, e.passwordEmpty);
        return false;
    }
      document.forms['loginForm'].submit();
return false;
}else{
    document.forms['loginForm'].submit();
    return false;
}
};
 }


Active Directory Federation Services (ADFS) Authentication Adapter Read More »

Directory Services–Cannot Change Password – Constraint Violation nTSecurityDescriptor

 

Recently I ran into an issue where trying to enable or disable the option ‘Cannot Change Password’ in Active Directory in my C# code. Using a Domain Administrator account the code worked perfectly fine, but when it was run under a non-administrator I would get “Constrain Violation Occurred” and the following exception

"0000051B: AtrErr: DSID-030F22B2, #1:\n\t0: 0000051B: DSID-030F22B2, problem 1005 (CONSTRAINT_ATT_TYPE), data 0, Att 20119 (nTSecurityDescriptor)\n"

Now the user in question was delegated full control over the user object which made it more frustrating as it could be done manually within Active Directory Users and Computers. What I did find out is that if the non-administrator user was assigned the owner of the user in the security option the code would work and is what lead me to the answer.

 

You must have the DirectoryEntry.Options.SecurityMasks defined to SecurityMasks.Dacl for it to work for a non-administrator user.

 

Allow Change Password

   1: public static void AllowChangePassword(DirectoryEntry user)

   2:        {

   3:            user.Options.SecurityMasks = SecurityMasks.Dacl;

   4:  

   5:            // Create a Guid that identifies the Change Password right.

   6:            Guid changePasswordGuid =

   7:                new Guid("{AB721A53-1E2F-11D0-9819-00AA0040529B}");

   8:  

   9:            // Get the ActiveDirectorySecurity for the user.

  10:            ActiveDirectorySecurity userSecurity = user.ObjectSecurity;

  11:  

  12:            // Create a SecurityIdentifier object for "everyone".

  13:            SecurityIdentifier everyoneSid =

  14:                new SecurityIdentifier(WellKnownSidType.WorldSid, null);

  15:  

  16:            // Create a SecurityIdentifier object for "self".

  17:            SecurityIdentifier selfSid =

  18:                new SecurityIdentifier(WellKnownSidType.SelfSid, null);

  19:  

  20:            // Create an access rule to allow everyone the change password 

  21:            // right. 

  22:            // This is used to remove any existing access rules.

  23:            ActiveDirectoryAccessRule allowEveryone =

  24:                new ActiveDirectoryAccessRule(

  25:                    everyoneSid,

  26:                    ActiveDirectoryRights.ExtendedRight,

  27:                    AccessControlType.Allow,

  28:                    changePasswordGuid);

  29:  

  30:            // Create an access rule to deny everyone the change password right.

  31:            ActiveDirectoryAccessRule denyEveryone =

  32:                new ActiveDirectoryAccessRule(

  33:                    everyoneSid,

  34:                    ActiveDirectoryRights.ExtendedRight,

  35:                    AccessControlType.Deny,

  36:                    changePasswordGuid);

  37:  

  38:            // Create an access rule to allow self the change password right.

  39:            // This is used to remove any existing access rules.

  40:            ActiveDirectoryAccessRule allowSelf =

  41:                new ActiveDirectoryAccessRule(

  42:                    selfSid,

  43:                    ActiveDirectoryRights.ExtendedRight,

  44:                    AccessControlType.Allow,

  45:                    changePasswordGuid);

  46:  

  47:            // Create an access rule to deny self the change password right.

  48:            ActiveDirectoryAccessRule denySelf =

  49:                new ActiveDirectoryAccessRule(

  50:                    selfSid,

  51:                    ActiveDirectoryRights.ExtendedRight,

  52:                    AccessControlType.Deny,

  53:                    changePasswordGuid);

  54:  

  55:            // Remove any existing rule that gives "everyone" the change 

  56:            // password right.

  57:            userSecurity.RemoveAccessRuleSpecific(denyEveryone);

  58:  

  59:            // Add a new access rule to deny "everyone" the change password 

  60:            // right.

  61:            userSecurity.AddAccessRule(allowEveryone);

  62:  

  63:            // Remove any existing rule that gives "self" the change password 

  64:            // right.

  65:            userSecurity.RemoveAccessRuleSpecific(denySelf);

  66:  

  67:            // Add a new access rule to deny "self" the change password right.

  68:            userSecurity.AddAccessRule(allowSelf);

  69:  

  70:            // Commit the changes.

  71:            user.CommitChanges();

  72:  

  73:            user.Options.SecurityMasks = SecurityMasks.None;

  74:        }

 

Deny Change Password

   1: public static void DenyChangePassword(DirectoryEntry user)

   2:       {

   3:           user.Options.SecurityMasks = SecurityMasks.Dacl;

   4:           

   5:           // Create a Guid that identifies the Change Password right.

   6:           Guid changePasswordGuid =

   7:               new Guid("{AB721A53-1E2F-11D0-9819-00AA0040529B}");

   8:  

   9:           // Get the ActiveDirectorySecurity for the user.

  10:           ActiveDirectorySecurity userSecurity = user.ObjectSecurity;

  11:  

  12:           // Create a SecurityIdentifier object for "everyone".

  13:           SecurityIdentifier everyoneSid =

  14:               new SecurityIdentifier(WellKnownSidType.WorldSid, null);

  15:  

  16:           // Create a SecurityIdentifier object for "self".

  17:           SecurityIdentifier selfSid =

  18:               new SecurityIdentifier(WellKnownSidType.SelfSid, null);

  19:  

  20:           // Create an access rule to allow everyone the change password 

  21:           // right. 

  22:           // This is used to remove any existing access rules.

  23:           ActiveDirectoryAccessRule allowEveryone =

  24:               new ActiveDirectoryAccessRule(

  25:                   everyoneSid,

  26:                   ActiveDirectoryRights.ExtendedRight,

  27:                   AccessControlType.Allow,

  28:                   changePasswordGuid);

  29:  

  30:           // Create an access rule to deny everyone the change password right.

  31:           ActiveDirectoryAccessRule denyEveryone =

  32:               new ActiveDirectoryAccessRule(

  33:                   everyoneSid,

  34:                   ActiveDirectoryRights.ExtendedRight,

  35:                   AccessControlType.Deny,

  36:                   changePasswordGuid);

  37:  

  38:           // Create an access rule to allow self the change password right.

  39:           // This is used to remove any existing access rules.

  40:           ActiveDirectoryAccessRule allowSelf =

  41:               new ActiveDirectoryAccessRule(

  42:                   selfSid,

  43:                   ActiveDirectoryRights.ExtendedRight,

  44:                   AccessControlType.Allow,

  45:                   changePasswordGuid);

  46:  

  47:           // Create an access rule to deny self the change password right.

  48:           ActiveDirectoryAccessRule denySelf =

  49:               new ActiveDirectoryAccessRule(

  50:                   selfSid,

  51:                   ActiveDirectoryRights.ExtendedRight,

  52:                   AccessControlType.Deny,

  53:                   changePasswordGuid);

  54:  

  55:           // Remove any existing rule that gives "everyone" the change 

  56:           // password right.

  57:           userSecurity.RemoveAccessRuleSpecific(allowEveryone);

  58:  

  59:           // Add a new access rule to deny "everyone" the change password 

  60:           // right.

  61:           userSecurity.AddAccessRule(denyEveryone);

  62:  

  63:           // Remove any existing rule that gives "self" the change password 

  64:           // right.

  65:           userSecurity.RemoveAccessRuleSpecific(allowSelf);

  66:  

  67:           // Add a new access rule to deny "self" the change password right.

  68:           userSecurity.AddAccessRule(denySelf);

  69:  

  70:           // Commit the changes.

  71:           user.CommitChanges();

  72:  

  73:           user.Options.SecurityMasks = SecurityMasks.None;

  74:       }

Directory Services–Cannot Change Password – Constraint Violation nTSecurityDescriptor Read More »

Apple Account Auto Verify

 

A tool I wrote in C# that automatically verifies apple accounts. Below is a link to the source code (Visual Studio 2010), however if you meet the following criteria, you can use it without modifying the code.

  1. Windows computer running .Net 4.0
  2. Running Exchange 2010
  3. Know the username and password to the mailbox that the verification email from apple is in, or you know the username and password to an elevated account that has permission to view the mailbox that the verification email from apple is in.

https://www.brandonclaps.com/downloads/AppleAccountVerify.zip – Includes source code too

If you meet the above criteria, unzip and browse to AppleAccountVerify > bin > Release > and run AppleAccountVerify.exe

 

Code:

   1: private void button_Verify_Click(object sender, EventArgs e)

   2:        {

   3:            string Log = string.Empty;

   4:            using (StreamReader sr = new StreamReader(textBox_CSVFile.Text))

   5:            {

   6:                string line;

   7:                while ((line = sr.ReadLine()) != null)

   8:                {

   9:                    string[] data = line.Split(',');

  10:  

  11:                    string ExchAuthUsername = data[0];

  12:                    string ExchAuthPassword = data[1];

  13:                    string ExchAuthDomain = data[2];

  14:                    string Exch_User_Email = data[3];

  15:                    string AppleUsername = data[4];

  16:                    string ApplePassword = data[5];

  17:  

  18:                    string Verify = GetAppleVerifyURL(ExchAuthUsername, ExchAuthPassword, ExchAuthDomain, Exch_User_Email);

  19:  

  20:                    if (Verify != string.Empty)

  21:                    {

  22:                        WebBrowser web = new WebBrowser();

  23:                        web.ScriptErrorsSuppressed = true;

  24:                        web.Navigate(new Uri(Verify));

  25:  

  26:                        while (web.ReadyState != WebBrowserReadyState.Complete)

  27:                        {

  28:                            Application.DoEvents();

  29:                        }

  30:                        try

  31:                        {

  32:                            HtmlElement el = web.Document.All["appleID"];

  33:  

  34:                            el.SetAttribute("value", AppleUsername);

  35:                            el.SetAttribute("text", AppleUsername);

  36:  

  37:                            HtmlElement el2 = web.Document.All["accountpassword"];

  38:  

  39:                            el2.SetAttribute("value", ApplePassword);

  40:                            el2.SetAttribute("text", ApplePassword);

  41:  

  42:                            foreach (HtmlElement el3 in web.Document.All)

  43:                            {

  44:                                if (el3.GetAttribute("className") == "btn bigblue")

  45:                                {

  46:                                    if (el3.InnerText.ToLower() == "verify address")

  47:                                    {

  48:                                        el3.InvokeMember("click");

  49:                                    }

  50:                                }

  51:                            }

  52:                            Log = Log + Environment.NewLine + AppleUsername + " - Verified successfully.";

  53:                        }

  54:                        catch (Exception Ex)

  55:                        {

  56:                            Log = Log + Environment.NewLine + AppleUsername + " - " + Ex.Message.ToString();

  57:                        }

  58:  

  59:                        Log = Log + Environment.NewLine + AppleUsername + " - Finished reading line";

  60:                    }

  61:                }

  62:            }

  63:            Log = Log + Environment.NewLine + " - Complete";

  64:            textBox_Log.Text = Log;

  65:        

  66:        }

Updated 12/29/14 – Updated code below (source code includes update)

   1: private static string GetAppleVerifyURL(string ExchangeAuthUsername, string ExchangeAuthPassword, string ExchangeAuthDomain, string EmailAddressToLookIn)

   2:        {

   3:            string URL = string.Empty;

   4:            try

   5:            {

   6:                ExchangeService ExchService = new ExchangeService(ExchangeVersion.Exchange2010_SP2);

   7:                ExchService.Credentials = new WebCredentials(ExchangeAuthUsername, ExchangeAuthPassword, ExchangeAuthDomain);

   8:                ExchService.AutodiscoverUrl(EmailAddressToLookIn);

   9:  

  10:                FolderId InboxID = new FolderId(WellKnownFolderName.Inbox, EmailAddressToLookIn);

  11:                ItemView view = new ItemView(50, 0, OffsetBasePoint.Beginning);

  12:                view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);

  13:                view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.DateTimeReceived, ItemSchema.Subject);

  14:                FindItemsResults<Item> findResults = ExchService.FindItems(InboxID, view);

  15:  

  16:                if (findResults != null && findResults.Items != null && findResults.Items.Count > 0)

  17:                    foreach (Item item in findResults.Items)

  18:                    {

  19:                        EmailMessage message = EmailMessage.Bind(ExchService, item.Id, new PropertySet(BasePropertySet.IdOnly, EmailMessageSchema.IsRead, ItemSchema.Body, ItemSchema.Subject, ItemSchema.Categories));

  20:  

  21:                        if (message.Subject.ToLower().Contains("verify your apple"))

  22:                        {

  23:                            string body = message.Body.Text;

  24:                            string[] AfterVerifyText = Regex.Split(body, "To verify this email address belongs to you");

  25:                            string[] BeginningOfURL = Regex.Split(AfterVerifyText[1], "<a href=\"");

  26:                            int Location_EndOfUrl = BeginningOfURL[1].IndexOf('"');

  27:                            URL = BeginningOfURL[1].Substring(0, Location_EndOfUrl);

  28:                            message.IsRead = true;

  29:                            message.Update(ConflictResolutionMode.AutoResolve);

  30:                        }

  31:                    }

  32:            }

  33:            catch (Exception)

  34:            {

  35:                return URL;

  36:            }

  37:  

  38:            return URL; 

  39:        }

Apple Account Auto Verify Read More »

Check group membership from AD with Foreign Security Principals

The following code will check if a user is a member of a specific group. This will work with a domain trust and Foreign Security Principals.

See the update below!

groupName = The sAMAccountName of the group you want to check the members of.
SearchDomain = This is the FQDN that you will be searching for the group. Ex: contoso.com
userName = This is the sAMAccountName of the user that you are checking if they are part of the group.
userDomain = This is the NetBIOS name of the domain of the user that you are checking. This really only comes into play when you are checking a user from a domain trust. Ex. CONTOSO
UserIsNativeDomain = This is true if the user you are checking is in the SearchDomain. If this is false, the user is in a domain trust and the code should be looking for the Foreign Security Principal and matching it to the userDomain and userName.

static bool CheckIfGroupMember(string groupName, string SearchDomain, string userName, string userDomain, bool UserIsNativeDomain)

        {

            bool GroupMember = false;                         

            string UserDN = string.Empty;           

            string FullLogonName = userDomain + "\\" + userName;

 

           if (UserIsNativeDomain == true)               

            {

                try //Get User's distinguishedName

                {                    

                    System.DirectoryServices.DirectoryEntry entry2 = new System.DirectoryServices.DirectoryEntry("LDAP://" + SearchDomain);

                    System.DirectoryServices.DirectorySearcher mySearcher2 = new System.DirectoryServices.DirectorySearcher(entry2);

                    mySearcher2.Filter = "(&(objectCategory=person)(ObjectClass=user)(sAMAccountName=" + userName + "))";

                    mySearcher2.PageSize = 1000;

                    System.DirectoryServices.SearchResult sr2 = mySearcher2.FindOne();

                    if (sr2 != null)

                    {

                        System.DirectoryServices.DirectoryEntry de2 = sr2.GetDirectoryEntry();

                        UserDN = de2.Properties["distinguishedName"].Value.ToString();

                        de2.Close();

                    }

                }

                catch (DirectoryServicesCOMException e2) { Console.Write(e2.Message); }

            }

 

            try //Check Group Membership

            {

                System.DirectoryServices.DirectoryEntry entry = new System.DirectoryServices.DirectoryEntry("LDAP://" + SearchDomain);

                System.DirectoryServices.DirectorySearcher mySearcher = new System.DirectoryServices.DirectorySearcher(entry);

                mySearcher.Filter = "(&(objectCategory=group)(sAMAccountName=" + groupName + "))";

                mySearcher.PageSize = 1000;

                System.DirectoryServices.SearchResult sr = mySearcher.FindOne();

                System.DirectoryServices.DirectoryEntry de = sr.GetDirectoryEntry();

 

                object[] members = (object[])de.Properties["member"].Value;

                foreach (object member in members)

                {

                    if (UserIsNativeDomain == false &&

                        member.ToString().Contains("CN=S-1-5"))   //If group member is a Foreign Security Principal

                    {

                        if (GetUserNameOfFSP(member.ToString()).ToLower() == FullLogonName.ToLower())

                        {

                            GroupMember = true;

                            break;

                        }

 

                    }

                    else

                    {

                        if (member.ToString().ToLower() == UserDN)

                        {

                            GroupMember = true;

                            break;

                        }

                    }

                }

                de.Close();

                return GroupMember;

            }

            catch (DirectoryServicesCOMException e) { Console.Write(e.Message); }

            return GroupMember;

        }

UPDATE 5/19/14: While working on an Active Directory Migration project using ADMT I found an issue with the code above. If you’re migrating a user from the source domain who is a member in a group in the target domain already it uses a Foreign Security Principal. Well after the ADMT migrates the user to the target domain, the user still shows as a Foreign Security Principal in the target domains group but with an updated domain name in the ForeignSecurityPrincipal OU. This new code will resolve that issue and handle it as necessary.

groupName = The sAMAccountName of the group you want to check the members of.

groupDomain = This is the FQDN that you will be searching for the group. Ex: contoso.com

userName = This is the sAMAccountName of the user that you are checking if they are part of the group.

userDomain = This is the NetBIOS name of the domain of the user that you are checking. Ex. CONTOSO

static bool CheckIfGroupMember(string groupName, string groupDomain, string userName, string userDomain)

{          

    bool GroupMember = false;

    string UserDN = string.Empty;

    string FullLogonName = userDomain + "\\" + userName;

 

    try //Get User's distinguishedName

    {

        DirectoryEntry entry2 = new DirectoryEntry("LDAP://" + userDomain);

        DirectorySearcher mySearcher2 = new DirectorySearcher(entry2);

        mySearcher2.Filter = "(&(objectCategory=person)(ObjectClass=user)(sAMAccountName=" + userName + "))";

        mySearcher2.PageSize = 1000;

        SearchResult sr2 = mySearcher2.FindOne();

        if (sr2 != null)

        {

            DirectoryEntry de2 = sr2.GetDirectoryEntry();

            UserDN = de2.Properties["distinguishedName"].Value.ToString();

            de2.Close();

        }

        entry2.Close();

    }

    catch (DirectoryServicesCOMException e2) { Console.Write(e2.Message); }

  

 

    try //Check Group Membership

    {

        DirectoryEntry entry = new DirectoryEntry("LDAP://" + groupDomain);

        DirectorySearcher mySearcher = new DirectorySearcher(entry);

        mySearcher.Filter = "(&(objectCategory=group)(sAMAccountName=" + groupName + "))";

        mySearcher.PageSize = 1000;

        SearchResult sr = mySearcher.FindOne();

        DirectoryEntry de = sr.GetDirectoryEntry();

 

        object[] members = (object[])de.Properties["member"].Value;

        foreach (object member in members)

        {

            if (member.ToString().Contains("CN=S-1-5"))

            {

                string FSPName = GetUserNameOfFSP(member.ToString().ToLower());

                if (FSPName.ToLower() == FullLogonName.ToLower())

                {

                    GroupMember = true;

                    break;

                }

            }

            else

            {

                if (member.ToString().ToLower() == UserDN.ToLower())

                {

                    GroupMember = true;

                    break;

                }

            }                

        }             

    }

    catch (DirectoryServicesCOMException e) { Console.Write(e.Message); }

 

    return GroupMember;

}

Check group membership from AD with Foreign Security Principals Read More »

Get username and domain of Foreign Security Principal from domain trust

You can use this code to determine the DOMAIN\username from the Foreign Security Principal which is really the SID of the account. Pass the full distinguishedName of the ForeignSecurityPrincipal.

static string GetUserNameOfFSP(string ForeignSecurityPrincipal)

       {

           //Returns with syntax of "DOMAIN\logonname"

           try

           {

               DirectoryEntry user = new DirectoryEntry("LDAP://" + ForeignSecurityPrincipal);

               SecurityIdentifier sid = new SecurityIdentifier((byte[])user.InvokeGet("objectSid"), 0);

               NTAccount account = (NTAccount)sid.Translate(typeof(NTAccount));

               return account.ToString();

           }

           catch (DirectoryServicesCOMException e) { Console.Write(e.Message); return "Error"; }

       }

Get username and domain of Foreign Security Principal from domain trust Read More »

Authenticate a user against Active Directory including domain trust

Authenticate a user’s credentials with this code against a domain. This also works with a domain trust.

static bool AuthenticateUser(string userName, string password, string domain)

        {

            bool authentic = false;

            try

            {

                DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain,

                    userName, password);

                object nativeObject = entry.NativeObject;

                authentic = true;

            }

            catch (DirectoryServicesCOMException e) { Console.Write(e.Message); }

            return authentic;

        }

Authenticate a user against Active Directory including domain trust Read More »

WindowsIdentity Impersonation – An attempt was made to reference a token that does not exist

 

Was working on a ASP.NET app to impersonate a domain user to access a network resource and came across the error “An attempt was made to reference a token that does not exist”.

When defining the domain for the following function, make sure it is in the FQDN format. domain.com and not DC=domain,DC=com 

private bool impersonateValidUser(String userName, String domain, String password)

Impersonation Reference: http://support.microsoft.com/kb/306158

WindowsIdentity Impersonation – An attempt was made to reference a token that does not exist Read More »