Menu

[r1914]: / framework / trunk / cppcms / session_interface.h  Maximize  Restore  History

Download this file

408 lines (356 with data), 13.3 kB

  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
 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
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCMS_SESSION_INTERFACE_H
#define CPPCMS_SESSION_INTERFACE_H
#include <cppcms/defs.h>
#include <booster/noncopyable.h>
#include <booster/hold_ptr.h>
#include <booster/shared_ptr.h>
#include <cppcms/cstdint.h>
#include <cppcms/cppcms_error.h>
#include <cppcms/serialization_classes.h>
#include <string>
#include <map>
#include <memory>
#include <sstream>
#include <typeinfo>
namespace cppcms {
namespace http {
class context;
class request;
class response;
}
class session_api;
///
/// \brief This exception is thrown when CSRF attempt is suspected:
///
class CPPCMS_API request_forgery_error : public cppcms_error {
public:
/// Create an exception object
request_forgery_error() :
cppcms_error("Cross site request forgery detected")
{
}
};
///
/// \brief This class provides an access to an application for session management
///
/// Usually it is accessed via application::session member function.
///
/// Note, when the application is asynchronous, the sessions should be loaded manually as
/// fetching information from session may be not so cheap
///
/// Generally, session data is represented as a map of key-value strings that can be read
/// and written. All changes in session should be done before headers are written to the output
/// (before requesting an output stream from http::response object)
///
/// Each of the values in session may be also exposed to client as cookie. For example if
/// you want to disclose "foo" session key to the client side (Java Script) and session
/// cookie is cppcms_session=S231abc23c34ca242352a then a cookie with name
/// cppcms_session_foo will be created caring the value of this key.
///
/// Notes:
/// - Be careful with values you pass, cookies can carry quite a limited range of strings
/// so it is your responsibility to make sure that these values are actually legal.
/// - Of course the client side can alter these cookies but this would not have an effect
/// on the actual values fetched using session object. But still remember you should not
/// relay on cookies values on server side for obvious security reasons.
///
class CPPCMS_API session_interface : private booster::noncopyable {
public:
/// \cond INTERNAL
session_interface(http::context &);
~session_interface();
/// \endcond
///
/// Check if a \a key is set (assigned some value to it) in the session
///
bool is_set(std::string const &key);
///
/// Erase specific \a key from the session
///
void erase(std::string const &key);
///
/// Remove all keys from the session and delete the session at all. (i.e. empty session is automatically deleted)
///
void clear();
///
/// Returns true if specific \a key is exposed to client via cookies
///
bool is_exposed(std::string const &key);
///
/// Set exposition of the \a key to client side, if val is true the value will be exposed, otherwise hidden and cookie
/// will be deleted.
///
void expose(std::string const &key,bool val=true);
///
/// Disable exposition of a \a key. Same as expose(key,false);
///
void hide(std::string const &key);
///
/// Get the reference to a value for a \a key. Note if \a key is not exist, empty string is created in session object
/// and reference to it returned (similarly to std::map's operator[])
///
std::string &operator[](std::string const &key);
///
/// Set value \a v for a session key \a key
///
void set(std::string const &key,std::string const &v);
///
/// Get a value for a session \a key. If it is not set, throws cppcms_error. It is good idea to call is_set before
/// you call this function.
///
std::string get(std::string const &key);
///
/// Get a value for a session \a key. If it is not set, returns default_value
///
std::string get(std::string const &key,std::string const &default_value);
///
/// Get convert the value that is set for a key \a key to type T using std::iostream. For example you can
/// read a number using int n=session().get<int>("number").
///
/// - it throws cppcms_error if a key \a key not set/
/// - it throws std::bad_cast of the conversion using std::iostream fails
///
/// Note: the conversion is locale independent (uses C locale)
///
template<typename T>
T get(std::string const &key)
{
std::istringstream ss(get(key));
ss.imbue(std::locale::classic());
T value;
ss>>value;
if(ss.fail() || !ss.eof())
throw std::bad_cast();
return value;
}
///
/// Assign a \a value of type \a T to \a key converting it to string using std::iostream.
/// For example session().set("num",100);
/// Note: the conversion is locale independent (uses C locale)
///
template<typename T>
void set(std::string const &key,T const &value)
{
std::ostringstream ss;
ss.imbue(std::locale::classic());
ss<<value;
set(key,ss.str());
}
///
/// Serialize an \a object and store it under a \a key.
///
/// The serialization is done using cppcms::serialization_traits
///
template<typename Serializable>
void store_data(std::string const &key,Serializable const &object)
{
std::string buffer;
serialization_traits<Serializable>::save(object,buffer);
set(key,buffer);
}
///
/// Fetch an \a object under \a key from the session deserializing it.
///
/// The serialization is done using cppcms::serialization_traits
///
/// Throws cppcms_error if the key is not set, may throw archive_error if deserialization fails
/// (assuming that serialization uses cppcms::archive.
///
template<typename Serializable>
void fetch_data(std::string const &key,Serializable &object)
{
std::string buffer=get(key);
serialization_traits<Serializable>::load(buffer,object);
}
///
/// This enum defines the way session timeout is managed
///
enum {
fixed, ///< Once the session is created it will expire in age() second from the moment it created
renew, ///< Once the session expires in age() seconds of inactivity, once user sends an HTTP request again
///< it is renewed
browser ///< The session is kept as long as browser keeps it (does not get closed). In addition the "renew" expiration
///< policy is valid. So if user does not close his browser but is not active, it will expire in age() seconds.
};
///
/// Get the maximal age of the session in seconds
///
int age();
///
/// Set the maximal age of the session in seconds
///
void age(int t);
///
/// Reset the maximal age of the session to default (session.timeout settings value or 24 hours if not set)
///
void default_age();
///
/// Get the expiration policy of the session: renew, fixed or browser
///
int expiration();
///
/// Set the expiration policy of the session: renew, fixed or browser
///
void expiration(int h);
///
/// Reset the expiration policy to the default (session.expire settings value or browser if not set)
///
void default_expiration();
///
/// Set store on server side option for session. If srv is true then the session will be always stored on server
/// side and not in cookies only (required "server" or "both" type storage in session.location setting
///
/// Rationale: client side storage using encrypted or signed cookies is very efficient, however it lacks of one
/// important security feature: there is no other way to control their expiration but using timeout.
/// So user may just revert the cookie to the old state to get back in time and restore its own session.
///
/// So it is recommended to use server side storage in such critical cases, like soling captcha or playing a game
/// where you can't return to previous status when storing the data in the session object.
///
void on_server(bool srv);
///
/// Get on_server session property
///
bool on_server();
///
/// Set the cookie that represents the current session (the value of the cookie)
///
/// This function should be used only by user implementations of session storage
///
void set_session_cookie(std::string const &data);
///
/// Remove the cookie of the current session
///
/// This function should be used only by user implementations of session storage
///
void clear_session_cookie();
///
/// Get the value of the cookie that represents session on the client
///
/// This function should be used only by user implementations of session storage
///
std::string get_session_cookie();
///
/// Load the session, should be called one when dealing with sessions on asynchronous API where sessions
/// are not loaded by default. This function returns true if any data was loaded.
///
bool load();
///
/// Save the session data, generally should not be called as it is saved automatically. However when
/// writing asynchronous application and using custom slow storage devices like SQL it may be useful to control
/// when and how save() is called.
///
void save();
///
/// Returns true if the underlying session back-end uses blocking API so it is unsuitable to be called
/// from asynchronous event loop. This can be used to decide how to load session for specific connection.
///
/// If the API is blocking you probably should load and save session from thread pool rather then
/// from event loop when using asynchronous applications.
///
bool is_blocking();
///
/// When using session id based session - force generation of new session id to prevent session
/// fixation attacks
///
void reset_session();
///
/// Check that the CSRF token is the same as in the session object, it does not do any checks, whether
/// CSRF enabled or the request method is correct. It should be used for custom request handling (like
/// custom content types for RESTful services.
///
/// Returns true if the token is valid, otherwise returns false
///
bool validate_csrf_token(std::string const &str);
///
/// Check that there is no Cross Site Request Forgery Attempt.
///
/// If CSRF checks enabled it validates that there is a valid CSRF token is submitted via POST request
/// or via X-CSRF-Token header for AJAX requests.
///
/// \note it is checked for POST requests only.
///
void validate_request_origin();
///
/// Set CSRF validation mode.
///
/// If \a required \c is true then validate_request_origin() would throw \ref request_forgery_error
/// if the CSRF token is not valid.
///
/// Setting it to false would prevent from validate_request_origin() to do any checks.
///
/// \note The default is defined in the configuration property \c security.csrf.automatic. If
/// its value is not set the default is \c true
///
/// It is useful when some parts of the application do not require CSRF validation regardless
/// the status of sepecifc session owner
///
void request_origin_validation_is_required(bool required);
///
/// Get CSRF token that is stored in the session that can be used for validation
/// of the request origin
///
std::string get_csrf_token();
///
/// Get the cooke name that holds CSRF token. Note it can be used only if security.csrf.exposed
/// is set to true (which is not by default)
///
std::string get_csrf_token_cookie_name();
private:
friend class http::response;
friend class http::request;
struct entry;
typedef std::map<std::string,entry> data_type;
data_type data_,data_copy_;
http::context *context_;
// Cached defaults
int timeout_val_def_;
int how_def_;
// User Values
int timeout_val_;
int how_;
// Information from session data
time_t timeout_in_;
uint32_t new_session_ : 1;
uint32_t saved_ : 1;
uint32_t on_server_ : 1;
uint32_t loaded_ : 1;
uint32_t reset_ : 1;
uint32_t csrf_checked_ : 1;
uint32_t csrf_do_validation_ : 1;
uint32_t csrf_validation_ : 1;
uint32_t reserved_ : 24;
std::string temp_cookie_;
// storage itself
booster::shared_ptr<session_api> storage_;
struct _data;
booster::hold_ptr<_data> d; // for future use
int cookie_age();
time_t session_age();
void check();
void update_exposed(bool);
void set_session_cookie(int64_t age,std::string const &data,std::string const &key=std::string());
void save_data(std::map<std::string,entry> const &data,std::string &s);
void load_data(std::map<std::string,entry> &data,std::string const &s);
std::string generate_csrf_token();
};
} // cppcms
#endif
MongoDB Logo MongoDB