Skip to content

Commit

Permalink
Add basic authn and authz implementation via keycloak and opa (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
francbartoli authored Apr 12, 2022
1 parent 17d0d69 commit 34eba99
Show file tree
Hide file tree
Showing 13 changed files with 2,741 additions and 101 deletions.
14 changes: 14 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ DEV_LOG_ENQUEUE=true
DEV_LOG_ROTATION="1 days"
DEV_LOG_RETENTION="1 months"
DEV_LOG_FORMAT='<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> [id:{extra[request_id]}] - <level>{message}</level>'
# opa
DEV_OPA_URL="http://localhost:8383"
# oidc
DEV_APP_URI="http://localhost:5000"
DEV_OIDC_WELL_KNOWN_ENDPOINT="http://localhost:8282/auth/realms/pygeoapi/.well-known/openid-configuration"
DEV_OIDC_CLIENT_ID="pygeoapi-client"
DEV_OIDC_CLIENT_SECRET="YPwVOZMlAwF5dFgs9QkPetqVGgyteoFO"

# prod configs
PROD_ROOT_PATH=
Expand All @@ -45,3 +52,10 @@ PROD_LOG_ENQUEUE=false
PROD_LOG_ROTATION="1 days"
PROD_LOG_RETENTION="1 months"
PROD_LOG_FORMAT='<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> [id:{extra[request_id]}] - <level>{message}</level>'
# opa
PROD_OPA_URL="http://localhost:8383"
# oidc
PROD_APP_URI="http://localhost:5000"
PROD_OIDC_WELL_KNOWN_ENDPOINT="http://localhost:8282/auth/realms/pygeoapi/.well-known/openid-configuration"
PROD_OIDC_CLIENT_ID="pygeoapi-client"
PROD_OIDC_CLIENT_SECRET="YPwVOZMlAwF5dFgs9QkPetqVGgyteoFO"
10 changes: 10 additions & 0 deletions app/config/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class DevConfig(GlobalConfig):
LOG_ROTATION: Optional[str] = Field(None, env="DEV_LOG_ROTATION")
LOG_RETENTION: Optional[str] = Field(None, env="DEV_LOG_RETENTION")
LOG_FORMAT: Optional[str] = Field(None, env="DEV_LOG_FORMAT")
OPA_URL: Optional[str] = Field(None, env="DEV_OPA_URL")
APP_URI: Optional[str] = Field(None, env="DEV_APP_URI")
OIDC_WELL_KNOWN_ENDPOINT: Optional[str] = Field(None, env="DEV_OIDC_WELL_KNOWN_ENDPOINT")
OIDC_CLIENT_ID: Optional[str] = Field(None, env="DEV_OIDC_CLIENT_ID")
OIDC_CLIENT_SECRET: Optional[str] = Field(None, env="DEV_OIDC_CLIENT_SECRET")


class ProdConfig(GlobalConfig):
Expand All @@ -45,6 +50,11 @@ class ProdConfig(GlobalConfig):
LOG_ROTATION: Optional[str] = Field(None, env="PROD_LOG_ROTATION")
LOG_RETENTION: Optional[str] = Field(None, env="PROD_LOG_RETENTION")
LOG_FORMAT: Optional[str] = Field(None, env="PROD_LOG_FORMAT")
OPA_URL: Optional[str] = Field(None, env="PROD_OPA_URL")
APP_URI: Optional[str] = Field(None, env="PROD_APP_URI")
OIDC_WELL_KNOWN_ENDPOINT: Optional[str] = Field(None, env="PROD_OIDC_WELL_KNOWN_ENDPOINT")
OIDC_CLIENT_ID: Optional[str] = Field(None, env="PROD_OIDC_CLIENT_ID")
OIDC_CLIENT_SECRET: Optional[str] = Field(None, env="PROD_OIDC_CLIENT_SECRET")


class FactoryConfig:
Expand Down
22 changes: 22 additions & 0 deletions app/config/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Authn and Authz module"""
from fastapi_opa import OPAConfig
from fastapi_opa.auth import OIDCAuthentication
from fastapi_opa.auth import OIDCConfig

from app.config.app import configuration as cfg


# The hostname of your Open Policy Agent instance
opa_host = cfg.OPA_URL
# In this example we use OIDC authentication flow (using Keycloak)
oidc_config = OIDCConfig(
well_known_endpoint=cfg.OIDC_WELL_KNOWN_ENDPOINT,
# well known endpoint
app_uri=cfg.APP_URI, # host where this app is running
# client id of your app configured in the identity provider
client_id=cfg.OIDC_CLIENT_ID,
# the client secret retrieved from your identity provider
client_secret=cfg.OIDC_CLIENT_SECRET,
)
oidc_auth = OIDCAuthentication(oidc_config)
opa_config = OPAConfig(authentication=oidc_auth, opa_host=opa_host)
4 changes: 4 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
import uvicorn
from app.config.app import configuration as cfg
from app.config.logging import create_logger
from app.config.auth import opa_config
from app.utils.app_exceptions import app_exception_handler
from app.utils.app_exceptions import AppExceptionError
from app.utils.request_exceptions import http_exception_handler
from app.utils.request_exceptions import request_validation_exception_handler
from fastapi import FastAPI
from fastapi.exceptions import RequestValidationError
from fastapi_opa import OPAMiddleware
from mangum import Mangum
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.middleware.cors import CORSMiddleware
Expand Down Expand Up @@ -40,6 +42,8 @@ async def custom_validation_exception_handler(request, e):
async def custom_app_exception_handler(request, e):
return await app_exception_handler(request, e)

# Add OPAMiddleware to the pygeoapi app
pygeoapi_app.add_middleware(OPAMiddleware, config=opa_config)
app.mount(path="/api", app=pygeoapi_app)

app.logger = create_logger(name="app.main")
Expand Down
3 changes: 0 additions & 3 deletions docs/requirements.txt

This file was deleted.

94 changes: 0 additions & 94 deletions example-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,100 +175,6 @@ resources:
id_field: id
title_field: name

gdps-temperature:
type: collection
title: Global Deterministic Prediction System sample
description: Global Deterministic Prediction System sample
keywords:
- gdps
- global
extents:
spatial:
bbox: [-180,-90,180,90]
crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
links:
- type: text/html
rel: canonical
title: information
href: https://eccc-msc.github.io/open-data/msc-data/nwp_gdps/readme_gdps_en
hreflang: en-CA
providers:
- type: coverage
name: rasterio
data: tests/data/CMC_glb_TMP_TGL_2_latlon.15x.15_2020081000_P000.grib2
options:
DATA_ENCODING: COMPLEX_PACKING
format:
name: GRIB
mimetype: application/x-grib2

test-data:
type: stac-collection
title: pygeoapi test data
description: pygeoapi test data
keywords:
- poi
- portugal
links:
- type: text/html
rel: canonical
title: information
href: https://github.com/geopython/pygeoapi/tree/master/tests/data
hreflang: en-US
extents:
spatial:
bbox: [-180,-90,180,90]
crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
providers:
- type: stac
name: FileSystem
data: tests/data
file_types:
- .gpkg
- .sqlite
- .csv
- .grib2
- .tif
- .shp

canada-metadata:
type: collection
title:
en: Open Canada sample data
fr: Exemple de donn\u00e9es Canada Ouvert
description:
en: Sample metadata records from open.canada.ca
fr: Exemples d'enregistrements de m\u00e9tadonn\u00e9es sur ouvert.canada.ca
keywords:
en:
- canada
- open data
fr:
- canada
- donn\u00e9es ouvertes
links:
- type: text/html
rel: canonical
title: information
href: https://open.canada.ca/en/open-data
hreflang: en-CA
- type: text/html
rel: alternate
title: informations
href: https://ouvert.canada.ca/fr/donnees-ouvertes
hreflang: fr-CA
extents:
spatial:
bbox: [-180,-90,180,90]
crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
providers:
- type: record
name: TinyDBCatalogue
data: tests/data/open.canada.ca/sample-records.tinydb
id_field: externalId
time_field: recordCreated
title_field: title

hello-world:
type: process
processor:
Expand Down
Loading

0 comments on commit 34eba99

Please sign in to comment.