Cutelyst  3.1.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 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
48  qRegisterMetaTypeStreamOperators<AuthenticationUser>();
49 #endif
50 }
51 
52 Authentication::~Authentication()
53 {
54  delete d_ptr;
55 }
56 
58 {
59  Q_D(Authentication);
60  realm->setParent(this);
61  d->realms.insert(realm->objectName(), realm);
62  d->realmsOrder.append(realm->objectName());
63 }
64 
66 {
67  addRealm(new AuthenticationRealm(store, credential, name, this));
68 }
69 
71 {
72  Q_D(const Authentication);
73  return d->realms.value(name);
74 }
75 
77 {
78  if (!auth) {
79  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
80  return false;
81  }
82 
83  AuthenticationRealm *realmPtr = auth->d_ptr->realm(realm);
84  if (realmPtr) {
85  const AuthenticationUser user = realmPtr->authenticate(c, userinfo);
86  if (!user.isNull()) {
87  AuthenticationPrivate::setAuthenticated(c, user, realm, realmPtr);
88  }
89 
90  return !user.isNull();
91  }
92 
93  qCWarning(C_AUTHENTICATION) << "Could not find realm" << realm;
94  return false;
95 }
96 
98 {
100  if (!auth) {
101  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
102  return ret;
103  }
104 
105  AuthenticationRealm *realmPtr = auth->d_ptr->realm(realm);
106  if (!realmPtr) {
107  qCWarning(C_AUTHENTICATION) << "Could not find realm" << realm;
108  return ret;
109  }
110 
111  ret = realmPtr->findUser(c, userinfo);
112  return ret;
113 }
114 
116 {
117  AuthenticationUser ret;
118  const QVariant user = c->stash(AUTHENTICATION_USER);
119  if (user.isNull()) {
120  ret = AuthenticationPrivate::restoreUser(c, QVariant(), QString());
121  } else {
122  ret = user.value<AuthenticationUser>();
123  }
124  return ret;
125 }
126 
128 {
129  if (!c->stash(AUTHENTICATION_USER).isNull()) {
130  return true;
131  } else {
132  if (auth) {
133  if (AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder)) {
134  return true;
135  }
136  } else {
137  qCCritical(C_AUTHENTICATION, "Authentication plugin not registered!");
138  }
139  return false;
140  }
141 }
142 
144 {
145  const QVariant user = c->stash(AUTHENTICATION_USER);
146  if (!user.isNull()) {
147  return user.value<AuthenticationUser>().authRealm() == realmName;
148  } else {
149  if (!auth) {
150  qCCritical(C_AUTHENTICATION, "Authentication plugin not registered!");
151  return false;
152  }
153 
154  AuthenticationRealm *realm = AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder);
155  if (realm) {
156  return realm->name() == realmName;
157  } else {
158  return false;
159  }
160  }
161 }
162 
164 {
165  AuthenticationPrivate::setUser(c, AuthenticationUser());
166 
167  if (auth) {
168  AuthenticationRealm *realm = AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder);
169  if (realm) {
171  }
172  } else {
173  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
174  }
175 }
176 
178 {
179  return connect(app, &Application::postForked, this, [=] {
180  auth = this;
181  });
182 }
183 
184 AuthenticationRealm *AuthenticationPrivate::realm(const QString &realmName) const
185 {
186  return realms.value(realmName.isNull() ? defaultRealm : realmName);
187 }
188 
189 AuthenticationUser AuthenticationPrivate::restoreUser(Context *c, const QVariant &frozenUser, const QString &realmName)
190 {
191  AuthenticationUser ret;
192  if (!auth) {
193  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
194  return ret;
195  }
196 
197  AuthenticationRealm *realmPtr = auth->d_ptr->realm(realmName);
198  if (!realmPtr) {
199  realmPtr = AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder);
200  }
201 
202  if (!realmPtr) {
203  return ret;
204  }
205 
206  ret = realmPtr->restoreUser(c, frozenUser);
207 
208  AuthenticationPrivate::setUser(c, ret);
209 
210  return ret;
211 }
212 
213 AuthenticationRealm *AuthenticationPrivate::findRealmForPersistedUser(Context *c, const QMap<QString, AuthenticationRealm *> &realms, const QStringList &realmsOrder)
214 {
215  const QVariant realmVariant = Session::value(c, AUTHENTICATION_USER_REALM);
216  if (!realmVariant.isNull()) {
217  AuthenticationRealm *realm = realms.value(realmVariant.toString());
218  if (realm && !realm->userIsRestorable(c).isNull()) {
219  return realm;
220  }
221  } else {
222  // we have no choice but to ask each realm whether it has a persisted user.
223  for (const QString &realmName : realmsOrder) {
224  AuthenticationRealm *realm = realms.value(realmName);
225  if (realm && !realm->userIsRestorable(c).isNull()) {
226  return realm;
227  }
228  }
229  }
230 
231  return nullptr;
232 }
233 
234 void AuthenticationPrivate::setAuthenticated(Context *c, const AuthenticationUser &user, const QString &realmName, AuthenticationRealm *realm)
235 {
236  AuthenticationPrivate::setUser(c, user, realmName);
237 
238  if (!realm) {
239  qCWarning(C_AUTHENTICATION) << "Called with invalid realm" << realmName;
240  }
241 
242  AuthenticationPrivate::persistUser(c, user, realmName, realm);
243 }
244 
245 void AuthenticationPrivate::setUser(Context *c, const AuthenticationUser &user, const QString &realmName)
246 {
247  if (user.isNull()) {
248  c->setStash(AUTHENTICATION_USER, QVariant());
249  c->setStash(AUTHENTICATION_USER_REALM, QVariant());
250  } else {
251  c->setStash(AUTHENTICATION_USER, QVariant::fromValue(user));
252  c->setStash(AUTHENTICATION_USER_REALM, realmName);
253  }
254 }
255 
256 void AuthenticationPrivate::persistUser(Context *c, const AuthenticationUser &user, const QString &realmName, AuthenticationRealm *realm)
257 {
258  if (Authentication::userInRealm(c, realmName)) {
259  Session::setValue(c, AUTHENTICATION_USER_REALM, realmName);
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"
The Cutelyst Application.
Definition: application.h:56
void postForked(Cutelyst::Application *app)
AuthenticationCredential(QObject *parent=nullptr)
Constructs a new AuthenticationCredential object with the given parent.
void removePersistedUser(Context *c)
Removes the user from the session.
virtual AuthenticationUser authenticate(Context *c, const ParamsMultiMap &authinfo)
Tries to authenticate the user with authinfo returning a non null AuthenticationUser on success.
static char * defaultRealm
default realm name
QVariant userIsRestorable(Context *c)
Checks if user can be retrieved.
AuthenticationUser persistUser(Context *c, const AuthenticationUser &user)
Stores the user on the session.
virtual AuthenticationUser findUser(Context *c, const ParamsMultiMap &userinfo)
Tries to find the user with authinfo returning a non null AuthenticationUser on success.
AuthenticationUser restoreUser(Context *c, const QVariant &frozenUser)
Retrieves the user from the store.
bool isNull() const
Returns true if the object is null.
void addRealm(AuthenticationRealm *realm)
Adds the realm with name.
static bool userInRealm(Context *c, const QString &realmName=QLatin1String(defaultRealm))
static bool userExists(Context *c)
virtual bool setup(Application *app) override
static void logout(Context *c)
static bool authenticate(Context *c, const ParamsMultiMap &userinfo, const QString &realm=QLatin1String(defaultRealm))
static char * defaultRealm
default realm name
Authentication(Application *parent)
Constructs a new Authentication object with the given parent.
static AuthenticationUser user(Context *c)
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...
AuthenticationRealm * realm(const QString &name=QLatin1String(defaultRealm)) const
Returns an AuthenticationRealm object that was registered with name.
QString name() const
Definition: component.cpp:44
The Cutelyst Context.
Definition: context.h:52
void stash(const QVariantHash &unite)
Definition: context.cpp:549
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:225
static QVariant value(Context *c, const QString &key, const QVariant &defaultValue=QVariant())
Definition: session.cpp:165
static void setValue(Context *c, const QString &key, const QVariant &value)
Definition: session.cpp:180
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:8
const T value(const Key &key, const T &defaultValue) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setParent(QObject *parent)
bool isNull() const const
QVariant fromValue(const T &value)
bool isNull() const const
QString toString() const const