Skip to content

Commit

Permalink
Merge pull request #319 from pkpdapp-team/https
Browse files Browse the repository at this point in the history
swap to ssl
  • Loading branch information
martinjrobins authored Dec 13, 2023
2 parents 5ccf881 + 000331c commit 2fcd299
Show file tree
Hide file tree
Showing 12 changed files with 352 additions and 236 deletions.
12 changes: 6 additions & 6 deletions .env.prod
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
PORT=8020
DEBUG=1
HOST_NAME=monkshood
SECRET_KEY=aLargeRandomSecretKey
EMAIL_HOST=in-v3.mailjet.com
EMAIL_PORT=25
EMAIL_HOST_USER=email_username
EMAIL_HOST_PASSWORD=email_password
DEFAULT_FROM_EMAIL=[email protected]
POSTGRES_PASSWORD=sekret2
DATABASE_URL=postgres://postgres:sekret2@postgres:5432/postgres

Expand All @@ -15,9 +9,15 @@ RABBITMQ_DEFAULT_PASS=guest

AUTH_LDAP_USE=0
AUTH_LDAP_SERVER_URI=ldap://ldap.forumsys.com:389

AUTH_LDAP_DIRECT_BIND=1
AUTH_LDAP_BIND_DN_TEMPLATE=uid=%(user)s,dc=example,dc=com

AUTH_LDAP_BIND_DN=cn=read-only-admin,dc=example,dc=com
AUTH_LDAP_BIND_PASSWORD=password
AUTH_LDAP_SEARCH_BASE=ou=mathematicians,dc=example,dc=com
AUTH_LDAP_SEARCH_FILTER=(uid=%(user)s)

AUTH_LDAP_GROUP_SEARCH=ou=groups,dc=example,dc=com
AUTH_LDAP_USER_GROUP=cn=user,ou=groups,dc=example,dc=com
AUTH_LDAP_ADMIN_GROUP=cn=admin,ou=groups,dc=example,dc=com
88 changes: 77 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,86 @@

PKPDApp is an open source web-based application to explore, analyse and model the pharmacokinetics and pharmacodynamics of chemical compounds. The app is currently under heavy development, however a preliminary version is being deployed with Heroku and can be found under https://pkpdapp.herokuapp.com/.

## Installation - production

Use these instructions for deploying the application in a production environment. Instructions for developers can be found below.

### `.env.prod` file

The configuration of the production application is stored in the `.env.prod` file. Edit this file and variables to correspond to your particular setup. The variables are described below:

