Replaced the username cookie with a compact auth option.

That option performs authentication of username, password in
a single go for clients that request Connection: Close.
This commit is contained in:
Nikos Mavrogiannopoulos
2014-01-12 11:59:45 +01:00
parent 151f107591
commit 2e2310187d
3 changed files with 70 additions and 63 deletions

View File

@@ -62,6 +62,18 @@ static const char login_msg_user[] =
"</form></auth>\n"
"</config-auth>";
static const char login_msg_compact[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<config-auth client=\"vpn\" type=\"auth-request\">\n"
"<version who=\"sg\">0.1(1)</version>\n"
"<auth id=\"main\">\n"
"<message>Please enter your username and password</message>\n"
"<form method=\"post\" action=\"/auth\">\n"
"<input type=\"text\" name=\"username\" label=\"Username:\" />\n"
"<input type=\"password\" name=\"password\" label=\"Password:\" />\n"
"</form></auth>\n"
"</config-auth>";
static const char login_msg_no_user[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<config-auth client=\"vpn\" type=\"auth-request\">\n"
@@ -75,9 +87,9 @@ static const char login_msg_no_user[] =
int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
{
int ret;
struct http_req_st *req = &ws->req;
char login_msg[MAX_MSG_SIZE + sizeof(login_msg_user)];
unsigned int lsize;
char *u;
tls_cork(ws->session);
ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver);
@@ -92,17 +104,26 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
if (ret < 0)
return -1;
if (ws->auth_state == S_AUTH_REQ) {
/* only ask password */
if (pmsg == NULL)
pmsg = "Please enter password";
lsize =
snprintf(login_msg, sizeof(login_msg), login_msg_no_user,
pmsg);
#ifdef ANYCONNECT_CLIENT_COMPAT
if (req && req->needs_compact_auth != 0) {
lsize = snprintf(login_msg, sizeof(login_msg), "%s", login_msg_compact);
} else {
/* ask for username only */
lsize = snprintf(login_msg, sizeof(login_msg), login_msg_user);
#endif
if (ws->auth_state == S_AUTH_REQ) {
/* only ask password */
if (pmsg == NULL)
pmsg = "Please enter password";
lsize =
snprintf(login_msg, sizeof(login_msg), login_msg_no_user,
pmsg);
} else {
/* ask for username only */
lsize = snprintf(login_msg, sizeof(login_msg), "%s", login_msg_user);
}
#ifdef ANYCONNECT_CLIENT_COMPAT
}
#endif
ret =
tls_printf(ws->session, "Content-Length: %u\r\n",
@@ -110,21 +131,6 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
if (ret < 0)
return -1;
#ifdef ANYCONNECT_CLIENT_COMPAT
if (ws->username[0] != 0) {
/* This is to make sure that some cisco clients that
* like to connect for each request, don't lose the
* username */
u = escape_url(ws->username, strlen(ws->username), NULL);
ret = tls_printf(ws->session, "Set-Cookie: ocuser=%s\r\n", u);
free(u);
if (ret < 0)
return -1;
}
#endif
ret = tls_puts(ws->session, "X-Transcend-Version: 1\r\n");
if (ret < 0)
return -1;
@@ -536,8 +542,6 @@ int read_user_pass(worker_st * ws, char *body, unsigned body_length,
char *p;
if (memmem(body, body_length, "<?xml", 5) != 0) {
oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", body_length,
body);
if (username != NULL) {
/* body should contain <username>test</username><password>test</password> */
@@ -683,25 +687,24 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
char tmp_user[MAX_USERNAME_SIZE];
char tmp_group[MAX_USERNAME_SIZE];
char msg[MAX_MSG_SIZE];
unsigned complete_auth = 0;
unsigned compact_auth = 0;
oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", (int)req->body_length,
req->body);
restart:
if (ws->auth_state == S_AUTH_INACTIVE) {
AuthInitMsg ireq = AUTH_INIT_MSG__INIT;
#ifdef ANYCONNECT_CLIENT_COMPAT
if (req->ocuser_cookie_set != 0) {
/* the client has provided the username in a different
* session and reconnected here to provide the password.
* So we read the username from the cookie, start auth
* and continue reading the password.
if (req->needs_compact_auth != 0) {
/* the client uses Connection: Close and needs to
* be asked the username and password in one go.
*/
complete_auth = 1;
ireq.user_name = ws->username;
ireq.tls_auth_ok = tls_has_session_cert(ws);
} else {
compact_auth = 1;
}
#endif
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
ret =
read_user_pass(ws, req->body, req->body_length,
@@ -736,10 +739,6 @@ restart:
ireq.cert_group_name = tmp_group;
}
#ifdef ANYCONNECT_CLIENT_COMPAT
}
#endif
ireq.hostname = req->hostname;
ret = send_msg_to_main(ws, AUTH_INIT,
@@ -799,7 +798,8 @@ restart:
ws->auth_state = S_AUTH_REQ;
#ifdef ANYCONNECT_CLIENT_COMPAT
if (complete_auth != 0) {
if (compact_auth != 0) {
compact_auth = 0; /* avoid infinite loop */
goto restart;
}
#endif

View File

@@ -42,6 +42,7 @@
#include <gettime.h>
#include <common.h>
#include <html.h>
#include <c-strcase.h>
#include <worker-bandwidth.h>
#include <vpn.h>
@@ -110,6 +111,8 @@ const static struct known_urls_st known_urls[] = {
LL("/profiles", get_config_handler, NULL),
LL("/+CSCOT+/translation-table", get_string_handler, NULL),
LL("/+CSCOT+/oem-customization", get_string_handler, NULL),
LL("/logout", get_empty_handler, NULL),
#endif
{NULL, 0, 0, NULL, NULL}
};
@@ -167,6 +170,7 @@ int url_cb(http_parser * parser, const char *at, size_t length)
}
#define STR_HDR_COOKIE "Cookie"
#define STR_HDR_CONNECTION "Connection"
#define STR_HDR_MS "X-DTLS-Master-Secret"
#define STR_HDR_CS "X-DTLS-CipherSuite"
#define STR_HDR_DMTU "X-DTLS-MTU"
@@ -186,6 +190,7 @@ static void value_check(struct worker_st *ws, struct http_req_st *req)
uint8_t *p;
char *token;
char *str;
char strtmp[16];
if (req->value.length <= 0)
return;
@@ -292,30 +297,22 @@ static void value_check(struct worker_st *ws, struct http_req_st *req)
case HEADER_DTLS_MTU:
req->dtls_mtu = atoi((char *)req->value.data);
break;
case HEADER_COOKIE:
case HEADER_CONNECTION:
length = req->value.length;
#ifdef ANYCONNECT_CLIENT_COMPAT
if (ws->username[0] == 0) {
p = memmem(req->value.data, length, "ocuser=", 7);
if (p != NULL) {
char *u;
if (length > sizeof(strtmp)-1)
break;
p += 7;
length -= 7;
u = unescape_url((char *)p, length, NULL);
if (u == NULL)
break;
memcpy(strtmp, req->value.data, length);
strtmp[length] = 0;
snprintf(ws->username, sizeof(ws->username),
"%s", u);
free(u);
req->ocuser_cookie_set = 1;
break;
}
if (c_strcasecmp(strtmp, "close") == 0) {
oclog(ws, LOG_INFO, "client needs compact auth");
req->needs_compact_auth = 1;
}
#endif
break;
case HEADER_COOKIE:
length = req->value.length;
p = memmem(req->value.data, length, "webvpn=", 7);
if (p == NULL || length <= 7) {
@@ -393,6 +390,10 @@ static void header_check(struct http_req_st *req)
strncmp((char *)req->header.data, STR_HDR_ATYPE,
req->header.length) == 0) {
req->next_header = HEADER_CSTP_ATYPE;
} else if (req->header.length == sizeof(STR_HDR_CONNECTION) - 1 &&
strncmp((char *)req->header.data, STR_HDR_CONNECTION,
req->header.length) == 0) {
req->next_header = HEADER_CONNECTION;
} else {
req->next_header = 0;
}

View File

@@ -50,6 +50,7 @@ enum {
HEADER_CSTP_ATYPE,
HEADER_DTLS_MTU,
HEADER_DTLS_CIPHERSUITE,
HEADER_CONNECTION,
};
enum {
@@ -76,7 +77,12 @@ struct http_req_st {
unsigned int next_header;
unsigned char cookie[COOKIE_SIZE];
unsigned int cookie_set;
unsigned int ocuser_cookie_set;
/* some CISCO clients reconnect for each request
* and is impossible to keep state for them. For
* that we ask username and password in one go for
* them.
*/
unsigned int needs_compact_auth;
unsigned char master_secret[TLS_MASTER_SIZE];
unsigned int master_secret_set;