当前位置:   article > 正文

鸿蒙3.1 基于Token的访问控制_openharmony token_native

openharmony token_native

介绍

代码路径:security_access_token: ATM(AccessTokenManager)是OpenHarmony上基于AccessToken构建的统一的应用权限管理能力。

ATM(AccessTokenManager)是OpenHarmony上基于AccessToken构建的统一的应用权限管理能力。

应用的Accesstoken信息主要包括应用身份标识APPID、用户ID,应用分身索引、应用APL(Ability Privilege Level)等级、应用权限信息等。每个应用的Accestoken信息由一个32bits的设备内唯一标识符TokenID(Token identity)来标识。

ATM模块主要提供如下功能:

  • 提供基于TokenID的应用权限校验机制,应用访问敏感数据或者API时可以检查是否有对应的权限。
  • 提供基于TokenID的Accestoken信息查询,应用可以根据TokenID查询自身的APL等级等信息。

目录介绍

  1. /base/security/access_token
  2. ├── frameworks # 框架层,基础功能代码存放目录
  3. │ ├── accesstoken # Accesstoken管理框架代码存放目录
  4. │ ├── tokensync # Accesstoken信息同步框架代码存放目录
  5. │ └── common # 框架公共代码存放目录
  6. ├── interfaces # 接口层
  7. │ └── innerkits # 内部接口层
  8. │ ├── accesstoken # Accesstoken内部接口代码存放目录
  9. │ ├── nativetoken # nativetoken内部接口代码存放目录
  10. │ └── tokensync # Accesstoken信息同步内部接口代码存放目录
  11. └── services # 服务层
  12. ├── accesstokenmanager # Accesstoken管理服务代码存放目录
  13. └── tokensyncmanager # Accesstoken信息同步服务代码存放目录

基础数据结构

HapTokenInfo

内存中保存token信息的结构,对应到数据库的hap_token_info_table表

  1. class HapTokenInfo final {
  2. public:
  3. ATokenAplEnum apl;
  4. char ver;
  5. int userID;
  6. std::string bundleName;
  7. int instIndex;
  8. std::string appID;
  9. std::string deviceID;
  10. AccessTokenID tokenID;
  11. AccessTokenAttr tokenAttr;
  12. };

appid = 应用包名+证书hash

PermissionPolicySet

存储tokenid和对应权限状态的关系类

TokenID组成

基本类型,tokenid就是一个int型。

typedef unsigned int AccessTokenID;

tokenid主要是如下的四部分组成的

  1. typedef struct {
  2. unsigned int tokenUniqueID : 20;
  3. unsigned int res : 7;
  4. unsigned int type : 2;
  5. unsigned int version : 3;
  6. } AccessTokenIDInner;

数据库结构

hap_token_info_table表

主要存储应用的token信息

列名

类型

备注

token_id

integer

user_id

integer

bundle_name

text

inst_index

integer

app_id

text

device_id

text

apl

integer

token_version

integer

token_attr

integer

primary key : token_id

native_token_info_table表

native服务的token信息

列名

类型

备注

token_id

integer

process_name

text

token_version

integer

token_attr

integer

dcap

text

apl

integer

primary key : token_id

permission_definition_table表

权限定义表

列名

类型

备注

token_id

integer

permission_name

text

bundle_name

text

grant_mode

integer

available_level

integer

provision_enable

integer

distributed_scene_enable

integer

label

text

label_id

text

description

text

description_id

text

primary key : token_id, permission_name

permission_state_table表

权限状态表

列名

类型

token_id

integer

permission_name

text

device_id

text

is_general

integer

grant_state

integer

grant_flag

integer

primary key : token_id, permission_name, device_id

启动过程

整个启动过程,主要分为两部分。一部分是去数据库中加载动态的信息,还有一部分就是去系统定义的目录下加载静态的配置文件,静态配置文件主要是native service的token信息。

token的生成

本地应用

应用安装时生成

本地服务

服务自己注册,静态配置文件中读取

远程应用或服务

远程应用访问本地设备时,根据远程应用的设备id,以及远程过来附带的tokenid,进行关系绑定,生成本地的tokenid。

相关本地token和权限的关系,是通过同步机制,从来源设备同步应用权限得到的。

token同步过程

调用点1

分布式组件管理部件

分布式组件管理部件模块负责跨设备组件管理,提供访问和控制远程组件的能力,支持分布式场景下的应用协同。主要功能如下:

- 远程启动元能力:跨设备拉起远端设备上的指定元能力。

- 远程迁移元能力:将元能力跨设备迁移到远端设备。

- 远程绑定元能力:跨设备绑定远端设备上的指定元能力。

