Skip to content

Commit

Permalink
Implemented the Approov protected server.
Browse files Browse the repository at this point in the history
Signed-off-by: Exadra37 <exadra37@gmail.com>
  • Loading branch information
Exadra37 committed Mar 5, 2021
1 parent 170d84b commit 5ca4c41
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/approov-protected-server/token-check/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# For production usage the secret is always retrieved with the Approov CLI tool, that can be also used to generate valid
# tokens for testing purposes. Check docs at https://approov.io/docs/v2.1/approov-cli-tool-reference/#token-commands.
#
# But if you don't have the Approov CLI tool, you can still test the backend with Postman or similar, by creating a
# secret with `openssl rand -base64 64 | tr -d '\n'; echo`, and afterwards you can use jwt.io to create the JWT token.
APPROOV_BASE64_SECRET=approov_base64_secret_here
60 changes: 60 additions & 0 deletions src/approov-protected-server/token-check/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Approov Token Integration Example

This Approov integration example is from where the code example for the [Approov token check quickstart](/docs/APPROOV_TOKEN_QUICKSTART.md) is extracted, and you can use it as a playground to better understand how simple and easy it is to implement [Approov](https://approov.io) in a Python FastAPI server.

## TOC - Table of Contents

* [Why?](#why)
* [How it Works?](#how-it-works)
* [Requirements](#requirements)
* [Try the Approov Integration Example](#try-the-approov-integration-example)


## Why?

To lock down your API server to your mobile app. Please read the brief summary in the [README](/README.md#why) at the root of this repo or visit our [website](https://approov.io/product.html) for more details.

[TOC](#toc---table-of-contents)


## How it works?

The Python FastAPI server is very simple and is defined in the file [src/approov-protected-server/token-check/hello-server-protected.py](src/approov-protected-server/token-check/hello-server-protected.py). Take a look at the `verifyApproovToken()` function to see the simple code for the check.

For more background on Approov, see the overview in the [README](/README.md#how-it-works) at the root of this repo.

[TOC](#toc---table-of-contents)


## Requirements

To run this example you will need to have installed:

* [Python 3](https://wiki.python.org/moin/BeginnersGuide/Download)
* [FastAPI](https://fastapi.tiangolo.com/tutorial/#install-fastapi)

[TOC](#toc---table-of-contents)


## Try the Approov Integration Example

First, you need to set the dummy secret in the `src/approov-protected-server/token-check/.env` file as explained [here](/README.md#the-dummy-secret).

Second, you need to install the dependencies. From the `src/approov-protected-server/token-check` folder execute:

```text
virtualenv venv
source venv/bin/activate
pip3 install -r requirements.txt
```

Now, you can run this example from the `src/approov-protected-server/token-check` folder with:

```text
uvicorn hello-server-protected:app --reload --port 8002
```
> **NOTE:** If using python from inside a docker container add the option `--host 0.0.0.0`
Finally, you can test that the Approov integration example works as expected with this [Postman collection](/README.md#testing-with-postman) or with some cURL requests [examples](/README.md#testing-with-curl).

[TOC](#toc---table-of-contents)
51 changes: 51 additions & 0 deletions src/approov-protected-server/token-check/hello-server-protected.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse

import base64

# @link https://github.com/jpadilla/pyjwt/
import jwt

# @link https://github.com/theskumar/python-dotenv
from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv(), override=True)
from os import getenv

# Token secret value obtained with the Approov CLI tool:
# - approov secret -get
approov_base64_secret = getenv('APPROOV_BASE64_SECRET')

if approov_base64_secret == None:
raise ValueError("Missing the value for environment variable: APPROOV_BASE64_SECRET")

APPROOV_SECRET = base64.b64decode(approov_base64_secret)

app = FastAPI()

# @link https://approov.io/docs/latest/approov-usage-documentation/#backend-integration
@app.middleware("http")
async def verifyApproovToken(request: Request, call_next):
approov_token = request.headers.get("Approov-Token")

# If we didn't find a token, then reject the request.
if approov_token == "":
# You may want to add some logging here.
# return None
return JSONResponse({}, status_code = 401)

try:
# Decode the Approov token explicitly with the HS256 algorithm to avoid
# the algorithm None attack.
approov_token_claims = jwt.decode(approov_token, APPROOV_SECRET, algorithms=['HS256'])
return await call_next(request)
except jwt.ExpiredSignatureError as e:
# You may want to add some logging here.
return JSONResponse({}, status_code = 401)
except jwt.InvalidTokenError as e:
# You may want to add some logging here.
return JSONResponse({}, status_code = 401)


@app.get("/")
async def root():
return {"message": "Hello World"}
9 changes: 9 additions & 0 deletions src/approov-protected-server/token-check/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
click==7.1.2
fastapi==0.63.0
h11==0.12.0
pydantic==1.8.1
PyJWT==2.0.1
python-dotenv==0.15.0
starlette==0.13.6
typing-extensions==3.7.4.3
uvicorn==0.13.4

0 comments on commit 5ca4c41

Please sign in to comment.