閱讀424 返回首頁    go 阿裏雲 go 技術社區[雲棲]


MongoDB權限管理代碼分析

本文主要介紹Mongodb RBAC(role based access control)權限管理機製,其核心是給每個用戶賦予一定的權限,用戶連接mongodb前需先驗證,驗證通過後即擁有用戶的權限,權限決定了用戶在某一組資源(如某個DB、某個特定集合)上可以執行哪些操作(比如增刪改查、建索引)。

ActionType

db/auth/action_types.txt文件裏包含mongo所有的action

ActionType代表一種操作,每個ActionType有一個唯一的ID,Role支持的所有操作通過ActionSet來描述,ActionSet實際是一個位圖,支持某種操作時,其ID對應的bit置1.

ActionType相關的代碼是由一個python腳本動態生成的

generate_action_types.py action_types.txt header_file source_file

ResourcePattern

ResourcePattern代表資源(某個數據庫、某個集合等)匹配方式,由資源名稱(DB.collection格式,如果為空代表匹配任意資源)及匹配方式組成

class {
private:
  MatchType _matchType;
  NamespaceString _ns;  
};

enum MatchType {
    matchNever = 0,              /// Matches no resource.
    matchClusterResource = 1,    /// Matches if the resource is the cluster resource.
    matchDatabaseName = 2,       /// Matches if the resource's database name is _ns.db().
    matchCollectionName = 3,     /// Matches if the resource's collection name is _ns.coll().
    matchExactNamespace = 4,     /// Matches if the resource's namespace name is _ns.
    matchAnyNormalResource = 5,  /// Matches all databases and non-system collections.
    matchAnyResource = 6         /// Matches absolutely anything.
};

Privilege

權限(Privilege)由ResourcePattern及支持的ActionSet構成,代表可以在匹配ResourcePattern的資源上可以執行ActionSet裏的所有操作。

class Privilege {
private:
  ResourcePattern _resource;
  ActionSet _actions;
};

Role & PrivilegeVector

權限集合代表是一組權限的並集

typedef std::vector PrivilegeVector;

往PrivilegeVector裏添加Previlege時,先檢查ResourcePattern是否已經存在,如果已經存在,直接添加對應的ActionSet;如果不存在,則構造一個新的Previlege添加到Vector裏。

void Privilege::addPrivilegeToPrivilegeVector(PrivilegeVector* privileges,
                                          const Privilege& privilegeToAdd) {
    for (PrivilegeVector::iterator it = privileges->begin(); it !=  privileges->end(); ++it) {
        if (it->getResourcePattern() == privilegeToAdd.getResourcePattern()) {
            it->addActions(privilegeToAdd.getActions());
            return;
        }
   }
   // No privilege exists yet for this resource
   privileges->push_back(privilegeToAdd);
}

Role

Role代表『對某些資源(Resource)可以執行哪些操作(action)』,每個Role包含一個PrivilegeVector,指定其擁有的權限。

BuiltIn Role

為方便管理,Mongodb已經內置了一組預先定義好的Role,比如read、readWrite等,auth模塊裏已經實現好了構造對應權限的接口

void addReadOnlyDbPrivileges(PrivilegeVector* privileges, StringData dbName);
void addReadWriteDbPrivileges(PrivilegeVector* privileges, StringData dbName);

每個Role跟一個DB(多個DB)關聯,代表這個Role能操作的資源(Resource),由RoleName唯一標識。

class RoleName {
public:
    RoleName(StringData role, StringData dbname);
private:
    std::string _fullName;  // The full name, stored as a string.  "role@db".
    size_t _splitPoint;     // The index of the "@" separating the role and db name parts.      
};

User

每個User跟一個DB關聯,由UserName唯一標識,多個DB下可能具有相同名字的User。每個User包含一組P

Class UserName {
public:
  UserName(StringData user, StringData dbname);
private:
  std::string _fullName;  // The full name, stored as a string.  "user@db".
  size_t _splitPoint;     // The index of the "@" separating the user and db name parts.
};

class User {
private:
  UserName _name;
  // Maps resource name to privilege on that resource
  ResourcePrivilegeMap _privileges;

  // Roles the user has privileges from
  unordered_set _roles;

  // Roles that the user indirectly has privileges from, due to role inheritance.
  std::vector _indirectRoles;
};

createUser

數據庫命令createUser用於創建新用戶,用戶創建時需指定用戶名、密碼及分配的權限信息(ActionSet@ResourcePattern),用戶的信息會存儲在admin.system.users集合裏。

mongodb用戶也可直接通過insert、update、remove等直接操作admin.system.users集合,但強烈不建議這麼做,所有的用戶操作建議都通過createUser、updateUser、dropUser等數據庫命令來完成。

auth

auth命令負責對連接進行認證,以確定該連接可以針對哪些資源執行什麼操作,同一個DB可以被auth多次,以最終auth的用戶權限為準。

class CmdAuthenticate : public Command {
public:
bool run(OperationContext* txn,
         const std::string& dbname,
         BSONObj& cmdObj,
         int options,
         std::string& errmsg,
         BSONObjBuilder& result);
}; 

每個連接對應一個AuthorizationSession,存儲著連接上已通過驗證的用戶信息

class AuthorizationSession {
private:
    // All Users who have been authenticated on this connection.
UserSet _authenticatedUsers;
    // The roles of the authenticated users. This vector is generated when the authenticated
   // users set is changed.
std::vector _authenticatedRoleNames;

};

當mongod接受到用戶請求時,會根據請求對應的操作需要的權限,在_authenticatedUsers進行匹配,如果包含所需權限,則該操作可以繼續執行。

請求權限驗證

用戶建立連接後,就可以開始發送請求,針對集合的增刪改查請求,主要包括OP_INSERT、OP_UPDATE、OP_DELETE等,這些請求在AuthorizationSession對應檢查權限的方法。

Status checkAuthForUpdate(const NamespaceString& ns,
                          const BSONObj& query,
                          const BSONObj& update,
                          bool upsert);
Status checkAuthForInsert(const NamespaceString& ns, const BSONObj& document);
Status checkAuthForDelete(const NamespaceString& ns, const BSONObj& query);
...

還有一類請求是數據庫命令,比如createUser、listCollections、listDatabases等,這些都是數據庫命令,mongodb裏每個命令都繼承自Command類,需實現run、checkAuthForCommand等方法,其中checkAuthForCommand用於檢查命令是否有權限執行;實際上就是檢查命令操作的DB(或集合)及對應的操作類型是否在用戶的PrivilegeVector裏。Command的權限檢查通過後就會執行run函數,完成命令的主體執行邏輯。

class Command {

    virtual Status checkAuthForCommand(ClientBasic* client, 
                                const std::string& dbname,
                                const BSONObj& cmdObj);
    virtual bool run(OperationContext* txn,
                 const std::string& db,
                 BSONObj& cmdObj,
                 int options,
                 std::string& errmsg,
                 BSONObjBuilder& result) = 0;
};

最後更新:2017-04-01 13:37:08

  上一篇:go PostgreSQL數據庫監控中的統計學 - 對象空間的數據分布圖
  下一篇:go PostgreSQL 鎖等待診斷詳解