Skip to content

Commit

Permalink
Fix 503 error if originurl has a query string
Browse files Browse the repository at this point in the history
Define separator for preauth query string
Fix status page with preauth
Update demo/example script
Various tidyups

Signed-off-by: Rob White <rob@blue-wave.net>
  • Loading branch information
bluewavenet committed Dec 5, 2018
1 parent afb385f commit 1656b4e
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 22 deletions.
52 changes: 41 additions & 11 deletions forward_authentication_service/PreAuth/demo-preauth.sh
Expand Up @@ -34,29 +34,59 @@ query=$(printf "${query_enc//%/\\x}")
#
# In a similar manner we can obtain any client or NDS information that ndsctl provides.

# The query string NDS sends to us will always be of the following form:
# ?clientip=[clientipaddress]&gatewayname=[gatewayname]&redir=[originalurl]&var4=[data]&var5=[data]&var6......
# The query string NDS sends to us will always be of the following form (with a "comma space" separator):
# ?clientip=[clientipaddress], gatewayname=[gatewayname], redir=[originalurl], var4=[data], var5=[data], var6......
#
# The first three variables will be clientip, gatewayname and redir
#
# We have chosen to name redir as $requested here as it is actually the originally requested url.
#
# There is one exception to this. If the client presses "back" on their browser NDS detects this
# and tells us by returning &status=authenticated instead of &redir=[originalurl]
# and tells us by returning status=authenticated instead of redir=[originalurl]
# If we detect this we show a page telling the client they are already logged in.
#
# Additional variables returned by NDS will be those we define here and send to NDS via an
# html form method=get
# See the examples here for $username and $emailaddress
#
# There is no limit to the number of variables we can define dynamically
# as long as the query string does not exceed 2048 bytes.
#
# The query string will be truncated if it does exceed this length.


# Parse for the system variables always sent by NDS:
clientip="$(echo $query | awk -F ', ' '{print $1;}' | awk -F 'clientip=' '{print $2;}')"
gatewayname="$(echo $query | awk -F ', ' '{print $2;}' | awk -F 'gatewayname=' '{print $2;}')"
# The third system variable is either:
requested="$(echo $query | awk -F ', ' '{print $3;}' | awk -F 'redir=' '{print $2;}')"
# or:
status="$(echo $query | awk -F ', ' '{print $3;}' | awk -F 'status=' '{print $2;}')"

# Parse for additional variables we define in this script
username="$(echo $query | awk -F ', ' '{print $4;}' | awk -F 'username=' '{print $2;}')"
emailaddr="$(echo $query | awk -F ', ' '{print $5;}' | awk -F 'emailaddr=' '{print $2;}')"

# parse for what we are looking for in this example:
clientip="$(echo $query | awk -F '&' '{print $1;}' | awk -F '=' '{print $2;}')"
gatewayname="$(echo $query | awk -F '&' '{print $2;}' | awk -F '=' '{print $2;}')"
requested="$(echo $query | awk -F '&' '{print $3;}' | awk -F '=' '{print $2;}')"
username="$(echo $query | awk -F '&' '{print $4;}' | awk -F '=' '{print $2;}')"
emailaddr="$(echo $query | awk -F '&' '{print $5;}' | awk -F '=' '{print $2;}')"

# Define some common html as the first part of the page to be served by NDS
#
# Note this example uses the default splash.css provided by NDS and uses splash.jpg
# as the browser shortcut icon. You can decide how your PreAuth splash page will look
# as the browser shortcut icon.
#
# You can decide how your PreAuth splash page will look
# by incorporating your own css and images.
#
# Note however that the output of this script will be displayed on the client device screen via the CPD process on that device.
# It should be noted when designing a custom splash page that for security reasons many client device CPD implementations:
#
# Immediately close the browser when the client has authenticated.
# Prohibit the use of href links.
# Prohibit downloading of external files (including .css and .js, even if they are allowed in NDS firewall settings).
# Prohibit the execution of javascript.
#



header="
<!DOCTYPE html>\n
<html>
Expand Down Expand Up @@ -92,7 +122,7 @@ echo -e $header

# Check if the client is already logged in and has tapped "back" on their browser
# Make this a friendly message explaining they are good to go
if [ $requested == "authenticated" ]; then
if [ $status == "authenticated" ]; then
echo "<p><big-red>You are already logged in and have access to the Internet.</big-red></p>"
echo "<hr>"
echo "<p><italic-black>You can use your Browser, Email and other network Apps as you normally would.</italic-black></p>"
Expand Down
5 changes: 4 additions & 1 deletion src/common.h
Expand Up @@ -30,7 +30,10 @@
#define MAX_BUF 4096

/* Max length of a query string in bytes */
#define QUERYMAXLEN 1024
#define QUERYMAXLEN 2048

/* Separator for Preauth query string */
#define QUERYSEPARATOR ", "

