Genivia - The Sessions Plugin

|  | Home | Documentation | The Sessions Plugin updated Wed Aug 17 2016 |

- Main Page
- Related Pages
- Classes
- Files

The Sessions Plugin

# HTTP Server Session Management Plugin

By Chris Moutsos and Robert van Engelen.

# Overview

The HTTP server session management plugin for gSOAP enables servers to store a database of sessions to keep track of client data across multiple requests. Client data is stored per session as name and value pairs that can be set to any valid string. Sessions are tracked with unique session IDs (sometimes called tokens) that are passed between the server and client with HTTP cookies.

The sessions plugin is MT safe.

# Features

- Stores sessions identified by random 128-bit session IDs managed with HTTP cookies
- Session validity can be restricted based on domain and path
- Each session stores a list of session variables (name/value string pairs)
- Can easily create, modify, delete, and retrieve session variables
- Configurable settings
  - Rolling sessions (re-set session ID cookie with every response)
  - Session ID cookie `Max-Age` and `Expire` attribute values
  - Maximum stale time before a session expires server-side
  - Time interval between purging expired sessions
  - Max number of sessions allowed in database
- Thread-safe
- Can be used with C or C++ projects

# Setup

To set up the sessions plugin on the server-side:

1. Make sure to compile your program with plugin/sessions.c and plugin/threads.c.
2. Enable cookies by compiling all gSOAP source code with `-DWITH_COOKIES`. Cookies are required for tracking session IDs.
3. Enable HTTPS (compile with `-DWITH_OPENSSL` or `-DWITH_GNUTLS` or link with `-lgsoapssl`/`-lgsoapssl++`).

Note
  While it is not a requirement to use HTTPS with this plugin, it is strongly recommended to use HTTPS. This is because the session ID cookies can be intercepted if not encrypted with SSL/TLS. Cookies are automatically sent with the Secure flag enabled when SSL is enabled. The HttpOnly flag is automatically enabled for all cookies in order to prevent XSS attacks.

# Basic Usage

Client-side usage is automatic, provided that the client supports cookies and the server has properly configured the plugin. If the client is a gSOAP application, make sure to compile with `-DWITH_COOKIES`.

For server-side usage, register the plugin with:

#include "plugin/sessions.h"
struct soap *soap = soap_new();
soap_register_plugin(soap, sessions);

If you are using a server object in C++ generated with soappcpp2 option `-j`:

#include "plugin/sessions.h"
soap_register_plugin(server.soap, sessions);

For brevity, the `struct soap*` version will be used below. Replace `soap` with your server object's `soap` member if necessary.

Start a new session with:

struct soap_session *session = soap_start_session(soap, "domain", "path");

This creates a new session with a random 128-bit session ID and the default settings (see section: Settings). If the client already has a session ID cookie with name `SESSION_COOKIE_NAME` and the given `domain` and `path`, and that ID refers to a valid session, that existing session will be returned instead.

Note
  For all of the sessions plugin function calls, `domain` and `path` arguments are required. These must match the values that were given when the session was created, otherwise the client's session ID cookie won't be found. The `domain` and `path` arguments may be set to `NULL` to use the current values given by the `soap` context's `cookie_domain` and `cookie_path` members:

  Attribute | Value
  --- | ---
  `const char *cookie_domain` | MUST be set to the domain (host) of the service
  `const char *cookie_path` | MAY be set to the default path to the service (defaults to '`/`')

  These rules also apply to the cookies used for tracking session IDs. See the gSOAP User Guide for more information on how gSOAP handles cookies.

For example, to create a session on localhost:8080 that is valid on any path:

soap->cookie_domain = "localhost:8080";
struct soap_session *session = soap_start_session(soap, NULL, NULL);

To create a new session variable or modify an existing session variable inside that session:

soap_set_session_var(soap, "session_var_name", "session_var_value", NULL, NULL);

To access the value of that session variable:

const char *value = soap_get_session_var(soap, "session_var_name", NULL, NULL);

To delete that session variable:

soap_clr_session_var(soap, "session_var_name", NULL, NULL);

Consider changing the session's `rolling`, `cookie_maxage`, `max_inactive_secs` settings from their defaults. Read more about these in the Settings section.

# Simple Calculator Server (C) Example

We will show how to extend the simple calculator server example (in C) to keep track of the client's last calculated value with a session variable.

Make sure to register the plugin and set the default `domain` and `path`. After calling `soap_destroy` and `soap_end`, we should also free the internal cookie database (or call `soap_done`):

