add support for basic HTTP authentication

using the "BasicAuth" keyword in tinyproxy.conf.

base64 code was written by myself and taken from my own library "libulz".
for this purpose it is relicensed under the usual terms of the tinyproxy
license.
This commit is contained in:
rofl0r 2017-11-16 12:04:37 +00:00 committed by rofl0r
parent 1ebfd2a2d1
commit 8db511b9bf
7 changed files with 210 additions and 0 deletions

View File

@ -215,6 +215,11 @@ MaxRequestsPerChild 0
# #
Allow 127.0.0.1 Allow 127.0.0.1
# BasicAuth: HTTP "Basic Authentication" for accessing the proxy.
# If there are any entries specified, access is only granted for authenticated
# users.
#BasicAuth user password
# #
# AddHeader: Adds the specified headers to outgoing HTTP requests that # AddHeader: Adds the specified headers to outgoing HTTP requests that
# Tinyproxy makes. Note that this option will not work for HTTPS # Tinyproxy makes. Note that this option will not work for HTTPS

View File

@ -47,6 +47,7 @@ tinyproxy_SOURCES = \
utils.c utils.h \ utils.c utils.h \
vector.c vector.h \ vector.c vector.h \
upstream.c upstream.h \ upstream.c upstream.h \
basicauth.c basicauth.h \
connect-ports.c connect-ports.h connect-ports.c connect-ports.h
EXTRA_tinyproxy_SOURCES = filter.c filter.h \ EXTRA_tinyproxy_SOURCES = filter.c filter.h \

122
src/basicauth.c Normal file
View File

