-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented the Approov protected server.
Signed-off-by: Exadra37 <exadra37@gmail.com>
- Loading branch information
Showing
4 changed files
with
126 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
51
src/approov-protected-server/token-check/hello-server-protected.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |