Cutelyst  2.13.0
authentication.cpp
1 /*
2  * Copyright (C) 2013-2018 Daniel Nicoletti <dantti12@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #include "authentication_p.h"
19 
20 #include "authenticationstore.h"
21 #include "authenticationrealm.h"
22 
23 #include "context.h"
24 #include "application.h"
25 
26 #include <Cutelyst/Plugins/Session/session.h>
27 
28 #include <QLoggingCategory>
29 
30 Q_LOGGING_CATEGORY(CUTELYST_UTILS_AUTH, "cutelyst.utils.auth", QtWarningMsg)
31 Q_LOGGING_CATEGORY(C_AUTHENTICATION, "cutelyst.plugin.authentication", QtWarningMsg)
32 
33 using namespace Cutelyst;
34 
35 char *Authentication::defaultRealm = const_cast<char *>("cutelyst_authentication_default_realm");
36 char *AuthenticationRealm::defaultRealm = const_cast<char *>("cutelyst_authentication_default_realm");
37 
38 static thread_local Authentication *auth = nullptr;
39 
40 #define AUTHENTICATION_USER QStringLiteral("_c_authentication_user")
41 #define AUTHENTICATION_USER_REALM QStringLiteral("_c_authentication_user_realm")
42 
44  , d_ptr(new AuthenticationPrivate)
45 {
46  qRegisterMetaType<AuthenticationUser>();
47  qRegisterMetaTypeStreamOperators<AuthenticationUser>();
48 }
49 
50 Authentication::~Authentication()
51 {
52  delete d_ptr;
53 }
54 
56 {
57  Q_D(Authentication);
58  realm->setParent(this);
59  d->realms.insert(realm->objectName(), realm);
60  d->realmsOrder.append(realm->objectName());
61 }
62 
64 {
65  addRealm(new AuthenticationRealm(store, credential, name, this));
66 }
67 
68 AuthenticationRealm *Authentication::realm(const QString &name) const
69 {
70  Q_D(const Authentication);
71  return d->realms.value(name);
72 }
73 
74 bool Authentication::authenticate(Cutelyst::Context *c, const ParamsMultiMap &userinfo, const QString &realm)
75 {
76  if (!auth) {
77  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
78  return false;
79  }
80 
81  AuthenticationRealm *realmPtr = auth->d_ptr->realm(realm);
82  if (realmPtr) {
83  const AuthenticationUser user = realmPtr->authenticate(c, userinfo);
84  if (!user.isNull()) {
85  AuthenticationPrivate::setAuthenticated(c, user, realm, auth->d_ptr->realm(realm));
86  }
87 
88  return !user.isNull();
89  }
90 
91  qCWarning(C_AUTHENTICATION) << "Could not find realm" << realm;
92  return false;
93 }
94 
96 {
98  if (!auth) {
99  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
100  return ret;
101  }
102 
103  AuthenticationRealm *realmPtr = auth->d_ptr->realm(realm);
104  if (!realmPtr) {
105  qCWarning(C_AUTHENTICATION) << "Could not find realm" << realm;
106  return ret;
107  }
108 
109  ret = realmPtr->findUser(c, userinfo);
110  return ret;
111 }
112 
114 {
115  AuthenticationUser ret;
116  const QVariant user = c->stash(AUTHENTICATION_USER);
117  if (user.isNull()) {
118  ret = AuthenticationPrivate::restoreUser(c, QVariant(), QString());
119  } else {
120  ret = user.value<AuthenticationUser>();
121  }
122  return ret;
123 }
124 
126 {
127  if (!c->stash(AUTHENTICATION_USER).isNull()) {
128  return true;
129  } else {
130  if (auth) {
131  if (AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder)) {
132  return true;
133  }
134  } else {
135  qCCritical(C_AUTHENTICATION, "Authentication plugin not registered!");
136  }
137  return false;
138  }
139 }
140 
141 bool Authentication::userInRealm(Cutelyst::Context *c, const QString &realmName)
142 {
143  const QVariant user = c->stash(AUTHENTICATION_USER);
144  if (!user.isNull()) {
145  return user.value<AuthenticationUser>().authRealm() == realmName;
146  } else {
147  if (!auth) {
148  qCCritical(C_AUTHENTICATION, "Authentication plugin not registered!");
149  return false;
150  }
151 
152  AuthenticationRealm *realm = AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder);
153  if (realm) {
154  return realm->name() == realmName;
155  } else {
156  return false;
157  }
158  }
159 }
160 
162 {
163  AuthenticationPrivate::setUser(c, AuthenticationUser());
164 
165  if (auth) {
166  AuthenticationRealm *realm = AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder);
167  if (realm) {
169  }
170  } else {
171  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
172  }
173 }
174 
176 {
177  return connect(app, &Application::postForked, this, [=] {
178  auth = this;
179  });
180 }
181 
182 AuthenticationRealm *AuthenticationPrivate::realm(const QString &realmName) const
183 {
184  return realms.value(realmName.isNull() ? defaultRealm : realmName);
185 }
186 
187 AuthenticationUser AuthenticationPrivate::restoreUser(Context *c, const QVariant &frozenUser, const QString &realmName)
188 {
189  AuthenticationUser ret;
190  if (!auth) {
191  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
192  return ret;
193  }
194 
195  AuthenticationRealm *realmPtr = auth->d_ptr->realm(realmName);
196  if (!realmPtr) {
197  realmPtr = AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder);
198  }
199 
200  if (!realmPtr) {
201  return ret;
202  }
203 
204  ret = realmPtr->restoreUser(c, frozenUser);
205 
206  AuthenticationPrivate::setUser(c, ret);
207 
208  return ret;
209 }
210 
211 AuthenticationRealm *AuthenticationPrivate::findRealmForPersistedUser(Context *c, const QMap<QString, AuthenticationRealm *> &realms, const QStringList &realmsOrder)
212 {
213  const QVariant realmVariant = Session::value(c, AUTHENTICATION_USER_REALM);
214  if (!realmVariant.isNull()) {
215  AuthenticationRealm *realm = realms.value(realmVariant.toString());
216  if (realm && !realm->userIsRestorable(c).isNull()) {
217  return realm;
218  }
219  } else {
220  // we have no choice but to ask each realm whether it has a persisted user.
221  for (const QString &realmName : realmsOrder) {
222  AuthenticationRealm *realm = realms.value(realmName);
223  if (realm && !realm->userIsRestorable(c).isNull()) {
224  return realm;
225  }
226  }
227  }
228 
229  return nullptr;
230 }
231 
232 void AuthenticationPrivate::setAuthenticated(Context *c, const AuthenticationUser &user, const QString &realmName, AuthenticationRealm *realm)
233 {
234  AuthenticationPrivate::setUser(c, user);
235 
236  if (!realm) {
237  qCWarning(C_AUTHENTICATION) << "Called with invalid realm" << realmName;
238  }
239 
240  AuthenticationPrivate::persistUser(c, user, realmName, realm);
241 }
242 
243 void AuthenticationPrivate::setUser(Context *c, const AuthenticationUser &user, const QString &realmName)
244 {
245  if (user.isNull()) {
246  c->setStash(AUTHENTICATION_USER, QVariant());
247  c->setStash(AUTHENTICATION_USER_REALM, QVariant());
248  } else {
249  c->setStash(AUTHENTICATION_USER, QVariant::fromValue(user));
250  c->setStash(AUTHENTICATION_USER_REALM, realmName);
251  }
252 }
253 
254 void AuthenticationPrivate::persistUser(Context *c, const AuthenticationUser &user, const QString &realmName, AuthenticationRealm *realm)
255 {
257  if (Session::isValid(c)) {
258  Session::setValue(c, AUTHENTICATION_USER_REALM, realmName);
259  }
260 
261  if (realm) {
262  realm->persistUser(c, user);
263  }
264  }
265 }
266 
268 {
269 
270 }
271 
272 Cutelyst::AuthenticationCredential::~AuthenticationCredential()
273 {
274 
275 }
276 
277 #include "moc_authentication.cpp"
Cutelyst::Authentication::authenticate
static bool authenticate(Context *c, const ParamsMultiMap &userinfo, const QString &realm=QLatin1String(defaultRealm))
Definition: authentication.cpp:74
Cutelyst::Application::postForked
void postForked(Cutelyst::Application *app)
Cutelyst::Plugin
Definition: plugin.h:30
Cutelyst::ParamsMultiMap
QMap< QString, QString > ParamsMultiMap
Definition: paramsmultimap.h:36
Cutelyst::AuthenticationRealm::removePersistedUser
void removePersistedUser(Context *c)
Removes the user from the session.
Definition: authenticationrealm.cpp:80
Cutelyst::Application
The Cutelyst Application.
Definition: application.h:55
Cutelyst::AuthenticationUser::isNull
bool isNull() const
Returns true if the object is null.
Definition: authenticationuser.cpp:49
Cutelyst::AuthenticationCredential
Definition: authentication.h:31
Cutelyst::Session::setValue
static void setValue(Context *c, const QString &key, const QVariant &value)
Definition: session.cpp:180
Cutelyst::Context
The Cutelyst Context.
Definition: context.h:50
Cutelyst::AuthenticationUser
Definition: authenticationuser.h:31
Cutelyst::AuthenticationRealm::userIsRestorable
QVariant userIsRestorable(Context *c)
Checks if user can be retrieved.
Definition: authenticationrealm.cpp:121
Cutelyst::AuthenticationRealm::persistUser
AuthenticationUser persistUser(Context *c, const AuthenticationUser &user)
Stores the user on the session.
Definition: authenticationrealm.cpp:85
Cutelyst::Context::setStash
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:225
Cutelyst::Authentication::realm
AuthenticationRealm * realm(const QString &name=QLatin1String(defaultRealm)) const
Returns an AuthenticationRealm object that was registered with name.
Definition: authentication.cpp:68
Cutelyst::Authentication::setup
virtual bool setup(Application *app) override
Definition: authentication.cpp:175
Cutelyst::Authentication::userInRealm
static bool userInRealm(Context *c, const QString &realmName=QLatin1String(defaultRealm))
Definition: authentication.cpp:141
Cutelyst::AuthenticationCredential::AuthenticationCredential
AuthenticationCredential(QObject *parent=nullptr)
Constructs a new AuthenticationCredential object with the given parent.
Definition: authentication.cpp:267
Cutelyst::Authentication::Authentication
Authentication(Application *parent)
Constructs a new Authentication object with the given parent.
Definition: authentication.cpp:43
Cutelyst::Authentication::defaultRealm
static char * defaultRealm
default realm name
Definition: authentication.h:55
Cutelyst::AuthenticationStore
Definition: authenticationstore.h:26
Cutelyst::Authentication::addRealm
void addRealm(AuthenticationRealm *realm)
Adds the realm with name.
Definition: authentication.cpp:55
Cutelyst::Authentication::userExists
static bool userExists(Context *c)
Definition: authentication.cpp:125
Cutelyst::AuthenticationRealm
Definition: authenticationrealm.h:30
Cutelyst::Authentication
Definition: authentication.h:49
Cutelyst::Authentication::findUser
static AuthenticationUser findUser(Context *c, const ParamsMultiMap &userinfo, const QString &realm=QLatin1String(defaultRealm))
Tries to find the user with userinfo using the realm, returning a non null AuthenticationUser on succ...
Definition: authentication.cpp:95
Cutelyst::AuthenticationRealm::authenticate
virtual AuthenticationUser authenticate(Context *c, const ParamsMultiMap &authinfo)
Tries to authenticate the user with authinfo returning a non null AuthenticationUser on success.
Definition: authenticationrealm.cpp:75
Cutelyst
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
Cutelyst::Component::name
QString name() const
Definition: component.cpp:44
Cutelyst::AuthenticationRealm::restoreUser
AuthenticationUser restoreUser(Context *c, const QVariant &frozenUser)
Retrieves the user from the store.
Definition: authenticationrealm.cpp:97
Cutelyst::Authentication::user
static AuthenticationUser user(Context *c)
Definition: authentication.cpp:113
Cutelyst::AuthenticationRealm::findUser
virtual AuthenticationUser findUser(Context *c, const ParamsMultiMap &userinfo)
Tries to find the user with authinfo returning a non null AuthenticationUser on success.
Definition: authenticationrealm.cpp:60
Cutelyst::Session::value
static QVariant value(Context *c, const QString &key, const QVariant &defaultValue=QVariant())
Definition: session.cpp:165
Cutelyst::Session::isValid
static bool isValid(Context *c)
Definition: session.cpp:251
Cutelyst::Authentication::logout
static void logout(Context *c)
Definition: authentication.cpp:161
Cutelyst::AuthenticationRealm::defaultRealm
static char * defaultRealm
default realm name
Definition: authenticationrealm.h:35
Cutelyst::Context::stash
void stash(const QVariantHash &unite)
Definition: context.h:558