mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-24 07:16:43 +00:00
Implement HTTP basic authentication
Use it in /restful/rhizome/bundlelist.json -- first 'rhizomehttp' test passes
This commit is contained in:
parent
b9faf54c91
commit
21fe12859f
262
http_server.c
262
http_server.c
@ -98,6 +98,8 @@ void http_request_init(struct http_request *r, int sockfd)
|
||||
assert(sockfd != -1);
|
||||
r->request_header.content_length = CONTENT_LENGTH_UNKNOWN;
|
||||
r->request_content_remaining = CONTENT_LENGTH_UNKNOWN;
|
||||
r->response.header.content_length = CONTENT_LENGTH_UNKNOWN;
|
||||
r->response.header.resource_length = CONTENT_LENGTH_UNKNOWN;
|
||||
r->alarm.stats = &http_server_stats;
|
||||
r->alarm.function = http_server_poll;
|
||||
if (r->idle_timeout == 0)
|
||||
@ -162,31 +164,85 @@ void http_request_finalise(struct http_request *r)
|
||||
r->phase = DONE;
|
||||
}
|
||||
|
||||
#define _SEP (1 << 0)
|
||||
#define _BND (1 << 1)
|
||||
#define _BASE64 (1 << 6)
|
||||
#define _MASK64 ((1 << 6) - 1)
|
||||
#define _SEP (1 << 7)
|
||||
#define _BND (1 << 8)
|
||||
|
||||
uint8_t http_ctype[256] = {
|
||||
['0'] = _BND, ['1'] = _BND, ['2'] = _BND, ['3'] = _BND, ['4'] = _BND,
|
||||
['5'] = _BND, ['6'] = _BND, ['7'] = _BND, ['8'] = _BND, ['9'] = _BND,
|
||||
['A'] = _BND, ['B'] = _BND, ['C'] = _BND, ['D'] = _BND, ['E'] = _BND,
|
||||
['F'] = _BND, ['G'] = _BND, ['H'] = _BND, ['I'] = _BND, ['J'] = _BND,
|
||||
['K'] = _BND, ['L'] = _BND, ['M'] = _BND, ['N'] = _BND, ['O'] = _BND,
|
||||
['P'] = _BND, ['Q'] = _BND, ['R'] = _BND, ['S'] = _BND, ['T'] = _BND,
|
||||
['U'] = _BND, ['V'] = _BND, ['W'] = _BND, ['X'] = _BND, ['Y'] = _BND,
|
||||
['Z'] = _BND,
|
||||
['a'] = _BND, ['b'] = _BND, ['c'] = _BND, ['d'] = _BND, ['e'] = _BND,
|
||||
['f'] = _BND, ['g'] = _BND, ['h'] = _BND, ['i'] = _BND, ['j'] = _BND,
|
||||
['k'] = _BND, ['l'] = _BND, ['m'] = _BND, ['n'] = _BND, ['o'] = _BND,
|
||||
['p'] = _BND, ['q'] = _BND, ['r'] = _BND, ['s'] = _BND, ['t'] = _BND,
|
||||
['u'] = _BND, ['v'] = _BND, ['w'] = _BND, ['x'] = _BND, ['y'] = _BND,
|
||||
['z'] = _BND,
|
||||
['+'] = _BND, ['-'] = _BND, ['.'] = _BND, ['/'] = _BND, [':'] = _BND,
|
||||
uint16_t http_ctype[256] = {
|
||||
['A'] = _BND | _BASE64 | 0,
|
||||
['B'] = _BND | _BASE64 | 1,
|
||||
['C'] = _BND | _BASE64 | 2,
|
||||
['D'] = _BND | _BASE64 | 3,
|
||||
['E'] = _BND | _BASE64 | 4,
|
||||
['F'] = _BND | _BASE64 | 5,
|
||||
['G'] = _BND | _BASE64 | 6,
|
||||
['H'] = _BND | _BASE64 | 7,
|
||||
['I'] = _BND | _BASE64 | 8,
|
||||
['J'] = _BND | _BASE64 | 9,
|
||||
['K'] = _BND | _BASE64 | 10,
|
||||
['L'] = _BND | _BASE64 | 11,
|
||||
['M'] = _BND | _BASE64 | 12,
|
||||
['N'] = _BND | _BASE64 | 13,
|
||||
['O'] = _BND | _BASE64 | 14,
|
||||
['P'] = _BND | _BASE64 | 15,
|
||||
['Q'] = _BND | _BASE64 | 16,
|
||||
['R'] = _BND | _BASE64 | 17,
|
||||
['S'] = _BND | _BASE64 | 18,
|
||||
['T'] = _BND | _BASE64 | 19,
|
||||
['U'] = _BND | _BASE64 | 20,
|
||||
['V'] = _BND | _BASE64 | 21,
|
||||
['W'] = _BND | _BASE64 | 22,
|
||||
['X'] = _BND | _BASE64 | 23,
|
||||
['Y'] = _BND | _BASE64 | 24,
|
||||
['Z'] = _BND | _BASE64 | 25,
|
||||
['a'] = _BND | _BASE64 | 26,
|
||||
['b'] = _BND | _BASE64 | 27,
|
||||
['c'] = _BND | _BASE64 | 28,
|
||||
['d'] = _BND | _BASE64 | 29,
|
||||
['e'] = _BND | _BASE64 | 30,
|
||||
['f'] = _BND | _BASE64 | 31,
|
||||
['g'] = _BND | _BASE64 | 32,
|
||||
['h'] = _BND | _BASE64 | 33,
|
||||
['i'] = _BND | _BASE64 | 34,
|
||||
['j'] = _BND | _BASE64 | 35,
|
||||
['k'] = _BND | _BASE64 | 36,
|
||||
['l'] = _BND | _BASE64 | 37,
|
||||
['m'] = _BND | _BASE64 | 38,
|
||||
['n'] = _BND | _BASE64 | 39,
|
||||
['o'] = _BND | _BASE64 | 40,
|
||||
['p'] = _BND | _BASE64 | 41,
|
||||
['q'] = _BND | _BASE64 | 42,
|
||||
['r'] = _BND | _BASE64 | 43,
|
||||
['s'] = _BND | _BASE64 | 44,
|
||||
['t'] = _BND | _BASE64 | 45,
|
||||
['u'] = _BND | _BASE64 | 46,
|
||||
['v'] = _BND | _BASE64 | 47,
|
||||
['w'] = _BND | _BASE64 | 48,
|
||||
['x'] = _BND | _BASE64 | 49,
|
||||
['y'] = _BND | _BASE64 | 50,
|
||||
['z'] = _BND | _BASE64 | 51,
|
||||
['0'] = _BND | _BASE64 | 52,
|
||||
['1'] = _BND | _BASE64 | 53,
|
||||
['2'] = _BND | _BASE64 | 54,
|
||||
['3'] = _BND | _BASE64 | 55,
|
||||
['4'] = _BND | _BASE64 | 56,
|
||||
['5'] = _BND | _BASE64 | 57,
|
||||
['6'] = _BND | _BASE64 | 58,
|
||||
['7'] = _BND | _BASE64 | 59,
|
||||
['8'] = _BND | _BASE64 | 60,
|
||||
['9'] = _BND | _BASE64 | 61,
|
||||
['+'] = _BND | _BASE64 | 62,
|
||||
['/'] = _BND | _BASE64 | 63,
|
||||
['='] = _SEP | _BND,
|
||||
['-'] = _BND,
|
||||
['.'] = _BND,
|
||||
[':'] = _BND,
|
||||
['_'] = _BND,
|
||||
['('] = _SEP | _BND,
|
||||
[')'] = _SEP | _BND,
|
||||
[','] = _SEP | _BND,
|
||||
['?'] = _SEP | _BND,
|
||||
['='] = _SEP | _BND,
|
||||
[' '] = _SEP | _BND,
|
||||
['\t'] = _SEP,
|
||||
['<'] = _SEP,
|
||||
@ -213,6 +269,21 @@ inline int is_http_ctl(char c)
|
||||
return iscntrl(c);
|
||||
}
|
||||
|
||||
inline int is_base64_digit(char c)
|
||||
{
|
||||
return (http_ctype[(unsigned char) c] & _BASE64) != 0;
|
||||
}
|
||||
|
||||
inline int is_base64_pad(char c)
|
||||
{
|
||||
return c == '=';
|
||||
}
|
||||
|
||||
inline uint8_t base64_digit(char c)
|
||||
{
|
||||
return http_ctype[(unsigned char) c] & _MASK64;
|
||||
}
|
||||
|
||||
inline int is_http_separator(char c)
|
||||
{
|
||||
return (http_ctype[(unsigned char) c] & _SEP) != 0;
|
||||
@ -612,6 +683,92 @@ static int _parse_content_type(struct http_request *r, struct mime_content_type
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t _parse_base64(struct http_request *r, char *bin, size_t binsize)
|
||||
{
|
||||
uint8_t buf = 0;
|
||||
size_t digits = 0;
|
||||
size_t bytes = 0;
|
||||
for (; !_run_out(r) && is_base64_digit(*r->cursor); _skip_optional_space(r), ++r->cursor) {
|
||||
if (bytes < binsize) {
|
||||
uint8_t d = base64_digit(*r->cursor);
|
||||
switch (digits++ & 3) {
|
||||
case 0:
|
||||
buf = d << 2;
|
||||
break;
|
||||
case 1:
|
||||
if (bin)
|
||||
bin[bytes] = buf | (d >> 4);
|
||||
++bytes;
|
||||
buf = d << 4;
|
||||
break;
|
||||
case 2:
|
||||
if (bin)
|
||||
bin[bytes] = buf | (d >> 2);
|
||||
++bytes;
|
||||
buf = d << 6;
|
||||
break;
|
||||
case 3:
|
||||
if (bin)
|
||||
bin[bytes] = buf | d;
|
||||
++bytes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (digits == 0)
|
||||
return 0;
|
||||
if (!_run_out(r) && is_base64_pad(*r->cursor))
|
||||
++r->cursor;
|
||||
if (!_run_out(r) && is_base64_pad(*r->cursor))
|
||||
++r->cursor;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static int _parse_authorization_credentials_basic(struct http_request *r, struct http_client_credentials_basic *cred, char *buf, size_t bufsz)
|
||||
{
|
||||
size_t n = _parse_base64(r, buf, bufsz - 1); // leave room for NUL terminator on password
|
||||
assert(n < bufsz); // buffer must be big enough
|
||||
char *pw = (char *) strnchr(buf, n, ':');
|
||||
if (pw == NULL)
|
||||
return 0; // malformed
|
||||
cred->user = buf;
|
||||
*pw++ = '\0'; // NUL terminate user
|
||||
cred->password = pw;
|
||||
buf[n] = '\0'; // NUL terminate password
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _parse_authorization(struct http_request *r, struct http_client_authorization *auth, size_t header_bytes)
|
||||
{
|
||||
const char *start = r->cursor;
|
||||
if (_skip_literal(r, "Basic") && _skip_space(r)) {
|
||||
size_t bufsz = 5 + header_bytes * 3 / 4; // enough for base64 decoding
|
||||
char buf[bufsz];
|
||||
if (_parse_authorization_credentials_basic(r, &auth->credentials.basic, buf, bufsz) == -1) {
|
||||
auth->scheme = BASIC;
|
||||
return 1;
|
||||
}
|
||||
if (r->debug_flag && *r->debug_flag)
|
||||
DEBUGF("Malformed HTTP header: Authorization: %s", alloca_toprint(50, start, header_bytes));
|
||||
return 0;
|
||||
}
|
||||
if (_skip_literal(r, "Digest") && _skip_space(r)) {
|
||||
if (r->debug_flag && *r->debug_flag)
|
||||
DEBUG("Ignoring unsupported HTTP Authorization scheme: Digest");
|
||||
r->cursor += header_bytes;
|
||||
return 1;
|
||||
}
|
||||
struct substring scheme;
|
||||
if (_skip_token(r, &scheme) && _skip_space(r)) {
|
||||
if (r->debug_flag && *r->debug_flag)
|
||||
DEBUGF("Unrecognised HTTP Authorization scheme: %s", alloca_toprint(-1, scheme.start, scheme.end - scheme.start));
|
||||
return 0;
|
||||
}
|
||||
if (r->debug_flag && *r->debug_flag)
|
||||
DEBUGF("Malformed HTTP Authorization header: %s", alloca_toprint(50, r->parsed, r->end - r->parsed));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _parse_quoted_rfc822_time(struct http_request *r, time_t *timep)
|
||||
{
|
||||
char datestr[40];
|
||||
@ -854,7 +1011,7 @@ static int http_request_parse_header(struct http_request *r)
|
||||
if ( _skip_literal(r, "bytes=")
|
||||
&& (n = _parse_ranges(r, r->request_header.content_ranges, NELS(r->request_header.content_ranges)))
|
||||
&& _skip_optional_space(r)
|
||||
&& (r->cursor == eol)
|
||||
&& r->cursor == eol
|
||||
) {
|
||||
r->cursor = nextline;
|
||||
_commit(r);
|
||||
@ -874,6 +1031,26 @@ static int http_request_parse_header(struct http_request *r)
|
||||
goto malformed;
|
||||
}
|
||||
_rewind(r);
|
||||
if (_skip_literal_nocase(r, "Authorization:")) {
|
||||
if (r->request_header.authorization.scheme != NOAUTH) {
|
||||
if (r->debug_flag && *r->debug_flag)
|
||||
DEBUGF("Skipping duplicate HTTP header Authorization: %s", alloca_toprint(50, sol, r->end - sol));
|
||||
r->cursor = nextline;
|
||||
_commit(r);
|
||||
return 0;
|
||||
}
|
||||
_skip_optional_space(r);
|
||||
if ( _parse_authorization(r, &r->request_header.authorization, eol - r->cursor)
|
||||
&& _skip_optional_space(r)
|
||||
&& r->cursor == eol
|
||||
) {
|
||||
assert(r->request_header.authorization.scheme != NOAUTH);
|
||||
r->cursor = nextline;
|
||||
_commit(r);
|
||||
}
|
||||
goto malformed;
|
||||
}
|
||||
_rewind(r);
|
||||
if (r->debug_flag && *r->debug_flag)
|
||||
DEBUGF("Skipped HTTP request header: %s", alloca_toprint(-1, sol, eol - sol));
|
||||
r->cursor = nextline;
|
||||
@ -1520,6 +1697,9 @@ static void http_request_send_response(struct http_request *r)
|
||||
r->response_buffer_sent += (size_t) written;
|
||||
assert(r->response_sent <= r->response_length);
|
||||
assert(r->response_buffer_sent <= r->response_buffer_length);
|
||||
if (r->debug_flag && *r->debug_flag)
|
||||
DEBUGF("Wrote %zu bytes to HTTP socket, total %"PRIhttp_size_t", remaining=%"PRIhttp_size_t,
|
||||
(size_t) written, r->response_sent, r->response_length - r->response_sent);
|
||||
// Reset inactivity timer.
|
||||
r->alarm.alarm = gettime_ms() + r->idle_timeout;
|
||||
r->alarm.deadline = r->alarm.alarm + r->idle_timeout;
|
||||
@ -1640,24 +1820,30 @@ static const char *httpResultString(int response_code)
|
||||
static int _render_response(struct http_request *r)
|
||||
{
|
||||
struct http_response hr = r->response;
|
||||
assert(hr.result_code != 0);
|
||||
assert(hr.header.content_range_start <= hr.header.resource_length);
|
||||
assert(hr.header.content_length <= hr.header.resource_length);
|
||||
// To save page handlers having to decide between 200 (OK) and 206 (Partial Content), they can
|
||||
// just send 200 and the content range fields, and this logic will detect if it should be 206.
|
||||
if (hr.header.content_length > 0 && hr.header.content_length < hr.header.resource_length && hr.result_code == 200)
|
||||
hr.result_code = 206; // Partial Content
|
||||
assert(hr.result_code >= 200);
|
||||
assert(hr.result_code < 600);
|
||||
const char *result_string = httpResultString(hr.result_code);
|
||||
strbuf sb = strbuf_local(r->response_buffer, r->response_buffer_size);
|
||||
if (hr.content == NULL && hr.content_generator == NULL) {
|
||||
assert(hr.header.content_length == CONTENT_LENGTH_UNKNOWN);
|
||||
assert(hr.header.resource_length == CONTENT_LENGTH_UNKNOWN);
|
||||
assert(hr.header.content_range_start == 0);
|
||||
strbuf cb = strbuf_alloca(100 + strlen(result_string));
|
||||
strbuf_puts(cb, "<html><h1>");
|
||||
strbuf_puts(cb, result_string);
|
||||
strbuf_puts(cb, "</h1></html>\r\n");
|
||||
strbuf_sprintf(cb, "<html><h1>%03u %s</h1></html>", hr.result_code, result_string);
|
||||
hr.content = strbuf_str(cb);
|
||||
hr.header.resource_length = hr.header.content_length = strbuf_len(cb);
|
||||
hr.header.content_type = "text/html";
|
||||
hr.header.content_range_start = 0;
|
||||
} else {
|
||||
assert(hr.header.content_length != CONTENT_LENGTH_UNKNOWN);
|
||||
assert(hr.header.resource_length != CONTENT_LENGTH_UNKNOWN);
|
||||
assert(hr.header.content_length <= hr.header.resource_length);
|
||||
assert(hr.header.content_range_start + hr.header.content_length <= hr.header.resource_length);
|
||||
// To save page handlers having to decide between 200 (OK) and 206 (Partial Content), they can
|
||||
// just set the content range fields and pass 200 to http_request_response_static(), and this
|
||||
// logic will change it to 206 if appropriate.
|
||||
if (hr.header.content_length > 0 && hr.header.content_length < hr.header.resource_length && hr.result_code == 200)
|
||||
hr.result_code = 206; // Partial Content
|
||||
}
|
||||
assert(hr.header.content_type != NULL);
|
||||
assert(hr.header.content_type[0]);
|
||||
@ -1684,6 +1870,16 @@ static int _render_response(struct http_request *r)
|
||||
);
|
||||
}
|
||||
strbuf_sprintf(sb, "Content-Length: %"PRIhttp_size_t"\r\n", hr.header.content_length);
|
||||
const char *scheme = NULL;
|
||||
switch (hr.header.www_authenticate.scheme) {
|
||||
case NOAUTH: break;
|
||||
case BASIC: scheme = "Basic"; break;
|
||||
}
|
||||
if (scheme) {
|
||||
strbuf_sprintf(sb, "WWW-Authenticate: %s realm=", scheme);
|
||||
strbuf_append_quoted_string(sb, hr.header.www_authenticate.realm);
|
||||
strbuf_puts(sb, "\r\n");
|
||||
}
|
||||
strbuf_puts(sb, "\r\n");
|
||||
if (strbuf_overrun(sb))
|
||||
return 0;
|
||||
@ -1836,8 +2032,10 @@ void http_request_simple_response(struct http_request *r, uint16_t result, const
|
||||
r->response.result_code = result;
|
||||
r->response.header.content_type = "text/html";
|
||||
r->response.header.content_range_start = 0;
|
||||
r->response.header.resource_length = r->response.header.content_length = h ? strbuf_len(h) : 0;
|
||||
r->response.content = h ? strbuf_str(h) : NULL;
|
||||
if (h) {
|
||||
r->response.header.resource_length = r->response.header.content_length = strbuf_len(h);
|
||||
r->response.content = strbuf_str(h);
|
||||
}
|
||||
r->response.content_generator = NULL;
|
||||
http_request_start_response(r);
|
||||
}
|
||||
|
@ -63,11 +63,28 @@ struct mime_content_type {
|
||||
char charset[31];
|
||||
};
|
||||
|
||||
|
||||
struct http_client_authorization {
|
||||
enum http_authorization_scheme { NOAUTH = 0, BASIC } scheme;
|
||||
union {
|
||||
struct http_client_credentials_basic {
|
||||
const char *user;
|
||||
const char *password;
|
||||
} basic;
|
||||
} credentials;
|
||||
};
|
||||
|
||||
struct http_www_authenticate {
|
||||
enum http_authorization_scheme scheme;
|
||||
const char *realm;
|
||||
};
|
||||
|
||||
struct http_request_headers {
|
||||
http_size_t content_length;
|
||||
struct mime_content_type content_type;
|
||||
unsigned short content_range_count;
|
||||
struct http_range content_ranges[5];
|
||||
struct http_client_authorization authorization;
|
||||
};
|
||||
|
||||
struct http_response_headers {
|
||||
@ -76,6 +93,7 @@ struct http_response_headers {
|
||||
http_size_t resource_length; // size of entire resource
|
||||
const char *content_type; // "type/subtype"
|
||||
const char *boundary;
|
||||
struct http_www_authenticate www_authenticate;
|
||||
};
|
||||
|
||||
typedef int (*HTTP_CONTENT_GENERATOR)(struct http_request *);
|
||||
|
@ -34,24 +34,29 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32
|
||||
|
||||
typedef int HTTP_HANDLER(rhizome_http_request *r, const char *remainder);
|
||||
|
||||
struct http_handler{
|
||||
const char *path;
|
||||
int (*parser)(rhizome_http_request *r, const char *remainder);
|
||||
HTTP_HANDLER *parser;
|
||||
};
|
||||
|
||||
static int rhizome_status_page(rhizome_http_request *r, const char *remainder);
|
||||
static int rhizome_file_page(rhizome_http_request *r, const char *remainder);
|
||||
static int manifest_by_prefix_page(rhizome_http_request *r, const char *remainder);
|
||||
static int interface_page(rhizome_http_request *r, const char *remainder);
|
||||
static int neighbour_page(rhizome_http_request *r, const char *remainder);
|
||||
static int fav_icon_header(rhizome_http_request *r, const char *remainder);
|
||||
static int root_page(rhizome_http_request *r, const char *remainder);
|
||||
static HTTP_HANDLER restful_rhizome_bundlelist_json;
|
||||
|
||||
extern int rhizome_direct_import(rhizome_http_request *r, const char *remainder);
|
||||
extern int rhizome_direct_enquiry(rhizome_http_request *r, const char *remainder);
|
||||
extern int rhizome_direct_dispatch(rhizome_http_request *r, const char *remainder);
|
||||
static HTTP_HANDLER rhizome_status_page;
|
||||
static HTTP_HANDLER rhizome_file_page;
|
||||
static HTTP_HANDLER manifest_by_prefix_page;
|
||||
static HTTP_HANDLER interface_page;
|
||||
static HTTP_HANDLER neighbour_page;
|
||||
static HTTP_HANDLER fav_icon_header;
|
||||
static HTTP_HANDLER root_page;
|
||||
|
||||
extern HTTP_HANDLER rhizome_direct_import;
|
||||
extern HTTP_HANDLER rhizome_direct_enquiry;
|
||||
extern HTTP_HANDLER rhizome_direct_dispatch;
|
||||
|
||||
struct http_handler paths[]={
|
||||
{"/restful/rhizome/bundlelist.json", restful_rhizome_bundlelist_json},
|
||||
{"/rhizome/status", rhizome_status_page},
|
||||
{"/rhizome/file/", rhizome_file_page},
|
||||
{"/rhizome/import", rhizome_direct_import},
|
||||
@ -312,6 +317,43 @@ int is_http_header_complete(const char *buf, size_t len, size_t read_since_last_
|
||||
OUT();
|
||||
}
|
||||
|
||||
/* Return 1 if the given authorization credentials are acceptable.
|
||||
* Return 0 if not.
|
||||
*/
|
||||
static int is_authorized(struct http_client_authorization *auth)
|
||||
{
|
||||
if (auth->scheme != BASIC)
|
||||
return 0;
|
||||
unsigned i;
|
||||
for (i = 0; i != config.rhizome.api.restful.users.ac; ++i) {
|
||||
if ( strcmp(config.rhizome.api.restful.users.av[i].key, auth->credentials.basic.user) == 0
|
||||
&& strcmp(config.rhizome.api.restful.users.av[i].value.password, auth->credentials.basic.password) == 0
|
||||
)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int restful_rhizome_bundlelist_json(rhizome_http_request *r, const char *remainder)
|
||||
{
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 1;
|
||||
if (*remainder)
|
||||
return 1;
|
||||
if (r->http.verb != HTTP_VERB_GET) {
|
||||
http_request_simple_response(&r->http, 405, NULL);
|
||||
return 0;
|
||||
}
|
||||
if (!is_authorized(&r->http.request_header.authorization)) {
|
||||
r->http.response.header.www_authenticate.scheme = BASIC;
|
||||
r->http.response.header.www_authenticate.realm = "Serval Rhizome";
|
||||
http_request_simple_response(&r->http, 401, NULL);
|
||||
return 0;
|
||||
}
|
||||
http_request_simple_response(&r->http, 200, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int neighbour_page(rhizome_http_request *r, const char *remainder)
|
||||
{
|
||||
if (r->http.verb != HTTP_VERB_GET) {
|
||||
|
@ -41,8 +41,20 @@ setup() {
|
||||
get_rhizome_server_port PORTA +A
|
||||
}
|
||||
|
||||
finally() {
|
||||
stop_all_servald_servers
|
||||
}
|
||||
|
||||
teardown() {
|
||||
kill_all_servald_processes
|
||||
assert_no_servald_processes
|
||||
report_all_servald_servers
|
||||
}
|
||||
|
||||
set_rhizome_config() {
|
||||
executeOk_servald config \
|
||||
set debug.httpd on \
|
||||
set debug.rhizome_httpd on \
|
||||
set debug.rhizome on \
|
||||
set debug.verbose on \
|
||||
set log.console.level debug
|
||||
@ -50,14 +62,18 @@ set_rhizome_config() {
|
||||
|
||||
doc_AuthBasicMissing="Basic Authentication credentials are required"
|
||||
test_AuthBasicMissing() {
|
||||
execute --exit-status=67 curl \
|
||||
--silent --fail --show-error \
|
||||
executeOk curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.output \
|
||||
--dump-header http.headers \
|
||||
"http://$addr_localhost:$PORTA/restful/rhizome/bundlelist.json"
|
||||
assertStdoutIs '401'
|
||||
CR='
'
|
||||
assertGrep http.headers "^WWW-Authenticate: Basic realm=\"Serval Rhizome\"$CR$"
|
||||
}
|
||||
teardown_AuthBasicMissing() {
|
||||
tfw_cat http.headers http.output
|
||||
teardown
|
||||
}
|
||||
|
||||
doc_AuthBasicWrong="Basic Authentication credentials must be correct"
|
||||
|
Loading…
Reference in New Issue
Block a user