Spec the terms of service handling for identity servers

Part of MSC2140

Convert status codes to strings if there is a string status code. Fixes a build error when we mix 4xx and 403 in the same definition. We also have to correct stringified numbers to pass the build.
pull/977/head
Travis Ralston 5 years ago
parent b7e84cf4ce
commit afd5018494

@ -165,7 +165,7 @@ paths:
description: The token generated by the ``requestToken`` call and emailed to the user. description: The token generated by the ``requestToken`` call and emailed to the user.
x-example: atoken x-example: atoken
responses: responses:
"200": 200:
description: Email address is validated. description: Email address is validated.
"3xx": "3xx":
description: |- description: |-

@ -167,7 +167,7 @@ paths:
description: The token generated by the ``requestToken`` call and sent to the user. description: The token generated by the ``requestToken`` call and sent to the user.
x-example: atoken x-example: atoken
responses: responses:
"200": 200:
description: Phone number is validated. description: Phone number is validated.
"3xx": "3xx":
description: |- description: |-

@ -95,6 +95,17 @@ paths:
} }
schema: schema:
$ref: "../client-server/definitions/errors/error.yaml" $ref: "../client-server/definitions/errors/error.yaml"
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"
"/3pid/bind": "/3pid/bind":
post: post:
summary: Publish an association between a session and a Matrix user ID. summary: Publish an association between a session and a Matrix user ID.
@ -208,6 +219,17 @@ paths:
} }
schema: schema:
$ref: "../client-server/definitions/errors/error.yaml" $ref: "../client-server/definitions/errors/error.yaml"
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"
"/3pid/unbind": "/3pid/unbind":
post: post:
summary: Remove an association between a session and a Matrix user ID. summary: Remove an association between a session and a Matrix user ID.
@ -294,6 +316,9 @@ paths:
This may also be returned if the identity server does not support This may also be returned if the identity server does not support
the chosen authentication method (such as blocking homeservers from the chosen authentication method (such as blocking homeservers from
unbinding identifiers). unbinding identifiers).
Another common error code is ``M_TERMS_NOT_SIGNED`` where the user
needs to `agree to more terms`_ in order to continue.
examples: examples:
application/json: { application/json: {
"errcode": "M_FORBIDDEN", "errcode": "M_FORBIDDEN",

@ -80,6 +80,17 @@ paths:
type: string type: string
description: The user ID which registered the token. description: The user ID which registered the token.
required: ['user_id'] required: ['user_id']
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"
"/account/logout": "/account/logout":
post: post:
summary: Logs out an access token, rendering it unusable. summary: Logs out an access token, rendering it unusable.
@ -107,3 +118,14 @@ paths:
} }
schema: schema:
$ref: "../client-server/definitions/errors/error.yaml" $ref: "../client-server/definitions/errors/error.yaml"
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"

@ -74,6 +74,17 @@ paths:
} }
schema: schema:
$ref: "../client-server/definitions/errors/error.yaml" $ref: "../client-server/definitions/errors/error.yaml"
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"
"/validate/email/submitToken": "/validate/email/submitToken":
post: post:
summary: Validate ownership of an email address. summary: Validate ownership of an email address.
@ -135,6 +146,17 @@ paths:
type: boolean type: boolean
description: Whether the validation was successful or not. description: Whether the validation was successful or not.
required: ['success'] required: ['success']
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"
get: get:
summary: Validate ownership of an email address. summary: Validate ownership of an email address.
description: |- description: |-
@ -171,7 +193,7 @@ paths:
description: The token generated by the ``requestToken`` call and emailed to the user. description: The token generated by the ``requestToken`` call and emailed to the user.
x-example: atoken x-example: atoken
responses: responses:
"200": 200:
description: Email address is validated. description: Email address is validated.
"3xx": "3xx":
description: |- description: |-
@ -181,3 +203,14 @@ paths:
"4xx": "4xx":
description: description:
Validation failed. Validation failed.
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"

@ -99,3 +99,14 @@ paths:
} }
schema: schema:
$ref: "../client-server/definitions/errors/error.yaml" $ref: "../client-server/definitions/errors/error.yaml"
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"