- `DEBUG`: set to 0 for production
- `HOST_NAME`: the host name of the application
- `SECRET_KEY`: a large random string used for cryptographic signing
- `POSTGRES_PASSWORD`: password for postgres database specified in `docker-compose.yml` (not needed if using your own database)
- `DATABASE_URL`: URL of a postgres database (e.g. postgres://username:password@postgres:5432/postgres). Do not alter this if you are using the
postgres service in the `docker-compose.yml` file.

- `RABBITMQ_DEFAULT_USER`: username for rabbitmq server (optional)
- `RABBITMQ_DEFAULT_PASS`: password for rabbitmq server (optional)

The following variables are used for LDAP authentication (optional):

- `AUTH_LDAP_USE`: set to 1 to use LDAP authentication
- `AUTH_LDAP_SERVER_URI`: URI of LDAP server (e.g. ldap://ldap.forumsys.com:389)

For direct binding:

- `AUTH_LDAP_DIRECT_BIND`: set to 1 to bind directly to LDAP server (see [here](https://django-auth-ldap.readthedocs.io/en/latest/authentication.html#direct-bind)
- `AUTH_LDAP_BIND_DN_TEMPLATE`: template for direct binding (e.g. `uid=%(user)s,dc=example,dc=com`)

For search/bind, connecting to the LDAP server either anonymously or with a fixed account and searching for the distinguished name of the authenticating user.

- `AUTH_LDAP_BIND_DN`: distinguished name of an authorized user (e.g. `cn=read-only-admin,dc=example,dc=com`)
- `AUTH_LDAP_BIND_PASSWORD`: password for the authorized user
- `AUTH_LDAP_SEARCH_BASE`: where to perform the search (e.g. `ou=mathematicians,dc=example,dc=com`)
- `AUTH_LDAP_SEARCH_FILTER`: search filter based on authenticated username (`uid=%(user)s`)
- `AUTH_LDAP_USER_GROUP`: (optional) authentication will only succeed if user is in this LDAP group (e.g. `cn=user,ou=groups,dc=example,dc=com`). If not set, then any user in the search base will be authenticated.
- `AUTH_LDAP_ADMIN_GROUP`: (optional) user must be in this LDAP group to be a superuser (e.g. `cn=admin,ou=groups,dc=example,dc=com`). If not set, then no user will be a superuser.


### SSL Certificate

The application uses SSL certificates for HTTPS. You will need to supply your
own SSL certificate and key. These should be placed in the `.certs/` directory
in the root folder (this folder needs to be created) and named `pkpdapp.crt` and
`pkpdapp.key` respectively.

### PostgreSQL database

The application uses a PostgreSQL database. You can either supply your own
database and set the `DATABASE_URL` variable in the `.env.prod` file, or the
`docker-compose.yml` file contains a postgres service that can be used, along
with the `DATABASE_URL` variable already set in the `.env.prod` file.

If you are using your own database, you can delete the postgres service from the
`docker-compose.yml` file.

### Containers

The application is deployed using docker containers and docker-compose, so you will need to install these.

You can build a docker image and run the image inside the container with commands below (run these commands in the root directory of the repository):

```bash
$ docker-compose build
$ docker-compose up
```

You should be able to see the web application at [127.0.0.1](127.0.0.1).

To leave the container running in the background, use

```bash
$ docker-compose up -d
```

## Installation - development

If you are interested in developing PKPDApp with us, or just run the app locally, you can clone the repository and follow the installation instructions below.

NOTE: the current version of the frontend does not currently use the rabbitmq server, so you can skip the installation of rabbitmq for the moment (later iterations of the frontend will use the rabbitmq server).

### Django backend

1. Install sundials, python dev libraries and rabbitmq server
Expand Down Expand Up @@ -56,7 +132,7 @@ cd pkpdapp
python manage.py migrate
```

5. Run RabbitMQ
5. Run RabbitMQ (optional)

```bash
celery -A pkpdapp worker --loglevel=INFO
Expand Down Expand Up @@ -105,16 +181,6 @@ yarn start
You should be able to see the pkpd web app at [127.0.0.1:3000](127.0.0.1:3000).


## Installation - production

Alternatively you can build a docker image and run the image inside the container with commands below.

```bash
$ docker-compose build
$ docker-compose up
```

You should be able to see the web application at [127.0.0.1](127.0.0.1).

## Code testing

Expand Down
6 changes: 5 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ services:
dockerfile: Dockerfile
context: .
ports:
- "80:${PORT}"
- 443:443
- 80:80
volumes:
- ${PWD}/.certs/pkpdapp.key:/etc/ssl/pkpdapp.key
- ${PWD}/.certs/pkpdapp.crt:/etc/ssl/pkpdapp.crt
restart: unless-stopped
env_file:
- ./.env.prod
Expand Down
1 change: 1 addition & 0 deletions frontend-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dependencies": {
"@emotion/react": "^11.10.8",
"@emotion/styled": "^11.10.8",
"@fontsource/comfortaa": "^5.0.18",
"@mui/icons-material": "^5.11.16",
"@mui/material": "^5.12.2",
"@reduxjs/toolkit": "^1.8.1",
Expand Down
17 changes: 15 additions & 2 deletions frontend-v2/src/features/login/login.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import {
Button,
Expand All @@ -9,6 +9,8 @@ import {
CssBaseline,
Stack,
Alert,
FormControlLabel,
Checkbox,
} from "@mui/material";
import { ReactComponent as PkpdAppIcon } from "../../logo_pkpdapp_with_text.svg";
import TextField from "../../components/TextField";
Expand All @@ -35,7 +37,7 @@ const Login: React.FC<LoginProps> = ({ onLogin, isLoading, errorMessage }) => {
};

return (
<Container component="main" maxWidth="xs">
<Container component="main" maxWidth="sm">
<CssBaseline />
<form onSubmit={handleSubmit(onSubmit)}>
<Stack spacing={2} sx={{ marginTop: 10 }}>
Expand Down Expand Up @@ -68,6 +70,17 @@ const Login: React.FC<LoginProps> = ({ onLogin, isLoading, errorMessage }) => {
{errorMessage && <Alert severity="error">{errorMessage}</Alert>}
</Stack>
</form>
<Typography variant="caption" sx={{ marginTop: 2 }}>
I acknowledge that I am bound by confidentiality obligations imposed
through my employment or contractual agreement with Roche in connection
with my access to confidential information, including PKPD Explorer and
its contents. By entering PKPD Explorer, I confirm that I understand
that my activities within PKPD Explorer may be monitored consistent with
local law, and all contents and passwords are confidential information,
and that unauthorized disclosure or use of such confidential information
may result in disciplinary action including termination of my employment
or services and/or legal action based on local law."
</Typography>
</Container>
);
};
Expand Down
6 changes: 4 additions & 2 deletions frontend-v2/src/features/main/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import VaccinesIcon from "@mui/icons-material/Vaccines";
import SsidChartIcon from "@mui/icons-material/SsidChart";
import ContactSupportIcon from "@mui/icons-material/ContactSupport";
import TableViewIcon from "@mui/icons-material/TableView";
import "@fontsource/comfortaa"; // Defaults to weight 400


const drawerWidth = 240;

Expand Down Expand Up @@ -192,8 +194,8 @@ export default function Sidebar() {
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>
PK/PD Simulator {project && ` - ${project.name}`}
<Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1, fontFamily: "comfortaa" }}>
pkpd explorer{project && ` - ${project.name}`}
</Typography>
<IconButton onClick={() => dispatch(logout())} color="inherit">
<Logout />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const SimulationSliderView: React.FC<SimulationSliderProps> = ({
<Replay />
</IconButton>
</Tooltip>
<Tooltip title={"Save value as default"} placement="top">
<Tooltip title={"Save value to parameters"} placement="top">
<IconButton aria-label="save" onClick={handleSave}>
<Save />
</IconButton>
Expand Down
11 changes: 10 additions & 1 deletion frontend-v2/src/features/simulation/Simulations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const getSimulateInput = (
for (const plot of simulation?.plots || []) {
for (const y_axis of plot.y_axes) {
const variable = variables?.find((v) => v.id === y_axis.variable);
if (variable && !outputs.includes(variable.name)) {
if (variable && !outputs.includes(variable.qname)) {
outputs.push(variable.qname);
}
}
Expand All @@ -85,6 +85,15 @@ const getSimulateInput = (
(v) => v.name === "time" || v.name === "t",
);
outputs.push(timeVariable?.qname || "time");

// for some reason we need to ask for concentration or myokit produces a kink in the output
const alwaysAsk = ["PKCompartment.C1"];
for (const v of alwaysAsk) {
const variable = variables?.find((vv) => vv.qname === v);
if (variable && !outputs.includes(variable.qname)) {
outputs.push(variable.qname);
}
}
return {
variables: simulateVariables,
outputs,
Expand Down
9 changes: 9 additions & 0 deletions frontend-v2/src/features/trial/Protocols.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ const Protocols: React.FC = () => {
(protocol) => protocol.variables.length > 0,
);

// sort protocols alphabetically by name
filteredProtocols?.sort((a, b) => {
if (a.name < b.name) {
return -1;
} else {
return 1;
}
});

return (
<TableContainer>
<Table>
Expand Down
5 changes: 5 additions & 0 deletions frontend-v2/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,11 @@
resolved "https://registry.yarnpkg.com/@exodus/schemasafe/-/schemasafe-1.3.0.tgz#731656abe21e8e769a7f70a4d833e6312fe59b7f"
integrity sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==

"@fontsource/comfortaa@^5.0.18":
version "5.0.18"
resolved "https://registry.yarnpkg.com/@fontsource/comfortaa/-/comfortaa-5.0.18.tgz#3424c932dd8ac27f02ae568197c98686aa7d6767"
integrity sha512-0Goub97HAU4AsAZvR8x7C4uSmBqqkBBEf6m1wFzThZIy+dA6wyqUW8n7uKfElMPcc8ZemI5XMXslW5SdnNJa2Q==

"@hapi/hoek@^9.0.0":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
Expand Down
20 changes: 18 additions & 2 deletions nginx.default.template
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ upstream app_server {
}

server {
listen $PORT;
server_name pkpdapp.herokuapp.com;
listen 443 ssl;
server_name pkpdapp.com;
ssl_certificate /etc/ssl/pkpdapp.crt;
ssl_certificate_key /etc/ssl/pkpdapp.key;

# javascript frontend
location / {
Expand Down Expand Up @@ -58,6 +60,20 @@ server {
proxy_buffering off;
}

# or /static/admin
location /static/admin {
proxy_pass http://app_server/static/admin;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect http://app_server/static/admin $scheme://$http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_read_timeout 20d;
proxy_buffering off;
}

# or /backend -> /static
location /backend {
proxy_pass http://app_server/static;
Expand Down
Loading

0 comments on commit 2fcd299

Please sign in to comment.