Skip to content

Commit

Permalink
Got it work with oauth2proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
TobiasDeBruijn committed Jun 30, 2024
1 parent dedeb00 commit 7a607ba
Show file tree
Hide file tree
Showing 37 changed files with 541 additions and 152 deletions.
8 changes: 8 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,11 @@ services:
- "./tmp/espocrm:/var/www/html"
depends_on:
- mariadb-espocrm

nginx:
image: nginx
network_mode: "host"
volumes:
- "./localhost.pem:/etc/ssl/certs/ssl-cert-snakeoil.pem"
- "./localhost-key.pem:/etc/ssl/private/ssl-cert-snakeoil.key"
- "./nginx.conf:/etc/nginx/conf.d/default.conf:ro"
3 changes: 3 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Summary
- [Introduction](introduction.md)
- [Deploying](./deploy/index.md)
- [Configuration](./deploy/configuration.md)
- [OAuth2 Proxy](./deploy/oauth2_proxy.md)
- [OAuth2](oauth2/index.md)
- [Authorization](oauth2/authorization.md)
- [API](api/index.md)
Expand Down
19 changes: 19 additions & 0 deletions docs/src/deploy/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Configuration


## Default config file
```json
{{#include ../../../sample_config.json}}
```

## Environmental variables
```
CONFIG_PATH=<path to config.json>
```

