We are excited to announce that the IIS.NET Forums are moving to the new Microsoft Q&A experience. Learn more >

Problems with LsaLogonUser function, IHttpUser, SetUser and integrated mode (win2008 server)RSS

2 replies

Last post Aug 26, 2010 01:47 PM by mvc_newbie

  • Problems with LsaLogonUser function, IHttpUser, SetUser and integrated mode (win2008 server)

    Feb 02, 2010 02:45 AM|DoPoljak|LINK

    Hi!

     I have problems with getting impersonating token from LsaLogonFuntion. I need token so i can set custom atentification provider, using deferent type of login over internet to IIS, and then use windows autentification (kerberos delegated and constained).

     Problem is next, my module fails running in integrated mode, where in classic application pool mode works fine! (i tested on Windows Server 2008 32bit and Windows Server 2008 R2 64bit).

     

    Here are my references.

    http://msdn.microsoft.com/en-us/library/ms689307.aspx i used this example and in

    virtual HANDLE GetImpersonationToken(VOID) method

    i called LsaLogonUser funtion from this example http://msdn.microsoft.com/en-us/magazine/cc188757.aspx to get impersonating token.

     

    Resultats are:

    In Classic application pool on both server everything is working great, i get full impersonalization, using LsaLogonUser and LogonUser from link above.

    In Integrated application pool on both server (on Windows R2 in 32bit app pool mode) it fails using LsaLogonUser funtion , server breaks down after 3,4 requests, but if i use LogonUser to get token, than it works fine, it's something with LsaLogonUser function under integrated mode. (i cant use LogonUser becouse i dont have password).

    (p.s. I'm using global module notification(besides requst level notitfication - on autentificate) OnGlobalApplicationStart, and what i see that in Integrated mode using LsaLogonUser function, OnGlobalApplicationStart event is fired on EVERY request, but only using LsaLogonUser, in Integrated mode)

     AppPool is runing under LocalSystem, and users are not disabled for delegation.

     

    Managed module:

    I tried creating managed module using C#, here is my code, and it works great (of course only in Integrated mode) but i wanna to have only one native module to do my work in both Application pools.

    WindowsIdentity id = new WindowsIdentity("testuser@test.local");
    WindowsPrincipal wp = new WindowsPrincipal(id);
    HttpContext.Current.User = wp; 
     
    Tnx!

     

    Here is my full code example:

     

    #pragma warning( disable : 4290 )

    #pragma warning( disable : 4530 )

    #define _WINSOCKAPI_

    #include <windows.h>

    #include <io.h>

    #include <sal.h>

    #include <httpserv.h>

    #include <string>

    #include <ntsecapi.h>

    #include <stdio.h>

    #pragma comment(lib, "secur32.lib")

    using namespace std;

     

    HANDLE GetLogonUser(LPCWSTR username, LPCWSTR domain, LPCWSTR password)

    {

    HANDLE hToken;

    if (LogonUser( username, domain, password, LOGON32_LOGON_NETWORK, 0, &hToken))

    {

    return hToken;

    }

    return NULL;

    }

    // some simple error handling functions

    void _err(const wchar_t* fcn, DWORD err = GetLastError())

    {

    wchar_t msg[256];if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, msg, sizeof msg / sizeof *msg, 0))

    {

    wsprintf(msg, L
    "hr = 0x%08X", err);

    }

    wprintf(L
    "%s failed: %s\n", fcn, msg);

    exit(1);

    }

    void _nterr(const wchar_t* fcn, NTSTATUS s)

    {

    _err(fcn, LsaNtStatusToWinError(s));

    }

    void _checknterr(const wchar_t* fcn, NTSTATUS s)

    {

    if (s) {

    _nterr(fcn, s);

    }

    else {wprintf(L"%s succeeded.\n", fcn);

    }

    }

    // helper for initializing Kernel type ANSI strings

    // from string literals

    void _si(LSA_STRING* a, const char* b)

    {

    a->Length = (USHORT)(strlen(b) *
    sizeof(*b));

    a->MaximumLength = (USHORT)(a->Length + sizeof(*b));

    a->Buffer = const_cast<char*>(b);

    }

    HANDLE _s4uLogon(
    const wchar_t* pszUserPrincipalName)

    {

    // connect to the Local Security Authority

    // this will allow us to get a token via S4U2Self

    // (note we aren't in the TCB so we won't be able

    // to use the resulting token to open Kernel objects)

    HANDLE hlsa;

    _checknterr(L
    "LsaConnectUntrusted",

    LsaConnectUntrusted(&hlsa));

     

    // look up the Kerb authentication provider's index

    LSA_STRING pkgName;

    _si(&pkgName, MICROSOFT_KERBEROS_NAME_A);

    ULONG authnPkg;

    _checknterr(L
    "LsaLookupAuthenticationPackage",

    LsaLookupAuthenticationPackage(hlsa,

    &pkgName, &authnPkg));

    const DWORD cchUPN = lstrlen(pszUserPrincipalName); const DWORD cbUPN = cchUPN * sizeof(wchar_t);

    // KERB_S4U_LOGON must be passed as a single

    // contiguous buffer that includes all strings,

    // otherwise LsaLogonUser will complain

    const DWORD cbLogon = sizeof(KERB_S4U_LOGON) + cbUPN;

    KERB_S4U_LOGON* s4uLogon =

    (KERB_S4U_LOGON*)calloc(cbLogon, 1);

    s4uLogon->MessageType = KerbS4ULogon;

    s4uLogon->ClientUpn.Buffer =

    (
    wchar_t*)((char*)s4uLogon + sizeof *s4uLogon);

    CopyMemory(s4uLogon->ClientUpn.Buffer,

    pszUserPrincipalName, cbUPN);

    s4uLogon->ClientUpn.Length = (USHORT)cbUPN;

    s4uLogon->ClientUpn.MaximumLength = (USHORT)cbUPN;

    // this information is copied into the resulting token

    // note that SourceName is an 8 character ASCII buffer

    TOKEN_SOURCE tokenSource;

    AllocateLocallyUniqueId(&tokenSource.SourceIdentifier);

    strcpy(tokenSource.SourceName,
    "test");

    LSA_STRING originName;

    _si(&originName,
    "MSDN S4U Logon Sample");

    // finally, the call to LsaLogonUser,

    // asking for a Network style logon

    // using the S4U2Self Kerb extension

    void* profile = 0;

    DWORD cbProfile = 0;

    LUID logonId;

    HANDLE htok;

    QUOTA_LIMITS quotaLimits;

    NTSTATUS subStatus;

    _checknterr(L
    "LsaLogonUser",

    LsaLogonUser(hlsa,

    &originName,

    Network,

    authnPkg,

    s4uLogon, cbLogon,

    0,

    &tokenSource,

    &profile, &cbProfile,

    &logonId,

    &htok,

    &quotaLimits,

    &subStatus));

    // clean up

    free(s4uLogon);

    LsaFreeReturnBuffer(profile);

    LsaClose(hlsa);

    return htok;

    }

     

    class CHttpUser : public IHttpUser

    {

    public:

     

    CHttpUser()

    {

    m_refs = 1;

    }

     

    virtual PCWSTR GetRemoteUserName(VOID)

    {

    return L"ValidUser";

    }

     

    virtual PCWSTR GetUserName(VOID)

    {

    return L"ValidUser";

    }

     

    virtual PCWSTR GetAuthenticationType(VOID)

    {

    return L"Anonymous";

    }

     

    virtual PCWSTR GetPassword(VOID)

    {

    return L"";

    }

    virtual HANDLE GetImpersonationToken(VOID)
    {
    //return GetLogonUser( L"testuser", L"test.local", L"testpass123");
    return _s4uLogon( Ltestuser@test.local" );

    }

     

    virtual HANDLE GetPrimaryToken(VOID)
    {
    return NULL;
    }

     

    virtual VOID ReferenceUser(VOID)
    {
    InterlockedIncrement(&m_refs);
    }
    virtual VOID DereferenceUser(VOID)

    {

    if (0 == InterlockedDecrement(&m_refs))

    {

    delete this;

    }

    }

     

    virtual BOOL SupportsIsInRole(VOID)

    {

    return FALSE;

    }

     

    virtual HRESULT IsInRole(IN PCWSTR pszRoleName,OUT BOOL* pfInRole)

    {

    return E_NOTIMPL;

    }

     

    virtual PVOID GetUserVariable(IN PCSTR pszVariableName)

    {

    return NULL;

    }

    private:

     

    virtual ~CHttpUser()

    {

    }

     

    LONG m_refs;

    };

     

    class CAuthenticateModule : public CHttpModule

    {

    public:

     

    CAuthenticateModule()

    {

    }

     

    virtual ~CAuthenticateModule()

    {

    }

     

    virtual REQUEST_NOTIFICATION_STATUS OnAuthenticateRequest(IN IHttpContext* pHttpContext,IN OUT IAuthenticationProvider* pProvider)

    {

     

    IHttpUser* currentUser = pHttpContext->GetUser();

     

    if (NULL == currentUser)

    {

    CHttpUser* httpUser =
    new CHttpUser;

    pProvider->SetUser(httpUser);

    }

     

    return RQ_NOTIFICATION_CONTINUE;

    }

     

    virtual REQUEST_NOTIFICATION_STATUS OnPostAuthenticateRequest(IN IHttpContext* pHttpContext,IN OUT IHttpEventProvider* pProvider)

    {

    UNREFERENCED_PARAMETER(pHttpContext);

    UNREFERENCED_PARAMETER(pProvider);

    return RQ_NOTIFICATION_CONTINUE;

    }

     

    virtual REQUEST_NOTIFICATION_STATUS OnSendResponse(IN IHttpContext* pHttpContext,IN OUT ISendResponseProvider* pProvider)

    {

    UNREFERENCED_PARAMETER(pProvider);

    return RQ_NOTIFICATION_CONTINUE;

    }

    };

     

    class CAuthenticateFactory : public IHttpModuleFactory

    {

    public:

     

    static HRESULT RegisterCHttpModule(DWORD dwServerVersion,IHttpModuleRegistrationInfo* pModuleInfo,IHttpServer* pGlobalInfo)

    {

    CAuthenticateFactory* moduleFactory =
    new CAuthenticateFactory;

     

    if (NULL == moduleFactory)

    {

    return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);

    }

     

    HRESULT hr = pModuleInfo->SetRequestNotifications(moduleFactory,RQ_AUTHENTICATE_REQUEST | RQ_SEND_RESPONSE,0);

     

    if (FAILED(hr))

    {

    return hr;

    }

     

    return pModuleInfo->SetPriorityForRequestNotification(RQ_AUTHENTICATE_REQUEST, PRIORITY_ALIAS_FIRST);

    }

     

    virtual HRESULT GetHttpModule(OUT CHttpModule** ppModule, IN IModuleAllocator* pAllocator)

    {

     

    UNREFERENCED_PARAMETER(pAllocator);

    (*ppModule) =
    new CAuthenticateModule;

     

    if (NULL == (*ppModule))

    {

    return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);

    }

     

    return S_OK;

    }

     

    virtual void Terminate()

    {

    delete this;

    }

    protected:

     

    CAuthenticateFactory()

    {

    }

    virtual ~CAuthenticateFactory()

    {

    }

    };

     

    HRESULT
    __stdcall RegisterModule(DWORD dwServerVersion, IHttpModuleRegistrationInfo* pModuleInfo,IHttpServer* pGlobalInfo)

    {

    return CAuthenticateFactory::RegisterCHttpModule(dwServerVersion, pModuleInfo, pGlobalInfo);

    }

     

     

     

    c++ native impersonation LsaLogonUser IHttpUser

  • Re: Problems with LsaLogonUser function, IHttpUser, SetUser and integrated mode (win2008 server)

    Feb 11, 2010 04:21 AM|DoPoljak|LINK

    I fixed problem with Integrated and Classic mode and Impresonalization token. The problem was with my GetImpersonationToken method, which returns token. I need to call _s4uLogon method in HttpUser constructor so i can get token before and return it in GetImperosnatinonToken ( but strange that this was only problem to integrated mode).

     But now i'm stuck with creating Domain User on which i can run my IIS 7.5 Application Pool Identity, and which have inaf privileges to run LsaLogonUser function and return full impersonating token, not identification one.

    I created user giving him next privileges and groups:

    In Active Directory Users and Computers -> My Domain -> Builtin      
          - Pre-Windows 2000 Compatible Access
          - Windows Autorization Access Group

    On local domain computer i add that domain user and give next privileges:
          In Local Security Polici:
               - Act as a part o operating system
          In Computer Management -> System Tools -> Local Users and Groups
               - IIS_IUSRS ( that group is in Impersonate a client after authentication group)

    But this is still not inaf privileges to get Impersonation level token using LsaLogonUser function

    I get next error:

    ---------


     

    Server Error in '/' Application.

    The handle is invalid. (Exception from HRESULT: 0x80070006 (E_HANDLE))

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.Runtime.InteropServices.COMException: The handle is invalid. (Exception from HRESULT: 0x80070006 (E_HANDLE))

    Source Error:

    An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

    Stack Trace:

    [COMException (0x80070006): The handle is invalid. (Exception from HRESULT: 0x80070006 (E_HANDLE))]
    
    [FileLoadException: Could not load file or assembly 'SMDiagnostics, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The handle is invalid. (Exception from HRESULT: 0x80070006 (E_HANDLE))]
       System.ServiceModel.Activation.HttpModule.ProcessRequest(Object sender, EventArgs e) +0
       System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +171
    


    Version Information: Microsoft .NET Framework Version:2.0.50727.4927; ASP.NET Version:2.0.50727.4927

     

    On same account i can call LogonUser function that return impersonation level token but i need LsaLogonUser becouse i dont have password, and LsaLogonUser function runs great on LocalSystem account, which is not option in my case.

    Please help me out, i'm realy stuck.

     Tnx!

    impersonation LsaLogonUser Token LogonUser

  • Re: Problems with LsaLogonUser function, IHttpUser, SetUser and integrated mode (win2008 server)

    Aug 26, 2010 01:47 PM|MVC_Newbie|LINK

    Hi DoPoljak, did you find a solution to this problem. I'm haveng a similar problem right now :-(