From 9b10d099b61554625b0f293346a0aa7cd0281ab2 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Wed, 24 Feb 2021 21:24:45 +0100 Subject: [PATCH] WIP: new user management and authentication system, use go 1.16 embed --- Dockerfile | 4 +- Makefile | 2 - README-RASPBERRYPI.md | 2 +- README.md | 23 +- assets/css/custom.css | 10 + assets/img/favicon-large.png | Bin 0 -> 18346 bytes assets/img/favicon.ico | Bin 0 -> 101544 bytes assets/img/favicon.png | Bin 0 -> 6230 bytes assets/tpl/admin_create_clients.html | 2 +- assets/tpl/admin_edit_user.html | 87 +++++ assets/tpl/admin_index.html | 31 +- assets/tpl/admin_user_index.html | 67 ++++ assets/tpl/index.html | 61 +++- assets/tpl/prt_nav.html | 17 +- assets/tpl/user_index.html | 23 +- efs.go | 12 + go.mod | 7 +- internal/authentication/provider.go | 31 ++ .../authentication/providers/ldap/provider.go | 203 +++++++++++ .../providers/password/provider.go | 186 ++++++++++ internal/authentication/user.go | 11 + internal/common/configuration.go | 51 ++- internal/ldap/authentication.go | 94 ----- internal/ldap/config.go | 27 ++ internal/ldap/ldap.go | 115 +++++- internal/ldap/usercache.go | 338 ------------------ internal/server/auth.go | 83 +++++ internal/server/core.go | 247 +++++++------ internal/server/handlers_auth.go | 128 ++++--- internal/server/handlers_common.go | 106 +++--- internal/server/handlers_interface.go | 40 +-- internal/server/handlers_peer.go | 90 ++--- internal/server/handlers_user.go | 269 ++++++++++++++ internal/server/helper.go | 93 ++--- internal/server/ldapsync.go | 150 +++++++- .../server/{usermanager.go => peermanager.go} | 158 ++++---- internal/server/routes.go | 30 +- internal/users/config.go | 17 + internal/users/manager.go | 263 ++++++++++++++ internal/users/user.go | 36 ++ 40 files changed, 2161 insertions(+), 953 deletions(-) create mode 100644 assets/img/favicon-large.png create mode 100644 assets/img/favicon.ico create mode 100644 assets/img/favicon.png create mode 100644 assets/tpl/admin_edit_user.html create mode 100644 assets/tpl/admin_user_index.html create mode 100644 efs.go create mode 100644 internal/authentication/provider.go create mode 100644 internal/authentication/providers/ldap/provider.go create mode 100644 internal/authentication/providers/password/provider.go create mode 100644 internal/authentication/user.go delete mode 100644 internal/ldap/authentication.go create mode 100644 internal/ldap/config.go delete mode 100644 internal/ldap/usercache.go create mode 100644 internal/server/auth.go create mode 100644 internal/server/handlers_user.go rename internal/server/{usermanager.go => peermanager.go} (79%) create mode 100644 internal/users/config.go create mode 100644 internal/users/manager.go create mode 100644 internal/users/user.go diff --git a/Dockerfile b/Dockerfile index 99154a2..05442d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ######- # Start from the latest golang base image as builder image (only used to compile the code) ######- -FROM golang:1.15 as builder +FROM golang:1.16 as builder RUN mkdir /build @@ -29,7 +29,7 @@ FROM debian:buster ENV TZ=Europe/Vienna # GOSS for container health checks -ENV GOSS_VERSION v0.3.14 +ENV GOSS_VERSION v0.3.16 RUN apt-get update && apt-get upgrade -y && \ apt-get install --no-install-recommends -y moreutils ca-certificates curl && \ rm -rf /var/cache/apt /var/lib/apt/lists/*; \ diff --git a/Makefile b/Makefile index 474d287..5265ea1 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,10 @@ IMAGE=h44z/wg-portal all: dep build build: dep $(addsuffix -amd64,$(addprefix $(BUILDDIR)/,$(BINARIES))) - cp -r assets $(BUILDDIR) cp scripts/wg-portal.service $(BUILDDIR) cp scripts/wg-portal.env $(BUILDDIR) build-cross-plat: dep build $(addsuffix -arm,$(addprefix $(BUILDDIR)/,$(BINARIES))) $(addsuffix -arm64,$(addprefix $(BUILDDIR)/,$(BINARIES))) - cp -r assets $(BUILDDIR) cp scripts/wg-portal.service $(BUILDDIR) cp scripts/wg-portal.env $(BUILDDIR) diff --git a/README-RASPBERRYPI.md b/README-RASPBERRYPI.md index fdaadf4..4278163 100644 --- a/README-RASPBERRYPI.md +++ b/README-RASPBERRYPI.md @@ -10,7 +10,7 @@ use the following instructions: ### Building This section describes how to build the WireGuard Portal code. To compile the final binary, use the Makefile provided in the repository. -As WireGuard Portal is written in Go, **golang >= 1.14** must be installed prior to building. +As WireGuard Portal is written in Go, **golang >= 1.16** must be installed prior to building. ``` make build-cross-plat diff --git a/README.md b/README.md index e4fd3f0..07fe303 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,13 @@ ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/h44z/wg-portal) [![Docker Pulls](https://img.shields.io/docker/pulls/h44z/wg-portal.svg)](https://hub.docker.com/r/h44z/wg-portal/) -A simple web base configuration portal for [WireGuard](https://wireguard.com). +A simple, web based configuration portal for [WireGuard](https://wireguard.com). The portal uses the WireGuard [wgctrl](https://github.com/WireGuard/wgctrl-go) library to manage the VPN interface. This allows for seamless activation or deactivation of new users, without disturbing existing VPN connections. -The configuration portal is designed to use LDAP (Active Directory) as a user source for authentication and profile data. -It still can be used without LDAP by using a predefined administrator account. Some features like mass creation of accounts -will only be available in combination with LDAP. +The configuration portal currently supports using SQLite, MySQL as a user source for authentication and profile data. +It also supports LDAP (Active Directory or OpenLDAP) as authentication provider. ## Features * Self-hosted and web based @@ -24,18 +23,19 @@ will only be available in combination with LDAP. * Enable / Disable clients seamlessly * Generation of `wgX.conf` after any modification * IPv6 ready - * User authentication (LDAP and/or predefined admin account) + * User authentication (SQLite/MySQL and LDAP) * Dockerized * Responsive template + * One single binary ![Screenshot](screenshot.png) ## Setup ### Docker -The easiest way to run WireGuard Portal is using the provided docker image. +The easiest way to run WireGuard Portal is to use the Docker image provided. -Docker compose snippet with sample values: +Docker Compose snippet with some sample configuration values: ``` version: '3.6' services: @@ -56,19 +56,20 @@ services: - WEBSITE_TITLE=WireGuard VPN - COMPANY_NAME=Your Company Name - MAIL_FROM=WireGuard VPN - - ADMIN_USER=admin # optional admin user + - ADMIN_USER=admin@domain.com - ADMIN_PASS=supersecret - - ADMIN_LDAP_GROUP=CN=WireGuardAdmins,OU=Users,DC=COMPANY,DC=LOCAL - EMAIL_HOST=10.10.10.10 - EMAIL_PORT=25 + - LDAP_ENABLED=true - LDAP_URL=ldap://srv-ad01.company.local:389 - LDAP_BASEDN=DC=COMPANY,DC=LOCAL - LDAP_USER=ldap_wireguard@company.local - LDAP_PASSWORD=supersecretldappassword + - LDAP_ADMIN_GROUP=CN=WireGuardAdmins,OU=Users,DC=COMPANY,DC=LOCAL ``` Please note that mapping ```/etc/wireguard``` to ```/etc/wireguard``` inside the docker, will erase your host's current configuration. If needed, please make sure to backup your files from ```/etc/wireguard```. -For a full list of configuration options take a look at the source file [internal/common/configuration.go](internal/common/configuration.go). +For a full list of configuration options take a look at the source file [internal/common/configuration.go](internal/common/configuration.go#L57). ### Standalone For a standalone application, use the Makefile provided in the repository to build the application. @@ -80,7 +81,7 @@ make make build-cross-plat ``` -The compiled binary and all necessary assets will be located in the dist folder. +The compiled binary will be located in the dist folder. A detailed description for using this software with a raspberry pi can be found in the [README-RASPBERRYPI.md](README-RASPBERRYPI.md). ## What is out of scope diff --git a/assets/css/custom.css b/assets/css/custom.css index 6bc0d62..f450dbb 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -40,6 +40,16 @@ pre{background:#f7f7f9}iframe{overflow:hidden;border:none}@media (min-width: 768 /* -------------------------------------------------- End collapsable table*/ +.jumbotron-home { + padding: 1rem 1rem; +} + +@media (min-width: 576px) { + .jumbotron-home { + padding: 2rem 2rem; + } +} + @media (min-width: 1440px) { .container, .container-lg, .container-md, .container-sm, .container-xl { max-width: 1400px; diff --git a/assets/img/favicon-large.png b/assets/img/favicon-large.png new file mode 100644 index 0000000000000000000000000000000000000000..ab037748917fc73aaf67a33afd15ec2e64a15d68 GIT binary patch literal 18346 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 literal 0 HcmV?d00001 diff --git a/assets/img/favicon.png b/assets/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..653984682f4f19f468dbc177b0cc663d4f4ffd23 GIT binary patch literal 6230 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 literal 0 HcmV?d00001 diff --git a/assets/tpl/admin_create_clients.html b/assets/tpl/admin_create_clients.html index fab3dec..ea233ce 100644 --- a/assets/tpl/admin_create_clients.html +++ b/assets/tpl/admin_create_clients.html @@ -53,7 +53,7 @@ } }).tokenfield({ autocomplete: { - source: [{{range $i, $u :=.Users}}{{$u.Mail}},{{end}}], + source: [{{range $i, $u :=.Users}}{{$u.Email}},{{end}}], delay: 100 }, showAutocompleteOnFocus: false diff --git a/assets/tpl/admin_edit_user.html b/assets/tpl/admin_edit_user.html new file mode 100644 index 0000000..97729b0 --- /dev/null +++ b/assets/tpl/admin_edit_user.html @@ -0,0 +1,87 @@ + + + + + + {{ .Static.WebsiteTitle }} - Users + + + + + + + +{{template "prt_nav.html" .}} +
+ {{if eq .User.CreatedAt .Epoch}} +