## Available options
The following Rust structs define the layout of the configuration.
An example of how this translates to JSON can be found in the [sample config](#default-config-file)
```rust,noplayground
{{#include ../../../server/wilford/src/config.rs:config}}
```
1 change: 1 addition & 0 deletions docs/src/deploy/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Deployment Documentation
96 changes: 96 additions & 0 deletions docs/src/deploy/oauth2_proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# OAuth2 Proxy

Wilford supports running with [oauth2-proxy](https://oauth2-proxy.github.io/oauth2-proxy/).
Using oaut2-proxy together with Wilford and nginx, you can protect static resources without needing to modify them.

## OAuth2 Config
Sample docker-compose file for running oauth2-proxy.
Replace the `CLIENT_ID` and `CLIENT_SECRET` with the ID and Secret generated by Wilford. Use `REDIRECT_URL` as the Redirect URL in Wilford.
The `COOKIE_SECRET` should be a securely generated random string.
```yml
version: '3.2'
services:
oauth2_proxy:
image: quay.io/oauth2-proxy/oauth2-proxy
environment:
- "OAUTH2_PROXY_COOKIE_SECRET=VsZqXqHQzwdPUcEUDgNxmQvTRZ46DtlQr8q-HtomkL8="
- "OAUTH2_PROXY_COOKIE_SECURE=true"
- "OAUTH2_PROXY_COOKIE_DOMAIN=localhost"
- "OAUTH2_PROXY_CLIENT_ID=NuWrxroZbOuhBL2ufHx9zj0qKT6XXQRg"
- "OAUTH2_PROXY_CLIENT_SECRET=vwn0MqNbD9qAnvCbGns9sNtikWC7eTM2V7DIz85vcimtxm12"
- "OAUTH2_PROXY_OIDC_ISSUER_URL=https://localhost:8443"
- "OAUTH2_PROXY_REDIRECT_URL=https://localhost:8443/oauth2/callback"
- "OAUTH2_PROXY_PROVIDER=oidc"
- "OAUTH2_PROXY_EMAIL_DOMAINS=*"
- "OAUTH2_PROXY_OIDC_EMAIL_CLAIM=sub_email"
- "OAUTH2_PROXY_PROVIDER_DISPLAY_NAME=Koala"
- "OAUTH2_PROXY_CUSTOM_SIGN_IN_LOGO=-"
- "OAUTH2_PROXY_BANNER=<img src='https://public.svsticky.nl/logos/logo_outline_kleur.png'/>"
- "OAUTH2_PROXY_FOOTER=-"
network_mode: "host"
```
## Nginx auth_directive
Using this setup, you can use the nginx auth directive very easily:
```conf
location /secure {
auth_request /oauth2/auth;
error_page 401 =403 /oauth2/sign_in;
proxy_pass http://my-secure-backend;
}
```

## Localhost
The JWKS specification requires it be served over https. When working locally, this can be a bit of a pain.

### Generate certificates for localhost
Install the required tools:
```bash
sudo apt install -y libnss3-tools mkcert
```
Generate a CA cert:
```bash
mkcert --install
```

Generate SSL certificate for `localhost`, from the repository root:
```bash
mkcert localhost
```

### Oauth2-proxy
Add the following to the docker-compose file:
```yml
volumes:
- "/usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro"
- "/etc/ssl/certs:/etc/ssl/certs:ro"
```
### nginx
Use the following block for Wilford:
```conf
server {
listen 8443 ssl default_server;
server_name _;

ssl_certificate /etc/ssl/certs/ssl-cert-localhost.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-localhost.key;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:2521;
}
}
```
docker-compose:
```yml
nginx:
image: nginx
network_mode: "host"
volumes:
- "./localhost.pem:/etc/ssl/certs/ssl-cert-localhost.pem"
- "./localhost-key.pem:/etc/ssl/private/ssl-cert-localhost.key"
- "./nginx.conf:/etc/nginx/conf.d/default.conf:ro"
```
28 changes: 28 additions & 0 deletions localhost-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDsNbwWcAH2Dss+
GPSLZkO1gYb8SOFTbjSw/pXCVudZNiLbCPNWrALSLpgwLiXJQyQLwG40lL4jOOl1
+p4nKGYl/6zRpPLolvngQH+GVbUJbODiYLY/MqjVdMT3PX97qIKGpqb2zzcPHm2E
ntlTfh7RIHzlvej9zPpccG62a4w9C67oj7Bh+E274HQY96pPSw3eFcictXekPoxS
lIdVnOh+3uP4TI/MnKDrcn346FJqnQZD9AnwQ5B7x4oB+d9BrmMyzWyQqF1jNxbV
CTzoTeKoyqsdJzCuecLeCHN+soSuK2aM9d2Wx5Pb16VUYD8XKMjEYg72tYNrGx7a
whMQ189rAgMBAAECggEAWUmSmJSsWRuMfiOmxM7aR1D3+oN+ETB2YHVLnNOGzfUl
xdAjU57fzh1oz8WR6PslNAAAaIXVPbE0prEeeUTPIAv+gpysaXkwaTFYQypArZhn
hYrzOP5oTY+/KIopl0/CTy3NrTv03xUsZtY45lOlSH3UWG+qE84Y0Tp6zx/mOehn
qVyWC+klhbcYbJDh2bRcddJbYv7TbtHMLKpvIiM2As5mYeDJChDX1oBPRirabALs
gxfvY+NWw/DmL+Nn7QRL6Il6Mr5U5GGLYiRyRlnQHRGPaZ2OjNiRmmxsVYkKcFQ2
7XWkNl4kKKgA+plqryGKl47blRG0p2fNhADjTax9iQKBgQDt0L9QFEE5YlFWS9/o
wOg2DKKTkDUUnBBKlw0nbx58ygLb0VZaPCoWp/Mukxd7Lry6PBdSMXsIPIZnY+BP
52A3o1a0sy/ssmNL97CJmTyQbDNKoXWzY8W/Ra0m0R6nbnV/CoFhbHmQoZnB4TeP
41t/EIC+1u8CBUIoZOpo4Y+EhwKBgQD+RY8tAvqYpR0XaxgKhxPxSgbtXAH/6dvd
fVVhsUqtfdE4gFZbJmHXdC2vf1bKyHQ7D/g4rqpUe2aauDUSD57WObBfl1w7i/uR
3dAyUFEwme4KsJz5nS0fNQxZ/6+0MFEVtywe3w96Jr15RhltwKZSZxhZehxcnlvH
jpvESDr6/QKBgEFU23nQVqrBC789UOHMPP68Md1//FURGpijLoXqzOFTTb29oI9h
f96BfRkKZ6T7jfVLlMyLs1Tr67Bzi6fn1FL0mFlD8KKBzy2LegATDMRQNTcHbCJA
Ao8tQQgs4tL0UWr5I9nzxuGow2izymPI/dXGXtgOi9JuR2J5drwhWx/5AoGABdPW
SjPNRn5SQl0j+enKnTcTHZGEQjc74MGkmU6U5ZECoIbgc8pXZ7az7Ve/x3n8n/Xn
vHTUVodVfKpIHRfajhJYZnhzlrHInDk3MlAA7Fo6yGfv0RC3HgX7OHzRrBGHajX+
ft6h3izRHtxqbMeDiFPwjOxthfnjJJmyHDeDkokCgYEA68cGwARZoX1lyzcXGbfb
TwOxJc79TU+zhdQVH/aTI6hzMeTdoc2qT+yPU8qOgJkVoCBM/TaRrIhrpGy+Tf1o
P4Gw1qcJWNMRdg1ssdyKCueCIx+M7DdNPA578UhD5RgdiCUmu0ufLWdC5ZPVxv8c
fFo8K4Bc9wBn4W3UBsnBROc=
-----END PRIVATE KEY-----
26 changes: 26 additions & 0 deletions localhost.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
-----BEGIN CERTIFICATE-----
MIIEUjCCArqgAwIBAgIQAKAUPbumOzgi7b+DtrstqDANBgkqhkiG9w0BAQsFADCB
jTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMTEwLwYDVQQLDCh0b2Jp
YXNAdG9iaWFzLWRlc2t0b3AgKFRvYmlhcyBkZSBCcnVpam4pMTgwNgYDVQQDDC9t
a2NlcnQgdG9iaWFzQHRvYmlhcy1kZXNrdG9wIChUb2JpYXMgZGUgQnJ1aWpuKTAe
Fw0yNDA2MzAxMzQ3MzBaFw0yNjA5MzAxMzQ3MzBaMFwxJzAlBgNVBAoTHm1rY2Vy
dCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTExMC8GA1UECwwodG9iaWFzQHRvYmlh
cy1kZXNrdG9wIChUb2JpYXMgZGUgQnJ1aWpuKTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAOw1vBZwAfYOyz4Y9ItmQ7WBhvxI4VNuNLD+lcJW51k2ItsI
81asAtIumDAuJclDJAvAbjSUviM46XX6nicoZiX/rNGk8uiW+eBAf4ZVtQls4OJg
tj8yqNV0xPc9f3uogoampvbPNw8ebYSe2VN+HtEgfOW96P3M+lxwbrZrjD0LruiP
sGH4TbvgdBj3qk9LDd4VyJy1d6Q+jFKUh1Wc6H7e4/hMj8ycoOtyffjoUmqdBkP0
CfBDkHvHigH530GuYzLNbJCoXWM3FtUJPOhN4qjKqx0nMK55wt4Ic36yhK4rZoz1
3ZbHk9vXpVRgPxcoyMRiDva1g2sbHtrCExDXz2sCAwEAAaNeMFwwDgYDVR0PAQH/
BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFNFs6uYdWwV2
bmxT5oolJDjqSqCcMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsF
AAOCAYEAKMi6fznFFhcxHKl94lIW8WBuw8SwbtRCRmugl1UFjT9zHYijLdwSTcPs
1FTIBSskK8xZFWI4b+UQJDe6jZEhuYUHRownx9OYznPy2daBK2Mnh3u7Ni07d7R5
EomqHurTxVTxC0+hnV487zLpXDZr3Xz0Q9YORuHOYj2ayMUOrahp6aR2ppBWFTAB
bOgioBj9qcavx0YWC5P3WzljG/+G1x2KQQ5Q1zrxy2E4bxwAWpxXjIMvTWjDq/NQ
wD6NCAPbRVvBEM1rgBJ3chKAQqp5VQ3oebxPXyQDoUG/WCTVgBfmO9t6mUT7eONT
pbKRxSP6CGnIdhPFCscODs9CffcfNBznUFj886q2+3vwOnFa1uZCLdQ2i35wurxl
PffKLJS+oJyUpP9qXPY7BNzmodw6hQwLhk4Mv3IGUWJcgfuHkIlsLYkUv41G4BMJ
wHGKflYVCTU+GVeT/M4zP/W5yLM0k1h56s+qgd5d8vlXIvIBnEmV9Y9jcgCT8+Wz
kYkapOB2
-----END CERTIFICATE-----
39 changes: 39 additions & 0 deletions nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
server {
listen 8443 ssl default_server;
server_name _;

ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Auth-Request-Redirect $request_uri;
# or, if you are handling multiple domains:
# proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
}
location = /oauth2/auth {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Uri $request_uri;
# nginx auth_request includes headers but not body
proxy_set_header Content-Length "";
proxy_pass_request_body off;
}

location /docs {
auth_request /oauth2/auth;
error_page 401 =403 /oauth2/sign_in;
proxy_pass https://google.com;
}


location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:2521;
}
}
21 changes: 15 additions & 6 deletions oauth2_proxy.docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@ version: '3.2'
services:
oauth2_proxy:
image: quay.io/oauth2-proxy/oauth2-proxy
volumes:
- "/usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro"
- "/etc/ssl/certs:/etc/ssl/certs:ro"
environment:
- "OAUTH2_PROXY_COOKIE_SECRET=VsZqXqHQzwdPUcEUDgNxmQvTRZ46DtlQr8q-HtomkL8="
- "OAUTH2_PROXY_CLIENT_ID=Vy1l9P2X7RFf4jHfo3OiLHtShllSZKDa"
- "OAUTH2_PROXY_CLIENT_SECRET=d4HtCZLeZvRvldGOxQd18l5a46hZEl6WWoocL2IbkfcozLH6"
- "OAUTH2_PROXY_OIDC_ISSUER_URL=http://localhost:2521"
- "OAUTH2_PROXY_REDIRECT_URL=http://127.0.0.1:4180/oauth2/callback"
- "OAUTH2_PROXY_COOKIE_SECURE=true"
- "OAUTH2_PROXY_COOKIE_DOMAIN=localhost"
- "OAUTH2_PROXY_CLIENT_ID=NuWrxroZbOuhBL2ufHx9zj0qKT6XXQRg"
- "OAUTH2_PROXY_CLIENT_SECRET=vwn0MqNbD9qAnvCbGns9sNtikWC7eTM2V7DIz85vcimtxm12"
- "OAUTH2_PROXY_OIDC_ISSUER_URL=https://localhost:8443"
- "OAUTH2_PROXY_REDIRECT_URL=https://localhost:8443/oauth2/callback"
- "OAUTH2_PROXY_PROVIDER=oidc"
- "OAUTH2_PROXY_EMAIL_DOMAINS=*"
- "OAUTH2_PROXY_OIDC_JWKS_URL=http://localhost:2521/.well-known/jwks.json"
network_mode: "host"
- "OAUTH2_PROXY_OIDC_EMAIL_CLAIM=sub_email"
- "OAUTH2_PROXY_PROVIDER_DISPLAY_NAME=Koala"
- "OAUTH2_PROXY_CUSTOM_SIGN_IN_LOGO=-"
- "OAUTH2_PROXY_BANNER=<img src='https://public.svsticky.nl/logos/logo_outline_kleur.png'/>"
- "OAUTH2_PROXY_FOOTER=-"
network_mode: "host"
2 changes: 2 additions & 0 deletions server/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 10 additions & 9 deletions server/database/migrations/1_initial.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ CREATE TABLE oauth2_pending_authorizations (
client_id VARCHAR(32) NOT NULL,
scopes TEXT DEFAULT NULL,
state TEXT DEFAULT NULL,
espo_user_id TEXT DEFAULT NULL,
user_id TEXT DEFAULT NULL,
ty TEXT NOT NULL,
nonce TEXT DEFAULT NULL,
PRIMARY KEY (id)
Expand All @@ -23,15 +23,15 @@ CREATE TABLE oauth2_access_tokens (
client_id VARCHAR(32) NOT NULL,
expires_at BIGINT NOT NULL,
issued_at BIGINT NOT NULL,
espo_user_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64) NOT NULL,
scopes TEXT DEFAULT NULL,
PRIMARY KEY (token)
);

