Skip to content

Commit de78fbc

Browse files
Adding route dependencies module. (#251)
**Description:** Generate a list of route dependencies from the environment variable `STAC_FASTAPI_ROUTE_DEPENDENCIES` or the file that this environment variable points to. Feed these route dependencies into the `STACApi` on initialisation. **PR Checklist:** - [x] Code is formatted and linted (run `pre-commit run --all-files`) - [x] Tests pass (run `make test`) - [x] Documentation has been updated to reflect changes, if applicable - [x] Changes are added to the changelog --------- Co-authored-by: Jonathan Healy <jonathan.d.healy@gmail.com>
1 parent f4618a9 commit de78fbc

File tree

16 files changed

+2499
-203
lines changed

16 files changed

+2499
-203
lines changed

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## [Unreleased]
99

10+
### Added
11+
- Added support for route depndencies configuration through the STAC_FASTAPI_ROUTE_DEPENDENCIES environment variable, directly or via json file. Allows for fastapi's inbuilt OAuth2 flows to be used as dependencies. Custom dependencies can also be written, see Basic Auth for an example. [#251](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/251)
12+
- Added docker-compose.route_dependencies_file.yml that gives an example of OAuth2 workflow using keycloak as the identity provider. [#251](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/251)
13+
- Added docker-compose.route_dependencies_env.yml that gives an example using the STAC_FASTAPI_ROUTE_DEPENDENCIES environment variable. [#251](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/251)
14+
15+
### Changed
16+
- Converted Basic auth to a route dependency and merged with new route depndencies method. [#251](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/251)
17+
- Updated docker-compose.basic_auth_protected.yml to use STAC_FASTAPI_ROUTE_DEPENDENCIES environment variable. [#251](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/251)
18+
1019
## [v3.0.0a2]
1120

1221
### Added
@@ -234,4 +243,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
234243
[v1.0.0]: <https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v0.3.0...v1.0.0>
235244
[v0.3.0]: <https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v0.2.0...v0.3.0>
236245
[v0.2.0]: <https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v0.1.0...v0.2.0>
237-
[v0.1.0]: <https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v0.1.0>
246+
[v0.1.0]: <https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v0.1.0>

README.md

Lines changed: 86 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -279,75 +279,106 @@ The modified Items with lowercase identifiers will now be visible to users acces
279279

280280
#### Environment Variable Configuration
281281

282-
Basic authentication is an optional feature. You can enable it by setting the environment variable `BASIC_AUTH` as a JSON string.
282+
Basic authentication is an optional feature that can be enabled through [Route Dependencies](#route-dependencies).
283283

284-
Example:
285-
```
286-
BASIC_AUTH={"users":[{"username":"user","password":"pass","permissions":"*"}]}
287-
```
288284

289-
### User Permissions Configuration
285+
### Example Configuration
290286

291-
In order to set endpoints with specific access permissions, you can configure the `users` key with a list of user objects. Each user object should contain the username, password, and their respective permissions.
292-
293-
Example: This example illustrates the configuration for two users: an **admin** user with full permissions (*) and a **reader** user with limited permissions to specific read-only endpoints.
287+
This example illustrates the configuration for two users: an **admin** user with full permissions (*) and a **reader** user with limited permissions to specific read-only endpoints.
294288
```json
295-
{
296-
"users": [
297-
{
298-
"username": "admin",
299-
"password": "admin",
300-
"permissions": "*"
301-
},
302-
{
303-
"username": "reader",
304-
"password": "reader",
305-
"permissions": [
306-
{"path": "/", "method": ["GET"]},
307-
{"path": "/conformance", "method": ["GET"]},
308-
{"path": "/collections/{collection_id}/items/{item_id}", "method": ["GET"]},
309-
{"path": "/search", "method": ["GET", "POST"]},
310-
{"path": "/collections", "method": ["GET"]},
311-
{"path": "/collections/{collection_id}", "method": ["GET"]},
312-
{"path": "/collections/{collection_id}/items", "method": ["GET"]},
313-
{"path": "/queryables", "method": ["GET"]},
314-
{"path": "/queryables/collections/{collection_id}/queryables", "method": ["GET"]},
315-
{"path": "/_mgmt/ping", "method": ["GET"]}
316-
]
289+
[
290+
{
291+
"routes": [
292+
{
293+
"method": "*",
294+
"path": "*"
295+
}
296+
],
297+
"dependencies": [
298+
{
299+
"method": "stac_fastapi.core.basic_auth.BasicAuth",
300+
"kwargs": {
301+
"credentials":[
302+
{
303+
"username": "admin",
304+
"password": "admin"
305+
}
306+
]
307+
}
308+
}
309+
]
310+
},
311+
{
312+
"routes": [
313+
{"path": "/", "method": ["GET"]},
314+
{"path": "/conformance", "method": ["GET"]},
315+
{"path": "/collections/{collection_id}/items/{item_id}", "method": ["GET"]},
316+
{"path": "/search", "method": ["GET", "POST"]},
317+
{"path": "/collections", "method": ["GET"]},
318+
{"path": "/collections/{collection_id}", "method": ["GET"]},
319+
{"path": "/collections/{collection_id}/items", "method": ["GET"]},
320+
{"path": "/queryables", "method": ["GET"]},
321+
{"path": "/queryables/collections/{collection_id}/queryables", "method": ["GET"]},
322+
{"path": "/_mgmt/ping", "method": ["GET"]}
323+
],
324+
"dependencies": [
325+
{
326+
"method": "stac_fastapi.core.basic_auth.BasicAuth",
327+
"kwargs": {
328+
"credentials":[
329+
{
330+
"username": "reader",
331+
"password": "reader"
332+
}
333+
]
317334
}
335+
}
318336
]
319-
}
337+
}
338+
]
320339
```
321340

341+
## Route Dependencies
322342

323-
### Public Endpoints Configuration
343+
### Configuration
324344

325-
In order to set endpoints with public access, you can configure the public_endpoints key with a list of endpoint objects. Each endpoint object should specify the path and method of the endpoint.
345+
Route dependencies for endpoints can enable through the `STAC_FASTAPI_ROUTE_DEPENDENCIES`
346+
environment variable as a path to a JSON file or a JSON string.
326347

327-
Example: This example demonstrates the configuration for public endpoints, allowing access without authentication to read-only endpoints.
328-
```json
329-
{
330-
"public_endpoints": [
331-
{"path": "/", "method": "GET"},
332-
{"path": "/conformance", "method": "GET"},
333-
{"path": "/collections/{collection_id}/items/{item_id}", "method": "GET"},
334-
{"path": "/search", "method": "GET"},
335-
{"path": "/search", "method": "POST"},
336-
{"path": "/collections", "method": "GET"},
337-
{"path": "/collections/{collection_id}", "method": "GET"},
338-
{"path": "/collections/{collection_id}/items", "method": "GET"},
339-
{"path": "/queryables", "method": "GET"},
340-
{"path": "/queryables/collections/{collection_id}/queryables", "method": "GET"},
341-
{"path": "/_mgmt/ping", "method": "GET"}
348+
#### Route Dependency
349+
350+
A Route Dependency must include `routes`, a list of at least one [Route](#routes), and `dependencies` a
351+
list of at least one [Dependency](#dependencies).
352+
353+
#### Routes
354+
355+
A Route must include a `path`, the relative path to the endpoint, and a `method`, the request method of the path.
356+
357+
#### Dependencies
358+
359+
A Dependency must include the `method`, a dot seperated path to the Class or Function, and
360+
can include any `args` or `kwargs` for the method.
361+
362+
#### Example
363+
```
364+
STAC_FASTAPI_ROUTE_DEPENDENCIES=[
365+
{
366+
"routes": [
367+
{
368+
"method": "GET",
369+
"path": "/collections"
370+
}
342371
],
343-
"users": [
344-
{
345-
"username": "admin",
346-
"password": "admin",
347-
"permissions": "*"
372+
"dependencies": [
373+
{
374+
"method": "fastapi.security.OAuth2PasswordBearer",
375+
"kwargs": {
376+
"tokenUrl": "token"
348377
}
378+
}
349379
]
350-
}
380+
}
381+
]
351382
```
352383

353384
### Docker Compose Configurations

docker-compose.basic_auth_protected.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ services:
2222
- ES_USE_SSL=false
2323
- ES_VERIFY_CERTS=false
2424
- BACKEND=elasticsearch
25-
- BASIC_AUTH={"users":[{"username":"admin","password":"admin","permissions":"*"},{"username":"reader","password":"reader","permissions":[{"path":"/","method":["GET"]},{"path":"/conformance","method":["GET"]},{"path":"/collections/{collection_id}/items/{item_id}","method":["GET"]},{"path":"/search","method":["GET","POST"]},{"path":"/collections","method":["GET"]},{"path":"/collections/{collection_id}","method":["GET"]},{"path":"/collections/{collection_id}/items","method":["GET"]},{"path":"/queryables","method":["GET"]},{"path":"/queryables/collections/{collection_id}/queryables","method":["GET"]},{"path":"/_mgmt/ping","method":["GET"]}]}]}
25+
- STAC_FASTAPI_ROUTE_DEPENDENCIES=[{"routes":[{"method":"*","path":"*"}],"dependencies":[{"method":"stac_fastapi.core.basic_auth.BasicAuth","kwargs":{"credentials":[{"username":"admin","password":"admin"}]}}]},{"routes":[{"path":"/","method":["GET"]},{"path":"/conformance","method":["GET"]},{"path":"/collections/{collection_id}/items/{item_id}","method":["GET"]},{"path":"/search","method":["GET","POST"]},{"path":"/collections","method":["GET"]},{"path":"/collections/{collection_id}","method":["GET"]},{"path":"/collections/{collection_id}/items","method":["GET"]},{"path":"/queryables","method":["GET"]},{"path":"/queryables/collections/{collection_id}/queryables","method":["GET"]},{"path":"/_mgmt/ping","method":["GET"]}],"dependencies":[{"method":"stac_fastapi.core.basic_auth.BasicAuth","kwargs":{"credentials":[{"username":"reader","password":"reader"}]}}]}]
2626
ports:
2727
- "8080:8080"
2828
volumes:
@@ -55,7 +55,7 @@ services:
5555
- ES_USE_SSL=false
5656
- ES_VERIFY_CERTS=false
5757
- BACKEND=opensearch
58-
- BASIC_AUTH={"users":[{"username":"admin","password":"admin","permissions":"*"},{"username":"reader","password":"reader","permissions":[{"path":"/","method":["GET"]},{"path":"/conformance","method":["GET"]},{"path":"/collections/{collection_id}/items/{item_id}","method":["GET"]},{"path":"/search","method":["GET","POST"]},{"path":"/collections","method":["GET"]},{"path":"/collections/{collection_id}","method":["GET"]},{"path":"/collections/{collection_id}/items","method":["GET"]},{"path":"/queryables","method":["GET"]},{"path":"/queryables/collections/{collection_id}/queryables","method":["GET"]},{"path":"/_mgmt/ping","method":["GET"]}]}]}
58+
- STAC_FASTAPI_ROUTE_DEPENDENCIES=[{"routes":[{"method":"*","path":"*"}],"dependencies":[{"method":"stac_fastapi.core.basic_auth.BasicAuth","kwargs":{"credentials":[{"username":"admin","password":"admin"}]}}]},{"routes":[{"path":"/","method":["GET"]},{"path":"/conformance","method":["GET"]},{"path":"/collections/{collection_id}/items/{item_id}","method":["GET"]},{"path":"/search","method":["GET","POST"]},{"path":"/collections","method":["GET"]},{"path":"/collections/{collection_id}","method":["GET"]},{"path":"/collections/{collection_id}/items","method":["GET"]},{"path":"/queryables","method":["GET"]},{"path":"/queryables/collections/{collection_id}/queryables","method":["GET"]},{"path":"/_mgmt/ping","method":["GET"]}],"dependencies":[{"method":"stac_fastapi.core.basic_auth.BasicAuth","kwargs":{"credentials":[{"username":"reader","password":"reader"}]}}]}]
5959
ports:
6060
- "8082:8082"
6161
volumes:

docker-compose.basic_auth_public.yml renamed to docker-compose.route_dependencies_env.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ services:
2222
- ES_USE_SSL=false
2323
- ES_VERIFY_CERTS=false
2424
- BACKEND=elasticsearch
25-
- BASIC_AUTH={"public_endpoints":[{"path":"/","method":"GET"},{"path":"/conformance","method":"GET"},{"path":"/collections/{collection_id}/items/{item_id}","method":"GET"},{"path":"/search","method":"GET"},{"path":"/search","method":"POST"},{"path":"/collections","method":"GET"},{"path":"/collections/{collection_id}","method":"GET"},{"path":"/collections/{collection_id}/items","method":"GET"},{"path":"/queryables","method":"GET"},{"path":"/queryables/collections/{collection_id}/queryables","method":"GET"},{"path":"/_mgmt/ping","method":"GET"}],"users":[{"username":"admin","password":"admin","permissions":[{"path":"/","method":["GET"]},{"path":"/conformance","method":["GET"]},{"path":"/collections/{collection_id}/items/{item_id}","method":["GET","POST","PUT","DELETE"]},{"path":"/search","method":["GET","POST"]},{"path":"/collections","method":["GET","PUT","POST"]},{"path":"/collections/{collection_id}","method":["GET","DELETE"]},{"path":"/collections/{collection_id}/items","method":["GET","POST"]},{"path":"/queryables","method":["GET"]},{"path":"/queryables/collections/{collection_id}/queryables","method":["GET"]},{"path":"/_mgmt/ping","method":["GET"]}]}]}
25+
- STAC_FASTAPI_ROUTE_DEPENDENCIES=[{"routes":[{"method":"GET","path":"/collections"}],"dependencies":[{"method":"conftest.must_be_bob"}]}]
2626
ports:
2727
- "8080:8080"
2828
volumes:
@@ -55,7 +55,7 @@ services:
5555
- ES_USE_SSL=false
5656
- ES_VERIFY_CERTS=false
5757
- BACKEND=opensearch
58-
- BASIC_AUTH={"public_endpoints":[{"path":"/","method":"GET"},{"path":"/conformance","method":"GET"},{"path":"/collections/{collection_id}/items/{item_id}","method":"GET"},{"path":"/search","method":"GET"},{"path":"/search","method":"POST"},{"path":"/collections","method":"GET"},{"path":"/collections/{collection_id}","method":"GET"},{"path":"/collections/{collection_id}/items","method":"GET"},{"path":"/queryables","method":"GET"},{"path":"/queryables/collections/{collection_id}/queryables","method":"GET"},{"path":"/_mgmt/ping","method":"GET"}],"users":[{"username":"admin","password":"admin","permissions":[{"path":"/","method":["GET"]},{"path":"/conformance","method":["GET"]},{"path":"/collections/{collection_id}/items/{item_id}","method":["GET","POST","PUT","DELETE"]},{"path":"/search","method":["GET","POST"]},{"path":"/collections","method":["GET","PUT","POST"]},{"path":"/collections/{collection_id}","method":["GET","DELETE"]},{"path":"/collections/{collection_id}/items","method":["GET","POST"]},{"path":"/queryables","method":["GET"]},{"path":"/queryables/collections/{collection_id}/queryables","method":["GET"]},{"path":"/_mgmt/ping","method":["GET"]}]}]}
58+
- STAC_FASTAPI_ROUTE_DEPENDENCIES=[{"routes":[{"method":"GET","path":"/collections"}],"dependencies":[{"method":"conftest.must_be_bob"}]}]
5959
ports:
6060
- "8082:8082"
6161
volumes:
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
version: '3.9'
2+
3+
services:
4+
app-elasticsearch:
5+
container_name: stac-fastapi-es
6+
image: stac-utils/stac-fastapi-es
7+
restart: always
8+
build:
9+
context: .
10+
dockerfile: dockerfiles/Dockerfile.dev.es
11+
environment:
12+
- STAC_FASTAPI_TITLE=stac-fastapi-elasticsearch
13+
- STAC_FASTAPI_DESCRIPTION=A STAC FastAPI with an Elasticsearch backend
14+
- STAC_FASTAPI_VERSION=3.0.0a1
15+
- APP_HOST=0.0.0.0
16+
- APP_PORT=8080
17+
- RELOAD=true
18+
- ENVIRONMENT=local
19+
- WEB_CONCURRENCY=10
20+
- ES_HOST=elasticsearch
21+
- ES_PORT=9200
22+
- ES_USE_SSL=false
23+
- ES_VERIFY_CERTS=false
24+
- BACKEND=elasticsearch
25+
- STAC_FASTAPI_ROUTE_DEPENDENCIES=/app/route_dependencies/route_dependencies.json
26+
ports:
27+
- "8080:8080"
28+
volumes:
29+
- ./stac_fastapi:/app/stac_fastapi
30+
- ./examples/route_dependencies:/app/route_dependencies
31+
- ./scripts:/app/scripts
32+
- ./esdata:/usr/share/elasticsearch/data
33+
depends_on:
34+
- elasticsearch
35+
command:
36+
bash -c "./scripts/wait-for-it-es.sh es-container:9200 && python -m stac_fastapi.elasticsearch.app"
37+
38+
app-opensearch:
39+
container_name: stac-fastapi-os
40+
image: stac-utils/stac-fastapi-os
41+
restart: always
42+
build:
43+
context: .
44+
dockerfile: dockerfiles/Dockerfile.dev.os
45+
environment:
46+
- STAC_FASTAPI_TITLE=stac-fastapi-opensearch
47+
- STAC_FASTAPI_DESCRIPTION=A STAC FastAPI with an Opensearch backend
48+
- STAC_FASTAPI_VERSION=2.1
49+
- APP_HOST=0.0.0.0
50+
- APP_PORT=8082
51+
- RELOAD=true
52+
- ENVIRONMENT=local
53+
- WEB_CONCURRENCY=10
54+
- ES_HOST=opensearch
55+
- ES_PORT=9202
56+
- ES_USE_SSL=false
57+
- ES_VERIFY_CERTS=false
58+
- BACKEND=opensearch
59+
- STAC_FASTAPI_ROUTE_DEPENDENCIES=/app/route_dependencies/route_dependencies.json
60+
ports:
61+
- "8082:8082"
62+
volumes:
63+
- ./stac_fastapi:/app/stac_fastapi
64+
- ./scripts:/app/scripts
65+
- ./osdata:/usr/share/opensearch/data
66+
depends_on:
67+
- opensearch
68+
command:
69+
bash -c "./scripts/wait-for-it-es.sh os-container:9202 && python -m stac_fastapi.opensearch.app"
70+
71+
elasticsearch:
72+
container_name: es-container
73+
image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTICSEARCH_VERSION:-8.11.0}
74+
hostname: elasticsearch
75+
environment:
76+
ES_JAVA_OPTS: -Xms512m -Xmx1g
77+
volumes:
78+
- ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
79+
- ./elasticsearch/snapshots:/usr/share/elasticsearch/snapshots
80+
ports:
81+
- "9200:9200"
82+
83+
opensearch:
84+
container_name: os-container
85+
image: opensearchproject/opensearch:${OPENSEARCH_VERSION:-2.11.1}
86+
hostname: opensearch
87+
environment:
88+
- discovery.type=single-node
89+
- plugins.security.disabled=true
90+
- OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m
91+
volumes:
92+
- ./opensearch/config/opensearch.yml:/usr/share/opensearch/config/opensearch.yml
93+
- ./opensearch/snapshots:/usr/share/opensearch/snapshots
94+
ports:
95+
- "9202:9202"
96+
97+
postgres:
98+
image: postgres:15
99+
container_name: postgres
100+
hostname: keycloakdb
101+
environment:
102+
- POSTGRES_DB=keycloak
103+
- POSTGRES_USER=keycloak
104+
- POSTGRES_PASSWORD=password
105+
volumes:
106+
- postgres:/var/lib/postgresql/data
107+
108+
keycloak:
109+
image: quay.io/keycloak/keycloak:25.0.0
110+
container_name: keycloak
111+
ports:
112+
- 8083:8083
113+
environment:
114+
- KEYCLOAK_IMPORT=/tmp/keycloak-realm.json
115+
- KEYCLOAK_ADMIN=admin
116+
- KEYCLOAK_ADMIN_PASSWORD=admin
117+
- KC_HTTP_PORT=8083
118+
- KC_DB=postgres
119+
- KC_DB_URL=jdbc:postgresql://keycloakdb:5432/keycloak
120+
- KC_DB_USERNAME=keycloak
121+
- KC_DB_PASSWORD=password
122+
volumes:
123+
- ./example/route_dependencies/stac-realm.json:/opt/keycloak/data/import
124+
command: start-dev --import-realm
125+
depends_on:
126+
- postgres
127+
128+
volumes:
129+
postgres:

0 commit comments

Comments
 (0)