diff --git a/app/authentication/auth.py b/app/authentication/auth.py index 7a744c039..f594d00ad 100644 --- a/app/authentication/auth.py +++ b/app/authentication/auth.py @@ -132,8 +132,9 @@ def _decode_jwt_token(auth_token, api_keys, service_id=None): try: decode_jwt_token(auth_token, api_key.secret) except TokenExpiredError: - err_msg = "Error: Your system clock must be accurate to within 30 seconds" - raise AuthError(err_msg, 403, service_id=service_id, api_key_id=api_key.id) + if not current_app.config.get('ALLOW_EXPIRED_API_TOKEN', False): + err_msg = "Error: Your system clock must be accurate to within 30 seconds" + raise AuthError(err_msg, 403, service_id=service_id, api_key_id=api_key.id) except TokenAlgorithmError: err_msg = "Invalid token: algorithm used is not HS256" raise AuthError(err_msg, 403, service_id=service_id, api_key_id=api_key.id) diff --git a/app/config.py b/app/config.py index d8808b04c..292f78b7e 100644 --- a/app/config.py +++ b/app/config.py @@ -80,6 +80,7 @@ class Config(object): ('{"%s":["%s"]}' % (ADMIN_CLIENT_ID, getenv('ADMIN_CLIENT_SECRET'))) ) ) + ALLOW_EXPIRED_API_TOKEN = False # encyption secret/salt SECRET_KEY = getenv('SECRET_KEY') DANGEROUS_SALT = getenv('DANGEROUS_SALT') @@ -368,6 +369,7 @@ class Development(Config): DANGEROUS_SALT = 'dev-notify-salt' SECRET_KEY = 'dev-notify-secret-key' # nosec B105 - this is only used in development INTERNAL_CLIENT_API_KEYS = {Config.ADMIN_CLIENT_ID: ['dev-notify-secret-key']} + ALLOW_EXPIRED_API_TOKEN = getenv('ALLOW_EXPIRED_API_TOKEN', '0') == '1' class Test(Development): diff --git a/docs/api-usage.md b/docs/api-usage.md index 70e6de389..e4a9646d4 100644 --- a/docs/api-usage.md +++ b/docs/api-usage.md @@ -20,3 +20,9 @@ flask command create-admin-jwt | tail -n 1 | pbcopy ``` to copy a token usable by the admin UI to your pasteboard. This token will expire in 30 seconds + +### Disable token expiration checking in development + +``` +env ALLOW_EXPIRED_API_TOKEN=1 make run-flask +``` diff --git a/docs/openapi.yml b/docs/openapi.yml index 178c8d477..38f2c3877 100644 --- a/docs/openapi.yml +++ b/docs/openapi.yml @@ -15,6 +15,13 @@ components: type: http scheme: bearer bearerFormat: JWT + parameters: + uuidPath: + name: uuid + in: path + required: true + schema: + type: string schemas: serviceObject: type: object @@ -128,6 +135,30 @@ components: state: type: string enum: ["pending", "active", "inactive"] + apiKeyResponse: + type: object + properties: + apiKeys: + type: array + items: + type: object + properties: + created_by: + type: string + created_at: + type: string + expiry_date: + type: string + id: + type: string + key_type: + type: string + name: + type: string + updated_at: + type: string + version: + type: number paths: /_status?simple=1: get: @@ -211,11 +242,7 @@ paths: tags: - internal-api parameters: - - name: uuid - in: path - required: true - schema: - type: string + - $ref: "#/components/parameters/uuidPath" responses: '200': description: OK @@ -275,6 +302,52 @@ paths: type: array items: $ref: "#/components/schemas/serviceObject" + /service/find-services-by-name: + get: + security: + - bearerAuth: [] + description: 'Find a service by name' + tags: + - internal-api + parameters: + - name: service_name + in: query + required: true + schema: + type: string + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + type: object + properties: + active: + type: boolean + id: + type: string + name: + type: string + research_mode: + type: boolean + restricted: + type: boolean + /service/live-services-data: + get: + security: + - bearerAuth: [] + description: 'Unsure' + tags: + - internal-api + responses: + '200': + description: OK /service/{uuid}: get: security: @@ -283,11 +356,7 @@ paths: tags: - internal-api parameters: - - name: uuid - in: path - required: true - schema: - type: string + - $ref: "#/components/parameters/uuidPath" responses: '200': description: OK @@ -306,11 +375,60 @@ paths: tags: - internal-api parameters: - - name: uuid + - $ref: "#/components/parameters/uuidPath" + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + /service/{uuid}/api-keys: + get: + security: + - bearerAuth: [] + description: 'Retrieve api-keys for a service' + tags: + - internal-api + parameters: + - $ref: "#/components/parameters/uuidPath" + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/apiKeyResponse" + /service/{uuid}/api-keys/{key-id}: + get: + security: + - bearerAuth: [] + description: 'Retrieve details of a single API key' + tags: + - internal-api + parameters: + - $ref: "#/components/parameters/uuidPath" + - name: key-id in: path required: true schema: type: string + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/apiKeyResponse" + /service/{uuid}/users: + get: + security: + - bearerAuth: [] + description: 'Retrieve users associated with this service' + tags: + - internal-api + parameters: + - $ref: "#/components/parameters/uuidPath" responses: '200': description: OK @@ -318,3 +436,8 @@ paths: application/json: schema: type: object + properties: + data: + type: array + items: + $ref: "#/components/schemas/userObject"