@ -76,6 +76,17 @@ paths:
} }
schema: schema:
$ref: "../client-server/definitions/errors/error.yaml" $ref: "../client-server/definitions/errors/error.yaml"
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"
"/validate/msisdn/submitToken": "/validate/msisdn/submitToken":
post: post:
summary: Validate ownership of a phone number. summary: Validate ownership of a phone number.
@ -137,6 +148,17 @@ paths:
type: boolean type: boolean
description: Whether the validation was successful or not. description: Whether the validation was successful or not.
required: ['success'] required: ['success']
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"
get: get:
summary: Validate ownership of a phone number. summary: Validate ownership of a phone number.
description: |- description: |-
@ -173,7 +195,7 @@ paths:
description: The token generated by the ``requestToken`` call and sent to the user. description: The token generated by the ``requestToken`` call and sent to the user.
x-example: atoken x-example: atoken
responses: responses:
"200": 200:
description: Phone number is validated. description: Phone number is validated.
"3xx": "3xx":
description: |- description: |-
@ -183,3 +205,14 @@ paths:
"4xx": "4xx":
description: description:
Validation failed. Validation failed.
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"

@ -163,3 +163,14 @@ paths:
} }
schema: schema:
$ref: "../client-server/definitions/errors/error.yaml" $ref: "../client-server/definitions/errors/error.yaml"
403:
description: |
The user must do something in order to use this endpoint. One example
is an ``M_TERMS_NOT_SIGNED`` error where the user must `agree to more terms`_.
examples:
application/json: {
"errcode": "M_TERMS_NOT_SIGNED",
"error": "Please accept our updated terms of service before continuing"
}
schema:
$ref: "../client-server/definitions/errors/error.yaml"

@ -0,0 +1,149 @@
# Copyright 2019 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
swagger: '2.0'
info:
title: "Matrix Identity Service Terms of Service API"
version: "2.0.0"
host: localhost:8090
schemes:
- https
basePath: /_matrix/identity/v2
consumes:
- application/json
produces:
- application/json
securityDefinitions:
$ref: definitions/security.yaml
paths:
"/terms":
get:
summary: Gets the terms of service offered by the server.
description: |-
Gets all the terms of service offered by the server. The client is expected
to filter through the terms to determine which terms need acceptance from the
user. Note that this endpoint does not require authentication.
operationId: getTerms
parameters: []
responses:
200:
description: |-
The terms of service offered by the server.
examples:
application/json: {
"policies": {
"terms_of_service": {
"version": "2.0",
"en": {
"name": "Terms of Service",
"url": "https://example.org/somewhere/terms-2.0-en.html"
},
"fr": {
"name": "Conditions d'utilisation",
"url": "https://example.org/somewhere/terms-2.0-fr.html"
}
},
"privacy_policy": {
"version": "1.2",
"en": {
"name": "Privacy Policy",
"url": "https://example.org/somewhere/privacy-1.2-en.html"
},
"fr": {
"name": "Politique de confidentialité",
"url": "https://example.org/somewhere/privacy-1.2-fr.html"
}
}
}
}
schema:
type: object
properties:
policies:
type: object
title: Policy Map
description: |-
The policies the server offers. Mapped from arbitrary ID (unused in
this version of the specification) to a Policy Object.
additionalProperties:
type: object
title: Policy Object
description: |-
The policy. Includes a map of language (ISO 639-2) to language-specific
policy information.
properties:
version:
type: string
description: |-
The version for the policy. There are no requirements on what this
might be and could be "alpha", semantically versioned, or arbitrary.
required: ['version']
# TODO: TravisR - Make this render
additionalProperties:
type: object
title: Internationalised Policy
description: |-
The policy information for the specified language.
properties:
name:
type: string
description: The translated name of the policy.
url:
type: string
description: |-
The URL, which should include the policy ID, version, and language
in it, to be presented to the user as the policy. URLs should have
all three criteria to avoid conflicts when the policy is updated
in the future: for example, if this was "https://example.org/terms.html"
then the server would be unable to update it because the client would
have already added that URL to the ``m.accepted_terms`` collection.
required: ['name', 'url']
required: ['policies']
post:
summary: Indicates acceptance of terms to the server.
description: |-
Called by a client to indicate that the user has accepted/agreed to the included
set of URLs. Servers MUST NOT assume that the client will be sending all previously
accepted URLs and should therefore append the provided URLs to what the server
already knows has been accepted.
Clients MUST provide the URL of the policy in the language that was presented
to the user. Servers SHOULD consider acceptance of any one language's URL as
acceptance for all other languages of that policy.
The server should avoid returning ``M_TERMS_NOT_SIGNED`` because the client
may not be accepting all terms at once.
operationId: agreeToTerms
security:
- accessToken: []
parameters:
- in: body
name: body
schema:
type: object
properties:
user_accepts:
type: array
items:
type: string
description: The URLs the user is accepting in this request.
example: "https://example.org/somewhere/terms-2.0-en.html"
required: ['user_accepts']
responses:
200:
description: |-
The server has considered the user as having accepted the provided URLs.
examples:
application/json: {}
schema:
type: object

