diff --git a/telco/camaraproject.org/KnowYourCustomer/kyc-match-0.3.0-openapi-metadata.yaml b/telco/camaraproject.org/KnowYourCustomer/kyc-match-0.3.0-openapi-metadata.yaml new file mode 100644 index 0000000..72fc049 --- /dev/null +++ b/telco/camaraproject.org/KnowYourCustomer/kyc-match-0.3.0-openapi-metadata.yaml @@ -0,0 +1,67 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: Know Your Customer Match + version: 0.3.0 +operations: + POST /match: + Successful match with name and birthdate: + request: + headers: + accept: application/json + body: | + { + "phoneNumber": "+12016219813", + "name": "John Doe", + "birthdate": "1985-02-08" + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: | + { + "nameMatch": "true", + "birthdateMatch": "true" + } + Partial match with email and mismatch on gender: + request: + headers: + accept: application/json + body: | + { + "phoneNumber": "+447405580375", + "email": "johndoe@example.com", + "gender": "MALE" + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: | + { + "emailMatch": "true", + "genderMatch": "false" + } + Failed match due to ID document mismatch: + request: + headers: + accept: application/json + body: | + { + "phoneNumber": "+937018460616", + "idDocument": "AB1234567" + } + response: + headers: + content-type: application/json + status: 403 + mediaType: application/json + body: | + { + "status": 403, + "code": "KNOW_YOUR_CUSTOMER.ID_DOCUMENT_MISMATCH", + "message": "The provided ID document does not match our records." + } diff --git a/telco/camaraproject.org/device-reachability-status/device-reachability-status-1.0.0-openapi-metadata.yaml b/telco/camaraproject.org/device-reachability-status/device-reachability-status-1.0.0-openapi-metadata.yaml new file mode 100644 index 0000000..ff037ea --- /dev/null +++ b/telco/camaraproject.org/device-reachability-status/device-reachability-status-1.0.0-openapi-metadata.yaml @@ -0,0 +1,182 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: Device Reachability Status + version: 1.0.0 +operations: + POST /retrieve: + Single IPv4 address: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.168.1.1", + "privateAddress" : "192.168.1.1" + }, + "phoneNumber" : "+123456789" + } + } + response: + status: 200 + Unique IPv6 address: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv6Address" : "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + } + response: + status: 200 + Multiple identifiers: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv6Address" : "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "phoneNumber" : "+987654321" + } + } + response: + status: 200 + Retrieve device reachability status - Example 1: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+123456789" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2023-01-30T16:59:58Z", + "reachable" : true, + "connectivity" : [ "DATA" ] + } + Retrieve device reachability status - Example 2: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.0.2.1", + "privateAddress" : "192.168.1.1", + "publicPort" : 8080 + } + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2023-01-30T16:59:58Z", + "reachable" : false, + "connectivity" : [ "SMS" ] + } + Retrieve device reachability status - Example 3: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "networkAccessIdentifier" : "ABCD1234@operator" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2023-01-30T16:59:58Z", + "reachable" : true, + "connectivity" : [ "DATA", "SMS" ] + } + example 1: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+123456789" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2022-01-01T12:00:00Z", + "reachable" : true, + "connectivity" : [ "DATA" ] + } + example 2: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.168.1.10", + "privateAddress" : "10.0.0.1", + "publicPort" : 8080 + } + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2022-01-02T08:30:00Z", + "reachable" : false, + "connectivity" : [ "SMS" ] + } + example 3: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv6Address" : "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2022-01-03T16:45:00Z", + "reachable" : true, + "connectivity" : [ "DATA" ] + } diff --git a/telco/camaraproject.org/device-reachability-status/device-reachability-status-1.0.0-openapi.yaml b/telco/camaraproject.org/device-reachability-status/device-reachability-status-1.0.0-openapi.yaml new file mode 100644 index 0000000..69ceb16 --- /dev/null +++ b/telco/camaraproject.org/device-reachability-status/device-reachability-status-1.0.0-openapi.yaml @@ -0,0 +1,531 @@ +openapi: 3.0.3 +info: + title: Device Reachability Status + description: | + This API provides the API consumer with the ability to query device reachability status. + + # Introduction + + ## Reachability Status + + API consumer is able to verify whether a certain user device is reachable from the network via data- or sms-usage. + + ## Relevant terms and definitions + + * **Device**: A device refers to any physical entity that can connect to a network and participate in network communication. + At least one identifier for the device (user equipment) out of four options: IPv4 address, IPv6 address, Phone number, or Network Access Identifier (not supported for this API version) assigned by the mobile network operator for the device. + + * **Reachable:** Indicates, if the device is reachable from the network or not. + + * **Connectivity:** Indicates the connectivity types (DATA, SMS or both) through which the device is reachable from the network. + + * **LastStatusTime** : This property specifies the time when the status was last updated. Its presence in the response indicates the freshness of the information, while its absence implies the information may be outdated or its freshness is uncertain. + + # API Functionality + + The API exposes following capabilities: + + ### Device Reachability situation + + The endpoint `POST /retrieve` allows to get current connectivity status information synchronously. + + # Identifying the device from the access token + + This API requires the API consumer to identify a device as the subject of the API as follows: + - When the API is invoked using a two-legged access token, the subject will be identified from the optional `device` object, which therefore MUST be provided. + - When a three-legged access token is used however, this optional identifier MUST NOT be provided, as the subject will be uniquely identified from the access token. + + This approach simplifies API usage for API consumers using a three-legged access token to invoke the API by relying on the information that is associated with the access token and was identified during the authentication process. + + ## Error handling: + + - If the subject cannot be identified from the access token and the optional `device` object is not included in the request, then the server will return an error with the `422 MISSING_IDENTIFIER` error code. + + - If the subject can be identified from the access token and the optional `device` object is also included in the request, then the server will return an error with the `422 UNNECESSARY_IDENTIFIER` error code. This will be the case even if the same device is identified by these two methods, as the server is unable to make this comparison. + + # Authorization and authentication + + The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. + + The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. + + In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. + + ## Multi-SIM scenario handling + + In multi-SIM scenarios where more than one mobile device is associated with a phone number (e.g. a smartphone with an associated smartwatch), it might not be possible to uniquely identify the device for which the reachability status should be returned from that phone number. If the phone number is used as the device identifier when querying in a multi-SIM scenario, the API may: + - respond with an error, or + - return a combined reachability status for the multi-SIM group as a whole, or + - return the reachability status for a single device in the multi-SIM group, which may not be the intended device. + + Possible solutions in such a scenario include: + - Using the authorisation code flow to obtain an access token, which will automatically identify the intended device + - Identifying the intended device from a unique identifier for that device, such as its source IP address and port + - Check with the SIM provider whether a unique "secondary" phone number is already associated with each device, and use the secondary phone number to identify the intended device if available. + + ## Further info and support + + (FAQs will be added in a later version of the documentation) + + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 + x-camara-commonalities: 0.5 +externalDocs: + description: Product documentation at CAMARA + url: https://github.com/camaraproject/DeviceStatus + +servers: + - url: "{apiRoot}/device-reachability-status/v1" + variables: + apiRoot: + default: http://localhost:9091 + description: API root +tags: + - name: Device reachability status + description: Operations to get the current reachability status of a device +paths: + /retrieve: + post: + tags: + - Device reachability status + summary: "Get the current reachability status information" + description: Get the current reachability status information + operationId: getReachabilityStatus + parameters: + - $ref: '#/components/parameters/x-correlator' + security: + - openId: + - device-reachability-status:read + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/RequestReachabilityStatus" + required: true + responses: + "200": + description: Contains information about current reachability status + headers: + x-correlator: + $ref: '#/components/headers/x-correlator' + content: + application/json: + schema: + $ref: "#/components/schemas/ReachabilityStatusResponse" + examples: + Connected-With-SMS: + value: + lastStatusTime: "2024-02-20T10:41:38.657Z" + reachable: true + connectivity: ["SMS"] + Connected-With-DATA: + value: + lastStatusTime: "2024-02-20T10:41:38.657Z" + reachable: true + connectivity: ["DATA"] + + Connected-With-DATA-And-SMS: + value: + lastStatusTime: "2024-02-20T10:41:38.657Z" + reachable: true + connectivity: ["DATA", "SMS"] + Not-Reachable: + value: + lastStatusTime: "2024-02-20T10:41:38.657Z" + reachable: false + "400": + $ref: "#/components/responses/Generic400" + "401": + $ref: "#/components/responses/Generic401" + "403": + $ref: "#/components/responses/Generic403" + "404": + $ref: "#/components/responses/Generic404" + "422": + $ref: "#/components/responses/Generic422" + "429": + $ref: "#/components/responses/Generic429" + "503": + $ref: "#/components/responses/Generic503" +components: + securitySchemes: + openId: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration + parameters: + x-correlator: + name: x-correlator + in: header + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + headers: + x-correlator: + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + schemas: + LastStatusTime: + description: Last time that the associated device reachability status was updated + type: string + format: date-time + example: "2024-02-20T10:41:38.657Z" + ReachabilityStatusResponse: + type: object + required: + - reachable + properties: + lastStatusTime: + $ref: "#/components/schemas/LastStatusTime" + reachable: + description: Indicates overall device reachability + type: boolean + connectivity: + type: array + items: + $ref: "#/components/schemas/ConnectivityType" + ConnectivityType: + description: | + DATA: The device is connected to the network for Data usage (regardless of the SMS reachability) + + SMS: The device is connected to the network only for SMS usage + + type: string + enum: + - DATA + - SMS + Device: + description: | + End-user equipment able to connect to a mobile network. Examples of devices include smartphones or IoT sensors/actuators. + + The developer can choose to provide the below specified device identifiers: + + * `ipv4Address` + * `ipv6Address` + * `phoneNumber` + * `networkAccessIdentifier` + + NOTE: the MNO might support only a subset of these options. The API invoker can provide multiple identifiers to be compatible across different MNOs. In this case the identifiers MUST belong to the same device. + type: object + properties: + phoneNumber: + $ref: "#/components/schemas/PhoneNumber" + networkAccessIdentifier: + $ref: "#/components/schemas/NetworkAccessIdentifier" + ipv4Address: + $ref: "#/components/schemas/DeviceIpv4Addr" + ipv6Address: + $ref: "#/components/schemas/DeviceIpv6Address" + minProperties: 1 + + PhoneNumber: + description: A public identifier addressing a telephone subscription. In mobile networks it corresponds to the MSISDN (Mobile Station International Subscriber Directory Number). In order to be globally unique it has to be formatted in international format, according to E.164 standard, prefixed with '+'. + type: string + pattern: '^\+[1-9][0-9]{4,14}$' + example: "+123456789" + + NetworkAccessIdentifier: + description: A public identifier addressing a subscription in a mobile network. In 3GPP terminology, it corresponds to the GPSI formatted with the External Identifier ({Local Identifier}@{Domain Identifier}). Unlike the telephone number, the network access identifier is not subjected to portability ruling in force, and is individually managed by each operator. + type: string + example: "123456789@domain.com" + + DeviceIpv4Addr: + type: object + description: | + The device should be identified by either the public (observed) IP address and port as seen by the application server, or the private (local) and any public (observed) IP addresses in use by the device (this information can be obtained by various means, for example from some DNS servers). + + If the allocated and observed IP addresses are the same (i.e. NAT is not in use) then the same address should be specified for both publicAddress and privateAddress. + + If NAT64 is in use, the device should be identified by its publicAddress and publicPort, or separately by its allocated IPv6 address (field ipv6Address of the Device object) + + In all cases, publicAddress must be specified, along with at least one of either privateAddress or publicPort, dependent upon which is known. In general, mobile devices cannot be identified by their public IPv4 address alone. + properties: + publicAddress: + $ref: "#/components/schemas/SingleIpv4Addr" + privateAddress: + $ref: "#/components/schemas/SingleIpv4Addr" + publicPort: + $ref: "#/components/schemas/Port" + anyOf: + - required: [publicAddress, privateAddress] + - required: [publicAddress, publicPort] + example: + publicAddress: "84.125.93.10" + publicPort: 59765 + + SingleIpv4Addr: + description: A single IPv4 address with no subnet mask + type: string + format: ipv4 + example: "84.125.93.10" + + Port: + description: TCP or UDP port number + type: integer + minimum: 0 + maximum: 65535 + + DeviceIpv6Address: + description: | + The device should be identified by the observed IPv6 address, or by any single IPv6 address from within the subnet allocated to the device (e.g. adding ::0 to the /64 prefix). + type: string + format: ipv6 + example: 2001:db8:85a3:8d3:1319:8a2e:370:7344 + + RequestReachabilityStatus: + description: The request to retrieve the current roaming-status for the requested device. + type: object + properties: + device: + $ref: "#/components/schemas/Device" + + ErrorInfo: + description: The error object used for error-cases. + type: object + required: + - status + - code + - message + properties: + status: + type: integer + description: HTTP response status code + code: + type: string + description: Code given to this error + message: + type: string + description: Detailed error description + + responses: + Generic400: + description: Bad Request + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + Generic401: + description: Unauthorized + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 401 + code: + enum: + - UNAUTHENTICATED + - AUTHENTICATION_REQUIRED + examples: + GENERIC_401_UNAUTHENTICATED: + description: Request cannot be authenticated + value: + status: 401 + code: UNAUTHENTICATED + message: Request not authenticated due to missing, invalid, or expired credentials. + GENERIC_401_AUTHENTICATION_REQUIRED: + description: New authentication is needed, authentication is no longer valid + value: + status: 401 + code: AUTHENTICATION_REQUIRED + message: New authentication is required. + Generic403: + description: Forbidden + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + Generic404: + description: Not found + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - NOT_FOUND + - IDENTIFIER_NOT_FOUND + examples: + GENERIC_404_NOT_FOUND: + description: Resource is not found + value: + status: 404 + code: NOT_FOUND + message: The specified resource is not found. + GENERIC_404_IDENTIFIER_NOT_FOUND: + description: The phone number is not associated with a CSP customer account + value: + status: 404 + code: IDENTIFIER_NOT_FOUND + message: The phone number provided is not associated with a customer account + Generic422: + description: Unprocessable Content + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - IDENTIFIER_MISMATCH + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + examples: + GENERIC_422_IDENTIFIER_MISMATCH: + description: Inconsistency between identifiers not pointing to the same device + value: + status: 422 + code: IDENTIFIER_MISMATCH + message: Provided identifiers are not consistent. + GENERIC_422_SERVICE_NOT_APPLICABLE: + description: Service not applicable for the provided identifier + value: + status: 422 + code: SERVICE_NOT_APPLICABLE + message: The service is not available for the provided identifier. + GENERIC_422_MISSING_IDENTIFIER: + description: An identifier is not included in the request and the device or phone number identification cannot be derived from the 3-legged access token + value: + status: 422 + code: MISSING_IDENTIFIER + message: The device cannot be identified. + GENERIC_422_UNSUPPORTED_IDENTIFIER: + description: None of the provided identifiers is supported by the implementation + value: + status: 422 + code: UNSUPPORTED_IDENTIFIER + message: The identifier provided is not supported. + GENERIC_422_UNNECESSARY_IDENTIFIER: + description: An explicit identifier is provided when a device or phone number has already been identified from the access token + value: + status: 422 + code: UNNECESSARY_IDENTIFIER + message: The device is already identified by the access token. + Generic429: + description: Too Many Requests + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 429 + code: + enum: + - QUOTA_EXCEEDED + - TOO_MANY_REQUESTS + examples: + GENERIC_429_QUOTA_EXCEEDED: + description: Request is rejected due to exceeding a business quota limit + value: + status: 429 + code: QUOTA_EXCEEDED + message: Out of resource quota. + GENERIC_429_TOO_MANY_REQUESTS: + description: Access to the API has been temporarily blocked due to rate or spike arrest limits being reached + value: + status: 429 + code: TOO_MANY_REQUESTS + message: Rate limit reached. + + Generic503: + description: Service Unavailable + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 503 + code: + enum: + - UNAVAILABLE + examples: + GENERIC_503_UNAVAILABLE: + description: Service is not available. Temporary situation usually related to maintenance process in the server side + value: + status: 503 + code: UNAVAILABLE + message: Network issue \ No newline at end of file diff --git a/telco/camaraproject.org/device-roaming-status/device-roaming-status-1.0.0-openapi-metadata.yaml b/telco/camaraproject.org/device-roaming-status/device-roaming-status-1.0.0-openapi-metadata.yaml new file mode 100644 index 0000000..63f439a --- /dev/null +++ b/telco/camaraproject.org/device-roaming-status/device-roaming-status-1.0.0-openapi-metadata.yaml @@ -0,0 +1,208 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: Device Roaming Status + version: 1.0.0 +operations: + POST /retrieve: + Single Identifier: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+1234567890" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2022-11-02T14:30:00Z", + "roaming" : true, + "countryCode" : 123, + "countryName" : [ "USA", "Canada" ] + } + Multiple Identifiers: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+1234567890", + "networkAccessIdentifier" : "example123", + "ipv6Address" : "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2022-10-06T10:25:00Z", + "roaming" : false + } + IPv4 Address Information: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.0.2.1", + "privateAddress" : "10.0.0.1" + } + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2022-10-20T08:15:00Z", + "roaming" : false + } + RoamingStatusRequest1: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+1234567890" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2023-12-21T10:15:30Z", + "roaming" : true, + "countryCode" : 302, + "countryName" : [ "US", "Canada" ] + } + RoamingStatusRequest2: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.168.1.2" + } + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2023-12-21T10:15:30Z", + "roaming" : false + } + RoamingStatusRequest3: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv6Address" : "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + } + response: + headers: + content-type: application/json + status: 422 + mediaType: application/json + body: |- + { + "status" : 422, + "code" : "ID_UNAVAILABLE", + "message" : "Identifier not found for the specified device" + } + Roaming status retrieval Example 1: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.168.1.10", + "privateAddress" : "192.168.1.20", + "publicPort" : 8080 + } + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2022-01-01T08:00:00Z", + "roaming" : true, + "countryCode" : 123, + "countryName" : [ "Country1", "Country2" ] + } + Roaming status retrieval Example 2: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+15555555555", + "networkAccessIdentifier" : "ABC123" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2022-01-01T08:30:00Z", + "roaming" : false + } + Roaming status retrieval Example 3: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv6Address" : "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastStatusTime" : "2022-01-01T09:00:00Z", + "roaming" : true, + "countryCode" : 456, + "countryName" : [ "AnotherCountry1" ] + } diff --git a/telco/camaraproject.org/device-roaming-status/device-roaming-status-1.0.0-openapi.yaml b/telco/camaraproject.org/device-roaming-status/device-roaming-status-1.0.0-openapi.yaml new file mode 100644 index 0000000..62c2e4a --- /dev/null +++ b/telco/camaraproject.org/device-roaming-status/device-roaming-status-1.0.0-openapi.yaml @@ -0,0 +1,544 @@ +openapi: 3.0.3 +info: + title: Device Roaming Status + description: | + This API provides the API consumer with the ability to query device roaming Status + + # Introduction + + ## Roaming Status + API consumer is able to verify whether a certain user device is in roaming situation (or not). + + The verification of the roaming situation depends on the network's ability. Additionally to the roaming status, when the device is in roaming situation, visited country information could be returned in the response. + + ## Possible Use-Cases + Roaming status verification could be useful in scenario such as (not exhaustive): + - For regulatory reasons, where a customer may need to be within a certain jurisdiction, or out with others, in order for transactions to be authorized + - For security / fraud reasons, to establish that a customer is located where they claim to be + - For service delivery reasons, to ensure that the customer has access to particular service, and will not incur roaming charges in accessing them + + + ## Relevant terms and definitions + + * **Device**: A device refers to any physical entity that can connect to a network and participate in network communication. + At least one identifier for the device (user equipment) out of four options: IPv4 address, IPv6 address, Phone number, or Network Access Identifier (not supported for this API version) assigned by the mobile network operator for the device. + + * **Roaming** : Roaming status - `true`, if device is in roaming situation - `false` else. + + * **Country** : Country code and name - visited country information, provided if the device is in roaming situation. + + * **LastStatusTime** : This property specifies the time when the status was last updated. Its presence in the response indicates the freshness of the information, while its absence implies the information may be outdated or its freshness is uncertain. + + # API Functionality + + The API exposes following capabilities: + + ## Device roaming situation + + The endpoint `POST /retrieve` allows to get roaming status and country information (if device in roaming situation) synchronously. + + # Identifying the device from the access token + + This API requires the API consumer to identify a device as the subject of the API as follows: + - When the API is invoked using a two-legged access token, the subject will be identified from the optional `device` object, which therefore MUST be provided. + - When a three-legged access token is used however, this optional identifier MUST NOT be provided, as the subject will be uniquely identified from the access token. + + This approach simplifies API usage for API consumers using a three-legged access token to invoke the API by relying on the information that is associated with the access token and was identified during the authentication process. + + ## Error handling: + + - If the subject cannot be identified from the access token and the optional `device` object is not included in the request, then the server will return an error with the `422 MISSING_IDENTIFIER` error code. + + - If the subject can be identified from the access token and the optional `device` object is also included in the request, then the server will return an error with the `422 UNNECESSARY_IDENTIFIER` error code. This will be the case even if the same device is identified by these two methods, as the server is unable to make this comparison. + + # Authorization and authentication + + The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. + + The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. + + In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. + + ## Multi-SIM scenario handling + + In multi-SIM scenarios where more than one mobile device is associated with a phone number (e.g. a smartphone with an associated smartwatch), it might not be possible to uniquely identify the device for which the roaming status should be returned from that phone number. If the phone number is used as the device identifier when querying in a multi-SIM scenario, the API may: + - respond with an error, or + - return a combined roaming status for the multi-SIM group as a whole, or + - return the roaming status for a single device in the multi-SIM group, which may not be the intended device. + + Possible solutions in such a scenario include: + - Using the authorisation code flow to obtain an access token, which will automatically identify the intended device + - Identifying the intended device from a unique identifier for that device, such as its source IP address and port + - Check with the SIM provider whether a unique "secondary" phone number is already associated with each device, and use the secondary phone number to identify the intended device if available. + + ## Further info and support + + (FAQs will be added in a later version of the documentation) + + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 + x-camara-commonalities: 0.5 +externalDocs: + description: Product documentation at CAMARA + url: https://github.com/camaraproject/DeviceStatus + +servers: + - url: "{apiRoot}/device-roaming-status/v1" + variables: + apiRoot: + default: http://localhost:9091 + description: API root + +tags: + - name: Roaming status retrieval + description: Operation to get device roaming status and country information (if roaming) synchronously +paths: + /retrieve: + post: + tags: + - Roaming status retrieval + summary: "Get the current roaming status and the country information" + description: Get the current roaming status and the country information + operationId: getRoamingStatus + parameters: + - $ref: '#/components/parameters/x-correlator' + security: + - openId: + - device-roaming-status:read + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/RoamingStatusRequest" + required: true + responses: + "200": + description: Contains information about current roaming status + headers: + x-correlator: + $ref: '#/components/headers/x-correlator' + content: + application/json: + schema: + $ref: "#/components/schemas/RoamingStatusResponse" + examples: + No-Country-Name: + value: + lastStatusTime: "2024-02-20T10:41:38.657Z" + roaming: true + countryCode: 901 + countryName: [] + Single-Country-Code: + value: + lastStatusTime: "2024-02-20T10:41:38.657Z" + roaming: true + countryCode: 262 + countryName: ["DE"] + Multiple-Country-Codes: + value: + lastStatusTime: "2024-02-20T10:41:38.657Z" + roaming: true + countryCode: 340 + countryName: ["BL", "GF", "GP", "MF", "MQ"] + "400": + $ref: "#/components/responses/Generic400" + "401": + $ref: "#/components/responses/Generic401" + "403": + $ref: "#/components/responses/Generic403" + "404": + $ref: "#/components/responses/Generic404" + "422": + $ref: "#/components/responses/Generic422" + "429": + $ref: "#/components/responses/Generic429" + "503": + $ref: "#/components/responses/Generic503" + +components: + securitySchemes: + openId: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration + parameters: + x-correlator: + name: x-correlator + in: header + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + headers: + x-correlator: + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + schemas: + RoamingStatusResponse: + type: object + required: + - roaming + properties: + lastStatusTime: + $ref: "#/components/schemas/LastStatusTime" + roaming: + $ref: "#/components/schemas/ActiveRoaming" + countryCode: + $ref: "#/components/schemas/CountryCode" + countryName: + $ref: "#/components/schemas/CountryName" + + LastStatusTime: + description: Last time that the associated device roaming status was updated + type: string + format: date-time + example: "2024-02-20T10:41:38.657Z" + + ActiveRoaming: + description: Roaming status. True, if it is roaming + type: boolean + + Device: + description: | + End-user equipment able to connect to a mobile network. Examples of devices include smartphones or IoT sensors/actuators. + + The developer can choose to provide the below specified device identifiers: + + * `ipv4Address` + * `ipv6Address` + * `phoneNumber` + * `networkAccessIdentifier` + + NOTE: the MNO might support only a subset of these options. The API invoker can provide multiple identifiers to be compatible across different MNOs. In this case the identifiers MUST belong to the same device. + type: object + properties: + phoneNumber: + $ref: "#/components/schemas/PhoneNumber" + networkAccessIdentifier: + $ref: "#/components/schemas/NetworkAccessIdentifier" + ipv4Address: + $ref: "#/components/schemas/DeviceIpv4Addr" + ipv6Address: + $ref: "#/components/schemas/DeviceIpv6Address" + minProperties: 1 + + PhoneNumber: + description: A public identifier addressing a telephone subscription. In mobile networks it corresponds to the MSISDN (Mobile Station International Subscriber Directory Number). In order to be globally unique it has to be formatted in international format, according to E.164 standard, prefixed with '+'. + type: string + pattern: '^\+[1-9][0-9]{4,14}$' + example: "+123456789" + + NetworkAccessIdentifier: + description: A public identifier addressing a subscription in a mobile network. In 3GPP terminology, it corresponds to the GPSI formatted with the External Identifier ({Local Identifier}@{Domain Identifier}). Unlike the telephone number, the network access identifier is not subjected to portability ruling in force, and is individually managed by each operator. + type: string + example: "123456789@domain.com" + + DeviceIpv4Addr: + type: object + description: | + The device should be identified by either the public (observed) IP address and port as seen by the application server, or the private (local) and any public (observed) IP addresses in use by the device (this information can be obtained by various means, for example from some DNS servers). + + If the allocated and observed IP addresses are the same (i.e. NAT is not in use) then the same address should be specified for both publicAddress and privateAddress. + + If NAT64 is in use, the device should be identified by its publicAddress and publicPort, or separately by its allocated IPv6 address (field ipv6Address of the Device object) + + In all cases, publicAddress must be specified, along with at least one of either privateAddress or publicPort, dependent upon which is known. In general, mobile devices cannot be identified by their public IPv4 address alone. + properties: + publicAddress: + $ref: "#/components/schemas/SingleIpv4Addr" + privateAddress: + $ref: "#/components/schemas/SingleIpv4Addr" + publicPort: + $ref: "#/components/schemas/Port" + anyOf: + - required: [publicAddress, privateAddress] + - required: [publicAddress, publicPort] + example: + publicAddress: "84.125.93.10" + publicPort: 59765 + + SingleIpv4Addr: + description: A single IPv4 address with no subnet mask + type: string + format: ipv4 + example: "84.125.93.10" + + Port: + description: TCP or UDP port number + type: integer + minimum: 0 + maximum: 65535 + + DeviceIpv6Address: + description: | + The device should be identified by the observed IPv6 address, or by any single IPv6 address from within the subnet allocated to the device (e.g. adding ::0 to the /64 prefix). + type: string + format: ipv6 + example: 2001:db8:85a3:8d3:1319:8a2e:370:7344 + + CountryCode: + description: The Mobile country code (MCC) as an geographic region identifier for the country and the dependent areas. + type: integer + + CountryName: + description: The ISO 3166 ALPHA-2 country-codes of mapped to mobile country code(MCC). If there is mapping of one MCC to multiple countries, then we have list of countries. If there is no mapping of MCC to any country, then an empty array [] shall be returned.. + type: array + items: + type: string + + RoamingStatusRequest: + description: The request for retrieving the current roaming status for the requested device. + type: object + properties: + device: + $ref: "#/components/schemas/Device" + + ErrorInfo: + description: The error object used for error-cases. + type: object + required: + - status + - code + - message + properties: + status: + type: integer + description: HTTP response status code + code: + type: string + description: Code given to this error + message: + type: string + description: Detailed error description + + responses: + Generic400: + description: Bad Request + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + Generic401: + description: Unauthorized + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 401 + code: + enum: + - UNAUTHENTICATED + - AUTHENTICATION_REQUIRED + examples: + GENERIC_401_UNAUTHENTICATED: + description: Request cannot be authenticated + value: + status: 401 + code: UNAUTHENTICATED + message: Request not authenticated due to missing, invalid, or expired credentials. + GENERIC_401_AUTHENTICATION_REQUIRED: + description: New authentication is needed, authentication is no longer valid + value: + status: 401 + code: AUTHENTICATION_REQUIRED + message: New authentication is required. + Generic403: + description: Forbidden + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + Generic404: + description: Not found + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - NOT_FOUND + - IDENTIFIER_NOT_FOUND + examples: + GENERIC_404_NOT_FOUND: + description: Resource is not found + value: + status: 404 + code: NOT_FOUND + message: The specified resource is not found. + GENERIC_404_IDENTIFIER_NOT_FOUND: + description: The phone number is not associated with a CSP customer account + value: + status: 404 + code: IDENTIFIER_NOT_FOUND + message: The phone number provided is not associated with a customer account + Generic422: + description: Unprocessable Content + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - IDENTIFIER_MISMATCH + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + examples: + GENERIC_422_IDENTIFIER_MISMATCH: + description: Inconsistency between identifiers not pointing to the same device + value: + status: 422 + code: IDENTIFIER_MISMATCH + message: Provided identifiers are not consistent. + GENERIC_422_SERVICE_NOT_APPLICABLE: + description: Service not applicable for the provided identifier + value: + status: 422 + code: SERVICE_NOT_APPLICABLE + message: The service is not available for the provided identifier. + GENERIC_422_MISSING_IDENTIFIER: + description: An identifier is not included in the request and the device or phone number identification cannot be derived from the 3-legged access token + value: + status: 422 + code: MISSING_IDENTIFIER + message: The device cannot be identified. + GENERIC_422_UNSUPPORTED_IDENTIFIER: + description: None of the provided identifiers is supported by the implementation + value: + status: 422 + code: UNSUPPORTED_IDENTIFIER + message: The identifier provided is not supported. + GENERIC_422_UNNECESSARY_IDENTIFIER: + description: An explicit identifier is provided when a device or phone number has already been identified from the access token + value: + status: 422 + code: UNNECESSARY_IDENTIFIER + message: The device is already identified by the access token. + Generic429: + description: Too Many Requests + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 429 + code: + enum: + - QUOTA_EXCEEDED + - TOO_MANY_REQUESTS + examples: + GENERIC_429_QUOTA_EXCEEDED: + description: Request is rejected due to exceeding a business quota limit + value: + status: 429 + code: QUOTA_EXCEEDED + message: Out of resource quota. + GENERIC_429_TOO_MANY_REQUESTS: + description: Access to the API has been temporarily blocked due to rate or spike arrest limits being reached + value: + status: 429 + code: TOO_MANY_REQUESTS + message: Rate limit reached. + + Generic503: + description: Service Unavailable + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 503 + code: + enum: + - UNAVAILABLE + examples: + GENERIC_503_UNAVAILABLE: + description: Service is not available. Temporary situation usually related to maintenance process in the server side + value: + status: 503 + code: UNAVAILABLE + message: Network issue \ No newline at end of file diff --git a/telco/camaraproject.org/location-verification/location-verification-2.0.0-openapi-metadata.yaml b/telco/camaraproject.org/location-verification/location-verification-2.0.0-openapi-metadata.yaml new file mode 100644 index 0000000..60b77aa --- /dev/null +++ b/telco/camaraproject.org/location-verification/location-verification-2.0.0-openapi-metadata.yaml @@ -0,0 +1,229 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: Device Location Verification + version: 2.0.0 +operations: + POST /verify: + Full verification for a device with a phone number identifier in a circle area: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+1234567890" + }, + "area" : { + "areaType" : "CIRCLE", + "centerCoordinates" : { + "latitude" : 37.7749, + "longitude" : -122.4194 + }, + "radius" : 100 + } + } + response: + status: 200 + Partial verification with match rate estimation for a device identified by IPv6 address in a circle area: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv6Address" : "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + }, + "area" : { + "areaType" : "CIRCLE", + "centerCoordinates" : { + "latitude" : 40.7128, + "longitude" : -74.006 + }, + "radius" : 50 + } + } + response: + status: 200 + Verification failure for a device identified by public IP address in an area not covered: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.0.2.1" + }, + "privateAddress" : "10.0.0.1" + }, + "area" : { + "areaType" : "CIRCLE", + "centerCoordinates" : { + "latitude" : 51.5074, + "longitude" : 0.1278 + }, + "radius" : 20 + } + } + response: + status: 200 + Verify device in specific area: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+1234567890" + }, + "area" : { + "areaType" : "CIRCLE", + "centerLatitude" : 40.7128, + "centerLongitude" : -74.006, + "radiusMeters" : 1000 + }, + "maxAge" : 3600 + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastLocationTime" : "2023-07-03T14:27:08.312+02:00", + "verificationResult" : "TRUE" + } + Verify device in different area: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.168.1.1" + } + }, + "area" : { + "areaType" : "CIRCLE", + "centerLatitude" : 37.7749, + "centerLongitude" : -122.4194, + "radiusMeters" : 500 + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastLocationTime" : "2023-07-03T14:27:08.312+02:00", + "verificationResult" : "FALSE" + } + Verify device with unknown location: + request: + headers: + accept: application/json + body: |- + { + "device" : { + "ipv6Address" : "2001:db8::1" + }, + "area" : { + "areaType" : "CIRCLE", + "centerLatitude" : 45.4215, + "centerLongitude" : -75.6972, + "radiusMeters" : 200 + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastLocationTime" : "UNKNOWN", + "verificationResult" : "UNKNOWN" + } + ValidRequest1: + request: + headers: + x-correlator: example-correlator-1 + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+123456789" + }, + "area" : { + "areaType" : "CIRCLE", + "centerLatitude" : 37.7749, + "centerLongitude" : -122.4194, + "radiusMeters" : 500 + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "lastLocationTime" : "2023-07-03T14:27:08.312+02:00", + "verificationResult" : true + } + InvalidRequest1: + request: + headers: + x-correlator: example-correlator-2 + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+987654321" + }, + "area" : { + "areaType" : "CIRCLE", + "centerLatitude" : 40.7128, + "centerLongitude" : -74.006, + "radiusMeters" : 200 + } + } + response: + headers: + content-type: application/json + status: 422 + mediaType: application/json + body: |- + { + "status" : 422, + "code" : "LOCATION_VERIFICATION.AREA_NOT_COVERED", + "message" : "The requested area is not covered by the network operator." + } + PartialMatchRequest1: + request: + headers: + accept: application/json + x-correlator: example-correlator-3 + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.0.2.1", + "privateAddress" : "10.0.0.1" + }, + "ipv4Port" : 8080 + }, + "area" : { + "areaType" : "CIRCLE", + "centerLatitude" : 48.8566, + "centerLongitude" : 2.3522, + "radiusMeters" : 1000 + } + } + response: + status: 200 diff --git a/telco/camaraproject.org/location-verification/location-verification-2.0.0-openapi.yaml b/telco/camaraproject.org/location-verification/location-verification-2.0.0-openapi.yaml new file mode 100644 index 0000000..a17a590 --- /dev/null +++ b/telco/camaraproject.org/location-verification/location-verification-2.0.0-openapi.yaml @@ -0,0 +1,651 @@ +openapi: 3.0.3 +info: + title: Device Location Verification + description: | + This API provides the consumer with the ability to verify the location of a device. + + # Introduction + + API consumers are able to verify whether the location of certain user device is within the area specified. Currently the only area supported as input is a circle determined by a set of coordinates (latitude and longitude) and some expected accuracy (radius). + + * If the provided area is out of the operator's coverage or it is not supported for any reason, an error `422 LOCATION_VERIFICATION.AREA_NOT_COVERED` will be returned. + * Legal restrictions regarding privacy, or other regulatory or implementation issues, may force the operator to set restrictions to the provided area, such as setting a minimum value to the accepted radius. In these cases, an error `422 LOCATION_VERIFICATION.INVALID_AREA` will be returned and the error message will refer to the reason of the limitation. + + The verification result depends on the network's ability and accuracy to locate the device at the requested area. + + * If the network's estimation of the device's location is fully contained within the requested area, the verification result is `TRUE`. + * If the network's estimation of the device's location does not overlap with the requested area at all, the verification result is `FALSE`. + * If the network's estimation of the device's location partially overlaps with the requested area, or it fully contains the requested area (because it is larger), the result is `PARTIAL`. In this case, a `match_rate` is included in the response, indicating an estimation of the likelihood of the match in percent. + * Lastly, the network may not be able to locate the device. In this case, the verification result is `UNKNOWN`. + * The client may optionally include a `maxAge` indication. If the location information known to the server is older than the specified `maxAge` or not known at all, an error with code `422 LOCATION_VERIFICATION.UNABLE_TO_FULFILL_MAX_AGE` is sent back, independently of the verification result. + + * `lastLocationTime` will be always included in a success response unless there is no historical location information available for the device. In this case, `UNKNOWN` will be returned without `lastLocationTime`. + + Location Verification could be useful in scenarios such as: + + - Fraud protection, to ensure a given user is located in the location area claimed for financial transactions. + - Verification of GPS coordinates reported by the app on a device, to ensure the GPS was not faked, e.g. for content delivery with regional restrictions. + - Contextual-based advertising, to trigger advertising after verifying the device is in the area of interest. + - Smart mobility (vehicle / bikes renting), to confirm the location of the device and the location of the vehicle/bike to guarantee they are rented correctly. + + # Relevant terms and definitions + + * **Device**: A device refers to any physical entity that can connect to a network and participate in network communication. + + * **Area**: It specifies the geographical surface where a device may be physically located. + + * **Max Age**: Maximum age of the location information which is accepted for the location verification (in seconds). + * Absence of maxAge means "any age" is acceptable for the client. In other words, this is like maxAge=infinite. In this case the system will still return lastLocationTime, if available. + * maxAge=0 means a fresh calculation is requested by the client. If the system is not able to provide the fresh location, an error with code `422 LOCATION_VERIFICATION.UNABLE_TO_FULFILL_MAX_AGE` is sent back. + + + * **Verification**: Process triggered in the API server to confirm or contradict the expectation assumed by the API client about the device location. + + # API Functionality + + The API exposes a single endpoint/operation: + + - Verify whether the device location is within a requested area, currently a circle with center specified by the latitude and longitude, and radius specified by the accuracy. The operation returns a verification result and, optionally, a match rate estimation for the location verification in percent. + + # Authorization and authentication + + The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. + + The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. + + In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. + + # Identifying the device from the access token + + This API requires the API consumer to identify a device as the subject of the API as follows: + - When the API is invoked using a two-legged access token, the subject will be identified from the optional `device` object, which therefore MUST be provided. + - When a three-legged access token is used however, this optional identifier MUST NOT be provided, as the subject will be uniquely identified from the access token. + + This approach simplifies API usage for API consumers using a three-legged access token to invoke the API by relying on the information that is associated with the access token and was identified during the authentication process. + + ## Error handling: + + - If the subject cannot be identified from the access token and the optional `device` object is not included in the request, then the server will return an error with the `422 MISSING_IDENTIFIER` error code. + + - If the subject can be identified from the access token and the optional `device` object is also included in the request, then the server will return an error with the `422 UNNECESSARY_IDENTIFIER` error code. This will be the case even if the same device is identified by these two methods, as the server is unable to make this comparison. + + # Multi-SIM scenario handling + + In multi-SIM scenarios, where more than one mobile device is associated with the phone number given as input in the API call (e.g. a smartphone with an associated smartwatch), it might not be possible to uniquely identify the device whose location is to be verified. Check with the API provider what is the expected behaviour when a phone number belonging to a multi-SIM group is used as the device identifier, as the API may response with: + + - an error indicating that that phone number is not supported for this API, or + - the verification for a single device in the multi-SIM group, if one of the devices is considered linked to the main SIM and this concept is supported by the operator, or + - a verification value that combines the location verification of all the SIMs associated to the requested phone number. + + Possible solutions to make the scenario more deterministic include: + + - Using preferably the authorisation code flow to obtain an access token, which will automatically identify the intended device. + - Identifying the intended device from a unique identifier for that device, such as its source IP address and port. + - Check with the API provider whether a unique "secondary" phone number is already associated with each device and use the secondary phone number to identify the intended device if available. + + # Further info and support + + (FAQs will be added in a later version of the documentation) + version: 2.0.0 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + x-camara-commonalities: 0.5 +externalDocs: + description: Project documentation at CAMARA + url: https://github.com/camaraproject/DeviceLocation +servers: + - url: "{apiRoot}/location-verification/v2" + variables: + apiRoot: + default: http://localhost:9091 + description: API root +tags: + - name: Location verification + description: Verification of the location of a device +paths: + /verify: + post: + tags: + - Location verification + summary: Verify the location of a device + description: | + Verify whether the location of a device is within a requested area. The operation returns a verification result and, optionally, a match rate estimation for the location verification in percent. + operationId: verifyLocation + parameters: + - $ref: "#/components/parameters/x-correlator" + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/VerifyLocationRequest" + examples: + INPUT_PHONE_NUMBER_CIRCLE: + summary: Phone number, circle and maxAge + description: Verify if device identified by a phone number is within a circle, providing a maxAge + value: + device: + phoneNumber: "+123456789" + area: + areaType: CIRCLE + center: + latitude: 50.735851 + longitude: 7.10066 + radius: 50000 + maxAge: 120 + INPUT_IP_ADDRESS_V4_CIRCLE: + summary: IPv4 address, circle, without maxAge + description: Verify if device identified by an IPv4 address is within a circle, not indicating a maxAge + value: + device: + ipv4Address: + publicAddress: 123.234.1.2 + publicPort: 1234 + area: + areaType: CIRCLE + center: + latitude: 50.735851 + longitude: 7.10066 + radius: 50000 + INPUT_NO_DEVICE: + summary: Device not provided + description: The device has to be deducted from token + value: + area: + areaType: CIRCLE + center: + latitude: 50.735851 + longitude: 7.10066 + radius: 50000 + maxAge: 120 + responses: + "200": + description: Location verification result + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: "#/components/schemas/VerifyLocationResponse" + examples: + VERIFICATION_TRUE: + summary: Match + description: The network locates the device within the requested area + value: + verificationResult: "TRUE" + lastLocationTime: "2023-09-07T10:40:52Z" + VERIFICATION_FALSE: + summary: No match + description: The requested area does not match the area where the network locates the device + value: + verificationResult: "FALSE" + lastLocationTime: "2023-09-07T10:40:52Z" + VERIFICATION_UNKNOWN: + summary: Unknown + description: The network cannot locate the device + value: + verificationResult: "UNKNOWN" + VERIFICATION_PARTIAL: + summary: Partial match + description: The requested area partially matches the area where the network locates the device + value: + verificationResult: "PARTIAL" + matchRate: 74 + lastLocationTime: "2023-09-07T10:40:52Z" + "400": + $ref: "#/components/responses/Generic400" + "401": + $ref: "#/components/responses/Generic401" + "403": + $ref: "#/components/responses/Generic403" + "404": + $ref: "#/components/responses/VerifyLocationNotFound404" + "422": + $ref: "#/components/responses/VerifyLocationUnprocessableEntity422" + security: + - openId: + - location-verification:verify +components: + securitySchemes: + openId: + description: OpenID Connect authentication + type: openIdConnect + openIdConnectUrl: https://example.org/.well-known/openid-configuration + parameters: + x-correlator: + name: x-correlator + in: header + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + headers: + x-correlator: + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + schemas: + Area: + description: Base schema for all areas + type: object + properties: + areaType: + $ref: "#/components/schemas/AreaType" + required: + - areaType + discriminator: + propertyName: areaType + mapping: + CIRCLE: "#/components/schemas/Circle" + + AreaType: + type: string + description: | + Type of this area. + CIRCLE - The area is defined as a circle. + enum: + - CIRCLE + + Circle: + description: Circular area + allOf: + - $ref: "#/components/schemas/Area" + - type: object + properties: + center: + $ref: "#/components/schemas/Point" + radius: + type: integer + description: | + Expected accuracy for the verification, in meters from `center`. + Note: The area surface could be restricted locally depending on regulations. Implementations may enforce a larger minimum radius (e.g. 1000 meters). + minimum: 1 + maximum: 200000 + required: + - center + - radius + example: + areaType: CIRCLE + center: + latitude: 50.735851 + longitude: 7.10066 + radius: 50000 + + Point: + type: object + description: Coordinates (latitude, longitude) defining a location in a map + required: + - latitude + - longitude + properties: + latitude: + $ref: "#/components/schemas/Latitude" + longitude: + $ref: "#/components/schemas/Longitude" + example: + latitude: 50.735851 + longitude: 7.10066 + + Latitude: + description: Latitude component of a location + type: number + format: double + minimum: -90 + maximum: 90 + example: 50.735851 + + Longitude: + description: Longitude component of location + type: number + format: double + minimum: -180 + maximum: 180 + example: 7.10066 + + VerifyLocationRequest: + description: Request to verify the location of a device. Device is not required when using a 3-legged access token, following the rules in the description. + type: object + properties: + device: + $ref: "#/components/schemas/Device" + area: + $ref: "#/components/schemas/Area" + maxAge: + $ref: "#/components/schemas/MaxAge" + required: + - area + + VerifyLocationResponse: + description: Response to a location verification request + type: object + required: + - verificationResult + properties: + lastLocationTime: + $ref: "#/components/schemas/LastLocationTime" + verificationResult: + $ref: "#/components/schemas/VerificationResult" + matchRate: + $ref: "#/components/schemas/MatchRate" + + Device: + description: | + End-user device able to connect to a mobile network. Examples of devices include smartphones or IoT sensors/actuators. + + The developer can choose to provide the below specified device identifiers: + + * `ipv4Address` + * `ipv6Address` + * `phoneNumber` + * `networkAccessIdentifier` + + NOTE1: the API provider might support only a subset of these options. The API consumer can provide multiple identifiers to be compatible across different API providers. In this case the identifiers MUST belong to the same device + NOTE2: as for this Commonalities release, we are enforcing that the networkAccessIdentifier is only part of the schema for future-proofing, and CAMARA does not currently allow its use. After the CAMARA meta-release work is concluded and the relevant issues are resolved, its use will need to be explicitly documented in the guidelines. + type: object + properties: + phoneNumber: + $ref: "#/components/schemas/PhoneNumber" + networkAccessIdentifier: + $ref: "#/components/schemas/NetworkAccessIdentifier" + ipv4Address: + $ref: "#/components/schemas/DeviceIpv4Addr" + ipv6Address: + $ref: "#/components/schemas/DeviceIpv6Address" + minProperties: 1 + + PhoneNumber: + description: A public identifier addressing a telephone subscription. In mobile networks it corresponds to the MSISDN (Mobile Station International Subscriber Directory Number). In order to be globally unique it has to be formatted in international format, according to E.164 standard, prefixed with '+'. + type: string + pattern: '^\+[1-9][0-9]{4,14}$' + example: "+123456789" + + NetworkAccessIdentifier: + description: A public identifier addressing a subscription in a mobile network. In 3GPP terminology, it corresponds to the GPSI formatted with the External Identifier ({Local Identifier}@{Domain Identifier}). Unlike the telephone number, the network access identifier is not subjected to portability ruling in force, and is individually managed by each operator. + type: string + example: "123456789@domain.com" + + DeviceIpv4Addr: + type: object + description: | + The device should be identified by either the public (observed) IP address and port as seen by the application server, or the private (local) and any public (observed) IP addresses in use by the device (this information can be obtained by various means, for example from some DNS servers). + + If the allocated and observed IP addresses are the same (i.e. NAT is not in use) then the same address should be specified for both publicAddress and privateAddress. + + If NAT64 is in use, the device should be identified by its publicAddress and publicPort, or separately by its allocated IPv6 address (field ipv6Address of the Device object) + + In all cases, publicAddress must be specified, along with at least one of either privateAddress or publicPort, dependent upon which is known. In general, mobile devices cannot be identified by their public IPv4 address alone. + properties: + publicAddress: + $ref: "#/components/schemas/SingleIpv4Addr" + privateAddress: + $ref: "#/components/schemas/SingleIpv4Addr" + publicPort: + $ref: "#/components/schemas/Port" + anyOf: + - required: [publicAddress, privateAddress] + - required: [publicAddress, publicPort] + example: + publicAddress: "84.125.93.10" + publicPort: 59765 + + SingleIpv4Addr: + description: A single IPv4 address with no subnet mask + type: string + format: ipv4 + example: "84.125.93.10" + + Port: + description: TCP or UDP port number + type: integer + minimum: 0 + maximum: 65535 + + DeviceIpv6Address: + description: | + The device should be identified by the observed IPv6 address, or by any single IPv6 address from within the subnet allocated to the device (e.g. adding ::0 to the /64 prefix). + type: string + format: ipv6 + example: 2001:db8:85a3:8d3:1319:8a2e:370:7344 + + MaxAge: + description: The maximum age (in seconds) for the location known by the implementation, which is accepted for the verification. Absence of maxAge means "any age" and maxAge=0 means a fresh calculation. + type: integer + example: 120 + + VerificationResult: + description: | + Result of a verification request: + - `TRUE`: when the network locates the device within the requested area, + - `FALSE`: when the requested area does not match the area where the network locates the device, + - `UNKNOWN`: when the network cannot locate the device, + - `PARTIAL`: when the requested area partially match the area where the network locates the device. A `match_rate` is included in the response. + type: string + enum: + - "TRUE" + - "FALSE" + - "UNKNOWN" + - "PARTIAL" + + MatchRate: + description: Estimation of the match rate between the area in the request (R), and area where the network locates the device (N), calculated as the percent value of the intersection of both areas divided by the network area, that is (R ∩ N) / N * 100. Included only if VerificationResult is PARTIAL. + type: integer + minimum: 1 + maximum: 99 + + LastLocationTime: + description: Timestamp of the last location information. It must follow RFC 3339 and must have time zone. Recommended format is yyyy-MM-dd'T'HH:mm:ss.SSSZ (i.e. which allows 2023-07-03T14:27:08.312+02:00 or 2023-07-03T12:27:08.312Z) + example: "2023-09-07T10:40:52Z" + format: date-time + type: string + + ErrorInfo: + description: Common schema for errors + type: object + required: + - status + - code + - message + properties: + status: + type: integer + description: HTTP status code returned along with this error response + code: + type: string + description: Code given to this error + message: + type: string + description: Detailed error description + + responses: + + Generic400: + description: Bad Request + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - OUT_OF_RANGE + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + GENERIC_400_OUT_OF_RANGE: + description: Out of Range. Specific Syntax Exception used when a given field has a pre-defined range or a invalid filter criteria combination is requested + value: + status: 400 + code: OUT_OF_RANGE + message: Client specified an invalid range. + + Generic401: + description: Unauthorized + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 401 + code: + enum: + - UNAUTHENTICATED + examples: + GENERIC_401_UNAUTHENTICATED: + description: Request cannot be authenticated + value: + status: 401 + code: UNAUTHENTICATED + message: Request not authenticated due to missing, invalid, or expired credentials. + + Generic403: + description: Forbidden + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + + VerifyLocationNotFound404: + description: Not found + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - IDENTIFIER_NOT_FOUND + examples: + GENERIC_404_IDENTIFIER_NOT_FOUND: + description: Some identifier cannot be matched to a device + value: + status: 404 + code: IDENTIFIER_NOT_FOUND + message: Device identifier not found. + + VerifyLocationUnprocessableEntity422: + description: Unprocessable Content + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - IDENTIFIER_MISMATCH + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + - LOCATION_VERIFICATION.AREA_NOT_COVERED + - LOCATION_VERIFICATION.INVALID_AREA + - LOCATION_VERIFICATION.UNABLE_TO_FULFILL_MAX_AGE + examples: + GENERIC_422_IDENTIFIER_MISMATCH: + description: Inconsistency between identifiers not pointing to the same device + value: + status: 422 + code: IDENTIFIER_MISMATCH + message: Provided identifiers are not consistent. + GENERIC_422_SERVICE_NOT_APPLICABLE: + description: Service not applicable for the provided identifier + value: + status: 422 + code: SERVICE_NOT_APPLICABLE + message: The service is not available for the provided identifier. + GENERIC_422_MISSING_IDENTIFIER: + description: An identifier is not included in the request and the device or phone number identification cannot be derived from the 3-legged access token + value: + status: 422 + code: MISSING_IDENTIFIER + message: The device cannot be identified. + GENERIC_422_UNSUPPORTED_IDENTIFIER: + description: None of the provided identifiers is supported by the implementation + value: + status: 422 + code: UNSUPPORTED_IDENTIFIER + message: The identifier provided is not supported. + GENERIC_422_UNNECESSARY_IDENTIFIER: + description: An explicit identifier is provided when a device or phone number has already been identified from the access token + value: + status: 422 + code: UNNECESSARY_IDENTIFIER + message: The device is already identified by the access token. + LOCATION_VERIFICATION_422_AREA_NOT_COVERED: + summary: The area cannot be covered + description: The system is not able cover the requested area + value: + status: 422 + code: LOCATION_VERIFICATION.AREA_NOT_COVERED + message: "Unable to cover the requested area" + LOCATION_VERIFICATION_422_INVALID_AREA: + summary: Invalid area + description: The requested area is too small to be supported by the system. + value: + status: 422 + code: LOCATION_VERIFICATION.INVALID_AREA + message: "The requested area is too small" + LOCATION_VERIFICATION_422_UNABLE_TO_FULFILL_MAX_AGE: + summary: Unable to fulfill maxAge + description: The system is not able to provide the fresh location required by the client + value: + status: 422 + code: LOCATION_VERIFICATION.UNABLE_TO_FULFILL_MAX_AGE + message: "Unable to provide expected freshness for location" \ No newline at end of file diff --git a/telco/camaraproject.org/number-verification/number-verification-2.0.0-openapi-metadata.yaml b/telco/camaraproject.org/number-verification/number-verification-2.0.0-openapi-metadata.yaml new file mode 100644 index 0000000..c705396 --- /dev/null +++ b/telco/camaraproject.org/number-verification/number-verification-2.0.0-openapi-metadata.yaml @@ -0,0 +1,277 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: Number Verification + version: 2.0.0 +operations: + POST /verify: + phoneNumber-verify-1: + request: + headers: + accept: application/json + body: |- + { + "hashedPhoneNumber" : "61c8ff3ad7a5e6dc885545a20ef8875a" + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "devicePhoneNumberVerified" : true + } + phoneNumber-verify-2: + request: + headers: + accept: application/json + body: |- + { + "hashedPhoneNumber" : "921fc3a855bb5fa912562819e440f908" + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "devicePhoneNumberVerified" : false + } + phoneNumber-verify-3: + request: + headers: + accept: application/json + body: |- + { + "hashedPhoneNumber" : "cfb686bd57d818f8102d8f5d16f8518c" + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "devicePhoneNumberVerified" : true + } + Realistic Example 1: + request: + headers: + accept: application/json + x-correlator: EXAMPLE12345 + body: |- + { + "phoneNumber" : "+1234567890" + } + response: + status: 200 + Realistic Example 2: + request: + headers: + accept: application/json + x-correlator: EXAMPLE54321 + body: |- + { + "hashedPhoneNumber" : "+1234567890" + } + response: + status: 200 + Realistic Example 3: + request: + headers: + accept: application/json + x-correlator: EXAMPLE98765 + body: |- + { + "phoneNumber" : "+1987654321" + } + response: + status: 200 + valid hash: + request: + headers: + x-correlator: abc123 + accept: application/json + body: |- + { + "phoneNumber" : "+1234567890", + "hashedPhoneNumber" : "246a6eb3238d5f9f47229669496b3892c08cd83127fd3445ff4e4f6ef7d5685a" + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "devicePhoneNumberVerified" : true + } + valid plain text: + request: + headers: + x-correlator: xyz987 + accept: application/json + body: |- + { + "phoneNumber" : "+1234567890" + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "devicePhoneNumberVerified" : false + } + invalid hash: + request: + headers: + x-correlator: def456 + accept: application/json + body: |- + { + "phoneNumber" : "+1987654321", + "hashedPhoneNumber" : "invalidhashednum" + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "devicePhoneNumberVerified" : false + } + GET /device-phone-number: + valid_device_phone_number: + request: + headers: + accept: application/json + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "devicePhoneNumber" : "+12345678901" + } + missing_correlator_header: + request: + headers: + accept: application/json + response: + headers: + content-type: application/json + status: 400 + mediaType: application/json + body: |- + { + "status" : 400, + "code" : "INVALID_ARGUMENT", + "message" : "Correlator header missing or invalid" + } + unauthorized_access: + request: + headers: + accept: application/json + response: + headers: + content-type: application/json + status: 401 + mediaType: application/json + body: |- + { + "status" : 401, + "code" : "UNAUTHENTICATED", + "message" : "Authentication required to access the resource" + } + Example of successful retrieval: + request: + headers: + accept: application/json + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "devicePhoneNumber" : "+15555555555" + } + Example of client request problem: + request: + headers: + accept: application/json + response: + headers: + content-type: application/json + status: 400 + mediaType: application/json + body: |- + { + "status" : 400, + "code" : "INVALID_ARGUMENT", + "message" : "Request parameters are invalid" + } + Example of unauthorized access: + request: + headers: + accept: application/json + response: + headers: + content-type: application/json + status: 401 + mediaType: application/json + body: |- + { + "status" : 401, + "code" : "UNAUTHENTICATED", + "message" : "Authentication required to access the resource" + } + example 1: + request: + headers: + accept: application/json + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "devicePhoneNumber" : "+123456789012" + } + example 2: + request: + headers: + accept: application/json + response: + headers: + content-type: application/json + status: 400 + mediaType: application/json + body: |- + { + "status" : 400, + "code" : "INVALID_ARGUMENT", + "message" : "One or more request parameters are invalid." + } + example 3: + request: + headers: + accept: application/json + response: + headers: + content-type: application/json + status: 401 + mediaType: application/json + body: |- + { + "status" : 401, + "code" : "UNAUTHENTICATED", + "message" : "User is unauthorized to access the device phone number." + } diff --git a/telco/camaraproject.org/number-verification/number-verification-2.0.0-openapi.yaml b/telco/camaraproject.org/number-verification/number-verification-2.0.0-openapi.yaml new file mode 100644 index 0000000..0eb6838 --- /dev/null +++ b/telco/camaraproject.org/number-verification/number-verification-2.0.0-openapi.yaml @@ -0,0 +1,328 @@ +openapi: 3.0.3 +info: + title: Number Verification + description: | + This API can verify or retrieve the **mobile phone number** that is currently allocated by the network operator to the SIM in the end user's device + + In this API **phone number** refers to the mobile phone number. + + # Introduction + + The Number Verification API is used by the API consumer to perform real-time checks to verify the phone number of a mobile device being used to access the application. This check can be done either by the API provider, returning "true" or "false", or by the application, by matching the phone number returned by the API Provider with the phone number of the device that is being used. + + It uses silent authentication (Network-based authentication or SIM-Based authentication) to verify possession of a phone number in the background without requiring user interaction. There are neither one-time passwords (OTP) received by SMS nor authenticator app downloads, so it is much simpler. It can be used at sign up, login, or transaction time to validate that a user's SIM is not spoofed or cloned. + + # Relevant Definitions and Concepts + + - **Network-Based Authentication**: Authentication mechanism based on the identification of the mobile phone. + A network operator knows to which subscriber a connected mobile phone belongs and what its associated phone number is. + - **SIM-Based Authentication**: Authentication mechanism based on the identification of the subscriber's SIM installed in the user's device. This mechanism relies on temporary tokens provided by the operator, as defined by [GSMA TS.43](https://www.gsma.com/newsroom/gsma_resources/ts-43-service-entitlement-configuration/) and [GSMA ASAC](https://www.gsma.com/newsroom/gsma_resources/asac-01-v1-0/). + + # API Functionality + + This API enables an API Consumer to verify or retrieve the phone number of the mobile device being used to access their service. + + # The Authentication Request + + ## Authentication Request with a temporary token + + If the API Consumer has a TS.43 temporary token created on the mobile device then this API works over all connections e.g. WiFi taking advantage of the SIM-Based authentication. + The API Consumer sends the temporary token to their backend which sends a CIBA Authentication Request, as described in the current release [CAMARA APIs Access and User Consent Management](https://github.com/camaraproject/IdentityAndConsentManagement), with a parameter "login_hint=operatortoken:". + How the API Consumers get a TS.43 temporary token and how this token is sent to their backend, is out-of-scope of the API definition. + + ## Authentication Request without a temporary token + + If the API Consumer does not have a TS.43 temporary token then the API Consumer must use OpenId Connect Authorization Code Flow as described in the current release of [CAMARA APIs Access and User Consent Management](https://github.com/camaraproject/IdentityAndConsentManagement). + For this method of authentication to work, the device must be connected to the mobile network. + + # Resources and Operations overview + + This API currently provides two endpoints which both require a **3-legged token** obtained by using one of the two methods indicated in _The Authentication Request_ section. This therefore **excludes** using, for example, SMS/OTP or user/password as an authentication method: + - The /verify endpoint checks whether the mobile phone number registered by the user with the API consumer matches the one actually associated with the mobile device. + It can receive either a hashed or a plain text phone number as input. + It compares the received phone number with the user's phone number associated to the access token in order to respond **true/false**. + - The /device-phone-number endpoint returns the phone number associated by the network operator with the SIM in the end user's device. + + # Sequence Diagram + + The following sequence diagram shows an example of a direct integration into the developer's application and the API Provider's Authorization Server and API for the case that no temporary token is available. + + UML Sequence Diagram + + **Implementation Details:** + + - **(1):** Authentication must be automatic without any user interactions. + Authentication methods such as SMS OTP or user/password are incompatible, as the goal is to validate the mobile phone number that is accessing the App. + + The API Consumer should use the request parameter prompt=none in the Authentication Request, as described in **[OIDC Connect](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest)**, ensuring no user interaction. + + The API Provider implies the request parameter prompt=none in the Authentication Request for this API. + + - **(2):** The way in which the phone number is retrieved depends upon the implementation. + For example, the access token may be a self-contained encrypted JWT, and so the API provider can decrypt and identify phone number directly from the access token. + Other implementations might retrieve the phone number associated with the access token from their Authorization Server. + + # Authorization and authentication + + The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to [Identity and Consent Management](https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. + + The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. + + In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. + + In the case of the Number Verification API scenario and according to the API definition, 3-legged access tokens must be used by API clients to invoke this API with dedicated scope. The API client must authenticate on behalf of a specific user to use this service. This must be done via mobile network authentication. + + version: 2.0.0 + x-camara-commonalities: 0.5 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +externalDocs: + description: Project documentation at CAMARA + url: https://github.com/camaraproject/NumberVerification +servers: + - url: '{apiRoot}/number-verification/v2' + variables: + apiRoot: + default: http://localhost:9091 + description: API root, defined by the service provider, e.g. `api.example.com` or `api.example.com/somepath +tags: + - name: Phone number verify + description: API operation to verify a phone number received as input. It can be received either in plain text or hashed format. + - name: Phone number share + description: API operation to return the phone number associated to the access token. +paths: + /verify: + post: + tags: + - Phone number verify + summary: Verifies if the received hashed/plain text phone number matches the phone number associated with the access token + description: | + Verifies if the specified phone number (either in plain text or hashed format) matches the one that the user is currently using. Only one of the plain or hashed formats must be provided. + - The number verification will be done for the user that has authenticated via mobile network + - It returns true/false depending on if the hashed phone number received as input matches the authenticated user's `device phone number` associated to the access token + operationId: phoneNumberVerify + parameters: + - $ref: "#/components/parameters/x-correlator" + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/NumberVerificationRequestBody' + required: true + responses: + '200': + description: OK + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: '#/components/schemas/NumberVerificationMatchResponse' + '400': + $ref: '#/components/responses/Generic400' + '401': + $ref: '#/components/responses/Generic401' + '403': + $ref: '#/components/responses/PhoneNumberVerificationPermissionDenied403' + security: + - openId: + - number-verification:verify + /device-phone-number: + get: + tags: + - Phone number share + summary: Returns the phone number associated with the access token + description: | + Returns the phone number so the API clients can verify the number themselves: + - It will be done for the user that has authenticated via mobile network + - It returns the authenticated user's `device phone number` associated to the access token + operationId: phoneNumberShare + parameters: + - $ref: "#/components/parameters/x-correlator" + responses: + '200': + description: OK + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: '#/components/schemas/NumberVerificationShareResponse' + '400': + $ref: '#/components/responses/Generic400' + '401': + $ref: '#/components/responses/Generic401' + '403': + $ref: '#/components/responses/PhoneNumberVerificationPermissionDenied403' + security: + - openId: + - number-verification:device-phone-number:read +components: + securitySchemes: + openId: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration + parameters: + x-correlator: + name: x-correlator + in: header + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + headers: + x-correlator: + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + schemas: + NumberVerificationRequestBody: + type: object + description: Payload to verify the phone number. + minProperties: 1 + maxProperties: 1 + properties: + phoneNumber: + type: string + pattern: '^\+[1-9][0-9]{4,14}$' + example: '+123456789' + description: A public identifier addressing a telephone subscription. In mobile networks it corresponds to the MSISDN (Mobile Station International Subscriber Directory Number). In order to be globally unique it has to be formatted in international format, according to E.164 standard, prefixed with '+'. + hashedPhoneNumber: + description: Hashed phone number. SHA-256 (in hexadecimal representation) of the mobile phone number in **E.164 format (starting with country code)**. Prefixed with '+'. + type: string + example: 32f67ab4e4312618b09cd23ed8ce41b13e095fe52b73b2e8da8ef49830e50dba + NumberVerificationMatchResponse: + type: object + description: Number verification result + required: + - devicePhoneNumberVerified + properties: + devicePhoneNumberVerified: + $ref: '#/components/schemas/DevicePhoneNumberVerified' + NumberVerificationShareResponse: + type: object + description: Number verification share result + required: + - devicePhoneNumber + properties: + devicePhoneNumber: + $ref: '#/components/schemas/DevicePhoneNumber' + DevicePhoneNumber: + type: string + pattern: '^\+[1-9][0-9]{4,14}$' + example: '+123456789' + description: A public identifier addressing a telephone subscription. In mobile networks it corresponds to the MSISDN (Mobile Station International Subscriber Directory Number). In order to be globally unique it has to be formatted in international format, according to E.164 standard, prefixed with '+'. + DevicePhoneNumberVerified: + description: Number verification. True, if it matches + type: boolean + ErrorInfo: + type: object + required: + - status + - code + - message + properties: + status: + type: integer + description: HTTP response status code + code: + type: string + description: Code given to this error + message: + type: string + description: Detailed error description + responses: + Generic400: + description: Problem with the client request + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + example: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param + Generic401: + description: Unauthorized + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 401 + code: + enum: + - UNAUTHENTICATED + - AUTHENTICATION_REQUIRED + examples: + GENERIC_401_UNAUTHENTICATED: + description: Request cannot be authenticated + value: + status: 401 + code: UNAUTHENTICATED + message: Request not authenticated due to missing, invalid, or expired credentials. + GENERIC_401_AUTHENTICATION_REQUIRED: + description: New authentication is needed, authentication is no longer valid + value: + status: 401 + code: AUTHENTICATION_REQUIRED + message: New authentication is required. + PhoneNumberVerificationPermissionDenied403: + description: | + Client does not have sufficient permission. + In addition to regular scenario of `PERMISSION_DENIED`, other scenarios may exist: + - Client authentication was not via mobile network. In order to check the authentication method, AMR parameter value in the 3-legged user's access token can be used and make sure that the authentication was not either by SMS+OTP nor username/password (`{"code": "NUMBER_VERIFICATION.USER_NOT_AUTHENTICATED_BY_MOBILE_NETWORK","message": "Client must authenticate via the mobile network to use this service"}`) + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + - NUMBER_VERIFICATION.USER_NOT_AUTHENTICATED_BY_MOBILE_NETWORK + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + GENERIC_403_USER_NOT_AUTHENTICATED_BY_MOBILE_NETWORK: + value: + status: 403 + code: NUMBER_VERIFICATION.USER_NOT_AUTHENTICATED_BY_MOBILE_NETWORK + message: Client must authenticate via the mobile network to use this service \ No newline at end of file diff --git a/telco/camaraproject.org/one-time-password-sms/one-time-password-sms-1.1.0-openapi-metadata.yaml b/telco/camaraproject.org/one-time-password-sms/one-time-password-sms-1.1.0-openapi-metadata.yaml new file mode 100644 index 0000000..d901c6f --- /dev/null +++ b/telco/camaraproject.org/one-time-password-sms/one-time-password-sms-1.1.0-openapi-metadata.yaml @@ -0,0 +1,235 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: One Time Password SMS + version: 1.1.0 +operations: + POST /send-code: + Valid-Request1: + request: + headers: + accept: application/json + body: |- + { + "phoneNumber" : "+123456789", + "message" : "Your OTP code is {{code}}" + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "authenticationId" : "123e4567-e89b-12d3-a456-426614174000" + } + Invalid-Request2: + request: + headers: + accept: application/json + body: |- + { + "phoneNumber" : "123456789", + "message" : "Your OTP code is {{code}}" + } + response: + headers: + content-type: application/json + status: 400 + mediaType: application/json + body: |- + { + "status" : 400, + "code" : "INVALID_ARGUMENT", + "message" : "Phone number is invalid. It should be in international format starting with '+'" + } + Rate-Limited-Request: + request: + headers: + accept: application/json + body: |- + { + "phoneNumber" : "+987654321", + "message" : "Your OTP code is {{code}}" + } + response: + headers: + content-type: application/json + status: 429 + mediaType: application/json + body: |- + { + "status" : 429, + "code" : "TOO_MANY_REQUESTS", + "message" : "You have reached the rate limiting limit for sending OTP codes." + } + Send OTP code to a phone number: + request: + headers: + accept: application/json + body: |- + { + "phoneNumber" : "+1234567890", + "message" : "Your OTP code is: {{code}}. Please use it to verify your number." + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "authenticationId" : "10101010-2020-3030-4040-505050505050" + } + Fail to send OTP code with invalid phone number: + request: + headers: + accept: application/json + body: |- + { + "phoneNumber" : "1234567890", + "message" : "Your OTP code is: {{code}}." + } + response: + headers: + content-type: application/json + status: 400 + mediaType: application/json + body: |- + { + "status" : 400, + "code" : "INVALID_ARGUMENT", + "message" : "Phone number is not in the correct format. Please provide a number in international format starting with a plus sign." + } + Fail to send OTP code due to quota exceeded: + request: + headers: + accept: application/json + body: |- + { + "phoneNumber" : "+9876543210", + "message" : "Your code is: {{code}}" + } + response: + headers: + content-type: application/json + status: 429 + mediaType: application/json + body: |- + { + "status" : 429, + "code" : "QUOTA_EXCEEDED", + "message" : "API request quota exceeded. Please try again later." + } + POST /validate-code: + Valid code validation: + request: + headers: + accept: application/json + body: |- + { + "authenticationId" : "7ba2eb62-1c4a-46f2-bb4c-21bcac10b03a", + "code" : "123456" + } + response: + headers: + content-type: application/json + status: 204 + mediaType: application/json + Expired AuthenticationId: + request: + headers: + accept: application/json + body: |- + { + "authenticationId" : "ecf9047e-e6e4-4e58-b908-158c314946a9", + "code" : "654321" + } + response: + headers: + content-type: application/json + status: 400 + mediaType: application/json + body: |- + { + "status" : 400, + "code" : "ONE_TIME_PASSWORD_SMS.VERIFICATION_EXPIRED", + "message" : "The authenticationId is no longer valid" + } + Invalid OTP for AuthenticationId: + request: + headers: + accept: application/json + body: |- + { + "authenticationId" : "4f94c823-2eb1-4658-993d-ba6f8ab7527d", + "code" : "999999" + } + response: + headers: + content-type: application/json + status: 400 + mediaType: application/json + body: |- + { + "status" : 400, + "code" : "ONE_TIME_PASSWORD_SMS.INVALID_OTP", + "message" : "The provided OTP is not valid for this authenticationId" + } + Valid OTP verification: + request: + headers: + x-correlator: abc123 + accept: application/json + body: |- + { + "authenticationId" : "54b10c56-0d46-48c2-b6f4-048afe18f592", + "code" : "123456" + } + response: + headers: + content-type: application/json + status: 204 + mediaType: application/json + Invalid OTP verification - Max attempts exceeded: + request: + headers: + x-correlator: def456 + accept: application/json + body: |- + { + "authenticationId" : "b9fb7ce0-164e-4c37-802b-54d86db1e9c5", + "code" : "654321" + } + response: + headers: + content-type: application/json + status: 400 + mediaType: application/json + body: |- + { + "status" : 400, + "code" : "ONE_TIME_PASSWORD_SMS.VERIFICATION_FAILED", + "message" : "The maximum number of attempts for this authenticationId was exceeded without providing a valid OTP" + } + Expired OTP verification: + request: + headers: + x-correlator: xyz789 + accept: application/json + body: |- + { + "authenticationId" : "c36e9ca1-2362-46e2-b6b5-275127e5d183", + "code" : "987654" + } + response: + headers: + content-type: application/json + status: 400 + mediaType: application/json + body: |- + { + "status" : 400, + "code" : "ONE_TIME_PASSWORD_SMS.VERIFICATION_EXPIRED", + "message" : "The authenticationId is no longer valid" + } diff --git a/telco/camaraproject.org/one-time-password-sms/one-time-password-sms-1.1.0-openapi.yaml b/telco/camaraproject.org/one-time-password-sms/one-time-password-sms-1.1.0-openapi.yaml new file mode 100644 index 0000000..b031a3a --- /dev/null +++ b/telco/camaraproject.org/one-time-password-sms/one-time-password-sms-1.1.0-openapi.yaml @@ -0,0 +1,438 @@ +openapi: 3.0.3 +info: + title: One Time Password SMS + description: |- + Service API to send short-lived OTPs (one time passwords) to a phone number via SMS and validate it afterwards, in order to verify the phone number as a proof of possession. + + # Relevant Definitions and concepts + - **OTP**: *One Time password* is a one-time authorization code that is valid for only one login session or transaction. + + # API Functionality + It enables a Service Provider (SP) to send an OTP code by SMS and validate it to verify the phone number (MSISDN) as a proof of possession. + + # Resources and Operations overview + This API currently provides two endpoints, one to send an OTP to a given phone number and another to validate the code received as input. + + # Authorization and authentication + + The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. + + The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. + + In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. + + version: 1.1.0 + x-camara-commonalities: 0.5 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +externalDocs: + description: Project documentation at CAMARA + url: https://github.com/camaraproject/OTPValidation +servers: + - url: "{apiRoot}/one-time-password-sms/v1" + variables: + apiRoot: + default: http://localhost:9091 + description: API root, defined by the service provider, e.g. `api.example.com` or `api.example.com/somepath` +tags: + - name: OTP Management + description: API operations to manage OTP codes +paths: + /send-code: + post: + tags: + - OTP Management + summary: Sends a message including an OTP code to the given phone number + description: |- + Sends an SMS with the desired message and an OTP code to the received phone number. + operationId: sendCode + parameters: + - $ref: "#/components/parameters/x-correlator" + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SendCodeBody' + required: true + responses: + '200': + description: OK + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: '#/components/schemas/SendCodeResponse' + '400': + $ref: '#/components/responses/Generic400' + '401': + $ref: '#/components/responses/Generic401' + '403': + $ref: '#/components/responses/SendCodeForbiddenError403' + '404': + $ref: '#/components/responses/Generic404' + '429': + $ref: '#/components/responses/Generic429' + security: + - openId: + - one-time-password-sms:send-validate + /validate-code: + post: + tags: + - OTP Management + summary: Verifies the OTP received as input + description: |- + Verifies the code is valid for the received authenticationId + operationId: validateCode + parameters: + - $ref: "#/components/parameters/x-correlator" + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ValidateCodeBody' + required: true + responses: + '204': + description: The OTP was successfully validated + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + '400': + $ref: '#/components/responses/ValidateCodeBadRequestError400' + '401': + $ref: '#/components/responses/Generic401' + '403': + $ref: '#/components/responses/Generic403' + '404': + $ref: '#/components/responses/Generic404' + '429': + $ref: '#/components/responses/Generic429' + security: + - openId: + - one-time-password-sms:send-validate +components: + parameters: + x-correlator: + name: x-correlator + in: header + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + headers: + x-correlator: + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + schemas: + SendCodeBody: + description: Structure to request sending a code to a phone number + type: object + properties: + phoneNumber: + $ref: '#/components/schemas/PhoneNumber' + message: + $ref: '#/components/schemas/Message' + required: + - message + - phoneNumber + SendCodeResponse: + description: Structure to provide authentication identifier + type: object + properties: + authenticationId: + $ref: '#/components/schemas/AuthenticationId' + required: + - authenticationId + ValidateCodeBody: + description: Strcuture to request code verification + type: object + properties: + authenticationId: + $ref: '#/components/schemas/AuthenticationId' + code: + $ref: '#/components/schemas/Code' + required: + - authenticationId + - code + PhoneNumber: + description: A public identifier addressing a telephone subscription. In mobile networks it corresponds to the MSISDN (Mobile Station International Subscriber Directory Number). In order to be globally unique it has to be formatted in international format, according to E.164 standard, prefixed with '+'. + type: string + pattern: '^\+[1-9][0-9]{4,14}$' + example: '+346661113334' + Message: + type: string + description: Message template used to compose the content of the SMS sent to the phone number. It must include the following label indicating where to include the short code `{{code}}` + pattern: .*\{\{code\}\}.* + maxLength: 160 + example: '{{code}} is your short code to authenticate with Cool App via SMS' + AuthenticationId: + type: string + description: unique id of the verification attempt the code belongs to. + maxLength: 36 + example: ea0840f3-3663-4149-bd10-c7c6b8912105 + Code: + type: string + description: temporal, short code to be validated + maxLength: 10 + example: AJY3 + ErrorInfo: + description: Structure to describe error + type: object + required: + - status + - code + - message + properties: + status: + type: integer + description: HTTP response status code + code: + type: string + description: Code given to this error + message: + type: string + description: Detailed error description + securitySchemes: + openId: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration + responses: + Generic400: + description: Problem with the client request + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + ValidateCodeBadRequestError400: + description: |- + Problem with the client request. In addition to regular scenario of `INVALID_ARGUMENT`, another scenarios may exist: + - Too many unsuccessful attempts (`{"code": "ONE_TIME_PASSWORD_SMS.VERIFICATION_FAILED","message": "The maximum number of attempts for this authenticationId was exceeded without providing a valid OTP"}`) + - Expired authenticationId (`{"code": "ONE_TIME_PASSWORD_SMS.VERIFICATION_EXPIRED","message": "The authenticationId is no longer valid"}`) + - OTP is not valid for the provided authenticationId (`{"code": "ONE_TIME_PASSWORD_SMS.INVALID_OTP","message": "The provided OTP is not valid for this authenticationId"}`) + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - OUT_OF_RANGE + - ONE_TIME_PASSWORD_SMS.VERIFICATION_FAILED + - ONE_TIME_PASSWORD_SMS.VERIFICATION_EXPIRED + - ONE_TIME_PASSWORD_SMS.INVALID_OTP + examples: + GENERIC_400_OUT_OF_RANGE: + description: Out of Range. Specific Syntax Exception used when a given field has a pre-defined range or a invalid filter criteria combination is requested + value: + status: 400 + code: OUT_OF_RANGE + message: Client specified an invalid range. + GENERIC_400_INVALID_ARGUMENT: + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param + OTP_VALIDATION_400_VERIFICATION_FAILED: + value: + status: 400 + code: ONE_TIME_PASSWORD_SMS.VERIFICATION_FAILED + message: The maximum number of attempts for this authenticationId was exceeded without providing a valid OTP + OTP_VALIDATION_400_VERIFICATION_EXPIRED: + value: + status: 400 + code: ONE_TIME_PASSWORD_SMS.VERIFICATION_EXPIRED + message: The authenticationId is no longer valid + OTP_VALIDATION_400_INVALID_OTP: + value: + status: 400 + code: ONE_TIME_PASSWORD_SMS.INVALID_OTP + message: The provided OTP is not valid for this authenticationId + Generic401: + description: Authentication problem with the client request + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 401 + code: + enum: + - UNAUTHENTICATED + examples: + GENERIC_401_UNAUTHENTICATED: + description: Request cannot be authenticated + value: + status: 401 + code: UNAUTHENTICATED + message: Request not authenticated due to missing, invalid, or expired credentials. + Generic403: + description: Client does not have sufficient permission + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + SendCodeForbiddenError403: + description: |- + Client does not have sufficient permissions to perform this action. + In addition to regular scenario of `PERMISSION_DENIED`, another scenarios may exist: + - Too many code requests were sent (`{"code": "ONE_TIME_PASSWORD_SMS.MAX_OTP_CODES_EXCEEDED","message": "Too many OTPs have been requested for this MSISDN. Try later."}`) + - The given phoneNumber can't receive an SMS due to business reasons in the operator, e.g. fraud, receiving SMS is not supported, etc (`{"code": "ONE_TIME_PASSWORD_SMS.PHONE_NUMBER_NOT_ALLOWED","message": "Phone_number can't receive an SMS due to business reasons in the operator."}`) + - The given phoneNumber is blocked to receive SMS due to any blocking business reason in the operator (`{"code": "ONE_TIME_PASSWORD_SMS.PHONE_NUMBER_BLOCKED","message": "Phone_number is blocked to receive SMS due to any blocking business reason in the operator."}`) + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + - ONE_TIME_PASSWORD_SMS.MAX_OTP_CODES_EXCEEDED + - ONE_TIME_PASSWORD_SMS.PHONE_NUMBER_NOT_ALLOWED + - ONE_TIME_PASSWORD_SMS.PHONE_NUMBER_BLOCKED + examples: + GENERIC_403_PERMISSION_DENIED: + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action + OTP_VALIDATION_403_MAX_OTP_CODES_EXCEEDED: + value: + status: 403 + code: ONE_TIME_PASSWORD_SMS.MAX_OTP_CODES_EXCEEDED + message: Too many OTPs have been requested for this MSISDN. Try later. + OTP_VALIDATION_403_PHONE_NUMBER_NOT_ALLOWED: + value: + status: 403 + code: ONE_TIME_PASSWORD_SMS.PHONE_NUMBER_NOT_ALLOWED + message: Phone_number can't receive an SMS due to business reasons in the operator. + OTP_VALIDATION_403_PHONE_NUMBER_BLOCKED: + value: + status: 403 + code: ONE_TIME_PASSWORD_SMS.PHONE_NUMBER_BLOCKED + message: Phone_number is blocked to receive SMS due to any blocking business reason in the operator. + Generic404: + description: Resource Not Found + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - NOT_FOUND + examples: + GENERIC_404_NOT_FOUND: + description: Resource is not found + value: + status: 404 + code: NOT_FOUND + message: The specified resource is not found. + Generic429: + description: Either out of resource quota or reaching rate limiting + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 429 + code: + enum: + - QUOTA_EXCEEDED + - TOO_MANY_REQUESTS + examples: + GENERIC_429_QUOTA_EXCEEDED: + description: Request is rejected due to exceeding a business quota limit + value: + status: 429 + code: QUOTA_EXCEEDED + message: Out of resource quota. + GENERIC_429_TOO_MANY_REQUESTS: + description: Access to the API has been temporarily blocked due to rate or spike arrest limits being reached + value: + status: 429 + code: TOO_MANY_REQUESTS + message: Rate limit reached. \ No newline at end of file diff --git a/telco/camaraproject.org/qos-profiles/qos-profiles-1.0.0-openapi-metadata.yaml b/telco/camaraproject.org/qos-profiles/qos-profiles-1.0.0-openapi-metadata.yaml new file mode 100644 index 0000000..c611f2d --- /dev/null +++ b/telco/camaraproject.org/qos-profiles/qos-profiles-1.0.0-openapi-metadata.yaml @@ -0,0 +1,620 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: QoS Profiles + version: 1.0.0 +operations: + GET /qos-profiles/{name}: + Real-time Interactive QoS Profile for Gaming: + request: + headers: + accept: application/json + parameters: + name: real-time-interactive + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "name" : "real-time-interactive", + "description" : "QoS profile optimized for real-time interactive gaming applications.", + "status" : "ACTIVE", + "targetMinUpstreamRate" : { + "value" : 100, + "unit" : "Mbps" + }, + "maxUpstreamRate" : { + "value" : 1000, + "unit" : "Mbps" + }, + "maxUpstreamBurstRate" : { + "value" : 150, + "unit" : "Mbps" + }, + "targetMinDownstreamRate" : { + "value" : 500, + "unit" : "Mbps" + }, + "maxDownstreamRate" : { + "value" : 1000, + "unit" : "Mbps" + }, + "maxDownstreamBurstRate" : { + "value" : 150, + "unit" : "Mbps" + }, + "minDuration" : { + "value" : 5, + "unit" : "Minutes" + }, + "maxDuration" : { + "value" : 60, + "unit" : "Minutes" + }, + "priority" : 10, + "packetDelayBudget" : { + "value" : 10, + "unit" : "Milliseconds" + }, + "jitter" : { + "value" : 5, + "unit" : "Milliseconds" + }, + "packetErrorLossRate" : 3, + "l4sQueueType" : "mixed-queue", + "serviceClass" : "real_time_interactive" + } + QoS Profile for Video Streaming: + request: + headers: + accept: application/json + parameters: + name: video-streaming + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "name" : "video-streaming", + "description" : "QoS profile designed for high-definition video streaming services.", + "status" : "ACTIVE", + "targetMinUpstreamRate" : { + "value" : 50, + "unit" : "Mbps" + }, + "maxUpstreamRate" : { + "value" : 500, + "unit" : "Mbps" + }, + "targetMinDownstreamRate" : { + "value" : 500, + "unit" : "Mbps" + }, + "maxDownstreamRate" : { + "value" : 1000, + "unit" : "Mbps" + }, + "maxDownstreamBurstRate" : { + "value" : 200, + "unit" : "Mbps" + }, + "minDuration" : { + "value" : 10, + "unit" : "Minutes" + }, + "maxDuration" : { + "value" : 120, + "unit" : "Minutes" + }, + "priority" : 20, + "packetDelayBudget" : { + "value" : 20, + "unit" : "Milliseconds" + }, + "jitter" : { + "value" : 10, + "unit" : "Milliseconds" + }, + "packetErrorLossRate" : 5, + "serviceClass" : "multimedia_streaming" + } + Active Voice QoS Profile: + request: + headers: + accept: application/json + parameters: + name: active-voice + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "name" : "active-voice", + "description" : "QoS profile for high-quality voice communications over IP networks.", + "status" : "ACTIVE", + "targetMinUpstreamRate" : { + "value" : 10, + "unit" : "Mbps" + }, + "maxUpstreamRate" : { + "value" : 50, + "unit" : "Mbps" + }, + "targetMinDownstreamRate" : { + "value" : 50, + "unit" : "Mbps" + }, + "maxDownstreamRate" : { + "value" : 150, + "unit" : "Mbps" + }, + "maxDownstreamBurstRate" : { + "value" : 50, + "unit" : "Mbps" + }, + "minDuration" : { + "value" : 1, + "unit" : "Minutes" + }, + "maxDuration" : { + "value" : 15, + "unit" : "Minutes" + }, + "priority" : 5, + "packetDelayBudget" : { + "value" : 5, + "unit" : "Milliseconds" + }, + "jitter" : { + "value" : 2, + "unit" : "Milliseconds" + }, + "packetErrorLossRate" : 2, + "l4sQueueType" : "non-l4s-queue", + "serviceClass" : "microsoft_voice" + } + basic_qos_profile: + request: + headers: + accept: application/json + parameters: + name: QOS_E + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "name" : "QOS_E", + "description" : "Low latency, high throughput profile", + "status" : "ACTIVE", + "targetMinUpstreamRate" : { + "value" : 300, + "unit" : "Kbps" + }, + "maxUpstreamRate" : { + "value" : 500, + "unit" : "kbps" + }, + "maxUpstreamBurstRate" : { + "value" : 600, + "unit" : "kbps" + }, + "targetMinDownstreamRate" : { + "value" : 1000, + "unit" : "kbps" + }, + "maxDownstreamRate" : { + "value" : 2000, + "unit" : "kbps" + }, + "maxDownstreamBurstRate" : { + "value" : 2500, + "unit" : "kbps" + }, + "minDuration" : { + "value" : 15, + "unit" : "Minutes" + }, + "maxDuration" : { + "value" : 1440, + "unit" : "Minutes" + }, + "priority" : 10, + "packetDelayBudget" : { + "value" : 100, + "unit" : "Milliseconds" + }, + "jitter" : { + "value" : 10, + "unit" : "Milliseconds" + }, + "packetErrorLossRate" : 5, + "l4sQueueType" : "l4s-queue", + "serviceClass" : "low_latency_data" + } + qos_profile_invalid_name: + request: + headers: + accept: application/json + parameters: + name: not_a_valid_profile + response: + headers: + content-type: application/json + status: 404 + mediaType: application/json + body: |- + { + "status" : 404, + "code" : "NOT_FOUND", + "message" : "QoS Profile 'not_a_valid_profile' is not found." + } + qos_profile_already_deprecated: + request: + headers: + accept: application/json + parameters: + name: QOS_D + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "name" : "QOS_D", + "description" : "Premium high-priority profile", + "status" : "DEPRECATED", + "targetMinUpstreamRate" : { + "value" : 300, + "unit" : "kbps" + }, + "maxUpstreamRate" : { + "value" : 500, + "unit" : "kbps" + }, + "maxUpstreamBurstRate" : { + "value" : 600, + "unit" : "kbps" + }, + "targetMinDownstreamRate" : { + "value" : 1000, + "unit" : "kbps" + }, + "maxDownstreamRate" : { + "value" : 2000, + "unit" : "kbps" + }, + "maxDownstreamBurstRate" : { + "value" : 2500, + "unit" : "kbps" + }, + "minDuration" : { + "value" : 10, + "unit" : "Minutes" + }, + "maxDuration" : { + "value" : 360, + "unit" : "Minutes" + }, + "priority" : 5, + "packetDelayBudget" : { + "value" : 200, + "unit" : "Milliseconds" + }, + "jitter" : { + "value" : 15, + "unit" : "Milliseconds" + }, + "packetErrorLossRate" : 4, + "l4sQueueType" : "mixed-queue", + "serviceClass" : "standard" + } + POST /retrieve-qos-profiles: + Regular device request: + request: + headers: + x-correlator: abcd1234 + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+123456789" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + [ { + "name" : "QOS_E", + "description" : "Example QoS profile for high priority traffic", + "status" : "ACTIVE", + "targetMinUpstreamRate" : { + "value" : 1000, + "unit" : "kbps" + }, + "maxUpstreamRate" : { + "value" : 2000, + "unit" : "kbps" + }, + "maxUpstreamBurstRate" : { + "value" : 2500, + "unit" : "kbps" + }, + "targetMinDownstreamRate" : { + "value" : 5000, + "unit" : "kbps" + }, + "maxDownstreamRate" : { + "value" : 10000, + "unit" : "kbps" + } + } ] + Special device request: + request: + headers: + accept: application/json + x-correlator: efgh5678 + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.168.0.1", + "privateAddress" : "10.0.0.1", + "publicPort" : 8080 + }, + "ipv6Address" : "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + [ { + "name" : "QOS_S", + "description" : "Example QoS profile for standard traffic", + "status" : "ACTIVE", + "targetMinUpstreamRate" : { + "value" : 500, + "unit" : "kbps" + }, + "maxUpstreamRate" : { + "value" : 1000, + "unit" : "kbps" + }, + "maxUpstreamBurstRate" : { + "value" : 1500, + "unit" : "kbps" + }, + "targetMinDownstreamRate" : { + "value" : 2500, + "unit" : "kbps" + }, + "maxDownstreamRate" : { + "value" : 5000, + "unit" : "kbps" + } + } ] + Authentication required: + request: + headers: + accept: application/json + x-correlator: ijkl9012 + body: |- + { + "device" : { + "phoneNumber" : "+987654321" + } + } + response: + headers: + content-type: application/json + status: 401 + mediaType: application/json + body: |- + { + "status" : 401, + "code" : "AUTHENTICATION_REQUIRED", + "message" : "API authentication required to access this resource" + } + Retrieve QoS Profiles by IPv4 address: + request: + headers: + x-correlator: qwerty123 + accept: application/json + body: |- + { + "device" : { + "ipv4Address" : { + "publicAddress" : "192.168.0.1", + "privateAddress" : "10.0.0.1" + }, + "name" : "QOS_E", + "status" : "ACTIVE" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + [ { + "name" : "QOS_E", + "description" : "Description of QoS Profile E", + "status" : "ACTIVE", + "targetMinUpstreamRate" : { + "value" : 500, + "unit" : "kbps" + }, + "maxUpstreamRate" : { + "value" : 1000, + "unit" : "kbps" + }, + "maxUpstreamBurstRate" : { + "value" : 1500, + "unit" : "kbps" + }, + "targetMinDownstreamRate" : { + "value" : 250, + "unit" : "kbps" + }, + "maxDownstreamRate" : { + "value" : 512, + "unit" : "kbps" + }, + "maxDownstreamBurstRate" : { + "value" : 768, + "unit" : "kbps" + }, + "minDuration" : { + "value" : 2, + "unit" : "Hours" + }, + "maxDuration" : { + "value" : 24, + "unit" : "Hours" + }, + "priority" : 50, + "packetDelayBudget" : { + "value" : 250, + "unit" : "milliseconds" + }, + "jitter" : { + "value" : 50, + "unit" : "milliseconds" + }, + "packetErrorLossRate" : 3, + "l4sQueueType" : "mixed-queue", + "serviceClass" : "high-throughput_data" + } ] + Retrieve QoS Profiles by IPv6 address: + request: + headers: + accept: application/json + x-correlator: asdfgh456 + body: |- + { + "device" : { + "ipv6Address" : "2001:db8::1", + "name" : "QOS_S", + "status" : "ACTIVE" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + [ { + "name" : "QOS_S", + "description" : "Description of QoS Profile S", + "status" : "ACTIVE", + "targetMinUpstreamRate" : { + "value" : 256, + "unit" : "kbps" + }, + "maxUpstreamRate" : { + "value" : 512, + "unit" : "kbps" + }, + "targetMinDownstreamRate" : { + "value" : 128, + "unit" : "kbps" + }, + "maxDownstreamRate" : { + "value" : 256, + "unit" : "kbps" + }, + "minDuration" : { + "value" : 4, + "unit" : "Hours" + }, + "maxDuration" : { + "value" : 48, + "unit" : "Hours" + }, + "priority" : 80, + "packetDelayBudget" : { + "value" : 200, + "unit" : "milliseconds" + }, + "jitter" : { + "value" : 40, + "unit" : "milliseconds" + }, + "packetErrorLossRate" : 2, + "l4sQueueType" : "mixed-queue", + "serviceClass" : "multimedia_streaming" + } ] + Retrieve QoS Profiles by phone number: + request: + headers: + x-correlator: zxcvbn789 + accept: application/json + body: |- + { + "device" : { + "phoneNumber" : "+1234567890", + "networkAccessIdentifier" : "1234@5678", + "name" : "QOS_M", + "status" : "ACTIVE" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + [ { + "name" : "QOS_M", + "description" : "Description of QoS Profile M", + "status" : "ACTIVE", + "maxUpstreamRate" : { + "value" : 25, + "unit" : "Mbps" + }, + "targetMinDownstreamRate" : { + "value" : 50, + "unit" : "Mbps" + }, + "maxDownstreamRate" : { + "value" : 100, + "unit" : "Mbps" + }, + "minDuration" : { + "value" : 1, + "unit" : "Hour" + }, + "maxDuration" : { + "value" : 12, + "unit" : "Hours" + }, + "priority" : 25, + "packetDelayBudget" : { + "value" : 100, + "unit" : "milliseconds" + }, + "jitter" : { + "value" : 30, + "unit" : "milliseconds" + }, + "packetErrorLossRate" : 5, + "l4sQueueType" : "l4s-queue", + "serviceClass" : "low_latency_data" + } ] diff --git a/telco/camaraproject.org/qos-profiles/qos-profiles-1.0.0-openapi.yaml b/telco/camaraproject.org/qos-profiles/qos-profiles-1.0.0-openapi.yaml new file mode 100644 index 0000000..b090159 --- /dev/null +++ b/telco/camaraproject.org/qos-profiles/qos-profiles-1.0.0-openapi.yaml @@ -0,0 +1,795 @@ +openapi: 3.0.3 +info: + title: QoS Profiles + description: | + The Qualtiy-of-Service (QoS) Profiles API provides a set of predefined network performance characteristics, such as latency, throughput, and priority, identified by a unique name. These profiles allow application developers to specify the desired network behavior for their application's data traffic, ensuring optimal performance. By selecting an appropriate QoS profile, developers can request stable latency (reduced jitter) or throughput for specific data flows between client devices and application servers when used by the Quality-On-Demand APIs. + + # Introduction + + QoS Profiles are used in conjunction with other Quality-On-Demand APIs, to offer the API consumer the capability to request for stable latency (reduced jitter) or throughput for some specified application data flows between application clients (within a user device) and Application Servers (backend services). The API consumer has a pre-defined set of Quality of Service (QoS) profiles which they could choose from depending on their latency or throughput requirements. The QoS profiles are defined by the API provider and are mapped to the connectivity characteristics of the supported networks. + + # API functionality + + The QoS Profiles API provides the following functionality: + - Discover all QoS profiles offered by the API provider + - Discover the available QoS profiles for a specific device + - Retrieve the characteristics of a specific QoS profile by name + + How QoS profiles are mapped to connectivity characteristics are subject to agreements between the API provider and the API consumer. Within the CAMARA project, you can find a sample for such a mapping of QoS profiles. [CAMARA QoS Profiles Mapping Table (REFERENCE DRAFT)](https://github.com/camaraproject/QualityOnDemand/blob/r2.2/documentation/API_documentation/QoSProfile_Mapping_Table.md) + + # Authorization and authentication + + The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. + + The specific authorization flows to be used will be agreed upon during the onboarding process, happening between the API consumer and the API provider, taking into account the declared purpose for accessing the API, whilst also being subject to the prevailing legal framework dictated by local legislation. + + In cases where personal data is processed by the API and users can exercise their rights through mechanisms such as opt-in and/or opt-out, the use of three-legged access tokens is mandatory. This ensures that the API remains in compliance with privacy regulations, upholding the principles of transparency and user-centric privacy-by-design. + + # Identifying the device from the access token + + The two operations defined by this API (`getQosProfile` and `retrieveQoSProfiles`) both allow the API consumer to use a three-legged access token to specify a target device as a query filter. When provided, only profiles available to the specified target device will be returned. Additionally, when a two-legged acccess token is used, the operation `retrieveQoSProfiles` allows the API consumer to optionally specify the target device in the request body. + + Hence, for the `retrieveQoSProfiles` operation: + - When invoked using a two-legged access token, the optional input device object will be used as filter if present. + + - When invoked using a three-legged access token, this optional identifier in the request body MUST NOT be provided, as the device to filter will be uniquely identified from the access token. + + This approach simplifies API usage for API consumers using a three-legged access token to invoke the API by relying on the information that is associated with the access token and was identified during the authentication process. + + ## Error handling: + - If the device can be identified from the access token and the optional `device` object is also included in the request, then the server will return an error with the `422 UNNECESSARY_IDENTIFIER` error code. This will be the case even if the same device is identified by these two methods, as the server is unable to make this comparison. + + # Multi-SIM scenario handling + + In multi-SIM scenarios where more than one mobile device is associated with a phone number (e.g. a smartphone with an associated smartwatch), it might not be possible to uniquely identify a single device from that phone number. When filtering QoS profiles by device in such scenarios, one of the following options should be used: + - Use the authorisation code flow to obtain a 3-legged access token, which will automatically identify the intended device + - Identify the intended device from a unique identifier for that device, such as its source IP address and port + - Check with the SIM provider whether a unique "secondary" phone number is already associated with each device, and use the secondary phone number to identify the intended device if available + + # Further info and support + + (FAQs will be added in a later version of the documentation) + + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.0 + x-camara-commonalities: 0.5 + + +externalDocs: + description: Project documentation at Camara + url: https://github.com/camaraproject/QualityOnDemand + +servers: + - url: "{apiRoot}/qos-profiles/v1" + variables: + apiRoot: + default: http://localhost:9091 + description: API root, defined by the service provider, e.g. `api.example.com` or `api.example.com/somepath` + +tags: + - name: QoS Profiles + description: Manage QoS Profiles + +paths: + /retrieve-qos-profiles: + post: + tags: + - QoS Profiles + summary: Retrieve QoS profiles + description: | + Returns all QoS Profiles that match the given criteria. + **NOTES:** + - The access token may be either a 2-legged or 3-legged access token. + - If the access token is 3-legged, all returned QoS Profiles will be available to the subject (device) associated with the access token. + - This call uses the POST method instead of GET to comply with the CAMARA Commonalities guidelines for sending sensitive or complex data in API calls. Since the device field may contain personally identifiable information, it should not be sent via GET. Additionally, this call may include complex data structures. + [CAMARA API Design Guidelines](https://github.com/camaraproject/Commonalities/blob/r2.3/documentation/API-design-guidelines.md#post-or-get-for-transferring-sensitive-or-complex-data) + + security: + - openId: + - qos-profiles:read + operationId: retrieveQoSProfiles + parameters: + - $ref: "#/components/parameters/x-correlator" + requestBody: + description: Parameters to query QoS Profiles for a given device + content: + application/json: + schema: + $ref: "#/components/schemas/QosProfileDeviceRequest" + required: true + responses: + "200": + description: Contains information about QoS Profiles + headers: + x-correlator: + $ref: '#/components/headers/x-correlator' + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/QosProfile" + "400": + $ref: "#/components/responses/Generic400" + "401": + $ref: "#/components/responses/Generic401" + "403": + $ref: "#/components/responses/Generic403" + "404": + $ref: "#/components/responses/GenericDevice404" + "422": + $ref: "#/components/responses/Generic422" + "429": + $ref: "#/components/responses/Generic429" + + /qos-profiles/{name}: + get: + tags: + - QoS Profiles + summary: "Get QoS Profile for a given name" + operationId: getQosProfile + description: | + Returns a QoS Profile that matches the given name. + + The access token may be either a 2-legged or 3-legged access token. If the access token is 3-legged, a QoS Profile is only returned if available to all subjects associated with the access token. + + security: + - openId: + - qos-profiles:read + parameters: + - name: name + in: path + description: Qos Profile name + required: true + schema: + $ref: "#/components/schemas/QosProfileName" + - $ref: "#/components/parameters/x-correlator" + responses: + "200": + description: Contains information about QoS Profiles + headers: + x-correlator: + $ref: '#/components/headers/x-correlator' + content: + application/json: + schema: + $ref: "#/components/schemas/QosProfile" + "400": + $ref: "#/components/responses/Generic400" + "401": + $ref: "#/components/responses/Generic401" + "403": + $ref: "#/components/responses/Generic403" + "404": + $ref: "#/components/responses/Generic404" + "429": + $ref: "#/components/responses/Generic429" + +components: + securitySchemes: + openId: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration + + parameters: + x-correlator: + name: x-correlator + in: header + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + + headers: + x-correlator: + description: Correlation id for the different services + schema: + type: string + pattern: ^[a-zA-Z0-9-]{0,55}$ + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + + schemas: + QosProfile: + description: | + Data type with attributes of a QosProfile + type: object + properties: + name: + $ref: "#/components/schemas/QosProfileName" + description: + description: | + A description of the QoS profile. + type: string + example: "QoS profile for video streaming" + status: + $ref: "#/components/schemas/QosProfileStatusEnum" + targetMinUpstreamRate: + description: | + This is the target minimum upload speed for the QoS profile. + It represents the minimum rate that the network attempts to deliver. + Please note that this is a target value—the network might not always be able to provide this rate under all conditions. + It helps ensure that applications like video calls or live streaming perform consistently. + allOf: + - $ref: "#/components/schemas/Rate" + maxUpstreamRate: + description: | + The maximum best effort data + allOf: + - $ref: "#/components/schemas/Rate" + maxUpstreamBurstRate: + description: | + When defined, this is the maximum upstream burst rate for the QoS profile, that will enable + the network to burst data at a higher rate than the maxUpstreamRate for a period of time. + allOf: + - $ref: "#/components/schemas/Rate" + targetMinDownstreamRate: + description: | + This is the target maximum upload speed for the QoS profile. + It represents the maximum rate that the network attempts to deliver. + Please note that this is a target value—the network might not always be able to provide this rate under all conditions. + It helps ensure that applications like video calls or live streaming perform consistently. + allOf: + - $ref: "#/components/schemas/Rate" + maxDownstreamRate: + description: | + The maximum best effort rate + allOf: + - $ref: "#/components/schemas/Rate" + maxDownstreamBurstRate: + description: | + When defined, this is the maximum downstream burst rate for the QoS profile, that will enable + the network to burst data at a higher rate than the maxDownstreamRate for a period of time. + This can result in improved user experience when there is additional network capacity. + For instance, when a user is streaming a video, the network can burst data at a higher rate + to fill the buffer, and then return to the maxUpstreamRate once the buffer is full. + allOf: + - $ref: "#/components/schemas/Rate" + minDuration: + description: | + The shortest time period that this profile can be deployed. + allOf: + - $ref: "#/components/schemas/Duration" + maxDuration: + description: | + The maximum time period that this profile can be deployed. + Overall session duration must not exceed this value. This includes the initial requested duration plus any extensions. + allOf: + - $ref: "#/components/schemas/Duration" + priority: + type: integer + example: 20 + description: | + Priority levels allow efficient resource allocation and ensure optimal performance + for various services in each technology, with the highest priority traffic receiving + preferential treatment. + The lower value the higher priority. + Not all access networks use the same priority range, so this priority will be + scaled to the access network's priority range. + format: int32 + minimum: 1 + maximum: 100 + packetDelayBudget: + description: | + The packet delay budget is the maximum allowable one-way latency between the customer's device + and the gateway from the operator's network to other networks. By limiting the delay, the network + can provide an acceptable level of performance for various services, such as voice calls, + video streaming, and data. + The end-to-end or round trip latency will be about two times this value plus the latency not controlled + by the operator + allOf: + - $ref: "#/components/schemas/Duration" + jitter: + description: | + The jitter requirement aims to limit the maximum variation in round-trip + packet delay for the 99th percentile of traffic, following ITU Y.1540 + standards. It considers only acknowledged packets in a session, which are + packets that receive a confirmation of receipt from the recipient (e.g., + using TCP). This requirement helps maintain consistent latency, essential + for real-time applications such as VoIP, video calls, and gaming. + allOf: + - $ref: "#/components/schemas/Duration" + packetErrorLossRate: + type: integer + description: | + This field specifies the acceptable level of data loss during transmission. + The value is an exponent of 10, so a value of 3 means that up to 10⁻³, or 0.1%, of the + data packets may be lost. This setting is part of a broader system that categorizes + different types of network traffic (like phone calls, video streams, or data transfers) + to ensure they perform reliably on the network. + format: int32 + minimum: 1 + maximum: 10 + example: 3 + l4sQueueType: + type: string + enum: + - non-l4s-queue + - l4s-queue + - mixed-queue + description: | + + **NOTE**: l4sQueueType is experimental and could change or be removed in a future release. + + Specifies the type of queue for L4S (Low Latency, Low Loss, Scalable Throughput) traffic management. L4S is an advanced queue management approach designed to provide ultra-low latency and high throughput for internet traffic, particularly beneficial for interactive applications such as gaming, video conferencing, and virtual reality. + + **Queue Type Descriptions:** + + - **non-l4s-queue**: + A traditional queue used for legacy internet traffic that does not utilize L4S enhancements. It provides standard latency and throughput levels. + + - **l4s-queue**: + A dedicated queue optimized for L4S traffic, delivering ultra-low latency, low loss, and scalable throughput to support latency-sensitive applications. + + - **mixed-queue**: + A shared queue that can handle both L4S and traditional traffic, offering a balance between ultra-low latency for L4S flows and compatibility with non-L4S flows. + + externalDocs: + description: For more details, refer to the L4S standard. + url: https://datatracker.ietf.org/doc/rfc9330/ + serviceClass: + type: string + description: | + + **NOTE**: serviceClass is experimental and could change or be removed in a future release. + + The name of a Service Class, representing a QoS Profile designed to provide optimized behavior for a specific application type. While DSCP values are commonly associated with Service Classes, their use may vary across network segments and may not be applied throughout the entire end-to-end QoS session. This aligns with the serviceClass concept used in HomeDevicesQoQ for consistent terminology. + + Service classes define specific QoS behaviors that map to DSCP (Differentiated Services Code Point) values or Microsoft QoS traffic types. + + The supported mappings are: + 1. Values aligned with the [RFC4594](https://datatracker.ietf.org/doc/html/rfc4594) guidelines for differentiated traffic classes. + 2. Microsoft [QOS_TRAFFIC_TYPE](https://learn.microsoft.com/en-us/windows/win32/api/qos2/ne-qos2-qos_traffic_type) values for Windows developers. + + **Supported Service Classes**: + + | Service Class Name | DSCP Name | DSCP value (decimal) | DCSP value (binary) | Microsoft Value | Application Examples | + |-----------------------|-----------|----------------------|---------------------|-----------------|----------------------------------------------------------------------| + | Microsoft Voice | CS7 | 56 | 111000 | 4,5 | Microsoft QOSTrafficTypeVoice and QOSTrafficTypeControl | + | Microsoft Audio/Video | CS5 | 40 | 101000 | 2,3 | Microsoft QOSTrafficTypeExcellentEffort and QOSTrafficTypeAudioVideo | + | Real-Time Interactive | CS4 | 32 | 100000 | | Video conferencing and Interactive gaming | + | Multimedia Streaming | AF31 | 26 | 011010 | | Streaming video and audio on demand | + | Broadcast Video | CS3 | 24 | 011000 | | Broadcast TV & live events | + | Low-Latency Data | AF21 | 18 | 010010 | | Client/server transactions Web-based ordering | + | High-Throughput Data | AF11 | 10 | 001010 | | Store and forward applications | + | Low-Priority Data | CS1 | 8 | 001000 | 1 | Any flow that has no BW assurance - also: | + | | | | | | Microsoft QOSTrafficTypeBackground | + | Standard | DF(CS0) | 0 | 000000 | 0 | Undifferentiated applications - also: | + | | | | | | Microsoft QOSTrafficTypeBestEffort | + enum: + - microsoft_voice # Microsoft QOSTrafficTypeVoice or Control + - microsoft_audio_video # Microsoft QOSTrafficTypeExcellentEffort or AudioVideo + - real_time_interactive # Video conferencing and interactive gaming + - multimedia_streaming # Streaming video or audio on demand + - broadcast_video # Broadcast TV and live events + - low_latency_data # Client/server transactions Web-based ordering + - high_throughput_data # STore and forward applications + - low_priority_data # Low-priority background traffic + - standard # Default traffic class + example: real_time_interactive + required: + - name + - status + + QosProfileName: + description: | + A unique name for identifying a specific QoS profile. + This may follow different formats depending on the service providers implementation. + Some options addresses: + - A UUID style string + - Support for predefined profile names like `QOS_E`, `QOS_S`, `QOS_M`, and `QOS_L` + - A searchable descriptive name + type: string + example: voice + minLength: 3 + maxLength: 256 + format: string + pattern: "^[a-zA-Z0-9_.-]+$" + + Rate: + description: Specification of rate + type: object + properties: + value: + description: Quantity of rate + type: integer + example: 10 + format: int32 + minimum: 0 + maximum: 1024 + unit: + $ref: "#/components/schemas/RateUnitEnum" + + Duration: + description: Specification of duration + type: object + properties: + value: + description: Quantity of duration + type: integer + example: 12 + format: int32 + minimum: 1 + unit: + $ref: "#/components/schemas/TimeUnitEnum" + + TimeUnitEnum: + description: Units of time + type: string + enum: + - Days + - Hours + - Minutes + - Seconds + - Milliseconds + - Microseconds + - Nanoseconds + + QosProfileStatusEnum: + description: | + The current status of the QoS Profile + - `ACTIVE`- QoS Profile is available to be used + - `INACTIVE`- QoS Profile is not currently available to be deployed + - `DEPRECATED`- QoS profile is actively being used in a QoD session, but can not be deployed in new QoD sessions + type: string + enum: + - ACTIVE + - INACTIVE + - DEPRECATED + + RateUnitEnum: + description: Units of rate + type: string + enum: + - bps + - kbps + - Mbps + - Gbps + - Tbps + + QosProfileDeviceRequest: + description: | + Request object for QoS Profiles for a given device + type: object + properties: + device: + $ref: "#/components/schemas/Device" + name: + $ref: "#/components/schemas/QosProfileName" + status: + $ref: '#/components/schemas/QosProfileStatusEnum' + + Device: + description: | + End-user equipment able to connect to a mobile network. Examples of devices include smartphones or IoT sensors/actuators. + + The developer can choose to provide the below specified device identifiers: + + * `ipv4Address` + * `ipv6Address` + * `phoneNumber` + NOTE1: the network operator might support only a subset of these options. The API consumer can provide multiple identifiers to be compatible across different operators. In this case the identifiers MUST belong to the same device. + NOTE2: as for this Commonalities release, we are enforcing that the networkAccessIdentifier is only part of the schema for future-proofing, and CAMARA does not currently allow its use. After the CAMARA meta-release work is concluded and the relevant issues are resolved, its use will need to be explicitly documented in the guidelines. + + type: object + properties: + phoneNumber: + $ref: "#/components/schemas/PhoneNumber" + networkAccessIdentifier: + $ref: "#/components/schemas/NetworkAccessIdentifier" + ipv4Address: + $ref: "#/components/schemas/DeviceIpv4Addr" + ipv6Address: + $ref: "#/components/schemas/DeviceIpv6Address" + minProperties: 1 + maxProperties: 4 + + NetworkAccessIdentifier: + description: A public identifier addressing a subscription in a mobile network. In 3GPP terminology, it corresponds to the GPSI formatted with the External Identifier ({Local Identifier}@{Domain Identifier}). Unlike the telephone number, the network access identifier is not subjected to portability ruling in force, and is individually managed by each operator. + type: string + example: "123456789@domain.com" + + PhoneNumber: + description: A public identifier addressing a telephone subscription. In mobile networks it corresponds to the MSISDN (Mobile Station International Subscriber Directory Number). In order to be globally unique it has to be formatted in international format, according to E.164 standard, prefixed with '+'. + type: string + pattern: '^\+[1-9][0-9]{4,14}$' + example: "+123456789" + + DeviceIpv4Addr: + type: object + description: | + The device should be identified by either the public (observed) IP address and port as seen by the application server, or the private (local) and any public (observed) IP addresses in use by the device (this information can be obtained by various means, for example from some DNS servers). + + If the allocated and observed IP addresses are the same (i.e. NAT is not in use) then the same address should be specified for both publicAddress and privateAddress. + + If NAT64 is in use, the device should be identified by its publicAddress and publicPort, or separately by its allocated IPv6 address (field ipv6Address of the Device object) + + In all cases, publicAddress must be specified, along with at least one of either privateAddress or publicPort, dependent upon which is known. In general, mobile devices cannot be identified by their public IPv4 address alone. + properties: + publicAddress: + $ref: "#/components/schemas/SingleIpv4Addr" + privateAddress: + $ref: "#/components/schemas/SingleIpv4Addr" + publicPort: + $ref: "#/components/schemas/Port" + anyOf: + - required: [publicAddress, privateAddress] + - required: [publicAddress, publicPort] + example: + { + "publicAddress": "203.0.113.0", + "publicPort": 59765 + } + + Port: + description: TCP or UDP port number + type: integer + minimum: 0 + maximum: 65535 + + SingleIpv4Addr: + description: A single IPv4 address with no subnet mask + type: string + format: ipv4 + example: "203.0.113.0" + + DeviceIpv6Address: + description: | + The device should be identified by the observed IPv6 address, or by any single IPv6 address from within the subnet allocated to the device (e.g. adding ::0 to the /64 prefix). + + The session shall apply to all IP flows between the device subnet and the specified application server, unless further restricted by the optional parameters devicePorts or applicationServerPorts. + type: string + format: ipv6 + example: 2001:db8:85a3:8d3:1319:8a2e:370:7344 + + ErrorInfo: + description: Common schema for errors + type: object + properties: + status: + type: integer + description: HTTP status code returned along with this error response + code: + type: string + description: Code given to this error + message: + type: string + description: Detailed error description + required: + - status + - code + - message + + responses: + Generic400: + description: Bad Request + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - OUT_OF_RANGE + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + GENERIC_400_OUT_OF_RANGE: + description: Out of Range. Specific Syntax Exception used when a given field has a pre-defined range or a invalid filter criteria combination is requested + value: + status: 400 + code: OUT_OF_RANGE + message: Client specified an invalid range. + + Generic401: + description: Unauthorized + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 401 + code: + enum: + - UNAUTHENTICATED + - AUTHENTICATION_REQUIRED + examples: + GENERIC_401_UNAUTHENTICATED: + description: Request cannot be authenticated + value: + status: 401 + code: UNAUTHENTICATED + message: Request not authenticated due to missing, invalid, or expired credentials. + GENERIC_401_AUTHENTICATION_REQUIRED: + description: New authentication is needed, authentication is no longer valid + value: + status: 401 + code: AUTHENTICATION_REQUIRED + message: New authentication is required. + + Generic403: + description: Forbidden + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + + Generic404: + description: Not found + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - NOT_FOUND + examples: + GENERIC_404_NOT_FOUND: + description: Resource is not found + value: + status: 404 + code: NOT_FOUND + message: The specified resource is not found. + + GenericDevice404: + description: Not found + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - NOT_FOUND + - IDENTIFIER_NOT_FOUND + examples: + GENERIC_404_NOT_FOUND: + description: Resource is not found + value: + status: 404 + code: NOT_FOUND + message: The specified resource is not found. + GENERIC_404_DEVICE_NOT_FOUND: + description: Device identifier not found + value: + status: 404 + code: IDENTIFIER_NOT_FOUND + message: Device identifier not found. + + Generic422: + description: Unprocessable Content + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - IDENTIFIER_MISMATCH + - SERVICE_NOT_APPLICABLE + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + examples: + GENERIC_422_IDENTIFIER_MISMATCH: + description: Inconsistency between identifiers not pointing to the same device + value: + status: 422 + code: IDENTIFIER_MISMATCH + message: Provided identifiers are not consistent. + GENERIC_422_SERVICE_NOT_APPLICABLE: + description: Service not applicable for the provided identifier + value: + status: 422 + code: SERVICE_NOT_APPLICABLE + message: The service is not available for the provided identifier. + GENERIC_422_UNSUPPORTED_IDENTIFIER: + description: None of the provided identifiers is supported by the implementation + value: + status: 422 + code: UNSUPPORTED_IDENTIFIER + message: The identifier provided is not supported. + GENERIC_422_UNNECESSARY_IDENTIFIER: + description: An explicit identifier is provided when a device or phone number has already been identified from the access token + value: + status: 422 + code: UNNECESSARY_IDENTIFIER + message: The device is already identified by the access token. + + Generic429: + description: Too Many Requests + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 429 + code: + enum: + - QUOTA_EXCEEDED + - TOO_MANY_REQUESTS + examples: + GENERIC_429_QUOTA_EXCEEDED: + description: Request is rejected due to exceeding a business quota limit + value: + status: 429 + code: QUOTA_EXCEEDED + message: Out of resource quota. + GENERIC_429_TOO_MANY_REQUESTS: + description: Access to the API has been temporarily blocked due to rate or spike arrest limits being reached + value: + status: 429 + code: TOO_MANY_REQUESTS + message: Rate limit reached. \ No newline at end of file diff --git a/telco/camaraproject.org/quality-on-demand/quality-on-demand-1.0.0-openapi-metadata.yaml b/telco/camaraproject.org/quality-on-demand/quality-on-demand-1.0.0-openapi-metadata.yaml new file mode 100644 index 0000000..f687914 --- /dev/null +++ b/telco/camaraproject.org/quality-on-demand/quality-on-demand-1.0.0-openapi-metadata.yaml @@ -0,0 +1,374 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: Quality-On-Demand + version: wip +operations: + POST /sessions/{sessionId}/extend: + Session extension for gaming: + request: + headers: + accept: application/json + parameters: + sessionId: 4f2c1843-1111-2222-3333-8bc29e2b5c43 + body: "{\"requestedAdditionalDuration\": 600}" + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: "{\"sessionId\":\"4f2c1843-1111-2222-3333-8bc29e2b5c43\",\"duration\"\ + :36600,\"startedAt\":\"2023-01-15T10:00:00Z\",\"expiresAt\":\"2023-01-15T20:10:00Z\"\ + ,\"qosStatus\":\"AVAILABLE\"}" + Extending remote work session: + request: + headers: + accept: application/json + parameters: + sessionId: a987b654-1111-2222-3333-20d1602f9a60 + body: "{\"requestedAdditionalDuration\": 1200}" + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: "{\"sessionId\":\"a987b654-1111-2222-3333-20d1602f9a60\",\"duration\"\ + :37200,\"startedAt\":\"2023-03-10T08:00:00Z\",\"expiresAt\":\"2023-03-10T18:20:00Z\"\ + ,\"qosStatus\":\"AVAILABLE\"}" + Extending lecture streaming session: + request: + headers: + accept: application/json + parameters: + sessionId: 123e4567-1111-2222-3333-e89b12d3f4b6 + body: "{\"requestedAdditionalDuration\": 1800}" + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: "{\"sessionId\":\"123e4567-1111-2222-3333-e89b12d3f4b6\",\"duration\"\ + :45000,\"startedAt\":\"2023-05-20T09:00:00Z\",\"expiresAt\":\"2023-05-20T21:30:00Z\"\ + ,\"qosStatus\":\"AVAILABLE\"}" + GET /sessions/{sessionId}: + Session Information Request for Gaming App: + request: + headers: + accept: application/json + parameters: + sessionId: 12f87b48-6479-4fe9-901a-7c67f0491a87 + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "sessionId" : "12f87b48-6479-4fe9-901a-7c67f0491a87", + "duration" : 3600, + "startedAt" : "2023-09-21T10:00:00Z", + "expiresAt" : "2023-09-21T11:00:00Z", + "qosStatus" : "AVAILABLE", + "device" : { + "ipv4Address" : { + "publicAddress" : "192.0.2.1", + "privateAddress" : "198.51.100.1" + } + }, + "applicationServer" : { + "ipv4Address" : "203.0.113.5" + }, + "qosProfile" : "QOS_E" + } + Session Detail for IoT Device: + request: + headers: + accept: application/json + parameters: + sessionId: e3a9e464-8b2e-4237-b2c2-edf7b64a7a63 + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "sessionId" : "e3a9e464-8b2e-4237-b2c2-edf7b64a7a63", + "duration" : 7200, + "startedAt" : "2023-09-22T15:00:00Z", + "expiresAt" : "2023-09-22T17:00:00Z", + "qosStatus" : "AVAILABLE", + "device" : { + "ipv6Address" : "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + }, + "applicationServer" : { + "ipv6Address" : "2001:0db8:85a3:0000:0000:abcd:0370:7334" + }, + "qosProfile" : "QOS_S" + } + Expired Session Query: + request: + headers: + accept: application/json + parameters: + sessionId: 99887766-55cc-4477-aa88-99ccbb447766 + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + { + "sessionId" : "99887766-55cc-4477-aa88-99ccbb447766", + "duration" : 1800, + "startedAt" : "2023-08-15T09:30:00Z", + "expiresAt" : "2023-08-15T10:00:00Z", + "qosStatus" : "UNAVAILABLE", + "statusInfo" : "DURATION_EXPIRED", + "device" : { + "phoneNumber" : "+12345678901" + }, + "applicationServer" : { + "ipv4Address" : "198.51.100.55" + }, + "qosProfile" : "QOS_L" + } + POST /sessions: + Creating a session for gaming app: + request: + headers: + accept: application/json + body: | + { + "device": { + "ipv4Address": { + "publicAddress": "203.0.113.5", + "publicPort": 8080 + } + }, + "applicationServer": { + "ipv4Address": "198.51.100.14/32" + }, + "qosProfile": "QOS_GAMING_HIGH", + "duration": 7200 + } + response: + headers: + content-type: application/json + status: 201 + mediaType: application/json + body: | + { + "sessionId": "2f5ae96c-db82-46ed-8b8e-d3c8cbf9b608", + "duration": 7200, + "qosStatus": "REQUESTED", + "applicationServer": { + "ipv4Address": "198.51.100.14/32" + } + } + Creating a session for video conferencing: + request: + headers: + accept: application/json + body: | + { + "device": { + "ipv4Address": { + "publicAddress": "203.0.113.7", + "privateAddress": "192.168.1.101" + } + }, + "applicationServer": { + "ipv4Address": "203.0.113.8/32" + }, + "qosProfile": "QOS_VIDEO_CONF", + "duration": 3600, + "sink": "https://yourcallbackurl.example.com/notifications" + } + response: + headers: + content-type: application/json + status: 201 + mediaType: application/json + body: | + { + "sessionId": "5df8b6de-abf3-4b03-bd4b-f7e2f8c578b9", + "duration": 3600, + "qosStatus": "AVAILABLE", + "applicationServer": { + "ipv4Address": "203.0.113.8/32" + }, + "startedAt": "2023-03-16T10:00:00Z", + "expiresAt": "2023-03-16T11:00:00Z" + } + Creating a session for IoT device data upload: + request: + headers: + accept: application/json + body: | + { + "device": { + "ipv6Address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + }, + "applicationServer": { + "ipv6Address": "2001:0db8:85a3:0000:0000:8a3b:0371:7335/64" + }, + "qosProfile": "QOS_IOT_LOW_LATENCY", + "duration": 300, + "sink": "https://yourcallbackurl.example.com/iot-notifications", + "sinkCredential": { + "credentialType": "ACCESSTOKEN", + "credentialValue": "token123456789" + } + } + response: + headers: + content-type: application/json + status: 201 + mediaType: application/json + body: | + { + "sessionId": "8fbdd4a1-4140-4c1e-bf67-877afc2a9d09", + "duration": 300, + "qosStatus": "REQUESTED", + "applicationServer": { + "ipv6Address": "2001:0db8:85a3:0000:0000:8a3b:0371:7335/64" + } + } + POST /retrieve-sessions: + Retrieve sessions for a device with IPv4: + request: + headers: + accept: application/json + body: | + { + "device": { + "ipv4Address": { + "publicAddress": "192.0.2.1", + "privateAddress": "10.0.0.1" + } + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: | + [ + { + "sessionId": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6", + "applicationServer": { + "ipv4Address": "203.0.113.1" + }, + "qosProfile": "QOS_E", + "qosStatus": "AVAILABLE", + "duration": 3600, + "startedAt": "2023-01-01T12:00:00Z", + "expiresAt": "2023-01-01T13:00:00Z" + } + ] + Retrieve sessions for a device with IPv6: + request: + headers: + accept: application/json + body: | + { + "device": { + "ipv6Address": "2001:db8::1" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: | + [ + { + "sessionId": "e4e4b37e-8c70-11eb-8dcd-0242ac130003", + "applicationServer": { + "ipv6Address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334" + }, + "qosProfile": "QOS_S", + "qosStatus": "AVAILABLE", + "duration": 7200, + "startedAt": "2023-02-01T14:00:00Z", + "expiresAt": "2023-02-01T16:00:00Z" + } + ] + Retrieve sessions for a device with phone number: + request: + headers: + accept: application/json + body: | + { + "device": { + "phoneNumber": "+1234567890" + } + } + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: | + [ + { + "sessionId": "a3f1a346-71e2-11ec-90d6-0242ac120003", + "applicationServer": { + "ipv4Address": "198.51.100.2" + }, + "qosProfile": "QOS_M", + "qosStatus": "AVAILABLE", + "duration": 1800, + "startedAt": "2023-03-01T09:00:00Z", + "expiresAt": "2023-03-01T09:30:00Z" + } + ] + DELETE /sessions/{sessionId}: + Successfully Deleted QoS Session: + request: + headers: + accept: application/json + parameters: + sessionId: 123e4567-e89b-12d3-a456-426655440000 + response: + headers: + content-type: application/json + status: 204 + mediaType: application/json + QoS Session Not Found: + request: + headers: + accept: application/json + parameters: + sessionId: 987e6543-e21c-12d3-a456-426655440000 + response: + headers: + content-type: application/json + status: 404 + mediaType: application/json + body: |- + { + "status" : 404, + "code" : "NOT_FOUND", + "message" : "Session ID does not exist." + } + Unauthorized Access to Delete QoS Session: + request: + headers: + accept: application/json + parameters: + sessionId: bc9e457b-a813-49b6-8d25-35f7d5b76bac + response: + headers: + content-type: application/json + status: 401 + mediaType: application/json + body: |- + { + "status" : 401, + "code" : "UNAUTHENTICATED", + "message" : "You must authenticate to access this resource." + } diff --git a/telco/camaraproject.org/sim-swap/sim-swap-2.0.0-openapi-metadata.yaml b/telco/camaraproject.org/sim-swap/sim-swap-2.0.0-openapi-metadata.yaml new file mode 100644 index 0000000..5a67e1f --- /dev/null +++ b/telco/camaraproject.org/sim-swap/sim-swap-2.0.0-openapi-metadata.yaml @@ -0,0 +1,238 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: SIM Swap + version: 1.0.0 +operations: + 'POST /retrieve-date': + "+937018305578": + request: + headers: + accept: application/json + body: + phoneNumber: "+937018305578" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-07-03T14:27:08.312+02:00" + "+2449238626609": + request: + headers: + accept: application/json + body: + phoneNumber: "+2449238626609" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-08-03T14:27:08.312+02:00" + "+2449235141894": + request: + headers: + accept: application/json + body: + phoneNumber: "+2449235141894" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-09-03T14:27:08.312+02:00" + "+614129559000": + request: + headers: + accept: application/json + body: + phoneNumber: "+614129559000" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-10-03T14:27:08.312+02:00" + "+8801817421995": + request: + headers: + accept: application/json + body: + phoneNumber: "+8801817421995" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-11-03T14:27:08.312+02:00" + "+324701053815": + request: + headers: + accept: application/json + body: + phoneNumber: "+324701053815" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-12-03T14:27:08.312+02:00" + "+324703318377": + request: + headers: + accept: application/json + body: + phoneNumber: "+324703318377" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-01-03T14:27:08.312+02:00" + "+551112345678": + request: + headers: + accept: application/json + body: + phoneNumber: "+551112345678" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-02-03T14:27:08.312+02:00" + "+6737124000017": + request: + headers: + accept: application/json + body: + phoneNumber: "+6737124000017" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-03-03T14:27:08.312+02:00" + "+61212345678": + request: + headers: + accept: application/json + body: + phoneNumber: "+61212345678" + response: + mediaType: application/json + status: "200" + body: + latestSimChange: "2023-04-03T14:27:08.312+02:00" + 'POST /check': + "+937018305578": + request: + headers: + accept: application/json + body: + phoneNumber: "+937018305578" + maxAge: 240 + response: + mediaType: application/json + status: "200" + body: + swapped: true + "+2449238626609": + request: + headers: + accept: application/json + body: + phoneNumber: "+2449238626609" + maxAge: 480 + response: + mediaType: application/json + status: "200" + body: + swapped: false + "+2449235141894": + request: + headers: + accept: application/json + body: + phoneNumber: "+2449235141894" + maxAge: 360 + response: + mediaType: application/json + status: "200" + body: + swapped: true + "+614129559000": + request: + headers: + accept: application/json + body: + phoneNumber: "+614129559000" + maxAge: 600 + response: + mediaType: application/json + status: "200" + body: + swapped: false + "+8801817421995": + request: + headers: + accept: application/json + body: + phoneNumber: "+8801817421995" + maxAge: 720 + response: + mediaType: application/json + status: "200" + body: + swapped: true + "+324701053815": + request: + headers: + accept: application/json + body: + phoneNumber: "+324701053815" + maxAge: 840 + response: + mediaType: application/json + status: "200" + body: + swapped: false + "+324703318377": + request: + headers: + accept: application/json + body: + phoneNumber: "+324703318377" + maxAge: 960 + response: + mediaType: application/json + status: "200" + body: + swapped: true + "+551112345678": + request: + headers: + accept: application/json + body: + phoneNumber: "+551112345678" + maxAge: 1080 + response: + mediaType: application/json + status: "200" + body: + swapped: false + "+6737124000017": + request: + headers: + accept: application/json + body: + phoneNumber: "+6737124000017" + maxAge: 1200 + response: + mediaType: application/json + status: "200" + body: + swapped: true + "+61212345678": + request: + headers: + accept: application/json + body: + phoneNumber: "+61212345678" + maxAge: 1320 + response: + mediaType: application/json + status: "200" + body: + swapped: false diff --git a/telco/camaraproject.org/sim-swap/sim-swap-v2.0.0.yaml b/telco/camaraproject.org/sim-swap/sim-swap-v2.0.0.yaml index da67ac5..ec594ef 100644 --- a/telco/camaraproject.org/sim-swap/sim-swap-v2.0.0.yaml +++ b/telco/camaraproject.org/sim-swap/sim-swap-v2.0.0.yaml @@ -37,6 +37,8 @@ info: - POST check: Checks if SIM swap has been performed during a past period (defined in the request with 'maxAge' attribute) for a given phone number. + NOTE: The phone numbers used for the mocks are randomly generated from https://dialaxy.com/lookups/phone-number-generator/ + # Authorization and authentication The "Camara Security and Interoperability Profile" provides details of how an API consumer requests an access token. Please refer to Identity and Consent Management (https://github.com/camaraproject/IdentityAndConsentManagement/) for the released version of the profile. diff --git a/telco/camaraproject.org/simple-edge-discovery/simple-edge-discovery-1.0.0-openapi-metadata.yaml b/telco/camaraproject.org/simple-edge-discovery/simple-edge-discovery-1.0.0-openapi-metadata.yaml new file mode 100644 index 0000000..8a38a90 --- /dev/null +++ b/telco/camaraproject.org/simple-edge-discovery/simple-edge-discovery-1.0.0-openapi-metadata.yaml @@ -0,0 +1,150 @@ +apiVersion: mocks.microcks.io/v1alpha1 +kind: APIExamples +metadata: + name: Simple Edge Discovery + version: 1.0.0 +operations: + GET /edge-cloud-zones: + Device with IPv4-Address: + request: + headers: + accept: application/json + IPv4-Address: 84.125.93.10 + parameters: + filter: closest + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: "[{\"edgeCloudZoneId\":\"4gt555-6457-7890-d4he-1dc79f44gb66\",\"edgeCloudZoneName\"\ + :\"example zone name\",\"edgeCloudProvider\":\"example zone provider\"}]" + Device with IPv6-Address: + request: + headers: + IPv6-Address: 2001:0db8:85a3:0000:0000:8a2e:0370:7334 + accept: application/json + parameters: + filter: closest + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: "[{\"edgeCloudZoneId\":\"4gt555-6457-7890-d4he-1dc79f44gb66\",\"edgeCloudZoneName\"\ + :\"example zone name\",\"edgeCloudProvider\":\"example zone provider\"}]" + Device with Phone-Number: + request: + headers: + accept: application/json + Phone-Number: +441234567890 + parameters: + filter: closest + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: "[{\"edgeCloudZoneId\":\"4gt555-6457-7890-d4he-1dc79f44gb66\",\"edgeCloudZoneName\"\ + :\"example zone name\",\"edgeCloudProvider\":\"example zone provider\"}]" + Edge Cloud Zone from IPv4-Address: + request: + headers: + accept: application/json + IPv4-Address: 84.125.93.10 + parameters: + filter: closest + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + [ { + "edgeCloudZoneId" : "4gt555-6457-7890-d4he-1dc79f44gb66", + "edgeCloudZoneName" : "example zone name", + "edgeCloudProvider" : "example zone provider" + } ] + Edge Cloud Zone from IPv6-Address: + request: + headers: + IPv6-Address: 2001:0db8:85a3:0000:0000:8a2e:0370:7334 + accept: application/json + parameters: + filter: closest + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + [ { + "edgeCloudZoneId" : "4gt555-6457-7890-d4he-1dc79f44gb66", + "edgeCloudZoneName" : "example zone name", + "edgeCloudProvider" : "example zone provider" + } ] + Edge Cloud Zone from Phone-Number: + request: + headers: + accept: application/json + Phone-Number: 441234567890 + parameters: + filter: closest + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: |- + [ { + "edgeCloudZoneId" : "4gt555-6457-7890-d4he-1dc79f44gb66", + "edgeCloudZoneName" : "example zone name", + "edgeCloudProvider" : "example zone provider" + } ] + Request with IPv4 Address: + request: + headers: + IPv4-Address: 84.125.93.10 + accept: application/json + parameters: + filter: closest + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: "[{\"edgeCloudZoneId\": \"4gt555-6457-7890-d4he-1dc79f44gb66\", \"edgeCloudZoneName\"\ + : \"example zone name\", \"edgeCloudProvider\": \"example zone provider\"\ + }]" + Request with Phone Number: + request: + headers: + Phone-Number: 441234567890 + accept: application/json + parameters: + filter: closest + response: + headers: + content-type: application/json + status: 200 + mediaType: application/json + body: "[{\"edgeCloudZoneId\": \"4gt555-6457-7890-d4he-1dc79f44gb66\", \"edgeCloudZoneName\"\ + : \"example zone name\", \"edgeCloudProvider\": \"example zone provider\"\ + }]" + Request without device identifier: + request: + headers: + accept: application/json + parameters: + filter: closest + response: + headers: + content-type: application/json + status: 422 + mediaType: application/json + body: |- + { + "code" : "UNIDENTIFIABLE_DEVICE", + "status" : 422, + "message" : "Cannot identify the device. Please provide a valid device identifier in the request." + } diff --git a/telco/camaraproject.org/simple-edge-discovery/simple-edge-discovery-1.0.0-openapi.yaml b/telco/camaraproject.org/simple-edge-discovery/simple-edge-discovery-1.0.0-openapi.yaml new file mode 100644 index 0000000..27a0b17 --- /dev/null +++ b/telco/camaraproject.org/simple-edge-discovery/simple-edge-discovery-1.0.0-openapi.yaml @@ -0,0 +1,746 @@ +--- +openapi: 3.0.3 +info: + title: Simple Edge Discovery + version: 1.0.0 + x-camara-commonalities: 0.4.0 + description: | + # Find the closest Edge Cloud Zone + --- + # Summary + + The Simple Edge Discovery API returns the name of the closest operator Edge + Cloud Zone to a particular user device. + + # Purpose + Network operators may host multiple Edge Cloud Zones in a + given territory. Connecting your application to a server on the closest + Edge Cloud Zone means packets travel the shortest distance between + endpoints, typically resulting in the lowest round-trip latency. Note, the + physical (GPS) location of a user device is not a reliable way to determine + the closest Edge Cloud Zone, due to the way operator networks are routed - + so the operator will calculate the Edge Cloud Zone with the + _shortest network path_to the network-attached device identified in the API + request. + + Once you have the name of the closest Edge Cloud Zone to the user device, + you may: + + * connect the application client on the user device to your application + server instance on that Edge Cloud Zone. Note: the address of that server + instance is not part of the API response, but should be known in advance. + * or, if you have no instance on that Edge Cloud Zone, you may wish to + deploy one there. + + Note: the provider of the Edge Cloud Zone may be an operator, or a cloud + provider working in partnership with the operator. + + # Usage + + The API may be called either by an application client hosted on a device + attached to the operator network (i.e. phone, tablet), or by a server. + + There is a single API endpoint: `/edge-cloud-zones?filter=closest`. To call + this endpoint, the API consumer must first obtain a valid OAuth2 token from + the token endpoint, and pass it as an `Authorization` header in the API + request. + + # Identifying the device + + The API returns the closest Edge Cloud Zone to a given device, so that + device needs to be identifiable by the network. This can be achieved either + by passing a device identifier in the request header, or, from the 3-legged + access token where implemented by the operator. + + ## Passing a device identifier in the request header + + * If you call the API from a server, you must explicitly pass one or + more device identifiers in the HTTP request header: + * `IPv4-Address` or `IPv6-Address`. This is the public IP address of the + user device: this + can be obtained by an application hosted on that device calling a + public IP address API (e.g. GET https://api.ipify.org?format=json) + * If you provide an `IPv4-Address` or `IPv6-Address`: for certain + operators you may be required to also provide a `Public-port` header. + * `Phone-Number` . The international E.164 format (starting with country + code), e.g. +4407123123456 + * `Network-Access-Identifier` (where available from the API host operator) + + * If you call the API from a device attached to the operator network, then + you can attempt the request without passing device identifier(s) parameters + in the request header. If that returns a 422 `UNIDENTIFIABLE_DEVICE` + error then retry the request but this time include a device identifier. + + NOTE1: the network operator might support only a subset of these options. + The API invoker can provide multiple identifiers to be compatible across + different network operators. In this case the identifiers MUST belong to the + same device. + + NOTE2: for the Commonalities release v0.4, we are enforcing that the + `networkAccessIdentifier` is only part of the schema for future-proofing, and + CAMARA does not currently allow its use. After the CAMARA meta-release work + is concluded and the relevant issues are resolved, its use will need to be + explicitly documented in the guidelines. + + ### Example requests: + + Examples for all API clients: + ``` + GET /edge-cloud-zones?filter=closest HTTP/1.1 + Host: example.com + Accept: application/json + IPv4-Address: 84.125.93.10 + + GET /edge-cloud-zones?filter=closest HTTP/1.1 + Host: example.com + Accept: application/json + Phone-Number: +441234567890 + ``` + Example where the network operator requires the public port to be passed: + ``` + GET /edge-cloud-zones?filter=closest HTTP/1.1 + Host: example.com + Accept: application/json + IPv4-Address: 84.125.93.10 + Public-port: 1234 + ``` + + Example where API client is on a network-attached device: + ``` + GET /edge-cloud-zones?filter=closest HTTP/1.1 + Host: example.com + Accept: application/json + ``` + + ## Identifying a device from the access token + + This specification defines the `device` identifying headers as optional in + API requests, specifically in cases where the API is accessed using a + 3-legged access token and the device can be uniquely identified by the token. + This approach simplifies API usage for API consumers by relying on the device + information associated with the access token used to invoke the API. + + ### Handling of device information: + + #### Optional device identifying headers for 3-legged tokens: + + - When using a 3-legged access token, the device associated with the access + token must be considered as the device for the API request. This means that + a device identifying header is not required in the request, and if + included it must identify the same device, therefore **it is recommended + NOT to include it in these scenarios** to simplify the API usage and avoid + additional validations. + + #### Validation mechanism: + + - The server will extract the device identification from the access token, if + available. + - If the API request additionally includes a `device` identifying header + when using a 3-legged access token, the API will validate that the device + identifier provided matches the one associated with the access token. + - If there is a mismatch, the API will respond with a + 403 `INVALID_TOKEN_CONTEXT` error, indicating that the device information + in the request does not match the token. + + #### Error handling for unidentifiable devices: + + - If the `device` identifying header is not included in the request and the + device information cannot be derived from the 3-legged access token, nor + inferred by the operator if the request is made directly from the client, + the server will return a 422 `UNIDENTIFIABLE_DEVICE` error. + + #### Restrictions for tokens without an associated authenticated identifier: + + - For scenarios which do not have a single device identifier associated to + the token during the authentication flow, e.g. 2-legged access tokens, a + `device` identifying header MUST be provided in the API request. This + ensures that the device identification is explicit and valid for each API + call made with these tokens. + + # Responses + + ## Success + + A JSON object is returned containing an array with a single member object. + This contains identifiers for the closest Edge Cloud Zone. The HTTP status + code will be`200 OK`. An example response: + + ``` + [ + { + "edgeCloudZoneId": "4gt555-6457-7890-d4he-1dc79f44gb66", + "edgeCloudZoneName": "example zone name", + "edgeCloudProvider": "example zone provider" + } + ] + ``` + * `edgeCloudZoneId` is a UUID for the Edge Cloud Zone. + * `edgeCloudZoneName` is the common name of the closest Edge Cloud Zone to + the user device. + * `edgeCloudProvider` is the name of the operator or cloud provider of + the Edge Cloud Zone. + + ## Errors + + If the authentication token is not valid, a `401 UNAUTHENTICATED` error is + returned. + + If the mobile subscription parameters contain a formatting error, a `400 + INVALID_ARGUMENT` error is returned. + + If the mobile subscription cannot be identified from the provided + parameters, a `404 NOT_FOUND` error is returned. + + Any more general service failures will result in an error in the `5xx`range + with an explanation. + + # Notes for Simple Edge Discovery API publishers + + If an `IPv4-Address` or `IPv6-Address` header parameter is provided then the + operator should + assume the request is coming from a developer's server rather than a device + attached to the network. In which case the developer server is expected to + have been provided with the device public IP address (e.g. by the + application client on that device signalling it back to the server). + + If neither an `IPv4-Address`/`IPv6-Address` parameter, nor any other device + identifier, is + provided in the API request header then the operator should assume the + request is from a device attached to their network, and attempt to use the + public IP source address to determine which packet gateway issued it (and + hence the closest edge to that gateway). + + If no `IPv4-Address`/`IPv6-Address` header parameter is provided, but another + device + identifier(s) is provided, then the operator should assume the request is + coming from a device attached to their network and should make use of one + or both of the public IP source address (from the IP packet header) and the + device identifier(s) provided in the HTTPS request header. + + Should your implementation require the `Port` value to be passed in addition + to the `IP-Address`, please make that explicit in the documentation, and + utilise the `GENERIC_400_MISSING_PORT` error if the `Port` header is omitted. + + # Authorization and authentication + + The "Camara Security and Interoperability Profile" provides details on how a + client requests an access token. Please refer to Identify and Consent + Management (https://github.com/camaraproject/IdentityAndConsentManagement/) + for the released version of the Profile. + + Which specific authorization flows are to be used will be determined during + onboarding process, happening between the API Client and the Telco Operator + exposing the API, taking into account the declared purpose for accessing + the API, while also being subject to the prevailing legal framework + dictated by local legislation. + + It is important to remark that in cases where personal user data is + processed by the API, and users can exercise their rights through + mechanisms such as opt-in and/or opt-out, the use of 3-legged access tokens + becomes mandatory. This measure ensures that the API remains in strict + compliance with user privacy preferences and regulatory obligations, + upholding the principles of transparency and user-centric data control. + + # Further info and support + + --- + + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + +externalDocs: + description: Product documentation at CAMARA. + url: https://github.com/camaraproject/EdgeCloud + +servers: + - url: "{apiRoot}/simple-edge-discovery/v1" + variables: + apiRoot: + default: https://localhost:9091 + description: | + API root, defined by the service provider, e.g. + `api.example.com` or `api.example.com/somepath` + +tags: + - name: Discovery + description: | + Find the closest Edge Cloud Zone to the user device. + +paths: + /edge-cloud-zones: + get: + security: + - openId: + - simple-edge-discovery:edge-cloud-zones:read + operationId: readClosestEdgeCloudZone + parameters: + - name: filter + in: query + required: true + description: | + Filter the Edge Cloud Zones according to the parameter value. + For this API the only supported value is `closest`. + schema: + type: string + enum: + - closest + + - name: IPv4-Address + in: header + required: false + description: The public IPv4 address allocated to the device by the network operator. + example: "84.125.93.10" + schema: + $ref: "#/components/schemas/SingleIpv4Addr" + + - name: Public-port + in: header + required: false + description: The public TCP or UDP port allocated to the device by the network operator. + example: 123 + schema: + $ref: "#/components/schemas/Port" + + - name: IPv6-Address + in: header + required: false + description: The public IPv6 address allocated to the device by the network operator. + example: "2001:db8:85a3:8d3:1319:8a2e:370:7348" + schema: + $ref: "#/components/schemas/DeviceIpv6Address" + + - name: Network-Access-Identifier + in: header + required: false + description: | + 3GPP network access identifier for the subscription + being used by the device. + schema: + $ref: "#/components/schemas/NetworkAccessIdentifier" + + - name: Phone-Number + in: header + example: "+441234567890" + required: false + description: | + MSISDN in E.164 format (starting with country code) of + the mobile subscription being used by the device. Optionally + prefixed with '+'. + schema: + $ref: "#/components/schemas/PhoneNumber" + + - name: x-correlator + in: header + required: false + description: | + When the API Consumer includes the "x-correlator" header in the + request, the API provider must include it in the response with + the same value that was used in the request. Otherwise, it is + optional to include the "x-correlator" header in the response with + any valid value. Recommendation is to use UUID for values. + schema: + type: string + + responses: + "200": + description: | + Successful response, returning the closest Edge Cloud + Zone to the user device identified in the request header. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: "#/components/schemas/EdgeCloudZones" + "400": + description: | + Client eror - the required querystring was not provided + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + InvalidQuerystring: + summary: Invalid querystring + description: The 'filter' querystring parameter is + missing or does not have a value of 'closest' + value: + status: 400 + code: INVALID_QUERYSTRING + message: "Querystring must be provided: filter=closest" + "401": + $ref: "#/components/responses/Generic401" + "403": + $ref: "#/components/responses/Generic403" + "404": + $ref: "#/components/responses/Generic404" + "406": + $ref: "#/components/responses/Generic406" + "422": + $ref: "#/components/responses/Generic422" + "429": + $ref: "#/components/responses/Generic429" + "500": + $ref: "#/components/responses/Generic500" + "501": + $ref: "#/components/responses/Generic501" + "502": + $ref: "#/components/responses/Generic502" + "503": + $ref: "#/components/responses/Generic503" + "504": + $ref: "#/components/responses/Generic504" + + tags: + - Discovery + summary: | + Returns the name of the Edge Cloud Zone closest to user device + identified in the request. + description: | + On receiving this request, the network will return the name + of the Edge Cloud Zone with the shortest network path to the end user + device identified in the request. + +components: + securitySchemes: + openId: + description: OpenID Provider Configuration Information. + type: openIdConnect + openIdConnectUrl: .well-known/openid-configuration + + headers: + x-correlator: + description: | + When the API Consumer includes the "x-correlator" header in the request, + the API provider must include it in the response with the same value t + hat was used in the request. Otherwise, it is optional to include the + "x-correlator" header in the response with any valid value. + Recommendation is to use UUID for values. + required: false + schema: + type: string + + schemas: + EdgeCloudZones: + type: array + items: + $ref: "#/components/schemas/EdgeCloudZone" + minItems: 1 + description: | + A collection of Edge Cloud Zones. For this Simple Edge + Discovery API the collection will have at most one member (the closest + Edge Cloud Zone to the user device indicated in the request). + additionalProperties: false + + EdgeCloudZone: + type: object + description: | + An Edge Cloud Zone, uniquely identified by a combination + of the value of the Edge Resource Name object and the value of the + Provider object (the name of the cloud provider or operator hosting that + edge cloud zone). + properties: + edgeCloudZoneId: + $ref: "#/components/schemas/EdgeCloudZoneId" + edgeCloudZoneName: + $ref: "#/components/schemas/EdgeCloudZoneName" + edgeCloudProvider: + $ref: "#/components/schemas/EdgeCloudProvider" + + EdgeCloudZoneId: + description: | + Operator-issued UUID for the Edge Cloud Zone. + type: string + format: uuid + additionalProperties: false + + EdgeCloudZoneName: + description: | + Edge Cloud Zone Name - the common name for the Edge Cloud Zone. + type: string + additionalProperties: false + + EdgeCloudProvider: + description: | + The company name of the Edge Cloud Zone provider. + type: string + + ErrorInfo: + type: object + description: Error information + required: + - message + - status + - code + properties: + message: + type: string + description: A human readable description of what the event represents + status: + type: integer + description: HTTP response status code + code: + type: string + description: Friendly Code to describe the error + + PhoneNumber: + description: A public identifier addressing a telephone subscription. In + mobile networks it corresponds to the MSISDN (Mobile Station + International Subscriber Directory Number). In order to be globally + unique it has to be formatted in international format, according to + E.164 standard, prefixed with '+'. + type: string + pattern: '^\+[1-9][0-9]{4,14}$' + example: "+123456789" + + NetworkAccessIdentifier: + description: A public identifier addressing a subscription in a mobile + network. In 3GPP terminology, it corresponds to the GPSI formatted with + the External Identifier ({Local Identifier}@{Domain Identifier}). + Unlike the telephone number, the network access identifier is not + subjected to portability ruling in force, and is individually managed + by each operator. + type: string + example: "123456789@domain.com" + + SingleIpv4Addr: + description: A single IPv4 address with no subnet mask + type: string + format: ipv4 + example: "84.125.93.10" + + DeviceIpv6Address: + description: The device should be identified by the observed IPv6 + address, or by any single IPv6 address from within the subnet allocated + to the device (e.g.adding ::0 to the /64 prefix). + type: string + format: ipv6 + example: "2001:db8:85a3:8d3:1319:8a2e:370:7344" + + Port: + description: TCP or UDP port number + type: integer + minimum: 0 + maximum: 65535 + + responses: + Generic401: + description: Unauthorized + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_401_UNAUTHENTICATED: + description: Request cannot be authenticated + value: + status: 401 + code: UNAUTHENTICATED + message: Request not authenticated due to missing, invalid, or expired credentials. + GENERIC_401_AUTHENTICATION_REQUIRED: + description: New authentication is needed, authentication is no longer valid + value: + status: 401 + code: AUTHENTICATION_REQUIRED + message: New authentication is required. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic403: + description: Forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + GENERIC_403_INVALID_TOKEN_CONTEXT:: + description: Reflect some inconsistency between information in some field of the API and the related OAuth2 Token + value: + status: 403 + code: INVALID_TOKEN_CONTEXT + message: "{{field}} is not consistent with access token." + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic404: + description: Not found + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_404_NOT_FOUND: + description: Resource is not found + value: + status: 404 + code: NOT_FOUND + message: The specified resource is not found. + GENERIC_404_DEVICE_NOT_FOUND: + description: Device identifier not found + value: + status: 404 + code: DEVICE_NOT_FOUND + message: Device identifier not found. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic406: + description: Not Acceptable + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_406_NOT_ACCEPTABLE: + description: | + API Server does not accept the media type (`Accept-*` header) indicated by API client + value: + status: 406 + code: NOT_ACCEPTABLE + message: | + The server cannot produce a response matching the content requested by the client + through `Accept-*` headers. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic422: + description: Unprocessable Content + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_422_DEVICE_IDENTIFIERS_MISMATCH: + description: Inconsistency between device identifiers not pointing to the same device + value: + status: 422 + code: DEVICE_IDENTIFIERS_MISMATCH + message: Provided device identifiers are not consistent. + GENERIC_422_DEVICE_NOT_APPLICABLE: + description: Service is not available for the provided device + value: + status: 422 + code: DEVICE_NOT_APPLICABLE + message: The Service is not available for the provided device. + GENERIC_422_UNIDENTIFIABLE_DEVICE: + description: The device identifier is not included in the request and the device information cannot be derived from the 3-legged access token + value: + status: 422 + code: UNIDENTIFIABLE_DEVICE + message: The device cannot be identified. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic429: + description: Too Many Requests + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_429_QUOTA_EXCEEDED: + description: Request is rejected due to exceeding a business quota limit + value: + status: 429 + code: QUOTA_EXCEEDED + message: Either out of resource quota or reaching rate limiting. + GENERIC_429_TOO_MANY_REQUESTS: + description: API Server request limit is overpassed + value: + status: 429 + code: TOO_MANY_REQUESTS + message: Either out of resource quota or reaching rate limiting. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic500: + description: Internal Server Error + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_500_INTERNAL: + description: Problem in Server side. Regular Server Exception + value: + status: 500 + code: INTERNAL + message: Unknown server error. Typically a server bug. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic501: + description: Not Implemented + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_501_NOT_IMPLEMENTED: + description: Service not implemented. The use of this code should be avoided as far as possible to get the objective to reach aligned implementations + value: + status: 501 + code: NOT_IMPLEMENTED + message: This functionality is not implemented yet. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic502: + description: Bad Gateway + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_502_BAD_GATEWAY: + description: Internal routing problem in the Server side that blocks to manage the service properly + value: + status: 502 + code: BAD_GATEWAY + message: An upstream internal service cannot be reached. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic503: + description: Service Unavailable + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_503_UNAVAILABLE: + description: Service is not available. Temporary situation usually related to maintenance process in the server side + value: + status: 503 + code: UNAVAILABLE + message: Service Unavailable. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + Generic504: + description: Gateway Timeout + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorInfo" + examples: + GENERIC_504_TIMEOUT: + description: API Server Timeout + value: + status: 504 + code: TIMEOUT + message: Request timeout exceeded. + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" \ No newline at end of file