ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

469 lines
14 KiB

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