Remoto - VFS: VFS_acl.cpp Source File
Remoto - VFS
VFS_acl.cpp
Go to the documentation of this file.
1 
2 #include "VFS.h"
3 #include "VFS_acl.h"
4 #include "VFS_auth/VFS_session.h"
6 
7 QMutex VFS_acl::_accessControlLock(QMutex::Recursive);
8 QList<VFS_acl *> VFS_acl::_accessControlLists;
9 //QJsonObject VFS_acl::_accessControlDefaults;
10 
112 VFS_acl::VFS_acl(QString vfspath, QString path, bool defaultAllow, QString superadmin)
113 : VFS_node()
114 , _vfspath(vfspath)
115 , _path(path)
116 , _defaultAllow(defaultAllow)
117 , _superadmin(superadmin)
118 , _initialized(false)
119 {
120  registerACL(this);
121 
122  connect(VFS::root(),SIGNAL(initialized()),this,SLOT(initialize()));
123 }
124 
126 {
127  unregisterACL(this);
128 }
129 
135 {
137  s->_metadata["createIfMissing"] = true;
138  s->_data = QJsonDocument();
139  issueRequest( VFS::root(), s );
140 }
141 
148 {
149  //QMutexLocker l1(&_accessControlLock);
150  QMutexLocker l2(&_lock);
151 
152  QString s = QString("vfspath: %1\npath: %2\nentries: %3").arg(_vfspath).arg(_path).arg(_accessControlList.keys().length());
153 
154  return s;
155 }
156 
163 {
164  return false;
165 }
166 
177 {
178  if ( r->_path.startsWith("browse") )
179  return this;
180 
181  return VFS_node::find(r);
182 }
183 
192 {
193  //QMutexLocker l1(&_accessControlLock);
194  QMutexLocker l2(&_lock);
195 
196  if (r->_path == "")
197  {
198  if (!_initialized)
199  {
200  VFS_request *s = r->getCallback(this);
202  s->_path = _path;
203  issueRequest(s);
204  }
205  else
206  {
207  r->_data.setObject(_accessControlList);
208  r->_success = true;
209  }
210 
211  return;
212  }
213 
214  r->_reason = QString("%1 bad path: %2").arg(className()).arg(r->_path);
215  r->_success = false;
216 }
217 
227 {
228  //QMutexLocker l1(&_accessControlLock);
229  QMutexLocker l2(&_lock);
230 
231  if (r->_path == "")
232  {
233  bool notifyRequestor = false;
234  QList<VFS_request *> queries;
235 
236  QJsonObject o = r->_data.object();
237  QJsonObject::iterator it;
238  for (it = o.begin(); it != o.end(); it++)
239  {
240  QString k = it.key();
241  QJsonValue v = it.value();
242 
243  if (v.isBool())
244  {
245  if (v.toBool()==true)
246  {
247  //printf("would add acl entry: %s\n",qUtf8Printable(k));
248  if (_accessControlList.contains(k))
249  {
250  r->_reason = "Entry already exists.\n\nWon't create a duplicate ACL entry.";
251  r->_success = false;
252  return;
253  }
254  else
255  {
256  //queue a request to learn the defaults and features of this node, if it exists
257  queries << createRequest(VFS_request::acl,k,r->_user);
258  notifyRequestor = true;
259  }
260  }
261  else
262  VFS::WARN( QString("Request to create new acl '%1', but received false. Ignoring.").arg(k) );
263  }
264  }
265 
267 
268  if (notifyRequestor)
269  r->_notifyExceptions.clear(); //we actually do want the sender to receive this back if it's a new item
270 
271  emit diff(this,r); //need to emit diff before issuing request(s) for ACLs
272 
273  //if (!r->_metadata["nosubmit"].toBool(false))
274  //{
275  VFS_request *s = r->getCallback(this); //submit to our storage mechanism
276  s->_path = _path;
277  issueRequest(s);
278  //}
279  //else
280  // r->_success = true;
281 
282  //having emitted a diff first, query the nodes about their ACL values
283  foreach(VFS_request *q, queries)
284  {
285  issueRequest(q);
286  //delete q;
287  }
288 
289  return;
290  }
291 
292  r->_reason = QString("%1 bad path: %2").arg(className()).arg(r->_path);
293  r->_success = false;
294 }
295 
296 
305 {
306  if (r->_path.startsWith("browse"))
307  {
308  VFS_request *s = r->getCallback(this);
309  s->_path = r->_path.mid( QString("browse/").length() );
310  issueRequest(s);
311 
312  return;
313  }
314 
316 }
317 
318 
327 {
328  if (r->_path.startsWith("browse"))
329  {
330  VFS_request *s = r->getCallback(this);
331  s->_path = r->_path.mid( QString("browse/").length() );
332  issueRequest(s);
333 
334  return;
335  }
336 
338 }
339 
340 
349 {
350  //QMutexLocker l1(&_accessControlLock);
351  QMutexLocker l2(&_lock);
352 
353  switch (r->_requestType)
354  {
355  case VFS_request::subscribe: {
356  if (r->_initialPath == _path)
357  if (r->_success)
358  {
359  //printf("ACL LIST: %s\n",qUtf8Printable(QJsonDocument(_accessControlList).toJson()));
360  //_accessControlList = r->_data.object();
362  //printf("ACL LIST: %s\n",qUtf8Printable(QJsonDocument(_accessControlList).toJson()));
363  _initialized = true;
364  //printf("ACL %s initialized\n",qUtf8Printable(_vfspath));
365  }
366  }
367  break;
368 
369  case VFS_request::acl: {
370  if (r->_success)
371  {
372  //printf("ACL REQUEST: '%s'\n%s\n",qUtf8Printable(r->_initialPath),qUtf8Printable(r->toJson()));
373 
374  QString p = r->_initialPath;
375  QJsonObject o;
376  o[p] = r->_data.object();
377 
378  VFS_request *s = createRequest(VFS_request::submit,"",r->_user,QJsonDocument(o));
379  submit(s); //submit emits a diff and writes to our acl file
380  //delete s;
381  //issueRequest(this,)
382  }
383  }
384  break;
385 
386  default: break;
387  }
388 
390 }
391 
407 bool VFS_acl::checkAllowAccess(VFS_session *s, QString path, QString feature)
408 {
409  QMutexLocker l(&_accessControlLock);
410 
411  bool wasDefault = false;
412  bool allowed = false;
413  foreach(VFS_acl *acl, _accessControlLists)
414  {
415  wasDefault = false;
416  allowed = acl->privateCheckAllowAccess(s,path,feature,wasDefault);
417 
418  if (!wasDefault) // if the path was found in the ACL, return the result of the check
419  return allowed;
420  }
421 
422  if (_accessControlLists.length())
423  return allowed; // if the path was not found on any acl, return the default access value of the last ACL in the list
424  else
425  return true; // if there are no ACLs registered, default to allow=true.
426 }
427 
440 bool VFS_acl::checkAllowAccess(VFS_request *r, QString feature)
441 {
442  //return VFS_acl::checkAllowAccess(r->_session, r->_initialPath, feature);
443  return VFS_acl::checkAllowAccess(r->_session, r->_prefixPath.join("/"), feature);
444 }
445 
465 bool VFS_acl::privateCheckAllowAccess(VFS_session *s, QString path, QString feature, bool &wasDefault)
466 {
467  //QMutexLocker l1(&_accessControlLock);
468  QMutexLocker l2(&_lock);
469 
470  bool _debug = false;
471 
472  if (_debug)
473  printf("ACL check: %s (%s)\n",qUtf8Printable(path),qUtf8Printable(feature));
474 
475  bool d = _defaultAllow;
476  QJsonObject o,g,u,f;
477 
478  QString user;
479  QJsonArray groups;
480 
481  if (s && __isNode(s))
482  {
483  user = s->_user;
484  groups = s->_groups;
485  }
486  else //if no session, return the default
487  {
488  wasDefault = true;
489  return _defaultAllow;
490  }
491 
492 
493  if (_debug)
494  printf(" check 0: %s %d\n",qUtf8Printable(path),d);
495 
496  //always return true for the superadmin
497  if (user == _superadmin)
498  return true;
499 
500  if (_debug)
501  printf(" check 1: %s %d\n",qUtf8Printable(path),d);
502 
503  if (_accessControlList.contains(path))
504  {
505  o = _accessControlList[path].toObject();
506  if (o.contains("default"))
507  d = o["default"].toBool();
508 
509  if (o.contains("groups"))
510  g = o["groups"].toObject();
511 
512  if (o.contains("users"))
513  u = o["users"].toObject();
514 
515  if (o.contains("features"))
516  f = o["features"].toObject();
517  }
518  else //if no path entry, return the default
519  {
520  wasDefault = true;
521  return _defaultAllow;
522  }
523 
524  if (_debug)
525  printf(" check 2: %s %d\n",qUtf8Printable(path),d);
526 
527  //check the group. If more than one group matches, the last one will set the value
528  for (int i=0;i<groups.size();i++)
529  if (g.contains(groups[i].toString()))
530  d = g[groups[i].toString()].toBool();
531 
532  if (_debug)
533  printf(" check 3: %s %d\n",qUtf8Printable(path),d);
534 
535  //check the user
536  if (u.contains(user))
537  d = u[user].toBool(d);
538 
539  if (_debug)
540  printf(" check 4: %s %d\n",qUtf8Printable(path),d);
541 
542  //check the feature
543  if (feature != "" && f.contains(feature))
544  {
545  QJsonObject ff,fg,fu;
546 
547  ff = f[feature].toObject();
548 
549  if (ff.contains("default"))
550  d = ff["default"].toBool();
551 
552  fg = ff["groups"].toObject();
553  fu = ff["users"].toObject();
554 
555  for (int j=0;j<groups.size();j++)
556  if (fg.contains(groups[j].toString()))
557  d = fg[groups[j].toString()].toBool();
558 
559  if (fu.contains(user))
560  d = fu[user].toBool(d);
561  }
562 
563  return d;
564 }
565 
574 {
575  QMutexLocker l(&_accessControlLock);
576 
577  _accessControlLists << acl;
578 }
579 
586 {
587  QMutexLocker l(&_accessControlLock);
588 
589  _accessControlLists.removeAll(acl);
590 }
591 
598 {
599  QMutexLocker l(&_accessControlLock);
600 
601  QStringList paths;
602 
603  foreach(VFS_acl *acl, _accessControlLists)
604  {
605  //paths << acl->_path;
606  paths << acl->_vfspath;
607  }
608 
609  return paths;
610 }
The ACL class for maintaining permission to nodes.
Definition: VFS_acl.h:7
bool _defaultAllow
The default value if an entry is not found.
Definition: VFS_acl.h:41
static QList< VFS_acl * > _accessControlLists
The ACLs that have been registered to the VFS.
Definition: VFS_acl.h:47
static QMutex _accessControlLock
A mutex used to modify the _accessControlFeatures.
Definition: VFS_acl.h:46
virtual void unsubscribe(VFS_request *r)
Perform a normal VFS_node::unsubscribe, unless the path is "browse".
Definition: VFS_acl.cpp:326
virtual void read(VFS_request *r)
Read the ACL entries.
Definition: VFS_acl.cpp:191
QString _vfspath
The VFS path of this node.
Definition: VFS_acl.h:39
bool privateCheckAllowAccess(VFS_session *s, QString path, QString feature, bool &wasDefault)
Check if a request has access to a resource.
Definition: VFS_acl.cpp:465
virtual void submit(VFS_request *r)
Submit features or settings to the ACL.
Definition: VFS_acl.cpp:226
QString _superadmin
A single user who these ACLs will not apply to regardless of ACL file.
Definition: VFS_acl.h:43
virtual void initialize()
Initialize the ACL by subscribing to its data file.
Definition: VFS_acl.cpp:134
static bool checkAllowAccess(VFS_session *s, QString path, QString feature="")
Check if a session has access to a resource.
Definition: VFS_acl.cpp:407
virtual bool isContainer()
VFS_acl nodes cannot contain children.
Definition: VFS_acl.cpp:162
Q_INVOKABLE VFS_acl(QString vfspath, QString path, bool defaultAllow=true, QString superadmin="")
Construct a VFS_acl object.
Definition: VFS_acl.cpp:112
virtual void receiveResponse(VFS_request *r)
A request has been completed, respond to the results.
Definition: VFS_acl.cpp:348
virtual QString reportDetails()
Report data about an ACL.
Definition: VFS_acl.cpp:147
virtual ~VFS_acl()
Definition: VFS_acl.cpp:125
virtual void subscribe(VFS_request *r)
Perform a normal VFS_node::subscribe, unless the path is "browse".
Definition: VFS_acl.cpp:304
bool _initialized
Whether or not the settings file has been loaded.
Definition: VFS_acl.h:44
static void registerACL(VFS_acl *acl)
Add an acl to the _accessControlLists list.
Definition: VFS_acl.cpp:573
static QStringList fetchACLPaths()
Fetch the VFS path to each registered ACL file.
Definition: VFS_acl.cpp:597
QString _path
The VFS path to an ACL settings file.
Definition: VFS_acl.h:40
QJsonObject _accessControlList
The ACL entries.
Definition: VFS_acl.h:42
virtual VFS_node * find(VFS_request *r)
Find a child based on a VFS_request::_path.
Definition: VFS_acl.cpp:176
static void unregisterACL(VFS_acl *acl)
Remove an acl from the _accessControlLists list.
Definition: VFS_acl.cpp:585
static QJsonObject applyJsonDiff(QJsonObject obj, QJsonObject diff, QString trace="", QString user="server")
Apply a json diff to a json object.
VFS_node is the base class from which all other VFS_node classes derive.
Definition: VFS_node.h:143
virtual VFS_request * createRequest(VFS_request::requestType type, QString path, QString user="unknown", QJsonDocument data=QJsonDocument(), QJsonObject metadata=QJsonObject(), bool dontDelete=false)
Create a new VFS_request with this object as _origin.
Definition: VFS_node.cpp:1913
virtual void issueRequest(VFS_request *t)
A convenience function.
Definition: VFS_node.cpp:1933
static bool __isNode(VFS_node *)
Check to see if a node is in the global registry.
Definition: VFS_node.cpp:588
VFS_node * find(QString path)
Find a node by string path.
Definition: VFS_node.cpp:1100
void diff(VFS_node *origin, VFS_request *t)
Emit a diff, which will trigger notifySubscribers() for a mounted node.
QString className()
Return the class name of a node.
Definition: VFS_node.cpp:2039
QMutex _lock
A recursive mutex that is local to this node.
Definition: VFS_node.h:178
virtual void unsubscribe(VFS_request *r)
Remove an entry from this node's _subscription list.
Definition: VFS_node.cpp:1263
virtual void subscribe(VFS_request *r)
Add an entry to this node's _subscription list.
Definition: VFS_node.cpp:1204
virtual void receiveResponse(VFS_request *t)
Once a VFS_request has been completed, a response will be issued back to its _origin.
Definition: VFS_node.cpp:1870
The base class for all requests between nodes.
Definition: VFS_node.h:54
@ read
read full contents (4)
Definition: VFS_node.h:68
@ acl
return the ACL defaults for this node (11)
Definition: VFS_node.h:75
@ subscribe
subscribe to a path (9)
Definition: VFS_node.h:73
@ submit
apply a diff (8)
Definition: VFS_node.h:72
requestType _requestType
the action this request is performing or requesting
Definition: VFS_node.h:87
QString _initialPath
the target path when the request was made (relative to the responder)
Definition: VFS_node.h:93
QStringList _prefixPath
the prefix elements found while searching for the target
Definition: VFS_node.h:94
QString _user
who initiated this request, mostly for logging
Definition: VFS_node.h:106
VFS_session * _session
The session associated with this request. This is an optional value, and care should be taken to chec...
Definition: VFS_node.h:105
QString _reason
if something (probably bad) happened, this is the reason
Definition: VFS_node.h:108
QString _path
the target path remnant... the remaining path element once the request has found its target
Definition: VFS_node.h:95
QList< notifyException > _notifyExceptions
a list of nodes not to send responses to for this transaction. For instance if a node submits to a no...
Definition: VFS_node.h:110
bool _success
if the request was successfully completed
Definition: VFS_node.h:107
QJsonDocument _data
the request payload
Definition: VFS_node.h:102
virtual VFS_request * getCallback(VFS_node *receiver)
Create and chain a VFS_request for a receiver.
Definition: VFS_node.cpp:316
QJsonObject _metadata
the request payload
Definition: VFS_node.h:101
The VFS_session object represents a single session.
Definition: VFS_session.h:14
QString _user
The username associated with this session.
Definition: VFS_session.h:75
QJsonArray _groups
The list of groups this user is a member of.
Definition: VFS_session.h:78
static VFS * root()
Return the root node of the VFS filesystem.
Definition: VFS.cpp:399
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
Definition: VFS.cpp:258
getter path
a getter DOCME