Microsoft KB Archive/320153

From BetaArchive Wiki

Article ID: 320153

Article Last Modified on 12/3/2002



APPLIES TO

  • Microsoft Internet Explorer (Programming)



This article was previously published under Q320153

SYMPTOMS

When you host the Web Browser control and you implement the IAuthenticate interface to programmatically bypass the authentication process, sometimes Internet Explorer may not call the Authenticate function, which causes an authentication dialog to appear.

CAUSE

This bug prevents Internet Explorer from calling Authenticate when MSHTML is not the current Active Document server. You can observe this bug when you initially move to a Hypertext Markup Language (HTML) page or when you move to an HTML page from an Active Document server other than MSHTML, such as a Microsoft Office document Active Document server or a Visual Basic Document (VBD) Active Document server.

RESOLUTION

You can work around the bug if you move to about:blank before you move to the secure page. You can also move to a non-secure page, which redirects you to the secure page.

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.

MORE INFORMATION

Internet Explorer obtains the IAuthenticate interface through the IServiceProvider::QueryService method. When the bug occurs, Internet Explorer does not ask for the IAuthenticate interface. Therefore, the Authenticate method cannot be called.

Steps to Reproduce the Behavior

Note: You must be familiar with Microsoft Foundation Classes (MFC) to understand the following steps.

  1. Create a Web page that is named Mysecurepage.htm.

    The content of the Web page is irrelevant.
  2. Place the Web page in a secure directory that is named Mysecuredirectory, with basic authentication on a Web server (Mysecureserver).
  3. Create a default CHtmlView-based MFC application with multiple-document interface (MDI) or single-document interface (SDI).
  4. Modify the MFC program to provide a custom control site object by overriding the COleControlSite class.

    You can read the following Microsoft KnowledgeBase article to obtain information about override of the MFC default control containment:

    HOWTO: Override the MFC Default Control Containment
    196835

    A sample of how the code may appear follows: Header file:

    #if !defined(MYCONTROLSITEHEADER)
    #define MYCONTROLSITEHEADER
    
    #undef AFX_DATA
    #define AFX_DATA AFX_DATA_IMPORT
    #include <..\src\occimpl.h>
    #undef AFX_DATA
    #define AFX_DATA AFX_DATA_EXPORT
    
    class CCustomControlSite : public COleControlSite
    {
    public:
        CCustomControlSite::CCustomControlSite(COleControlContainer* pCtrlCont) :
            COleControlSite(pCtrlCont)
        {
        }
    };
    
    class CMyOccManager : public COccManager
    {
    public:
        CMyOccManager() {}
    
        virtual COleControlSite* CreateSite(COleControlContainer* pCtrlCont)
        {
            // advanced control container override
            return new CCustomControlSite(pCtrlCont);
        }
    };
    
    #endif
                        

    Implementation files:

    CMyOccManager theManager;
    
    BOOL CMyApp::InitInstance()
    {
        AfxEnableControlContainer(&theManager);
    ...
                        


    BOOL CReproView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
    {
        // create the view window itself
        m_pCreateContext = pContext;
        if (!CView::Create(lpszClassName, lpszWindowName,
                    dwStyle, rect, pParentWnd,  nID, pContext))
        {
            return FALSE;
        }
    
        RECT rectClient;
        GetClientRect(&rectClient);
    
        // create the control window
        // AFX_IDW_PANE_FIRST is a safe but arbitrary ID
        if (!m_wndBrowser.CreateControl(CLSID_WebBrowser, lpszWindowName,
                    WS_VISIBLE | WS_CHILD, rectClient, this, AFX_IDW_PANE_FIRST))
        {
            DestroyWindow();
            return FALSE;
        }
    
        LPUNKNOWN lpUnk = m_wndBrowser.GetControlUnknown();
        HRESULT hr = lpUnk->QueryInterface(IID_IWebBrowser2, (void**) &m_pBrowserApp);
        if (!SUCCEEDED(hr))
        {
            m_pBrowserApp = NULL;
            m_wndBrowser.DestroyWindow();
            DestroyWindow();
            return FALSE;
        }
    
        return TRUE;
    }
                        
  5. Header file:Add code to implement the IServiceProvider interface in the custom COleControlSite class you just implemented.

    A sample of how the header file and the implementation file may appear follows: Header file:

    class CCustomControlSite : public COleControlSite
    {
    public:
        CCustomControlSite::CCustomControlSite(COleControlContainer* pCtrlCont) :
            COleControlSite(pCtrlCont)
        {
        }
    
    protected:
    
        DECLARE_INTERFACE_MAP()
    
        // ... other stuff
    
        /////////////////////////////////////// 
        //// Implement IServiceProvider
        BEGIN_INTERFACE_PART(ServiceProvider, IServiceProvider)
        STDMETHOD(QueryService)(REFGUID,REFIID,void**);
        END_INTERFACE_PART(ServiceProvider)
    };
                        

    Implementation file:

    BEGIN_INTERFACE_MAP(CCustomControlSite, COleControlSite)
        INTERFACE_PART(CCustomControlSite, IID_IServiceProvider, ServiceProvider)
    END_INTERFACE_MAP()
    
    ///////////////////////////////////////////////////////////// 
    // ServiceProvider Methods
    ULONG FAR EXPORT CCustomControlSite::XServiceProvider::AddRef()
    {
        METHOD_PROLOGUE(CCustomControlSite, ServiceProvider)
        return pThis->ExternalAddRef();
    }
    
    ULONG FAR EXPORT CCustomControlSite::XServiceProvider::Release()
    {                            
        METHOD_PROLOGUE(CCustomControlSite, ServiceProvider)
        return pThis->ExternalRelease();
    }
    
    HRESULT FAR EXPORT CCustomControlSite::XServiceProvider::QueryInterface(REFIID riid, 
        void** ppvObj)
    {
        METHOD_PROLOGUE(CCustomControlSite, ServiceProvider)
        HRESULT hr = (HRESULT)pThis->ExternalQueryInterface(&riid, ppvObj);
        return hr;
    }
    STDMETHODIMP CCustomControlSite::XServiceProvider::QueryService(REFGUID guidService,  
        REFIID riid,
        void** ppvObject)
    {
        if (guidService == IID_IAuthenticate &&
            riid == IID_IAuthenticate)
        {
            METHOD_PROLOGUE(CCustomControlSite, ServiceProvider);
            HRESULT hr = (HRESULT)pThis->ExternalQueryInterface(&riid, ppvObject);
            return hr;
        }
        else
        {
            *ppvObject = NULL;
    
        }
        return E_NOINTERFACE;
    }
                        
  6. Header file:Add code to implement the IAuthenicate interface in the custom COleControlSite class.

    A sample of how the header file and the implementation file may appear follows: Header file:

    class CCustomControlSite : public COleControlSite
    {
    public:
        CCustomControlSite::CCustomControlSite(COleControlContainer* pCtrlCont) :
            COleControlSite(pCtrlCont)
        {
        }
    
    protected:
    
        DECLARE_INTERFACE_MAP()
    
        // ... other stuff
    
        /////////////////////////////////////// 
        //// Implement IAuthenticate
        BEGIN_INTERFACE_PART(Authenticate, IAuthenticate)
        STDMETHOD(Authenticate)(HWND*, LPWSTR*, LPWSTR*);
        END_INTERFACE_PART(Authenticate)
    };
                        

    Implementation file:

    BEGIN_INTERFACE_MAP(CCustomControlSite, COleControlSite)
        INTERFACE_PART(CCustomControlSite, IID_IServiceProvider, ServiceProvider)
        INTERFACE_PART(CCustomControlSite, IID_IAuthenticate, Authenticate)
    END_INTERFACE_MAP()
    
    // 
    // IAuthenticate
    // 
    ULONG FAR EXPORT CCustomControlSite::XAuthenticate::AddRef()
    {
        METHOD_PROLOGUE(CCustomControlSite, Authenticate)
        return pThis->ExternalAddRef();
    }
    
    ULONG FAR EXPORT CCustomControlSite::XAuthenticate::Release()
    {                            
        METHOD_PROLOGUE(CCustomControlSite, Authenticate)
        return pThis->ExternalRelease();
    }
    
    HRESULT FAR EXPORT CCustomControlSite::XAuthenticate::QueryInterface(REFIID
        riid, void **ppvObj)
    {
        METHOD_PROLOGUE(CCustomControlSite, Authenticate)
        HRESULT hr = (HRESULT)pThis->ExternalQueryInterface(&riid, ppvObj);
        return hr;
    }
    
    HRESULT FAR EXPORT CCustomControlSite::XAuthenticate::Authenticate(
        /* [out] */ HWND *phwnd,
        /* [out] */ LPWSTR *pszUsername,
        /* [out] */ LPWSTR *pszPassword) 
    {
        USES_CONVERSION;
        METHOD_PROLOGUE(CCustomControlSite, Authenticate)
    
        char* userName = "mydomain\\myuserid";
        char* password = "mysecretpassword";
        *phwnd = NULL;
        long size = (strlen(userName)+1)*sizeof(WCHAR);
        *pszUsername = (LPWSTR)::CoTaskMemAlloc(size);
        memcpy(*pszUsername, T2W(userName), size);
        size = (strlen(password)+1)*sizeof(WCHAR);
        *pszPassword = (LPWSTR)::CoTaskMemAlloc(size);
        memcpy(*pszPassword, T2W(password), size);
        return S_OK;
    }
                        
  7. Header file:Add code to move to the secure page.

    A sample that uses the Navigate method follows:

    void CQ320153View::OnInitialUpdate()
    {
        CHtmlView::OnInitialUpdate();
    
        // Navigate2(_T("about:blank"),NULL,NULL); // call this for workaround
        Navigate2(_T("http://myserver/mysecuredirectory/mysecurepage.htm"),NULL,NULL);
    }
                        
  8. Header file:Build the project and run the program.

    Notice the prompt for the authentication dialog. The prompt disappears if you comment out the code to move to about:blank.


Keywords: kbbug kbpending kbsecurity kburlmon kbwebbrowser KB320153