virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { ActionSet actions; actions.addAction(ActionType::listCollections); out->push_back(Privilege(ResourcePattern::forDatabaseName(dbname), actions)); }
Privilege AuthorizationSession::_modifyPrivilegeForSpecialCases(const Privilege& privilege) { ActionSet newActions; newActions.addAllActionsFromSet(privilege.getActions()); NamespaceString ns( privilege.getResource() ); if (ns.coll() == "system.users") { if (newActions.contains(ActionType::insert) || newActions.contains(ActionType::update) || newActions.contains(ActionType::remove)) { // End users can't modify system.users directly, only the system can. newActions.addAction(ActionType::userAdminV1); } else { newActions.addAction(ActionType::userAdmin); } newActions.removeAction(ActionType::find); newActions.removeAction(ActionType::insert); newActions.removeAction(ActionType::update); newActions.removeAction(ActionType::remove); } else if (ns.coll() == "system.profile") { newActions.removeAction(ActionType::find); newActions.addAction(ActionType::profileRead); } else if (ns.coll() == "system.indexes" && newActions.contains(ActionType::find)) { newActions.removeAction(ActionType::find); newActions.addAction(ActionType::indexRead); } return Privilege(privilege.getResource(), newActions); }
bool AuthorizationManager::checkAuthorization(const std::string& resource, ActionSet actions) { if (_externalState->shouldIgnoreAuthChecks()) return true; return _acquiredPrivileges.hasPrivilege(Privilege(nsToDatabase(resource), actions)); }
void AuthorizationSession::addAuthorizedPrincipal(Principal* principal) { // Log out any already-logged-in user on the same database as "principal". logoutDatabase(principal->getName().getDB().toString()); // See SERVER-8144. _authenticatedPrincipals.add(principal); if (!principal->isImplicitPrivilegeAcquisitionEnabled()) return; const std::string dbname = principal->getName().getDB().toString(); if (dbname == StringData("local", StringData::LiteralTag()) && principal->getName().getUser() == internalSecurity.user) { // Grant full access to internal user ActionSet allActions; allActions.addAllActions(); acquirePrivilege(Privilege(PrivilegeSet::WILDCARD_RESOURCE, allActions), principal->getName()); return; } _acquirePrivilegesForPrincipalFromDatabase(ADMIN_DBNAME, principal->getName()); principal->markDatabaseAsProbed(ADMIN_DBNAME); _acquirePrivilegesForPrincipalFromDatabase(dbname, principal->getName()); principal->markDatabaseAsProbed(dbname); _externalState->onAddAuthorizedPrincipal(principal); }
virtual Status checkAuthForCommand( ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj ) { return client->getAuthorizationSession()->checkAuthForPrivilege( Privilege( AuthorizationManager::CLUSTER_RESOURCE_NAME, ActionType::mergeChunks ) ); }
void CmdShutdown::addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { ActionSet actions; actions.addAction(ActionType::shutdown); out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); }
virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { ActionSet actions; actions.addAction(ActionType::getShardMap); out->push_back(Privilege(AuthorizationManager::CLUSTER_RESOURCE_NAME, actions)); }
virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { ActionSet actions; actions.addAction(ActionType::find); out->push_back(Privilege(parseNs(dbname, cmdObj), actions)); }
void addPrivilegesRequiredForFindAndModify(Command* commandTemplate, const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { bool update = cmdObj["update"].trueValue(); bool upsert = cmdObj["upsert"].trueValue(); bool remove = cmdObj["remove"].trueValue(); ActionSet actions; actions.addAction(ActionType::find); if (update) { actions.addAction(ActionType::update); } if (upsert) { actions.addAction(ActionType::insert); } if (remove) { actions.addAction(ActionType::remove); } ResourcePattern resource(commandTemplate->parseResourcePattern(dbname, cmdObj)); uassert(17137, "Invalid target namespace " + resource.toString(), resource.isExactNamespacePattern()); out->push_back(Privilege(resource, actions)); }
void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) const override { ActionSet actions; actions.addAction(ActionType::convertToCapped); out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); }
Status AuthorizationManager::_buildPrivilegeSetFromOldStylePrivilegeDocument( const std::string& dbname, const PrincipalName& principal, const BSONObj& privilegeDocument, PrivilegeSet* result) { if (!(privilegeDocument.hasField(USERNAME_FIELD_NAME) && privilegeDocument.hasField(PASSWORD_FIELD_NAME))) { return Status(ErrorCodes::UnsupportedFormat, mongoutils::str::stream() << "Invalid old-style privilege document " "received when trying to extract privileges: " << privilegeDocument, 0); } if (privilegeDocument[USERNAME_FIELD_NAME].str() != principal.getUser()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Principal name from privilege document \"" << privilegeDocument[USERNAME_FIELD_NAME].str() << "\" doesn't match name of provided Principal \"" << principal.getUser() << "\"", 0); } bool readOnly = privilegeDocument[READONLY_FIELD_NAME].trueValue(); ActionSet actions = getActionsForOldStyleUser(dbname, readOnly); std::string resourceName = (dbname == ADMIN_DBNAME || dbname == LOCAL_DBNAME) ? PrivilegeSet::WILDCARD_RESOURCE : dbname; result->grantPrivilege(Privilege(resourceName, actions), principal); return Status::OK(); }
virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { ActionSet actions; actions.addAction(ActionType::dropIndex); out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); }
virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { ActionSet actions; actions.addAction(ActionType::connPoolStats); out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); }
Status Pipeline::checkAuthForCommand(ClientBasic* client, const std::string& db, const BSONObj& cmdObj) { NamespaceString inputNs(db, cmdObj.firstElement().str()); auto inputResource = ResourcePattern::forExactNamespace(inputNs); uassert(17138, mongoutils::str::stream() << "Invalid input namespace, " << inputNs.ns(), inputNs.isValid()); std::vector<Privilege> privileges; if (cmdObj.getFieldDotted("pipeline.0.$indexStats")) { Privilege::addPrivilegeToPrivilegeVector( &privileges, Privilege(ResourcePattern::forAnyNormalResource(), ActionType::indexStats)); } else { // If no source requiring an alternative permission scheme is specified then default to // requiring find() privileges on the given namespace. Privilege::addPrivilegeToPrivilegeVector(&privileges, Privilege(inputResource, ActionType::find)); } BSONObj pipeline = cmdObj.getObjectField("pipeline"); BSONForEach(stageElem, pipeline) { BSONObj stage = stageElem.embeddedObjectUserCheck(); StringData stageName = stage.firstElementFieldName(); if (stageName == "$out" && stage.firstElementType() == String) { NamespaceString outputNs(db, stage.firstElement().str()); uassert(17139, mongoutils::str::stream() << "Invalid $out target namespace, " << outputNs.ns(), outputNs.isValid()); ActionSet actions; actions.addAction(ActionType::remove); actions.addAction(ActionType::insert); if (shouldBypassDocumentValidationForCommand(cmdObj)) { actions.addAction(ActionType::bypassDocumentValidation); } Privilege::addPrivilegeToPrivilegeVector( &privileges, Privilege(ResourcePattern::forExactNamespace(outputNs), actions)); } else if (stageName == "$lookup" && stage.firstElementType() == Object) { NamespaceString fromNs(db, stage.firstElement()["from"].str()); Privilege::addPrivilegeToPrivilegeVector( &privileges, Privilege(ResourcePattern::forExactNamespace(fromNs), ActionType::find)); } }
/** * Adds to "outPrivileges" the privileges associated with having the named "role" on "dbname". * * Returns non-OK status if "role" is not a defined role in "dbname". */ static Status _addPrivilegesForSystemRole(const std::string& dbname, const std::string& role, std::vector<Privilege>* outPrivileges) { const bool isAdminDB = (dbname == ADMIN_DBNAME); if (role == SYSTEM_ROLE_READ) { outPrivileges->push_back(Privilege(dbname, readRoleActions)); } else if (role == SYSTEM_ROLE_READ_WRITE) { outPrivileges->push_back(Privilege(dbname, readWriteRoleActions)); } else if (role == SYSTEM_ROLE_USER_ADMIN) { outPrivileges->push_back(Privilege(dbname, userAdminRoleActions)); } else if (role == SYSTEM_ROLE_DB_ADMIN) { outPrivileges->push_back(Privilege(dbname, dbAdminRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_READ_ANY_DB) { outPrivileges->push_back(Privilege(PrivilegeSet::WILDCARD_RESOURCE, readRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_READ_WRITE_ANY_DB) { outPrivileges->push_back( Privilege(PrivilegeSet::WILDCARD_RESOURCE, readWriteRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_USER_ADMIN_ANY_DB) { outPrivileges->push_back( Privilege(PrivilegeSet::WILDCARD_RESOURCE, userAdminRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_DB_ADMIN_ANY_DB) { outPrivileges->push_back( Privilege(PrivilegeSet::WILDCARD_RESOURCE, dbAdminRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_SERVER_ADMIN) { outPrivileges->push_back( Privilege(PrivilegeSet::WILDCARD_RESOURCE, serverAdminRoleActions)); } else if (isAdminDB && role == SYSTEM_ROLE_CLUSTER_ADMIN) { outPrivileges->push_back( Privilege(PrivilegeSet::WILDCARD_RESOURCE, clusterAdminRoleActions)); } else { return Status(ErrorCodes::BadValue, mongoutils::str::stream() <<"No such role, " << role << ", in database " << dbname); } return Status::OK(); }
virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { // TODO: update this with the new rules around user creation in 2.6. ActionSet actions; actions.addAction(ActionType::userAdmin); out->push_back(Privilege(dbname, actions)); }
void AuthorizationSession::grantInternalAuthorization(const UserName& userName) { Principal* principal = new Principal(userName); ActionSet actions; actions.addAllActions(); addAuthorizedPrincipal(principal); fassert(16581, acquirePrivilege(Privilege(PrivilegeSet::WILDCARD_RESOURCE, actions), principal->getName()).isOK()); }
void AuthorizationManager::grantInternalAuthorization() { Principal* internalPrincipal = new Principal("__system"); _authenticatedPrincipals.add(internalPrincipal); ActionSet allActions; allActions.addAllActions(); AcquiredPrivilege privilege(Privilege("*", allActions), internalPrincipal); Status status = acquirePrivilege(privilege); verify (status == Status::OK()); }
void AuthorizationManager::grantInternalAuthorization(const std::string& principalName) { Principal* principal = new Principal(PrincipalName(principalName, "local")); ActionSet actions; actions.addAllActions(); addAuthorizedPrincipal(principal); fassert(16581, acquirePrivilege(Privilege(PrivilegeSet::WILDCARD_RESOURCE, actions), principal->getName()).isOK()); }
virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { ActionSet sourceActions; sourceActions.addAction(ActionType::find); out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), sourceActions)); ActionSet targetActions; targetActions.addAction(ActionType::insert); targetActions.addAction(ActionType::createIndex); targetActions.addAction(ActionType::convertToCapped); std::string collection = cmdObj.getStringField("toCollection"); uassert(16708, "bad 'toCollection' value", !collection.empty()); out->push_back(Privilege(ResourcePattern::forExactNamespace( NamespaceString(dbname, collection)), targetActions)); }
void Pipeline::addRequiredPrivileges(Command* commandTemplate, const string& db, BSONObj cmdObj, vector<Privilege>* out) { ResourcePattern inputResource(commandTemplate->parseResourcePattern(db, cmdObj)); uassert(17138, mongoutils::str::stream() << "Invalid input resource, " << inputResource.toString(), inputResource.isExactNamespacePattern()); if (false && cmdObj["allowDiskUsage"].trueValue()) { // TODO no privilege for this yet. } out->push_back(Privilege(inputResource, ActionType::find)); BSONObj pipeline = cmdObj.getObjectField("pipeline"); BSONForEach(stageElem, pipeline) { BSONObj stage = stageElem.embeddedObjectUserCheck(); if (str::equals(stage.firstElementFieldName(), "$out")) { // TODO Figure out how to handle temp collection privileges. For now, using the // output ns is ok since we only do db-level privilege checks. NamespaceString outputNs(db, stage.firstElement().str()); uassert(17139, mongoutils::str::stream() << "Invalid $out target namespace, " << outputNs.ns(), outputNs.isValid()); ActionSet actions; // logically on output ns actions.addAction(ActionType::remove); actions.addAction(ActionType::insert); // on temp ns due to implementation, but not logically on output ns actions.addAction(ActionType::createCollection); actions.addAction(ActionType::createIndex); actions.addAction(ActionType::dropCollection); actions.addAction(ActionType::renameCollectionSameDB); out->push_back(Privilege(ResourcePattern::forExactNamespace(outputNs), actions)); out->push_back(Privilege(ResourcePattern::forExactNamespace( NamespaceString(db, "system.indexes")), ActionType::find)); } }
Status checkAuthForOperation(OperationContext* opCtx, const std::string& dbname, const BSONObj& cmdObj) const override { // Must be authenticated as an internal cluster member. auto authSession = AuthorizationSession::get(opCtx->getClient()); if (!authSession->isAuthorizedForPrivilege( Privilege(ResourcePattern::forClusterResource(), ActionType::impersonate))) { return {ErrorCodes::Unauthorized, "unauthorized"}; } return Status::OK(); }
virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { ActionSet actions; actions.addAction(ActionType::logApplicationMessage); // TODO: Investigate if using the 'normal resource' // pattern of the new ResourcePattern API matches our // original use of SERVER_RESOURCE_NAME. We may want // to use somethine scoped to the given database name. out->push_back(Privilege(ResourcePattern::forAnyNormalResource(), actions)); }
Status checkAuthForWriteCommand(AuthorizationSession* authzSession, BatchedCommandRequest::BatchType cmdType, const OpMsgRequest& request) { std::vector<Privilege> privileges; ActionSet actionsOnCommandNSS; if (shouldBypassDocumentValidationForCommand(request.body)) { actionsOnCommandNSS.addAction(ActionType::bypassDocumentValidation); } NamespaceString cmdNSS; if (cmdType == BatchedCommandRequest::BatchType_Insert) { auto op = Insert::parse(IDLParserErrorContext("insert"), request); cmdNSS = op.getNamespace(); if (!op.getNamespace().isSystemDotIndexes()) { actionsOnCommandNSS.addAction(ActionType::insert); } else { // Special-case indexes until we have a command const auto swNssToIndex = getIndexedNss(op.getDocuments()); if (!swNssToIndex.isOK()) { return swNssToIndex.getStatus(); } const auto& nssToIndex = swNssToIndex.getValue(); privileges.push_back( Privilege(ResourcePattern::forExactNamespace(nssToIndex), ActionType::createIndex)); } } else if (cmdType == BatchedCommandRequest::BatchType_Update) { auto op = Update::parse(IDLParserErrorContext("update"), request); cmdNSS = op.getNamespace(); actionsOnCommandNSS.addAction(ActionType::update); // Upsert also requires insert privs if (containsUpserts(op.getUpdates())) { actionsOnCommandNSS.addAction(ActionType::insert); } } else { fassert(17251, cmdType == BatchedCommandRequest::BatchType_Delete); auto op = Delete::parse(IDLParserErrorContext("delete"), request); cmdNSS = op.getNamespace(); actionsOnCommandNSS.addAction(ActionType::remove); } if (!actionsOnCommandNSS.empty()) { privileges.emplace_back(ResourcePattern::forExactNamespace(cmdNSS), actionsOnCommandNSS); } if (authzSession->isAuthorizedForPrivileges(privileges)) return Status::OK(); return Status(ErrorCodes::Unauthorized, "unauthorized"); }
Status AuthorizationManager::_buildPrivilegeSetFromOldStylePrivilegeDocument( const std::string& dbname, Principal* principal, const BSONObj& privilegeDocument, PrivilegeSet* result) { if (!(privilegeDocument.hasField("user") && privilegeDocument.hasField("pwd"))) { return Status(ErrorCodes::UnsupportedFormat, mongoutils::str::stream() << "Invalid old-style privilege document " "received when trying to extract privileges: " << privilegeDocument, 0); } bool readOnly = false; ActionSet actions; if (privilegeDocument.hasField("readOnly") && privilegeDocument["readOnly"].trueValue()) { actions.addAllActionsFromSet(readRoleActions); readOnly = true; } else { actions.addAllActionsFromSet(readWriteRoleActions); actions.addAllActionsFromSet(dbAdminRoleActions); actions.addAllActionsFromSet(userAdminRoleActions); } if (dbname == "admin" || dbname == "local") { // Make all basic actions available on all databases result->grantPrivilege(AcquiredPrivilege(Privilege("*", actions), principal)); // Make server and cluster admin actions available on admin database. if (!readOnly) { actions.addAllActionsFromSet(serverAdminRoleActions); actions.addAllActionsFromSet(clusterAdminRoleActions); } } result->grantPrivilege(AcquiredPrivilege(Privilege(dbname, actions), principal)); return Status::OK(); }
void addPrivilegesRequiredForRenameCollection(const BSONObj& cmdObj, std::vector<Privilege>* out) { NamespaceString sourceNS = NamespaceString(cmdObj.getStringField("renameCollection")); NamespaceString targetNS = NamespaceString(cmdObj.getStringField("to")); uassert(17140, "Invalid source namespace " + sourceNS.ns(), sourceNS.isValid()); uassert(17141, "Invalid target namespace " + targetNS.ns(), targetNS.isValid()); ActionSet sourceActions; ActionSet targetActions; if (sourceNS.db() == targetNS.db()) { sourceActions.addAction(ActionType::renameCollectionSameDB); targetActions.addAction(ActionType::renameCollectionSameDB); } else { sourceActions.addAction(ActionType::cloneCollectionLocalSource); sourceActions.addAction(ActionType::dropCollection); targetActions.addAction(ActionType::createCollection); targetActions.addAction(ActionType::cloneCollectionTarget); targetActions.addAction(ActionType::createIndex); } out->push_back(Privilege(ResourcePattern::forExactNamespace(sourceNS), sourceActions)); out->push_back(Privilege(ResourcePattern::forExactNamespace(targetNS), targetActions)); }
virtual void addRequiredPrivileges(const std::string &dbname, const BSONObj &cmdObj, std::vector<Privilege> *out) { ActionSet actions; actions.addAction(ActionType::transactionCommands); if (cmdObj["isolation"].valuestringdatasafe() == "serializable") { actions.addAction(ActionType::beginSerializableTransaction); } // This doesn't really need to be specific to this dbname, but it ensures that you are // authed as someone and aren't just anonymous. This means that if you're running with // auth, you need to issue transaction commands against a db that you have privileges // on, which doesn't seem like that big of a requirement. out->push_back(Privilege(dbname, actions)); }
void addPrivilegesRequiredForMapReduce(Command* commandTemplate, const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { Config::OutputOptions outputOptions = Config::parseOutputOptions(dbname, cmdObj); ResourcePattern inputResource(commandTemplate->parseResourcePattern(dbname, cmdObj)); uassert(17142, mongoutils::str::stream() << "Invalid input resource " << inputResource.toString(), inputResource.isExactNamespacePattern()); out->push_back(Privilege(inputResource, ActionType::find)); if (outputOptions.outType != Config::INMEMORY) { ActionSet outputActions; outputActions.addAction(ActionType::insert); if (outputOptions.outType == Config::REPLACE) { outputActions.addAction(ActionType::remove); } else { outputActions.addAction(ActionType::update); } if (shouldBypassDocumentValidationforCommand(cmdObj)) { outputActions.addAction(ActionType::bypassDocumentValidation); } ResourcePattern outputResource( ResourcePattern::forExactNamespace( NamespaceString(outputOptions.finalNamespace))); uassert(17143, mongoutils::str::stream() << "Invalid target namespace " << outputResource.ns().ns(), outputResource.ns().isValid()); // TODO: check if outputNs exists and add createCollection privilege if not out->push_back(Privilege(outputResource, outputActions)); } }
void addPrivilegesRequiredForMapReduce(const std::string& dbname, const BSONObj& cmdObj, std::vector<Privilege>* out) { Config::OutputOptions outputOptions = Config::parseOutputOptions(dbname, cmdObj); ActionSet inputActions, outputActions; inputActions.addAction(ActionType::find); std::string inputNs = dbname + '.' + cmdObj.firstElement().valuestr(); out->push_back(Privilege(inputNs, inputActions)); if (outputOptions.outType != Config::INMEMORY) { outputActions.addAction(ActionType::insert); if (outputOptions.outType == Config::REPLACE) { outputActions.addAction(ActionType::remove); } else { outputActions.addAction(ActionType::update); } std::string outputNs = outputOptions.finalNamespace; // TODO: check if outputNs exists and add createCollection privilege if not out->push_back(Privilege(outputNs, outputActions)); } }
ImpersonationSessionGuard::ImpersonationSessionGuard(OperationContext* opCtx) : _opCtx(opCtx) { auto authSession = AuthorizationSession::get(_opCtx->getClient()); const auto impersonatedUsersAndRoles = rpc::getImpersonatedUserMetadata(opCtx); if (impersonatedUsersAndRoles) { uassert(ErrorCodes::Unauthorized, "Unauthorized use of impersonation metadata.", authSession->isAuthorizedForPrivilege( Privilege(ResourcePattern::forClusterResource(), ActionType::impersonate))); fassert(ErrorCodes::InternalError, !authSession->isImpersonating()); authSession->setImpersonatedUserData(impersonatedUsersAndRoles->getUsers(), impersonatedUsersAndRoles->getRoles()); _active = true; return; } }