Added Basic auth support to cHTTPRequest.
This commit is contained in:
parent
1012fd82fd
commit
db3d83b38d
@ -26,6 +26,18 @@ void cHTTPConnection::SendStatusAndReason(int a_StatusCode, const AString & a_Re
|
|||||||
{
|
{
|
||||||
AppendPrintf(m_OutgoingData, "%d %s\r\n\r\n", a_StatusCode, a_Response.c_str());
|
AppendPrintf(m_OutgoingData, "%d %s\r\n\r\n", a_StatusCode, a_Response.c_str());
|
||||||
m_HTTPServer.NotifyConnectionWrite(*this);
|
m_HTTPServer.NotifyConnectionWrite(*this);
|
||||||
|
m_State = wcsRecvHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cHTTPConnection::SendNeedAuth(const AString & a_Realm)
|
||||||
|
{
|
||||||
|
AppendPrintf(m_OutgoingData, "HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"%s\"\r\n\r\n", a_Realm.c_str());
|
||||||
|
m_HTTPServer.NotifyConnectionWrite(*this);
|
||||||
|
m_State = wcsRecvHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,6 +85,12 @@ void cHTTPConnection::AwaitNextRequest(void)
|
|||||||
{
|
{
|
||||||
switch (m_State)
|
switch (m_State)
|
||||||
{
|
{
|
||||||
|
case wcsRecvHeaders:
|
||||||
|
{
|
||||||
|
// Nothing has been received yet, or a special response was given (SendStatusAndReason() or SendNeedAuth() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case wcsRecvIdle:
|
case wcsRecvIdle:
|
||||||
{
|
{
|
||||||
// The client is waiting for a response, send an "Internal server error":
|
// The client is waiting for a response, send an "Internal server error":
|
||||||
|
@ -43,6 +43,9 @@ public:
|
|||||||
/// Sends HTTP status code together with a_Reason (used for HTTP errors)
|
/// Sends HTTP status code together with a_Reason (used for HTTP errors)
|
||||||
void SendStatusAndReason(int a_StatusCode, const AString & a_Reason);
|
void SendStatusAndReason(int a_StatusCode, const AString & a_Reason);
|
||||||
|
|
||||||
|
/// Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified realm
|
||||||
|
void SendNeedAuth(const AString & a_Realm);
|
||||||
|
|
||||||
/// Sends the headers contained in a_Response
|
/// Sends the headers contained in a_Response
|
||||||
void Send(const cHTTPResponse & a_Response);
|
void Send(const cHTTPResponse & a_Response);
|
||||||
|
|
||||||
|
@ -71,7 +71,8 @@ cHTTPRequest::cHTTPRequest(void) :
|
|||||||
super(mkRequest),
|
super(mkRequest),
|
||||||
m_EnvelopeParser(*this),
|
m_EnvelopeParser(*this),
|
||||||
m_IsValid(true),
|
m_IsValid(true),
|
||||||
m_UserData(NULL)
|
m_UserData(NULL),
|
||||||
|
m_HasAuth(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,6 +205,20 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
|
|||||||
|
|
||||||
void cHTTPRequest::OnHeaderLine(const AString & a_Key, const AString & a_Value)
|
void cHTTPRequest::OnHeaderLine(const AString & a_Key, const AString & a_Value)
|
||||||
{
|
{
|
||||||
|
if (
|
||||||
|
(NoCaseCompare(a_Key, "Authorization") == 0) &&
|
||||||
|
(strncmp(a_Value.c_str(), "Basic ", 6) == 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
AString UserPass = Base64Decode(a_Value.substr(6));
|
||||||
|
size_t idxCol = UserPass.find(':');
|
||||||
|
if (idxCol != AString::npos)
|
||||||
|
{
|
||||||
|
m_AuthUsername = UserPass.substr(0, idxCol);
|
||||||
|
m_AuthPassword = UserPass.substr(idxCol + 1);
|
||||||
|
m_HasAuth = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
AddHeader(a_Key, a_Value);
|
AddHeader(a_Key, a_Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,15 @@ public:
|
|||||||
/// Returns true if more data is expected for the request headers
|
/// Returns true if more data is expected for the request headers
|
||||||
bool IsInHeaders(void) const { return m_EnvelopeParser.IsInHeaders(); }
|
bool IsInHeaders(void) const { return m_EnvelopeParser.IsInHeaders(); }
|
||||||
|
|
||||||
|
/// Returns true if the request did present auth data that was understood by the parser
|
||||||
|
bool HasAuth(void) const { return m_HasAuth; }
|
||||||
|
|
||||||
|
/// Returns the username that the request presented. Only valid if HasAuth() is true
|
||||||
|
const AString & GetAuthUsername(void) const { return m_AuthUsername; }
|
||||||
|
|
||||||
|
/// Returns the password that the request presented. Only valid if HasAuth() is true
|
||||||
|
const AString & GetAuthPassword(void) const { return m_AuthPassword; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Parser for the envelope data
|
/// Parser for the envelope data
|
||||||
cEnvelopeParser m_EnvelopeParser;
|
cEnvelopeParser m_EnvelopeParser;
|
||||||
@ -110,6 +119,15 @@ protected:
|
|||||||
/// Data that the HTTPServer callbacks are allowed to store.
|
/// Data that the HTTPServer callbacks are allowed to store.
|
||||||
void * m_UserData;
|
void * m_UserData;
|
||||||
|
|
||||||
|
/// Set to true if the request contains auth data that was understood by the parser
|
||||||
|
bool m_HasAuth;
|
||||||
|
|
||||||
|
/// The username used for auth
|
||||||
|
AString m_AuthUsername;
|
||||||
|
|
||||||
|
/// The password used for auth
|
||||||
|
AString m_AuthPassword;
|
||||||
|
|
||||||
|
|
||||||
/** Parses the incoming data for the first line (RequestLine)
|
/** Parses the incoming data for the first line (RequestLine)
|
||||||
Returns the number of bytes consumed, or -1 for an error
|
Returns the number of bytes consumed, or -1 for an error
|
||||||
|
@ -73,6 +73,16 @@ class cDebugCallbacks :
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test the auth failure and success:
|
||||||
|
if (a_Request.GetURL() == "/auth")
|
||||||
|
{
|
||||||
|
if (!a_Request.HasAuth() || (a_Request.GetAuthUsername() != "a") || (a_Request.GetAuthPassword() != "b"))
|
||||||
|
{
|
||||||
|
a_Connection.SendNeedAuth("MCServer WebAdmin");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cHTTPResponse Resp;
|
cHTTPResponse Resp;
|
||||||
Resp.SetContentType("text/plain");
|
Resp.SetContentType("text/plain");
|
||||||
a_Connection.Send(Resp);
|
a_Connection.Send(Resp);
|
||||||
|
@ -745,3 +745,71 @@ AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Converts one Hex character in a Base64 encoding into the data value
|
||||||
|
static inline int UnBase64(char c)
|
||||||
|
{
|
||||||
|
if (c >='A' && c <= 'Z')
|
||||||
|
{
|
||||||
|
return c - 'A';
|
||||||
|
}
|
||||||
|
if (c >='a' && c <= 'z')
|
||||||
|
{
|
||||||
|
return c - 'a' + 26;
|
||||||
|
}
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
return c - '0' + 52;
|
||||||
|
}
|
||||||
|
if (c == '+')
|
||||||
|
{
|
||||||
|
return 62;
|
||||||
|
}
|
||||||
|
if (c == '/')
|
||||||
|
{
|
||||||
|
return 63;
|
||||||
|
}
|
||||||
|
if (c == '=')
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AString Base64Decode(const AString & a_Base64String)
|
||||||
|
{
|
||||||
|
AString res;
|
||||||
|
size_t i, len = a_Base64String.size();
|
||||||
|
int o, c;
|
||||||
|
res.resize((len * 4) / 3 + 5, 0); // Approximate the upper bound on the result length
|
||||||
|
for (o = 0, i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
c = UnBase64(a_Base64String[i]);
|
||||||
|
if (c >= 0)
|
||||||
|
{
|
||||||
|
switch (o & 7)
|
||||||
|
{
|
||||||
|
case 0: res[o >> 3] |= (c << 2); break;
|
||||||
|
case 6: res[o >> 3] |= (c >> 4); res[(o >> 3) + 1] |= (c << 4); break;
|
||||||
|
case 4: res[o >> 3] |= (c >> 2); res[(o >> 3) + 1] |= (c << 6); break;
|
||||||
|
case 2: res[o >> 3] |= c; break;
|
||||||
|
}
|
||||||
|
o += 6;
|
||||||
|
}
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
// Error while decoding, invalid input. Return as much as we've decoded:
|
||||||
|
res.resize(o >> 3);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.resize(o >> 3);
|
||||||
|
return res;}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,6 +81,9 @@ extern AString URLDecode(const AString & a_String); // Cannot export to Lua aut
|
|||||||
/// Replaces all occurrences of char a_From inside a_String with char a_To.
|
/// Replaces all occurrences of char a_From inside a_String with char a_To.
|
||||||
extern AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_To); // Needn't export to Lua, since Lua doesn't have chars anyway
|
extern AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_To); // Needn't export to Lua, since Lua doesn't have chars anyway
|
||||||
|
|
||||||
|
/// Decodes a Base64-encoded string into the raw data
|
||||||
|
extern AString Base64Decode(const AString & a_Base64String);
|
||||||
|
|
||||||
// If you have any other string helper functions, declare them here
|
// If you have any other string helper functions, declare them here
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user