mirror of
https://github.com/falk-werner/webfuse
synced 2024-10-27 20:34:10 +00:00
webfuse-server: add header-based authentication
This commit is contained in:
parent
f12f461154
commit
8c290b8c02
@ -22,6 +22,7 @@ add_library(webfuse_static STATIC
|
||||
src/webfuse/response_type.cpp
|
||||
src/webfuse/util/commandline_args.cpp
|
||||
src/webfuse/util/commandline_reader.cpp
|
||||
src/webfuse/util/authenticator.cpp
|
||||
src/webfuse/filesystem.cpp
|
||||
src/webfuse/filesystem/status.cpp
|
||||
src/webfuse/filesystem/accessmode.cpp
|
||||
|
13
script/authenticator.sh
Executable file
13
script/authenticator.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
AUTH_TOKEN="$1"
|
||||
|
||||
if [[ "$AUTH_TOKEN" == "user:bob;token=foo" ]]
|
||||
then
|
||||
echo "$(date): webfuse: auth granted: $AUTH_TOKEN" >> /tmp/webfuse_auth.log
|
||||
else
|
||||
echo "$(date): webfuse: auth denied: $AUTH_TOKEN" >> /tmp/webfuse_auth.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -272,7 +272,7 @@ class FilesystemProvider:
|
||||
}
|
||||
|
||||
async def run(self):
|
||||
async with websockets.connect(self.url) as connection:
|
||||
async with websockets.connect(self.url, extra_headers=[("X-Auth-Token", "user:bob;token=foo")]) as connection:
|
||||
while True:
|
||||
request = await connection.recv()
|
||||
reader = MessageReader(request)
|
||||
|
55
src/webfuse/util/authenticator.cpp
Normal file
55
src/webfuse/util/authenticator.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "webfuse/util/authenticator.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
authenticator::authenticator(std::string const & app)
|
||||
: app_(app)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool authenticator::authenticate(std::string const & token)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
pid_t const pid = fork();
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
// child
|
||||
|
||||
// prepare file descriptors
|
||||
closefrom(0);
|
||||
open("/dev/null", O_RDONLY);
|
||||
open("/dev/null", O_WRONLY);
|
||||
dup2(STDOUT_FILENO, STDERR_FILENO);
|
||||
|
||||
execl(app_.c_str(), app_.c_str(), token.c_str(), nullptr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (pid > 0)
|
||||
{
|
||||
// parent
|
||||
int exit_status = EXIT_FAILURE;
|
||||
|
||||
int status = 0;
|
||||
int const rc = waitpid(pid, &status, 0);
|
||||
if (rc == pid)
|
||||
{
|
||||
exit_status = WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
result = (exit_status == EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
23
src/webfuse/util/authenticator.hpp
Normal file
23
src/webfuse/util/authenticator.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef WEBFUSE_AUTHENTICATOR_HPP
|
||||
#define WEBFUSE_AUTHENTICATOR_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
class authenticator
|
||||
{
|
||||
public:
|
||||
explicit authenticator(std::string const & app);
|
||||
~authenticator() = default;
|
||||
|
||||
bool authenticate(std::string const & token);
|
||||
|
||||
private:
|
||||
std::string app_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -30,10 +30,12 @@ int app::run(int argc, char * argv[]) // NOLINT(readability-convert-member-funct
|
||||
fuse::print_usage();
|
||||
std::cout << R"(
|
||||
WEBFUSE options:
|
||||
--wf-port PORT port number of websocket server (default: 8081)
|
||||
--wf-vhost VHOST name of the virtual host (default: localhost)
|
||||
--wf-cert PATH path of the server's public certificate (optional)
|
||||
--wf-key PATH path of the server's private key (optional)
|
||||
--wf-port PORT port number of websocket server (default: 8081)
|
||||
--wf-vhost VHOST name of the virtual host (default: localhost)
|
||||
--wf-cert PATH path of the server's public certificate (optional)
|
||||
--wf-key PATH path of the server's private key (optional)
|
||||
--wf-authenticator PATH path of authenticatior app (optional)
|
||||
--wf-auth-header NAME name of the authentication header (optional)
|
||||
)";
|
||||
}
|
||||
break;
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "webfuse/ws/config.hpp"
|
||||
#include "webfuse/util/commandline_reader.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
@ -87,6 +89,18 @@ ws_config::ws_config(int argc, char * argv[])
|
||||
use_tls = true;
|
||||
}
|
||||
}
|
||||
else if (arg == "--wf-authenticator")
|
||||
{
|
||||
get_arg(*this, reader, authenticator, "missing AUTHENTICATOR");
|
||||
}
|
||||
else if (arg == "--wf-auth-header")
|
||||
{
|
||||
if (get_arg(*this, reader, auth_header, "missing AUTH_HEADER"))
|
||||
{
|
||||
std::transform(auth_header.begin(), auth_header.end(), auth_header.begin(),
|
||||
[](auto c) {return std::tolower(c); });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args.push(arg.c_str());
|
||||
|
@ -30,6 +30,9 @@ public:
|
||||
bool use_tls;
|
||||
std::string cert_path;
|
||||
std::string key_path;
|
||||
|
||||
std::string authenticator;
|
||||
std::string auth_header;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "webfuse/ws/server.hpp"
|
||||
#include "webfuse/util/authenticator.hpp"
|
||||
|
||||
#include <libwebsockets.h>
|
||||
|
||||
@ -32,6 +33,9 @@ struct user_data
|
||||
uint32_t id = 0;
|
||||
std::queue<webfuse::messagewriter> requests;
|
||||
std::unordered_map<uint32_t, std::promise<webfuse::messagereader>> pending_responses;
|
||||
|
||||
std::string authenticator;
|
||||
std::string auth_header;
|
||||
};
|
||||
|
||||
|
||||
@ -72,6 +76,75 @@ void do_receive(void * in, int len, lws* wsi, user_data * data)
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_auth_token_of_known_header(lws * wsi, lws_token_indexes header)
|
||||
{
|
||||
std::string token;
|
||||
int const length = lws_hdr_total_length(wsi, header);
|
||||
if (length > 0)
|
||||
{
|
||||
std::vector<char> data(length + 1);
|
||||
int const actual_length = lws_hdr_copy(wsi, data.data(), length + 1, header);
|
||||
if (actual_length > 0)
|
||||
{
|
||||
token = data.data();
|
||||
}
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string get_auth_token_from_custom_header(lws * wsi, std::string const & auth_header)
|
||||
{
|
||||
std::string token;
|
||||
int const length = lws_hdr_custom_length(wsi, auth_header.c_str(), auth_header.size());
|
||||
if (length > 0)
|
||||
{
|
||||
std::vector<char> data(length + 1);
|
||||
int const actual_length = lws_hdr_custom_copy(wsi, data.data(), length + 1,
|
||||
auth_header.c_str(), auth_header.size());
|
||||
if (actual_length > 0)
|
||||
{
|
||||
token = data.data();
|
||||
}
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string get_auth_token(lws * wsi, std::string const & auth_header)
|
||||
{
|
||||
if (auth_header == "authorization")
|
||||
{
|
||||
return get_auth_token_of_known_header(wsi, WSI_TOKEN_HTTP_AUTHORIZATION);
|
||||
}
|
||||
|
||||
if (auth_header == "x-auth-token")
|
||||
{
|
||||
return get_auth_token_of_known_header(wsi, WSI_TOKEN_X_AUTH_TOKEN);
|
||||
}
|
||||
|
||||
return get_auth_token_from_custom_header(wsi, auth_header);
|
||||
}
|
||||
|
||||
int do_authenticate(lws * wsi, std::string const & authenticator_app, std::string const & auth_header)
|
||||
{
|
||||
int result = 0;
|
||||
if ((!authenticator_app.empty()) && (!auth_header.empty()))
|
||||
{
|
||||
std::string token = get_auth_token(wsi, auth_header);
|
||||
if (!token.empty())
|
||||
{
|
||||
webfuse::authenticator authenticator(authenticator_app);
|
||||
result = authenticator.authenticate(token) ? 0 : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -90,6 +163,11 @@ static int ws_server_callback(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
int result = 0;
|
||||
switch(reason)
|
||||
{
|
||||
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
|
||||
{
|
||||
result = do_authenticate(wsi, data->authenticator, data->auth_header);
|
||||
}
|
||||
break;
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
if (nullptr == data->connection)
|
||||
{
|
||||
@ -164,6 +242,9 @@ public:
|
||||
detail(ws_config const & config)
|
||||
: shutdown_requested(false)
|
||||
{
|
||||
data.authenticator = config.authenticator;
|
||||
data.auth_header = config.auth_header;
|
||||
|
||||
lws_set_log_level(0, nullptr);
|
||||
|
||||
memset(reinterpret_cast<void*>(protocols), 0, sizeof(protocols));
|
||||
|
@ -80,7 +80,7 @@ int process::wait()
|
||||
{
|
||||
int status = 0;
|
||||
int rc = waitpid(pid, &status, 0);
|
||||
if (rc == 0)
|
||||
if (rc == pid)
|
||||
{
|
||||
exit_code = WEXITSTATUS(status);
|
||||
pid = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user