#include "plugin/session.h"
...
struct soap soap;
soap_init(&soap);
soap_register_plugin(&soap, sessions);
soap.cookie_domain = "localhost:8080";
soap.cookie_path = "/";
... // set up the service and serve requests
soap_destroy(&soap);
soap_end(&soap);
soap_free_cookies(&soap);

Now in each of our calculator service operations (`ns__add`, `ns__sub`, etc.), we can update the `lastCalculation` session variable in our current session:

int ns__add(struct soap *soap, double a, double b, double *result)
{
(void)soap; *result = a + b;
// make sure we have a session
if (!soap_get_session(soap, NULL, NULL))
{
// no current session, create a new one
if (!soap_start_session(soap, NULL, NULL))
return SOAP_ERR; // session creation failed
// configure session settings
soap_set_session_rolling(soap, 1, NULL, NULL);
soap_set_session_cookie_maxage(soap, 30, NULL, NULL);
soap_set_session_max_inactive_secs(soap, 30, NULL, NULL);
}
// update `lastCalculation` session variable
char calculation[80];
sprintf(calculation, "add %f %f, result = %f", a, b, *result);
soap_set_session_var(soap, "lastCalculation", calculation, NULL, NULL);
return SOAP_OK;
}

If we want to allow the client to access their last calculation, add another service operation to retrieve the `lastCalculation` session variable:

int ns__getLastCalculation(struct soap *soap, char **r)
{
const char *lastCalculation = soap_get_session_var(soap, "lastCalculation", NULL, NULL);
if (!lastCalculation)
lastCalculation = "None";
if ((*r = (char*)soap_malloc(soap, strlen(lastCalculation)+1)))
strcpy(*r, lastCalculation);
return SOAP_OK;
}

# Sessions Plugin API

This section describes the Sessions Plugin API.

Note
  The term session ID cookie refers to a cookie with the name `SESSION_COOKIE_NAME` (see section: Settings), the given `domain` and `path` (see section: Basic Usage), and a random 128-bit session ID as the value. The term current session refers to the session in the database identified by the client's session ID cookie.
  The arguments `domain` and `path` may be set to `NULL` to use the current values given by `soap->cookie_domain` and `soap->cookie_path` (see section: Basic Usage).

The sessions plugin provides the following API for server-side session management:

Session Plugin Function Description
struct soap_session* soap_start_session(struct soap * soap, const char *domain, const char *path); Create a session in the database and a session ID cookie. Behaves the same as `soap_get_session` if the client already has a valid session ID cookie. Returns pointer to the session node, or `NULL` if the session could not be created.
struct soap_session* soap_get_session(struct soap *soap, const char *domain, const char *path); Get the current session. Can be used as a 'touch'. Returns pointer to the session node, or `NULL` if the session is not found or is expired.
int soap_get_num_sessions(struct soap *soap, const char *domain, const char *path); Get the number of sessions in the database. Returns `-1` if the session is not found or is expired.
struct soap_session* soap_regenerate_session_id(struct soap * soap, const char *domain, const char *path); Create a new session ID for the current session and update the session ID cookie. Returns pointer to the session node, or `NULL` if the session is not found or is expired.
int soap_get_num_session_vars(struct soap *soap, const char *domain, const char *path); Get the number of session variables in the current session. Returns `-1` if the session is not found or is expired.
void soap_end_session(struct soap *soap, const char * domain, const char *path); Delete the current session from the database and clear the client's session ID cookie.
void soap_end_sessions(struct soap *soap, const char * domain, const char *path); Delete all sessions in the database and clear the current session ID cookie.
struct soap_session_var* soap_set_session_var(struct soap * soap, const char *name, const char *value, const char domain, const char *path); Set a session variable with the given `name` and `value` in the current session, overwring any old `value`. Returns pointer to the session variable node, or `NULL` if the session is not found or is expired.
const char* soap_get_session_var(struct soap *soap, const char *name, const char *domain, const char *path); Get the `value` of the session variable with the given `name` in the current session. Returns `NULL` if the session is not found or is expired.
void soap_clr_session_var(struct soap *soap, const char *name, const char *domain, const char *path); Delete the session variable with the given `name` in the current session.
void soap_clr_session_vars(struct soap *soap, const char *domain, const char *path); Delete all session variables in the current session.

For managing session settings (see section: Settings), the following API is provided:

Session Plugin Function Description (Settings / Misc.)
int soap_set_session_rolling(struct soap * soap, int rolling, const char *domain, const char * path); Set the `rolling` setting for the current session. Zero (non-rolling) means the session ID cookie is only set when the session is first created. Non-zero (rolling) means the session ID cookie will be re-set on every response. If successful, returns SOAP_OK, or SOAP_ERR otherwise.
int soap_get_session_rolling(struct soap * soap, const char *domain, const char *path); Get the `rolling` setting for the current session. Returns `-1` if the session is not found or is expired.
int soap_set_session_cookie_maxage(struct soap * soap, long maxage, const char *domain, const char * path); Set the `cookie_maxage` member for the current session. This will be used to set the session ID cookie's `Max-Age` and `Expires` attributes. `-1` means the cookie will have no `Max-Age` or `Expires` attributes. If successful, returns SOAP_OK, or SOAP_ERR otherwise.
long soap_get_session_cookie_maxage(struct soap * soap, const char *domain, const char *path); Get the `cookie_maxage` member for the current session. Returns `0` if the session is not found or is expired.
int soap_set_session_max_inactive_secs(struct soap * soap, long max, const char *domain, const char * path); Set the `max_inactive_secs` member for the current session. This is the maximum amount of stale time in seconds before a session is marked as expired (to be purged) on the server-side. `-1` means the session will never expire. If successful, returns SOAP_OK, or SOAP_ERR otherwise.
long soap_get_session_max_inactive_secs(struct soap * soap, const char *domain, const char *path); Get the `max_inactive_secs` member for the current session. Returns `0` if the session is not found or is expired.
struct soap_session* soap_get_sessions_head(); Get `soap_sessions`, the first node in the sessions linked list. Not necessary unless low-level list management is needed (see section: The Internals).

# Settings

In `plugins/session.h`, the following constants are defined:

Name | Default | Description
--- | --- | ---
`SESSION_COOKIE_NAME` | `"GSOAP_SESSIONID"` | The name to use for session ID cookies.
`SESSION_MAX` | `8192` | The max number of sessions allowed in the database. Any attempt to create more sessions than this will fail.
`SESSIONS_DEFAULT_MAX_INACTIVE_SECS` | `300` | The default time in seconds for sessions' `max_inactive_secs` member. `-1` means the session will never expire server-side.
`SESSION_PURGE_INTERVAL` | `300` | On every session database access, the time since the last database purge is checked. If it's been longer than this interval (in seconds), any expired sessions will be purged with `soap_purge_sessions()`. `0` means a purge will occcur on every database access. `-1` means a purge will never occur.

Set these values to whatever makes sense for your application.

In each session node, the following settings are declared:

Name | Default | Description
--- | --- | ---
`rolling` | `0` | Non-rolling (`0`) means the session ID cookie is only set when the session is first created. Rolling (non-`0`) means the session ID cookie will be re-set on every response after any part of the session has been touched.
`cookie_maxage` | `-1` | This will be used to set the session ID cookie's `Max-Age` and `Expires` attributes. `-1` means the cookie will have no `Max-Age` or `Expires` attributes.
`max_inactive_secs` | `SESSIONS_DEFAULT_MAX_INACTIVE_SECS` | This is the maximum amount of stale time in seconds before a session is marked as expired (to be purged) on the server-side. `-1` means the session will never expire server-side. This should probably be set equal to `cookie_maxage` unless that value is `-1`.

Note
  These settings should not be changed directly. See the Sessions Plugin API section for functions to manage these settings.

# The Internals

The session database is stored as a linked list pointed to by `soap_sessions` (accessible by calling `soap_get_sessions_head()`). Session nodes are of type `struct soap_session` and are declared as:

struct soap_session
{
struct soap_session *next;
const char *id;
struct soap_session_var *session_vars;
struct soap_session_var *session_vars_tail;
int num_session_vars; // the total number of session_vars we have in this session
long cookie_maxage; // client time in seconds before the cookie expires (-1 for session cookie)
int rolling; // whether or not we should set the cookie's maxage on every response
time_t last_touched; // time that we last touched this session or its vars
long max_inactive_secs; // server time in seconds before inactive session expires (-1 to never expire)
// this should usually be at least as high as cookie_maxage
};

The `session_vars` member is a pointer to the session's linked list of session variables. Session variable nodes are of type `struct soap_session_var` and are declared as:

struct soap_session_var
{
struct soap_session_var *next;
const char *name;
const char *value;
};