Create a new user

+ {{else}} +

Edit user {{.User.Email}}

+ {{end}} + + {{template "prt_flashes.html" .}} + +
+ {{if eq .User.CreatedAt .Epoch}} +
+
+ + +
+
+ {{else}} + + {{end}} +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+ + +
+
+ + +
+
+
+ + + Cancel +
+
+{{template "prt_footer.html" .}} + + + + + + + \ No newline at end of file diff --git a/assets/tpl/admin_index.html b/assets/tpl/admin_index.html index 40edc5e..7e7afd3 100644 --- a/assets/tpl/admin_index.html +++ b/assets/tpl/admin_index.html @@ -84,13 +84,11 @@
-

Current VPN Users

+

Current VPN Peers

- {{if not .Static.LdapDisabled}} - - {{end}} - M + + M
@@ -98,11 +96,11 @@ - Identifier - Public Key - E-Mail - IP's - Handshake + Identifier + Public Key + E-Mail + IP's + Handshake @@ -144,15 +142,14 @@

User details

- {{if not $p.LdapUser}} -

No LDAP user-information available...

+ {{if not $p.User}} +

No user information available...

{{else}}
    -
  • Firstname: {{$p.LdapUser.Firstname}}
  • -
  • Lastname: {{$p.LdapUser.Lastname}}
  • -
  • Phone: {{index $p.LdapUser.RawLdapData.Attributes "telephoneNumber"}}
  • -
  • Mail: {{$p.LdapUser.Mail}}
  • -
  • Department: {{index $p.LdapUser.RawLdapData.Attributes "department"}}
  • +
  • Firstname: {{$p.User.Firstname}}
  • +
  • Lastname: {{$p.User.Lastname}}
  • +
  • Phone: {{$p.User.Phone}}
  • +
  • Mail: {{$p.User.Email}}
{{end}}

