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

athmangude/permissionspec #343

Open
wants to merge 10 commits into
base: dm/permissionspec
Choose a base branch
from
109 changes: 56 additions & 53 deletions specs/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The canonical model for a permissions document is a JSON [JSON] object. When ser
"schemes": ["DelegatedWork"],
"methods": ["GET"],
"paths": {
"/print/settings": {}
"/print/settings": ""
}
}]
}
Expand All @@ -51,33 +51,15 @@ The permissions object contains the details about a permission that can be used
### note
The "note" member is a freeform string that provides additional details about the permission that cannot be determined from the other members of the permission object.

### implicit
The "implicit" member is a boolean value that indicates that the current permission object is implied. The default value is "false". This member is usually set to "true" in combination with a "alsoRequires" expression.

> Note: This member enables support for legacy paths that have been created that do not require any permission. Also, when used in combination with the "alsoRequires" member it enables support for the Microsoft Graph "create subscription" endpoint and the "Search query" endpoint.

### schemes
The "schemes" member is a REQUIRED JSON object whose members are [Scheme objects](#schemeObject) supported by the permission. The key of each member is an identifier of the scheme and the value is a [Scheme object](#schemeObject) that contains descriptions of the permission within the scheme.

### pathSets
The "pathSets" member is a REQUIRED JSON Array. Each element of the array is a [pathSet object](#pathSetObject).

### privilegeLevel
The "privilegeLevel" member value provides a hint as to the risks of consenting this permissions. Valid values include: low, medium and high.

## <a name="provisioningInfo"></a>Provisioning Info Object

The provisioning info object contains information related to the deployment of the permission into its environment. This object should only contain information that is not required by a consumer of the API and can safely be removed in any public projection of the permissions information.

### isHidden
The "isHidden" member is a boolean value that indicates if a permission should be publicly usable in the API.

### requiredEnvironments
The "requiredEnvironments" member is an array of strings that identifies the deployment environments in which the permission SHOULD be supported. When this member is not present, support for all environments is implied.

### resourceAppId
The "resourceAppId" member value provides an identifier of the resource server that is used to enforce Conditional Access checks for this permission.
## <a name="ownerInfo"></a>Owner Info Object

The owner info object contains information related to the ownership of the permission. This object should only contain information that is not required by a consumer of the API and can safely be removed in any public projection of the permissions information.
### ownerSecurityGroup
The "ownerSecurityGroup" member is a REQUIRED string that provides a contact mechanism for communicating with the owners of the permission. It is important that owners of permissions are aware when new paths are added to an existing permission.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should qualify that ownerSecurityGroup is only required when ownerInfo is present otherwise it is a contradiction saying that it can be "safely removed".


Expand All @@ -98,7 +80,7 @@ A pathSet object identifies a set of paths that are accessible and have a common
"schemeKeys": ["Application"],
"methods": ["GET,POST"],
"paths": {
"/print/settings": {}
"/print/settings": ""
}
}
]
Expand All @@ -113,9 +95,6 @@ The "methods" member is a REQUIRED array of strings that represent the HTTP meth
### paths
The "paths" member is a REQUIRED object whose keys contain a simplified URI template to identify the resources protected by this permission object.

### alsoRequires
The "alsoRequires" member is logical expression of permissions that must be presented as claims alongside the current permission.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to go back here.

```
(User.Read | User.Read.All) & Group.Read
```
Expand All @@ -126,7 +105,6 @@ The "includedProperties" member is an array of strings that identify properties
### excludedProperties
The "excludedProperties" member is an array of strings that identify properties of the resource representation returned by the path, that are not accessible with the permission.


## <a name="schemeObject"></a>Scheme Object
The scheme object has members that describe the permission within the context of the scheme. Additional members provide behavioral constraints of the permission when used with the scheme.

Expand All @@ -137,15 +115,18 @@ The scheme object has members that describe the permission within the context of
"adminDescription": "Allows the app to read and report the signed-in user's activity in the app.",
"userConsentDisplayName": "Read and write app activity to users'activity feed",
"userConsentDescription": "Allows the app to read and report the signed-in user's activity in the app.",
"requiresAdminConsent": true
"requiresAdminConsent": true,
"privilegeLevel": 3
Copy link
Contributor

