Howto: [] Use Request.LogonUserIdentity to fetch the current user's Active Directory DirectoryEntry?0 Reacties

If you have a website using ASP pages or pages, and you want to integrate user management with active directory, you’ll have a lot of extra technology that you need to make yourself known with. 


Add this article to my Live favorites


What you mostly would do, is disable anonymous web access, and have users login, using credentials stored at Active Directory.


But unfortunately, IIS, Internet Information Server, on Windows 2003 and 2000, does map only the current logged on user through an NT4 domain format, which looks like ‘DOMAIN\johnd’ retrieved from Request.ServerVariables(“LOGON_USER”) or Request.LogonUserIdentity.Name, will equal exactly that name in NT 4 format. You can also logon to an IIS website using a user principal  (in AD, this the attribute userPrincipalName like 'johnd@domain') but we need to be sure that the identity -always- can be handled, no matter what syntax is given by the user at logon.


So from there you need to translate the NT4 name to a distinguished Name (dn is like  “cn=itsme,cn=users,dc=nwtraders,dc=msft”)  that is suitable for Active Directory.


Now comes an often made ‘trick’ which is obviously slow (see for a listing, completely below)! 

One could do a Directory Search on sAMAccountName=’johnd’ and get the active, logged on user and its active directory record. <- don't do this!


A very fast method would be as follows.
note: this is assuming that you are using the DotNet framework version 2.0 and c#. The very same effective code could be written for Vb.Net.



protected void Page_Load(object sender, EventArgs e)


// identical to Request.LogonUserIdentity but using a static method instead of a Page property
//WindowsIdentity wi = System.Security.Principal.WindowsIdentity.GetCurrent();

