diff options
Diffstat (limited to 'src/mongo/db/auth/authz_manager_external_state.cpp')
| -rw-r--r-- | src/mongo/db/auth/authz_manager_external_state.cpp | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/mongo/db/auth/authz_manager_external_state.cpp b/src/mongo/db/auth/authz_manager_external_state.cpp new file mode 100644 index 00000000000..e5f63496799 --- /dev/null +++ b/src/mongo/db/auth/authz_manager_external_state.cpp @@ -0,0 +1,195 @@ +/** +* Copyright (C) 2012 10gen Inc. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License, version 3, +* as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* As a special exception, the copyright holders give permission to link the +* code of portions of this program with the OpenSSL library under certain +* conditions as described in each individual source file and distribute +* linked combinations including the program with the OpenSSL library. You +* must comply with the GNU Affero General Public License in all respects for +* all of the code used other than as permitted herein. If you modify file(s) +* with this exception, you may extend this exception to your version of the +* file(s), but you are not obligated to do so. If you do not wish to do so, +* delete this exception statement from your version. If you delete this +* exception statement from all source files in the program, then also delete +* it in the license file. +*/ + +#include "mongo/db/auth/authz_manager_external_state.h" + +#include "mongo/base/status.h" +#include "mongo/db/auth/authorization_manager.h" +#include "mongo/db/auth/security_key.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/namespace_string.h" +#include "mongo/util/mongoutils/str.h" + +namespace mongo { + + AuthzManagerExternalState::AuthzManagerExternalState() {} + AuthzManagerExternalState::~AuthzManagerExternalState() {} + + Status AuthzManagerExternalState::getPrivilegeDocumentV1(const StringData& dbname, + const UserName& userName, + BSONObj* result) { + if (userName == internalSecurity.user->getName()) { + return Status(ErrorCodes::InternalError, + "Requested privilege document for the internal user"); + } + + if (!NamespaceString::validDBName(dbname)) { + return Status(ErrorCodes::BadValue, + mongoutils::str::stream() << "Bad database name \"" << dbname << "\""); + } + + const bool isUserFromTargetDB = (dbname == userName.getDB()); + + // Build the query needed to get the privilege document + + BSONObjBuilder queryBuilder; + const NamespaceString usersNamespace(dbname, "system.users"); + queryBuilder.append(AuthorizationManager::V1_USER_NAME_FIELD_NAME, userName.getUser()); + if (isUserFromTargetDB) { + queryBuilder.appendNull(AuthorizationManager::V1_USER_SOURCE_FIELD_NAME); + } + else { + queryBuilder.append(AuthorizationManager::V1_USER_SOURCE_FIELD_NAME, userName.getDB()); + } + + // Query for the privilege document + BSONObj userBSONObj; + Status found = findOne(usersNamespace, queryBuilder.done(), &userBSONObj); + if (!found.isOK()) { + if (found.code() == ErrorCodes::NoMatchingDocument) { + // Return more detailed status that includes user name. + return Status(ErrorCodes::UserNotFound, + mongoutils::str::stream() << "auth: couldn't find user " << + userName.toString() << ", " << usersNamespace.ns(), + 0); + } else { + return found; + } + } + + if (isUserFromTargetDB) { + if (userBSONObj[AuthorizationManager::PASSWORD_FIELD_NAME].eoo()) { + return Status(ErrorCodes::AuthSchemaIncompatible, mongoutils::str::stream() << + "User documents with schema version " << + AuthorizationManager::schemaVersion24 << + " must have a \"" << + AuthorizationManager::PASSWORD_FIELD_NAME << + "\" field."); + } + } + + *result = userBSONObj.getOwned(); + return Status::OK(); + } + + bool AuthzManagerExternalState::hasAnyPrivilegeDocuments() { + BSONObj userBSONObj; + Status status = findOne( + AuthorizationManager::usersCollectionNamespace, + BSONObj(), + &userBSONObj); + // If the status is NoMatchingDocument, there are no privilege documents. + // If it's OK, there are. Otherwise, we were unable to complete the query, + // so best to assume that there _are_ privilege documents. This might happen + // if the node contaning the users collection becomes transiently unavailable. + // See SERVER-12616, for example. + return status != ErrorCodes::NoMatchingDocument; + } + + + Status AuthzManagerExternalState::insertPrivilegeDocument(const string& dbname, + const BSONObj& userObj, + const BSONObj& writeConcern) { + Status status = insert(NamespaceString("admin.system.users"), userObj, writeConcern); + if (status.isOK()) { + return status; + } + if (status.code() == ErrorCodes::DuplicateKey) { + std::string name = userObj[AuthorizationManager::USER_NAME_FIELD_NAME].String(); + std::string source = userObj[AuthorizationManager::USER_DB_FIELD_NAME].String(); + return Status(ErrorCodes::DuplicateKey, + mongoutils::str::stream() << "User \"" << name << "@" << source << + "\" already exists"); + } + if (status.code() == ErrorCodes::UnknownError) { + return Status(ErrorCodes::UserModificationFailed, status.reason()); + } + return status; + } + + Status AuthzManagerExternalState::updatePrivilegeDocument( + const UserName& user, const BSONObj& updateObj, const BSONObj& writeConcern) { + Status status = updateOne( + NamespaceString("admin.system.users"), + BSON(AuthorizationManager::USER_NAME_FIELD_NAME << user.getUser() << + AuthorizationManager::USER_DB_FIELD_NAME << user.getDB()), + updateObj, + false, + writeConcern); + if (status.isOK()) { + return status; + } + if (status.code() == ErrorCodes::NoMatchingDocument) { + return Status(ErrorCodes::UserNotFound, + mongoutils::str::stream() << "User " << user.getFullName() << + " not found"); + } + if (status.code() == ErrorCodes::UnknownError) { + return Status(ErrorCodes::UserModificationFailed, status.reason()); + } + return status; + } + + Status AuthzManagerExternalState::removePrivilegeDocuments(const BSONObj& query, + const BSONObj& writeConcern, + int* numRemoved) { + Status status = remove(NamespaceString("admin.system.users"), + query, + writeConcern, + numRemoved); + if (status.code() == ErrorCodes::UnknownError) { + return Status(ErrorCodes::UserModificationFailed, status.reason()); + } + return status; + } + + Status AuthzManagerExternalState::updateOne( + const NamespaceString& collectionName, + const BSONObj& query, + const BSONObj& updatePattern, + bool upsert, + const BSONObj& writeConcern) { + int nMatched; + Status status = update(collectionName, + query, + updatePattern, + upsert, + false, + writeConcern, + &nMatched); + if (!status.isOK()) { + return status; + } + dassert(nMatched == 1 || nMatched == 0); + if (nMatched == 0) { + return Status(ErrorCodes::NoMatchingDocument, "No document found"); + } + return Status::OK(); + } + +} // namespace mongo |
