CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
session_token.cc
Go to the documentation of this file.
1 
7 #include "session_token.h"
8 
9 #include <limits>
10 
11 #include "crypto/encrypt.h"
12 #include "json.h"
13 #include "json_document.h"
14 #include "util/logging.h"
15 #include "util/platform.h"
16 #include "util/pointer.h"
17 #include "util/string.h"
18 
19 namespace receiver {
20 
30 bool GenerateSessionToken(const std::string &key_id, const std::string &path,
31  uint64_t max_lease_time, std::string *session_token,
32  std::string *public_token_id,
33  std::string *token_secret) {
34  if (session_token == NULL || public_token_id == NULL
35  || token_secret == NULL) {
36  return false;
37  }
38 
39  if (key_id.empty() && path.empty()) {
40  return false;
41  }
42 
44  if (!secret.IsValid()) {
45  return false;
46  }
47 
48  const UniquePtr<cipher::Cipher> cipher(
50  if (!cipher.IsValid()) {
51  return false;
52  }
53 
54  *public_token_id = key_id + path;
55  *token_secret = secret->ToBase64();
56 
57  const uint64_t current_time = platform_monotonic_time();
58  if (std::numeric_limits<uint64_t>::max() - max_lease_time < current_time) {
59  return false;
60  }
61 
62  const std::string expiry(StringifyUint(current_time + max_lease_time));
63 
64  std::string encrypted_body;
65  if (!cipher->Encrypt(
66  "{\"path\" : \"" + path + "\", \"expiry\" : \"" + expiry + "\"}",
67  *secret, &encrypted_body)) {
68  return false;
69  }
70 
71  *session_token = Base64("{\"token_id\" : \"" + *public_token_id
72  + "\", \"blob\" : \"" + Base64(encrypted_body)
73  + "\"}");
74 
75  return true;
76 }
77 
82 bool GetTokenPublicId(const std::string &token, std::string *public_id) {
83  if (public_id == NULL) {
84  return false;
85  }
86 
87  std::string debased64_token;
88  if (!Debase64(token, &debased64_token)) {
89  return false;
90  }
91 
92  const UniquePtr<JsonDocument> token_json(
93  JsonDocument::Create(debased64_token));
94  if (!token_json.IsValid()) {
95  return false;
96  }
97 
98  const JSON *token_id = JsonDocument::SearchInObject(token_json->root(),
99  "token_id", JSON_STRING);
100  const JSON *blob = JsonDocument::SearchInObject(token_json->root(), "blob",
101  JSON_STRING);
102 
103  if (token_id == NULL || blob == NULL) {
104  return false;
105  }
106 
107  *public_id = token_id->string_value;
108 
109  return true;
110 }
111 
112 /*
113  * Check the validity of a session token using the associated secret
114  */
115 TokenCheckResult CheckToken(const std::string &token, const std::string &secret,
116  std::string *lease_path) {
117  if (!lease_path) {
118  return kInvalid;
119  }
120 
121  std::string debased64_token;
122  if (!Debase64(token, &debased64_token)) {
123  return kInvalid;
124  }
125 
126  const UniquePtr<JsonDocument> token_json(
127  JsonDocument::Create(debased64_token));
128  if (!token_json.IsValid()) {
129  return kInvalid;
130  }
131 
132  const JSON *token_id = JsonDocument::SearchInObject(token_json->root(),
133  "token_id", JSON_STRING);
134  const JSON *blob = JsonDocument::SearchInObject(token_json->root(), "blob",
135  JSON_STRING);
136  if (token_id == NULL || blob == NULL) {
137  return kInvalid;
138  }
139 
140  std::string debased64_secret;
141  if (!Debase64(secret, &debased64_secret)) {
142  return kInvalid;
143  }
144  const UniquePtr<cipher::Key> key(
145  cipher::Key::CreateFromString(debased64_secret));
146  if (!key.IsValid()) {
147  return kInvalid;
148  }
149 
150  std::string encrypted_body;
151  if (!Debase64(blob->string_value, &encrypted_body)) {
152  return kInvalid;
153  }
154 
155  std::string body;
156  if (!cipher::Cipher::Decrypt(encrypted_body, *key, &body)) {
157  return kInvalid;
158  }
159 
160  const UniquePtr<JsonDocument> body_json(JsonDocument::Create(body));
161  if (!token_json.IsValid()) {
162  return kInvalid;
163  }
164 
165  const JSON *path = JsonDocument::SearchInObject(body_json->root(), "path",
166  JSON_STRING);
167  const JSON *expiry = JsonDocument::SearchInObject(body_json->root(), "expiry",
168  JSON_STRING);
169  if (path == NULL || expiry == NULL) {
170  return kInvalid;
171  }
172 
173  // TODO(radu): can we still use monotonic time if the process restarts?
174  const uint64_t expiry_time = String2Uint64(expiry->string_value);
175  const uint64_t current_time = platform_monotonic_time();
176  if (current_time > expiry_time) {
177  return kExpired;
178  }
179 
180  *lease_path = path->string_value;
181 
182  return kValid;
183 }
184 
185 } // namespace receiver
static bool Decrypt(const std::string &ciphertext, const Key &key, std::string *plaintext)
Definition: encrypt.cc:186
static JSON * SearchInObject(const JSON *json_object, const std::string &name, const json_type type)
static Cipher * Create(const Algorithms a)
Definition: encrypt.cc:157
std::string ToBase64() const
Definition: encrypt.cc:109
bool GenerateSessionToken(const std::string &key_id, const std::string &path, uint64_t max_lease_time, std::string *session_token, std::string *public_token_id, std::string *token_secret)
static Key * CreateRandomly(const unsigned size)
Definition: encrypt.cc:32
std::string StringifyUint(const uint64_t value)
Definition: string.cc:83
bool Debase64(const string &data, string *decoded)
Definition: string.cc:598
static JsonDocument * Create(const std::string &text)
uint64_t platform_monotonic_time()
bool GetTokenPublicId(const std::string &token, std::string *public_id)
TokenCheckResult CheckToken(const std::string &token, const std::string &secret, std::string *lease_path)
string Base64(const string &data)
Definition: string.cc:537
bool Encrypt(const std::string &plaintext, const Key &key, std::string *ciphertext)
Definition: encrypt.cc:170
uint64_t String2Uint64(const string &value)
Definition: string.cc:240
static Key * CreateFromString(const std::string &key)
Definition: encrypt.cc:77
struct json_value JSON
Definition: helper_allow.cc:11
const JSON * root() const
Definition: json_document.h:25