diff --git a/code/API_definitions/sim-swap-subscriptions.yaml b/code/API_definitions/sim-swap-subscriptions.yaml index 36fd897..d5c1261 100644 --- a/code/API_definitions/sim-swap-subscriptions.yaml +++ b/code/API_definitions/sim-swap-subscriptions.yaml @@ -46,14 +46,40 @@ info: will be posted by the sim swap resource server to the webhook url provided by notification listener. + ### Data Minimization + + #### phoneNumber presence: + These rules apply for subscription: + + - If 3-legged access token is used, the POST and GET{id} requests & responses must NOT provide thev``phoneNumber``. For GET (list) only subscription(s) for this exactly phone number is/are retrieved (implicit filtering). + - If 2-legged access token is used, for POST and GET{id}, the presence of ``phoneNumber`` in the request & response is mandatory. For GET (list) the device identifier (``phoneNumber``) could be used as filtering criteria. + + #### sinkCredential presence: + + ``sinkCredential`` is only present in POST request and not provided in POST or GET response. + # 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. + Which specific authorization flows are to be used will be determined during onboarding process, happening between the API Client and the API Provider, 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. + # 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 `phoneNumber` identifier, which therefore MUST be provided. + - When a three-legged access token is used however, this optional `phoneNumber` 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 `phoneNumber` identifier 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 `phoneNumber` identifier 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. + # Further info and support (FAQs will be added in a later version of the documentation) @@ -62,7 +88,7 @@ info: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html version: wip - x-camara-commonalities: 0.4.0 + x-camara-commonalities: 0.5.0 externalDocs: description: Product documentation at CAMARA @@ -99,6 +125,8 @@ paths: examples: SUBSCRIPTION_REQUEST: $ref: '#/components/examples/SUBSCRIPTION_REQUEST' + SUBSCRIPTION_REQUEST_3LEGS: + $ref: '#/components/examples/SUBSCRIPTION_REQUEST_3LEGS' required: true callbacks: notifications: @@ -138,10 +166,6 @@ paths: $ref: "#/components/responses/Generic410" "429": $ref: "#/components/responses/Generic429" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" security: - {} - notificationsBearerAuth: [] @@ -159,6 +183,8 @@ paths: examples: SUBSCRIPTION_RESPONSE: $ref: '#/components/examples/SUBSCRIPTION_RESPONSE' + SUBSCRIPTION_RESPONSE_3LEGS: + $ref: '#/components/examples/SUBSCRIPTION_RESPONSE_3LEGS' "202": description: Request accepted to be processed. It applies for async creation process. headers: @@ -173,19 +199,13 @@ paths: "401": $ref: "#/components/responses/Generic401" "403": - $ref: "#/components/responses/CreateSubscription403" + $ref: "#/components/responses/SubscriptionPermissionDenied403" "409": $ref: "#/components/responses/Generic409" - "415": - $ref: "#/components/responses/Generic415" "422": - $ref: "#/components/responses/CreateSubscription422" + $ref: "#/components/responses/CreateSubscriptionUnprocessableEntity422" "429": $ref: "#/components/responses/Generic429" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" get: tags: - Sim Swap Subscription @@ -213,17 +233,14 @@ paths: examples: SUBSCRIPTIONS: $ref: '#/components/examples/SUBSCRIPTIONS' - + SUBSCRIPTIONS_3LEGS: + $ref: '#/components/examples/SUBSCRIPTIONS_3LEGS' "400": $ref: "#/components/responses/Generic400" "401": $ref: "#/components/responses/Generic401" "403": $ref: "#/components/responses/Generic403" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" /subscriptions/{subscriptionId}: get: tags: @@ -250,18 +267,16 @@ paths: examples: SUBSCRIPTION: $ref: '#/components/examples/SUBSCRIPTION_RESPONSE' + SUBSCRIPTION_3LEGS: + $ref: '#/components/examples/SUBSCRIPTION_RESPONSE_3LEGS' "400": - $ref: "#/components/responses/SubscriptionIdRequired" + $ref: "#/components/responses/SubscriptionIdRequired400" "401": $ref: "#/components/responses/Generic401" "403": $ref: "#/components/responses/Generic403" "404": $ref: "#/components/responses/Generic404" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" delete: tags: - Sim Swap Subscription @@ -290,17 +305,13 @@ paths: schema: $ref: "#/components/schemas/SubscriptionAsync" "400": - $ref: "#/components/responses/SubscriptionIdRequired" + $ref: "#/components/responses/SubscriptionIdRequired400" "401": $ref: "#/components/responses/Generic401" "403": $ref: "#/components/responses/Generic403" "404": $ref: "#/components/responses/Generic404" - "500": - $ref: "#/components/responses/Generic500" - "503": - $ref: "#/components/responses/Generic503" components: securitySchemes: openId: @@ -519,8 +530,6 @@ components: CreateSubscriptionDetail: description: The detail of the requested event subscription type: object - required: - - phoneNumber properties: phoneNumber: $ref: '#/components/schemas/PhoneNumber' @@ -553,8 +562,6 @@ components: format: url description: The address to which events shall be delivered using the selected protocol. example: "https://endpoint.example.com/sink" - sinkCredential: - $ref: '#/components/schemas/SinkCredential' types: description: | Camara Event types eligible for subscription: @@ -895,28 +902,51 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - OUT_OF_RANGE + - INVALID_PROTOCOL + - INVALID_CREDENTIAL + - INVALID_TOKEN examples: - InvalidArgument: + 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: "INVALID_ARGUMENT" - message: "Client specified an invalid argument, request body or query param" - InvalidProtocol: + code: OUT_OF_RANGE + message: Client specified an invalid range. + GENERIC_400_INVALID_PROTOCOL: + description: Invalid protocol for events subscription management value: status: 400 - code: "INVALID_PROTOCOL" - message: "Only HTTP is supported" - InvalidCredential: + code: INVALID_PROTOCOL + message: Only HTTP is supported + GENERIC_400_INVALID_CREDENTIAL: + description: Invalid sink credential type value: status: 400 - code: "INVALID_CREDENTIAL" - message: "Only Access token is supported" - InvalidToken: + code: INVALID_CREDENTIAL + message: Only Access token is supported + GENERIC_400_INVALID_TOKEN: + description: Invalid token type for sink credential of type ACCESSTOKEN value: status: 400 - code: "INVALID_TOKEN" - message: "Only bearer token is supported" + code: INVALID_TOKEN + message: Only bearer token is supported Generic400: description: Problem with the client request headers: @@ -925,11 +955,54 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 400 - code: "INVALID_ARGUMENT" - message: "Client specified an invalid argument, request body or query param" + 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. + SubscriptionIdRequired400: + 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. + GENERIC_400_SUBSCRIPTION_ID_REQUIRED: + description: subscription id is required + value: + status: 400 + code: INVALID_ARGUMENT + message: "Expected property is missing: subscriptionId" Generic401: description: Authentication problem with the client request headers: @@ -938,13 +1011,31 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 401 - code: "UNAUTHENTICATED" - message: "Request not authenticated due to missing, invalid, or expired credentials" - - CreateSubscription403: + 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: Client does not have sufficient permission headers: x-correlator: @@ -952,19 +1043,24 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED examples: - PermissionDenied: - value: - status: 403 - code: "PERMISSION_DENIED" - message: "Client does not have sufficient permissions to perform this action" - TokenMismatch: + 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: "SUBSCRIPTION_MISMATCH" - message: "Inconsistent access token for requested events subscription" - Generic403: + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + SubscriptionPermissionDenied403: description: Client does not have sufficient permission headers: x-correlator: @@ -972,11 +1068,30 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 403 - code: "PERMISSION_DENIED" - message: "Client does not have sufficient permissions to perform this action" + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + - SUBSCRIPTION_MISMATCH + 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_SUBSCRIPTION_MISMATCH: + description: Inconsistent access token for requested subscription + value: + status: 403 + code: "SUBSCRIPTION_MISMATCH" + message: "Inconsistent access token for requested events subscription" Generic404: description: Resource Not Found headers: @@ -985,11 +1100,23 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 404 - code: NOT_FOUND - message: "The specified resource is not found" + 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. Generic409: description: Conflict headers: @@ -998,11 +1125,30 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 409 - code: CONFLICT - message: "The specified resource is in a conflict" + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 409 + code: + enum: + - ABORTED + - ALREADY_EXISTS + examples: + GENERIC_409_ABORTED: + description: Concurreny of processes of the same nature/scope + value: + status: 409 + code: ABORTED + message: Concurrency conflict. + GENERIC_409_ALREADY_EXISTS: + description: Trying to create an existing resource + value: + status: 409 + code: ALREADY_EXISTS + message: The resource that a client tried to create already exists. Generic410: description: Gone headers: @@ -1011,25 +1157,24 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 410 - code: GONE - message: "The specified resource is no longer available at the requested address" - Generic415: - description: Unsupported Media Type - headers: - X-Correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 415 - code: UNSUPPORTED_MEDIA_TYPE - message: "The specified media type is not supported" - CreateSubscription422: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 410 + code: + enum: + - GONE + examples: + GENERIC_410_GONE: + description: Use in notifications flow to allow API Consumer to indicate that its callback is no longer available + value: + status: 410 + code: GONE + message: Access to the target resource is no longer available. + CreateSubscriptionUnprocessableEntity422: description: Unprocessable Entity headers: x-correlator: @@ -1037,20 +1182,37 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNNECESSARY_IDENTIFIER examples: - PermissionDenied: + GENERIC_422_SERVICE_NOT_APPLICABLE: + description: Service not applicable for the provided identifier value: status: 422 - code: "MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED" - message: "Multi event types subscription not managed" - PhoneNumberNotApplicable: - description: Service is not available for the provided phone number + 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: PHONE_NUMBER_NOT_APPLICABLE - message: The service is not available for the provided phone number. - + code: MISSING_IDENTIFIER + message: The device cannot be identified. + 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: @@ -1059,60 +1221,30 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 429 - code: TOO_MANY_REQUESTS - message: "Endpoint does not support as many requests per time slot" - Generic500: - description: Server error - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 500 - code: "INTERNAL" - message: "Server error" - Generic503: - description: Service unavailable. Typically the server is down. - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorInfo" - example: - status: 503 - code: "UNAVAILABLE" - message: "Service unavailable" - SubscriptionIdRequired: - description: Problem with the client request - headers: - x-correlator: - $ref: "#/components/headers/x-correlator" - content: - application/json: - schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 429 + code: + enum: + - QUOTA_EXCEEDED + - TOO_MANY_REQUESTS examples: - Generic400: - summary: Schema validation failed + GENERIC_429_QUOTA_EXCEEDED: + description: Request is rejected due to exceeding a business quota limit value: - status: 400 - code: INVALID_ARGUMENT - message: "Client specified an invalid argument, request body or query param" - subscriptionIdRequired: - summary: subscription id is required + status: 429 + code: QUOTA_EXCEEDED + message: Rejected due to exceeding a business quota limit. + GENERIC_429_TOO_MANY_REQUESTS: + description: API Server request limit is overpassed value: - status: 400 - code: INVALID_ARGUMENT - message: "Expected property is missing: subscriptionId" - + status: 429 + code: TOO_MANY_REQUESTS + message: Rejected due to request rate limit overpassed. examples: SWAPPED: value: @@ -1155,7 +1287,7 @@ components: subscriptionDetail: phoneNumber: "+123456789" subscriptionExpireTime: '2025-01-17T13:18:23.682Z' - SUBSCRIPTION_RESPONSE: + SUBSCRIPTION_REQUEST_3LEGS: value: protocol: HTTP sink: https://endpoint.example.com/sink @@ -1164,6 +1296,15 @@ components: accessToken: "yJ2ZXIiOiIxLjAiLCJ0eXAiO..." accessTokenExpiresUtc: "1717753038" accessTokenType: "bearer" + types: + - org.camaraproject.sim-swap-subscriptions.v0.swapped + config: + subscriptionDetail: {} + subscriptionExpireTime: '2025-01-17T13:18:23.682Z' + SUBSCRIPTION_RESPONSE: + value: + protocol: HTTP + sink: https://endpoint.example.com/sink types: - org.camaraproject.sim-swap-subscriptions.v0.swapped config: @@ -1174,16 +1315,24 @@ components: startsAt: '2024-06-07T16:10:15.302Z' expiresAt: '2024-06-07T16:10:15.302Z' status: ACTIVATION_REQUESTED + SUBSCRIPTION_RESPONSE_3LEGS: + value: + protocol: HTTP + sink: https://endpoint.example.com/sink + types: + - org.camaraproject.sim-swap-subscriptions.v0.swapped + config: + subscriptionDetail: {} + subscriptionExpireTime: '2025-01-17T13:18:23.682Z' + id: '1119920371' + startsAt: '2024-06-07T16:10:15.302Z' + expiresAt: '2024-06-07T16:10:15.302Z' + status: ACTIVATION_REQUESTED SUBSCRIPTIONS: value: - protocol: HTTP sink: https://endpoint.example.com/sink - sinkCredential: - credentialType: ACCESSTOKEN - accessToken: "yJ2ZXIiOiIxLjAiLCJ0eXAiO..." - accessTokenExpiresUtc: "1717753038" - accessTokenType: "bearer" types: - org.camaraproject.sim-swap-subscriptions.v0.swapped config: @@ -1194,3 +1343,17 @@ components: startsAt: '2024-06-07T16:10:15.302Z' expiresAt: '2024-06-07T16:10:15.302Z' status: ACTIVATION_REQUESTED + SUBSCRIPTIONS_3LEGS: + value: + - protocol: HTTP + sink: https://endpoint.example.com/sink + types: + - org.camaraproject.sim-swap-subscriptions.v0.swapped + config: + subscriptionDetail: {} + + subscriptionExpireTime: '2025-01-17T13:18:23.682Z' + id: '1119920371' + startsAt: '2024-06-07T16:10:15.302Z' + expiresAt: '2024-06-07T16:10:15.302Z' + status: ACTIVATION_REQUESTED diff --git a/code/Test_definitions/sim-swap-subscriptions.feature b/code/Test_definitions/sim-swap-subscriptions.feature index c52ec05..ef22f44 100644 --- a/code/Test_definitions/sim-swap-subscriptions.feature +++ b/code/Test_definitions/sim-swap-subscriptions.feature @@ -1,4 +1,4 @@ -Feature: CAMARA sim swap subscriptions API, v0.1.1 +Feature: CAMARA sim swap subscriptions API, v0.2.0 # Input to be provided by the implementation to the tester # # Testing assets: @@ -9,7 +9,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 # References to OAS spec schemas refer to schemas specifies in sim-swap-subscriptions.yaml, version v0.1.1 Background: Common subscriptions setup - Given the resource "/sim-swap-subscriptions/v0.1/subscriptions" as BaseURL | + Given the resource "/sim-swap-subscriptions/v0.2/subscriptions" as BaseURL | And the header "Content-Type" is set to "application/json" And the header "Authorization" is set to a valid access token And the header "x-correlator" is set to a UUID value @@ -24,10 +24,10 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_01_sync_creation Scenario: Check sync subscription creation - This scenario could be bypass if async creation is provided (following scenario) Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"="HTTP" - And "$.config.subscriptionDetail.phoneNumber" is set with with provided phoneNumber + And a valid phone number identified by the token or provided in the request body And "$.sink" is set to provided callbackUrl Then the response property "$.status" is 201 And the response header "Content-Type" is "application/json" @@ -39,10 +39,10 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_02_async_creation Scenario: Check async subscription creation - This scenario could be bypass if previous scenario is provided Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"="HTTP" - And "$.config.subscriptionDetail.phoneNumber" is set with with provided phoneNumber + And a valid phone number identified by the token or provided in the request body And "$.sink" is set to provided callbackUrl Then the response property "$.status" is 202 And the response header "Content-Type" is "application/json" @@ -51,30 +51,53 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_retrieve_03_retrieve_by_id Scenario: Check existing subscription is retrieved by id - Given a valid subscription is existing and identified by an "id" + Given a subscription is existing and identified by an "id" And use BaseURL - When get sim swap subscription with subscriptionId="id" + When the HTTP "GET" request is sent with subscriptionId="id" Then the response property "$.status" is 200 And the response header "Content-Type" is "application/json" And the response header "x-correlator" has same value as the request header "x-correlator" And the response body complies with the OAS schema at "#/components/schemas/Subscription" - @sim_swap_subscription_retrieve_04_retrieve_list - Scenario: Check existing subscription is retreived in list - Given valid subscriptions are existing + @sim_swap_subscription_retrieve_04_retrieve_list_2legs + Scenario: Check existing subscription(s) is/are retreived in list + Given at least one subscription is existing for the API client making this request + And use BaseURL + When the HTTP "GET" request is sent + Then the response property "$.status" is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body complies with an array of OAS schema defined at "#/components/schemas/Subscription" + And subscription(s) is/are listed + + @sim_swap_subscription_retrieve_07_retrieve_list_3legs + Scenario: Check existing subscription(s) is/are retrieved in list + Given a subscription is existing for a phoneNumber + And this phone number is identified by the token And use BaseURL - When get sim swap subscription + When the HTTP "GET" request is sent Then the response property "$.status" is 200 And the response header "Content-Type" is "application/json" And the response header "x-correlator" has same value as the request header "x-correlator" And the response body complies with an array of OAS schema defined at "#/components/schemas/Subscription" - And all valid subscriptions are listed + And the subscriptions for this phoneNumber are listed + + @sim_swap_subscription_retrieve_08_retrieve_empty_list_3legs + Scenario: Check no existing subscription is retrieved in list + Given no subscription is existing for a phoneNumber + And this phone number is identified by the token + And use BaseURL + When the HTTP "GET" request is sent + Then the response property "$.status" is 200 + And the response header "Content-Type" is "application/json" + And the response header "x-correlator" has same value as the request header "x-correlator" + And the response body is an empty list @sim_swap_subscription_delete_05_delete_subscription Scenario: Check deletion of existing subscription & triggering of subscription-ends event - Given a valid subscription is existing and identified by an "id" + Given a subscription is existing and identified by an "id" And use BaseURL - When delete sim swap subscription with subscriptionId="id" + When the HTTP "DELETE" request is sent with subscriptionId="id" Then the response property "$.status" is 204 And the response header "Content-Type" is "application/json" And the response header "x-correlator" has same value as the request header "x-correlator" @@ -89,7 +112,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_06_swapped Scenario: Check swapped event is triggered when a sim swap is performed on the device Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"="HTTP" And "$.config.subscriptionDetail.phoneNumber" is set with with provided phoneNumber @@ -108,6 +131,8 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 # Rainy Day scenario ######################### +# No test definition for 429 # + ################## # Error code 400 ################## @@ -115,7 +140,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_20_invalid_protocol Scenario: subscription creation with invalid protocol Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"<>"HTTP" And "$.config.subscriptionDetail.phoneNumber" is set with with provided phoneNumber @@ -127,7 +152,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_21_invalid_credential Scenario: subscription creation with invalid credential Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"="HTTP" And "$.config.subscriptionDetail.phoneNumber" is set with with provided phoneNumber @@ -143,7 +168,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_22_invalid_token Scenario: subscription creation with invalid token Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"="HTTP" And "$.config.subscriptionDetail.phoneNumber" is set with with provided phoneNumber @@ -159,7 +184,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_23_invalid_eventType Scenario: subscription creation with invalid event type Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"<>"org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"="HTTP" And "$.config.subscriptionDetail.phoneNumber" is set with with provided phoneNumber @@ -171,7 +196,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_24_invalid_subscription_expire_time Scenario: subscription creation with invalid expire time Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"="HTTP" And "$.config.subscriptionDetail.phoneNumber" is set with with provided phoneNumber @@ -184,7 +209,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_25_require_input_properties_missing Scenario: subscription creation with required properties missing Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And the request body property "" is not included Then the response property "$.status" is 400 And the response property "$.code" is "INVALID_ARGUMENT" @@ -200,7 +225,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_creation_26_invalid_sink Scenario: subscription creation with invalid sink Given use BaseURL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"="HTTP" And "$.config.subscriptionDetail.phoneNumber" is set with with provided phoneNumber @@ -302,45 +327,6 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 And the response property "$.code" is "UNAUTHENTICATED" And the response property "$.message" contains a user friendly text -################## -# Error Code 403 -################## - - @sim_swap_subscription_creation_60_phone_number_token_mismatch - Scenario: Inconsistent access token context for the phone number - # To test this, a token have to be obtained for a different phone number - Given the request body property "$.config.subscriptionDetail.phoneNumber" is set to a valid testing phone number - And the header "Authorization" is set to a valid access token emitted for a different phone number - And use BaseUrL - When the HTTP "POST" request is sent - Then the response property "$.status" is 403 - And the response property "$.code" is "INVALID_TOKEN_CONTEXT" - And the response property "$.message" contains a user friendly text - - - @sim_swap_subscription_retrieve_61_phone_number_token_mismatch - Scenario: Inconsistent access token context for the phone number - # To test this, a token have to be obtained for a different phone number - Given an existing subscription for a phone number - And the header "Authorization" is set to a valid access token emitted for a different phone number - And use BaseUrL - When the HTTP "GET" request is sent - Then the response property "$.status" is 403 - And the response property "$.code" is "INVALID_TOKEN_CONTEXT" - And the response property "$.message" contains a user friendly text - - - @sim_swap_subscription_delete_62_device_token_mismatch - Scenario: Inconsistent access token context for the device - # To test this, a token have to be obtained for a different device - Given an existing subscription for a phone number - And the header "Authorization" is set to a valid access token emitted for a different phone number - And use BaseUrL - When the HTTP "DELETE" request is sent - Then the response property "$.status" is 403 - And the response property "$.code" is "INVALID_TOKEN_CONTEXT" - And the response property "$.message" contains a user friendly text - ################## # Error Code 404 ################## @@ -348,7 +334,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_retrieve_80_not_found_retrieve_by_id Scenario: Request to retrieve a non-existing subscription Given use BaseURL - When get sim swap subscription with subscriptionId set to non-existing subscription id + When the HTTP "GET" request is sent with subscriptionId set to non-existing subscription id Then the response property "$.status" is 404 And the response property "$.code" is "NOT_FOUND" And the response property "$.message" contains a user friendly text @@ -356,7 +342,7 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 @sim_swap_subscription_delete_81_not_found_delete_by_id Scenario: Request to delete a non-existing subscription Given use BaseURL - When delete sim swap subscription with subscriptionId set to non-existing subscription id + When the HTTP "DELETE" request is sent subscriptionId set to non-existing subscription id Then the response property "$.status" is 404 And the response property "$.code" is "NOT_FOUND" And the response property "$.message" contains a user friendly text @@ -365,15 +351,39 @@ Feature: CAMARA sim swap subscriptions API, v0.1.1 # Error Code 422 ################## + @sim_swap_subscription_creation_101_phone_number_token_mismatch + Scenario: Inconsistent access token context for the phone number + # To test this, a token have to be obtained for a different phone number + Given the request body property "$.config.subscriptionDetail.phoneNumber" is set to a valid testing phone number + And the header "Authorization" is set to a valid access token identifying a phone number + And use BaseUrL + When the HTTP "POST" request is sent + Then the response property "$.status" is 422 + And the response property "$.code" is "UNNECESSARY_IDENTIFIER" + And the response property "$.message" contains a user friendly text + @sim_swap_subscription_creation_100_not_applicable Scenario: request for an unapplicable phone number for sim swap subscription - # To test this it is required to have a phone number not compatibme with sim swap subscription + # To test this it is required to have a phone number not compatible with sim swap subscription Given use BaseUrL - When create sim swap subscription + When the HTTP "POST" request is sent And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" And "$.protocol"="HTTP" And "$.config.subscriptionDetail.phoneNumber" is set to a valid testing device that does not allow sim swap subscription And "$.sink" is set to provided callbackUrl Then the response property "$.status" is 422 - And the response property "$.code" is "DEVICE_NOT_APPLICABLE" + And the response property "$.code" is "UNSUPPORTED_IDENTIFIER" + And the response property "$.message" contains a user friendly text + + @sim_swap_subscription_creation_102_missing_identifier + Scenario: request without any device identifier for sim swap subscription + Given use BaseUrL + When the HTTP "POST" request is sent + And "$.types"="org.camaraproject.sim-swap-subscriptions.v0.swapped" + And "$.protocol"="HTTP" + And "$.config.subscriptionDetail.phoneNumber" is not valued + And the valid access token does no identified a device + And "$.sink" is set to provided callbackUrl + Then the response property "$.status" is 422 + And the response property "$.code" is "MISSING_IDENTIFIER" And the response property "$.message" contains a user friendly text