mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-10-04 16:08:31 +00:00
preliminary support for http basic auth (real)
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
#include "../../uwsgi.h"
|
||||
|
||||
#ifdef UWSGI_ROUTING
|
||||
|
||||
#ifdef __linux__
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
extern struct uwsgi_server uwsgi;
|
||||
|
||||
// this algo is based on nginx one (the fastest i have tested)
|
||||
static char *http_basic_auth_get(char *authorization, uint16_t len) {
|
||||
|
||||
uint16_t i;
|
||||
static uint8_t table64[] = {
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
|
||||
77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
|
||||
77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
|
||||
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
|
||||
77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
|
||||
};
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (authorization[i] == '=')
|
||||
break;
|
||||
|
||||
// check for invalid content
|
||||
if (table64[ (uint8_t) authorization[i] ] == 77) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// check for invalid length
|
||||
if (i % 4 == 1)
|
||||
return NULL;
|
||||
|
||||
uint16_t dst_len = (((len+3)/4) * 3) + 1;
|
||||
char *dst = uwsgi_malloc(dst_len);
|
||||
|
||||
char *ptr = dst;
|
||||
uint8_t *src = (uint8_t *) authorization;
|
||||
while(i > 3) {
|
||||
*ptr++= (char) ( table64[src[0]] << 2 | table64[src[1]] >> 4);
|
||||
*ptr++= (char) ( table64[src[1]] << 4 | table64[src[2]] >> 2);
|
||||
*ptr++= (char) ( table64[src[2]] << 6 | table64[src[3]]);
|
||||
|
||||
src+=4;
|
||||
i-=4;
|
||||
}
|
||||
|
||||
if (i > 1) {
|
||||
*ptr++= (char) ( table64[src[0]] << 2 | table64[src[1]] >> 4);
|
||||
}
|
||||
|
||||
if (i > 2) {
|
||||
*ptr++= (char) ( table64[src[1]] << 4 | table64[src[2]] >> 2);
|
||||
}
|
||||
|
||||
*ptr++= 0;
|
||||
|
||||
return dst;
|
||||
|
||||
}
|
||||
|
||||
uint16_t check_htpasswd(char *filename, char *auth) {
|
||||
|
||||
char line[1024];
|
||||
|
||||
char *colon = strchr(auth, ':');
|
||||
if (!colon) return 0;
|
||||
|
||||
FILE *htpasswd = fopen(filename, "r");
|
||||
if (!htpasswd) {
|
||||
return 0;
|
||||
}
|
||||
while(fgets(line, 1024, htpasswd)) {
|
||||
char *colon2 = strchr(line, ':');
|
||||
if (!colon2) break;
|
||||
|
||||
char *cpwd = colon2+1;
|
||||
size_t clen = strlen(cpwd);
|
||||
if (clen < 13) break;
|
||||
|
||||
if (clen > 13) cpwd[13] = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
struct crypt_data cd;
|
||||
cd.initialized = 0;
|
||||
// we do as nginx here
|
||||
cd.current_salt[0] = ~cpwd[0];
|
||||
char *crypted = crypt_r( colon+1, cpwd, &cd);
|
||||
#else
|
||||
char *crypted = crypt( colon+1, cpwd);
|
||||
#endif
|
||||
if (!crypted) continue;
|
||||
|
||||
if (!strcmp( crypted, cpwd )) {
|
||||
fclose(htpasswd);
|
||||
return colon-auth;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(htpasswd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
|
||||
|
||||
struct iovec iov[4];
|
||||
|
||||
if (wsgi_req->protocol_len > 0) {
|
||||
iov[0].iov_base = wsgi_req->protocol;
|
||||
iov[0].iov_len = wsgi_req->protocol_len;
|
||||
}
|
||||
else {
|
||||
iov[0].iov_base = "HTTP/1.0";
|
||||
iov[0].iov_len = 8;
|
||||
}
|
||||
|
||||
// chec for "Basic =" string at least
|
||||
if (wsgi_req->authorization_len > 7) {
|
||||
if (strncmp(wsgi_req->authorization, "Basic ", 6))
|
||||
goto forbidden;
|
||||
|
||||
char *auth = http_basic_auth_get(wsgi_req->authorization+6, wsgi_req->authorization_len-6);
|
||||
if (auth) {
|
||||
if (ur->custom) {
|
||||
// check htpasswd-like file
|
||||
}
|
||||
else {
|
||||
if (!strcmp(auth, ur->data2)) {
|
||||
free(auth);
|
||||
return UWSGI_ROUTE_CONTINUE;
|
||||
}
|
||||
}
|
||||
free(auth);
|
||||
if (ur->is_last)
|
||||
goto forbidden;
|
||||
return UWSGI_ROUTE_NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
forbidden:
|
||||
iov[1].iov_base = " 401 Authorization Required\r\nWWW-Authenticate: Basic realm=\"";
|
||||
iov[1].iov_len = 60 ;
|
||||
|
||||
iov[2].iov_base = ur->data;
|
||||
iov[2].iov_len = ur->data_len;
|
||||
|
||||
iov[3].iov_base = "\"\r\n\r\n";
|
||||
iov[3].iov_len = 5;
|
||||
|
||||
wsgi_req->headers_size = wsgi_req->socket->proto_writev_header(wsgi_req, iov, 4);
|
||||
|
||||
wsgi_req->response_size = wsgi_req->socket->proto_write(wsgi_req,"Unauthorized", 12);
|
||||
|
||||
return UWSGI_ROUTE_BREAK;
|
||||
}
|
||||
|
||||
|
||||
int uwsgi_router_basicauth(struct uwsgi_route *ur, char *args) {
|
||||
|
||||
ur->func = uwsgi_routing_func_basicauth;
|
||||
|
||||
char *comma = strchr(args, ',');
|
||||
if (!comma) {
|
||||
uwsgi_log("invalid route syntax: %s\n", args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
*comma = 0;
|
||||
|
||||
char *colon = strchr(comma+1, ':');
|
||||
// is an htpasswd-like file ?
|
||||
if (!colon) {
|
||||
ur->custom = 1;
|
||||
}
|
||||
|
||||
ur->data = args;
|
||||
ur->data_len = strlen(args);
|
||||
|
||||
ur->data2 = comma+1;
|
||||
ur->data2_len = strlen(ur->data2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void router_basicauth_register(void) {
|
||||
|
||||
uwsgi_register_router("basicauth", uwsgi_router_basicauth);
|
||||
}
|
||||
|
||||
struct uwsgi_plugin router_basicauth_plugin = {
|
||||
|
||||
.name = "router_redirect",
|
||||
.on_load = router_basicauth_register,
|
||||
};
|
||||
#else
|
||||
struct uwsgi_plugin router_basicauth_plugin = {
|
||||
.name = "router_basicauth",
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
NAME='router_basicauth'
|
||||
|
||||
CFLAGS = []
|
||||
LDFLAGS = []
|
||||
LIBS = ['-lcrypt']
|
||||
GCC_LIST = ['router_basicauth']
|
||||
Reference in New Issue
Block a user