Skip to content

Commit

Permalink
Print SAML authentication URL for user convenience
Browse files Browse the repository at this point in the history
  • Loading branch information
Rainer-Keller committed Oct 10, 2024
1 parent 8d7d836 commit 4de2220
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 25 deletions.
6 changes: 3 additions & 3 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,8 @@ int load_config(struct vpn_config *cfg, const char *filename)

if (port < 1 || port > 65535) {
log_error("Bad SAML listen port: \"%s\".\n", val);
goto err_free;
}
goto err_free;
}
cfg->saml_port = (uint16_t)port;
} else if (strcmp(key, "user-key") == 0) {
free(cfg->user_key);
Expand Down Expand Up @@ -544,7 +544,7 @@ void merge_config(struct vpn_config *dst, struct vpn_config *src)
free(dst->cookie);
dst->cookie = src->cookie;
}
if(src->saml_port != 0){
if(src->saml_port != 0) {
dst->saml_port = src->saml_port;
}
if (src->pinentry) {
Expand Down
2 changes: 1 addition & 1 deletion src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
* @param[out] dest the buffer to write the URL-encoded string
* @param[in] str the input string to be escaped
*/
static void url_encode(char *dest, const char *str)
void url_encode(char *dest, const char *str)
{
while (*str != '\0') {
if (isalnum(*str) || *str == '-' || *str == '_' ||
Expand Down
10 changes: 10 additions & 0 deletions src/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@
#define ERR_HTTP_PERMISSION -6
#define ERR_HTTP_NO_COOKIE -7

/*
* URL-encodes a string for HTTP requests.
*
* The dest buffer size MUST be at least strlen(str) * 3 + 1.
*
* @param[out] dest the buffer to write the URL-encoded string
* @param[in] str the input string to be escaped
*/
void url_encode(char *dest, const char *str);

static inline const char *err_http_str(int code)
{
if (code > 0)
Expand Down
67 changes: 46 additions & 21 deletions src/http_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,31 @@
#include "config.h"
#include "log.h"
#include "tunnel.h"
#include "http.h" // for url_encode

static void print_url(const struct vpn_config *cfg) {
char *encoded_realm = NULL;
char realm[] = "&realm=";
char *empty_string = "\0";

// Desired string is https://company.com:port/remote/saml/start?redirect=1(&realm=<str>)
// with the realm being optional
static const char *uri_pattern = "https://%s:%d/remote/saml/start?redirect=1%s%s";

if (cfg->realm[0] != '\0') {
encoded_realm = alloca(strlen(cfg->realm) * 3 + 1); // url_encode required three times the size
url_encode(encoded_realm, cfg->realm);
} else {
encoded_realm = empty_string;
realm[0] = 0; // Make realm appear empty when printing as string
}

int required_size = 1 + snprintf(NULL, 0, uri_pattern, cfg->gateway_host, cfg->gateway_port, realm, encoded_realm);
char *url = alloca(required_size);
snprintf(url, required_size, uri_pattern, cfg->gateway_host, cfg->gateway_port, realm, encoded_realm);

log_info("Authenticate at '%s'\n", url);
}

// Convenience function to send a response with a user readable status message and the
// request URL shown for debug purposes.
Expand Down Expand Up @@ -59,19 +84,19 @@ static int process_request(int new_socket, char *id) {
}

// Extract the id
static const char *token_delimiter = " &\r\n";
char *next_token = request + strlen(request_head); // strsep does modify the input argument and we don't want to loose our request pointer.
char *id_start = strsep(&next_token, token_delimiter);

if (next_token == NULL) {
// In case not found, nextToken was set to NULL
// This should be invalid because we expext \r\n at the end of the GET request line
log_error("Bad request format\n");
send_status_response(new_socket, "Invalid formatting of Fortinet server redirect response. VPN could not be established.");
return -1;
}

// strsep inserted a NULL at the location of the delimiter.
static const char *token_delimiter = " &\r\n";
char *next_token = request + strlen(request_head); // strsep does modify the input argument and we don't want to loose our request pointer.
char *id_start = strsep(&next_token, token_delimiter);

if (next_token == NULL) {
// In case not found, next_token was set to NULL
// This should be invalid because we expect \r\n at the end of the GET request line
log_error("Bad request format\n");
send_status_response(new_socket, "Invalid formatting of Fortinet server redirect response. VPN could not be established.");
return -1;
}

// strsep inserted a NULL at the location of the delimiter.
int id_length = strlen(id_start);

if(id_length == 0 || id_length >= MAX_SAML_SESSION_ID_LENGTH) {
Expand All @@ -80,7 +105,7 @@ static int process_request(int new_socket, char *id) {
return -1;
}

// It was checked above, that the length is smaller than MAX_SAML_SESSION_ID_LENGTH
// It was checked above, that the length is smaller than MAX_SAML_SESSION_ID_LENGTH
strcpy(id, id_start);

for (int i = 0; i < id_length; i++) {
Expand All @@ -92,16 +117,16 @@ static int process_request(int new_socket, char *id) {

log_info("Extracted id: %s\n", id);
send_status_response(new_socket,
"SAML session id received from Fortinet server. VPN will be established..."
"\r\nYou can close this browser tab now.");
"SAML session id received from Fortinet server. VPN will be established..."
"\r\nYou may close this browser tab now.");
return 0;
}

/**
* Run a http server to listen for SAML login requests
*
* @return 0 in case of success
* < 0 in case of error
* < 0 in case of error
*/
int wait_for_http_request(struct vpn_config *config) {
int server_fd, new_socket;
Expand Down Expand Up @@ -130,7 +155,7 @@ int wait_for_http_request(struct vpn_config *config) {
// Forcefully attaching socket to the port
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
close(server_fd);
log_error("Failed to bind socket to port %d \n", saml_port);
log_error("Failed to bind socket to port %d\n", saml_port);
return -1;
}

Expand All @@ -144,16 +169,16 @@ int wait_for_http_request(struct vpn_config *config) {
fd_set readfds;
struct timeval tv;

log_info("Listening for SAML login on port %d.\n", saml_port);
log_info("Listening for SAML login on port %d\n", saml_port);
print_url(config);

while(max_tries > 0) {
--max_tries;
FD_ZERO(&readfds);
FD_SET(server_fd, &readfds);
// Wait up to ten seconds
tv.tv_sec = 10;
tv.tv_usec = 0;
tv.tv_sec = 10;
tv.tv_usec = 0;

int retval = select(server_fd + 1, &readfds, NULL, NULL, &tv);

Expand Down

0 comments on commit 4de2220

Please sign in to comment.