From 2bc1a19c42ade7b00394e6816f1a1396e16c0549 Mon Sep 17 00:00:00 2001 From: Darrel Miller Date: Tue, 26 Jul 2022 22:28:04 -0400 Subject: [PATCH 01/10] First crack at permissions spec --- specs/permissions.md | 283 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 specs/permissions.md diff --git a/specs/permissions.md b/specs/permissions.md new file mode 100644 index 000000000..4eb828786 --- /dev/null +++ b/specs/permissions.md @@ -0,0 +1,283 @@ +# Permissions for HTTP APIs + +## Abstract +This document defines a "permission" object and "permissions" document that describes identifiers that can be used by security claims to grant access to HTTP resources. + +## Introduction + +## Notational Conventions +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. + +## Permissions JSON Object +The canonical model for a permissions document is a JSON [JSON] object. When serialized in a JSON document, that format is identified with the "application/permissions+json" media type. + +```json +{ +  "permissions": { +    "PrintSettings.Read.All": { +      "schemes": { +        "DelegatedWork": { +          "type": "DelegatedWork", +          "description": "Allow signed in user to read print settings", +        } +      }, +      "pathSets": [ +        { +          "schemes": ["DelegatedWork"], +          "methods": ["GET"], +          "paths": { +            "/print/settings": {} +          } +        } +      ] +    } +} +``` +In this example, the claim "PrintSettings.Read.All" is required when using the "DelegatedWork" security scheme to access the resource "/print/settings" using the "GET" method. + +### permissions +The "permissions" member is a JSON object whose members permission objects. The key of each member is the claim identifier used for the [Permission Object](#permissionObject) + + +## Permission Object + +### note +The "note" member is a freeform string that provides additional details at about the permission that cannot be determined from the other members of the permission object. + +### alsoRequires +The "alsoRequires" member is logical expression of permissions that must be presented as claims alongside the current permission. + +``` +(User.Read | User.Read.All) & Group.Read +``` + +### implicit +The "implicit" member is a boolean value that indicates that the current permission object is implied. The default value is "false". This member us usually set to "true" in combination with a "alsoRequires" expression. + +> Note: This member 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). + +### 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. + +### privilegeLevel +The "privilegeLevel" member value provides a hint as to the risks of consenting this permissions. Valid values include: low, medium and high. + +### appIdForConditionalAccessChecks +TBD + +### ownerEmail +The "ownerEmail" member is a REQUIRED string that provides a contact mechanism for communicating with the owner of the permission. It is important that owners of permissions are aware when new paths are added to an existing permission. + +## PathSet Object +A pathSet object identifies a set of paths that are accessible via the identified HTTP methods and schemes. Ideally, a permission object contains a single pathSet object. This indicates that all paths protected by the permission support the same HTTP methods and and schemes. In practice there are cases where support is not uniform. Distinct pathSet objects can be created to separate the paths with varying support. + +> Note: The design chosen was intentional to encourage permission creators to ensure support for methods and schemes is as consistent as possible. This produces a better developer experience for API consumers. + +```json +      "pathSets": [ +        { +          "schemes": ["DelegatedWork"], +          "methods": ["GET"], +          "paths": { +            "/print/settings": {} +          } +        }, +        { +          "schemes": ["Application"], +          "methods": ["GET,POST"], +          "paths": { +            "/print/settings": {} +          } +        } +      ] +``` + +### schemes +The "schemes" member is a REQUIRED array of strings that reference the schemes defined in the [permission object](#permissionObject) that are supported by the paths in this pathSet object. + +### methods +The "methods" member is a REQUIRED array of strings that represent the HTTP methods supported by the paths in this pathSet object. + +### paths +The "paths" member is a REQUIRED object whose keys contain a simplified URI template to identify the resources protected by this permission object. + +## 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. + +```json +"schemes": { + "DelegatedWork": { + "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.", + "consentDisplayName": "Read and write app activity to users'activity feed", + "consentDescription": "Allows the app to read and report the signed-in user's activity in the app.", + "requiresAdminConsent": true + }, + "DelegatedPersonal": { + "type": "DelegatedPersonal", + "consentDisplayName": "Read and write app activity to users'activity feed", + "consentDescription": "Allows the app to read and report the signed-in user's activity in the app." + }, + "Application": { + "type": "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.", + } +``` +### adminDisplayName +The "adminDisplayName" member is a string that provides a short permission name that considers the current scheme and the perspective of a resource administrator. + +### adminDescription +The "adminDescription" member is a string that describes the permission considering the current scheme from the perspective of a resource administrator. + +### consentDisplayName +The "consentDisplayName" member is a REQUIRED string that provides a short permission name that considers the current scheme and the perspective of the user consenting an application. + +### consentDescription +The "consentDescription" member is a REQUIRED string that describes the permission considering the current scheme from the perspective of the user consenting an application. + +### 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. + +## 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. + +```json +"paths": { + "/me/activities/{id}": { + "leastPrivilegePath": ["DelegateedWork", "DelegatedPersonal"], + "includedProperties": ["id","displayName"], + "excludedProperties": ["cost"] + } +``` +### leastPrivilegePath +The "leastPrivilegePath" member is an array of strings that identify the schemes for which this permission is the least privilege permission for accessing the path. + +### includedProperties +The "includedProperties" member is an array of strings that identify properties of the resource representation returned by the path, that are accessible with the permission. + +### excludedProperties +The "includedProperties" member is an array of strings that identify properties of the resource representation returned by the path, that are not accessible with the permission. + +## Appendix A. JSON Schema for HTTP Problem +```json +{ + "$schema": "http://json-schema.org/draft-07/schema", + "title": "Schema for OAuth Permissions", + "type": "object", + "properties": { + "additionalProperties": false, + "permissions": { + "title": "Map of permission name to definition", + "additionalProperties": false, + "type": "object", + "patternProperties": { + "[\\w]+\\.[\\w]+[\\.[\\w]+]?": { + "type": "object", + "title": "Permission definition", + "additionalProperties": false, + "properties": { + "note": { + "type": "string" + }, + "alsoRequires": { + "type": "string", + "pattern": "[\\w]+\\.[\\w]+[\\.[\\w]+]?" + }, + "schemes": { + "type": "object", + "patternProperties": { + ".*": { + "$ref": "#/definitions/scheme" + } + } + } + }, + "pathSets": { + "type": "array", + "items": { + "$ref": "#/definitions/pathSet" + } + } + } + } + } + } + } + }, + "definitions": { + "schemeTypes": { + "type": "string", + "enum": [ + "delegated-work", + "delegated-personal", + "application", + "resource-specific-consent" + ] + }, + "pathSet": { + "type": "object", + "additionalProperties": false, + "properties": { + "schemes": { + "type": "array", + "items": { + "$ref": "#/definitions/schemeTypes" + } + }, + "methods": { + "type": "array", + "items": { + "type": "string", + "enum": ["GET","PUT","POST","DELETE","PATCH","HEAD","OPTIONS","","" + ] + } + }, + "paths": { + "type": "object", + "patternProperties": { + ".*": { + "$ref": "#/definitions/path" + } + } + } + } + }, + "path": { + "type": "object", + "properties": { + "excludeProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "scheme": { + "type": "object", + "properties": { + "requiresAdminConsent": { + "type": "boolean" + }, + "type": { + "$ref": "#/definitions/schemeTypes" + }, + "description": { + "type": "string" + }, + "consentDescription": { + "type": "string" + } + } + } +} +``` \ No newline at end of file From fd5f4616334f697f8edbb82d9309a4c43be4453d Mon Sep 17 00:00:00 2001 From: Darrel Miller Date: Tue, 26 Jul 2022 22:32:52 -0400 Subject: [PATCH 02/10] Tried to fix JSON formatting --- specs/permissions.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/specs/permissions.md b/specs/permissions.md index 4eb828786..7243479ab 100644 --- a/specs/permissions.md +++ b/specs/permissions.md @@ -83,22 +83,22 @@ A pathSet object identifies a set of paths that are accessible via the identifie > Note: The design chosen was intentional to encourage permission creators to ensure support for methods and schemes is as consistent as possible. This produces a better developer experience for API consumers. ```json -      "pathSets": [ -        { -          "schemes": ["DelegatedWork"], -          "methods": ["GET"], -          "paths": { -            "/print/settings": {} -          } -        }, -        { -          "schemes": ["Application"], -          "methods": ["GET,POST"], -          "paths": { -            "/print/settings": {} -          } -        } -      ] + "pathSets": [ +   { +     "schemes": ["DelegatedWork"], +     "methods": ["GET"], +     "paths": { + "/print/settings": {} +     } +   }, +   { +     "schemes": ["Application"], +     "methods": ["GET,POST"], +     "paths": { + "/print/settings": {} +     } +   } + ] ``` ### schemes From 95a371152db191390c3a8474c0da4e7b9ea194eb Mon Sep 17 00:00:00 2001 From: Darrel Miller Date: Tue, 26 Jul 2022 22:38:43 -0400 Subject: [PATCH 03/10] Tried to fix JSON formatting again --- specs/permissions.md | 68 +++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/specs/permissions.md b/specs/permissions.md index 7243479ab..04c4267e5 100644 --- a/specs/permissions.md +++ b/specs/permissions.md @@ -12,25 +12,24 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S The canonical model for a permissions document is a JSON [JSON] object. When serialized in a JSON document, that format is identified with the "application/permissions+json" media type. ```json -{ -  "permissions": { -    "PrintSettings.Read.All": { -      "schemes": { -        "DelegatedWork": { -          "type": "DelegatedWork", -          "description": "Allow signed in user to read print settings", -        } -      }, -      "pathSets": [ -        { -          "schemes": ["DelegatedWork"], -          "methods": ["GET"], -          "paths": { -            "/print/settings": {} -          } -        } -      ] -    } +{ + "permissions": { + "PrintSettings.Read.All": { + "schemes": { + "DelegatedWork": { + "type": "DelegatedWork", + "description": "Allow signed in user to read print settings" + } + }, + "pathSets": [{ + "schemes": ["DelegatedWork"], + "methods": ["GET"], + "paths": { + "/print/settings": {} + } + }] + } + } } ``` In this example, the claim "PrintSettings.Read.All" is required when using the "DelegatedWork" security scheme to access the resource "/print/settings" using the "GET" method. @@ -83,22 +82,21 @@ A pathSet object identifies a set of paths that are accessible via the identifie > Note: The design chosen was intentional to encourage permission creators to ensure support for methods and schemes is as consistent as possible. This produces a better developer experience for API consumers. ```json - "pathSets": [ -   { -     "schemes": ["DelegatedWork"], -     "methods": ["GET"], -     "paths": { - "/print/settings": {} -     } -   }, -   { -     "schemes": ["Application"], -     "methods": ["GET,POST"], -     "paths": { - "/print/settings": {} -     } -   } - ] +"pathSets": [{ + "schemes": ["DelegatedWork"], + "methods": ["GET"], + "paths": { + "/print/settings": {} + } + }, + { + "schemes": ["Application"], + "methods": ["GET,POST"], + "paths": { + "/print/settings": {} + } + } +] ``` ### schemes From fb5ed70cd6ba2cce24eff5bb6853c065a86632bb Mon Sep 17 00:00:00 2001 From: Darrel Miller Date: Wed, 27 Jul 2022 10:59:47 -0400 Subject: [PATCH 04/10] Updated with diagram --- specs/permissions.md | 189 ++++++++++++++++++++++++++++--------------- 1 file changed, 124 insertions(+), 65 deletions(-) diff --git a/specs/permissions.md b/specs/permissions.md index 04c4267e5..5ff24446a 100644 --- a/specs/permissions.md +++ b/specs/permissions.md @@ -32,6 +32,7 @@ The canonical model for a permissions document is a JSON [JSON] object. When ser } } ``` + In this example, the claim "PrintSettings.Read.All" is required when using the "DelegatedWork" security scheme to access the resource "/print/settings" using the "GET" method. ### permissions @@ -43,13 +44,6 @@ The "permissions" member is a JSON object whose members permission objects. The ### note The "note" member is a freeform string that provides additional details at about the permission that cannot be determined from the other members of the permission object. -### alsoRequires -The "alsoRequires" member is logical expression of permissions that must be presented as claims alongside the current permission. - -``` -(User.Read | User.Read.All) & Group.Read -``` - ### implicit The "implicit" member is a boolean value that indicates that the current permission object is implied. The default value is "false". This member us usually set to "true" in combination with a "alsoRequires" expression. @@ -77,20 +71,20 @@ TBD The "ownerEmail" member is a REQUIRED string that provides a contact mechanism for communicating with the owner of the permission. It is important that owners of permissions are aware when new paths are added to an existing permission. ## PathSet Object -A pathSet object identifies a set of paths that are accessible via the identified HTTP methods and schemes. Ideally, a permission object contains a single pathSet object. This indicates that all paths protected by the permission support the same HTTP methods and and schemes. In practice there are cases where support is not uniform. Distinct pathSet objects can be created to separate the paths with varying support. +A pathSet object identifies a set of paths that are accessible have a common set of security characteristics, such as HTTP methods and schemes. Ideally, a permission object contains a single pathSet object. This indicates that all paths protected by the permission support the same characteristics. In practice there are cases where support is not uniform. Distinct pathSet objects can be created to separate the paths with varying characteristics. > Note: The design chosen was intentional to encourage permission creators to ensure support for methods and schemes is as consistent as possible. This produces a better developer experience for API consumers. ```json "pathSets": [{ - "schemes": ["DelegatedWork"], + "schemeKeys": ["DelegatedWork"], "methods": ["GET"], "paths": { "/print/settings": {} } }, { - "schemes": ["Application"], + "schemeKeys": ["Application"], "methods": ["GET,POST"], "paths": { "/print/settings": {} @@ -99,8 +93,8 @@ A pathSet object identifies a set of paths that are accessible via the identifie ] ``` -### schemes -The "schemes" member is a REQUIRED array of strings that reference the schemes defined in the [permission object](#permissionObject) that are supported by the paths in this pathSet object. +### schemeKeys +The "schemeKeys" member is a REQUIRED array of strings that reference the schemes defined in the [permission object](#permissionObject) that are supported by the paths in this pathSet object. Each value in this array MUST match one of the keys of the "schemes" member in the [permission object](#permissionObject). ### methods The "methods" member is a REQUIRED array of strings that represent the HTTP methods supported by the paths in this pathSet object. @@ -108,6 +102,20 @@ 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. + +``` +(User.Read | User.Read.All) & Group.Read +``` + +### includedProperties +The "includedProperties" member is an array of strings that identify properties of the resource representation returned by the path, that are accessible with the permission. + +### excludedProperties +The "includedProperties" member is an array of strings that identify properties of the resource representation returned by the path, that are not accessible with the permission. + + ## 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. @@ -121,16 +129,15 @@ The scheme object has members that describe the permission within the context of "requiresAdminConsent": true }, "DelegatedPersonal": { - "type": "DelegatedPersonal", "consentDisplayName": "Read and write app activity to users'activity feed", "consentDescription": "Allows the app to read and report the signed-in user's activity in the app." }, "Application": { - "type": "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.", } ``` + ### adminDisplayName The "adminDisplayName" member is a string that provides a short permission name that considers the current scheme and the perspective of a resource administrator. @@ -157,16 +164,50 @@ The path object contains properties that affect how the permission object contro "excludedProperties": ["cost"] } ``` + ### leastPrivilegePath The "leastPrivilegePath" member is an array of strings that identify the schemes for which this permission is the least privilege permission for accessing the path. -### includedProperties -The "includedProperties" member is an array of strings that identify properties of the resource representation returned by the path, that are accessible with the permission. +## Appendix A. Model Diagram -### excludedProperties -The "includedProperties" member is an array of strings that identify properties of the resource representation returned by the path, that are not accessible with the permission. +```mermaid +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{ + leastPrivilegePath: string + } + + class Scheme{ + adminDisplayName: string + adminDescription: string + userDisplayName: string + userDescription: string + requiresAdminConsent: string + } -## Appendix A. JSON Schema for HTTP Problem +``` + +## Appendix B. JSON Schema for HTTP Problem ```json { "$schema": "http://json-schema.org/draft-07/schema", @@ -180,56 +221,61 @@ The "includedProperties" member is an array of strings that identify properties "type": "object", "patternProperties": { "[\\w]+\\.[\\w]+[\\.[\\w]+]?": { - "type": "object", - "title": "Permission definition", - "additionalProperties": false, - "properties": { - "note": { - "type": "string" - }, - "alsoRequires": { - "type": "string", - "pattern": "[\\w]+\\.[\\w]+[\\.[\\w]+]?" - }, - "schemes": { - "type": "object", - "patternProperties": { - ".*": { - "$ref": "#/definitions/scheme" - } - } - } - }, - "pathSets": { - "type": "array", - "items": { - "$ref": "#/definitions/pathSet" - } - } - } - } + "$ref": "#/definitions/permission" + } } } } }, "definitions": { - "schemeTypes": { - "type": "string", - "enum": [ - "delegated-work", - "delegated-personal", - "application", - "resource-specific-consent" - ] - }, - "pathSet": { + "permission": { "type": "object", + "title": "Permission definition", "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": { + ".*": { + "$ref": "#/definitions/scheme" + } + } + } + }, + "pathSets": { + "type": "array", + "items": { + "$ref": "#/definitions/pathSet" + } + } + } + }, + "pathSet": { + "type": "object", + "additionalProperties": false, + "properties": { + "schemeKeys": { "type": "array", "items": { - "$ref": "#/definitions/schemeTypes" + "type": "string" } }, "methods": { @@ -248,16 +294,26 @@ The "includedProperties" member is an array of strings that identify properties } } } + }, + "includeProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "excludeProperties": { + "type": "array", + "items": { + "type": "string" + } } }, "path": { "type": "object", "properties": { - "excludeProperties": { + "leastPrivilegePath": { "type": "array", - "items": { - "type": "string" - } + "items": { "type":"string"} } }, "scheme": { @@ -266,10 +322,13 @@ The "includedProperties" member is an array of strings that identify properties "requiresAdminConsent": { "type": "boolean" }, - "type": { - "$ref": "#/definitions/schemeTypes" + "adminDisplayName": { + "type": "string" + }, + "adminDescription": { + "type": "string" }, - "description": { + "consentDisplayName": { "type": "string" }, "consentDescription": { From e382eee1408cbb2b2d8ba423d86f06908ee2e24c Mon Sep 17 00:00:00 2001 From: Darrel Miller Date: Wed, 27 Jul 2022 14:16:56 -0400 Subject: [PATCH 05/10] renamed leastPrivilegedPath --- specs/permissions.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/specs/permissions.md b/specs/permissions.md index 5ff24446a..30c17a1ea 100644 --- a/specs/permissions.md +++ b/specs/permissions.md @@ -159,14 +159,12 @@ The path object contains properties that affect how the permission object contro ```json "paths": { "/me/activities/{id}": { - "leastPrivilegePath": ["DelegateedWork", "DelegatedPersonal"], - "includedProperties": ["id","displayName"], - "excludedProperties": ["cost"] + "leastPrivilegePermission": ["DelegatedWork", "DelegatedPersonal"] } ``` -### leastPrivilegePath -The "leastPrivilegePath" member is an array of strings that identify the schemes for which this permission is the least privilege permission for accessing the path. +### leastPrivilegePermission +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 @@ -194,7 +192,7 @@ classDiagram PathSet "1" --> "*" Path:paths class Path{ - leastPrivilegePath: string + leastPrivilegePermission: string } class Scheme{ @@ -311,7 +309,7 @@ classDiagram "path": { "type": "object", "properties": { - "leastPrivilegePath": { + "leastPrivilegePermission": { "type": "array", "items": { "type":"string"} } From f6a3f96f64d6c4444709401072de3124e27a30d6 Mon Sep 17 00:00:00 2001 From: Darrel Miller Date: Thu, 28 Jul 2022 11:49:25 -0400 Subject: [PATCH 06/10] Added introduction --- specs/permissions.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/specs/permissions.md b/specs/permissions.md index 30c17a1ea..c802740bd 100644 --- a/specs/permissions.md +++ b/specs/permissions.md @@ -4,6 +4,11 @@ This document defines a "permission" object and "permissions" document that describes identifiers that can be used by security claims to grant access to HTTP resources. ## Introduction +Protecting data in HTTP APIs from unauthorized access is critical. One technique to do this is by associating permissions with resources and requiring API callers to present a bearer token that can prove what permissions have been consented to the caller. This document describes a JSON based document format that can store the relationships between permission and resource. + +In this design, the permission is the primary concept and the resources that are controlled are associated to the permission. The relationship is many-to-many and so could be modelled in an inverted way with resources being assigned the permissions. However, the permission centric view was chosen to emphasise to the author of the permission the scope of control being assigned to the permission. It is the opposite view to how this information will often be used in tooling. Tooling will need to invert the model to identify what permissions could be used to access a resource. The trade-off is the tooling writers will need to do more for the benefit of permission authors. Application users and administrators are increasingly asking for the ability to consent to more fine-grained permissions that are limited in the number of resources they can access via a single permission. This limits the ability of applications performing unintended or malicious actions on behalf of users. Models that present a resource centric view of permissions obscure the total scope of the permission and lead to the creation of permissions that create unnecessary risk. + +The relationship between a permission and the resources it controls have a number of attributes including the HTTP method being granted, the type of security scheme being used, and properties of the resource being protected. Ideally these relationships would be consistent for all resources controlled by a permission. However, in reality that is not always the case. This model enables modelling the paths as sets of paths that do behave consistently and a permission can have multiple sets of paths. This approach minimizes the duplication of relationship attributes and encourages consistency in relationship design due to the overhead of managing distinct path sets. ## Notational Conventions The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. @@ -17,8 +22,8 @@ The canonical model for a permissions document is a JSON [JSON] object. When ser "PrintSettings.Read.All": { "schemes": { "DelegatedWork": { - "type": "DelegatedWork", - "description": "Allow signed in user to read print settings" + "consentDisplayName": "Read print settings", + "consentDescription": "Allow signed in user to read print settings" } }, "pathSets": [{ @@ -47,7 +52,7 @@ The "note" member is a freeform string that provides additional details at about ### implicit The "implicit" member is a boolean value that indicates that the current permission object is implied. The default value is "false". This member us usually set to "true" in combination with a "alsoRequires" expression. -> Note: This member enables support for the Microsoft Graph create subscription endpoint and the Search query endpoint. +> 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. From d684ba989a8a3f06a0c33f631f441361f7d2719c Mon Sep 17 00:00:00 2001 From: Darrel Date: Sun, 14 Aug 2022 17:59:00 -0400 Subject: [PATCH 07/10] Update specs/permissions.md Co-authored-by: Peter Richards <15617285+PetRich-MSFT@users.noreply.github.com> --- specs/permissions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/permissions.md b/specs/permissions.md index c802740bd..ced700100 100644 --- a/specs/permissions.md +++ b/specs/permissions.md @@ -118,7 +118,7 @@ The "alsoRequires" member is logical expression of permissions that must be pres The "includedProperties" member is an array of strings that identify properties of the resource representation returned by the path, that are accessible with the permission. ### excludedProperties -The "includedProperties" member is an array of strings that identify properties of the resource representation returned by the path, that are not accessible with the permission. +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. ## Scheme Object From e16b7cd2ce3ad189d4eea772a4d8d9de06277f2a Mon Sep 17 00:00:00 2001 From: Darrel Date: Sun, 14 Aug 2022 18:11:43 -0400 Subject: [PATCH 08/10] Update specs/permissions.md Co-authored-by: Peter Richards <15617285+PetRich-MSFT@users.noreply.github.com> --- specs/permissions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/permissions.md b/specs/permissions.md index ced700100..a67fdfcd5 100644 --- a/specs/permissions.md +++ b/specs/permissions.md @@ -76,7 +76,7 @@ TBD The "ownerEmail" member is a REQUIRED string that provides a contact mechanism for communicating with the owner of the permission. It is important that owners of permissions are aware when new paths are added to an existing permission. ## PathSet Object -A pathSet object identifies a set of paths that are accessible have a common set of security characteristics, such as HTTP methods and schemes. Ideally, a permission object contains a single pathSet object. This indicates that all paths protected by the permission support the same characteristics. In practice there are cases where support is not uniform. Distinct pathSet objects can be created to separate the paths with varying characteristics. +A pathSet object identifies a set of paths that are accessible and have a common set of security characteristics, such as HTTP methods and schemes. Ideally, a permission object contains a single pathSet object. This indicates that all paths protected by the permission support the same characteristics. In practice there are cases where support is not uniform. Distinct pathSet objects can be created to separate the paths with varying characteristics. > Note: The design chosen was intentional to encourage permission creators to ensure support for methods and schemes is as consistent as possible. This produces a better developer experience for API consumers. From 052d84da422fd7f461302d422a474ce6e377f1a6 Mon Sep 17 00:00:00 2001 From: Darrel Miller Date: Fri, 2 Sep 2022 16:17:03 -0400 Subject: [PATCH 09/10] Updated to add provisioningInfo object --- specs/permissions.md | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/specs/permissions.md b/specs/permissions.md index c802740bd..7a19594df 100644 --- a/specs/permissions.md +++ b/specs/permissions.md @@ -22,8 +22,8 @@ The canonical model for a permissions document is a JSON [JSON] object. When ser "PrintSettings.Read.All": { "schemes": { "DelegatedWork": { - "consentDisplayName": "Read print settings", - "consentDescription": "Allow signed in user to read print settings" + "userConsentDisplayName": "Read print settings", + "userConsentDescription": "Allow signed in user to read print settings" } }, "pathSets": [{ @@ -46,6 +46,8 @@ The "permissions" member is a JSON object whose members permission objects. The ## Permission Object +The permissions object contains the details about a permission that can be used as claim in a API security token. + ### note The "note" member is a freeform string that provides additional details at about the permission that cannot be determined from the other members of the permission object. @@ -60,20 +62,24 @@ The "schemes" member is a REQUIRED JSON object whose members are [Scheme objects ### 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. + +## 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. -### privilegeLevel -The "privilegeLevel" member value provides a hint as to the risks of consenting this permissions. Valid values include: low, medium and high. - -### appIdForConditionalAccessChecks -TBD +### resourceAppId +The "resourceAppId" member value provides an identifier of the resource server that is used to enforce Conditional Access checks for this permission. -### ownerEmail -The "ownerEmail" member is a REQUIRED string that provides a contact mechanism for communicating with the owner of the permission. It is important that owners of permissions are aware when new paths are added to an existing permission. +### 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. ## PathSet Object A pathSet object identifies a set of paths that are accessible have a common set of security characteristics, such as HTTP methods and schemes. Ideally, a permission object contains a single pathSet object. This indicates that all paths protected by the permission support the same characteristics. In practice there are cases where support is not uniform. Distinct pathSet objects can be created to separate the paths with varying characteristics. @@ -129,13 +135,13 @@ The scheme object has members that describe the permission within the context of "DelegatedWork": { "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.", - "consentDisplayName": "Read and write app activity to users'activity feed", - "consentDescription": "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 }, "DelegatedPersonal": { - "consentDisplayName": "Read and write app activity to users'activity feed", - "consentDescription": "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." }, "Application": { "adminDisplayName": "Read and write app activity to users' activity feed", @@ -149,11 +155,11 @@ The "adminDisplayName" member is a string that provides a short permission name ### adminDescription The "adminDescription" member is a string that describes the permission considering the current scheme from the perspective of a resource administrator. -### consentDisplayName -The "consentDisplayName" member is a REQUIRED string that provides a short permission name that considers the current scheme and the perspective of the user consenting an application. +### userConsentDisplayName +The "userConsentDisplayName" member is a REQUIRED string that provides a short permission name that considers the current scheme and the perspective of the user consenting an application. -### consentDescription -The "consentDescription" member is a REQUIRED string that describes the permission considering the current scheme from the perspective of the user consenting an application. +### userConsentDescription +The "userConsentDescription" member is a REQUIRED string that describes the permission considering the current scheme from the perspective of the user consenting an application. ### 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. @@ -331,10 +337,10 @@ classDiagram "adminDescription": { "type": "string" }, - "consentDisplayName": { + "userConsentDisplayName": { "type": "string" }, - "consentDescription": { + "userConsentDescription": { "type": "string" } } From ae03c13aa85e7191f2f745bea87062ecfe64d679 Mon Sep 17 00:00:00 2001 From: njaci1 Date: Tue, 7 Feb 2023 12:33:27 +0300 Subject: [PATCH 10/10] Update permissions.md Corrected two grammatical error for ease of readability. --- specs/permissions.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/permissions.md b/specs/permissions.md index 0698dd7cb..bc4689435 100644 --- a/specs/permissions.md +++ b/specs/permissions.md @@ -41,7 +41,7 @@ The canonical model for a permissions document is a JSON [JSON] object. When ser In this example, the claim "PrintSettings.Read.All" is required when using the "DelegatedWork" security scheme to access the resource "/print/settings" using the "GET" method. ### permissions -The "permissions" member is a JSON object whose members permission objects. The key of each member is the claim identifier used for the [Permission Object](#permissionObject) +The "permissions" member is a JSON object whose members are permission objects. The key of each member is the claim identifier used for the [Permission Object](#permissionObject) ## Permission Object @@ -49,10 +49,10 @@ The "permissions" member is a JSON object whose members permission objects. The The permissions object contains the details about a permission that can be used as claim in a API security token. ### note -The "note" member is a freeform string that provides additional details at about the permission that cannot be determined from the other members of the permission object. +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 us usually set to "true" in combination with a "alsoRequires" expression. +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. @@ -346,4 +346,4 @@ classDiagram } } } -``` \ No newline at end of file +```