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());
|
||||
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)
|
||||
{
|
||||
case wcsRecvHeaders:
|
||||
{
|
||||
// Nothing has been received yet, or a special response was given (SendStatusAndReason() or SendNeedAuth() )
|
||||
break;
|
||||
}
|
||||
|
||||
case wcsRecvIdle:
|
||||
{
|
||||
// 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)
|
||||
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
|
||||
void Send(const cHTTPResponse & a_Response);
|
||||
|
||||
|
@ -71,7 +71,8 @@ cHTTPRequest::cHTTPRequest(void) :
|
||||
super(mkRequest),
|
||||
m_EnvelopeParser(*this),
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,15 @@ public:
|
||||
/// Returns true if more data is expected for the request headers
|
||||
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:
|
||||
/// Parser for the envelope data
|
||||
cEnvelopeParser m_EnvelopeParser;
|
||||
@ -110,6 +119,15 @@ protected:
|
||||
/// Data that the HTTPServer callbacks are allowed to store.
|
||||
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)
|
||||
Returns the number of bytes consumed, or -1 for an error
|
||||
|
@ -73,6 +73,16 @@ class cDebugCallbacks :
|
||||
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;
|
||||
Resp.SetContentType("text/plain");
|
||||
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.
|
||||
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
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user