Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.1 Introduction CYFS for Developers: CYFS permission system #17

Open
streetycat opened this issue Apr 25, 2023 · 0 comments
Open

3.1 Introduction CYFS for Developers: CYFS permission system #17

streetycat opened this issue Apr 25, 2023 · 0 comments
Assignees

Comments

@streetycat
Copy link
Collaborator

streetycat commented Apr 25, 2023

CYFS permission system

Every one needs to protect secret information from being accessed, and CYFS is an open platform, and anyone has the opportunity to read the information stored on it. The best way to protect privacy is not to deal with other people, and sensitive information is not shown to others. In CYFS, it is necessary to protect the ObjectId of sensitive information. Once someone else gets your ObjectId, it is possible to get the object content itself. This is very important, and it should be regarded as a principle for using CYFS. Information can be leaked in many ways:

  • Send to others actively.
  • Malicious or poor quality DECApps may deliver it on purpose or accidentally. Therefore, We should try our best to install DECApp from a reliable source, and even read the source code and build DECApp by ourselves.

It's too difficult to distinguish and prevent dangerous behaviors by users themselves. Therefore, CYFS provides a permission system to help users manage private data. The user can prohibit all DECApp except the system DECApp from accessing an object, and can also prohibit any other user from actively accessing an object. No one can read the object content without permissions even if the ObjectId is leaked. As a basic system, CYFS provides a flexible methods to config the permissions, which can only open partial access permissions for specific trusted users or DECApp; of course, the author cannot prevent Object from continuing to propagate after it has been displayed to others, It's also unpreventable in real world.

Let me emphasize again that users should try their best to abide by the confidentiality principle mentioned above. The system can only provide auxiliary management capabilities and cannot be used as the final guarantee.

I will describe the design of the CYFS permissions (hereafter referred to as ACL) system as follow.

Default Permissions

If no permissions are configured for an Object, the default permissions are effective as follows:

  • If the Owner of Object is not itself, anyone has the full permissions.

  • If the request is from the current Zone or a friend Zone, and the source DECApp is same as the DECApp that constructs Object, the request will be granted.

    It's important to add friends cautiously!

  • Otherwise the request will be prevented.

Level

Currently, CYFS already supports several ways to configure ACL:

  • Configured by the req_path field of the request:
    • It can be used to prevent the requests to the service provided by DECApp.
    • It can be used to restrict the access rights of the RootState subtree, and its lower-level subtrees also apply the same permission configuration, unless the lower-level subtrees are configured otherwise.
  • Configure objects that meet certain rules (rmeta).
  • Configure for a single object.

The rules are hit one by one in above order, and the permission configuration with the highest matching degree is found and applied. If you still remember the architectural design of CyfsStack, the ACL system is a Processor in it, and the implementation code is in src\cyfs-stack\src\non_api\acl.

Static configuration as file

ACL can be statically configured by app-manager to read the acl configuration in the installation package when DECApp is installed. For the specific configuration method, refer to the app_acl_config field of the cyfs.config.json file.

The file is used to configure the permissions that the app needs and awarded to others by the app. This file will be read by app-manager when the app is installed, and the corresponding permissions will be registered with the system according to the configured values.

A complete permission configuration file is shown as follows:

[self]

[self.access]   // Grant permissions to your own data by path
// /test3 by each alone group
"/test3" = [{group = "OthersDec", access = "-wx"}, {group = "CurrentDevice", access = "---"}]
// complete string, set/clear each bits for each group
"/test2" = "rwxrwxrwx---rwx---"
"/test1" = "rwxrwxrwx---rwx--x"

[self.specified]    // Authorize your own data to the specified DECApp or user
"/test3" = {access = "--x", dec_id = "9tGpLNnDpa8deXEk2NaWGccEu4yFQ2DrTZJPLYLTxxxx"} // The specified  DECApp running on any zone can call the specified path.
"/test2" = {access = "--x", zone_category = "current-zone", dec_id = "9tGpLNnDpa8deXEk2NaWGccEu4yFQ2DrTZJPLYLTxxxx"} // The specified  DECApp running on the specified zone can call the specified path.
"/test1" = {access = "--x", zone = "5aSixgLwnWbmcDKwBtTBd7p9U4bmqwNU2C6h6SCvxxxx"} // Any DECApp running on the specified zone can call the specified path.

// Request authorization from a specified DECApp(DECID_A)
[DECID_A.specified]
// The `dec_id` field in SpecifiedGroup will never be set, otherwise the rule will be discarded.
"/test3" = {access = "--x"} // Apply for the permission to call the specified path.
"/test2" = {access = "--x", zone_category = "current-zone"} // Apply for the permission to call the specified path limited in the specified zone("current-zone").
"/test1" = {access = "--x", zone = "5aSixgLwnWbmcDKwBtTBd7p9U4bmqwNU2C6h6SCvxxxx"} // Apply for the permission to call the specified path limited in the specified zone("5aSixgLwnWbmcDKwBtTBd7p9U4bmqwNU2C6h6SCvxxxx").