/* Max dynamic html page size in bytes */
#define HTMLMAXSIZE 4096
Expand Down
35 changes: 25 additions & 10 deletions src/http_microhttpd.c
Expand Up @@ -67,7 +67,7 @@ static int send_redirect_temp(struct MHD_Connection *connection, const char *url
static int send_refresh(struct MHD_Connection *connection);
static int is_foreign_hosts(struct MHD_Connection *connection, const char *host);
static int is_splashpage(const char *host, const char *url);
static int get_query(struct MHD_Connection *connection, char **collect_query);
static int get_query(struct MHD_Connection *connection, char **collect_query, const char *separator);
static const char *get_redirect_url(struct MHD_Connection *connection);
static const char *lookup_mimetype(const char *filename);

Expand Down Expand Up @@ -513,12 +513,18 @@ static int authenticated(struct MHD_Connection *connection,
}

if (check_authdir_match(url, config->authdir)) {
if (config->fas_port) {
if (config->fas_port && !config->preauth) {
safe_asprintf(&fasurl, "http://%s:%u%s?clientip=%s&gatewayname=%s&status=authenticated",
config->fas_remoteip, config->fas_port, config->fas_path, client->ip, config->gw_name);
ret = send_redirect_temp(connection, fasurl);
free(fasurl);
return ret;
} else if (config->fas_port && config->preauth) {
safe_asprintf(&fasurl, "?clientip=%s%sgatewayname=%s%sstatus=authenticated",
client->ip, QUERYSEPARATOR, config->gw_name, QUERYSEPARATOR);
ret = show_preauthpage(connection, fasurl);
free(fasurl);
return ret;
} else {
return show_statuspage(connection, client);
}
Expand Down Expand Up @@ -608,9 +614,10 @@ static int preauthenticated(struct MHD_Connection *connection,

debug(LOG_DEBUG, "preauthdir url detected: %s", url);

get_query(connection, &query);
get_query(connection, &query, QUERYSEPARATOR);

ret = show_preauthpage(connection, query);
free(query);
return ret;
}

Expand Down Expand Up @@ -664,13 +671,12 @@ static int preauthenticated(struct MHD_Connection *connection,
static int encode_and_redirect_to_splashpage(struct MHD_Connection *connection, const char *originurl, const char *querystr)
{
char *splashpageurl = NULL;
char encoded[2048];
char encoded[QUERYMAXLEN] = {0};
s_config *config;
int ret;

config = config_get_config();

memset(encoded, 0, sizeof(encoded));
if (originurl) {
if (uh_urlencode(encoded, sizeof(encoded), originurl, strlen(originurl)) == -1) {
debug(LOG_WARNING, "could not encode url");
Expand Down Expand Up @@ -713,23 +719,30 @@ static int encode_and_redirect_to_splashpage(struct MHD_Connection *connection,
static int redirect_to_splashpage(struct MHD_Connection *connection, t_client *client, const char *host, const char *url)
{
char *originurl = NULL;
char *query = NULL;
char query_str[QUERYMAXLEN] = {0};
char *query = query_str;
int ret = 0;
const char *separator = "&";
char *querystr = NULL;
s_config *config = config_get_config();

get_query(connection, &query);
get_query(connection, &query, separator);
if (!query) {
debug(LOG_DEBUG, "Unable to get query string - error 503");
/* no mem */
free(query);
return send_error(connection, 503);
}

debug(LOG_DEBUG, "Query string is [ %s ]", query);

if (config->fas_secure_enabled != 1) {
safe_asprintf(&querystr, "?clientip=%s&gatewayname=%s&tok=%s", client->ip, config->gw_name, client->token);
} else {
safe_asprintf(&querystr, "?clientip=%s&gatewayname=%s", client->ip, config->gw_name);
}
safe_asprintf(&originurl, "http://%s%s%s%s", host, url, strlen(query) ? "?" : "" , query);

safe_asprintf(&originurl, "http://%s%s%s", host, url, query);
ret = encode_and_redirect_to_splashpage(connection, originurl, querystr);
free(originurl);
free(querystr);
Expand Down Expand Up @@ -794,7 +807,7 @@ static const char *get_redirect_url(struct MHD_Connection *connection)
}

/* save the query or empty string into **query.*/
static int get_query(struct MHD_Connection *connection, char **query)
static int get_query(struct MHD_Connection *connection, char **query, const char *separator)
{
int element_counter;
char **elements;
Expand All @@ -804,6 +817,8 @@ static int get_query(struct MHD_Connection *connection, char **query)
int j;
int length = 0;

debug(LOG_DEBUG, " Separator is [%s].", separator);

element_counter = MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, counter_iterator, NULL);
if (element_counter == 0) {
*query = safe_strdup("");
Expand Down Expand Up @@ -847,7 +862,7 @@ static int get_query(struct MHD_Connection *connection, char **query)
strcpy(query_str, "?");
} else {
if (QUERYMAXLEN - strlen(query_str) > length - j + 1) {
strncat(query_str, "&", QUERYMAXLEN - strlen(query_str));
strncat(query_str, separator, QUERYMAXLEN - strlen(query_str));
}
}

Expand Down

0 comments on commit 1656b4e

Please sign in to comment.