1177 lines
39 KiB
C++
1177 lines
39 KiB
C++
|
|
// Copyright (c) 2013, IOnU Security, Inc.
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The Permissions class...
|
||
|
|
*/
|
||
|
|
#include "permissions.h"
|
||
|
|
#include "cloudguardurn.h"
|
||
|
|
#include "../../cppjson/jsonobject.h"
|
||
|
|
#include "../../libeye/eyeutils.h"
|
||
|
|
#include "../../libeye/eyeinterface.h"
|
||
|
|
|
||
|
|
#ifdef WIN32
|
||
|
|
#include <io.h>
|
||
|
|
#else
|
||
|
|
#include <unistd.h>
|
||
|
|
#endif
|
||
|
|
#include <sstream>
|
||
|
|
#include <algorithm>
|
||
|
|
#include <list>
|
||
|
|
#include <functional>
|
||
|
|
#include <locale>
|
||
|
|
|
||
|
|
using namespace sequencelogic;
|
||
|
|
|
||
|
|
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
const int SL_USER_ID_LENGTH = SL_URN_PMO_LEN;
|
||
|
|
|
||
|
|
const std::string PERMISSIONS_ALL = PERMISSION_ALL;
|
||
|
|
|
||
|
|
const char TOPIC_KEY[] = "topic";
|
||
|
|
const char KEYS_KEY[] = "keys";
|
||
|
|
|
||
|
|
bool checkUserValue(const std::string &value);
|
||
|
|
|
||
|
|
std::string getSignaturePath(const std::string &digest);
|
||
|
|
|
||
|
|
// will behave as if it is a StorageNode
|
||
|
|
// Add the new object to the array.
|
||
|
|
void createPermittedItem(const std::string &metaType, const std::string &urn, JSONArray &itemArray);
|
||
|
|
|
||
|
|
// van null -> only groups; van non-null -> only users
|
||
|
|
void addReferences(const JSONArray &permArray, std::set<CloudGuardURN> &list, const CloudGuardURN &van = CloudGuardURN());
|
||
|
|
|
||
|
|
// Legacy code. This used to check for "nested" groups.
|
||
|
|
bool checkGroupTopology(const std::string &type, const std::string &u) { return true; }
|
||
|
|
|
||
|
|
bool checkPermissionKey(const std::string &perm) { return (PERMISSIONS_ALL.find(perm) != std::string::npos); }
|
||
|
|
|
||
|
|
int SplitString(const std::string &strToSplit, const char ch, std::vector<std::string> &splitStrings);
|
||
|
|
|
||
|
|
#ifdef WIN32
|
||
|
|
bool canReadFile (const std::string &fileName) { return (_access_s(fileName.c_str(), 04) == 0); }
|
||
|
|
bool canWriteFile(const std::string &fileName) { return (_access_s(fileName.c_str(), 02) == 0); }
|
||
|
|
#else
|
||
|
|
bool canReadFile (const std::string &fileName) { return (access(fileName.c_str(), R_OK) == 0); }
|
||
|
|
bool canWriteFile(const std::string &fileName) { return (access(fileName.c_str(), W_OK) == 0); }
|
||
|
|
#endif
|
||
|
|
};
|
||
|
|
|
||
|
|
const char* Permissions::PERMISSION_KEYS[] = {
|
||
|
|
PERMISSION_READ,
|
||
|
|
PERMISSION_WRITE,
|
||
|
|
PERMISSION_ADMIN,
|
||
|
|
PERMISSION_DOORWAY,
|
||
|
|
PERMISSION_STREAM,
|
||
|
|
PERMISSION_SHOW_SHREDDED
|
||
|
|
};
|
||
|
|
const int Permissions::NUM_PERMISSION_KEYS = sizeof(PERMISSION_KEYS) / sizeof(PERMISSION_KEYS[0]);
|
||
|
|
|
||
|
|
const char Permissions::SIGNATURE_KEY[] = "signature";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Construct with default permissions.
|
||
|
|
*/
|
||
|
|
Permissions::Permissions() : _pData(new JSONObject())
|
||
|
|
{
|
||
|
|
for (int i = 0; i < NUM_PERMISSION_KEYS; ++i)
|
||
|
|
{
|
||
|
|
std::string keyName = PERMISSION_KEYS[i];
|
||
|
|
_pData->setJSONArray(keyName.c_str());
|
||
|
|
keyName += PERMISSION_ASSIGNMENT_SUFFIX;
|
||
|
|
_pData->setJSONArray(keyName.c_str());
|
||
|
|
}
|
||
|
|
mergeDefaultPermissions();
|
||
|
|
}
|
||
|
|
|
||
|
|
Permissions::Permissions(const PermissionsPtr pOrigObj) : _pData(new JSONObject(*pOrigObj->_pData))
|
||
|
|
{
|
||
|
|
setAuthority (pOrigObj->getAuthority());
|
||
|
|
//mergeDefaultPermissions();
|
||
|
|
}
|
||
|
|
|
||
|
|
Permissions::Permissions(const std::string &permStr) : _pData(new JSONObject (permStr))
|
||
|
|
{
|
||
|
|
//mergeDefaultPermissions();
|
||
|
|
}
|
||
|
|
|
||
|
|
Permissions::Permissions(const Permissions &origObj) : _pData(new JSONObject(*origObj._pData))
|
||
|
|
{
|
||
|
|
setAuthority(origObj.getAuthority());
|
||
|
|
//mergeDefaultPermissions();
|
||
|
|
}
|
||
|
|
|
||
|
|
Permissions::Permissions(const JSONObject &origObj) : _pData(new JSONObject(origObj))
|
||
|
|
{
|
||
|
|
//mergeDefaultPermissions();
|
||
|
|
}
|
||
|
|
|
||
|
|
Permissions& Permissions::operator=(const Permissions &rhs)
|
||
|
|
{
|
||
|
|
_pData.reset(new JSONObject(*rhs._pData));
|
||
|
|
setAuthority(rhs.getAuthority());
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Comparison.
|
||
|
|
*/
|
||
|
|
bool Permissions::operator==(const Permissions &rhs)
|
||
|
|
{
|
||
|
|
return ((*_pData == *rhs._pData) && (_authority == rhs._authority));
|
||
|
|
}
|
||
|
|
|
||
|
|
PermissionsPtr Permissions::createFromParent(const JSONObject &parent)
|
||
|
|
{
|
||
|
|
PermissionsPtr pRetVal (new Permissions());
|
||
|
|
|
||
|
|
if (parent.search(PERMISSION_ROOT_KEY) != NULL)
|
||
|
|
pRetVal.reset (new Permissions (parent.getJSONObject(PERMISSION_ROOT_KEY).toString()));
|
||
|
|
pRetVal->set(std::string(PERMISSION_SHOW_SHREDDED) + PERMISSION_ASSIGNMENT_SUFFIX, PERMISSION_VALUE_OWNER);
|
||
|
|
pRetVal->mergeDefaultPermissions();
|
||
|
|
return pRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
PermissionsPtr Permissions::createFromDeviceFile(const std::string &fileName, const CloudGuardURN &ownerAuthority)
|
||
|
|
{
|
||
|
|
std::shared_ptr <Permissions> pRetVal (new Permissions ());
|
||
|
|
|
||
|
|
pRetVal->setOwner(ownerAuthority.getPMOID());
|
||
|
|
pRetVal->setAuthority(ownerAuthority.getPMOID());
|
||
|
|
|
||
|
|
if(canReadFile(fileName))
|
||
|
|
{
|
||
|
|
pRetVal->setWithAssign(PERMISSION_READ, PERMISSION_VALUE_OWNER);
|
||
|
|
pRetVal->setWithAssign(PERMISSION_STREAM, PERMISSION_VALUE_OWNER);
|
||
|
|
}
|
||
|
|
if (canWriteFile(fileName))
|
||
|
|
pRetVal->setWithAssign(PERMISSION_WRITE, PERMISSION_VALUE_OWNER);
|
||
|
|
|
||
|
|
pRetVal->set(std::string(PERMISSION_SHOW_SHREDDED) + PERMISSION_ASSIGNMENT_SUFFIX, PERMISSION_VALUE_OWNER);
|
||
|
|
pRetVal->mergeDefaultPermissions();
|
||
|
|
|
||
|
|
return pRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Construct from a flattened non-json string.
|
||
|
|
* @param owner
|
||
|
|
* @param authority
|
||
|
|
* @param string read=something,else | write=something ...
|
||
|
|
* @return
|
||
|
|
*/
|
||
|
|
PermissionsPtr Permissions::createFromFlatString(const std::string &owner, const std::string &string, const std::string &authority /*= ""*/)
|
||
|
|
{
|
||
|
|
PermissionsPtr pRetVal (new Permissions ());
|
||
|
|
|
||
|
|
pRetVal->setAuthority(authority);
|
||
|
|
pRetVal->setOwner(owner);
|
||
|
|
|
||
|
|
std::vector<std::string> flatStringToks;
|
||
|
|
::SplitString(string, '|', flatStringToks);
|
||
|
|
for (unsigned int i = 0; i < flatStringToks.size(); ++i)
|
||
|
|
{
|
||
|
|
std::vector<std::string> whatParts;
|
||
|
|
if (::SplitString(flatStringToks[i], '=', whatParts) > 0)
|
||
|
|
{
|
||
|
|
std::string keyName = whatParts[0];
|
||
|
|
if (keyName == PERMISSION_KEY_OWNER)
|
||
|
|
{
|
||
|
|
if (checkUserValue(whatParts[1]))
|
||
|
|
pRetVal->_pData->setJSONValue(keyName.c_str(), whatParts[1].c_str());
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (checkPermissionKey(keyName))
|
||
|
|
{
|
||
|
|
pRetVal->_pData->setJSONArray(keyName);
|
||
|
|
JSONArray &subArrayVal = pRetVal->_pData->getJSONArray(keyName);
|
||
|
|
|
||
|
|
std::vector<std::string> whoParts;
|
||
|
|
::SplitString(whatParts[1], ',', whoParts);
|
||
|
|
for (unsigned int j = 0; j < whoParts.size(); ++j)
|
||
|
|
{
|
||
|
|
if (checkUserValue(whoParts[j]))
|
||
|
|
subArrayVal.addElement(whoParts[j]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
pRetVal->mergeDefaultPermissions();
|
||
|
|
|
||
|
|
return pRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Incoming userPermissions is of form:
|
||
|
|
* <pre>
|
||
|
|
* {
|
||
|
|
* "id": "me",
|
||
|
|
* "role": "owner",
|
||
|
|
* "selfLink": "https:\/\/www.googleapis.com\/drive\/v2\/files\/0ByK--JTHkV6AZzB5LXlpR2RnMU0\/permissions\/me",
|
||
|
|
* "type": "user",
|
||
|
|
* "etag": "\"Q0cVodxX8sh4vfxZTlOyWcmmc0k\/m7evUIvideYSbzR6BMwMo0JTKWU\"",
|
||
|
|
* "kind": "drive#permission"
|
||
|
|
* },
|
||
|
|
* </pre>
|
||
|
|
* @param userPermissions
|
||
|
|
* @param ownerAuthority - if google perms indicate ownership of file then this will be assigned to our
|
||
|
|
* owner and authority; if we are NOT the owner, then those fields are NOT set
|
||
|
|
* @return
|
||
|
|
* @see https://developers.google.com/drive/v2/reference/permissions#resource
|
||
|
|
*/
|
||
|
|
PermissionsPtr Permissions::createFromGoogleUserPermissions(const JSONObjectPtr pUserPermissions, const CloudGuardURN &ownerAuthority)
|
||
|
|
{
|
||
|
|
PermissionsPtr pRetVal (new Permissions ());
|
||
|
|
|
||
|
|
if (!pUserPermissions->empty() && (pUserPermissions->getJSONString("kind") == "drive#permission"))
|
||
|
|
{
|
||
|
|
std::string role = pUserPermissions->getJSONString("role");
|
||
|
|
std::string id = pUserPermissions->getJSONString("id");
|
||
|
|
if ((role == "owner") && (id == "me"))
|
||
|
|
{
|
||
|
|
pRetVal->setAuthority(ownerAuthority.getPMOID());
|
||
|
|
pRetVal->setOwner(ownerAuthority.getPMOID());
|
||
|
|
pRetVal->setWithAssign(PERMISSION_ADMIN, PERMISSION_VALUE_OWNER);
|
||
|
|
pRetVal->setWithAssign(PERMISSION_READ, PERMISSION_VALUE_OWNER);
|
||
|
|
pRetVal->setWithAssign(PERMISSION_WRITE, PERMISSION_VALUE_OWNER);
|
||
|
|
pRetVal->set(std::string(PERMISSION_SHOW_SHREDDED) + PERMISSION_ASSIGNMENT_SUFFIX, PERMISSION_VALUE_OWNER);
|
||
|
|
pRetVal->set(PERMISSION_STREAM, PERMISSION_VALUE_OWNER);
|
||
|
|
}
|
||
|
|
else if (role == "reader")
|
||
|
|
{
|
||
|
|
pRetVal->set(PERMISSION_READ, ownerAuthority.getPMOID());
|
||
|
|
pRetVal->set(PERMISSION_STREAM, ownerAuthority.getPMOID());
|
||
|
|
pRetVal->setWithAssign(PERMISSION_SHOW_SHREDDED, PERMISSION_VALUE_OWNER);
|
||
|
|
}
|
||
|
|
else if (role == "writer")
|
||
|
|
{
|
||
|
|
pRetVal->set(PERMISSION_READ, ownerAuthority.getPMOID());
|
||
|
|
pRetVal->set(PERMISSION_WRITE, ownerAuthority.getPMOID());
|
||
|
|
pRetVal->set(PERMISSION_STREAM, ownerAuthority.getPMOID());
|
||
|
|
pRetVal->set(std::string(PERMISSION_SHOW_SHREDDED) + PERMISSION_ASSIGNMENT_SUFFIX, PERMISSION_VALUE_OWNER);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
pRetVal->mergeDefaultPermissions();
|
||
|
|
return pRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Creates a Permission object that references ONLY a single office. Typically this office
|
||
|
|
* will be the client office.
|
||
|
|
* @param pmoUrn
|
||
|
|
* @return
|
||
|
|
*/
|
||
|
|
PermissionsPtr Permissions::createFromOffice(const CloudGuardURN &pmoUrn)
|
||
|
|
{
|
||
|
|
std::vector<CloudGuardURN> tmpUrnVec;
|
||
|
|
tmpUrnVec.push_back(pmoUrn);
|
||
|
|
return createFromUrnList(tmpUrnVec);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Creates a Permission object that references a team
|
||
|
|
* @param teamUrn
|
||
|
|
* @return
|
||
|
|
*/
|
||
|
|
PermissionsPtr Permissions::createFromTeam(const CloudGuardURN &teamUrn)
|
||
|
|
{
|
||
|
|
// Verify this is a team URN...
|
||
|
|
if ((teamUrn.getType() == CloudGuardURN::URN_TYPE::PMO_DEVICE_DOCUMENT) && (teamUrn.getDeviceID() == GROUP_DOC_DEVICE_ID))
|
||
|
|
{
|
||
|
|
std::vector<CloudGuardURN> tmpUrnVec;
|
||
|
|
tmpUrnVec.push_back(teamUrn);
|
||
|
|
return createFromUrnList(tmpUrnVec);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
return PermissionsPtr();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Given two or more URNs, create Permissions object that allows them to chat.
|
||
|
|
* At least one URN must NOT be a group.
|
||
|
|
* @param urns - at least two, with at least one being a non-group
|
||
|
|
* @return
|
||
|
|
*/
|
||
|
|
PermissionsPtr Permissions::createFromUrnList(std::vector<CloudGuardURN> &urns)
|
||
|
|
{
|
||
|
|
PermissionsPtr pRetVal (new Permissions());
|
||
|
|
|
||
|
|
// Find the first urn that is not a group urn, and set that as the owner.
|
||
|
|
CloudGuardURN ownerURN;
|
||
|
|
for (unsigned int i = 0; (ownerURN.getType() == CloudGuardURN::URN_TYPE::INVALID) && (i < urns.size()); ++i)
|
||
|
|
if (!urns[i].isGroupURN())
|
||
|
|
ownerURN = urns[i];
|
||
|
|
|
||
|
|
pRetVal->setOwner(ownerURN.getPMOID());
|
||
|
|
pRetVal->setAuthority(ownerURN.getPMOID());
|
||
|
|
// We want the same Permissions toOrderedString, with the same owner/auth, no matter
|
||
|
|
// what the order of URNs are, e.g. A,B should produce same digest as B,A
|
||
|
|
// So just sort the array.
|
||
|
|
std::sort(urns.begin(), urns.end());
|
||
|
|
|
||
|
|
for (unsigned int i = 0; i < urns.size(); ++i)
|
||
|
|
{
|
||
|
|
CloudGuardURN &urn = urns[i];
|
||
|
|
std::string pmo = urn.getPMOID();
|
||
|
|
|
||
|
|
if (urn.isGroupURN())
|
||
|
|
pmo = urn.getUrn();
|
||
|
|
|
||
|
|
pRetVal->set(std::string(PERMISSION_ADMIN) + PERMISSION_ASSIGNMENT_SUFFIX, pmo);
|
||
|
|
pRetVal->set(std::string(PERMISSION_READ) + PERMISSION_ASSIGNMENT_SUFFIX, pmo);
|
||
|
|
pRetVal->set(std::string(PERMISSION_WRITE) + PERMISSION_ASSIGNMENT_SUFFIX, pmo);
|
||
|
|
pRetVal->set(std::string(PERMISSION_SHOW_SHREDDED) + PERMISSION_ASSIGNMENT_SUFFIX, pmo);
|
||
|
|
pRetVal->set(PERMISSION_ADMIN, pmo);
|
||
|
|
pRetVal->set(PERMISSION_READ, pmo);
|
||
|
|
pRetVal->set(PERMISSION_WRITE, pmo);
|
||
|
|
|
||
|
|
// Currently, we are not allowing groups and individual users.
|
||
|
|
//if (urn.isGroupURN())
|
||
|
|
// break;
|
||
|
|
}
|
||
|
|
pRetVal->mergeDefaultPermissions();
|
||
|
|
|
||
|
|
return pRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::mergeDefaultPermissions()
|
||
|
|
{
|
||
|
|
// 1.2.8.7 removed required perms
|
||
|
|
/*
|
||
|
|
char *pPolicy = ionu_policy_check(PN_REQUIRED_PERMS);
|
||
|
|
if (pPolicy != NULL)
|
||
|
|
{
|
||
|
|
Permissions defPerms(pPolicy);
|
||
|
|
mergePermissions(this, defPerms, false);
|
||
|
|
delete [] pPolicy;
|
||
|
|
}
|
||
|
|
*/
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Guarantee consistent ordering of hash keys...
|
||
|
|
* This will not include owner key and value, and any "owner" value will be replaced by
|
||
|
|
* the actual owner ID in the output.
|
||
|
|
* @return
|
||
|
|
*/
|
||
|
|
std::string Permissions::toOrderedString() const
|
||
|
|
{
|
||
|
|
std::stringstream streamBuf;
|
||
|
|
streamBuf << "{";
|
||
|
|
std::string comma;
|
||
|
|
for (int i = 0; i < 2; ++i)
|
||
|
|
{
|
||
|
|
std::string suffix = (i == 0) ? "" : PERMISSION_ASSIGNMENT_SUFFIX;
|
||
|
|
for (int j = 0; j < NUM_PERMISSION_KEYS; ++j)
|
||
|
|
{
|
||
|
|
std::stringstream tmpBuf;
|
||
|
|
const JSONArray &perms = _pData->getJSONArray(std::string(PERMISSION_KEYS[j]) + suffix);
|
||
|
|
|
||
|
|
std::list<std::string> tmpList;
|
||
|
|
for (int k = 0; k < perms.getnumelements(); ++k)
|
||
|
|
{
|
||
|
|
std::string permVal = perms[k].getstring();
|
||
|
|
if (permVal != "")
|
||
|
|
tmpList.push_back(permVal);
|
||
|
|
}
|
||
|
|
tmpList.sort();
|
||
|
|
|
||
|
|
bool bHasOwner = false;
|
||
|
|
for (std::list<std::string>::const_iterator citer = tmpList.begin();
|
||
|
|
citer != tmpList.end(); ++citer)
|
||
|
|
{
|
||
|
|
std::string permVal = *citer;
|
||
|
|
|
||
|
|
if (permVal == getOwner())
|
||
|
|
bHasOwner = true;
|
||
|
|
|
||
|
|
if (permVal == PERMISSION_VALUE_OWNER)
|
||
|
|
{
|
||
|
|
if (bHasOwner)
|
||
|
|
// we already emitted the UUID for owner so don't do it again
|
||
|
|
// note that normal "assign" logic prevents all other duplicate values
|
||
|
|
continue;
|
||
|
|
else
|
||
|
|
permVal = getOwner();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (citer != tmpList.begin())
|
||
|
|
tmpBuf << ",";
|
||
|
|
tmpBuf << "\"" << permVal << "\"";
|
||
|
|
}
|
||
|
|
|
||
|
|
streamBuf << comma << "\"" << PERMISSION_KEYS[j] << suffix << "\":[" << tmpBuf.str() << "]";
|
||
|
|
comma = ",";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Append "topic"...
|
||
|
|
if (HasMember(TOPIC_KEY) && (_pData->getJSONString(TOPIC_KEY) != ""))
|
||
|
|
streamBuf << ",\"" << TOPIC_KEY << "\":\"" << _pData->getJSONString(TOPIC_KEY) << "\"";
|
||
|
|
streamBuf << "}";
|
||
|
|
|
||
|
|
return streamBuf.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* For UX display of short rights string.
|
||
|
|
* @param user
|
||
|
|
* @return
|
||
|
|
*/
|
||
|
|
std::string Permissions::toRightsString(const std::string &user) const
|
||
|
|
{
|
||
|
|
std::stringstream streamBuf;
|
||
|
|
streamBuf << rightsString(PERMISSION_READ, user);
|
||
|
|
streamBuf << rightsString(PERMISSION_WRITE, user);
|
||
|
|
streamBuf << rightsString(PERMISSION_DOORWAY, user);
|
||
|
|
streamBuf << rightsString(PERMISSION_STREAM, user);
|
||
|
|
streamBuf << rightsString(PERMISSION_ADMIN, user);
|
||
|
|
return streamBuf.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::rightsString(const std::string &perm, const std::string &user) const
|
||
|
|
{
|
||
|
|
bool r = can(*this, perm, user);
|
||
|
|
bool ra = can(*this, perm+PERMISSION_ASSIGNMENT_SUFFIX, user);
|
||
|
|
// r+w+d+a+ or r+w d -; e.g. {right|-}[+ ]...
|
||
|
|
return (r ? perm.substr(0, 1) : "-") +
|
||
|
|
(ra ? "+" : " ");
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::getPermittedRightsSignature()
|
||
|
|
{
|
||
|
|
std::string str = toOrderedString();
|
||
|
|
//LibIOnU ionu = new LibIOnU();
|
||
|
|
//String dig = ionu.md5(str);
|
||
|
|
std::string dig = DigestMessage(MESSAGE_DIGEST_MD5, reinterpret_cast<unsigned const char *>(str.c_str()), str.length());
|
||
|
|
dig = dig.substr(0, 12);
|
||
|
|
return dig;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::getSignature(const CloudGuardURN &van) const
|
||
|
|
{
|
||
|
|
return getUserAndGroupSig(van);
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::getUserAndGroupSig(const CloudGuardURN &van) const
|
||
|
|
{
|
||
|
|
std::string refs = getOrderedReferences(van);
|
||
|
|
std::string digest = DigestMessage(MESSAGE_DIGEST_MD5, reinterpret_cast<unsigned const char *>(refs.c_str()), refs.length());
|
||
|
|
digest = digest.substr(0, 12);
|
||
|
|
return digest;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::getPermittedRightsSig() const
|
||
|
|
{
|
||
|
|
std::string str = toOrderedString();
|
||
|
|
std::string digest = DigestMessage(MESSAGE_DIGEST_MD5, reinterpret_cast<unsigned const char *>(str.c_str()), str.length());
|
||
|
|
digest = digest.substr(0, 12);
|
||
|
|
return digest;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::getOrderedReferences(const CloudGuardURN &van) const
|
||
|
|
{
|
||
|
|
CloudGuardURNSet allRefs;
|
||
|
|
getAllReferences(van, allRefs);
|
||
|
|
std::stringstream allRefsStr;
|
||
|
|
for (CloudGuardURNSetIter iter = allRefs.begin(); iter != allRefs.end(); ++iter)
|
||
|
|
{
|
||
|
|
if (iter != allRefs.begin())
|
||
|
|
allRefsStr << "|";
|
||
|
|
allRefsStr << iter->getUrn();
|
||
|
|
}
|
||
|
|
return allRefsStr.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::getSignaturePath(const CloudGuardURN &van) const
|
||
|
|
{
|
||
|
|
std::string dig = getSignature(van);
|
||
|
|
return ::getSignaturePath(dig);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::getPermittedItems(const CloudGuardURN &van, JSONArray &permittedItems) const
|
||
|
|
{
|
||
|
|
permittedItems.clear();
|
||
|
|
createPermittedItem(PERMISSION_VALUE_OWNER, CloudGuardURN(van.getVANID(), getOwner()).getUrn(), permittedItems);
|
||
|
|
//createPermittedItem(PERMISSION_VALUE_ALL, "", permittedItems);
|
||
|
|
|
||
|
|
std::set<CloudGuardURN> urnSet;
|
||
|
|
getReferencedGroups(urnSet);
|
||
|
|
for (std::set<CloudGuardURN>::const_iterator citer = urnSet.begin();
|
||
|
|
citer != urnSet.end();
|
||
|
|
++citer)
|
||
|
|
{
|
||
|
|
createPermittedItem("group", citer->getUrn(), permittedItems);
|
||
|
|
}
|
||
|
|
|
||
|
|
getReferencedUsers(van, urnSet);
|
||
|
|
for (std::set<CloudGuardURN>::const_iterator citer = urnSet.begin();
|
||
|
|
citer != urnSet.end();
|
||
|
|
++citer)
|
||
|
|
{
|
||
|
|
createPermittedItem("user", citer->getUrn(), permittedItems);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Gets a set of referenced user values. This does NOT reference 'mbrs' data but inspects
|
||
|
|
* individual rights.
|
||
|
|
* @param van tell us what van we are operating within
|
||
|
|
* @param Return set, possibly empty list of group document URN's
|
||
|
|
*/
|
||
|
|
void Permissions::getReferencedUsers(const CloudGuardURN &van, std::set<CloudGuardURN> &referencedUsers) const
|
||
|
|
{
|
||
|
|
referencedUsers.clear();
|
||
|
|
for (int i = 0; i < NUM_PERMISSION_KEYS; ++i)
|
||
|
|
{
|
||
|
|
addReferences(_pData->getJSONArray(PERMISSION_KEYS[i]), referencedUsers, van);
|
||
|
|
addReferences(_pData->getJSONArray(std::string(PERMISSION_KEYS[i])+PERMISSION_ASSIGNMENT_SUFFIX), referencedUsers, van);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Gets a set of referenced group values. This does NOT reference 'mbrs' data but inspects
|
||
|
|
* individual rights.
|
||
|
|
* @param Return set, possibly empty list of group document URN's
|
||
|
|
*/
|
||
|
|
void Permissions::getReferencedGroups(std::set<CloudGuardURN> &referencedGroups) const
|
||
|
|
{
|
||
|
|
referencedGroups.clear();
|
||
|
|
for (int i = 0; i < NUM_PERMISSION_KEYS; ++i)
|
||
|
|
{
|
||
|
|
addReferences(_pData->getJSONArray(PERMISSION_KEYS[i]), referencedGroups);
|
||
|
|
addReferences(_pData->getJSONArray(std::string(PERMISSION_KEYS[i])+PERMISSION_ASSIGNMENT_SUFFIX), referencedGroups);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get all references, both users and groups (you need to check the group device ID to see what's
|
||
|
|
* a group and what is a normal user).
|
||
|
|
* @param van
|
||
|
|
*/
|
||
|
|
void Permissions::getAllReferences(const CloudGuardURN &van, std::set<CloudGuardURN> &allReferences) const
|
||
|
|
{
|
||
|
|
allReferences.clear();
|
||
|
|
getReferencedUsers(van, allReferences);
|
||
|
|
std::set<CloudGuardURN> tmpRefs;
|
||
|
|
getReferencedGroups(tmpRefs);
|
||
|
|
std::copy(tmpRefs.begin(), tmpRefs.end(), std::inserter(allReferences, allReferences.begin()));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Same results as getAllReferences but in JSONArray format with each element being a string.
|
||
|
|
* @param van
|
||
|
|
* @return
|
||
|
|
*/
|
||
|
|
JSONArrayPtr Permissions::getAllReferencesAsStringArray (const CloudGuardURN &vanUrn) const
|
||
|
|
{
|
||
|
|
std::set<CloudGuardURN> allRefs;
|
||
|
|
getAllReferences(vanUrn, allRefs);
|
||
|
|
JSONArrayPtr pRetVal (new JSONArray());
|
||
|
|
for (std::set<CloudGuardURN>::iterator iter = allRefs.begin(); iter != allRefs.end(); ++iter)
|
||
|
|
pRetVal->addElement(iter->getUrn());
|
||
|
|
return pRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Updates members array by adding all unique UUID values referenced by this object and
|
||
|
|
* any referenced groups. Membership simply means that you are named in a *some* permission.
|
||
|
|
* It's useful for indexing and having a list of everyone who can interact with a document.
|
||
|
|
*
|
||
|
|
* @param van - tell us van we are operating within
|
||
|
|
* @param groupMap - null (no group resolution) or map of group doc URN to UUID values.
|
||
|
|
* @param Return set of members (PMO urn's) - internal 'mbrs' array is also set on this object
|
||
|
|
*/
|
||
|
|
void Permissions::updateMembers(const CloudGuardURN &van, const CloudGuardURNToURNSetMap &groupMap, CloudGuardURNSet &curMembers)
|
||
|
|
{
|
||
|
|
curMembers.clear();
|
||
|
|
for (int i = 0; i < NUM_PERMISSION_KEYS; ++i)
|
||
|
|
{
|
||
|
|
collectMembers(van, groupMap, _pData->getJSONArray(PERMISSION_KEYS[i]), curMembers);
|
||
|
|
collectMembers(van, groupMap, _pData->getJSONArray(std::string(PERMISSION_KEYS[i])+PERMISSION_ASSIGNMENT_SUFFIX), curMembers);
|
||
|
|
}
|
||
|
|
|
||
|
|
_pData->setJSONArray(PERMISSION_MEMBERS_KEY);
|
||
|
|
JSONArray &newMembers = _pData->getJSONArray(PERMISSION_MEMBERS_KEY);
|
||
|
|
|
||
|
|
for (CloudGuardURNSetIter urnIter = curMembers.begin(); urnIter != curMembers.end(); ++urnIter)
|
||
|
|
newMembers.addElement(urnIter->getUrn());
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::setOwner(const std::string &owner)
|
||
|
|
{
|
||
|
|
if (checkUserValue(owner))
|
||
|
|
_pData->setJSONValue(PERMISSION_KEY_OWNER, owner.c_str());
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::getOwner() const
|
||
|
|
{
|
||
|
|
return _pData->getJSONString(PERMISSION_KEY_OWNER);
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::getName() const
|
||
|
|
{
|
||
|
|
return _pData->getJSONString(PERMISSION_NAME_KEY);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::setName(const std::string &name)
|
||
|
|
{
|
||
|
|
_pData->setJSONValue(PERMISSION_NAME_KEY, name.c_str());
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::getType() const
|
||
|
|
{
|
||
|
|
return _pData->getJSONString(PERMISSION_TYPE_KEY, "file");
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Permissions::canRead(const std::string &user) const
|
||
|
|
{
|
||
|
|
return can(*this, PERMISSION_READ, user);
|
||
|
|
}
|
||
|
|
bool Permissions::canWrite(const std::string &user) const
|
||
|
|
{
|
||
|
|
return can(*this, PERMISSION_WRITE, user);
|
||
|
|
}
|
||
|
|
bool Permissions::isAdmin(const std::string &user) const
|
||
|
|
{
|
||
|
|
return can(*this, PERMISSION_ADMIN, user);
|
||
|
|
}
|
||
|
|
bool Permissions::canDoorway(const std::string &user) const
|
||
|
|
{
|
||
|
|
return can(*this, PERMISSION_DOORWAY, user);
|
||
|
|
}
|
||
|
|
bool Permissions::canStream(const std::string &user) const
|
||
|
|
{
|
||
|
|
return can(*this, PERMISSION_STREAM, user);
|
||
|
|
}
|
||
|
|
bool Permissions::canHide(const std::string &user) const
|
||
|
|
{
|
||
|
|
return can(*this, PERMISSION_SHOW_SHREDDED, user);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Permissions::assignRead(const std::string &user)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_READ, _authority, user);
|
||
|
|
}
|
||
|
|
bool Permissions::assignRead(const std::vector<std::string> &users)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_READ, _authority, users);
|
||
|
|
}
|
||
|
|
bool Permissions::assignWrite(const std::string &user)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_WRITE, _authority, user);
|
||
|
|
}
|
||
|
|
bool Permissions::assignWrite(const std::vector<std::string> &users)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_WRITE, _authority, users);
|
||
|
|
}
|
||
|
|
bool Permissions::assignAdmin(const std::string &user)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_ADMIN, _authority, user);
|
||
|
|
}
|
||
|
|
bool Permissions::assignAdmin(const std::vector<std::string> &users)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_ADMIN, _authority, users);
|
||
|
|
}
|
||
|
|
bool Permissions::assignDoorway(const std::string &user)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_DOORWAY, _authority, user);
|
||
|
|
}
|
||
|
|
bool Permissions::assignDoorway(const std::vector<std::string> &users)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_DOORWAY, _authority, users);
|
||
|
|
}
|
||
|
|
bool Permissions::assignStream(const std::string &user)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_STREAM, _authority, user);
|
||
|
|
}
|
||
|
|
bool Permissions::assignStream(const std::vector<std::string> &users)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_STREAM, _authority, users);
|
||
|
|
}
|
||
|
|
bool Permissions::assignHide(const std::string &user)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_SHOW_SHREDDED, _authority, user);
|
||
|
|
}
|
||
|
|
bool Permissions::assignHide(const std::vector<std::string> &users)
|
||
|
|
{
|
||
|
|
return assign(_pData.get(), PERMISSION_SHOW_SHREDDED, _authority, users);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Merge, or copy, perms into this permissions object.
|
||
|
|
*/
|
||
|
|
void Permissions::simpleMerge(const Permissions &perms)
|
||
|
|
{
|
||
|
|
mergePermissions(this, perms, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
PermissionsPtr Permissions::merge(const Permissions &permissions)
|
||
|
|
{
|
||
|
|
PermissionsPtr pRetVal(new Permissions(*this));
|
||
|
|
mergePermissions(pRetVal.get(), permissions, true);
|
||
|
|
return pRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::mergePermissions(Permissions *pDest, const Permissions &src, bool bAssign)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < 2; ++i)
|
||
|
|
{
|
||
|
|
std::string suffix = (i == 0) ? "" : PERMISSION_ASSIGNMENT_SUFFIX;
|
||
|
|
for (int j = 0; j < NUM_PERMISSION_KEYS; ++j)
|
||
|
|
{
|
||
|
|
const JSONArray &oldArray = src._pData->getJSONArray(std::string(PERMISSION_KEYS[j]) + suffix);
|
||
|
|
if (oldArray.empty())
|
||
|
|
continue;
|
||
|
|
for (int i = 0; i < oldArray.getnumelements(); ++i)
|
||
|
|
{
|
||
|
|
std::string oldVal = oldArray[i].getstring();
|
||
|
|
if (bAssign)
|
||
|
|
assign(*pDest, PERMISSION_KEYS[j], pDest->_authority, oldVal);
|
||
|
|
else
|
||
|
|
pDest->set(PERMISSION_KEYS[j], oldVal);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set a value, and it's 'assign' counterpart.
|
||
|
|
*/
|
||
|
|
void Permissions::setWithAssign(const std::string &perm, const std::string &user)
|
||
|
|
{
|
||
|
|
set(perm, user);
|
||
|
|
set(perm+PERMISSION_ASSIGNMENT_SUFFIX, user);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::removeWithAssign(const std::string &perm, const std::string &user)
|
||
|
|
{
|
||
|
|
remove(perm, user);
|
||
|
|
remove(perm+PERMISSION_ASSIGNMENT_SUFFIX, user);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set the indicated permission, ignoring any access/assignment rights checking.
|
||
|
|
* @param perm
|
||
|
|
* @param user - no validation is performed on this value
|
||
|
|
*/
|
||
|
|
void Permissions::set(const std::string &perm, const std::string &user)
|
||
|
|
{
|
||
|
|
if (checkPermissionKey(perm) &&
|
||
|
|
checkUserValue(user) &&
|
||
|
|
checkGroupTopology(getType(), user))
|
||
|
|
{
|
||
|
|
_pData->setJSONArray(perm);
|
||
|
|
JSONArray &permVal = _pData->getJSONArray(perm);
|
||
|
|
|
||
|
|
// It is an array.
|
||
|
|
bool bFoundVal = false;
|
||
|
|
for (int i = 0; i < permVal.getnumelements(); ++i)
|
||
|
|
{
|
||
|
|
std::string tmpVal = permVal[i].getstring();
|
||
|
|
bFoundVal = (user == tmpVal);
|
||
|
|
}
|
||
|
|
if (!bFoundVal)
|
||
|
|
permVal.addElement(user);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Remove the indicated permission, ignoring any access/assignment rights checking.
|
||
|
|
* @param perm
|
||
|
|
* @param user
|
||
|
|
*/
|
||
|
|
void Permissions::remove(const std::string &perm, const std::string &user)
|
||
|
|
{
|
||
|
|
if (checkPermissionKey(perm) && checkUserValue(user))
|
||
|
|
{
|
||
|
|
if (_pData->search(perm.c_str()) != NULL)
|
||
|
|
{
|
||
|
|
JSONArray &permArray = _pData->getJSONArray(perm);
|
||
|
|
permArray.removeElement(user);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
mergeDefaultPermissions();
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::setType(const std::string &type)
|
||
|
|
{
|
||
|
|
if (type == "")
|
||
|
|
_pData->erase(PERMISSION_TYPE_KEY);
|
||
|
|
else if (std::string(PERMISSION_TYPE_VALUES).find(type) != std::string::npos)
|
||
|
|
_pData->setJSONValue(PERMISSION_TYPE_KEY, type.c_str());
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::collectMembers(const CloudGuardURN &van, const CloudGuardURNToURNSetMap &groupMap, const JSONArray &permArray, CloudGuardURNSet &mbrs)
|
||
|
|
{
|
||
|
|
if (permArray.empty())
|
||
|
|
return;
|
||
|
|
|
||
|
|
for (int i = 0; i < permArray.getnumelements(); ++i)
|
||
|
|
{
|
||
|
|
std::string memberStr = permArray[i].getstring();
|
||
|
|
if (memberStr != "")
|
||
|
|
{
|
||
|
|
if (memberStr.find(CloudGuardURN::NAMESPACE) == 0)
|
||
|
|
{
|
||
|
|
if (!groupMap.empty())
|
||
|
|
{
|
||
|
|
//memberStr = memberStr.substr(sizeof(PERMISSION_GROUP_PREFIX)-1);
|
||
|
|
CloudGuardURN groupKey (memberStr);
|
||
|
|
CloudGuardURNToURNSetMapCIter mapIter = groupMap.find(groupKey);
|
||
|
|
if (mapIter == groupMap.end())
|
||
|
|
{
|
||
|
|
// Aparrently, this is bad. According to the comments in the Java code:
|
||
|
|
// "bad programmer, didn't call getReferencedGroups and then iterate DB and resolve each"
|
||
|
|
//std::stringstream msg;
|
||
|
|
//msg << "In Permissions::collectMembers: expect: " << groupKey.getUrn() << " /" << groupKey.getUrn() << std::endl;
|
||
|
|
//for (mapIter = groupMap.begin(); mapIter != groupMap.end(); ++mapIter)
|
||
|
|
// msg << " has: " << mapIter->first.getUrn() << " /" << mapIter->first.getUrn() << std::endl;
|
||
|
|
//IONUWebService::logDebug("%s", msg.str().c_str());
|
||
|
|
}
|
||
|
|
else
|
||
|
|
std::copy(mapIter->second.begin(), mapIter->second.end(), std::inserter(mbrs, mbrs.begin()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (memberStr == PERMISSION_VALUE_OWNER)
|
||
|
|
mbrs.insert(CloudGuardURN(van.getVANID(), getOwner()));
|
||
|
|
//else if (memberStr == Permissions::PERMISSION_VALUE_ALL)
|
||
|
|
// mbrs.insert(CloudGuardURN(van.getVANID(), CloudGuardURN::PMO_ALL_ID));
|
||
|
|
else
|
||
|
|
// uuid
|
||
|
|
mbrs.insert(CloudGuardURN(van.getVANID(), memberStr));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//////////// static: can be used on Permissions or raw JSONObject
|
||
|
|
/**
|
||
|
|
* Does the user have the indicated permission?
|
||
|
|
* @param obj
|
||
|
|
* @param perm either a perm (read) or assignment (readAssign)
|
||
|
|
* @param user
|
||
|
|
* @return
|
||
|
|
*/
|
||
|
|
bool Permissions::can(const Permissions &obj, const std::string &perm, const std::string &user, std::string *pWhyReturn /*= NULL*/)
|
||
|
|
{
|
||
|
|
std::string tmpUser = user;
|
||
|
|
bool bRemove = ((tmpUser != "") && (tmpUser[0] == '-'));
|
||
|
|
if ((tmpUser != "") && ((tmpUser[0] == '+') || (tmpUser[0] == '-')))
|
||
|
|
tmpUser.erase(tmpUser.begin());
|
||
|
|
return can(obj._pData.get(), perm, tmpUser, bRemove, pWhyReturn);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Permissions::can(const JSONObject *pObj, const std::string &perm, const std::string &user, bool bRemove, std::string *pWhyReturn /*= NULL*/)
|
||
|
|
{
|
||
|
|
bool bRetVal = (checkPermissionKey(perm) && checkUserValue(user));
|
||
|
|
|
||
|
|
if ((pObj != NULL) && bRetVal)
|
||
|
|
{
|
||
|
|
bRetVal = false;
|
||
|
|
if (pObj->search(perm.c_str()) == NULL)
|
||
|
|
const_cast<JSONObject *>(pObj)->setJSONArray(perm);
|
||
|
|
const JSONArray &permArray = pObj->getJSONArray(perm);
|
||
|
|
std::string owner = pObj->getJSONString(PERMISSION_KEY_OWNER);
|
||
|
|
std::string why = "not permitted";
|
||
|
|
|
||
|
|
if (permArray.empty() && (perm.find(PERMISSION_ASSIGNMENT_SUFFIX) != std::string::npos))
|
||
|
|
{
|
||
|
|
// Perms array must not exist. Older files will not have the 'hideAssign', and possibly
|
||
|
|
// others in the future.
|
||
|
|
// For now, create the missing '...Assign' perm based on the write permissions.
|
||
|
|
const JSONArray &writeArray = pObj->getJSONArray(PERMISSION_WRITE);
|
||
|
|
const_cast<JSONArray &>(permArray) = writeArray;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!bRetVal)
|
||
|
|
{
|
||
|
|
Permissions tmpPerms;
|
||
|
|
tmpPerms.mergeDefaultPermissions();
|
||
|
|
for (int i = 0; i < permArray.getnumelements(); ++i)
|
||
|
|
{
|
||
|
|
std::string permMember = permArray[i].getstring();
|
||
|
|
if (bRemove &&
|
||
|
|
tmpPerms.HasMember(perm) &&
|
||
|
|
(tmpPerms._pData->getJSONArray(perm).getnumelements() > 0) &&
|
||
|
|
(tmpPerms._pData->getJSONArray(perm).hasString(permMember)))
|
||
|
|
{
|
||
|
|
bRetVal = false;
|
||
|
|
why = "cannot remove default permission";
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
else if ((permMember == PERMISSION_VALUE_OWNER) && (owner == user))
|
||
|
|
{
|
||
|
|
bRetVal = true;
|
||
|
|
why = "is owner";
|
||
|
|
}
|
||
|
|
else if (permMember == user)
|
||
|
|
{
|
||
|
|
bRetVal = true;
|
||
|
|
why = "is named user";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (pWhyReturn != NULL)
|
||
|
|
*pWhyReturn += why;
|
||
|
|
}
|
||
|
|
|
||
|
|
return bRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Permissions::canAssign(const JSONObject *pObj, const std::string &perm, const std::string &user)
|
||
|
|
{
|
||
|
|
return can(pObj, perm+std::string(PERMISSION_ASSIGNMENT_SUFFIX), user, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Assign 'perm' to 'user', but only if 'auth' has assign* priv.
|
||
|
|
* @param obj - Permissions object
|
||
|
|
* @param perm -
|
||
|
|
* @param auth
|
||
|
|
* @param user - no validation is performed on this value
|
||
|
|
* @return true if assignment successful; false if it was not
|
||
|
|
*/
|
||
|
|
bool Permissions::assign(JSONObject *pObj, const std::string &perm, const std::string &auth, const std::string &user)
|
||
|
|
{
|
||
|
|
if (pObj == NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
if (!checkPermissionKey(perm))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
std::string trimUser = user;
|
||
|
|
if ((trimUser[0] == '-') || (trimUser[0] == '+'))
|
||
|
|
trimUser.erase(0, 1);
|
||
|
|
|
||
|
|
if (!checkUserValue(trimUser))
|
||
|
|
return false;
|
||
|
|
if (!checkGroupTopology(pObj->getJSONString("type", "file"), trimUser))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// check *Assign unless we are trying to assign/update a *Assign field in which
|
||
|
|
// we check adminAssign
|
||
|
|
std::string asn;
|
||
|
|
if ((perm.find(PERMISSION_ASSIGNMENT_SUFFIX) == std::string::npos) && (perm != PERMISSION_ADMIN))
|
||
|
|
// read/write/doorway/stream/hide => *Assign required
|
||
|
|
asn = perm + PERMISSION_ASSIGNMENT_SUFFIX;
|
||
|
|
else if (perm == PERMISSION_ADMIN)
|
||
|
|
// admin => admin
|
||
|
|
asn = PERMISSION_ADMIN;
|
||
|
|
else if (perm == (std::string(PERMISSION_ADMIN) + PERMISSION_ASSIGNMENT_SUFFIX))
|
||
|
|
// adminAssign => adminAssign
|
||
|
|
asn = perm;
|
||
|
|
else
|
||
|
|
// readAssign/writeAssign/doorwayAssign => admin
|
||
|
|
asn = PERMISSION_ADMIN;
|
||
|
|
|
||
|
|
bool bRetVal = can(Permissions(*pObj), asn, auth);
|
||
|
|
if (bRetVal)
|
||
|
|
{
|
||
|
|
pObj->setJSONArray(perm);
|
||
|
|
JSONArray &permArray = pObj->getJSONArray(perm);
|
||
|
|
if (user.find('-') == 0)
|
||
|
|
permArray.removeElement(trimUser);
|
||
|
|
else
|
||
|
|
permArray.addElement(trimUser);
|
||
|
|
}
|
||
|
|
else if (can(Permissions(*pObj), perm, trimUser))
|
||
|
|
bRetVal = true; // since the perm already exists, do not fail if authority cannot assign it
|
||
|
|
|
||
|
|
return bRetVal;
|
||
|
|
}
|
||
|
|
bool Permissions::assign(JSONObject *pObj, const std::string &perm, const std::string &auth, const std::vector<std::string> &users)
|
||
|
|
{
|
||
|
|
bool bRetVal = true;
|
||
|
|
for (unsigned int i = 0; bRetVal && (i < users.size()); ++i)
|
||
|
|
bRetVal &= assign(pObj, perm, auth, users[i]);
|
||
|
|
return bRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Permissions::HasMember(const std::string &memberName) const
|
||
|
|
{
|
||
|
|
return (_pData->search(memberName.c_str()) != NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string Permissions::toString() const
|
||
|
|
{
|
||
|
|
return _pData->toString();
|
||
|
|
}
|
||
|
|
|
||
|
|
JSONArray Permissions::getUserArray(const std::string &arrayName) const
|
||
|
|
{
|
||
|
|
return _pData->getJSONArray(arrayName);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Permissions::LoadFromFile(const std::string &fileName)
|
||
|
|
{
|
||
|
|
return _pData->LoadFromFile(fileName);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Permissions::SaveToFile(const std::string &fileName) const
|
||
|
|
{
|
||
|
|
return _pData->SaveToFile(fileName);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::setKeys(const JSONArray &keys)
|
||
|
|
{
|
||
|
|
_pData->setJSONValue(KEYS_KEY, keys);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Permissions::hasKeys() const
|
||
|
|
{
|
||
|
|
return (_pData->search(KEYS_KEY) != NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Permissions::clearKeys()
|
||
|
|
{
|
||
|
|
_pData->erase(KEYS_KEY);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Permissions::isEmpty() const
|
||
|
|
{
|
||
|
|
bool bRetVal = _pData->empty();
|
||
|
|
if (!bRetVal)
|
||
|
|
{
|
||
|
|
// Check that the arrays are empty...
|
||
|
|
bRetVal = true;
|
||
|
|
for (int i = 0; bRetVal && (i < NUM_PERMISSION_KEYS); ++i)
|
||
|
|
{
|
||
|
|
std::string keyName = PERMISSION_KEYS[i];
|
||
|
|
const JSONArray &permArray = _pData->getJSONArray(keyName);
|
||
|
|
bRetVal &= (permArray.getnumelements() == 0);
|
||
|
|
keyName += PERMISSION_ASSIGNMENT_SUFFIX;
|
||
|
|
const JSONArray &permAssignArray = _pData->getJSONArray(keyName);
|
||
|
|
bRetVal &= (permAssignArray.getnumelements() == 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return bRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get a list of users, based on a permission key.
|
||
|
|
*/
|
||
|
|
void Permissions::getUsers(const CloudGuardURN &van, const std::string &key, std::vector<CloudGuardURN> &users) const
|
||
|
|
{
|
||
|
|
users.clear();
|
||
|
|
|
||
|
|
const JSONArray &keyArray = _pData->getJSONArray(key);
|
||
|
|
for (int i = 0; i < keyArray.getnumelements(); ++i)
|
||
|
|
{
|
||
|
|
std::string userStr = keyArray[i].getstring();
|
||
|
|
if (userStr.find(CloudGuardURN::NAMESPACE) == 0)
|
||
|
|
users.push_back(CloudGuardURN(userStr));
|
||
|
|
else
|
||
|
|
users.push_back(CloudGuardURN(van.getVANID(), userStr, "", ""));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
bool checkUserValue(const std::string &value)
|
||
|
|
{
|
||
|
|
std::string upperCaseValue = value;
|
||
|
|
if (upperCaseValue.find(CloudGuardURN::NAMESPACE) == 0)
|
||
|
|
std::transform(upperCaseValue.begin()+::strlen(CloudGuardURN::NAMESPACE), upperCaseValue.end(),
|
||
|
|
upperCaseValue.begin()+::strlen(CloudGuardURN::NAMESPACE), std::bind2nd(std::ptr_fun(std::toupper<std::string::value_type>), std::locale()));
|
||
|
|
else
|
||
|
|
std::transform(upperCaseValue.begin(), upperCaseValue.end(), upperCaseValue.begin(), std::bind2nd(
|
||
|
|
std::ptr_fun(std::toupper<std::string::value_type>), std::locale()));
|
||
|
|
|
||
|
|
bool bRetVal = (value == PERMISSION_VALUE_OWNER);
|
||
|
|
if (!bRetVal)
|
||
|
|
{
|
||
|
|
bRetVal = true;
|
||
|
|
size_t i = 0;
|
||
|
|
bool bPermissionGroup = (upperCaseValue.find(CloudGuardURN::NAMESPACE) == 0);
|
||
|
|
if (bPermissionGroup)
|
||
|
|
i = ::strlen(CloudGuardURN::NAMESPACE) - 1;
|
||
|
|
for (; bRetVal && (i < upperCaseValue.length()); ++i)
|
||
|
|
{
|
||
|
|
char tmpChar = upperCaseValue[i];
|
||
|
|
bRetVal = (std::isdigit(tmpChar, std::locale()) ||
|
||
|
|
(('A' <= tmpChar) && (tmpChar <= 'F'))) ||
|
||
|
|
(bPermissionGroup && (tmpChar == ':'));
|
||
|
|
}
|
||
|
|
if (bRetVal)
|
||
|
|
// Check lengths...
|
||
|
|
bRetVal = ((upperCaseValue.length() == SL_USER_ID_LENGTH) ||
|
||
|
|
(upperCaseValue.length() == static_cast<unsigned int>(CloudGuardURN::NSS_LENGTH))) ||
|
||
|
|
(bPermissionGroup && (upperCaseValue.length() == CloudGuardURN::NSS_LENGTH + ::strlen(CloudGuardURN::NAMESPACE)));
|
||
|
|
}
|
||
|
|
return bRetVal;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string getSignaturePath(const std::string &digest)
|
||
|
|
{
|
||
|
|
std::stringstream streamBuf;
|
||
|
|
if (digest.length() >= 12)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < 12; i += 3)
|
||
|
|
{
|
||
|
|
if (i > 0)
|
||
|
|
streamBuf << "/";
|
||
|
|
streamBuf << digest.substr(i, 3);
|
||
|
|
}
|
||
|
|
streamBuf << digest.substr(12);
|
||
|
|
}
|
||
|
|
return streamBuf.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
// will behave as if it is a StorageNode
|
||
|
|
void createPermittedItem(const std::string &metaType, const std::string &urn, JSONArray &itemArray)
|
||
|
|
{
|
||
|
|
JSONObject node;
|
||
|
|
node.setJSONValue( "name", ""); // caller must resolve
|
||
|
|
node.setJSONValue("path", urn.c_str());
|
||
|
|
node.setJSONValue("metatype", metaType.c_str());
|
||
|
|
node.setJSONValue("type", "SNT_ACTION"); // avoid pulling in StorageNodeType import
|
||
|
|
node.setJSONValue("status", "informational"); // ... StorageNodeStatus
|
||
|
|
itemArray.addElement(node);
|
||
|
|
}
|
||
|
|
|
||
|
|
// van null -> only groups; van non-null -> only users
|
||
|
|
void addReferences(const JSONArray &permArray, std::set<CloudGuardURN> &list, const CloudGuardURN &van /*= CloudGuardURN()*/)
|
||
|
|
{
|
||
|
|
if (permArray.empty())
|
||
|
|
return;
|
||
|
|
|
||
|
|
for (int i = 0; i < permArray.getnumelements(); ++i)
|
||
|
|
{
|
||
|
|
std::string objStr = permArray[i].getstring();
|
||
|
|
if ((van.getType() == CloudGuardURN::INVALID) && (objStr.find(CloudGuardURN::NAMESPACE) == 0))
|
||
|
|
list.insert(objStr);
|
||
|
|
else if ( (objStr != "") && (van.getType() != CloudGuardURN::INVALID) &&
|
||
|
|
(objStr.find(CloudGuardURN::NAMESPACE) != 0) &&
|
||
|
|
(objStr != PERMISSION_VALUE_OWNER) )/* &&
|
||
|
|
(objStr != Permissions::PERMISSION_VALUE_ALL) )*/
|
||
|
|
{
|
||
|
|
CloudGuardURN urn (van.getVANID(), objStr);
|
||
|
|
list.insert(urn);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int SplitString(const std::string &strToSplit, const char ch, std::vector<std::string> &splitStrings)
|
||
|
|
{
|
||
|
|
int nRetVal = 0;
|
||
|
|
splitStrings.clear();
|
||
|
|
|
||
|
|
std::string::size_type nStart = 0;
|
||
|
|
while (strToSplit.find(ch, nStart) != std::string::npos)
|
||
|
|
{
|
||
|
|
splitStrings.push_back(strToSplit.substr(nStart, strToSplit.find(ch, nStart) - nStart));
|
||
|
|
++nRetVal;
|
||
|
|
nStart = strToSplit.find(ch, nStart)+1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check for a last arg...
|
||
|
|
if (nStart <= strToSplit.length())
|
||
|
|
{
|
||
|
|
splitStrings.push_back(strToSplit.substr(nStart));
|
||
|
|
++nRetVal;
|
||
|
|
}
|
||
|
|
return nRetVal;
|
||
|
|
}
|
||
|
|
}
|