CREATE TABLE oauth2_refresh_tokens (
token VARCHAR(32) NOT NULL,
client_id VARCHAR(32) NOT NULL,
espo_user_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64) NOT NULL,
scopes TEXT DEFAULT NULL,
PRIMARY KEY (token)
);
Expand All @@ -41,22 +41,23 @@ CREATE TABLE oauth2_authorization_codes (
code VARCHAR(32) NOT NULL,
expires_at BIGINT NOT NULL,
scopes TEXT DEFAULT NULL,
espo_user_id TEXT NOT NULL,
user_id TEXT NOT NULL,
nonce TEXT DEFAULT NULL,
PRIMARY KEY (code)
);

CREATE TABLE users (
espo_user_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64) NOT NULL,
name TEXT NOT NULL,
is_espo_admin BOOL,
PRIMARY KEY (espo_user_id)
email TEXT NOT NULL,
is_admin BOOL,
PRIMARY KEY (user_id)
);

CREATE TABLE user_permitted_scopes (
espo_user_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64) NOT NULL,
scope VARCHAR(64) NOT NULL,
PRIMARY KEY (espo_user_id, scope)
PRIMARY KEY (user_id, scope)
);

CREATE TABLE constant_access_tokens (
Expand Down
5 changes: 5 additions & 0 deletions server/database/src/constant_access_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::driver::Database;
use crate::generate_string;
use sqlx::FromRow;
use sqlx::Result;
use tracing::instrument;

#[derive(Debug, Clone, FromRow)]
pub struct ConstantAccessToken {
Expand All @@ -14,6 +15,7 @@ impl ConstantAccessToken {
generate_string(32)
}

#[instrument]
pub async fn new(driver: &Database, name: String) -> Result<Self> {
let token = Self::generate_token();

Expand All @@ -26,12 +28,14 @@ impl ConstantAccessToken {
Ok(Self { name, token })
}

#[instrument]
pub async fn list(driver: &Database) -> Result<Vec<Self>> {
Ok(sqlx::query_as("SELECT * FROM constant_access_tokens")
.fetch_all(&**driver)
.await?)
}

#[instrument]
pub async fn get_by_token(driver: &Database, token: &str) -> Result<Option<Self>> {
Ok(
sqlx::query_as("SELECT * FROM constant_access_tokens WHERE token = ?")
Expand All @@ -41,6 +45,7 @@ impl ConstantAccessToken {
)
}

#[instrument]
pub async fn revoke(self, driver: &Database) -> Result<()> {
sqlx::query("DELETE FROM constant_access_tokens WHERE token = ?")
.bind(self.token)
Expand Down
Loading

0 comments on commit 7a607ba

Please sign in to comment.