Skip to content

Commit d4ee2ef

Browse files
jocelyneholdbrookTom Searle
authored andcommitted
CU-869ajt55f: Add option to use OIDC auth in medcat-trainer (#161)
* - Add tests to increase coverage in medcat-trainer frontend - Add job in CI and QA workflows to test frontend * Fix indentation * Update medcat-trainer_ci.yml * Fix line endings * properly fix line endings mismatch * Create ConceptDatabase.spec.ts * remove erroneously added test files * re-add end of file return * readd new line at end of file * properly fix line endings mismatch Create ConceptDatabase.spec.ts Fix indentation remove erroneously added test files readd new line at end of file * CU-869admfwg: Disable push to dockerhub in QA workflow for testing * CU-869admfwg: Remove workflow dispatch from QA workflow now that testing is complete * CU-869ajt55f: Initial dev setup with feature flag * CU-869ajt55f: Map Keycloak Roles to Django User * CU-869ajt55f: Add env var expansion to optionally include Traefik labels and gateway auth network * CU-869ajt55f: Tidy up configuration and fix logout * CU-869ajt55f: Disable OIDC auth by default * CU-869ajt55f: Revert unintended changes * CU-869ajt55f: Addressing code review feedback * CU-869ajt55f: Fix broken test
1 parent 258f1d7 commit d4ee2ef

File tree

23 files changed

+572
-218
lines changed

23 files changed

+572
-218
lines changed

medcat-trainer/.env-example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ SPACY_MODELS="en_core_web_sm en_core_web_md en_core_web_lg"
33

44
# Ports
55
MCTRAINER_PORT=8001
6-
SOLR_PORT=8983
6+
SOLR_PORT=8983

medcat-trainer/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ MedCATTrainer was presented at EMNLP/IJCNLP 2019 :tada:
1515
Official docs available [here](https://docs.cogstack.org/projects/medcat-trainer)
1616

1717
If you have any questions why not reach out to the community [discourse forum here](https://discourse.cogstack.org/)
18+
19+

medcat-trainer/docker-compose-dev.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ services:
88
args:
99
SPACY_MODELS: ${SPACY_MODELS:-en_core_web_md}
1010
restart: always
11+
networks:
12+
- gateway-auth_gateway-net
1113
volumes:
1214
- api-media:/home/api/media
1315
- api-static:/home/api/static
@@ -32,13 +34,20 @@ services:
3234
- api-static:/home/api/static
3335
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
3436
- ./nginx/sites-enabled/:/etc/nginx/sites-enabled
37+
networks:
38+
- gateway-auth_gateway-net
3539
env_file:
3640
- ./envs/env
3741
ports:
3842
- ${MCTRAINER_PORT:-8001}:8000
3943
depends_on:
4044
- medcattrainer
4145
- solr
46+
labels:
47+
- "traefik.enable=true"
48+
- "traefik.http.routers.nginx.rule=Host(`${NGINX_HOST:-medcattrainer.cogstack.localhost}`)"
49+
- "traefik.http.routers.nginx.entrypoints=web"
50+
- "traefik.http.services.nginx.loadbalancer.server.port=8000"
4251

4352
solr:
4453
container_name: mct_solr
@@ -50,6 +59,8 @@ services:
5059
- ${SOLR_PORT:-8983}:8983
5160
volumes:
5261
- solr-data:/var/solr
62+
networks:
63+
- gateway-auth_gateway-net
5364
command:
5465
- -cloud
5566

@@ -59,3 +70,8 @@ volumes:
5970
api-db:
6071
api-db-backup:
6172
solr-data:
73+
74+
networks:
75+
gateway-auth_gateway-net:
76+
external: true
77+

medcat-trainer/docs/installation.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ For password resets and other emailing services email environment variables are
5252

5353
Personal email accounts can be set up by users to do this, or you can contact someone in CogStack for a cogstack no email credentials.
5454

55-
The environment variables required are listed in [Environment Variables.](#(optional)-environment-variables)
55+
The environment variables required are listed in [Environment Variables.](#optional-environment-variables)
5656

5757
Environment Variables are located in envs/env or envs/env-prod, when those are set webapp/frontend/.env must change "VITE_APP_EMAIL" to 1.
5858

@@ -73,6 +73,30 @@ Set these and re-run the docker-compose file.
7373

7474
You'll need to `docker stop` the running containers if you have already run the install.
7575

76+
## OIDC Authentication
77+
78+
You can enable OIDC (OpenID Connect) authentication for the MedCAT Trainer. To do so, you must configure the following environment variables:
79+
80+
| Variable | Used by | Description |
81+
|-----------------------------------------|-------------------------|----------------------------------------------------------------|
82+
| USE_OIDC | Backend | Enable OIDC login flow (1 (true) / 0 (false)). |
83+
| VITE_USE_OIDC | Frontend | Exposed version of USE_OIDC for Vue. |
84+
| VITE_API_URL | Frontend | Base API URL for frontend calls. |
85+
| VITE_KEYCLOAK_URL | Frontend | Keycloak base URL (e.g. http://keycloak.cogstack.localhost/). |
86+
| VITE_KEYCLOAK_REALM | Frontend | Keycloak realm name. |
87+
| VITE_KEYCLOAK_CLIENT_ID | Frontend | Keycloak client ID for this app. |
88+
| VITE_KEYCLOAK_TOKEN_REFRESH_INTERVAL_MS | Frontend | Token refresh frequency in ms. |
89+
| VITE_KEYCLOAK_TOKEN_MIN_VALIDITY_SECS | Frontend | Minimum token validity before refresh. |
90+
| VITE_LOGOUT_REDIRECT_URI | Frontend | Where to send user after logout. |
91+
| NGINX_HOST | Backend | Host alias used by reverse proxy (Traefik ) |
92+
93+
You can either use the Gateway Auth stack available in cogstack-ops or deploy your own Keycloak instance.
94+
If you deploy your own Keycloak instance, make sure to configure the network accordingly.
95+
96+
Currently, there are two roles that can be assigned to users:
97+
- medcattrainer_superuser: grants superuser privileges in the application.
98+
- medcattrainer_staff: grants staff-level privileges without full superuser access.
99+
76100
### (Optional) Postgres Database Support
77101
MedCAT trainer defaults to a local SQLite database, which is suitable for single-user or small-scale setups.
78102

medcat-trainer/docs/project_admin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Creating an Annotation Project
44
Annotation projects are used to inspect, validate and improve concepts recognised & linked by MedCAT.
5-
They can also be used collect annotations for defined MetaCAT models tasks, and coming soon RelCAT, or relation annotation models.
5+
They can also be used to collect annotations for defined MetaCAT models tasks, and coming soon RelCAT, or relation annotation models.
66

77
Using the admin page, a configured admin or superuser can create, edit and delete annotation projects.
88

medcat-trainer/envs/env

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,14 @@ [email protected]
4444
EMAIL_PASS="to be changed"
4545
EMAIL_HOST=mail.cogstack.org
4646
EMAIL_PORT=465
47+
48+
# Backend auth
49+
USE_OIDC=
50+
51+
# Traefik
52+
NGINX_HOST=medcattrainer.cogstack.localhost
53+
54+
# OIDC settings
55+
OIDC_HOST=http://keycloak:8080
56+
OIDC_REALM=cogstack-realm
57+
OIDC_FRONTEND_CLIENT_ID=cogstack-medcattrainer-frontend
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from django.contrib.auth import get_user_model
2+
import secrets
3+
4+
def get_user_by_email(request, id_token):
5+
"""
6+
Resolve or create a Django user using the email claim from OIDC.
7+
"""
8+
User = get_user_model()
9+
email = id_token.get('email')
10+
username = id_token.get('preferred_username')
11+
print(id_token)
12+
roles = []
13+
if 'realm_access' in id_token:
14+
roles = id_token['realm_access'].get('roles', [])
15+
16+
is_superuser = 'medcattrainer_superuser' in roles
17+
is_staff = 'medcattrainer_staff' in roles
18+
19+
user, created = User.objects.get_or_create(
20+
email=email,
21+
defaults={
22+
"username": username,
23+
"first_name": id_token.get("given_name", ""),
24+
"last_name": id_token.get("family_name", ""),
25+
"is_active": True,
26+
"password": secrets.token_urlsafe(32),
27+
},
28+
)
29+
30+
user.username = username
31+
user.first_name = id_token.get("given_name", "")
32+
user.last_name = id_token.get("family_name", "")
33+
user.is_superuser = is_superuser
34+
user.is_staff = is_staff
35+
36+
user.save()
37+
return user

medcat-trainer/webapp/api/api/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import traceback
23
from smtplib import SMTPException
34
from tempfile import NamedTemporaryFile
@@ -223,7 +224,6 @@ def post(self, request, *args, **kwargs):
223224
Please visit https://medcattrainer.readthedocs.io for more information to resolve this. <br>
224225
You can also ask a question at: https://discourse.cogstack.org/c/medcat/5''')
225226

226-
227227
@api_view(http_method_names=['GET'])
228228
def get_anno_tool_conf(_):
229229
return Response({k: v for k, v in os.environ.items()})

medcat-trainer/webapp/api/core/settings.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151

5252
APPEND_SLASH = True
5353

54+
USE_OIDC = os.getenv('USE_OIDC', '').lower() == '1'
55+
5456
# Application definition
5557

5658
INSTALLED_APPS = [
@@ -197,6 +199,38 @@
197199
]
198200
}
199201

202+
if USE_OIDC:
203+
log.info("Using OIDC authentication")
204+
REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] = [
205+
'oidc_auth.authentication.JSONWebTokenAuthentication',
206+
'oidc_auth.authentication.BearerTokenAuthentication',
207+
]
208+
209+
OIDC_HOST = os.environ.get("OIDC_HOST", "")
210+
OIDC_REALM = os.environ.get("OIDC_REALM", "")
211+
OIDC_FRONTEND_CLIENT_ID = os.environ.get("OIDC_FRONTEND_CLIENT_ID", "")
212+
213+
OIDC_AUTH = {
214+
'OIDC_ENDPOINT': f"{OIDC_HOST}/realms/{OIDC_REALM}",
215+
'OIDC_CLAIMS_OPTIONS': {
216+
'aud': {
217+
'values': [
218+
'account',
219+
OIDC_FRONTEND_CLIENT_ID
220+
],
221+
'essential': True,
222+
},
223+
'iss': {
224+
'values': [
225+
f"{OIDC_HOST}/realms/{OIDC_REALM}"
226+
],
227+
'essential': True,
228+
},
229+
},
230+
'USERINFO_ENDPOINT': f"{OIDC_HOST}/realms/{OIDC_REALM}/protocol/openid-connect/userinfo",
231+
'OIDC_CREATE_USER': True,
232+
'OIDC_RESOLVE_USER_FUNCTION': 'api.oidc_utils.get_user_by_email',
233+
}
200234

201235
# Internationalization
202236
# https://docs.djangoproject.com/en/2.2/topics/i18n/
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Override this with your .env.production
2+
# Frontend auth settings
3+
VITE_USE_OIDC=0
4+
VITE_KEYCLOAK_URL=http://keycloak.cogstack.localhost/
5+
VITE_KEYCLOAK_REALM=cogstack-realm
6+
VITE_KEYCLOAK_CLIENT_ID=cogstack-medcattrainer-frontend
7+
VITE_KEYCLOAK_TOKEN_REFRESH_INTERVAL_MS=10000
8+
VITE_KEYCLOAK_TOKEN_MIN_VALIDITY_SECS=30
9+
VITE_LOGOUT_REDIRECT_URI=http://home.cogstack.localhost/

0 commit comments

Comments
 (0)