Cutelyst  3.5.0
authentication.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2013-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "authentication_p.h"
6 
7 #include "authenticationstore.h"
8 #include "authenticationrealm.h"
9 
10 #include "context.h"
11 #include "application.h"
12 
13 #include <Cutelyst/Plugins/Session/session.h>
14 
15 #include <QLoggingCategory>
16 
17 Q_LOGGING_CATEGORY(CUTELYST_UTILS_AUTH, "cutelyst.utils.auth", QtWarningMsg)
18 Q_LOGGING_CATEGORY(C_AUTHENTICATION, "cutelyst.plugin.authentication", QtWarningMsg)
19 
20 using namespace Cutelyst;
21 
22 char *Authentication::defaultRealm = const_cast<char *>("cutelyst_authentication_default_realm");
23 char *AuthenticationRealm::defaultRealm = const_cast<char *>("cutelyst_authentication_default_realm");
24 
25 static thread_local Authentication *auth = nullptr;
26 
27 #define AUTHENTICATION_USER QStringLiteral("_c_authentication_user")
28 #define AUTHENTICATION_USER_REALM QStringLiteral("_c_authentication_user_realm")
29 
31  , d_ptr(new AuthenticationPrivate)
32 {
33  qRegisterMetaType<AuthenticationUser>();
34 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
35  qRegisterMetaTypeStreamOperators<AuthenticationUser>();
36 #endif
37 }
38 
39 Authentication::~Authentication()
40 {
41  delete d_ptr;
42 }
43 
45 {
46  Q_D(Authentication);
47  realm->setParent(this);
48  d->realms.insert(realm->objectName(), realm);
49  d->realmsOrder.append(realm->objectName());
50 }
51 
53 {
54  addRealm(new AuthenticationRealm(store, credential, name, this));
55 }
56 
58 {
59  Q_D(const Authentication);
60  return d->realms.value(name);
61 }
62 
64 {
65  if (!auth) {
66  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
67  return false;
68  }
69 
70  AuthenticationRealm *realmPtr = auth->d_ptr->realm(realm);
71  if (realmPtr) {
72  const AuthenticationUser user = realmPtr->authenticate(c, userinfo);
73  if (!user.isNull()) {
74  AuthenticationPrivate::setAuthenticated(c, user, realm, realmPtr);
75  }
76 
77  return !user.isNull();
78  }
79 
80  qCWarning(C_AUTHENTICATION) << "Could not find realm" << realm;
81  return false;
82 }
83 
85 {
87  if (!auth) {
88  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
89  return ret;
90  }
91 
92  AuthenticationRealm *realmPtr = auth->d_ptr->realm(realm);
93  if (!realmPtr) {
94  qCWarning(C_AUTHENTICATION) << "Could not find realm" << realm;
95  return ret;
96  }
97 
98  ret = realmPtr->findUser(c, userinfo);
99  return ret;
100 }
101 
103 {
104  AuthenticationUser ret;
105  const QVariant user = c->stash(AUTHENTICATION_USER);
106  if (user.isNull()) {
107  ret = AuthenticationPrivate::restoreUser(c, QVariant(), QString());
108  } else {
109  ret = user.value<AuthenticationUser>();
110  }
111  return ret;
112 }
113 
115 {
116  if (!c->stash(AUTHENTICATION_USER).isNull()) {
117  return true;
118  } else {
119  if (auth) {
120  if (AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder)) {
121  return true;
122  }
123  } else {
124  qCCritical(C_AUTHENTICATION, "Authentication plugin not registered!");
125  }
126  return false;
127  }
128 }
129 
131 {
132  const QVariant user = c->stash(AUTHENTICATION_USER);
133  if (!user.isNull()) {
134  return user.value<AuthenticationUser>().authRealm() == realmName;
135  } else {
136  if (!auth) {
137  qCCritical(C_AUTHENTICATION, "Authentication plugin not registered!");
138  return false;
139  }
140 
141  AuthenticationRealm *realm = AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder);
142  if (realm) {
143  return realm->name() == realmName;
144  } else {
145  return false;
146  }
147  }
148 }
149 
151 {
152  AuthenticationPrivate::setUser(c, AuthenticationUser());
153 
154  if (auth) {
155  AuthenticationRealm *realm = AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder);
156  if (realm) {
158  }
159  } else {
160  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
161  }
162 }
163 
165 {
166  return connect(app, &Application::postForked, this, [=] {
167  auth = this;
168  });
169 }
170 
171 AuthenticationRealm *AuthenticationPrivate::realm(const QString &realmName) const
172 {
173  return realms.value(realmName.isNull() ? defaultRealm : realmName);
174 }
175 
176 AuthenticationUser AuthenticationPrivate::restoreUser(Context *c, const QVariant &frozenUser, const QString &realmName)
177 {
178  AuthenticationUser ret;
179  if (!auth) {
180  qCCritical(C_AUTHENTICATION) << "Authentication plugin not registered";
181  return ret;
182  }
183 
184  AuthenticationRealm *realmPtr = auth->d_ptr->realm(realmName);
185  if (!realmPtr) {
186  realmPtr = AuthenticationPrivate::findRealmForPersistedUser(c, auth->d_ptr->realms, auth->d_ptr->realmsOrder);
187  }
188 
189  if (!realmPtr) {
190  return ret;
191  }
192 
193  ret = realmPtr->restoreUser(c, frozenUser);
194 
195  AuthenticationPrivate::setUser(c, ret);
196 
197  return ret;
198 }
199 
200 AuthenticationRealm *AuthenticationPrivate::findRealmForPersistedUser(Context *c, const QMap<QString, AuthenticationRealm *> &realms, const QStringList &realmsOrder)
201 {
202  const QVariant realmVariant = Session::value(c, AUTHENTICATION_USER_REALM);
203  if (!realmVariant.isNull()) {
204  AuthenticationRealm *realm = realms.value(realmVariant.toString());
205  if (realm && !realm->userIsRestorable(c).isNull()) {
206  return realm;
207  }
208  } else {
209  // we have no choice but to ask each realm whether it has a persisted user.
210  for (const QString &realmName : realmsOrder) {
211  AuthenticationRealm *realm = realms.value(realmName);
212  if (realm && !realm->userIsRestorable(c).isNull()) {
213  return realm;
214  }
215  }
216  }
217 
218  return nullptr;
219 }
220 
221 void AuthenticationPrivate::setAuthenticated(Context *c, const AuthenticationUser &user, const QString &realmName, AuthenticationRealm *realm)
222 {
223  AuthenticationPrivate::setUser(c, user, realmName);
224 
225  if (!realm) {
226  qCWarning(C_AUTHENTICATION) << "Called with invalid realm" << realmName;
227  }
228 
229  AuthenticationPrivate::persistUser(c, user, realmName, realm);
230 }
231 
232 void AuthenticationPrivate::setUser(Context *c, const AuthenticationUser &user, const QString &realmName)
233 {
234  if (user.isNull()) {
235  c->setStash(AUTHENTICATION_USER, QVariant());
236  c->setStash(AUTHENTICATION_USER_REALM, QVariant());
237  } else {
238  c->setStash(AUTHENTICATION_USER, QVariant::fromValue(user));
239  c->setStash(AUTHENTICATION_USER_REALM, realmName);
240  }
241 }
242 
243 void AuthenticationPrivate::persistUser(Context *c, const AuthenticationUser &user, const QString &realmName, AuthenticationRealm *realm)
244 {
245  if (Authentication::userInRealm(c, realmName)) {
246  Session::setValue(c, AUTHENTICATION_USER_REALM, realmName);
247 
248  if (realm) {
249  realm->persistUser(c, user);
250  }
251  }
252 }
253 
255 {
256 
257 }
258 
259 Cutelyst::AuthenticationCredential::~AuthenticationCredential()
260 {
261 
262 }
263 
264 #include "moc_authentication.cpp"
AuthenticationUser restoreUser(Context *c, const QVariant &frozenUser)
Retrieves the user from the store.
void postForked(Cutelyst::Application *app)
virtual AuthenticationUser findUser(Context *c, const ParamsMultiMap &userinfo)
Tries to find the user with authinfo returning a non null AuthenticationUser on success.
static char * defaultRealm
default realm name
AuthenticationUser persistUser(Context *c, const AuthenticationUser &user)
Stores the user on the session.
bool isNull() const
Returns true if the object is null.
virtual AuthenticationUser authenticate(Context *c, const ParamsMultiMap &authinfo)
Tries to authenticate the user with authinfo returning a non null AuthenticationUser on success...
void addRealm(AuthenticationRealm *realm)
Adds the realm with name.
void setStash(const QString &key, const QVariant &value)
Definition: context.cpp:212
static void logout(Context *c)
bool isNull() const const
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...
QVariant userIsRestorable(Context *c)
Checks if user can be retrieved.
The Cutelyst Context.
Definition: context.h:38
AuthenticationRealm * realm(const QString &name=QLatin1String(defaultRealm)) const
Returns an AuthenticationRealm object that was registered with name.
static bool authenticate(Context *c, const ParamsMultiMap &userinfo, const QString &realm=QLatin1String(defaultRealm))
bool isNull() const const
void stash(const QVariantHash &unite)
Definition: context.cpp:540
QString name() const
Definition: component.cpp:31
static void setValue(Context *c, const QString &key, const QVariant &value)
Definition: session.cpp:165
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
virtual bool setup(Application *app) override
Authentication(Application *parent)
Constructs a new Authentication object with the given parent.
void setParent(QObject *parent)
QVariant fromValue(const T &value)
static bool userExists(Context *c)
static char * defaultRealm
default realm name
AuthenticationCredential(QObject *parent=nullptr)
Constructs a new AuthenticationCredential object with the given parent.
static bool userInRealm(Context *c, const QString &realmName=QLatin1String(defaultRealm))
static QVariant value(Context *c, const QString &key, const QVariant &defaultValue=QVariant())
Definition: session.cpp:150
The Cutelyst Application.
Definition: application.h:42
static AuthenticationUser user(Context *c)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString toString() const const
const T value(const Key &key, const T &defaultValue) const const
void removePersistedUser(Context *c)
Removes the user from the session.