[DECID_A.config]    // **None currently?**
  1. This file is structured in toml format, where each section represents authorization in the same direction, and the section name rules are as follows:

    ${SectionName} = ${dec_id}[.access|specified|config]

  • ${dec_id}: the DecAppId that needs to provide permissions. If it is the current DecAppId (can be replaced by self), it means that the permission is open to others, otherwise, it means that the current DECApp needs the permissions from the specified DECApp.
  • access: A more general permission configuration method divided by group,
  • specified: The way to configure permissions for specific targets (DECApp, Zone, etc.), key is the request path, which can be the path of RootState, or the value of req_path in the request. It can manage permissions more granularly than access
  • config: None?
  1. The content of each line is as follows:

    ${SectionRow} = ${key} = ${AccessString} | ${SpecifiedGroup}

  • ${key}: request path, which can be the path of RootState, or the value of req_path in the request.

  • AccessString: Indicates the complete permission corresponding to a path. Refer to the file system permission in linux. A set of specific permissions is represented by 3 bits. A total of 6 groups of 18 bits represent a complete permission, and each bit represents the authorization of the corresponding group.

    There are 3 permissions currently: Read/Write/Call:

    pub enum AccessPermission {
        Call = 0b001, // 用`x`表示
        Write = 0b010, // 用`w`表示
        Read = 0b100, // 用`r`表示
    }

    And there are 6 groups divided according to device and DECApp:

    pub enum AccessGroup {
        CurrentDevice = 0,
        CurrentZone = 3,
        FriendZone = 6,
        OthersZone = 9,
    
        OwnerDec = 12,
        OthersDec = 15,
    }

    Now, there are 2 methods to represent an AccessString in a configuration file:

    • A complete string, use an 18-chats string to represent a complete permission, and use linux "rwx-" in the group to represent the permission of each bit. Groups can be separated by spaces or underscores

      Example: Full permissions for OwnerDec in CurrentDevice | CurrentZone, read | write permissions for OwnerDec in FriendZone, and read permission for OthersDec in OthersZone. We can express it as "rwxrwxrw-r--rwxr--"; it is equivalent to "rwx rwx rw- r-- rwx r--" or "rwx_rwx_rw-_r--_rwx_r--".

    • Grant permissions for specified groups separately based on the default permissions, expressed as an array formed as {group, access}, group is the enumeration name of AccessGroup, and access is a 3-chats "rwx-" string.
      • Default AccessString permission: "rwxrwxrwx---rwx"
      • Still take the above permissions as an example, expressed as [{group = "FriendZone", access = "rw-"}, {group = "OthersZone", access = "r--"}, {group = "OthersDec" , access = "r--"}]
  • SpecifiedGroup: The permissions of a specific DECApp, Zone, or zone_category, the difference from AccessString is that AccessString can only configure permissions for each group, and SpecifiedGroup can limit permissions into a specific DECApp or Zone.

    There are 4 fields:

    • access: Permission configuration, which is a 3-chats "rwx-" string

    • zone: ZoneId of the Zone which the permission is applied to. Here, it is usually filled with the PeopleId of Zone. You can also fill in a DeviceId, indicating that it is limited to a specific Device. We can remove the field to match any device.

    • zone_category: The group of zone this permission will be applied to, if not filled, it means for any devices. Can take one of the following values:

      • "current-device"
      • "current-zone"
      • "friend-zone"
      • "other-zone"

      I found that the zone_category is words with hyphen, it's different with it in AccessGroup for AccessString. can we use the same style?

    • dec_id: DECApp which this permission applies to, if not filled, it means for any DECApps.

    Among the 4 fields, access is required, and zone, zone_category, and dec_id must be filled in at least one. The permission will be passed when all the three conditions of zone, zone_category, and dec_id are matched.

Dynamic configuration interface

We can config the ACL statically by app-manager to read the acl configuration in the installation package when DECApp is installed. And we can also config it dynamically by calling SharedCyfsStack when the DECApp is running. The entry point of the dynamic configuration interface is:

let meta: GlobalStateMetaStub = SharedCyfsStack.root_state_meta_stub();

GlobalStateMetaStub provides different interfaces for various configuration methods. I will introduce as follow.

  1. req_path constraints
  • add_access: Add a permission constraint on req_path, the core structure is designed as follows:
pub struct GlobalStatePathAccessItem {
    // GlobalState path, must end with /
    pub path: String,

    // Access value, it's a `AccessString` as uint32, or a SpecifiedGroup
    pub access: GlobalStatePathGroupAccess,
}
  • remove_access: Use path as key to delete the parameter specified permission.
  1. rmeta constraints
  • add_object_meta: Add a matching rule, the core structure is designed as follows:
pub struct GlobalStateObjectMetaItem {
    // Object dynamic selector: `${key} ${operator} ${value}`
    pub selector: String,

    // Access value
    pub access: GlobalStatePathGroupAccess,

    // Object referer's depth, default is 1
    pub depth: Option<u8>,
}

We can use the following operators in selector:

`==`, `!=`, `<=`, `>=`, `<`, `>`, `&&`, `||`, `&`, `^`, `|`, `!`.

The key and corresponding value are as follows:

key type value
obj_type_code u16 ObjectTypeCode enum int values
object_category string ObjectCategory enum values
obj_type u16 value of obj_type
object.dec_id string ObjectId
object.author string ObjectId
object.owner string ObjectId
object.create_time u64 bucky time
object.update_time u64 bucky time
object.expired_time u64 bucky time
insert_time u64 bucky time
update_time u64 bucky time
  • remove_object_meta: Use selector as key, delete the permission specified by the parameter.
  1. object_id constraints
  • Just specify the access parameter directly when put_object is called, if you want to change it, call put_object again.

Principles of select

How to choose a method to config the permission, I suggest as follow:

  • You should write it clearly in the static configuration file if you want to grant permissions to the others (other DECApp or Zone); dynamic configuration in the program is more difficult to maintain. You can use dynamic configuration if the static configuration file can not do it.

  • You must write it in this configuration file and let app-manager register during installation, if you want to request permissions from other DECApp. There is no way to register dynamically in code.

  • You must use the specified section to request permissions from other DECApp, anything in the access field is ignored.

  • There is no way to request permissions from other zone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Draft
Development

No branches or pull requests

3 participants