wi = System.Security.Principal.WindowsIdentity.GetCurrent();

        WindowsIdentity wi = Request.LogonUserIdentity;

        DirectoryEntry dir = new DirectoryEntry("LDAP:// + SidToHex(wi.User) + ">");


        dir = new DirectoryEntry("LDAP://" + (string)dir.Properties["distinguishedName"][0], null, null,

            AuthenticationTypes.Secure |




//Now you got ‘dir’ at your disposal and you can read the current users profile information (for instance)!




To get Request.LogonUserIdentity initialized after a browser logon to your aspx pages, with the correct user-logon-info,

configure web.Config as follows so that it contains at least the configuration seen below.



xml version="1.0" encoding="utf-8"?>

<configuration xmlns="">


            <compilation defaultLanguage="c#" debug="true">


            <add assembly="System.DirectoryServices, Version=, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>

                  <add assembly="System.Security, Version=, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>



        <authentication mode="Windows" />

        <identity impersonate="true"/>





    ///  needed for Windows 2000 compatibility

    /// Windows 2003 can bind using a S-1-xx-x-xx-xxx- format




    private static string SidToHex(SecurityIdentifier sid)


        int binLength = sid.BinaryLength;

        byte[] bt = new byte[binLength];

        sid.GetBinaryForm(bt, 0);

        System.Text.StringBuilder retval = new System.Text.StringBuilder(binLength * 2, binLength * 2);

        for (int cx = 0; cx < binLength; cx++)       


        return retval.ToString();


Bad performing often used code, not to be used!

string ldapPath = "LDAP://" + userDomain;
DirectoryEntry rootEntry = new DirectoryEntry(ldapPath);
using (DirectorySearcher ds = new DirectorySearcher(rootEntry, "(samAccountName=" + userName + ")"))
            SearchResult result = ds.FindOne();
            if (result != null)
                        ResultPropertyValueCollection resultValues = result.Properties["displayName"];
                        if (resultValues.Count > 0)
                                    Label1.Text = (string) resultValues[0];
                                    Label1.Text = "No display name"; 

[C++] a Full Featured CAtlServiceModuleT implementation...0 Reacties

I had to do some maintenance on a Windows ® service and found that you can use an ATL service as a windows service very well without all the overhead.


There are some samples on the internet, but they stop where I wanted to continue. That is, run UI-less services for instance, a job that could be done through a task scheduled-job but better be done through a service?


b.t.w. for the ones interested in a minimal windows service and who feel a sick inclination J writing the smallest EXE possible, they should use  a plain C implementation provided by  Microsoft’s ® Platform SDK located at [Platform SDK folder]\Samples\WinBase\Service and they should not use MS VC 8 but 4 or so...


Note that the grey highlighted code, is my code, the normal colored code is left over of what the MS Visual Studio created for you through the wizard. In addition, I’ve snipped all trace & debugging code.

The Visual Studio 2005 wizard creates an EXE that is suitable both as COM service (DCOM) and as windows service. You can guess a lot of overhead and unneeded lines.


This service does not perform anything, keep in mind it is a template for a 'scheduled' task-service, a batch for instance. Your code comes within DoDBMSJob...


// Service_Template.cpp : Implementation of WinMain


#include "stdafx.h"

#include "resource.h"


#include "Service_Template.h"

#pragma warning(disable: 4482) // nonstandard extension used: 'enum CServiceStatus' used in qualified name


[v1_enum] //32 bit rulez

enum CServiceStatus


      run = 0,


      stop = 2,



class CService_Module : public CAtlServiceModuleT< CService_Module, IDS_SERVICENAME >



      // this flag in milliseconds, tells us how often

      // is checked for tasks

      DWORD m_iPollTime;

      HANDLE m_ThreadHandle; // eventually use CHandle

      HANDLE  m_hServerStopEvent;

      bool connDone;

      CServiceStatus m_ServiceStatus ;

      bool stopNow;

public :

      ~CService_Module() throw()


            if (m_ThreadHandle != NULL)


            if (m_hServerStopEvent != NULL)



      CService_Module()  throw():   m_iPollTime(10), m_ThreadHandle(NULL), m_hServerStopEvent(NULL),



            m_ServiceStatus =CServiceStatus::run;

            //m_dwTimeOut = 60000; // one minute




      // we can’t skip this! Leave as is created by wizard



      HRESULT InitializeSecurity() throw()


// we don’t need this here

            return S_OK;



      void OnPauze() throw()


            m_ServiceStatus = CServiceStatus::pauze;


            if ( m_hServerStopEvent != NULL)




      void OnStop() throw()



            m_ServiceStatus =CServiceStatus::stop;

            if ( m_hServerStopEvent != NULL)


                  stopNow= true;

                  // be sure not to kill the thread & process

                  // before it nicely ends

                  // otherwise, our pointers will ‘Release()’ while

                  // the instance has been killed already, a common bug!


                  DWORD tc = GetTickCount();

                  while(m_hServerStopEvent != NULL || GetTickCount() - tc > 20000) // max 20 seconds wait





      void OnContinue( ) throw( )



            m_ServiceStatus =CServiceStatus::run;

            if ( m_hServerStopEvent != NULL)




      void OnShutDown() throw()



            m_ServiceStatus =CServiceStatus::pauze;

            if ( m_hServ

HOWTO: [DotNet] marshale a managed string array for Interop0 Reacties

Normally if you have defined a struct in C# which is for a Win32 call, you might tend to copy-paste it from C++, and then modify LPWSTR to string and add attributes (etc),
like this:

struct myStruct
   public string blah; //ok
   [MarshalAs(UnmanagedType.ByValArray, ArraySubType=UnmanagedType.LPWStr)]   
    public string[] stringarray;

Let's concentrate on the array definition. The original array was defined like LPWSTR* stringarray;  this is an array of pointers to zero-terminated strings.

Now you thought, that a few attributes, would be sufficient to support your interop?

[MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr)]   
public string[] stringarray;

but the .NET framework, won't support you here. It is not able to create an unmanaged array of 'some type' on structs (this however, is working for parameter definitions) and to pass it to your unmanaged API.

And if you wonder what UnmanagedType.ByValArray, UnmanagedType.LPWStr  really does; it creates a pointer to a contigous block of zero terminated strings. It would not create an array of stringpointers. So now you know, why interop is an art, not a science :)

At last, I wrote an easy wrapper. It returns an IntPtr which is a just pointer to our first element to an array of string pointers :)

