diff options
author | Freya Murphy <freya@freyacat.org> | 2024-05-27 00:29:36 -0400 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2024-05-27 00:29:36 -0400 |
commit | cb9d1193c37b7567dcad5497330169d43ab1e8a2 (patch) | |
tree | 41fea58928d5d4cf87306458114f5465b6620711 | |
download | ldap_forwardauth-cb9d1193c37b7567dcad5497330169d43ab1e8a2.tar.gz ldap_forwardauth-cb9d1193c37b7567dcad5497330169d43ab1e8a2.tar.bz2 ldap_forwardauth-cb9d1193c37b7567dcad5497330169d43ab1e8a2.zip |
initial
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | build/nginx/Dockerfile | 21 | ||||
-rw-r--r-- | build/php/Dockerfile | 16 | ||||
-rw-r--r-- | conf/ldap/ldap.env | 9 | ||||
-rw-r--r-- | conf/nginx/nginx.conf | 50 | ||||
-rw-r--r-- | docker-compose.yml | 21 | ||||
-rw-r--r-- | src/public/bg.jpg | bin | 0 -> 425136 bytes | |||
-rw-r--r-- | src/public/main.css | 70 | ||||
-rw-r--r-- | src/web/helpers/auth.php | 59 | ||||
-rw-r--r-- | src/web/helpers/ldap.php | 41 | ||||
-rw-r--r-- | src/web/index.php | 66 | ||||
-rw-r--r-- | src/web/views/footer.php | 4 | ||||
-rw-r--r-- | src/web/views/header.php | 13 | ||||
-rw-r--r-- | src/web/views/login.php | 22 | ||||
-rw-r--r-- | src/web/views/message.php | 1 |
15 files changed, 394 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1269488 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +data diff --git a/build/nginx/Dockerfile b/build/nginx/Dockerfile new file mode 100644 index 0000000..6aa4e00 --- /dev/null +++ b/build/nginx/Dockerfile @@ -0,0 +1,21 @@ +FROM alpine:3.19 + +# install packages +RUN apk add --no-cache nginx shadow tini +RUN rm -fr /var/cache/apk/* + +# update nginx user +RUN groupmod --gid 1000 nginx +RUN usermod --uid 1000 nginx + +# remove build packages +RUN apk del shadow + +# make log syms +RUN ln -sf /dev/stdout /var/log/nginx/access.log && \ + ln -sf /dev/stderr /var/log/nginx/error.log + +# do the +USER nginx +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["/usr/sbin/nginx", "-c", "/etc/nginx/nginx.conf"] diff --git a/build/php/Dockerfile b/build/php/Dockerfile new file mode 100644 index 0000000..252e516 --- /dev/null +++ b/build/php/Dockerfile @@ -0,0 +1,16 @@ +FROM php:fpm-alpine + +# install packages +RUN apk add --no-cache runuser shadow openldap-dev +RUN rm -fr /var/cache/apk/* + +# update php user +RUN groupmod --gid 1000 www-data +RUN usermod --uid 1000 www-data + +# install php packages +RUN docker-php-ext-install ldap + +# remove build packages +RUN apk del shadow +USER www-data diff --git a/conf/ldap/ldap.env b/conf/ldap/ldap.env new file mode 100644 index 0000000..f387147 --- /dev/null +++ b/conf/ldap/ldap.env @@ -0,0 +1,9 @@ + +LDAP_URL= +LDAP_BIND_DN= +LDAP_BIND_PASSWORD= +LDAP_BASE_DN= +LDAP_FILTER="(&)" +LDAP_UID="cn" + +HTTP_HOST=auth.example.com diff --git a/conf/nginx/nginx.conf b/conf/nginx/nginx.conf new file mode 100644 index 0000000..ae17eba --- /dev/null +++ b/conf/nginx/nginx.conf @@ -0,0 +1,50 @@ +worker_processes 4; +daemon off; +pid /tmp/nginx.pid; +error_log /var/log/nginx/error.log; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 70; + server_tokens off; + client_max_body_size 2m; + + access_log /var/log/nginx/access.log; + + server { + listen 8080; + root /opt/website; + + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml image/x-icon; + + location /favicon.ico { + add_header Cache-Control "public, max-age=31536000, immutable"; + root /opt/website/public/icons; + } + + location /public { + add_header Cache-Control "public, max-age=31536000, immutable"; + try_files $uri =404; + } + + location / { + add_header Content-Security-Policy "script-src 'none'; object-src 'none'; base-uri 'none'"; + root /opt/website/web; + include fastcgi_params; + fastcgi_pass php:9000; + fastcgi_param SCRIPT_FILENAME $document_root/index.php; + } + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8c35bad --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +services: + + web: + build: ./build/nginx + restart: unless-stopped + ports: + - '80:8080' + volumes: + - ./src:/opt/website:ro + - ./conf/nginx/nginx.conf:/etc/nginx/nginx.conf:ro + depends_on: + - php + + php: + build: ./build/php + restart: unless-stopped + env_file: + - ./conf/ldap/ldap.env + volumes: + - ./src:/opt/website:ro + - ./data/session:/var/lib/php/session diff --git a/src/public/bg.jpg b/src/public/bg.jpg Binary files differnew file mode 100644 index 0000000..98ef823 --- /dev/null +++ b/src/public/bg.jpg diff --git a/src/public/main.css b/src/public/main.css new file mode 100644 index 0000000..058a49e --- /dev/null +++ b/src/public/main.css @@ -0,0 +1,70 @@ + +:root { + --blue: rgb(0, 102, 204); +} + +* { + box-sizing: border-box; +} + +html, body { + height: 100%; + padding: 0; + margin: 0; +} + +body { + display: flex; + justify-content: center; + background: #898989; + background-image: url('./bg.jpg'); + background-size: 100%; + background-position: 50% 50%; + color: #fff; + font-family: "Open Sans", Helvetica, Arial, sans-serif; + font-weight: 100; + font-size: 12px; +} + +main { + margin-top: 20vh; + height: fit-content; + width: 400px; + background: #fff; + color: #000; +} + +main .heading { + border-top: 5px solid var(--blue); + font-size: 1.5rem; + text-align: center; + padding: 10px; +} + +main .content { + padding: 10px; +} + +main .content, form { + display: flex; + flex-direction: column; +} + +main label, +main #submit { + margin-top: 10px; +} + +main input { + border: 1px solid #ddd; + outline: none; + padding: 7px; + font-size: 14px; + border-bottom-color: black; +} + +main #submit { + background: var(--blue); + color: white; + cursor: pointer; +} diff --git a/src/web/helpers/auth.php b/src/web/helpers/auth.php new file mode 100644 index 0000000..7aa4aff --- /dev/null +++ b/src/web/helpers/auth.php @@ -0,0 +1,59 @@ +<?php /* Copyright (c) 2024 Freya Murphy */ + +$keys = array(); + +function load_key($key) { + $file = "/tmp/$key"; + if (!file_exists($file)) + return FALSE; + $content = explode("\n", file_get_contents($file)); + return array( + 'user' => $content[0], + 'time' => $content[1] + ); +} + +function store_key($key, $user) { + $file = "/tmp/$key"; + $now = (string)time(); + $content = "$user\n{$now}"; + file_put_contents($file, $content, LOCK_EX); +} + +function get_random($n) +{ + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $randomString = ''; + + for ($i = 0; $i < $n; $i++) { + $index = rand(0, strlen($characters) - 1); + $randomString .= $characters[$index]; + } + + return $randomString; +} + +function key_auth() { + if (!isset($_SESSION['auth'])) { + return FALSE; + } + $key = $_SESSION['auth']; + $data = load_key($key); + if ($data === FALSE) { + return FALSE; + } + $user = $data['user']; + $time = $data['time']; + $now = time(); + if ($time > $now || $now - $time > 60 * 60 * 24) { + return FALSE; + } + store_key($key, $user); + return $user; +} + +function key_new($user) { + $key = get_random(128); + store_key($key, $user); + $_SESSION['auth'] = $key; +} diff --git a/src/web/helpers/ldap.php b/src/web/helpers/ldap.php new file mode 100644 index 0000000..f3697cc --- /dev/null +++ b/src/web/helpers/ldap.php @@ -0,0 +1,41 @@ +<?php /* Copyright (c) 2024 Freya Murphy */ + +function ldap_auth($auth_username, $auth_password) { + $url = getenv("LDAP_URL"); + $bind = getenv("LDAP_BIND_DN"); + $password = getenv("LDAP_BIND_PASSWORD"); + $bound = getenv("LDAP_BASE_DN"); + $filter = getenv("LDAP_FILTER"); + $uid = getenv("LDAP_UID"); + + $conn = @ldap_connect($url); + if (!$conn) { + return NULL; + } + ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3); + + $bind_conn = @ldap_bind($conn, $bind, $password); + if (!$bind_conn) { + return NULL; + } + + $search = @ldap_search($conn, $bound, $filter); + + $info = @ldap_get_entries($conn, $search); + $user = NULL; + for ($i=0; $i<$info['count']; $i++) { + $user = $info[$i]; + if (!array_key_exists($uid, $user)) + continue; + if ($user[$uid][0] == $auth_username) + break; + } + + if ($user == NULL) { + return FALSE; + } + + $succ = @ldap_bind($conn, $user['dn'], $auth_password); + return !!$succ; +} + diff --git a/src/web/index.php b/src/web/index.php new file mode 100644 index 0000000..ffd6b06 --- /dev/null +++ b/src/web/index.php @@ -0,0 +1,66 @@ +<?php /* Copyright (c) 2024 Freya Murphy */ + +ini_set('html_errors', '1'); + +$webroot = dirname(__FILE__); +$publicroot = realpath(dirname(__FILE__) . '/../public'); + +// load stuff +require($webroot . '/helpers/ldap.php'); +require($webroot . '/helpers/auth.php'); + +// start session +session_set_cookie_params( + 60 * 60 * 24, // lifetime (seconds), + '/', // path + NULL, // domain, + TRUE, // secure, + TRUE // http only +); +session_start(); + +function page($file, $data = array()) { + extract($data); + $webroot = $GLOBALS['webroot']; + require($webroot . '/views/header.php'); + require($webroot . "/views/$file.php"); + require($webroot . '/views/footer.php'); +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + parse_str(file_get_contents('php://input'), $post); + $res = ldap_auth($post['username'], $post['password']); + $msg = ''; + $title = ''; + if ($res) { + $msg = 'Authenticated. You can now go back to your content'; + $title = 'Success'; + key_new($post['username']); + } else { + $msg = 'Invalid Credentials'; + $title = 'Error'; + } + page('message', array( + 'title' => $title, + 'msg' => $msg + )); +} else { + if (($user = key_auth())) { + http_response_code(200); + header("X-Webauth-User: $user"); + die(); + } + + $host = $_SERVER['HTTP_HOST']; + $env = getenv("HTTP_HOST"); + if ($host != $env) { + // we are being forwarded authed + // redirect + http_response_code(301); + header("Location: https://$env"); + } else { + page('login', array( + 'title' => 'Login' + )); + } +} diff --git a/src/web/views/footer.php b/src/web/views/footer.php new file mode 100644 index 0000000..eb7ee28 --- /dev/null +++ b/src/web/views/footer.php @@ -0,0 +1,4 @@ +<?php /* Copyright (c) 2024 Freya Murphy */ ?> + </main> + </body> +</html> diff --git a/src/web/views/header.php b/src/web/views/header.php new file mode 100644 index 0000000..c0a0487 --- /dev/null +++ b/src/web/views/header.php @@ -0,0 +1,13 @@ +<?php /* Copyright (c) 2024 Freya Murphy */ ?> +<!DOCTYPE html> +<html> + <head> + <link href="//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700&subset=latin" rel="stylesheet"> + <link rel="stylesheet" href="/public/main.css"> + </head> + <body> + <main id="main" role="main"> + <div class="heading"> + <span><?=$title?></span> + </div> + <div class="content"> diff --git a/src/web/views/login.php b/src/web/views/login.php new file mode 100644 index 0000000..98d69af --- /dev/null +++ b/src/web/views/login.php @@ -0,0 +1,22 @@ +<?php /* Copyright (c) 2024 Freya Murphy */ ?> +<form method="post"> +<label for="username">Username</label> +<input + type="text" + id="username" + name="username" + autofocus="true" +> +<label fot="password">Password</label> +<input + type="password" + id="password" + name="password" +> +<input + type="submit" + role="button" + id="submit" + value="Sign In" +> +<form> diff --git a/src/web/views/message.php b/src/web/views/message.php new file mode 100644 index 0000000..a071409 --- /dev/null +++ b/src/web/views/message.php @@ -0,0 +1 @@ +<center><?=$msg?></center> |