Connection / Traffic

diff --git a/assets/tpl/admin_user_index.html b/assets/tpl/admin_user_index.html new file mode 100644 index 0000000..6c431e8 --- /dev/null +++ b/assets/tpl/admin_user_index.html @@ -0,0 +1,67 @@ + + + + + + {{ .Static.WebsiteTitle }} - Users + + + + + + + + {{template "prt_nav.html" .}} +
+

WireGuard VPN Users

+ {{template "prt_flashes.html" .}} +
+
+

All Users

+
+
+ M +
+
+
+ + + + + + + + + + + + + {{range $i, $u :=.Users}} + + + + + + + + + {{end}} + +
E-Mail Lastname Firstname Source Is Admin
{{$u.Email}}{{$u.Lastname}}{{$u.Firstname}}{{$u.Source}}{{if $u.IsAdmin}}True{{else}}False{{end}} + {{if eq $.Session.IsAdmin true}} + {{if eq $u.Source "db"}} + + {{end}} + {{end}} +
+

Currently listed users: {{len .Users}}

+
+
+ {{template "prt_footer.html" .}} + + + + + + + \ No newline at end of file diff --git a/assets/tpl/index.html b/assets/tpl/index.html index 1536271..f46a2eb 100644 --- a/assets/tpl/index.html +++ b/assets/tpl/index.html @@ -13,18 +13,69 @@ {{template "prt_nav.html" .}} -
+
{{template "prt_flashes.html" .}}

WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN.

+

More Information

+
+
+
+
WireGuard Installation
+
+

Installation

+

Installation instructions for client software can be found on the official WireGuard website.

+ Open Instructions +
+
+
+
+
+
About WireGuard
+
+

About

+

WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography.

+ More details +
+
+
+
+
+
About WireGuard Portal
+
+

WireGuard Portal

+

WireGuard Portal is a simple, web based configuration portal for WireGuard.

+ More details +
+
+
+
-

VPN Profiles and configuration

-

You can access your personal VPN configurations via your Userprofile: Open Userprofile

+
+

VPN Profiles

+

You can access and download your personal VPN configurations via your Userprofile.

+
+

To find all your configured profiles click on the button below.

+

+ Open My Profile +

+
+ + {{with eq $.Session.LoggedIn true}}{{with eq $.Session.IsAdmin true}} +
+

Administration Area

+

In the administration area you can manage WireGuard peers and the server interface as well as users that are allowed to log in to the WireGuard Portal.

+
+

To find all your configured profiles click on the button below.

+

+ Open WireGuard Administration + Open User Administration +

+
+ {{end}}{{end}} -

Client Software

-

Installation instructions for client software can be found on the official WireGuard website: https://www.wireguard.com/

{{template "prt_footer.html" .}} diff --git a/assets/tpl/prt_nav.html b/assets/tpl/prt_nav.html index 79178a5..6ab5d9b 100644 --- a/assets/tpl/prt_nav.html +++ b/assets/tpl/prt_nav.html @@ -7,19 +7,28 @@