You should assign this class as a member variable on your own class. If you use this class inside a member function, your unmanaged memory might be cleaned when the function goes out of scope.
PS: Please send back the improved code, if you decide to use it (at your own risk of course). It might be improved, to pack managed structures as well, using C# generics.


class myClass()

{   private packLPArray packit;      

      void myMemberfunction()
      {   // ... do your dangerous, endeavourish :) interop thing here
            packit = new packLPArray(new string[] {"element1", "element2", "blah"});
            mystruct.stringarray = packit.arrayPtr;




packs an array of strings (type = string[]) to unmanaged memory
/// also works for 64-bit environments

public sealed class  packLPArray
    private IntPtr taskAlloc;

    private readonly int _length;

    private IntPtr[] _strings;

    public packLPArray(string[] theArray)

    {   int sizeIntPtr = IntPtr.Size;

        int neededSize = 0;

        if (theArray != null)


            this._length = theArray.Length;

            this._strings = new IntPtr[this._length];

           // System.Diagnostics.Debugger.Break();

            neededSize = this._length * sizeIntPtr;

            this.taskAlloc = Marshal.AllocCoTaskMem(neededSize);           

            for (int cx = this._length - 1; cx >= 0; cx--)
            {   this._strings[cx] = Marshal.StringToCoTaskMemUni(theArray[cx]);
                Marshal.WriteIntPtr(this.taskAlloc, cx * sizeIntPtr, this._strings[cx]);





    /// retrieves array length


    public int Length


        get { return _length; }


    public IntPtr arrayPtr


        get { return this.taskAlloc; }



    ~packLPArray() // clean up the rub


        if (taskAlloc != IntPtr.Zero)



            int cx = this._length;

            while(cx-- != 0)





A C# implementation of DsCrackNames for a NameTranslate class, what about unsafe code? (update)0 Reacties

Have you ever tried to pinvoke a function, that returns a pointer to an array of structs? There's you can easily marshale them using safe C# code but if the code was not written already and you can't simply copy-paste that :), I promise to you, that you'll have to do a lot more work to get it done. unsafe code might be a quicker solution.

You could use unsafe code in the following situations:

a) You are not writing code or utilities, that might or will run in restricted environments, such as with an ISP environment. And ISPs (eg.) should not allow .NET to run third-party code that needs full-trust policies.
b) You have knowledge about pointers using C++
c) Your program will not be completely 'type safe', this is what some evangelists say, however, I don't see a flawless windows or webfarm if only everything were typesafe :).

Therefore, I propagate, that the biggest part, if not all, of your code, is type-safe. If some tiny utilities, are tested well and in favor of speed and power and possibilities, need to be type-unsafe, just go on.

If conditions have been considered, make your decision. Eventually stop reading now and wait for other postings :).

Such a candidate to be marked as unsafe, would be DsCrackNames, for the COM/automation world, it would be clever to instantiate the NameTranslate class which has an IDispatch interface (good for scripting as well).
Since ít's my hobby, to avoid easy solutions :) I wrote a unique (for the moment, I did not find another on the internet) wrapper for DsCrackNames which run nearly identical its earlier automation friend.

