Implement WinHTTP authentication
This commit is contained in:
parent
1a34f3dab9
commit
4fd6091513
@ -52,6 +52,23 @@ private:
|
||||
wxDECLARE_NO_COPY_CLASS(wxWebResponseWinHTTP);
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_NET wxWebAuthChallengeWinHTTP : public wxWebAuthChallenge
|
||||
{
|
||||
public:
|
||||
explicit wxWebAuthChallengeWinHTTP(Source source, wxWebRequestWinHTTP& request);
|
||||
|
||||
bool Init();
|
||||
|
||||
void SetCredentials(const wxString& user, const wxString& password) wxOVERRIDE;
|
||||
|
||||
private:
|
||||
wxWebRequestWinHTTP& m_request;
|
||||
DWORD m_target;
|
||||
DWORD m_selectedScheme;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxWebAuthChallengeWinHTTP);
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_NET wxWebRequestWinHTTP : public wxWebRequest
|
||||
{
|
||||
public:
|
||||
@ -65,6 +82,8 @@ public:
|
||||
|
||||
wxWebResponse* GetResponse() wxOVERRIDE;
|
||||
|
||||
wxWebAuthChallenge* GetAuthChallenge() const wxOVERRIDE { return m_authChallenge.get(); }
|
||||
|
||||
void HandleCallback(DWORD dwInternetStatus, LPVOID lpvStatusInformation,
|
||||
DWORD dwStatusInformationLength);
|
||||
|
||||
@ -76,15 +95,20 @@ private:
|
||||
HINTERNET m_connect;
|
||||
HINTERNET m_request;
|
||||
wxScopedPtr<wxWebResponseWinHTTP> m_response;
|
||||
wxScopedPtr<wxWebAuthChallengeWinHTTP> m_authChallenge;
|
||||
wxMemoryBuffer m_dataWriteBuffer;
|
||||
wxFileOffset m_dataWritten;
|
||||
|
||||
void SendRequest();
|
||||
|
||||
void WriteData();
|
||||
|
||||
void CreateResponse();
|
||||
|
||||
void SetFailedWithLastError();
|
||||
|
||||
friend class wxWebAuthChallengeWinHTTP;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxWebRequestWinHTTP);
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
class wxWebResponse;
|
||||
class wxWebSession;
|
||||
class wxWebAuthChallenge;
|
||||
|
||||
WX_DECLARE_STRING_HASH_MAP(wxString, wxWebRequestHeaderMap);
|
||||
|
||||
@ -33,19 +34,12 @@ public:
|
||||
{
|
||||
State_Idle,
|
||||
State_Unauthorized,
|
||||
State_UnauthorizedProxy,
|
||||
State_Active,
|
||||
State_Completed,
|
||||
State_Failed,
|
||||
State_Cancelled
|
||||
};
|
||||
|
||||
enum CredentialTarget
|
||||
{
|
||||
CredentialTarget_Server,
|
||||
CredentialTarget_Proxy
|
||||
};
|
||||
|
||||
virtual ~wxWebRequest() { }
|
||||
|
||||
virtual void SetHeader(const wxString& name, const wxString& value)
|
||||
@ -57,9 +51,6 @@ public:
|
||||
|
||||
void SetData(wxSharedPtr<wxInputStream> dataStream, const wxString& contentType, wxFileOffset dataSize = wxInvalidOffset);
|
||||
|
||||
void SetCredentials(const wxString& user, const wxString& password,
|
||||
CredentialTarget target);
|
||||
|
||||
void SetIgnoreServerErrorStatus(bool ignore) { m_ignoreServerErrorStatus = ignore; }
|
||||
|
||||
virtual void Start() = 0;
|
||||
@ -68,6 +59,8 @@ public:
|
||||
|
||||
virtual wxWebResponse* GetResponse() = 0;
|
||||
|
||||
virtual wxWebAuthChallenge* GetAuthChallenge() const = 0;
|
||||
|
||||
int GetId() const { return m_id; }
|
||||
|
||||
State GetState() const { return m_state; }
|
||||
@ -125,6 +118,30 @@ private:
|
||||
wxDECLARE_NO_COPY_CLASS(wxWebResponse);
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_NET wxWebAuthChallenge
|
||||
{
|
||||
public:
|
||||
enum Source
|
||||
{
|
||||
Source_Server,
|
||||
Source_Proxy
|
||||
};
|
||||
|
||||
virtual ~wxWebAuthChallenge() { }
|
||||
|
||||
Source GetSource() const { return m_source; }
|
||||
|
||||
virtual void SetCredentials(const wxString& user, const wxString& password) = 0;
|
||||
|
||||
protected:
|
||||
wxWebAuthChallenge(Source source): m_source(source) { }
|
||||
|
||||
private:
|
||||
Source m_source;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxWebAuthChallenge);
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_NET wxWebSessionFactory
|
||||
{
|
||||
public:
|
||||
|
@ -93,15 +93,10 @@ void wxWebRequest::SetData(wxSharedPtr<wxInputStream> dataStream, const wxString
|
||||
SetHeader("Content-Type", contentType);
|
||||
}
|
||||
|
||||
void wxWebRequest::SetCredentials(const wxString & user, const wxString & password, CredentialTarget target)
|
||||
{
|
||||
wxFAIL_MSG("not implemented");
|
||||
}
|
||||
|
||||
void wxWebRequest::SetState(State state, const wxString & failMsg)
|
||||
{
|
||||
// Add a reference while the request is active
|
||||
if (state == State_Active && m_state != State_Active)
|
||||
if (state == State_Active && m_state != State_Active && m_state != State_Unauthorized)
|
||||
IncRef();
|
||||
|
||||
// Trigger the event in the main thread
|
||||
|
@ -219,10 +219,20 @@ void wxWebRequestWinHTTP::CreateResponse()
|
||||
if (::WinHttpReceiveResponse(m_request, NULL))
|
||||
{
|
||||
m_response.reset(new wxWebResponseWinHTTP(*this));
|
||||
if (CheckServerStatus())
|
||||
int status = m_response->GetStatus();
|
||||
if ( status == 401 || status == 407)
|
||||
{
|
||||
m_authChallenge.reset(new wxWebAuthChallengeWinHTTP(
|
||||
(status == 407) ? wxWebAuthChallenge::Source_Proxy : wxWebAuthChallenge::Source_Server, *this));
|
||||
if ( m_authChallenge->Init() )
|
||||
SetState(State_Unauthorized, m_response->GetStatusText());
|
||||
else
|
||||
SetFailedWithLastError();
|
||||
}
|
||||
else if ( CheckServerStatus() )
|
||||
{
|
||||
// Start reading the response
|
||||
if (!m_response->ReadData())
|
||||
if ( !m_response->ReadData() )
|
||||
SetFailedWithLastError();
|
||||
}
|
||||
}
|
||||
@ -297,16 +307,21 @@ void wxWebRequestWinHTTP::Start()
|
||||
return;
|
||||
}
|
||||
|
||||
SendRequest();
|
||||
}
|
||||
|
||||
void wxWebRequestWinHTTP::SendRequest()
|
||||
{
|
||||
// Combine all headers to a string
|
||||
wxString allHeaders;
|
||||
for (wxWebRequestHeaderMap::const_iterator header = m_headers.begin(); header != m_headers.end(); ++header)
|
||||
for ( wxWebRequestHeaderMap::const_iterator header = m_headers.begin(); header != m_headers.end(); ++header )
|
||||
allHeaders.append(wxString::Format("%s: %s\n", header->first, header->second));
|
||||
|
||||
if ( m_dataSize )
|
||||
m_dataWritten = 0;
|
||||
|
||||
// Send request
|
||||
if ( WinHttpSendRequest(m_request,
|
||||
if ( ::WinHttpSendRequest(m_request,
|
||||
allHeaders.wc_str(), allHeaders.length(),
|
||||
NULL, 0, m_dataSize,
|
||||
(DWORD_PTR)this) )
|
||||
@ -408,6 +423,57 @@ void wxWebResponseWinHTTP::ReportDataComplete()
|
||||
m_stream.reset(new wxMemoryInputStream(m_readBuffer.GetData(), m_readBuffer.GetDataLen()));
|
||||
}
|
||||
|
||||
//
|
||||
// wxWebAuthChallengeWinHTTP
|
||||
//
|
||||
wxWebAuthChallengeWinHTTP::wxWebAuthChallengeWinHTTP(Source source, wxWebRequestWinHTTP & request):
|
||||
wxWebAuthChallenge(source),
|
||||
m_request(request),
|
||||
m_target(0),
|
||||
m_selectedScheme(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool wxWebAuthChallengeWinHTTP::Init()
|
||||
{
|
||||
DWORD supportedSchemes;
|
||||
DWORD firstScheme;
|
||||
|
||||
if ( ::WinHttpQueryAuthSchemes(m_request.GetHandle(),
|
||||
&supportedSchemes, &firstScheme, &m_target) )
|
||||
{
|
||||
if ( supportedSchemes & WINHTTP_AUTH_SCHEME_NEGOTIATE )
|
||||
m_selectedScheme = WINHTTP_AUTH_SCHEME_NEGOTIATE;
|
||||
else if ( supportedSchemes & WINHTTP_AUTH_SCHEME_NTLM )
|
||||
m_selectedScheme = WINHTTP_AUTH_SCHEME_NTLM;
|
||||
else if ( supportedSchemes & WINHTTP_AUTH_SCHEME_PASSPORT )
|
||||
m_selectedScheme = WINHTTP_AUTH_SCHEME_PASSPORT;
|
||||
else if ( supportedSchemes & WINHTTP_AUTH_SCHEME_DIGEST )
|
||||
m_selectedScheme = WINHTTP_AUTH_SCHEME_DIGEST;
|
||||
else if ( supportedSchemes & WINHTTP_AUTH_SCHEME_BASIC )
|
||||
m_selectedScheme = WINHTTP_AUTH_SCHEME_BASIC;
|
||||
else
|
||||
m_selectedScheme = 0;
|
||||
|
||||
if ( m_selectedScheme )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxWebAuthChallengeWinHTTP::SetCredentials(const wxString& user,
|
||||
const wxString& password)
|
||||
{
|
||||
if ( ::WinHttpSetCredentials(m_request.GetHandle(), m_target, m_selectedScheme,
|
||||
user.wc_str(), password.wc_str(), NULL) )
|
||||
m_request.SendRequest();
|
||||
else
|
||||
m_request.SetFailedWithLastError();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// wxWebSessionWinHTTP
|
||||
//
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
{
|
||||
switch (evt.GetState())
|
||||
{
|
||||
case wxWebRequest::State_Unauthorized:
|
||||
case wxWebRequest::State_Completed:
|
||||
case wxWebRequest::State_Failed:
|
||||
case wxWebRequest::State_Cancelled:
|
||||
@ -124,6 +125,28 @@ TEST_CASE_METHOD(RequestFixture, "WebRequest", "[net][.]")
|
||||
request->SetMethod("PUT");
|
||||
Run();
|
||||
}
|
||||
|
||||
SECTION("Server auth BASIC")
|
||||
{
|
||||
Create("/digest-auth/auth/wxtest/wxwidgets");
|
||||
Run(wxWebRequest::State_Unauthorized, 401);
|
||||
REQUIRE( request->GetAuthChallenge() != NULL );
|
||||
request->GetAuthChallenge()->SetCredentials("wxtest", "wxwidgets");
|
||||
loop.Run();
|
||||
REQUIRE( request->GetResponse()->GetStatus() == 200 );
|
||||
REQUIRE( request->GetState() == wxWebRequest::State_Completed );
|
||||
}
|
||||
|
||||
SECTION("Server auth DIGEST")
|
||||
{
|
||||
Create("/digest-auth/auth/wxtest/wxwidgets");
|
||||
Run(wxWebRequest::State_Unauthorized, 401);
|
||||
REQUIRE( request->GetAuthChallenge() != NULL );
|
||||
request->GetAuthChallenge()->SetCredentials("wxtest", "wxwidgets");
|
||||
loop.Run();
|
||||
REQUIRE( request->GetResponse()->GetStatus() == 200 );
|
||||
REQUIRE( request->GetState() == wxWebRequest::State_Completed );
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_WEBREQUEST
|
||||
|
Loading…
Reference in New Issue
Block a user