@ -0,0 +1,122 @@
/* tinyproxy - A fast light-weight HTTP proxy
* This file: Copyright (C) 2016-2017 rofl0r
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "main.h"
#include "basicauth.h"
#include "conns.h"
#include "heap.h"
#include "html-error.h"
#include "log.h"
#include "conf.h"
/* calculates number of bytes base64-encoded stream of N bytes will take. */
#define BASE64ENC_BYTES(N) (((N+2)/3)*4)
static const char base64_tbl[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* my own base64 impl (taken from libulz) */
static void base64enc(char *dst, const void* src, size_t count)
{
unsigned const char *s = src;
char* d = dst;
while(count) {
int i = 0, n = *s << 16;
s++;
count--;
if(count) {
n |= *s << 8;
s++;
count--;
i++;
}
if(count) {
n |= *s;
s++;
count--;
i++;
}
*d++ = base64_tbl[(n >> 18) & 0x3f];
*d++ = base64_tbl[(n >> 12) & 0x3f];
*d++ = i ? base64_tbl[(n >> 6) & 0x3f] : '=';
*d++ = i == 2 ? base64_tbl[n & 0x3f] : '=';
}
*d = 0;
}
/*
* Add entry to the basicauth list
*/
void basicauth_add (vector_t authlist,
const char *user, const char *pass)
{
char tmp[256+2];
char b[BASE64ENC_BYTES((sizeof tmp)-1) + 1];
int l;
size_t bl;
if (user == NULL || pass == NULL) {
log_message (LOG_WARNING,
"Illegal basicauth rule: missing user or pass");
return;
}
l = snprintf(tmp, sizeof tmp, "%s:%s", user, pass);
if(l >= (ssize_t) sizeof tmp) {
log_message (LOG_WARNING,
"User / pass in basicauth rule too long");
return;
}
base64enc(b, tmp, l);
bl = BASE64ENC_BYTES(l) + 1;
if (vector_append(authlist, b, bl) == -ENOMEM) {
log_message (LOG_ERR,
"Unable to allocate memory in basicauth_add()");
return;
}
log_message (LOG_INFO,
"Added basic auth user : %s", user);
}
/*
* Check if a user/password combination (encoded as base64)
* is in the basicauth list.
* return 1 on success, 0 on failure.
*/
int basicauth_check (vector_t authlist, const char *authstring)
{
ssize_t vl, i;
size_t al, el;
const char* entry;
vl = vector_length (authlist);
if (vl == -EINVAL) return 0;
al = strlen (authstring);
for (i = 0; i < vl; i++) {
entry = vector_getentry (authlist, i, &el);
if (strncmp (authstring, entry, al) == 0)
return 1;
}
return 0;
}

31
src/basicauth.h Normal file
View File

@ -0,0 +1,31 @@
/* tinyproxy - A fast light-weight HTTP proxy
* Copyright (C) 2005 Robert James Kaes <rjkaes@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* See 'basicauth.c' for detailed information. */
#ifndef TINYPROXY_BASICAUTH_H
#define TINYPROXY_BASICAUTH_H
#include "vector.h"
extern void basicauth_add (vector_t authlist,
const char *user, const char *pass);
extern int basicauth_check (vector_t authlist, const char *authstring);
#endif

View File

@ -36,6 +36,7 @@
#include "reverse-proxy.h" #include "reverse-proxy.h"
#include "upstream.h" #include "upstream.h"
#include "connect-ports.h" #include "connect-ports.h"
#include "basicauth.h"
/* /*
* The configuration directives are defined in the structure below. Each * The configuration directives are defined in the structure below. Each
@ -116,6 +117,7 @@ static HANDLE_FUNC (handle_nop)
} /* do nothing function */ } /* do nothing function */
static HANDLE_FUNC (handle_allow); static HANDLE_FUNC (handle_allow);
static HANDLE_FUNC (handle_basicauth);
static HANDLE_FUNC (handle_anonymous); static HANDLE_FUNC (handle_anonymous);
static HANDLE_FUNC (handle_bind); static HANDLE_FUNC (handle_bind);
static HANDLE_FUNC (handle_bindsame); static HANDLE_FUNC (handle_bindsame);
@ -232,6 +234,7 @@ struct {
handle_deny), handle_deny),
STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind), STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind),
/* other */ /* other */
STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth),
STDCONF ("errorfile", INT WS STR, handle_errorfile), STDCONF ("errorfile", INT WS STR, handle_errorfile),
STDCONF ("addheader", STR WS STR, handle_addheader), STDCONF ("addheader", STR WS STR, handle_addheader),
@ -299,6 +302,7 @@ static void free_config (struct config_s *conf)
safefree (conf->user); safefree (conf->user);
safefree (conf->group); safefree (conf->group);
vector_delete(conf->listen_addrs); vector_delete(conf->listen_addrs);
vector_delete(conf->basicauth_list);
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
safefree (conf->filter); safefree (conf->filter);
#endif /* FILTER_ENABLE */ #endif /* FILTER_ENABLE */
@ -1000,6 +1004,27 @@ static HANDLE_FUNC (handle_loglevel)
return -1; return -1;
} }
static HANDLE_FUNC (handle_basicauth)
{
char *user, *pass;
user = get_string_arg(line, &match[2]);
if (!user)
return -1;
pass = get_string_arg(line, &match[3]);
if (!pass) {
safefree (user);
return -1;
}
if (!conf->basicauth_list) {
conf->basicauth_list = vector_create ();
}
basicauth_add (conf->basicauth_list, user, pass);
safefree (user);
safefree (pass);
return 0;
}
#ifdef FILTER_ENABLE #ifdef FILTER_ENABLE
static HANDLE_FUNC (handle_filter) static HANDLE_FUNC (handle_filter)
{ {

View File

@ -37,6 +37,7 @@ typedef struct {
* Hold all the configuration time information. * Hold all the configuration time information.
*/ */
struct config_s { struct config_s {
vector_t basicauth_list;
char *logf_name; char *logf_name;
char *config_file; char *config_file;
unsigned int syslog; /* boolean */ unsigned int syslog; /* boolean */

View File

@ -48,6 +48,7 @@
#include "upstream.h" #include "upstream.h"
#include "connect-ports.h" #include "connect-ports.h"
#include "conf.h" #include "conf.h"
#include "basicauth.h"
/* /*
* Maximum length of a HTTP line * Maximum length of a HTTP line
@ -1562,6 +1563,30 @@ void handle_connection (int fd)
goto fail; goto fail;
} }
if (config.basicauth_list != NULL) {
ssize_t len;
char *authstring;
int failure = 1;
len = hashmap_entry_by_key (hashofheaders, "proxy-authorization",
(void **) &authstring);
if (len > 0 &&
/* currently only "basic" auth supported */
(strncmp(authstring, "Basic ", 6) == 0 ||
strncmp(authstring, "basic ", 6) == 0) &&
basicauth_check (config.basicauth_list, authstring + 6) == 1)
failure = 0;
if(failure) {
update_stats (STAT_DENIED);
indicate_http_error (connptr, 403, "Access denied",
"detail",
"The administrator of this proxy has not configured "
"it to service requests from you.",
NULL);
goto fail;
}
hashmap_remove (hashofheaders, "proxy-authorization");
}
/* /*
* Add any user-specified headers (AddHeader directive) to the * Add any user-specified headers (AddHeader directive) to the
* outgoing HTTP request. * outgoing HTTP request.