Cutelyst  2.5.0
roleacl.cpp
1 /*
2  * Copyright (C) 2014-2017 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 "roleacl_p.h"
19 
20 #include "common.h"
21 
22 #include <Cutelyst/Plugins/Authentication/authentication.h>
23 #include <Cutelyst/Controller>
24 #include <Cutelyst/Dispatcher>
25 
26 using namespace Cutelyst;
27 
126 RoleACL::RoleACL(QObject *parent) : Component(parent)
127  , d_ptr(new RoleACLPrivate)
128 {
129 }
130 
131 RoleACL::~RoleACL()
132 {
133  delete d_ptr;
134 }
135 
136 Component::Modifiers RoleACL::modifiers() const
137 {
138  return AroundExecute;
139 }
140 
141 bool RoleACL::init(Cutelyst::Application *application, const QVariantHash &args)
142 {
143  Q_D(RoleACL);
144  Q_UNUSED(application)
145 
146  const auto attributes = args.value(QLatin1String("attributes")).value<ParamsMultiMap>();
147  d->actionReverse = args.value(QLatin1String("reverse")).toString();
148 
149  if (!attributes.contains(QLatin1String("RequiresRole")) && !attributes.contains(QLatin1String("AllowedRole"))) {
150  qFatal("RoleACL: Action %s requires at least one RequiresRole or AllowedRole attribute", qPrintable(d->actionReverse));
151  } else {
152  const QStringList required = attributes.values(QLatin1String("RequiresRole"));
153  for (const QString &role : required) {
154  d->requiresRole.append(role);
155  }
156 
157  const QStringList allowed = attributes.values(QLatin1String("AllowedRole"));
158  for (const QString &role : allowed) {
159  d->allowedRole.append(role);
160  }
161  }
162 
163  auto it = attributes.constFind(QLatin1String("ACLDetachTo"));
164  if (it == attributes.constEnd() || it.value().isEmpty()) {
165  qFatal("RoleACL: Action %s requires the ACLDetachTo(<action>) attribute", qPrintable(d->actionReverse));
166  }
167  d->aclDetachTo = it.value();
168 
169  return true;
170 }
171 
172 bool RoleACL::aroundExecute(Context *c, QStack<Cutelyst::Component *> stack)
173 {
174  Q_D(const RoleACL);
175 
176  if (canVisit(c)) {
177  return Component::aroundExecute(c, stack);
178  }
179 
180  c->detach(d->detachTo);
181 
182  return false;
183 }
184 
186 {
187  Q_D(const RoleACL);
188 
189  const QStringList user_has = Authentication::user(c).value(QStringLiteral("roles")).toStringList();
190 
191  const QStringList required = d->requiresRole;
192  const QStringList allowed = d->allowedRole;
193 
194  if (!required.isEmpty() && !allowed.isEmpty()) {
195  for (const QString &role : required) {
196  if (!user_has.contains(role)) {
197  return false;
198  }
199  }
200 
201  for (const QString &role : allowed) {
202  if (user_has.contains(role)) {
203  return true;
204  }
205  }
206  } else if (!required.isEmpty()) {
207  for (const QString &role : required) {
208  if (!user_has.contains(role)) {
209  return false;
210  }
211  }
212  return true;
213  } else if (!allowed.isEmpty()) {
214  for (const QString &role : allowed) {
215  if (user_has.contains(role)) {
216  return true;
217  }
218  }
219  }
220 
221  return false;
222 }
223 
224 bool RoleACL::dispatcherReady(const Dispatcher *dispatcher, Cutelyst::Controller *controller)
225 {
226  Q_D(RoleACL);
227  Q_UNUSED(dispatcher)
228 
229  d->detachTo = controller->actionFor(d->aclDetachTo);
230  if (!d->detachTo) {
231  d->detachTo = dispatcher->getActionByPath(d->aclDetachTo);
232  if (!d->detachTo) {
233  qFatal("RoleACL: Action '%s' requires a valid action set on the ACLDetachTo(%s) attribute",
234  qPrintable(d->actionReverse), qPrintable(d->aclDetachTo));
235  }
236  }
237 
238  return true;
239 }
240 
241 #include "moc_roleacl.cpp"
QMap< QString, QString > ParamsMultiMap
virtual bool init(Application *application, const QVariantHash &args) override
Definition: roleacl.cpp:141
void detach(Action *action=nullptr)
Definition: context.cpp:317
Action * actionFor(const QString &name) const
Definition: controller.cpp:48
virtual bool aroundExecute(Context *c, QStack< Component *> stack) override
Definition: roleacl.cpp:172
The Cutelyst Component base class.
Definition: component.h:38
The Cutelyst Context.
Definition: context.h:50
Cutelyst Controller base class
Definition: controller.h:102
bool canVisit(Context *c) const
Definition: roleacl.cpp:185
User role-based authorization action class.
Definition: roleacl.h:31
virtual Modifiers modifiers() const override
Definition: roleacl.cpp:136
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
RoleACL(QObject *parent=nullptr)
Definition: roleacl.cpp:126
virtual bool dispatcherReady(const Dispatcher *dispatcher, Controller *controller) override
Definition: roleacl.cpp:224
virtual bool aroundExecute(Context *c, QStack< Component *> stack)
Definition: component.cpp:109
The Cutelyst Application.
Definition: application.h:55
static AuthenticationUser user(Context *c)
Action * getActionByPath(const QString &path) const
Definition: dispatcher.cpp:231
The Cutelyst Dispatcher.
Definition: dispatcher.h:40