Let's have a look at the MSDN definition of this function.:
DWORD DsCrackNames(
  DS_NAME_FORMAT formatOffered
  DS_NAME_FORMAT formatDesired
  DWORD cNames
  LPCTSTR* rpNames


Wow! this promises a lot of troubles, since PDS_NAME_RESULT is a pointer to a structure which contains an array of pointers to another sequential struct.

MSDN definition:
typedef struct
  DWORD cItems;

And here's the struct  rItems refers to...

typedef struct {
DWORD status;
LPTSTR pDomain;


I do challence you, to write a 'safe' equivalent to it, I tried it, and believe me, the .NET framework does its stinking best to tell you that your attributes are not valid.

Of course, we understand that it simply is not possible  unless you jump to a MC++ solution or you use the definition from which is requires a lot tricky code (no offense to anybody)... .

You cannot use attributes on the structure, and pass the stuff in one single call to the platform invoke and have the net framework do the actual marshaling for you.  You should create some looping work using Marshal.ReadInt32 (..) if you go for the 'safe' code solution .

I want to stress the point that safe platform invokes are not necessarily safer! They can leak memory as hell sorry, as well.

I've tried to use the [MarshalAs] attribute, but a having interop fill an array of IntPtrs inside a struct is not supported by the IL environment. Yes, you can try something like

        int cItems;
        IntPtr firstItem; //will work only if you crack one item or if you use Marshal.ReadInt32 etc code seen at

Or try this... But now you have a managed array of IntPtr and that won't work as well.

        int cItems;
        IntPtr[] pDS_NAME_RESULT_ITEM; //won't be marshaled since the framework cannot create and marshale this array on the fly

and DS_NAME_RESULT ITEM would be like:

public int status;
public string pDomain;
public string pName;
} ;

Let's see how easy you could write the solution set the 'unsafe'  attribute in spite of how disastrous this might sound.

Unsafe only allows for easy interop with unmaged IL code, this is a facto default with MC++, where you easily can use all those .h files, (windows.h, winbase.h etc) without having to retype all your DllImport statements or without having to copy them from which often has untested declares. I could have use MC++ as well, but if you want to expose the assembly for reusage, you'll start to redefine all those Win32 enums and constants anyway. We have to learn to live with the border between managed and unmanged code.

Our 'unsafe' CSharp code, looks very much like a C++ implementation. In addition, it offers some improvements over the IADsNameTranslate interface (that you derive from NameTranslate, with Guid("b1b272a3-3625-11d1-a3a4-00c04fb950dc").

Some remarks about my style of programming: I really don't like ansi or Win9x compatible code. Screw it! :), as you can see, my declares favor Windows 2000 and higher. Also take in account, that this is not full proof & tested code.

Have fun using this code.

/* Copyright, Nierop Webconsultancy 2005

 * Use of this code, in your projects, is for your own risk.

 * If you modify the code, you send improvements back

 * If you copy the code, you won't remove the credits for the code


using System;

using System.DirectoryServices;

using System.Runtime.InteropServices;

using System.DirectoryServices.ActiveDirectory;

using System.Data;

using System.ComponentModel;



namespace NameTranslate


    public enum ADS_NAME_INITTYPE_ENUM



        /// Initializes a NameTranslate object by setting the domain that the object binds to.




        /// Initializes a NameTranslate object by setting the server that the object binds to.




        /// Initializes a NameTranslate object by locating the global catalog that the object binds to



    } ;


    public enum DS_NAME_FORMAT


        DS_UNKNOWN_NAME = 0,

        DS_FQDN_1779_NAME = 1,

        DS_NT4_ACCOUNT_NAME = 2,

        DS_DISPLAY_NAME = 3,

        DS_UNIQUE_ID_NAME = 6,

        DS_CANONICAL_NAME = 7,





        DS_DNS_DOMAIN_NAME = 12

    } ;


    enum DS_NAME_FLAGS



        /// Indicates that there are no associated flags


        DS_NAME_NO_FLAGS = 0x0,


        /// Performs a syntactical mapping at the client without transferring over the network.

        /// The only syntactic mapping supported is from DS_FQDN_1779_NAME to DS_CANONICAL_NAME or DS_CANONICAL_NAME_EX.

        /// DsCrackNames returns the DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING flag if a syntactical mapping is not possible.




        /// Forces a trip to the domain controller for evaluation, even if the syntax could be cracked locally


        DS_NAME_FLAG_EVAL_AT_DC = 0x2,


        /// The call fails if the domain controller is not a global catalog server.


        DS_NAME_FLAG_GCVERIFY = 0x4,


        /// Enables cross forest trust referral.



    } ;

    public enum DS_NAME_ERROR



        /// The conversion was successful.


        DS_NAME_NO_ERROR = 0,


        /// A generic processing error occurred.