./distributedschedule/dmsfwk/services/dtbschedmgr/src/distributed_sched_permission.cpp:177:    uint32_t dAccessToken = AccessToken::AccessTokenKit::AllocLocalTokenID(

任务调度过程中,会存在检查权限的场景,该服务会先创建远程tokenid,然后再会检查权限。

数据结构

整个交互过程中,消息中会附带如下的信息

  1. struct CallerInfo {
  2. int32_t uid = -1;
  3. int32_t pid = -1;
  4. int32_t callerType = CALLER_TYPE_NONE;
  5. std::string sourceDeviceId;
  6. int32_t duid = -1;
  7. std::string callerAppId;
  8. std::vector<std::string> bundleNames;
  9. int32_t dmsVersion = -1;
  10. uint32_t accessToken = 0;
  11. };

StartAbilityFromRemote

远程启动应用的时候会去调用权限相关操作

  1. //远程启动应用
  2. int32_t DistributedSchedService::StartAbilityFromRemote(const OHOS::AAFwk::Want& want,
  3. const OHOS::AppExecFwk::AbilityInfo& abilityInfo, int32_t requestCode,
  4. const CallerInfo& callerInfo, const AccountInfo& accountInfo)
  5. {
  6. std::string localDeviceId;
  7. std::string deviceId = want.GetElement().GetDeviceID();
  8. if (!GetLocalDeviceId(localDeviceId) ||
  9. !CheckDeviceIdFromRemote(localDeviceId, deviceId, callerInfo.sourceDeviceId)) {
  10. HILOGE("check deviceId failed");
  11. return INVALID_REMOTE_PARAMETERS_ERR;
  12. }
  13. //检查权限
  14. DistributedSchedPermission& permissionInstance = DistributedSchedPermission::GetInstance();
  15. ErrCode err = permissionInstance.CheckDPermission(want, callerInfo, accountInfo, abilityInfo, deviceId);
  16. if (err != ERR_OK) {
  17. HILOGE("CheckDPermission denied!!");
  18. return err;
  19. }
  20. err = AAFwk::AbilityManagerClient::GetInstance()->Connect();
  21. if (err != ERR_OK) {
  22. HILOGE("connect ability server failed %{public}d", err);
  23. return err;
  24. }
  25. std::vector<int> ids;
  26. ErrCode ret = OsAccountManager::QueryActiveOsAccountIds(ids);
  27. if (ret != ERR_OK || ids.empty()) {
  28. return INVALID_PARAMETERS_ERR;
  29. }
  30. err = AAFwk::AbilityManagerClient::GetInstance()->StartAbility(want, requestCode, ids[0]);
  31. if (err != ERR_OK) {
  32. HILOGE("StartAbility failed %{public}d", err);
  33. }
  34. return err;
  35. }

StartAbilityByCallFromRemote

  1. int32_t DistributedSchedService::StartAbilityByCallFromRemote(const OHOS::AAFwk::Want& want,
  2. const sptr<IRemoteObject>& connect, const CallerInfo& callerInfo, const AccountInfo& accountInfo)
  3. {
  4. HILOGD("[PerformanceTest] DistributedSchedService StartAbilityByCallFromRemote begin");
  5. if (connect == nullptr) {
  6. HILOGE("StartAbilityByCallFromRemote connect is null");
  7. return INVALID_REMOTE_PARAMETERS_ERR;
  8. }
  9. std::string localDeviceId;
  10. std::string destinationDeviceId = want.GetElement().GetDeviceID();
  11. if (!GetLocalDeviceId(localDeviceId) ||
  12. !CheckDeviceIdFromRemote(localDeviceId, destinationDeviceId, callerInfo.sourceDeviceId)) {
  13. HILOGE("StartAbilityByCallFromRemote check deviceId failed");
  14. return INVALID_REMOTE_PARAMETERS_ERR;
  15. }
  16. DistributedSchedPermission& permissionInstance = DistributedSchedPermission::GetInstance();
  17. int32_t result = permissionInstance.CheckGetCallerPermission(want, callerInfo, accountInfo, localDeviceId);
  18. if (result != ERR_OK) {
  19. HILOGE("StartAbilityByCallFromRemote CheckDPermission denied!!");
  20. return result;
  21. }
  22. sptr<IRemoteObject> callbackWrapper;
  23. {
  24. std::lock_guard<std::mutex> autoLock(calleeLock_);
  25. auto itConnect = calleeMap_.find(connect);
  26. if (itConnect != calleeMap_.end()) {
  27. callbackWrapper = itConnect->second.callbackWrapper;
  28. } else {
  29. callbackWrapper = new AbilityConnectionWrapperStub(connect, localDeviceId);
  30. }
  31. }
  32. int32_t errCode = DistributedSchedAdapter::GetInstance().StartAbilityByCall(want, callbackWrapper, this);
  33. HILOGD("[PerformanceTest] StartAbilityByCallFromRemote end");
  34. if (errCode == ERR_OK) {
  35. {
  36. std::lock_guard<std::mutex> autoLock(calleeLock_);
  37. ConnectInfo connectInfo {callerInfo, callbackWrapper, want.GetElement()};
  38. calleeMap_.emplace(connect, connectInfo);
  39. }
  40. connect->AddDeathRecipient(callerDeathRecipient_);
  41. }
  42. return errCode;
  43. }

ConnectAbilityFromRemote

  1. int32_t DistributedSchedService::ConnectAbilityFromRemote(const OHOS::AAFwk::Want& want,
  2. const AppExecFwk::AbilityInfo& abilityInfo, const sptr<IRemoteObject>& connect,
  3. const CallerInfo& callerInfo, const AccountInfo& accountInfo)
  4. {
  5. HILOGD("[PerformanceTest] DistributedSchedService ConnectAbilityFromRemote begin");
  6. if (connect == nullptr) {
  7. HILOGE("ConnectAbilityFromRemote connect is null");
  8. return INVALID_REMOTE_PARAMETERS_ERR;
  9. }
  10. HILOGD("ConnectAbilityFromRemote uid is %{public}d, pid is %{public}d, AccessTokenID is %{public}u",
  11. callerInfo.uid, callerInfo.pid, callerInfo.accessToken);
  12. std::string localDeviceId;
  13. std::string destinationDeviceId = want.GetElement().GetDeviceID();
  14. if (!GetLocalDeviceId(localDeviceId) ||
  15. !CheckDeviceIdFromRemote(localDeviceId, destinationDeviceId, callerInfo.sourceDeviceId)) {
  16. HILOGE("ConnectAbilityFromRemote check deviceId failed");
  17. return INVALID_REMOTE_PARAMETERS_ERR;
  18. }
  19. DistributedSchedPermission& permissionInstance = DistributedSchedPermission::GetInstance();
  20. int32_t result = permissionInstance.CheckDPermission(want, callerInfo, accountInfo, abilityInfo, localDeviceId);
  21. if (result != ERR_OK) {
  22. HILOGE("ConnectAbilityFromRemote CheckDPermission denied!!");
  23. return result;
  24. }
  25. HILOGD("ConnectAbilityFromRemote callerType is %{public}d", callerInfo.callerType);
  26. sptr<IRemoteObject> callbackWrapper = connect;
  27. std::map<sptr<IRemoteObject>, ConnectInfo>::iterator itConnect;
  28. if (callerInfo.callerType == CALLER_TYPE_HARMONY) {
  29. std::lock_guard<std::mutex> autoLock(connectLock_);
  30. itConnect = connectAbilityMap_.find(connect);
  31. if (itConnect != connectAbilityMap_.end()) {
  32. callbackWrapper = itConnect->second.callbackWrapper;
  33. } else {
  34. callbackWrapper = new AbilityConnectionWrapperStub(connect);
  35. }
  36. }
  37. int32_t errCode = DistributedSchedAdapter::GetInstance().ConnectAbility(want, callbackWrapper, this);
  38. HILOGD("[PerformanceTest] ConnectAbilityFromRemote end");
  39. if (errCode == ERR_OK) {
  40. std::lock_guard<std::mutex> autoLock(connectLock_);
  41. if (itConnect == connectAbilityMap_.end()) {
  42. ConnectInfo connectInfo {callerInfo, callbackWrapper};
  43. connectAbilityMap_.emplace(connect, connectInfo);
  44. }
  45. }
  46. return errCode;
  47. }

权限检查过程

  1. /**
  2. * @brief 检查权限
  3. *
  4. * @param tokenID
  5. * @param permissionName
  6. * @return int
  7. */
  8. int PermissionManager::VerifyAccessToken(AccessTokenID tokenID, const std::string& permissionName)
  9. {
  10. ACCESSTOKEN_LOG_INFO(LABEL, "%{public}s called, tokenID: 0x%{public}x, permissionName: %{public}s", __func__,
  11. tokenID, permissionName.c_str());
  12. //检查权限名是否合法
  13. if (!PermissionValidator::IsPermissionNameValid(permissionName)) {
  14. ACCESSTOKEN_LOG_ERROR(LABEL, "invalid params!");
  15. return PERMISSION_DENIED;
  16. }
  17. std::shared_ptr<HapTokenInfoInner> tokenInfoPtr =
  18. AccessTokenInfoManager::GetInstance().GetHapTokenInfoInner(tokenID);
  19. if (tokenInfoPtr == nullptr) {
  20. ACCESSTOKEN_LOG_ERROR(LABEL, "can not find tokenInfo!");
  21. return PERMISSION_DENIED;
  22. }
  23. //远程的应用,并且本地没有对应权限定义。直接拒绝
  24. if (!tokenInfoPtr->IsRemote() && !PermissionDefinitionCache::GetInstance().HasDefinition(permissionName)) {
  25. ACCESSTOKEN_LOG_ERROR(
  26. LABEL, "no definition for permission: %{public}s!", permissionName.c_str());
  27. return PERMISSION_DENIED;
  28. }
  29. std::shared_ptr<PermissionPolicySet> permPolicySet =
  30. AccessTokenInfoManager::GetInstance().GetHapPermissionPolicySet(tokenID);
  31. if (permPolicySet == nullptr) {
  32. ACCESSTOKEN_LOG_ERROR(LABEL, "invalid params!");
  33. return PERMISSION_DENIED;
  34. }
  35. //根据数据库中加载的授权信息进行权限状态的检查。
  36. return permPolicySet->VerifyPermissStatus(permissionName);
  37. }

AccessTokenID使用

目前看到的tokenid是在binder里面使用的,原本的binder传输的是uid,目前鸿蒙系统中新增了tokenid的传输,目前可以直接从binder里面获取。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/224509
推荐阅读
相关标签
  

闽ICP备14008679号