// 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 #else #include #endif #include #include #include #include #include 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 &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 &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 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 flatStringToks; ::SplitString(string, '|', flatStringToks); for (unsigned int i = 0; i < flatStringToks.size(); ++i) { std::vector 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 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: *
	* {
	*   "id": "me",
	*   "role": "owner",
	*   "selfLink": "https:\/\/www.googleapis.com\/drive\/v2\/files\/0ByK--JTHkV6AZzB5LXlpR2RnMU0\/permissions\/me",
	*   "type": "user",
	*   "etag": "\"Q0cVodxX8sh4vfxZTlOyWcmmc0k\/m7evUIvideYSbzR6BMwMo0JTKWU\"",
	*   "kind": "drive#permission"
	* },
	* 
* @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 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 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 &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 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::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(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(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(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 urnSet; getReferencedGroups(urnSet); for (std::set::const_iterator citer = urnSet.begin(); citer != urnSet.end(); ++citer) { createPermittedItem("group", citer->getUrn(), permittedItems); } getReferencedUsers(van, urnSet); for (std::set::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 &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 &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 &allReferences) const { allReferences.clear(); getReferencedUsers(van, allReferences); std::set 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 allRefs; getAllReferences(vanUrn, allRefs); JSONArrayPtr pRetVal (new JSONArray()); for (std::set::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 &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 &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 &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 &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 &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 &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(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(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 &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 &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::locale())); else std::transform(upperCaseValue.begin(), upperCaseValue.end(), upperCaseValue.begin(), std::bind2nd( std::ptr_fun(std::toupper), 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(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 &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 &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; } }