From 8aee529519ca5e9499fdcd34db48a38298c8308c Mon Sep 17 00:00:00 2001 From: Alexis Aurin Date: Mon, 14 Mar 2022 17:25:05 +0100 Subject: [PATCH 1/2] Give the way to connect against LDAP server with certificate and key --- README.md | 23 ++++++++------- .../authentication/providers/ldap/provider.go | 29 ++++++++++++++++++- internal/ldap/config.go | 10 ++++--- internal/ldap/ldap.go | 29 ++++++++++++++++++- 4 files changed, 75 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d05d7d1b..269cc83a 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ ![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 based configuration portal for [WireGuard](https://wireguard.com). -The portal uses the WireGuard [wgctrl](https://github.com/WireGuard/wgctrl-go) library to manage existing VPN -interfaces. This allows for seamless activation or deactivation of new users, without disturbing existing VPN +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 existing VPN +interfaces. This allows for seamless activation or deactivation of new users, without disturbing existing VPN connections. The configuration portal currently supports using SQLite and MySQL as a user source for authentication and profile data. @@ -31,11 +31,11 @@ It also supports LDAP (Active Directory or OpenLDAP) as authentication provider. * Can be used with existing WireGuard setups * Support for multiple WireGuard interfaces * REST API for management and client deployment - + ![Screenshot](screenshot.png) ## Setup -Make sure that your host system has at least one WireGuard interface (for example wg0) available. +Make sure that your host system has at least one WireGuard interface (for example wg0) available. If you did not start up a WireGuard interface yet, take a look at [wg-quick](https://manpages.debian.org/unstable/wireguard-tools/wg-quick.8.en.html) in order to get started. ### Docker @@ -156,6 +156,9 @@ The following configuration options are available: | LDAP_ATTR_LASTNAME | attrLastname | ldap | sn | User lastname attribute. | | LDAP_ATTR_PHONE | attrPhone | ldap | telephoneNumber | User phone number attribute. | | LDAP_ATTR_GROUPS | attrGroups | ldap | memberOf | User groups attribute. | +| LDAP_CERT_CONN | ldapCertConn | ldap | false | Allow connection with certificate against LDAP server without user/password | +| LDAPTLS_CERT | ldapTlsCert | ldap | | The LDAP cert's path | +| LDAPTLS_KEY | ldapTlsKey | ldap | | The LDAP key's path | | LOG_LEVEL | | | debug | Specify log level, one of: trace, debug, info, off. | | LOG_JSON | | | false | Format log output as JSON. | | LOG_COLOR | | | true | Colorize log output. | @@ -190,7 +193,7 @@ email: user: test@gmail.com pass: topsecret wg: - devices: + devices: - wg0 - wg1 defaultDevice: wg0 @@ -199,8 +202,8 @@ wg: ``` ### RESTful API -WireGuard Portal offers a RESTful API to interact with. -The API is documented using OpenAPI 2.0, the Swagger UI can be found +WireGuard Portal offers a RESTful API to interact with. +The API is documented using OpenAPI 2.0, the Swagger UI can be found under the URL `http:///swagger/index.html?displayOperationId=true`. The [API's unittesting](tests/test_API.py) may serve as an example how to make use of the API with python3 & pyswagger. @@ -210,7 +213,7 @@ The [API's unittesting](tests/test_API.py) may serve as an example how to make u * Generation or application of any `iptables` or `nftables` rules. * Setting up or changing IP-addresses of the WireGuard interface on operating systems other than linux. * Importing private keys of an existing WireGuard setup. - + ## Application stack * [Gin, HTTP web framework written in Go](https://github.com/gin-gonic/gin) @@ -221,6 +224,6 @@ The [API's unittesting](tests/test_API.py) may serve as an example how to make u ## License * MIT License. [MIT](LICENSE.txt) or https://opensource.org/licenses/MIT - + This project was inspired by [wg-gen-web](https://github.com/vx3r/wg-gen-web). diff --git a/internal/authentication/providers/ldap/provider.go b/internal/authentication/providers/ldap/provider.go index 26f66e05..0327e2b8 100644 --- a/internal/authentication/providers/ldap/provider.go +++ b/internal/authentication/providers/ldap/provider.go @@ -2,6 +2,7 @@ package ldap import ( "crypto/tls" + "io/ioutil" "strings" "github.com/gin-gonic/gin" @@ -154,7 +155,33 @@ func (provider Provider) GetUserModel(ctx *authentication.AuthContext) (*authent } func (provider Provider) open() (*ldap.Conn, error) { - tlsConfig := &tls.Config{InsecureSkipVerify: !provider.config.CertValidation} + var tlsConfig *tls.Config + + if provider.config.LdapCertConn { + + certificate, err := ioutil.ReadFile(provider.config.LdapTlsCert) + if err != nil { + return nil, errors.WithMessage(err, "failed to load the certificate") + + } + + key, err := ioutil.ReadFile(provider.config.LdapTlsKey) + if err != nil { + return nil, errors.WithMessage(err, "failed to load the key") + } + + cert, err := tls.X509KeyPair(certificate, key) + if err != nil { + return nil, errors.WithMessage(err, "failed X509") + + } + tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}} + + } else { + + tlsConfig = &tls.Config{InsecureSkipVerify: !provider.config.CertValidation} + } + conn, err := ldap.DialURL(provider.config.URL, ldap.DialWithTLSConfig(tlsConfig)) if err != nil { return nil, errors.WithMessage(err, "failed to connect to LDAP") diff --git a/internal/ldap/config.go b/internal/ldap/config.go index ff8a11cc..c88bd831 100644 --- a/internal/ldap/config.go +++ b/internal/ldap/config.go @@ -4,7 +4,6 @@ import ( gldap "github.com/go-ldap/ldap/v3" ) - type Type string const ( @@ -26,8 +25,11 @@ type Config struct { PhoneAttribute string `yaml:"attrPhone" envconfig:"LDAP_ATTR_PHONE"` GroupMemberAttribute string `yaml:"attrGroups" envconfig:"LDAP_ATTR_GROUPS"` - LoginFilter string `yaml:"loginFilter" envconfig:"LDAP_LOGIN_FILTER"` // {{login_identifier}} gets replaced with the login email address - SyncFilter string `yaml:"syncFilter" envconfig:"LDAP_SYNC_FILTER"` - AdminLdapGroup string `yaml:"adminGroup" envconfig:"LDAP_ADMIN_GROUP"` // Members of this group receive admin rights in WG-Portal + LoginFilter string `yaml:"loginFilter" envconfig:"LDAP_LOGIN_FILTER"` // {{login_identifier}} gets replaced with the login email address + SyncFilter string `yaml:"syncFilter" envconfig:"LDAP_SYNC_FILTER"` + AdminLdapGroup string `yaml:"adminGroup" envconfig:"LDAP_ADMIN_GROUP"` // Members of this group receive admin rights in WG-Portal AdminLdapGroup_ *gldap.DN `yaml:"-"` + LdapCertConn bool `yaml:"ldapCertConn" envconfig:"LDAP_CERT_CONN"` + LdapTlsCert string `yaml:"ldapTlsCert" envconfig:"LDAPTLS_CERT"` + LdapTlsKey string `yaml:"ldapTlsKey" envconfig:"LDAPTLS_KEY"` } diff --git a/internal/ldap/ldap.go b/internal/ldap/ldap.go index 38af07ba..12ce6466 100644 --- a/internal/ldap/ldap.go +++ b/internal/ldap/ldap.go @@ -2,6 +2,7 @@ package ldap import ( "crypto/tls" + "io/ioutil" "github.com/go-ldap/ldap/v3" "github.com/pkg/errors" @@ -14,7 +15,33 @@ type RawLdapData struct { } func Open(cfg *Config) (*ldap.Conn, error) { - tlsConfig := &tls.Config{InsecureSkipVerify: !cfg.CertValidation} + var tlsConfig *tls.Config + + if cfg.LdapCertConn { + + certificate, err := ioutil.ReadFile(cfg.LdapTlsCert) + if err != nil { + return nil, errors.WithMessage(err, "failed to load the certificate") + + } + + key, err := ioutil.ReadFile(cfg.LdapTlsKey) + if err != nil { + return nil, errors.WithMessage(err, "failed to load the key") + } + + cert, err := tls.X509KeyPair(certificate, key) + if err != nil { + return nil, errors.WithMessage(err, "failed X509") + + } + tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}} + + } else { + + tlsConfig = &tls.Config{InsecureSkipVerify: !cfg.CertValidation} + } + conn, err := ldap.DialURL(cfg.URL, ldap.DialWithTLSConfig(tlsConfig)) if err != nil { return nil, errors.Wrap(err, "failed to connect to LDAP") From 4219f44cf6ad4767eb8fa38d62d50315cb925f49 Mon Sep 17 00:00:00 2001 From: Alexis Aurin Date: Tue, 15 Mar 2022 12:04:24 +0100 Subject: [PATCH 2/2] fix(ldap) Update cert variable name In order to be more explicit --- internal/authentication/providers/ldap/provider.go | 6 +++--- internal/ldap/ldap.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/authentication/providers/ldap/provider.go b/internal/authentication/providers/ldap/provider.go index 0327e2b8..dff25752 100644 --- a/internal/authentication/providers/ldap/provider.go +++ b/internal/authentication/providers/ldap/provider.go @@ -159,7 +159,7 @@ func (provider Provider) open() (*ldap.Conn, error) { if provider.config.LdapCertConn { - certificate, err := ioutil.ReadFile(provider.config.LdapTlsCert) + cert_plain, err := ioutil.ReadFile(provider.config.LdapTlsCert) if err != nil { return nil, errors.WithMessage(err, "failed to load the certificate") @@ -170,12 +170,12 @@ func (provider Provider) open() (*ldap.Conn, error) { return nil, errors.WithMessage(err, "failed to load the key") } - cert, err := tls.X509KeyPair(certificate, key) + cert_x509, err := tls.X509KeyPair(cert_plain, key) if err != nil { return nil, errors.WithMessage(err, "failed X509") } - tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}} + tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert_x509}} } else { diff --git a/internal/ldap/ldap.go b/internal/ldap/ldap.go index 12ce6466..d1d2c84e 100644 --- a/internal/ldap/ldap.go +++ b/internal/ldap/ldap.go @@ -19,7 +19,7 @@ func Open(cfg *Config) (*ldap.Conn, error) { if cfg.LdapCertConn { - certificate, err := ioutil.ReadFile(cfg.LdapTlsCert) + cert_plain, err := ioutil.ReadFile(cfg.LdapTlsCert) if err != nil { return nil, errors.WithMessage(err, "failed to load the certificate") @@ -30,12 +30,12 @@ func Open(cfg *Config) (*ldap.Conn, error) { return nil, errors.WithMessage(err, "failed to load the key") } - cert, err := tls.X509KeyPair(certificate, key) + cert_x509, err := tls.X509KeyPair(cert_plain, key) if err != nil { return nil, errors.WithMessage(err, "failed X509") } - tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}} + tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert_x509}} } else {