Open captain-parzival opened 1 month ago
+1
Got it to work eventually myself as well, beware ldap_sync_interval
is just for show, it's not mapped to anything in code - once you enable syncronize: true
, the LDAP service is queried every 10 seconds as per https://github.com/h44z/wg-portal/blob/master/internal/app/auth/auth.go#L39. What a mess...
How did you get it to work? What backend are you using for LDAP?
Would you be able to post your configuration? I'm hoping it can help me track down my issues.
Here's my working config for v2:
advanced:
log_level: trace
ldap_sync_interval: 15m
core:
admin_user: admin@example.com
admin_password: password
create_default_peer: true
create_default_peer_on_creation: false
web:
external_url: https://example.com
request_logging: true
auth:
callback_url_prefix: https://example.com/api/v0
ldap:
- id: ldap1
provider_name: company ldap
display_name: Login with</br>LDAP
url: ldap://example.com:389
start_tls: true
bind_user: cn=admin@example.com,ou=users,dc=example,dc=com
bind_pass: password
base_dn: ou=users,dc=example,dc=com
login_filter: (&(objectClass=inetOrgPerson)(memberOf=cn=users_of_wgportal,ou=groups,dc=example,dc=com)(mail={{login_identifier}}))
admin_group: cn=administrators,ou=users,dc=example,dc=com
synchronize: false
sync_filter: (&(objectClass=inetOrgPerson)(memberOf=cn=users_of_wgportal,ou=groups,dc=example,dc=com))
registration_enabled: true
field_map:
user_identifier: uid
email: mail
memberof: memberOf
firstname: givenName
lastname: sn
phone: mobile
department: title
Since ldap_sync_interval
is useless in v2, and syncronization happens every 10 seconds for some insane reason (hardcoded), I have gone to using v1 which also has a hardcoded value, but at least on that it is 1 minute. Here's my config there (docker-compose.yml
):
version: '3.6'
services:
wg-portal:
image: wgportal/wg-portal:v1
container_name: wg-portal
restart: unless-stopped
cap_add:
- NET_ADMIN
network_mode: "host"
volumes:
- /etc/wireguard:/etc/wireguard
- ./data:/app/data
ports:
- '8123:8123'
environment:
# WireGuard Settings
- WG_DEVICES=wg0,wg1
- WG_DEFAULT_DEVICE=wg0
- WG_CONFIG_PATH=/etc/wireguard
- SELF_PROVISIONING=true
# Core Settings
- EXTERNAL_URL=https://example.com
- LOGO_URL=https://example.com/logo.png
- CREATE_DEFAULT_PEER=true
- WEBSITE_TITLE=Example VPN
- COMPANY_NAME=Example
- ADMIN_USER=admin@example.com
- ADMIN_PASS=password
# Mail Settings
- MAIL_FROM=Example VPN <vpn@example.com>
- EMAIL_HOST=1.1.1.1
- EMAIL_PORT=25
# LDAP Settings
- LDAP_ENABLED=true
- LDAP_URL=ldap://example.com:389
- LDAP_STARTTLS=true
- LDAP_CERT_VALIDATION=false
- LDAP_BASEDN=ou=users,dc=example,dc=com
- LDAP_USER=cn=admin@example.com,ou=users,dc=example,dc=com
- LDAP_PASSWORD=password
- LDAP_LOGIN_FILTER=(&(objectClass=inetOrgPerson)(memberOf=cn=users_of_wgportal,ou=groups,dc=example,dc=com)(mail={{login_identifier}}))
- LDAP_SYNC_FILTER=(&(objectClass=inetOrgPerson)(memberOf=cn=users_of_wgportal,ou=groups,dc=example,dc=com))
- LDAP_SYNC_GROUP_FILTER=(&(objectClass=inetOrgPerson)(ou=groups,dc=example,dc=com))
- LDAP_ADMIN_GROUP=cn=administrators,ou=groups,dc=example,dc=com
- LDAP_ATTR_EMAIL=mail
- LDAP_ATTR_FIRSTNAME=givenName
- LDAP_ATTR_LASTNAME=sn
- LDAP_ATTR_PHONE=mobile
- LDAP_ATTR_GROUPS=memberOf
- LDAP_CERT_CONN=false
# Log
- LOG_LEVEL=trace
Although, to be perfectly honest with you, I don't like the interface of this project at all - it is too complicated for the casual users; I will probably go back to a custom patched wg-easy with an external authenticator. Here is the patch to wg-easy to support the Remote-User
header from Authelia (it's in a comment on YouTube):
@WolfgangsChannel Managed to pull it off. It's rather simple actually. The changes are as follows:
In file ansible-easy-vpn/roles/bunkerweb/templates/env.j2
, add {{ wireguard_host }}_REVERSE_PROXY_HEADERS=Remote-User $user
on the last line.
docker exec -it wg-easy apk add nano
.
docker exec -it wg-easy nano lib/Server.js
Ctrl + W
, type return WireGuard.getClients(
, Enter
. Replace the line with return WireGuard.getClients(req.header("Remote-User"));
.
Ctrl + W
, type return WireGuard.createClient(
, Enter
. 2 lines above (where function starts), add [req.body.name](javascript:void(0);) = req.header("Remote-User") + "_" + [req.body.name](javascript:void(0););
.
Ctrl + W
, type return WireGuard.updateClientName(
, Enter
. 3 lines above (where function starts), add [req.body.name](javascript:void(0);) = req.header("Remote-User") + "_" + [req.body.name](javascript:void(0););
.
Ctrl+X
, y
, Enter
to exit nano.
docker exec -it wg-easy nano lib/WireGuard.js
Ctrl + W
, type async getClients(remote_user) {
. In this method, replace lines 2 and 4 with this, respectively:
const clients = Object.entries(config.clients).filter(([clientId, client]) => client.name.startsWith(remote_user + "_")).map(([clientId, client]) => ({
name: client.name.substring((remote_user + "_").length, client.name.length),
docker exec -it wg-easy nano www/index.html
Ctrl+W
, type <span class="text-sm">New</span>
, Enter
. After 2 lines, where the div
closes, add this:
<div class="flex-shrink-0">
<button @click="location.replace('[https://auth.example.com/logout?rd=https%3A%2F%2Fwg.example.com%2F');](javascript:void(0);)"
class="hover:bg-red-800 hover:border-red-800 hover:text-white text-gray-700 border-2 border-gray-100 py-2 px-4 rounded inline-flex items-center transition">
<svg style="transform-box: fill-box; transform-origin: center; transform: rotate(45deg);" class="w-4 mr-2" inline xmlns="[http://www.w3.org/2000/svg](javascript:void(0);)" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
<span class="text-sm">Log out</span>
</button>
</div>
cd ansible-easy-vpn/
ansible-playbook run.yml
, enter valut password.
reboot
This patch has the effect that the headers sent by Authelia always contain the Remote-User
field populated with the LDAP uid of the currently logged in user. On the wg-easy side, what I did was to prefix config files with "username_", and then filter the returned configs to only include those belonging to the currently logged in user. Finally, steps 10-11 add a "Log out" button to the "wg-easy" web page, so users can easily log out. Remember to replace example.com
with your actual domain.
I am a bit amazed by the lack of proper options in this area of WireGuard frontend, but I always keep looking since the protocol in itself is SO GOOD compared to anything else I have used.
I'm having issues with wg-portal and lldap as a LDAPS authentication provider.
When opening the front end, I see this error:![image](https://github.com/user-attachments/assets/4416e208-c3ff-451f-8c86-6bcd4d3995a0)
If I try to sign in with any of the LDAP accounts, an authentication error occurs.
Here's the snag, LDAPS binds properly. I can see on the lldap side the request come through, bind and return the correct users based on the sync filter. I've pulled the database file to see if the user information was synced. Looks like everything came over except password, but I'm assuming that's the correct behavior. For reference, the same LDAP backend is working fine with other services.
On first run with a new database file I see this in the wg-portal log. It continues to cycle starting to synchronize, and fetching the raw users endlessly. It's also not in alignment to the synchronization interval.
My docker compose file:
My config,yml
I'm unsure if this issue is a configuration issue on my end or an issue with how LDAP synchronization occurs behind the scenes. I took a quick look at user_manager.go, but based on the flow I would think that the users are synced properly. Not sure why I see the backend connection error when it appears to have been set up properly.
Any thoughts or suggestions as to the source of my issues?