• 1
  • 2
  • 3
  • 4
  • 5
mssql数据库问题 首 页  »  帮助中心  »  数据库  »  mssql数据库问题
MongoDB权限管理代码分析说明
发布日期:2016-4-29 17:4:24

  本文主要介绍Mongodb RBAC(role based access control)权限管理机制,它的核心是给每个用户赋予一定的权限,用户连接mongodb前需先进行验证,验证通过后就拥有用户的权限,权限决定了用户在某一组资源(如某个DB、某个特定集合)上可以执行哪些操作(比如增删改查、建索引)。

  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.

  };

  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

  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);

  }

  Privilege

  权限(Privilege)由ResourcePattern及支持的ActionSet构成,代表可以在匹配ResourcePattern的资源上可以执行ActionSet里的所有操作。

  class Privilege {

  private:

  ResourcePattern _resource;

  ActionSet _actions;

  };

  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;

  };

  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进行匹配,如果包含所需权限,则该操作可以继续执行。

  createUser

  数据库命令createUser用于创建新用户,用户创建时需指定用户名、密码及分配的权限信息(ActionSet@ResourcePattern),用户的信息会存储在admin.system.users集合里。

  mongodb用户也可直接通过insert、update、remove等直接操作admin.system.users集合,但强烈不建议这么做,所有的用户操作建议都通过createUser、updateUser、dropUser等数据库命令来完成。

  请求权限验证

  用户建立连接后,就可以开始发送请求,针对集合的增删改查请求,主要包括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;

  };