Implement authentication support for wxWebRequest under Mac
Add wxWebAuthChallengeURLSession and use the appropriate delegate callback to create it.
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "wx/private/webrequest.h"
|
#include "wx/private/webrequest.h"
|
||||||
|
|
||||||
|
DECLARE_WXCOCOA_OBJC_CLASS(NSURLCredential);
|
||||||
DECLARE_WXCOCOA_OBJC_CLASS(NSURLSession);
|
DECLARE_WXCOCOA_OBJC_CLASS(NSURLSession);
|
||||||
DECLARE_WXCOCOA_OBJC_CLASS(NSURLSessionTask);
|
DECLARE_WXCOCOA_OBJC_CLASS(NSURLSessionTask);
|
||||||
DECLARE_WXCOCOA_OBJC_CLASS(wxWebSessionDelegate);
|
DECLARE_WXCOCOA_OBJC_CLASS(wxWebSessionDelegate);
|
||||||
@@ -22,6 +23,29 @@ class wxWebSessionURLSession;
|
|||||||
class wxWebRequestURLSession;
|
class wxWebRequestURLSession;
|
||||||
class wxWebResponseURLSession;
|
class wxWebResponseURLSession;
|
||||||
|
|
||||||
|
class wxWebAuthChallengeURLSession : public wxWebAuthChallengeImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
wxWebAuthChallengeURLSession(wxWebAuthChallenge::Source source,
|
||||||
|
wxWebRequestURLSession& request)
|
||||||
|
: wxWebAuthChallengeImpl(source),
|
||||||
|
m_request(request)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~wxWebAuthChallengeURLSession();
|
||||||
|
|
||||||
|
void SetCredentials(const wxWebCredentials& cred) wxOVERRIDE;
|
||||||
|
|
||||||
|
WX_NSURLCredential GetURLCredential() const { return m_cred; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxWebRequestURLSession& m_request;
|
||||||
|
WX_NSURLCredential m_cred = NULL;
|
||||||
|
|
||||||
|
wxDECLARE_NO_COPY_CLASS(wxWebAuthChallengeURLSession);
|
||||||
|
};
|
||||||
|
|
||||||
class wxWebResponseURLSession : public wxWebResponseImpl
|
class wxWebResponseURLSession : public wxWebResponseImpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -67,7 +91,8 @@ public:
|
|||||||
wxWebResponseImplPtr GetResponse() const wxOVERRIDE
|
wxWebResponseImplPtr GetResponse() const wxOVERRIDE
|
||||||
{ return m_response; }
|
{ return m_response; }
|
||||||
|
|
||||||
wxWebAuthChallengeImplPtr GetAuthChallenge() const wxOVERRIDE;
|
wxWebAuthChallengeImplPtr GetAuthChallenge() const wxOVERRIDE
|
||||||
|
{ return m_authChallenge; }
|
||||||
|
|
||||||
wxFileOffset GetBytesSent() const wxOVERRIDE;
|
wxFileOffset GetBytesSent() const wxOVERRIDE;
|
||||||
|
|
||||||
@@ -79,14 +104,22 @@ public:
|
|||||||
|
|
||||||
void HandleCompletion();
|
void HandleCompletion();
|
||||||
|
|
||||||
|
void HandleChallenge(wxWebAuthChallengeURLSession* challenge);
|
||||||
|
|
||||||
|
void OnSetCredentials(const wxWebCredentials& cred);
|
||||||
|
|
||||||
wxWebResponseURLSession* GetResponseImplPtr() const
|
wxWebResponseURLSession* GetResponseImplPtr() const
|
||||||
{ return m_response.get(); }
|
{ return m_response.get(); }
|
||||||
|
|
||||||
|
wxWebAuthChallengeURLSession* GetAuthChallengeImplPtr() const
|
||||||
|
{ return m_authChallenge.get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wxWebSessionURLSession& m_sessionImpl;
|
wxWebSessionURLSession& m_sessionImpl;
|
||||||
wxString m_url;
|
wxString m_url;
|
||||||
WX_NSURLSessionTask m_task;
|
WX_NSURLSessionTask m_task;
|
||||||
wxObjectDataPtr<wxWebResponseURLSession> m_response;
|
wxObjectDataPtr<wxWebResponseURLSession> m_response;
|
||||||
|
wxObjectDataPtr<wxWebAuthChallengeURLSession> m_authChallenge;
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(wxWebRequestURLSession);
|
wxDECLARE_NO_COPY_CLASS(wxWebRequestURLSession);
|
||||||
};
|
};
|
||||||
|
@@ -97,6 +97,60 @@
|
|||||||
[m_requests removeObjectForKey:task];
|
[m_requests removeObjectForKey:task];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)URLSession:(NSURLSession *)session
|
||||||
|
task:(NSURLSessionTask *)task
|
||||||
|
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
|
||||||
|
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
|
||||||
|
{
|
||||||
|
wxUnusedVar(session);
|
||||||
|
|
||||||
|
wxWebRequestURLSession* request = [self requestForTask:task];
|
||||||
|
wxCHECK_RET( request, "received authentication challenge for an unknown task" );
|
||||||
|
|
||||||
|
NSURLProtectionSpace* const space = [challenge protectionSpace];
|
||||||
|
|
||||||
|
wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: didReceiveChallenge for %s",
|
||||||
|
request,
|
||||||
|
wxCFStringRefFromGet([space description]).AsString());
|
||||||
|
|
||||||
|
// We need to distinguish between session-wide and task-specific
|
||||||
|
// authentication challenges, we're only really interested in the latter
|
||||||
|
// ones here (but apparently there is no way to get just them, even though
|
||||||
|
// the documentation seems to imply that session-wide challenges shouldn't
|
||||||
|
// be sent to this task-specific delegate -- but they're, at least under
|
||||||
|
// 10.14).
|
||||||
|
const auto authMethod = space.authenticationMethod;
|
||||||
|
if ( authMethod == NSURLAuthenticationMethodHTTPBasic ||
|
||||||
|
authMethod == NSURLAuthenticationMethodHTTPDigest )
|
||||||
|
{
|
||||||
|
if ( auto* const authChallenge = request->GetAuthChallengeImplPtr() )
|
||||||
|
{
|
||||||
|
// We're going to get called until we don't provide the correct
|
||||||
|
// credentials, so don't use them again (and again, and again...)
|
||||||
|
// if we had already used them unsuccessfully.
|
||||||
|
if ( !challenge.previousFailureCount )
|
||||||
|
{
|
||||||
|
wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: using credentials", request);
|
||||||
|
|
||||||
|
completionHandler(NSURLSessionAuthChallengeUseCredential,
|
||||||
|
authChallenge->GetURLCredential());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: not using failing credentials again", request);
|
||||||
|
}
|
||||||
|
|
||||||
|
request->HandleChallenge(new wxWebAuthChallengeURLSession(
|
||||||
|
[space isProxy] ? wxWebAuthChallenge::Source_Proxy
|
||||||
|
: wxWebAuthChallenge::Source_Server,
|
||||||
|
*request
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -170,14 +224,22 @@ void wxWebRequestURLSession::Cancel()
|
|||||||
|
|
||||||
void wxWebRequestURLSession::HandleCompletion()
|
void wxWebRequestURLSession::HandleCompletion()
|
||||||
{
|
{
|
||||||
if ( CheckServerStatus() )
|
switch ( m_response->GetStatus() )
|
||||||
SetState(wxWebRequest::State_Completed);
|
{
|
||||||
|
case 401:
|
||||||
|
case 407:
|
||||||
|
SetState(wxWebRequest::State_Unauthorized, m_response->GetStatusText());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ( CheckServerStatus() )
|
||||||
|
SetState(wxWebRequest::State_Completed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wxWebAuthChallengeImplPtr wxWebRequestURLSession::GetAuthChallenge() const
|
void wxWebRequestURLSession::HandleChallenge(wxWebAuthChallengeURLSession* challenge)
|
||||||
{
|
{
|
||||||
wxFAIL_MSG("not implemented");
|
m_authChallenge.reset(challenge);
|
||||||
return wxWebAuthChallengeImplPtr();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFileOffset wxWebRequestURLSession::GetBytesSent() const
|
wxFileOffset wxWebRequestURLSession::GetBytesSent() const
|
||||||
@@ -200,6 +262,33 @@ wxFileOffset wxWebRequestURLSession::GetBytesExpectedToReceive() const
|
|||||||
return m_task.countOfBytesExpectedToReceive;
|
return m_task.countOfBytesExpectedToReceive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// wxWebAuthChallengeURLSession
|
||||||
|
//
|
||||||
|
|
||||||
|
wxWebAuthChallengeURLSession::~wxWebAuthChallengeURLSession()
|
||||||
|
{
|
||||||
|
[m_cred release];
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxWebAuthChallengeURLSession::SetCredentials(const wxWebCredentials& cred)
|
||||||
|
{
|
||||||
|
wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: setting credentials", &m_request);
|
||||||
|
|
||||||
|
[m_cred release];
|
||||||
|
|
||||||
|
m_cred = [NSURLCredential
|
||||||
|
credentialWithUser:wxCFStringRef(cred.GetUser()).AsNSString()
|
||||||
|
password:wxCFStringRef(wxSecretString(cred.GetPassword())).AsNSString()
|
||||||
|
persistence:NSURLCredentialPersistenceNone
|
||||||
|
];
|
||||||
|
|
||||||
|
[m_cred retain];
|
||||||
|
|
||||||
|
m_request.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// wxWebResponseURLSession
|
// wxWebResponseURLSession
|
||||||
//
|
//
|
||||||
|
@@ -42,12 +42,6 @@ public:
|
|||||||
dataSize = 0;
|
dataSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool UsingNSURLSession()
|
|
||||||
{
|
|
||||||
return wxWebSession::GetDefault().GetLibraryVersionInfo().GetName()
|
|
||||||
== "URLSession";
|
|
||||||
}
|
|
||||||
|
|
||||||
// All tests should call this function first and skip the test entirely if
|
// All tests should call this function first and skip the test entirely if
|
||||||
// it returns false, as this indicates that web requests tests are disabled.
|
// it returns false, as this indicates that web requests tests are disabled.
|
||||||
bool InitBaseURL()
|
bool InitBaseURL()
|
||||||
@@ -240,12 +234,6 @@ TEST_CASE_METHOD(RequestFixture,
|
|||||||
if ( !InitBaseURL() )
|
if ( !InitBaseURL() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( UsingNSURLSession() )
|
|
||||||
{
|
|
||||||
WARN("NSURLSession backend doesn't support authentication, skipping.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Create("/basic-auth/wxtest/wxwidgets");
|
Create("/basic-auth/wxtest/wxwidgets");
|
||||||
Run(wxWebRequest::State_Unauthorized, 401);
|
Run(wxWebRequest::State_Unauthorized, 401);
|
||||||
REQUIRE( request.GetAuthChallenge().IsOk() );
|
REQUIRE( request.GetAuthChallenge().IsOk() );
|
||||||
@@ -273,12 +261,6 @@ TEST_CASE_METHOD(RequestFixture,
|
|||||||
if ( !InitBaseURL() )
|
if ( !InitBaseURL() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( UsingNSURLSession() )
|
|
||||||
{
|
|
||||||
WARN("NSURLSession backend doesn't support authentication, skipping.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Create("/digest-auth/auth/wxtest/wxwidgets");
|
Create("/digest-auth/auth/wxtest/wxwidgets");
|
||||||
Run(wxWebRequest::State_Unauthorized, 401);
|
Run(wxWebRequest::State_Unauthorized, 401);
|
||||||
REQUIRE( request.GetAuthChallenge().IsOk() );
|
REQUIRE( request.GetAuthChallenge().IsOk() );
|
||||||
|
Reference in New Issue
Block a user