@darrelmiller darrelmiller May 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using integer values is problematic because how does anyone know if 1 is high privilege or 5 is? I see it is in the description, but that doesn't help when just looking at the JSON object.

},
"DelegatedPersonal": {
"userConsentDisplayName": "Read and write app activity to users'activity feed",
"userConsentDescription": "Allows the app to read and report the signed-in user's activity in the app."
"userConsentDescription": "Allows the app to read and report the signed-in user's activity in the app.",
"privilegeLevel": 2
},
"Application": {
"adminDisplayName": "Read and write app activity to users' activity feed",
"adminDescription": "Allows the app to read and report the signed-in user's activity in the app.",
"privilegeLevel": 5
}
```

Expand All @@ -164,17 +145,50 @@ The "userConsentDescription" member is a REQUIRED string that describes the perm
### requiresAdminConsent
The "requiresAdminConsent" member is a boolean value with a default value of false. When true, this permission can only be consented by an adminstrator.

### privilegeLevel
The "privilegeLevel" member is an integer value that provides a hint as to the risks of consenting to the permissions. Valid values range from 1 (least privileged) to 5 (most privileged). The value is arrived at by considering the breadth of access that a permission will give access to and the sensitivity of the operations allowed by the permission. The same permission can have different privilege levels when used with different schemes.

## <a name="pathObject"></a>Path Object
The path object contains properties that affect how the permission object controls access to resource identified by the key of the path object.
The path object contains stringified properties and value pairs that affect how the permission object controls access to resource identified by the key of the path object.

```json
"paths": {
"/me/activities/{id}": "least=DelegatedWork,DelegatedPersonal"
```

```json
"paths": {
"/me/activities/{id}": {
"leastPrivilegePermission": ["DelegatedWork", "DelegatedPersonal"]
}
"/search/query": "implicit=true;alsoRequires=Bookmark.Read.All;least=Delegated"
}
```

### leastPrivilegePermission
### alsoRequires
The "alsoRequires" member is logical expression of permissions that must be presented as claims alongside the current permission.

The value `alsoRequires` member can express complex logical expressions using boolean operators.

```json
"paths": {
"/search/query": "implicit=true;alsoRequires=Bookmark.Read.All||ChatMessages.Read;least=Delegated"
}
```
The example above shows that any one of a list of additional permissions are required.

We can also express more complex scenarios using parenthesis.

```json
"paths": {
"/foo/bar": "implicit=true;alsoRequires=(PermissionA.Read.All||PermissionB.Read)&&(PermissionC.Read.All&&PermissionD.Read.All);least=Delegated",
"/foo/barz": "implicit=true;alsoRequires=(PermissionA.Read.All&&PermissionB.Read)||(PermissionC.Read.All&&PermissionD.Read.All);least=Delegated"
}
```

### implicit
The "implicit" member is a boolean value that indicates that the current permission object is implied. The default value is "false". This member is usually set to "true" in combination with a "alsoRequires" expression.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just remove implicit unless we find a place where we need it.

We cannot associate implicit to a path because we don't describe paths anywhere. We only describe relationships between paths and permissions.


> Note: This member enables support for legacy paths that have been created that do not require any permission. Also, when used in combination with the "alsoRequires" member it enables support for the Microsoft Graph "create subscription" endpoint and the "Search query" endpoint.

### least (least privilege permission)
The "leastPrivilegePermission" member is an array of strings that identify the schemes for which the current permission is the least privilege permission for accessing the path. Each string value in the array MUST match one of the schemes defined in the [pathSet Object](#pathsetObject)

## Appendix A. Model Diagram
Expand All @@ -184,25 +198,24 @@ classDiagram

class Permission{
note: string
implicit: bool
requiredEnvironments: string[]
ownerEmail:string
isHidden: bool
privilegeLevel: string
}
Permission "1" --> "*" PathSet:pathSets
Permission "1" --> "*" Scheme:schemes

class PathSet{
schemeKeys: string[]
methods: string[]
alsoRequires: stringExpression
includedProperties: string[]
excludedProperties: string[]
}
PathSet "1" --> "*" Path:paths

class Path{
alsoRequires: stringExpression
implicit: bool
leastPrivilegePermission: string
}

Expand All @@ -212,6 +225,7 @@ classDiagram
userDisplayName: string
userDescription: string
requiresAdminConsent: string
privilegeLevel: int
}

```
Expand Down Expand Up @@ -243,23 +257,13 @@ classDiagram
"additionalProperties": false,
"properties": {
"note": {"type": "string"},
"implicit": {"type": "boolean"},
"isHidden": {"type": "boolean"},
"ownerEmail": {"type": "string"},
"privilegeLevel": {
"type":"string",
"enum":["low","medium","high"]
}
"requiredEnvironments": {
"type": "array",
"items": {
"type": "string"
}
},
"alsoRequires": {
"type": "string",
"pattern": "[\\w]+\\.[\\w]+[\\.[\\w]+]?"
},
"schemes": {
"type": "object",
"patternProperties": {
Expand Down Expand Up @@ -318,13 +322,8 @@ classDiagram
}
},
"path": {
"type": "object",
"properties": {
"leastPrivilegePermission": {
"type": "array",
"items": { "type":"string"}
}
},
"type": "string",
},
"scheme": {
"type": "object",
"properties": {
Expand All @@ -342,6 +341,10 @@ classDiagram
},
"userConsentDescription": {
"type": "string"
},
"privilegeLevel": {
"type": "int",
"enum": [1, 2, 3, 4, 5]
}
}
}
Expand Down