PIHTTPServer basic auth works

This commit is contained in:
2024-11-24 23:23:08 +03:00
parent c2c9822169
commit 1acaf24df9
8 changed files with 184 additions and 61 deletions

View File

@@ -30,13 +30,23 @@
// clang-format on
struct MicrohttpdServerConnection {
bool ready();
int sendReply(const PIHTTP::MessageMutable & r);
int sendError();
using namespace PIHTTP;
bool done = false;
PIHTTP::Method method = PIHTTP::Method::Unknown;
struct BasicAuthCred {
bool exists = false;
PIString user;
PIString pass;
};
struct MicrohttpdServerConnection {
bool checkBasicAuth();
bool ready();
int sendReply(const MessageMutable & r);
BasicAuthCred getBasicAuthCred();
bool done = false, authorized = false;
Method method = Method::Unknown;
PIString path;
PIByteArray body;
PIMap<PIString, PIString> headers, args, post;
@@ -46,12 +56,31 @@ struct MicrohttpdServerConnection {
};
bool MicrohttpdServerConnection::checkBasicAuth() {
if (headers.contains(Header::Authorization)) {
auto ba_up = getBasicAuthCred();
bool ok = false; // server->callback_auth(ba_up.user, ba_up.pass);
if (server->callback_auth) ok = server->callback_auth(ba_up.user, ba_up.pass);
if (ok) {
authorized = true;
return true;
}
}
// piCout << "miss authorization";
sendReply(MessageMutable::fromCode(Code::Unauthorized)
.addHeader(Header::WWWAuthenticate, "Basic realm=\"%1\", charset=\"UTF-8\""_a.arg(server->realm))
.setBody(PIByteArray::fromAscii("Authorization required")));
// piCout << "answer sent";
return false;
}
bool MicrohttpdServerConnection::ready() {
if (!server) return false;
if (done) return true;
done = true;
PIHTTP::MessageMutable rep;
if (method == PIHTTP::Method::Get) {
MessageMutable rep;
if (method == Method::Get) {
if (path == "/favicon.ico"_a) {
// piCout << "send favicon" << server->favicon.size() << "bytes";
rep.setBody(server->favicon);
@@ -60,13 +89,13 @@ bool MicrohttpdServerConnection::ready() {
}
}
// piCout << "ready" << (int)method << path;
PIHTTP::MessageMutable req;
MessageMutable req;
req.setMethod(method);
req.setPath(path);
req.setBody(body);
req.headers() = headers;
req.arguments() = args;
rep.setCode(PIHTTP::Code::BadRequest);
rep.setCode(Code::BadRequest);
if (server->callback) rep = server->callback(req);
MicrohttpdServer::addFixedHeaders(rep);
sendReply(rep);
@@ -75,7 +104,7 @@ bool MicrohttpdServerConnection::ready() {
}
int MicrohttpdServerConnection::sendReply(const PIHTTP::MessageMutable & r) {
int MicrohttpdServerConnection::sendReply(const MessageMutable & r) {
MHD_Response * response = MHD_create_response_from_buffer(r.body().size(), (void *)r.body().data(), MHD_RESPMEM_MUST_COPY);
if (!response) {
// piCout << "null response" << r.body.size() << (void *)r.body.data();
@@ -91,8 +120,21 @@ int MicrohttpdServerConnection::sendReply(const PIHTTP::MessageMutable & r) {
}
int MicrohttpdServerConnection::sendError() {
return MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_MUST_COPY));
BasicAuthCred MicrohttpdServerConnection::getBasicAuthCred() {
BasicAuthCred ret;
char * p = nullptr;
auto u = MHD_basic_auth_get_username_password(connection, &p);
if (u) {
ret.user = PIString::fromUTF8(u);
ret.exists = true;
MHD_free(u);
}
if (p) {
ret.pass = PIString::fromUTF8(p);
ret.exists = true;
MHD_free(p);
}
return ret;
}
@@ -152,38 +194,38 @@ int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char *
}
int answer_to_connection(void * cls,
MHD_Connection * connection,
const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** con_cls) {
int answer_callback(void * cls,
MHD_Connection * connection,
const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** con_cls) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
PIHTTP::Method m = PIHTTP::Method::Unknown;
Method m = Method::Unknown;
if (0 == strcmp(method, "GET"))
m = PIHTTP::Method::Get;
m = Method::Get;
else if (0 == strcmp(method, "POST"))
m = PIHTTP::Method::Post;
m = Method::Post;
else if (0 == strcmp(method, "HEAD"))
m = PIHTTP::Method::Head;
m = Method::Head;
else if (0 == strcmp(method, "PUT"))
m = PIHTTP::Method::Put;
m = Method::Put;
else if (0 == strcmp(method, "DELETE"))
m = PIHTTP::Method::Delete;
m = Method::Delete;
else if (0 == strcmp(method, "CONNECT"))
m = PIHTTP::Method::Connect;
m = Method::Connect;
else if (0 == strcmp(method, "OPTIONS"))
m = PIHTTP::Method::Options;
m = Method::Options;
else if (0 == strcmp(method, "TRACE"))
m = PIHTTP::Method::Trace;
m = Method::Trace;
else if (0 == strcmp(method, "PATCH"))
m = PIHTTP::Method::Patch;
m = Method::Patch;
if (m == PIHTTP::Method::Unknown) {
if (m == Method::Unknown) {
piCout << "[MicrohttpdServer]"
<< "Warning:"
<< "Unknown method!";
@@ -200,11 +242,14 @@ int answer_to_connection(void * cls,
conn->method = m;
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
return MHD_YES;
}
if (m == PIHTTP::Method::Unknown) {
return conn->sendError();
if (m == Method::Unknown) {
return conn->sendReply(MessageMutable::fromCode(Code::MethodNotAllowed));
}
if (server->isBasicAuthEnabled() && !conn->authorized) {
if (!conn->checkBasicAuth()) return MHD_YES;
}
if (*upload_data_size) {
@@ -216,7 +261,7 @@ int answer_to_connection(void * cls,
*upload_data_size = 0;
} else {
// qDebug() << "answer ok";
if (!conn->ready()) return conn->sendError();
if (!conn->ready()) return conn->sendReply(MessageMutable::fromCode(Code::InternalServerError));
}
return MHD_YES;
}
@@ -231,6 +276,7 @@ MicrohttpdServer::MicrohttpdServer() {
PRIVATE->daemon = nullptr;
opts[Option::ConnectionLimit] = FD_SETSIZE - 4;
opts[Option::ConnectionTimeout] = 0_s;
realm = "Restricted"_a;
}
@@ -285,7 +331,7 @@ bool MicrohttpdServer::listen(PINetworkAddress addr) {
addr.port(),
nullptr,
nullptr,
(MHD_AccessHandlerCallback)answer_to_connection,
(MHD_AccessHandlerCallback)answer_callback,
this,
MHD_OPTION_ARRAY,
options.data(),
@@ -307,14 +353,14 @@ void MicrohttpdServer::stop() {
}
void MicrohttpdServer::addFixedHeaders(PIHTTP::MessageMutable & msg) {
if (!msg.headers().contains(PIHTTP::Header::ContentType)) {
void MicrohttpdServer::addFixedHeaders(MessageMutable & msg) {
if (!msg.headers().contains(Header::ContentType)) {
if (msg.body().isNotEmpty()) {
if (msg.body().startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
msg.addHeader(PIHTTP::Header::ContentType, "text/html; charset=utf-8");
msg.addHeader(Header::ContentType, "text/html; charset=utf-8");
else if (msg.body()[0] == '[' || msg.body()[0] == '{')
msg.addHeader(PIHTTP::Header::ContentType, "application/json; charset=utf-8");
msg.addHeader(Header::ContentType, "application/json; charset=utf-8");
}
}
msg.addHeader(PIHTTP::Header::AccessControlAllowOrigin, "*");
msg.addHeader(Header::AccessControlAllowOrigin, "*");
}