Cutelyst  1.11.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 
185 // TODO maybe mark this as static for 2.0
187 {
188  Q_D(const RoleACL);
189 
190  const QStringList user_has = Authentication::user(c).value(QStringLiteral("roles")).toStringList();
191 
192  const QStringList required = d->requiresRole;
193  const QStringList allowed = d->allowedRole;
194 
195  if (!required.isEmpty() && !allowed.isEmpty()) {
196  for (const QString &role : required) {
197  if (!user_has.contains(role)) {
198  return false;
199  }
200  }
201 
202  for (const QString &role : allowed) {
203  if (user_has.contains(role)) {
204  return true;
205  }
206  }
207  } else if (!required.isEmpty()) {
208  for (const QString &role : required) {
209  if (!user_has.contains(role)) {
210  return false;
211  }
212  }
213  return true;
214  } else if (!allowed.isEmpty()) {
215  for (const QString &role : allowed) {
216  if (user_has.contains(role)) {
217  return true;
218  }
219  }
220  }
221 
222  return false;
223 }
224 
225 bool RoleACL::dispatcherReady(const Dispatcher *dispatcher, Cutelyst::Controller *controller)
226 {
227  Q_D(RoleACL);
228  Q_UNUSED(dispatcher)
229 
230  d->detachTo = controller->actionFor(d->aclDetachTo);
231  if (!d->detachTo) {
232  d->detachTo = dispatcher->getActionByPath(d->aclDetachTo);
233  if (!d->detachTo) {
234  qFatal("RoleACL: Action '%s' requires a valid action set on the ACLDetachTo(%s) attribute",
235  qPrintable(d->actionReverse), qPrintable(d->aclDetachTo));
236  }
237  }
238 
239  return true;
240 }
241 
242 #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:319
Action * getActionByPath(const QString &path) const
Definition: dispatcher.cpp:231
The Cutelyst Component base class.
Definition: component.h:38
The Cutelyst Context.
Definition: context.h:50
Action * actionFor(const QString &name) const
Definition: controller.cpp:48
Cutelyst Controller base class
Definition: controller.h:102
virtual bool aroundExecute(Context *c, QStack< Component * > stack) override
Definition: roleacl.cpp:172
User role-based authorization action class.
Definition: roleacl.h:31
bool canVisit(Context *c) const
Definition: roleacl.cpp:186
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:225
virtual bool aroundExecute(Context *c, QStack< Component * > stack)
Definition: component.cpp:97
The Cutelyst Application.
Definition: application.h:54
static AuthenticationUser user(Context *c)
The Cutelyst Dispatcher.
Definition: dispatcher.h:40