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/response_type.cpp
|
||||||
src/webfuse/util/commandline_args.cpp
|
src/webfuse/util/commandline_args.cpp
|
||||||
src/webfuse/util/commandline_reader.cpp
|
src/webfuse/util/commandline_reader.cpp
|
||||||
|
src/webfuse/util/authenticator.cpp
|
||||||
src/webfuse/filesystem.cpp
|
src/webfuse/filesystem.cpp
|
||||||
src/webfuse/filesystem/status.cpp
|
src/webfuse/filesystem/status.cpp
|
||||||
src/webfuse/filesystem/accessmode.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 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:
|
while True:
|
||||||
request = await connection.recv()
|
request = await connection.recv()
|
||||||
reader = MessageReader(request)
|
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();
|
fuse::print_usage();
|
||||||
std::cout << R"(
|
std::cout << R"(
|
||||||
WEBFUSE options:
|
WEBFUSE options:
|
||||||
--wf-port PORT port number of websocket server (default: 8081)
|
--wf-port PORT port number of websocket server (default: 8081)
|
||||||
--wf-vhost VHOST name of the virtual host (default: localhost)
|
--wf-vhost VHOST name of the virtual host (default: localhost)
|
||||||
--wf-cert PATH path of the server's public certificate (optional)
|
--wf-cert PATH path of the server's public certificate (optional)
|
||||||
--wf-key PATH path of the server's private key (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;
|
break;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "webfuse/ws/config.hpp"
|
#include "webfuse/ws/config.hpp"
|
||||||
#include "webfuse/util/commandline_reader.hpp"
|
#include "webfuse/util/commandline_reader.hpp"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -87,6 +89,18 @@ ws_config::ws_config(int argc, char * argv[])
|
|||||||
use_tls = true;
|
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
|
else
|
||||||
{
|
{
|
||||||
args.push(arg.c_str());
|
args.push(arg.c_str());
|
||||||
|
@ -30,6 +30,9 @@ public:
|
|||||||
bool use_tls;
|
bool use_tls;
|
||||||
std::string cert_path;
|
std::string cert_path;
|
||||||
std::string key_path;
|
std::string key_path;
|
||||||
|
|
||||||
|
std::string authenticator;
|
||||||
|
std::string auth_header;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "webfuse/ws/server.hpp"
|
#include "webfuse/ws/server.hpp"
|
||||||
|
#include "webfuse/util/authenticator.hpp"
|
||||||
|
|
||||||
#include <libwebsockets.h>
|
#include <libwebsockets.h>
|
||||||
|
|
||||||
@ -32,6 +33,9 @@ struct user_data
|
|||||||
uint32_t id = 0;
|
uint32_t id = 0;
|
||||||
std::queue<webfuse::messagewriter> requests;
|
std::queue<webfuse::messagewriter> requests;
|
||||||
std::unordered_map<uint32_t, std::promise<webfuse::messagereader>> pending_responses;
|
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;
|
int result = 0;
|
||||||
switch(reason)
|
switch(reason)
|
||||||
{
|
{
|
||||||
|
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
|
||||||
|
{
|
||||||
|
result = do_authenticate(wsi, data->authenticator, data->auth_header);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case LWS_CALLBACK_ESTABLISHED:
|
case LWS_CALLBACK_ESTABLISHED:
|
||||||
if (nullptr == data->connection)
|
if (nullptr == data->connection)
|
||||||
{
|
{
|
||||||
@ -164,6 +242,9 @@ public:
|
|||||||
detail(ws_config const & config)
|
detail(ws_config const & config)
|
||||||
: shutdown_requested(false)
|
: shutdown_requested(false)
|
||||||
{
|
{
|
||||||
|
data.authenticator = config.authenticator;
|
||||||
|
data.auth_header = config.auth_header;
|
||||||
|
|
||||||
lws_set_log_level(0, nullptr);
|
lws_set_log_level(0, nullptr);
|
||||||
|
|
||||||
memset(reinterpret_cast<void*>(protocols), 0, sizeof(protocols));
|
memset(reinterpret_cast<void*>(protocols), 0, sizeof(protocols));
|
||||||
|
@ -80,7 +80,7 @@ int process::wait()
|
|||||||
{
|
{
|
||||||
int status = 0;
|
int status = 0;
|
||||||
int rc = waitpid(pid, &status, 0);
|
int rc = waitpid(pid, &status, 0);
|
||||||
if (rc == 0)
|
if (rc == pid)
|
||||||
{
|
{
|
||||||
exit_code = WEXITSTATUS(status);
|
exit_code = WEXITSTATUS(status);
|
||||||
pid = 0;
|
pid = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user