@ -0,0 +1 @@
Add endpoints for accepting and handling terms of service.

@ -0,0 +1,10 @@
{
"$ref": "core/event.json",
"type": "m.accepted_terms",
"content": {
"accepted": [
"https://example.org/somewhere/terms-1.2-en.html",
"https://example.org/somewhere/privacy-1.2-en.html"
]
}
}

@ -0,0 +1,23 @@
---
allOf:
- $ref: core-event-schema/event.yaml
description: |-
A list of terms URLs the user has previously accepted. Clients SHOULD use this
to avoid presenting the user with terms they have already agreed to.
properties:
content:
type: object
properties:
accepted:
type: array
items:
type: string
description: |-
The list of URLs the user has previously accepted. Should be appended to
when the user agrees to new terms.
type:
enum:
- m.accepted_terms
type: string
title: Accepted Terms of Service URLs
type: object

@ -586,7 +586,21 @@ class MatrixUnits(Units):
raise Exception("Error handling parameter %s" % param_name, e) raise Exception("Error handling parameter %s" % param_name, e)
# endfor[param] # endfor[param]
good_response = None good_response = None
for code in sorted(endpoint_swagger.get("responses", {}).keys()): endpoint_status_codes = endpoint_swagger.get("responses", {}).keys()
# Check to see if any of the status codes are strings ("4xx") and if
# so convert everything to a string to avoid comparing ints and strings.
has_string_status = False
for code in endpoint_status_codes:
if isinstance(code, str):
has_string_status = True
break
if has_string_status:
endpoint_status_codes = [str(i) for i in endpoint_status_codes]
for code in sorted(endpoint_status_codes):
# Convert numeric responses to ints, assuming they got converted
# above.
if isinstance(code, str) and code.isdigit():
code = int(code)
res = endpoint_swagger["responses"][code] res = endpoint_swagger["responses"][code]
if not good_response and code == 200: if not good_response and code == 200:
good_response = res good_response = res

@ -198,6 +198,33 @@ status of 401 and the error code ``M_UNAUTHORIZED``.
{{v2_auth_is_http_api}} {{v2_auth_is_http_api}}
.. _`agree to more terms`:
Terms of service
----------------
Identity Servers are encouraged to have terms of service (or similar policies) to
ensure that users have agreed to their data being processed by the server. To facilitate
this, an identity server can respond to almost any authenticated API endpoint with a
HTTP 403 and the error code ``M_TERMS_NOT_SIGNED``. The error code is used to indicate
that the user must accept new terms of service before being able to continue.
All endpoints which support authentication can return the ``M_TERMS_NOT_SIGNED`` error.
When clients receive the error, they are expected to make a call to ``GET /terms`` to
find out what terms the server offers. The client compares this to the ``m.accepted_terms``
account data for the user (described later) and presents the user with option to accept
the still-missing terms of service. After the user has made their selection, if applicable,
the client sends a request to ``POST /terms`` to indicate the user's acceptance. The
server cannot expect that the client will send acceptance for all pending terms, and the
client should not expect that the server will not respond with another ``M_TERMS_NOT_SIGNED``
on their next request. The terms the user has just accepted are appended to ``m.accepted_terms``.
{{m_accepted_terms_event}}
{{v2_terms_is_http_api}}
Status check Status check
------------ ------------

Loading…
Cancel
Save