Compare commits

..

5 Commits

Author SHA1 Message Date
Chris F Ravenscroft 10cc5c5850 chore: rewire ldap package 2023-12-10 15:05:33 -08:00
shipperizer 80b9401c69 feat: allow tls config for startTLS 2023-11-28 10:20:05 +00:00
shipperizer b30104506e build: update libs to use newer ldap 2023-11-28 10:18:32 +00:00
shipperizer 1491ff0858 feat: pass tls config for startTLS to ldap server 2023-11-28 10:16:29 +00:00
shipperizer 661e7b4662 feat: introduce tls parameters in config to allow startTLS 2023-11-28 10:16:29 +00:00
58 changed files with 689 additions and 2021 deletions
+3 -3
View File
@@ -4,13 +4,13 @@ on:
pull_request:
push:
branches:
- master
- dev
jobs:
build:
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
strategy:
matrix:
go-version: [1.21.x]
go-version: [1.19.x, 1.20.x]
steps:
- name: Install Go
uses: actions/setup-go@v4
+4 -4
View File
@@ -2,7 +2,7 @@ name: "CodeQL"
on:
push:
branches: [ "master" ]
branches: [ "master", "dev" ]
pull_request:
branches: [ "master" ]
schedule:
@@ -27,15 +27,15 @@ jobs:
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"
+13 -6
View File
@@ -1,20 +1,27 @@
name: release-please
on:
pull_request:
push:
branches:
- master
- dev
permissions:
contents: write
pull-requests: write
name: release-please
jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/release-please-action@v4
- uses: actions/checkout@v4
- uses: google-github-actions/release-please-action@v3
with:
release-type: go
package-name: GLAuth
path: v2
default-branch: master
pull-request-title-pattern: "ci: release ${version}"
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
extra-files: |
v2/internal/version/const.go
-4
View File
@@ -3,7 +3,6 @@ v2/certs/
v2/bin
v2/docker/assets/linux
v2/gl.db
v2/buildlogs
.vscode/
# Output of the go coverage tool, specifically when used with LiteIDE
@@ -13,9 +12,6 @@ v2/buildlogs
/vendor/
/Godeps/
# Various
go.work.sum
# gomocks auto-generated
**/mock_*.go
+4 -4
View File
@@ -1,12 +1,12 @@
[submodule "v2/pkg/plugins/glauth-sqlite"]
path = v2/pkg/plugins/glauth-sqlite
url = git@github.com:glauth/glauth-sqlite
url = https://github.com/glauth/glauth-sqlite
[submodule "v2/pkg/plugins/glauth-mysql"]
path = v2/pkg/plugins/glauth-mysql
url = git@github.com:glauth/glauth-mysql
url = https://github.com/glauth/glauth-mysql
[submodule "v2/pkg/plugins/glauth-postgres"]
path = v2/pkg/plugins/glauth-postgres
url = git@github.com:glauth/glauth-postgres
url = https://github.com/glauth/glauth-postgres
[submodule "v2/pkg/plugins/glauth-pam"]
path = v2/pkg/plugins/glauth-pam
url = git@github.com:glauth/glauth-pam
url = https://github.com/glauth/glauth-pam
-3
View File
@@ -1,3 +0,0 @@
{
"v2": "2.5.0"
}
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018 Ned McClain & Ben Yanke & Chris Ravenscroft
Copyright (c) 2018 Ned McClain & Ben Yanke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+6 -5
View File
@@ -1,14 +1,14 @@
# GLAuth: LDAP authentication server for developers
[![Official GLAuth Website](https://img.shields.io/badge/Official%20GLAuth%20Website-glauth.github.io-brightgreen?style=plastic)](https://glauth.github.io/)
[![kittens dns](https://img.shields.io/badge/kittens%20dns-github-blue?style=plastic)](https://github.com/fusion/kittendns)
[![wing vpn](https://img.shields.io/badge/wing%20vpn-github-orange?style=plastic)](https://github.com/fusion/wing-vpn)
Go-lang LDAP Authentication (GLAuth) is a secure, easy-to-use, LDAP server w/ configurable backends.
[![Gitter](https://badges.gitter.im/glauth/community.svg)](https://gitter.im/glauth/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Matrix](https://img.shields.io/badge/chat-%2fjoin%20%23glauth_community:gitter.im-green)](hey)
![GitHub all releases](https://img.shields.io/github/downloads/glauth/glauth/total)
![Docker pulls](https://badgen.net/docker/pulls/glauth/glauth)
![GitHub last commit (branch)](https://img.shields.io/github/last-commit/glauth/glauth/master)
![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability-percentage/glauth/glauth)
* Centrally manage accounts across your infrastructure
* Centrally manage SSH keys, Linux accounts, and passwords for cloud servers.
@@ -110,3 +110,4 @@ For advanced users, GLAuth supports pluggable backends. Currently, it can use a
# Stargazers over time
[![Stargazers over time](https://starchart.cc/glauth/glauth.svg)](https://starchart.cc/glauth/glauth)
+1 -3
View File
@@ -1,5 +1,3 @@
go 1.21.0
toolchain go1.21.5
go 1.19
use ./v2
-13
View File
@@ -1,13 +0,0 @@
{
"packages": {
"v2": {
"release-type": "go",
"package-name": "GLAuth",
"pull-request-title-pattern": "ci: release ${version}",
"extra-files": [
"v2/internal/version/const.go"
]
}
},
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
}
-88
View File
@@ -1,93 +1,5 @@
# Changelog
## [2.5.0](https://github.com/glauth/glauth/compare/GLAuth-v2.5.0...GLAuth-v2.5.0) (2026-04-19)
### Features
* allow tracing configuration via main config ([f692394](https://github.com/glauth/glauth/commit/f692394942aa0f93a1aa1572331fd1c3e3553156))
* alt container build registry ([f8dee8d](https://github.com/glauth/glauth/commit/f8dee8da879232f5c6ae2a2a19565562c7d0d9fd))
* embedded plugins ([c0ed908](https://github.com/glauth/glauth/commit/c0ed90822fd4d2ee7104a1979d423a0c93d758ac))
* introduce context for otlp spans into handler pkg ([d05630f](https://github.com/glauth/glauth/commit/d05630f66b80a776fd406782ad1fde5c6c66eac6))
* introduce context for otlp spans into plugins pkg ([46e49b6](https://github.com/glauth/glauth/commit/46e49b6976318a9f3670b88bdcb3411dfac0a17c))
* introduce legacy behavior, based on past versions ([#318](https://github.com/glauth/glauth/issues/318)) ([34a6b30](https://github.com/glauth/glauth/commit/34a6b30b8fe69c90cab09eb85890ffdfe8fc80fd))
* introduce otelsql ([2ca5312](https://github.com/glauth/glauth/commit/2ca53126965aa7d42b23aee15f750df12822d454))
* introduce otlp tracer ([0cf0403](https://github.com/glauth/glauth/commit/0cf04037a2a7b38c8ed7af2451b115f48c5427b5))
* proxying ldap paging compat ([#422](https://github.com/glauth/glauth/issues/422)) ([8476506](https://github.com/glauth/glauth/commit/8476506b8c51e993eb90c73d612f69fec5350b89))
* starttls and ldaps now matching features ([#458](https://github.com/glauth/glauth/issues/458)) ([d68c78a](https://github.com/glauth/glauth/commit/d68c78a18b150679038e5ce549b6b227c31518d7))
* wire up basic tracer ([1c2b23c](https://github.com/glauth/glauth/commit/1c2b23c00ff85b83a6d2e4bf4a9a68081aaf2777))
### Bug Fixes
* 246 and [#252](https://github.com/glauth/glauth/issues/252) ([ceefc66](https://github.com/glauth/glauth/commit/ceefc66dbba9ae054958269825de31d22d30e262))
* config watcher now updates whenf ile added to dir ([#424](https://github.com/glauth/glauth/issues/424)) ([a90f37b](https://github.com/glauth/glauth/commit/a90f37b23b76af22c700392d68bf227b7aee1894))
* Credentials leaked on INFO log level ([#451](https://github.com/glauth/glauth/issues/451)) ([645dbb2](https://github.com/glauth/glauth/commit/645dbb226683ae57f3d5382e21ea42444e940752))
* drop vendored toml ([24455e3](https://github.com/glauth/glauth/commit/24455e39889716ce7ae1e7e8a7dacfa7d4c96080))
* formatting ([c90cbfe](https://github.com/glauth/glauth/commit/c90cbfe5fb090fc19a55d64e01cd0e31c38bf2f0))
* go test not checking otp within allowed basedn ([#403](https://github.com/glauth/glauth/issues/403)) ([ed52a91](https://github.com/glauth/glauth/commit/ed52a91ec4117ff58fe606a1d8ba10786501a1e5))
* move all toml parsing into a new internal package, drop the mappings in favour of toml.Primitive decoding ([3ba8e11](https://github.com/glauth/glauth/commit/3ba8e1113217be647d240261322453d213ea7da4))
* patch group name fetches for the rest of handlers ([#450](https://github.com/glauth/glauth/issues/450)) ([b498736](https://github.com/glauth/glauth/commit/b498736cfdd0ee6f1585d682a5c54c9d927b8dbb))
* remove spinlock in monitoring code ([#405](https://github.com/glauth/glauth/issues/405)) ([a2c151b](https://github.com/glauth/glauth/commit/a2c151b0d025332462369a846a51ef4deff5332b))
* removed config setup from main, reshoring log configuration ([5fe8aca](https://github.com/glauth/glauth/commit/5fe8aca852bdfe7e375ea99b87074bae35fc3407))
* update ldap library to fix [#389](https://github.com/glauth/glauth/issues/389) ([#430](https://github.com/glauth/glauth/issues/430)) ([a5ecc26](https://github.com/glauth/glauth/commit/a5ecc26e064cea9e4dab3dd234ebd5d5eb06be0e))
* update tracing code to work with breaking otlp 1.20 changes ([1a37396](https://github.com/glauth/glauth/commit/1a3739610997b58100040d0c8a405596fccc8e23))
* upgrade to use BurntSushi/toml ([f9addbc](https://github.com/glauth/glauth/commit/f9addbc2c5b13ccc2779dbabc4c55bc8706f53d6))
### Miscellaneous Chores
* force release 2.5.0 ([ff7a9e6](https://github.com/glauth/glauth/commit/ff7a9e6215857e0dd3450504b7b063409ccfc374))
* release 2.3.1 ([0bf3d4a](https://github.com/glauth/glauth/commit/0bf3d4a82a8451e7bbda74e3730345aab5a855a7))
## [2.4.0](https://github.com/glauth/glauth/compare/v2.3.2...v2.4.0) (2024-08-04)
### Features
* proxying ldap paging compat ([#422](https://github.com/glauth/glauth/issues/422)) ([8476506](https://github.com/glauth/glauth/commit/8476506b8c51e993eb90c73d612f69fec5350b89))
### Bug Fixes
* config watcher now updates whenf ile added to dir ([#424](https://github.com/glauth/glauth/issues/424)) ([a90f37b](https://github.com/glauth/glauth/commit/a90f37b23b76af22c700392d68bf227b7aee1894))
* update ldap library to fix [#389](https://github.com/glauth/glauth/issues/389) ([#430](https://github.com/glauth/glauth/issues/430)) ([a5ecc26](https://github.com/glauth/glauth/commit/a5ecc26e064cea9e4dab3dd234ebd5d5eb06be0e))
## [2.3.2](https://github.com/glauth/glauth/compare/v2.3.1...v2.3.2) (2024-02-19)
### Bug Fixes
* remove spinlock in monitoring code ([#405](https://github.com/glauth/glauth/issues/405)) ([a2c151b](https://github.com/glauth/glauth/commit/a2c151b0d025332462369a846a51ef4deff5332b))
## [2.3.1](https://github.com/glauth/glauth/compare/v2.2.1...v2.3.1) (2024-02-12)
### Features
* allow tracing configuration via main config ([f692394](https://github.com/glauth/glauth/commit/f692394942aa0f93a1aa1572331fd1c3e3553156))
* introduce context for otlp spans into handler pkg ([d05630f](https://github.com/glauth/glauth/commit/d05630f66b80a776fd406782ad1fde5c6c66eac6))
* introduce context for otlp spans into plugins pkg ([46e49b6](https://github.com/glauth/glauth/commit/46e49b6976318a9f3670b88bdcb3411dfac0a17c))
* introduce otelsql ([2ca5312](https://github.com/glauth/glauth/commit/2ca53126965aa7d42b23aee15f750df12822d454))
* introduce otlp tracer ([0cf0403](https://github.com/glauth/glauth/commit/0cf04037a2a7b38c8ed7af2451b115f48c5427b5))
* wire up basic tracer ([1c2b23c](https://github.com/glauth/glauth/commit/1c2b23c00ff85b83a6d2e4bf4a9a68081aaf2777))
### Bug Fixes
* drop vendored toml ([24455e3](https://github.com/glauth/glauth/commit/24455e39889716ce7ae1e7e8a7dacfa7d4c96080))
* formatting ([c90cbfe](https://github.com/glauth/glauth/commit/c90cbfe5fb090fc19a55d64e01cd0e31c38bf2f0))
* go test not checking otp within allowed basedn ([#403](https://github.com/glauth/glauth/issues/403)) ([ed52a91](https://github.com/glauth/glauth/commit/ed52a91ec4117ff58fe606a1d8ba10786501a1e5))
* move all toml parsing into a new internal package, drop the mappings in favour of toml.Primitive decoding ([3ba8e11](https://github.com/glauth/glauth/commit/3ba8e1113217be647d240261322453d213ea7da4))
* removed config setup from main, reshoring log configuration ([5fe8aca](https://github.com/glauth/glauth/commit/5fe8aca852bdfe7e375ea99b87074bae35fc3407))
* update tracing code to work with breaking otlp 1.20 changes ([1a37396](https://github.com/glauth/glauth/commit/1a3739610997b58100040d0c8a405596fccc8e23))
* upgrade to use BurntSushi/toml ([f9addbc](https://github.com/glauth/glauth/commit/f9addbc2c5b13ccc2779dbabc4c55bc8706f53d6))
### Miscellaneous Chores
* release 2.3.1 ([0bf3d4a](https://github.com/glauth/glauth/commit/0bf3d4a82a8451e7bbda74e3730345aab5a855a7))
## [2.3.0](https://github.com/glauth/glauth/compare/v2.2.0...v2.3.0) (2023-10-02)
+41 -149
View File
@@ -1,7 +1,5 @@
.DEFAULT_GOAL := help
MAKEFLAGS += --no-print-directory
VERSION=$(shell bin/linuxamd64/glauth --version)
GIT_COMMIT=$(shell git rev-list -1 HEAD )
@@ -21,12 +19,10 @@ GIT_BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
BUILD_VARS?=-s -w
BUILD_FILES=.
TRIM_FLAGS>?=-trimpath
BUILD_TAGS?=noembed
# Targets
MAIN_TARGETS?=linux/amd64,linux/386,linux/arm64,linux/arm-7,linux/riscv64,darwin/amd64,darwin/arm64,windows/amd64,windows/386
PLUGIN_TARGETS?=linux/amd64,linux/386,linux/arm64,linux/arm-7,linux/riscv64,darwin/amd64,darwin/arm64
EMBED_TARGETS?=windows/amd64
MAIN_TARGETS=linux/amd64,linux/386,linux/arm64,linux/arm-7,darwin/amd64,darwin/arm64,windows/amd64,windows/386
PLUGIN_TARGETS=linux/amd64,linux/386,linux/arm64,linux/arm-7,darwin/amd64,darwin/arm64
# For release process
GO_RELEASE_V=$(shell go version | { read _ _ v _; echo $${v#go}; })
@@ -69,11 +65,8 @@ all: setup binaries verify
#fast: @ run build process for only linuxamd64
fast: setup linuxamd64
#fastdebug: @ run build process for only linuxamd64 in debug mode
fastdebug: setup linuxamd64debug
#binaries: @ list of binary formats to build
binaries: linux386 linuxamd64 linuxarm linuxarm64 linuxriscv64 darwinamd64 darwinarm64 win386 winamd64
binaries: linux386 linuxamd64 linuxarm linuxarm64 darwinamd64 darwinarm64 win386 winamd64
#setup: @ setup commands to always run
setup: getdeps format
@@ -81,27 +74,6 @@ setup: getdeps format
#####################
# Subcommands
#####################
# @echo \- removing any changes and pulling latest master && \
# git reset --hard HEAD >/dev/null 2>&1 && \
# git checkout master >/dev/null 2>&1 && \
# git pull >/dev/null 2>&1 && \
prepbuild:
echo \- taking care of ignore files && \
sudo rm -rf bin/* >/dev/null && \
echo \- cleaning up plugins remnants && \
make forget-plugins && \
make remember-plugins
forget-embed:
@if [ -f pkg/server/embed_sqlite.go ]; then \
mv pkg/server/embed_sqlite.go /tmp/; \
fi
remember-embed:
@if [ ! -f pkg/server/embed_sqlite.go ]; then \
mv /tmp/embed_sqlite.go pkg/server/; \
fi
# Run integration test
runtest:
@@ -115,7 +87,7 @@ updatetest:
./scripts/ci/integration-test.sh
format:
go fmt ./...
go fmt
devrun:
go run ${BUILD_FILES} -c sample-simple.cfg
@@ -126,22 +98,14 @@ mkbindir:
.PHONY: mkbindir
build: mkbindir
@go build ${TRIM_FLAGS} -tags ${BUILD_TAGS} -ldflags "${BUILD_VARS}" -o bin/$(GOOS)$(GOARCH)/glauth -buildvcs .
@go build ${TRIM_FLAGS} -ldflags "${BUILD_VARS}" -o bin/$(GOOS)$(GOARCH)/glauth -buildvcs=false .
$(MAKE) sha256
.PHONY: build
builddebug: mkbindir
@go build ${TRIM_FLAGS} -tags ${BUILD_TAGS} -gcflags="all=-N -l" -o bin/$(GOOS)$(GOARCH)/glauth -buildvcs .
$(MAKE) sha256
.PHONY: builddebug
sha256:
@sha256sum bin/$(GOOS)$(GOARCH)/glauth > bin/$(GOOS)$(GOARCH)/glauth.sha256
.PHONY: sha256
linuxamd64debug:
GOOS=linux GOARCH=amd64 $(MAKE) builddebug
linux386:
GOOS=linux GOARCH=386 $(MAKE) build
@@ -154,16 +118,6 @@ linuxarm:
linuxarm64:
GOOS=linux GOARCH=arm64 $(MAKE) build
linuxriscv64:
GOOS=linux GOARCH=riscv64 $(MAKE) build
testing:
mkdir -p pkg/embed && \
cat pkg/plugins/glauth-sqlite/sqlite.go | sed -e 's/func main() {}//' -e 's/^package main/package embed/' > pkg/embed/sqlite.go && \
go mod tidy && \
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 BUILD_TAGS=embedsqlite $(MAKE) build && \
rm -rf pkg/embed
darwinamd64:
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 $(MAKE) build
@@ -177,128 +131,70 @@ winamd64:
GOOS=windows GOARCH=amd64 $(MAKE) build
verify:
@for binary in linux386 linuxamd64 linuxarm linuxarm64 linuxriscv64 darwinamd64 darwinarm64 win386 winamd64; do cd bin/$$binary && sha256sum glauth.sha256 -c && cd ../..; done
@for binary in linux386 linuxamd64 linuxarm linuxarm64 darwinamd64 darwinarm64 win386 winamd64; do cd bin/$$binary && sha256sum glauth.sha256 -c && cd ../..; done
pull-plugin-dependencies:
pull-plugin:
@git submodule add $U $M && \
(for pkg in $$(cat $$M/go.mod | awk '/^require [a-z]/{print $$2} /^\)/{rblock=0} rblock{if($$4!="indirect" && $$1!~"glauth"){print $$1}} /^require \(/{rblock=1}'); do if [ "$$(grep $$pkg go.mod &>/dev/null)" = "" ]; then go get $$pkg; fi; done)
#prepare-plugins-buid: @ pull plugins dependencies for local building
prepare-plugins-build:
@M=pkg/plugins/glauth-sqlite make pull-plugin-dependencies && \
M=pkg/plugins/glauth-mysql make pull-plugin-dependencies && \
M=pkg/plugins/glauth-postgres make pull-plugin-dependencies && \
M=pkg/plugins/glauth-pam make pull-plugin-dependencies
#pull-base-plugins: @ pull plugins for local building
pull-base-plugins:
@U=https://github.com/glauth/glauth-sqlite M=pkg/plugins/glauth-sqlite make pull-plugin && \
U=https://github.com/glauth/glauth-mysql M=pkg/plugins/glauth-mysql make pull-plugin && \
U=https://github.com/glauth/glauth-postgres M=pkg/plugins/glauth-postgres make pull-plugin && \
U=https://github.com/glauth/glauth-pam M=pkg/plugins/glauth-pam make pull-plugin
forget-plugin:
rm -rf $M ../.git/modules/v2/$M; \
git config --remove-section submodule.v2/$M; \
git rm --cache $M; \
go mod tidy; \
true
rm -rf $M ../.git/modules/v2/$M && \
git config --remove-section submodule.v2/$M && \
git rm --cache $M && \
go mod tidy
#forget-plugin: @ remove plugins, restoring original file structure
forget-plugins:
for pkg in pkg/plugins/*; do \
if [ -d "$$pkg" ]; then \
P=$$(echo $$pkg | cut -d'/' -f 3) M=$$pkg make forget-plugin >/dev/null 2>&1;\
fi; \
done; \
rm -rf buildlogs
for pkg in pkg/plugins/*/go.mod; do\
P=$$(echo $$pkg | cut -d'/' -f 3) M=$$(dirname $$pkg) make forget-plugin;\
done
remember-plugins:
cd ../ && \
for module in $$(cat .gitmodules | awk '/path =/{P=$$3} /url =/{print $$3 "," P}'); do \
git submodule add $${module%%,*} $${module#*,}; \
done; \
git submodule update --init --recursive
_buildmain:
#releasemain: @ build main binaries for distribution
releasemain:
@xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out glauth -dest bin -buildvcs=false --targets="${MAIN_TARGETS}" .
#buildmain: @ build main binaries for distribution
buildmain: prepbuild _buildmain
releaseplugin:
@xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out $P -dest bin -buildvcs=false -buildmode=plugin --targets="${PLUGIN_TARGETS}" --pkg $M/$P.go . && \
(cd bin && for lib in $$(ls $$P-*); do sudo mv $$lib $$lib.so; done)
buildsingleembed:
git checkout -b build_embeds && \
mkdir -p pkg/embed && \
cat pkg/plugins/$P/$M | sed -e 's/func main() {}//' -e 's/^package main/package embed/' > pkg/embed/$M && \
go mod tidy && \
git add pkg/embed/$M go.mod go.sum && \
git commit -m "build cruft" && \
git push -u origin build_embeds && \
xgo -v -ldflags="${BUILD_VARS}" --tags=$T -trimpath -go ${GO_RELEASE_V} -out glauth -dest bin -buildvcs=false --targets="${EMBED_TARGETS}" . && \
rm -rf pkg/embed && \
git checkout master && \
git push -d origin build_embeds && \
git branch -D build_embeds
#releaseplugins: @ build base plugins for distribution
releaseplugins:
@for pkg in pkg/plugins/*/go.mod; do\
M=pkg/plugins/$$(echo $$pkg | cut -d'/' -f 3) && P=$$(echo $$M | grep -oP 'glauth-\K\w+') && M=$$M P=$$P make releaseplugin;\
done
_buildmainembeds:
P=glauth-sqlite M=sqlite.go T=embedsqlite make buildsingleembed
#buildmainembeds: @ build main binaries for distribution, including embedded plugins
buildmainembeds: prepbuild _buildmainembeds
buildplugin:
ifeq ($P,pam)
xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out $P -dest bin -buildvcs=false -buildmode=plugin --targets="${PLUGIN_TARGETS}" --pkg $M/$P.go --bringupcmd 'apt update && apt install -y libpam0g-dev' .
else
xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out $P -dest bin -buildvcs=false -buildmode=plugin --targets="${PLUGIN_TARGETS}" --pkg $M/$P.go .
endif
(cd bin && for lib in $$(ls $$P-* | grep -v \.so$$); do sudo mv $$lib $$lib.so; done);
_buildplugins: prepare-plugins-build
for pkg in pkg/plugins/*; do \
if [ -d "$$pkg" ]; then \
M=pkg/plugins/$$(echo $$pkg | cut -d'/' -f 3) && P=$$(echo $$M | grep -oP 'glauth-\K\w+') && M=$$M P=$$P make buildplugin;\
fi; \
done; \
#buildplugins: @ build base plugins for distribution
buildplugins: forget-embed _buildplugins remember-embed
_checkdockerauth:
@if ! grep -q "index.docker.io" $(HOME)/.docker/config.json; then \
echo "❌ Not logged in to Docker Hub (index.docker.io not found in config)."; \
exit 1; \
fi; \
if ! grep -q "ghcr.io" $(HOME)/.docker/config.json; then \
echo "❌ Not logged in to GitHub Hub (ghcr.io not found in config)."; \
exit 1; \
fi
builddockermain:
$(if $(TAG),,$(error ❌ Must set TAG))
$(if $(REPO),,$(error ❌ Must set REPO - glauth or other))
releasedockermain:
$(if $(TAG),,$(error Must set TAG))
$(if $(REPO),,$(error Must set REPO - glauth or other))
@mkdir -p docker/assets/linux/amd64 docker/assets/linux/arm64 docker/assets/linux/arm/v7 && \
cp -f bin/glauth-linux-amd64 docker/assets/linux/amd64/glauth && \
cp -f bin/glauth-linux-arm64 docker/assets/linux/arm64/glauth && \
cp -f bin/glauth-linux-arm-7 docker/assets/linux/arm/v7/glauth && \
cp -f bin/glauth-linux-riscv64 docker/assets/linux/riscv64/glauth && \
docker buildx build --tag ghcr.io/$$REPO/glauth:$$TAG -t ghcr.io/$$REPO/glauth:latest -f docker/Dockerfile-standalone --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker && \
docker buildx build --tag $$REPO/glauth:$$TAG -t $$REPO/glauth:latest -f docker/Dockerfile-standalone --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker
docker buildx build --tag $$REPO/glauth:$$TAG -t $$REPO/glauth:latest -f docker/Dockerfile-standalone --platform linux/amd64,linux/arm64,linux/arm/v7 --push docker
builddockerplugins:
$(if $(TAG),,$(error ❌ Must set TAG))
$(if $(REPO),,$(error ❌ Must set REPO - glauth or other))
releasedockerplugins:
$(if $(TAG),,$(error Must set TAG))
$(if $(REPO),,$(error Must set REPO - glauth or other))
@mkdir -p docker/assets/linux/amd64 docker/assets/linux/arm64 docker/assets/linux/arm/v7 && \
cp -f bin/sqlite-linux-amd64.so docker/assets/linux/amd64/sqlite.so && \
cp -f bin/sqlite-linux-arm64.so docker/assets/linux/arm64/sqlite.so && \
cp -f bin/sqlite-linux-arm-7.so docker/assets/linux/arm/v7/sqlite.so && \
cp -f bin/sqlite-linux-riscv64.so docker/assets/linux/riscv64/sqlite.so && \
cp -f bin/mysql-linux-amd64.so docker/assets/linux/amd64/mysql.so && \
cp -f bin/mysql-linux-arm64.so docker/assets/linux/arm64/mysql.so && \
cp -f bin/mysql-linux-arm-7.so docker/assets/linux/arm/v7/mysql.so && \
cp -f bin/mysql-linux-riscv64.so docker/assets/linux/riscv64/mysql.so && \
cp -f bin/postgres-linux-amd64.so docker/assets/linux/amd64/postgres.so && \
cp -f bin/postgres-linux-arm64.so docker/assets/linux/arm64/postgres.so && \
cp -f bin/postgres-linux-arm-7.so docker/assets/linux/arm/v7/postgres.so && \
cp -f bin/postgres-linux-riscv64.so docker/assets/linux/riscv64/postgres.so && \
docker buildx build --tag ghcr.io/$$REPO/glauth-plugins:$$TAG -t ghcr.io/$$REPO/glauth-plugins:latest -f docker/Dockerfile-plugins --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker && \
docker buildx build --tag $$REPO/glauth-plugins:$$TAG -t $$REPO/glauth-plugins:latest -f docker/Dockerfile-plugins --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker
docker buildx build --tag $$REPO/glauth-plugins:$$TAG -t $$REPO/glauth-plugins:latest -f docker/Dockerfile-plugins --platform linux/amd64,linux/arm64,linux/arm/v7 --push docker
builddocker: _checkdockerauth builddockermain builddockerplugins
buildeverything: prepbuild forget-embed _buildmain _buildplugins remember-embed _buildmainembeds builddocker
releasedocker: releasedockermain releasedockerplugins
#testdocker: @ run integration test using docker
testdocker:
@@ -340,8 +236,4 @@ testdocker:
docker rm glauth-test && \
echo "==> Testing complete."
.PHONY: all \
prepbuild run test fast binaries setup getdeps runtest updatetest format devrun \
linux386 linuxamd64 linuxarm linuxarm64 linuxriscv64 darwinamd64 darwinarm64 win386 winamd64 verify \
pull-plugin pull-base-plugins forget-plugin forget-plugins buildmain buildplugin build \
buildplugins builddockermain builddockerplugins builddocker testdocker buildeverything
.PHONY: all run test fast binaries setup getdeps runtest updatetest format devrun linux386 linuxamd64 linuxarm linuxarm64 darwinamd64 darwinarm64 win386 winamd64 verify pull-plugin pull-base-plugins forget-plugin forget-plugins releasemain releaseplugin release releaseplugins releasedockermain releaserdockerplugins releasedocker testdocker
+2 -11
View File
@@ -10,17 +10,8 @@ RUN apk add --no-cache git make busybox-static dumb-init
# Run Step
#################
FROM gcr.io/distroless/base-debian13 as run
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>" \
org.opencontainers.image.title="GLauth" \
org.opencontainers.image.description="A simple LDAP server for development, home use, or CI pipelines" \
org.opencontainers.image.authors="Ben Yanke, Jörn Friedrich Dreyer, Chris F Ravenscroft" \
org.opencontainers.image.source="https://github.com/glauth/glauth" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.version="latest" \
org.opencontainers.image.url="https://github.com/glauth/glauth"
FROM gcr.io/distroless/base-debian11 as run
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>"
ARG TARGETPLATFORM
# Copy docker specific scripts from build container
+2 -11
View File
@@ -10,17 +10,8 @@ RUN apk add --no-cache git make busybox-static dumb-init
# Run Step
#################
FROM gcr.io/distroless/base-debian13 as run
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>" \
org.opencontainers.image.title="GLauth" \
org.opencontainers.image.description="A simple LDAP server for development, home use, or CI pipelines" \
org.opencontainers.image.authors="Ben Yanke, Jörn Friedrich Dreyer, Chris F Ravenscroft" \
org.opencontainers.image.source="https://github.com/glauth/glauth" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.version="latest" \
org.opencontainers.image.url="https://github.com/glauth/glauth"
FROM gcr.io/distroless/base-debian11 as run
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>"
ARG TARGETPLATFORM
# Copy docker specific scripts from build container
+4 -28
View File
@@ -17,7 +17,6 @@ import (
"github.com/glauth/glauth/v2/internal/monitoring"
_tls "github.com/glauth/glauth/v2/internal/tls"
"github.com/glauth/glauth/v2/internal/toml"
"github.com/glauth/glauth/v2/internal/tracing"
"github.com/glauth/glauth/v2/internal/version"
"github.com/glauth/glauth/v2/pkg/config"
"github.com/glauth/glauth/v2/pkg/frontend"
@@ -131,46 +130,25 @@ func startService() {
}
monitor := monitoring.NewMonitor(&log)
tracer := tracing.NewTracer(
tracing.NewConfig(
activeConfig.Tracing.Enabled,
activeConfig.Tracing.GRPCEndpoint,
activeConfig.Tracing.HTTPEndpoint,
&log,
),
)
startConfigWatcher()
var err error
var starttlsConfig *tls.Config
var tlsConfig *tls.Config
if c := activeConfig.LDAP; c.Enabled && c.TLS {
// TODO check if tls params are string or bytes and change config accordingly
starttlsConfig, err = _tls.MakeTLS([]byte(c.TLSCert), []byte(c.TLSKey), c.LegacyTLS)
tlsConfig, err = _tls.MakeTLS([]byte(c.TLSCert), []byte(c.TLSKey))
if err != nil {
log.Warn().Err(err).Msg("unable to configure TLS for StartTLS: StartTLS won't be supported")
}
}
var ldapstlsConfig *tls.Config
if c := activeConfig.LDAPS; c.Enabled {
// TODO check if tls params are string or bytes and change config accordingly
ldapstlsConfig, err = _tls.MakeTLS([]byte(c.Cert), []byte(c.Key), c.LegacyTLS)
if err != nil {
log.Warn().Err(err).Msg("unable to configure TLS for LDAPS")
os.Exit(1)
log.Warn().Err(err).Msg("unable to configure TLS, proceeding without....StartTLS won't be supported")
}
}
s, err := server.NewServer(
server.Logger(log),
server.Config(activeConfig),
server.StartTLSConfig(starttlsConfig),
server.LDAPSTLSConfig(ldapstlsConfig),
server.Monitor(monitor),
server.Tracer(tracer),
server.TLSConfig(tlsConfig),
)
if err != nil {
@@ -236,8 +214,6 @@ func startConfigWatcher() {
isChanged = true
} else if event.Op&fsnotify.Remove == fsnotify.Remove { // vim edit file with rename/remove
isChanged, isRemoved = true, true
} else if event.Op&fsnotify.Create == fsnotify.Create { // only when watching a directory
isChanged = true
}
case err := <-watcher.Errors:
log.Error().Err(err).Msg("watcher error")
+164 -210
View File
@@ -6,6 +6,8 @@ import (
"strings"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
type testEnv struct {
@@ -23,233 +25,185 @@ type testEnv struct {
checkemployeetype string
}
func TestProperBuild(t *testing.T) {
info, err := os.Stat("bin/glauth")
if err != nil {
t.Error(err)
}
mode := uint32(info.Mode())
if mode&0b001001001 == 0 {
t.Fatalf("bad file mode: %b", mode)
}
}
func TestIntegerStuff(t *testing.T) {
func batteryOfTests(t *testing.T, env *testEnv) {
tests := []struct {
Name string
Path string
Check func(t testing.TB)
}{
{
Name: "searching for the 'hackers' user",
Check: func(t testing.TB) {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
if got, want := out, env.expectedaccount; got != want {
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "searching for the 'hackers' user without binding with a group",
Check: func(t testing.TB) {
if env.svcdnnogroup == "" {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdnnogroup, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
if got, want := out, env.expectedaccount; got != want {
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "searching for the 'hackers' user after binding using the account's UPN",
Check: func(t testing.TB) {
if !env.checkbindUPN {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", "serviceuser@example.com", "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
if got, want := out, env.expectedaccount; got != want {
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "querying the root SDE",
Check: func(t testing.TB) {
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-s", "base", "(objectclass=*)")
if got, want := out, env.expectedinfo; got != want {
t.Fatalf("should get some meta information\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "querying the root SDE anonymously without authorizing in config file",
Check: func(t testing.TB) {
if !env.checkanonymousrootDSE {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-x", "-s", "base", "(objectclass=*)")
if got, want := out, "exit status 50"; got != want {
t.Fatalf("should get error 50\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "enumerating posix groups",
Check: func(t testing.TB) {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(objectclass=posixgroup)")
if got, want := out, env.expectedgroup; got != want {
t.Fatalf("should get a list starting with the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "searching for members of the 'superheros' group",
Check: func(t testing.TB) {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com)")
if got, want := out, env.expectedfirstaccount; got != want {
t.Fatalf("should get a list starting with the 'hackers' user\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "performing a complex search for members of 'superheros' group",
Check: func(t testing.TB) {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(&(objectClass=*)(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com))")
if got, want := out, env.expectedfirstaccount; got != want {
t.Fatalf("should get a list starting with the 'hackers' user\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "searching for the 'hacker' user using a TOTP-enabled account",
Check: func(t testing.TB) {
if !env.checkTOTP {
t.SkipNow()
}
otpvalue := doRunGetFirst(RD, "oathtool", "--totp", "-b", "-d", "6", "3hnvnk4ycv44glzigd6s25j4dougs3rk")
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret"+otpvalue, "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
if got, want := out, env.scopedaccount; got != want {
t.Fatalf("should find them in in the 'superheros' group\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "searching for the 'hacker' user using a TOTP-enabled account and no value",
Check: func(t testing.TB) {
if !env.checkTOTP {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
if got, want := out, "exit status 49"; got != want {
t.Fatalf("should get 'Invalid credentials(49)'\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "searching for the 'hacker' user using a TOTP-enabled account and the wrong value",
Check: func(t testing.TB) {
if !env.checkTOTP {
t.SkipNow()
}
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret123456", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
if got, want := out, "exit status 49"; got != want {
t.Fatalf("should get 'Invalid credentials(49)'\ngot: %s\nwant: %s", got, want)
}
},
},
{
Name: "searching for the 'hacker' user",
Check: func(t testing.TB) {
if env.checkemployeetype == "" {
t.SkipNow()
}
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", env.checkemployeetype, "employeetype")
if got, want := out, "employeetype: Intern"; got != want {
t.Fatalf("type should be 'Intern'\ngot: %s\nwant: %s", got, want)
}
},
},
}
Convey("Preflight: Testing pre-requisites", t, func() {
Convey("bin/glauth should exist", func() {
info, err := os.Stat("bin/glauth")
So(err, ShouldEqual, nil)
Convey("bin/glauth should be executable", func() {
mode := uint32(info.Mode())
So(mode&0b001001001, ShouldNotEqual, 0)
for _, tc := range tests {
t.Run(tc.Name, func(t *testing.T) {
tc.Check(t)
Convey("Testing sample-simple local file-based LDAP server", func() {
svc := startSvc(SD, "bin/glauth", "-c", "sample-simple.cfg")
batteryOfTests(
t,
svc, testEnv{
checkanonymousrootDSE: true,
checkTOTP: true,
checkbindUPN: true,
expectedinfo: "supportedLDAPVersion: 3",
svcdn: "cn=serviceuser,ou=svcaccts,dc=glauth,dc=com",
svcdnnogroup: "cn=serviceuser,dc=glauth,dc=com",
otpdn: "cn=otpuser,ou=superheros,dc=glauth,dc=com",
expectedaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
scopedaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
expectedfirstaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
expectedgroup: "dn: ou=superheros,ou=users,dc=glauth,dc=com",
checkemployeetype: "cn=hackers",
})
stopSvc(svc)
})
matchingLibrary := doRunGetFirst(RD, "ls", "bin/sqlite.so")
if matchingLibrary == "bin/sqlite.so" {
Convey("Testing sample-database LDAP server", func() {
svc := startSvc(SD, "bin/glauth", "-c", "pkg/plugins/sample-database.cfg")
batteryOfTests(
t,
svc, testEnv{
checkanonymousrootDSE: true,
checkTOTP: false,
checkbindUPN: true,
expectedinfo: "supportedLDAPVersion: 3",
svcdn: "cn=serviceuser,ou=svcaccts,dc=glauth,dc=com",
svcdnnogroup: "cn=serviceuser,dc=glauth,dc=com",
otpdn: "cn=otpuser,ou=superheros,dc=glauth,dc=com",
expectedaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
scopedaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
expectedfirstaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
expectedgroup: "dn: ou=superheros,ou=users,dc=glauth,dc=com",
checkemployeetype: "",
})
stopSvc(svc)
})
}
})
})
})
matchingContainers := doRunGetFirst(RD, "sh", "-c", "docker ps | grep openldap-service | wc -l")
if matchingContainers == "1" {
Convey("Testing sample-simple local LDAP server", t, func() {
svc := startSvc(SD, "bin/glauth", "-c", "sample-ldap-injection.cfg")
batteryOfTests(
t,
svc, testEnv{
checkanonymousrootDSE: false,
checkTOTP: true,
checkbindUPN: false,
expectedinfo: "objectClass: top",
svcdn: "cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com",
svcdnnogroup: "", // ignore
otpdn: "cn=otpuser,cn=superheros,ou=users,dc=glauth,dc=com",
expectedaccount: "dn: cn=hackers,cn=superheros,ou=users,dc=glauth,dc=com",
scopedaccount: "dn: cn=hackers,cn=superheros,dc=glauth,dc=com",
expectedfirstaccount: "dn: cn=johndoe,cn=superheros,ou=users,dc=glauth,dc=com",
expectedgroup: "dn: ou=superheros,ou=users,dc=glauth,dc=com",
checkemployeetype: "",
})
stopSvc(svc)
})
}
}
func TestSampleSimple(t *testing.T) {
env := testEnv{
checkanonymousrootDSE: true,
checkTOTP: true,
checkbindUPN: true,
expectedinfo: "supportedLDAPVersion: 3",
svcdn: "cn=serviceuser,ou=svcaccts,dc=glauth,dc=com",
svcdnnogroup: "cn=serviceuser,dc=glauth,dc=com",
otpdn: "cn=otpuser,ou=superheros,dc=glauth,dc=com",
expectedaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
scopedaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
expectedfirstaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
expectedgroup: "dn: ou=superheros,ou=users,dc=glauth,dc=com",
checkemployeetype: "cn=hackers",
func batteryOfTests(t *testing.T, svc *exec.Cmd, env testEnv) {
Convey("When searching for the 'hackers' user", func() {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
Convey("We should find them in the 'superheros' group", func() {
So(out, ShouldEqual, env.expectedaccount)
})
})
if env.svcdnnogroup != "" {
Convey("When searching for the 'hackers' user without binding with a group", func() {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdnnogroup, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
Convey("We should find them in the 'superheros' group", func() {
So(out, ShouldEqual, env.expectedaccount)
})
})
}
svc := startSvc(SD, "bin/glauth", "-c", "sample-simple.cfg")
batteryOfTests(t, &env)
stopSvc(svc)
}
func TestSQLitePlugin(t *testing.T) {
matchingLibrary := doRunGetFirst(RD, "ls", "bin/sqlite.so")
if matchingLibrary != "bin/sqlite.so" {
t.SkipNow()
if env.checkbindUPN {
Convey("When searching for the 'hackers' user after binding using the account's UPN", func() {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", "serviceuser@example.com", "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
Convey("We should find them in the 'superheros' group", func() {
So(out, ShouldEqual, env.expectedaccount)
})
})
}
env := testEnv{
checkanonymousrootDSE: true,
checkTOTP: false,
checkbindUPN: true,
expectedinfo: "supportedLDAPVersion: 3",
svcdn: "cn=serviceuser,ou=svcaccts,dc=glauth,dc=com",
svcdnnogroup: "cn=serviceuser,dc=glauth,dc=com",
otpdn: "cn=otpuser,ou=superheros,dc=glauth,dc=com",
expectedaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
scopedaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
expectedfirstaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
expectedgroup: "dn: ou=superheros,ou=users,dc=glauth,dc=com",
checkemployeetype: "",
Convey("When querying the root SDE", func() {
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-s", "base", "(objectclass=*)")
Convey("We should get some meta information", func() {
So(out, ShouldEqual, env.expectedinfo)
})
})
if env.checkanonymousrootDSE {
Convey("When querying the root SDE anonymously without authorizing in config file", func() {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-x", "-s", "base", "(objectclass=*)")
Convey("We should get error 50", func() {
So(out, ShouldEqual, "exit status 50")
})
})
}
svc := startSvc(SD, "bin/glauth", "-c", "pkg/plugins/glauth-sqlite/sample-database.cfg")
batteryOfTests(t, &env)
stopSvc(svc)
}
Convey("When enumerating posix groups", func() {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(objectclass=posixgroup)")
Convey("We should get a list starting with the 'superheros' group", func() {
So(out, ShouldEqual, env.expectedgroup)
})
})
func TestLdapInjection(t *testing.T) {
matchingContainers := doRunGetFirst(RD, "sh", "-c", "docker ps | grep ldap-service | wc -l")
if matchingContainers != "1" {
t.SkipNow()
Convey("When searching for members of the 'superheros' group", func() {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com)")
Convey("We should get a list starting with the 'hackers' user", func() {
So(out, ShouldEqual, env.expectedfirstaccount)
})
})
Convey("When performing a complex search for members of 'superheros' group", func() {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(&(objectClass=*)(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com))")
Convey("We should get a list starting with the 'hackers' user", func() {
So(out, ShouldEqual, env.expectedfirstaccount)
})
})
if env.checkTOTP {
Convey("When searching for the 'hacker' user using a TOTP-enabled account", func() {
otpvalue := doRunGetFirst(RD, "oathtool", "--totp", "-b", "-d", "6", "3hnvnk4ycv44glzigd6s25j4dougs3rk")
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret"+otpvalue, "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
Convey("We should find them in in the 'superheros' group", func() {
So(out, ShouldEqual, env.scopedaccount)
})
})
Convey("When searching for the 'hacker' user using a TOTP-enabled account and no value", func() {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
Convey("We should get 'Invalid credentials(49)'", func() {
So(out, ShouldEqual, "exit status 49")
})
})
Convey("When searching for the 'hacker' user using a TOTP-enabled account and the wrong value", func() {
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret123456", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
Convey("We should get 'Invalid credentials(49)'", func() {
So(out, ShouldEqual, "exit status 49")
})
})
}
env := testEnv{
checkanonymousrootDSE: false,
checkTOTP: true,
checkbindUPN: false,
expectedinfo: "objectClass: top",
svcdn: "cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com",
svcdnnogroup: "", // ignore
otpdn: "cn=otpuser,cn=superheros,ou=users,dc=glauth,dc=com",
expectedaccount: "dn: cn=hackers,cn=superheros,ou=users,dc=glauth,dc=com",
scopedaccount: "dn: cn=hackers,cn=superheros,ou=users,dc=glauth,dc=com",
expectedfirstaccount: "dn: cn=johndoe,cn=superheros,ou=users,dc=glauth,dc=com",
expectedgroup: "dn: ou=superheros,ou=users,dc=glauth,dc=com",
checkemployeetype: "",
if env.checkemployeetype != "" {
Convey("When searching for the 'hacker' user", func() {
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", env.checkemployeetype, "employeetype")
Convey("Employee type should be 'Intern'", func() {
So(out, ShouldEqual, "employeetype: Intern")
})
})
}
svc := startSvc(SD, "bin/glauth", "-c", "sample-ldap-injection.cfg")
batteryOfTests(t, &env)
stopSvc(svc)
}
// -----=============================================================================----
+18 -33
View File
@@ -1,59 +1,44 @@
module github.com/glauth/glauth/v2
go 1.21
go 1.19
require (
github.com/BurntSushi/toml v1.3.2
github.com/GeertJohan/yubigo v0.0.0-20190917122436-175bc097e60e
github.com/arl/statsviz v0.6.0
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/fsnotify/fsnotify v1.7.0
github.com/glauth/ldap v0.0.0-20240419171521-1f14f5c1b4ad
github.com/fsnotify/fsnotify v1.6.0
github.com/glauth/ldap v0.0.0-20231210225823-b9bf4d1baf6e
github.com/jinzhu/copier v0.4.0
github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.18.0
github.com/prometheus/client_golang v1.17.0
github.com/prometheus/client_model v0.5.0
github.com/rs/zerolog v1.31.0
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3
github.com/smartystreets/goconvey v1.8.1
github.com/yaegashi/msgraph.go v0.1.4
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1
go.opentelemetry.io/otel v1.21.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0
go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/trace v1.21.0
go.uber.org/mock v0.4.0
golang.org/x/crypto v0.18.0
go.uber.org/mock v0.3.0
golang.org/x/crypto v0.14.0
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/kr/text v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rickb777/date v1.12.4 // indirect
github.com/rickb777/plural v1.2.0 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.59.0 // indirect
github.com/rickb777/date v1.20.5 // indirect
github.com/rickb777/plural v1.4.1 // indirect
github.com/smarty/assertions v1.15.0 // indirect
golang.org/x/sys v0.13.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
)
+43 -80
View File
@@ -7,117 +7,92 @@ github.com/arl/statsviz v0.6.0 h1:jbW1QJkEYQkufd//4NDYRSNBpwJNrdzPahF7ZmoGdyE=
github.com/arl/statsviz v0.6.0/go.mod h1:0toboo+YGSUXDaS4g1D5TVS4dXs7S7YYT5J/qnW2h8s=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/glauth/ldap v0.0.0-20240419171521-1f14f5c1b4ad h1:2ERGXiofR9ISXg4evamCngs2EeuMhVJRuDwWGa6bS6s=
github.com/glauth/ldap v0.0.0-20240419171521-1f14f5c1b4ad/go.mod h1:5ueZMujvJ5nuYPyBj6uQTPV4R1YshboRa/osaP4Emfs=
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/glauth/ldap v0.0.0-20231210225823-b9bf4d1baf6e h1:ohe1O2DUo198delHsQvA8O+CgAPP8wv1SmSxLPlO9ao=
github.com/glauth/ldap v0.0.0-20231210225823-b9bf4d1baf6e/go.mod h1:EHMcFuVSIs0huelHOhaGtj9IKMB/Dmxo+jDheipjtYA=
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rickb777/date v1.12.4 h1:+6IzcCCS/1t17DrmnEvrznyq7nM8vPwir6/UhlyohKw=
github.com/rickb777/date v1.12.4/go.mod h1:xP0eo/I5qmUt97yRGClHZfyLZ3ikMw6v6SU5MOGZTE0=
github.com/rickb777/plural v1.2.0 h1:5tvEc7UBCZ7l8h/2UeybSkt/uu1DQsZFOFdNevmUhlE=
github.com/rickb777/date v1.20.5 h1:Ybjz7J7ga9ui4VJizQpil0l330r6wkn6CicaoattIxQ=
github.com/rickb777/date v1.20.5/go.mod h1:6BPrm3/aQI0I8jvlD1fAlm/86k5eSeTQ2mR5FEmTnSw=
github.com/rickb777/plural v1.2.0/go.mod h1:UdpyWFCGbo3mvK3f/PfZOAOrkjzJlYN/sD46XNWJ+Es=
github.com/rickb777/plural v1.4.1 h1:5MMLcbIaapLFmvDGRT5iPk8877hpTPt8Y9cdSKRw9sU=
github.com/rickb777/plural v1.4.1/go.mod h1:kdmXUpmKBJTS0FtG/TFumd//VBWsNTD7zOw7x4umxNw=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3 h1:LNi0Qa7869/loPjz2kmMvp/jwZZnMZ9scMJKhDJ1DIo=
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3/go.mod h1:jyigonKik3C5V895QNiAGpKYKEvFuqjw9qAEZks1mUg=
github.com/yaegashi/msgraph.go v0.1.4 h1:leDXSczAbwBpYFSmmZrdByTiPoUw8dbTfNMetAjJvbw=
github.com/yaegashi/msgraph.go v0.1.4/go.mod h1:vgeYhHa5skJt/3lTyjGXThTZhwbhRnGo6uUxzoJIGME=
github.com/yaegashi/wtz.go v0.0.2/go.mod h1:nOLA5QXsmdkRxBkP5tljhua13ADHCKirLBrzPf4PEJc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1 h1:f4beMGDKiVzg9IcX7/VuWVy+oGdjx3dNJ72YehmtY5k=
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1/go.mod h1:U9jhkEl8d1LL+QXY7q3kneJWJugiN3kZJV2OWz3hkBY=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E=
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -126,8 +101,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -137,32 +111,23 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200529172331-a64b76657301/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
@@ -170,6 +135,4 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b h1:tdSyAzD5FHJmZAZ13d5WexAo7YJkiyGphhzFfInMnDw=
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b/go.mod h1:cE0dCGx2UfBTjLFlzEx4EXJUmoX6BXBoX9GjKOvqha4=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+2
View File
@@ -21,6 +21,8 @@ func (m *LDAPMonitorWatcher) sync() {
case tick := <-m.syncTicker.C:
m.logger.Debug().Time("value", tick).Msg("Tick")
m.storeMetrics()
default:
continue
}
}
}
+5 -47
View File
@@ -12,29 +12,8 @@ var (
log zerolog.Logger
)
var secureCipherSuites = []uint16{
// TLS 1.3 cipher suites (automatically used when TLS 1.3 is negotiated)
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
tls.TLS_CHACHA20_POLY1305_SHA256,
// TLS 1.2 ECDHE cipher suites (Forward Secrecy)
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
// Additional secure TLS 1.2 cipher suites (CBC with HMAC-SHA256)
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
// tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
// tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
}
// MakeTLS generates a tls.Config
func MakeTLS(clientCert, key []byte, legacy bool) (*tls.Config, error) {
func MakeTLS(clientCert, key []byte) (*tls.Config, error) {
if clientCert == nil && key == nil {
return new(tls.Config), nil
}
@@ -76,24 +55,11 @@ func MakeTLS(clientCert, key []byte, legacy bool) (*tls.Config, error) {
log.Debug().Interface("root.ca", rootCAs)
log.Debug().Interface("certificates", []tls.Certificate{cert})
if legacy {
return &tls.Config{
RootCAs: rootCAs,
MinVersion: tls.VersionTLS10,
MaxVersion: tls.VersionTLS13,
PreferServerCipherSuites: true,
CipherSuites: nil,
Certificates: []tls.Certificate{cert},
}, nil
}
return &tls.Config{
RootCAs: rootCAs,
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
PreferServerCipherSuites: true,
CipherSuites: secureCipherSuites,
Certificates: []tls.Certificate{cert},
RootCAs: rootCAs,
MinVersion: tls.VersionTLS10,
MaxVersion: tls.VersionTLS13,
Certificates: []tls.Certificate{cert},
}, nil
}
@@ -113,11 +79,3 @@ func DecodePEM(certPEM []byte) tls.Certificate {
return cert
}
func CipherSuiteNames(suites []uint16) []string {
var names []string
for _, suite := range suites {
names = append(names, tls.CipherSuiteName(suite))
}
return names
}
+25 -63
View File
@@ -179,13 +179,11 @@ func parseConfigFile(configFileLocation string, args map[string]interface{}) (*c
// Patch with default values where not specified
for i := range cfg.Backends {
if cfg.Backends[i].NameFormat == "" {
cfg.Backends[i].NameFormat = "cn,uid"
cfg.Backends[i].NameFormat = "cn"
}
cfg.Backends[i].NameFormatAsArray = strings.Split(cfg.Backends[i].NameFormat, ",")
if cfg.Backends[i].GroupFormat == "" {
cfg.Backends[i].GroupFormat = "ou,cn"
cfg.Backends[i].GroupFormat = "ou"
}
cfg.Backends[i].GroupFormatAsArray = strings.Split(cfg.Backends[i].GroupFormat, ",")
if cfg.Backends[i].SSHKeyAttr == "" {
cfg.Backends[i].SSHKeyAttr = "sshPublicKey"
}
@@ -223,7 +221,9 @@ func usersCustomAttributes(location string, config *config.Config) {
x := make(map[string]interface{})
for _, attribute := range user.CustomAttributes {
_ = md.PrimitiveDecode(attribute, x)
err := md.PrimitiveDecode(attribute, x)
fmt.Println(err, x)
for k, v := range x {
@@ -386,47 +386,13 @@ func validateConfig(cfg *config.Config) (*config.Config, error) {
if cfg.LDAPS.Enabled {
// LDAPS enabled - verify requirements (cert, key, listen)
if len(cfg.LDAPS.Cert) == 0 || len(cfg.LDAPS.Key) == 0 {
return cfg, fmt.Errorf("LDAPS was enabled but no certificate or key were specified: please disable LDAPS or use the 'cert' and 'key' options")
}
if len(cfg.LDAPS.Listen) == 0 {
return cfg, fmt.Errorf("no LDAPS bind address was specified: please disable LDAPS or use the 'listen' option")
}
if cfg.LDAPS.Cert == "" && cfg.LDAPS.CertPath != "" {
byteData, err := os.ReadFile(cfg.LDAPS.CertPath)
if err != nil {
return cfg, fmt.Errorf("unable to read TLS certificate file")
}
cfg.LDAPS.Cert = string(byteData)
}
if cfg.LDAPS.Key == "" && cfg.LDAPS.KeyPath != "" {
byteData, err := os.ReadFile(cfg.LDAPS.KeyPath)
if err != nil {
return cfg, fmt.Errorf("unable to read TLS key file")
}
cfg.LDAPS.Key = string(byteData)
}
// Ugly wart for backward compatibility
// In the olden times, we would simply say "please read from this file"
// This is now the role of the Path files.
if !strings.HasPrefix(cfg.LDAPS.Cert, "-----") {
byteData, err := os.ReadFile(cfg.LDAPS.Cert)
if err != nil {
return cfg, fmt.Errorf("unable to read TLS certificate file")
}
cfg.LDAPS.Cert = string(byteData)
}
if !strings.HasPrefix(cfg.LDAPS.Key, "-----") {
byteData, err := os.ReadFile(cfg.LDAPS.Key)
if err != nil {
return cfg, fmt.Errorf("unable to read TLS key file")
}
cfg.LDAPS.Key = string(byteData)
}
if cfg.LDAPS.Cert == "" || cfg.LDAPS.Key == "" {
return cfg, fmt.Errorf("LDAPS was enabled but no certificate or key were specified: please disable LDAPS or use the 'cert'/'key' or 'certpath'/'keypath' options")
}
}
if cfg.LDAP.Enabled {
@@ -435,27 +401,24 @@ func validateConfig(cfg *config.Config) (*config.Config, error) {
return cfg, fmt.Errorf("no LDAP bind address was specified: please disable LDAP or use the 'listen' option")
}
if cfg.LDAP.TLS {
if cfg.LDAP.TLSCert == "" && cfg.LDAP.TLSCertPath != "" {
byteData, err := os.ReadFile(cfg.LDAP.TLSCertPath)
if err != nil {
return cfg, fmt.Errorf("unable to read TLS certificate file")
}
cfg.LDAP.TLSCert = string(byteData)
}
if cfg.LDAP.TLS && cfg.LDAP.TLSCert == "" && cfg.LDAP.TLSCertPath != "" {
byteData, err := os.ReadFile(cfg.LDAP.TLSCertPath)
cfg.LDAP.TLSCert = string(byteData)
if cfg.LDAP.TLSKey == "" && cfg.LDAP.TLSKeyPath != "" {
byteData, err := os.ReadFile(cfg.LDAP.TLSKeyPath)
if err != nil {
return cfg, fmt.Errorf("unable to read TLS key file")
}
cfg.LDAP.TLSKey = string(byteData)
}
if cfg.LDAP.TLSCert == "" || cfg.LDAP.TLSKey == "" {
return cfg, fmt.Errorf("StartTLS was enabled but no certificate or key were specified: please disable StartTLS or use the 'tlscert'/'tlskey' or 'tlscertpath'/'tlskeypath' options")
if err != nil {
return cfg, fmt.Errorf("unable to read TLS certificate file")
}
}
if cfg.LDAP.TLS && cfg.LDAP.TLSKey == "" && cfg.LDAP.TLSKeyPath != "" {
byteData, err := os.ReadFile(cfg.LDAP.TLSKeyPath)
cfg.LDAP.TLSKey = string(byteData)
if err != nil {
return cfg, fmt.Errorf("unable to read TLS key file")
}
}
}
//spew.Dump(cfg)
@@ -467,9 +430,8 @@ func validateConfig(cfg *config.Config) (*config.Config, error) {
case "ldap":
case "owncloud":
case "plugin":
case "embed":
default:
return cfg, fmt.Errorf("invalid backend %s - must be 'config', 'ldap', 'owncloud', 'plugin' or 'embed", cfg.Backends[i].Datastore)
return cfg, fmt.Errorf("invalid backend %s - must be 'config', 'ldap', 'owncloud' or 'plugin'", cfg.Backends[i].Datastore)
}
}
-24
View File
@@ -1,24 +0,0 @@
package tracing
import (
"github.com/rs/zerolog"
)
type Config struct {
OtelHTTPEndpoint string
OtelGRPCEndpoint string
Logger *zerolog.Logger
Enabled bool
}
func NewConfig(enabled bool, otelGRPCEndpoint, otelHTTPEndpoint string, logger *zerolog.Logger) *Config {
c := new(Config)
c.OtelGRPCEndpoint = otelGRPCEndpoint
c.OtelHTTPEndpoint = otelHTTPEndpoint
c.Logger = logger
c.Enabled = enabled
return c
}
-134
View File
@@ -1,134 +0,0 @@
package tracing
import (
"context"
"runtime/debug"
"github.com/rs/zerolog"
"go.opentelemetry.io/contrib/propagators/jaeger"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
"go.opentelemetry.io/otel/trace/noop"
)
type Tracer struct {
embedded.Tracer
tracer trace.Tracer
logger *zerolog.Logger
}
func (t *Tracer) init(service string, e sdktrace.SpanExporter) {
traceProvider := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(e),
sdktrace.WithResource(
t.buildResource(service),
),
)
otel.SetTracerProvider(traceProvider)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}, jaeger.Jaeger{}))
t.tracer = otel.Tracer(service)
}
func (t *Tracer) gitRevision(settings []debug.BuildSetting) string {
for _, setting := range settings {
if setting.Key == "vcs.revision" {
return setting.Value
}
}
return "n/a"
}
func (t *Tracer) buildResource(service string) *resource.Resource {
var res *resource.Resource
res = resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(service),
semconv.ServiceVersion("n/a"),
)
if info, ok := debug.ReadBuildInfo(); ok {
if service == "" {
service = info.Path
}
res = resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(service),
attribute.String("git_sha", t.gitRevision(info.Settings)),
attribute.String("app", info.Main.Path),
)
}
return res
}
func (t *Tracer) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
return t.tracer.Start(ctx, spanName, opts...)
}
// basic tracer implementation of trace.Tracer, just adding some extra configuration
func NewTracer(cfg *Config) *Tracer {
t := new(Tracer)
t.logger = cfg.Logger
// if tracing disabled skip the config
if !cfg.Enabled {
t.tracer = noop.NewTracerProvider().Tracer("github.com/glauth/glauth")
return t
}
var err error
var exporter sdktrace.SpanExporter
if cfg.OtelGRPCEndpoint != "" {
exporter, err = otlptrace.New(
context.TODO(),
otlptracegrpc.NewClient(
otlptracegrpc.WithEndpoint(cfg.OtelGRPCEndpoint),
otlptracegrpc.WithInsecure(),
),
)
} else if cfg.OtelHTTPEndpoint != "" {
exporter, err = otlptrace.New(
context.TODO(),
otlptracehttp.NewClient(
otlptracehttp.WithEndpoint(cfg.OtelHTTPEndpoint),
otlptracehttp.WithInsecure(),
),
)
} else {
exporter, err = stdouttrace.New(
stdouttrace.WithPrettyPrint(),
)
}
if err != nil {
t.logger.Error().Err(err).Msg("unable to initialize tracing exporter")
return nil
}
// set tracer provider and propagator properly, this is to ensure all
// instrumentation library could run well
t.init("github.com/glauth/glauth", exporter)
return t
}
+1 -1
View File
@@ -2,4 +2,4 @@ package version
// Version is the tag of the latest release, it gets changed by the ci
// process when a release is happening
const Version = "v2.5.0" // x-release-please-version
const Version = "v2.3.0" // x-release-please-version
-3
View File
@@ -1,3 +0,0 @@
olcAccess: to dn.subtree="dc=glauth,dc=com"
by dn.exact="cn=admin,dc=glauth,dc=com" manage
by * break
@@ -1,7 +0,0 @@
dn: olcDatabase={1}mdb,cn=config
changetype: modify
delete: olcAccess
-
add: olcAccess
olcAccess: to attrs=userPassword,shadowLastChange by self write by dn="cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com" write by anonymous auth by * none
olcAccess: to * by self write by dn="cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com" write by users read by * none
@@ -1,4 +0,0 @@
dn: cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com
changetype: modify
replace: userPassword
userPassword: mysecret
-3
View File
@@ -1,3 +0,0 @@
TLS_REQCERT never
URI ldaps://192.168.1.222
BASE dc=test,dc=example,dc=com
-83
View File
@@ -1,83 +0,0 @@
#!/usr/bin/env bash
for arg in "$@"; do
if [[ "$arg" == *"="* ]]; then
key="${arg%%=*}"
value="${arg#*=}"
eval "$key"="'$value'"
else
eval "$arg"=true
fi
done
if [[ "$ipaddr" == "" ]]; then
echo "Please provide ipaddr=<ip address> to create/use" >&2
exit 1
fi
if [[ "$ipmask" == "" ]]; then
ipmask=24
fi
eipaddr=$(echo "$ipaddr" | sed 's/\./\\./g')
ifname=$(ip -brief addr show | awk "/$eipaddr\// {print \$1}")
if [[ "$ifname" == "" ]]; then
ping -c 1 $ipaddr &>/dev/null
if [[ $? -eq 0 ]]; then
echo "It looks like you specified an already allocated ip address." >&2
exit 1
fi
fi
if [[ "$ifname" == "" ]]; then
passed=0
if [[ "$ipmask" == "" ]]; then
passed=1
fi
if [[ "$iface" == "" ]]; then
passed=2
fi
if [[ $passed -ne 0 ]]; then
echo "To create an interface, specify ipaddr=<ip address> ipmask=<mask> iface=<interface name>" >&2
echo "Example: ipaddr=192.168.1.222 ipmask=24 iface=en0" >&2
exit 1
fi
echo "Creating $ipaddr/$ipmask on interface $iface"
sudo ip addr add $ipaddr/$ipmask dev $iface
fi
if [[ "$domain" == "" ]]; then
domain="TEST.EXAMPLE.COM"
fi
if [[ "$defaultdns" == "" ]]; then
defaultdns="192.168.1.1"
fi
echo "Running Samba AD, listening on $ipaddr for domain $domain"
docker run -d
--name ad \
--hostname DC1 \
--restart unless-stopped \
-e REALM='TEST.LOCAL' \
-e DOMAIN='TEST' \
-e ADMIN_PASS='MySecret2026!' \
-e DNS_FORWARDER='8.8.8.8' \
-v dc_etc:/usr/local/samba/etc \
-v dc_private:/usr/local/samba/private \
-v dc_var:/usr/local/samba/var \
-p $ipaddr:53:53 \
-p $ipaddr:53:53/udp \
-p $ipaddr:88:88 \
-p $ipaddr:88:88/udp \
-p $ipaddr:135:135 \
-p $ipaddr:137-138:137-138/udp \
-p $ipaddr:139:139 \
-p $ipaddr:389:389 \
-p $ipaddr:389:389/udp \
-p $ipaddr:445:445 \
-p $ipaddr:464:464 \
-p $ipaddr:464:464/udp \
-p $ipaddr:636:636 \
-p $ipaddr:1024-1044:1024-1044 \
-p $ipaddr:3268-3269:3268-3269 \
diegogslomp/samba-ad-dc
-33
View File
@@ -1,33 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFtDCCA5ygAwIBAgIEhCJsaTANBgkqhkiG9w0BAQsFADB6MR0wGwYDVQQKExRT
YW1iYSBBZG1pbmlzdHJhdGlvbjE3MDUGA1UECxMuU2FtYmEgLSB0ZW1wb3Jhcnkg
YXV0b2dlbmVyYXRlZCBDQSBjZXJ0aWZpY2F0ZTEgMB4GA1UEAxMXVEVTVERDLnRl
c3QuZXhhbXBsZS5jb20wHhcNMjYwMTE4MDAwMDA0WhcNMjcxMjE5MDAwMDA0WjB6
MR0wGwYDVQQKExRTYW1iYSBBZG1pbmlzdHJhdGlvbjE3MDUGA1UECxMuU2FtYmEg
LSB0ZW1wb3JhcnkgYXV0b2dlbmVyYXRlZCBDQSBjZXJ0aWZpY2F0ZTEgMB4GA1UE
AxMXVEVTVERDLnRlc3QuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQDuYBt2jNruSR4xL0wI8Nx2uq+jQKpiViWzDPw4eivNrLXc8Bdr
o9GqCo4uokPZiFS6jGez3holnMKF1bxU8uES2ma228zRIJVAHo0qU2O8zGoMtAuL
Z+F9gZAVSQKUMp0Vl2yyNERY453Ne4B2Oz92G87YtNuDyNYzuK4778FiE5iXjvan
CsAENXrspfxvn8QD5IloHPFoieFkfeaigDA6Zjtr2be+LhDbc2wn6YY7t8Z+5wxG
UPUy8oYKQ5lyHSn6I7aezAJpJJHSN4eSg76smTMjUOAnLqJJHPurGF9zzq+maRg+
M2runjqRcnZzQtkdZJayK8GQ39kEFpHnl1PueexFEIA5PxHaJEbapAiL7nP65bAy
Ey6wiOVvuLgztf8CU6hT/Not3qVG5lCGiK1VC9W684X5vQcVnQXTAIY3Edt91u8C
/wt4i5j58orVbcghAZMsU3FKjjqyvQMMSD2Pwgf6+m2mVQIAnZOrkErsQrltmFxO
CPBbRY+5Yg8v2ZucMWfKNy4IEzm8LyddrZKAENbW73/bZtPCw7cJqeb6ZaWVzrqW
BAgMiyrBYq/oGnXP6rHnTpB02LWTx8dvPPmEgvPhjecCRKroesYeKX38KWywGalA
xXbs+Eo9ApGst7qhkenAzM3E7Fy56OoELUAKGQW9gtVEnn+8BofLhezUyQIDAQAB
o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
ShGTEQzxmK0IrRMPiPYbRxfntYQwDQYJKoZIhvcNAQELBQADggIBAFxD6ShgnqwK
6oMzXKZOXoVfVu8yFKhL9Z3ui+6Q/duckzLf873sMlxz9msLTjH1O2Pk9gaND9/l
25t37BvVLuNTJKHvTfte53l8fQUrqCgOq2feARoXyCAA77bTUh+uSGsjZYGbSJx/
M93fOtabElD9T3o3B0L2EJyL7LHZ3in9MOyVBBcCnOMqi+1eoQEnaoj5TRnE8eEu
RuTs7Vu3lceZuCvH1mTRPis2D8bPCWa3aAI6w+LZoJNP3B1izo6Arjje7TBHBMGJ
A65o9LP1+OeZ5EA+J3nIkU5rSHu+Pk5biBNEThsnkGjEhSTXZPCVgZRQJOgQyvnf
LPWUOMdMLsnsO2oW3/BG6zTmbZw4CMzE8yZUtNZxph7+N1ukzYWZbSwDADxxi+dQ
vFQk6tguKpxBCko+pWajgNcxG97MFQMMCfGfva7xdaqBSB4R8sdmQm+wknAYQrlm
Jc6csvkJgoIHvyBn9yfSKYNvbjh8RUGA2TZMWrbBMdt51ivw6e1NM16OneGtELh+
zGlgv0EfJPaf9IG+RWqvMuhGFF1DgqBi8l816XFy4g3SEFC2F0D6VAv9mQZdq8q1
9y7B9vpcBQbNiHqJahIEwgp1JlHdoj281Ms2KixBf88O0y7zSMbyejxHtGv8IUVD
+Nth1G9FpENenG73njJIh1dLLYyHvxnp
-----END CERTIFICATE-----
-30
View File
@@ -1,30 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFETCCAvmgAwIBAgIUHfUrLa/sMlGeT6VIZdkj73UjZfkwDQYJKoZIhvcNAQEL
BQAwGDEWMBQGA1UEAwwNU2FtYmEgVGVzdCBDQTAeFw0yNjAxMTgwMTEzMzVaFw0z
NjAxMTYwMTEzMzVaMBgxFjAUBgNVBAMMDVNhbWJhIFRlc3QgQ0EwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQC464FD54YJ1rgi/5Z9DQrIbEzED8NhMjo/
ndqD+0sfqkiYjQEqAh7Wpj+6r9D9AZ1wnTdF2Ee767OTwkSA2lG5aQAF9HDFzgIJ
8yVbeqJIABOzKotLTl1wCNeRx+YeY69xcytzsQ6iNFyOVV/CbkbxtyJvDfxD9rC5
Pwf1A7yBLz0H8U+kXBKC0SCDSW4+SAgmJQu3NQ7wd2eg+EBH/cPVhw0F97K3Yfb0
c8wekQdqAMrvfo/jq81/JADUEmzi1lyQ34zX2ToBIeu42/oTBmJ8ZX2ZAFgUu0y1
Kh+rmmYLhszPLfwB/28j1wizd/iVdpN0+ssJj3y+rEgKeXFfo1x7KSWprHUCJzZk
+T7l59tEg7ZiSuRexgkc3Rf+4DYNq7JzCFnVnBvhC++fym29JRrriX0DOUYMGAS3
dFBiLJT65kdLCwrgkCAZTbsNKTVkEQx3QYn58dUYMTmQXndg4AEG0VUa4s+oqOFu
jokyeqVqp37CUm0MU9cKJVnkMqWkqI9JRTBe90xHSy5xrmB0N1zM/FbUTBvMCh6Z
t7ZAiB3gB1LTXaDRWafJ+opYJtPkVhvAlmFjEwuYCYdUM8lz+i/MKK8hrAoztUvr
C2n5qoDUX5Tm9VygefWVxzCvyzTy+FKEq+4aU8ye0zohCJ+UP1SMi3j98aGdVjBJ
sI9KhOQNmQIDAQABo1MwUTAdBgNVHQ4EFgQUgFOZGLtmwudA8tVaKeLvowVQLMYw
HwYDVR0jBBgwFoAUgFOZGLtmwudA8tVaKeLvowVQLMYwDwYDVR0TAQH/BAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAgEAPNmj5RCacwRbySYERx8XBlcV50DRFnFS51G0
EEKObiOBxt/xboAt/bPw+6dVeqS0JILrgMJhHn7dufRTdnGK/z9VkRDrTh6FudAk
16qdhglXzPrPzETGl1VHJxQEkqm+qkUeD4r9waUP5ZIXdsUrvGdnCaXgQRA3v2RD
NDvNldmgCTScjTPM4ox0B2iL0P0Uo4pRzQTGuPmubCMv2B8EkBOPIQx/TO2svL6M
oal/25v06+xUEyVAxWQPD4xolL8ksEjdqa7l5h/1YkpouWq+jaEDpWGzVqt/fLYI
cdGUxSNcaueEmHB2QOklrTdDVvvczAE98ytDZ/zswj8cKKLhe2d3Z3ie40xx+4/x
NprbosIGWrHnz0NbDlzXRvd8yk7ZWk4QFRycJb7Ve3Za3hPOlDeKgm5iCjafCS4G
C1D8r+SwGjCjgsaL7J/zY4IHyxurRVBU+jZSRgy2WQlR/BQ2gSdVt3BhxsEPgbmu
jKOiPltNkqPmUHoXFnosJyAblF8yjYkBPBpbM5luAUiKMYBkdkSA3oSJYK3WuIDl
UNcKwcC9sJPu63ciPDtEZlgV5blvMr80PPyJZDofo+KHxWweKxoyXxQoIKCrP53D
Av2KGBhIZlJUzNrj4LWMGbf+8BAGL+i1oyM77D/N8L589Y0x1mQMa/quQW+TJ8kH
g2wgxQw=
-----END CERTIFICATE-----
-52
View File
@@ -1,52 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQC464FD54YJ1rgi
/5Z9DQrIbEzED8NhMjo/ndqD+0sfqkiYjQEqAh7Wpj+6r9D9AZ1wnTdF2Ee767OT
wkSA2lG5aQAF9HDFzgIJ8yVbeqJIABOzKotLTl1wCNeRx+YeY69xcytzsQ6iNFyO
VV/CbkbxtyJvDfxD9rC5Pwf1A7yBLz0H8U+kXBKC0SCDSW4+SAgmJQu3NQ7wd2eg
+EBH/cPVhw0F97K3Yfb0c8wekQdqAMrvfo/jq81/JADUEmzi1lyQ34zX2ToBIeu4
2/oTBmJ8ZX2ZAFgUu0y1Kh+rmmYLhszPLfwB/28j1wizd/iVdpN0+ssJj3y+rEgK
eXFfo1x7KSWprHUCJzZk+T7l59tEg7ZiSuRexgkc3Rf+4DYNq7JzCFnVnBvhC++f
ym29JRrriX0DOUYMGAS3dFBiLJT65kdLCwrgkCAZTbsNKTVkEQx3QYn58dUYMTmQ
Xndg4AEG0VUa4s+oqOFujokyeqVqp37CUm0MU9cKJVnkMqWkqI9JRTBe90xHSy5x
rmB0N1zM/FbUTBvMCh6Zt7ZAiB3gB1LTXaDRWafJ+opYJtPkVhvAlmFjEwuYCYdU
M8lz+i/MKK8hrAoztUvrC2n5qoDUX5Tm9VygefWVxzCvyzTy+FKEq+4aU8ye0zoh
CJ+UP1SMi3j98aGdVjBJsI9KhOQNmQIDAQABAoICADiu8APZn2u6pt0LjZytd8Wx
9OIQlupfVB2WDJpyWDfPocspRdcTqVJQya43II+9g/42IvBE+NAw0u4TGZ6JzY1R
E1G/+SWZHWThZG0jLUV2yJMeEm62CcxC2Zl1NiPQmMHk9MfU2VB9TnXO07isxxBm
+6YhGlfW8ZsHKDBBwfGzgjjCDpCqLH5vDlFQG/v5Zo4SwwGYwQiTAXAFSOcIcZQt
fp96qwyted669DHWcPhcX9iD6iV2z1oOtjZLo5bw8JT0AZ9UlgQs2q3iuEhGp7/L
+HEC+vz34O6Th/u5K1iTLIrBZMNUAkRxMNiaiNd/7nloOv6mPi3Qb5DOYyNW1wzg
TlF5fERqz2OeuFqjnEfoE/uFjvBN0bclenuFTCWDeSxEZqni9qjLhnqK4Iot7/D2
P148t4UIT8h5l82Wiod05cenlnPfpWbRRdzVXy0NZe1BTf2U8LXRW1ANdJyfVSC6
802KPP6noWnaFYfkhIIdD10ZlTd9vTwdcHEYfoJNNbXcwwI/OslGwPB1a+tp+rSd
Vr2l8RoF0/28cjsRnDi7hoaMkNIqszXq1WA+d5zOvmOsfuy/32pfnm+rw8HafYNj
SNK0t5sh0PCsHrRrCRfTaOIQbFveABcf0uxbM68xSMAIKH8rpTrp4lcEEO5Yrcrj
qDFQ7rw+VnRR0Nu4eX+VAoIBAQDbWhvWkZssTNHR8Xs9OtaAiHktEgJbreaRPvCe
GgfyuZ+aYj6M9ivY/z99AJqH4pueXWbZuyBHmPp39zvvN44WP6Yc+4EDyDpiRIxi
CjofYzbOIMxnMqgXePPWHXv+UA1zaSu1HGF1kMMeU+cT4knQpkQNrbmioYIetOnU
BzdKJt/LTK2KRvHn4VN6Tt49ZnIfrAo8UIOZPdpT6qumX/RENw0/66AU220bLtaP
xxZNqipjf56wikkQiHbmP85ZW9dPTR2aUtJZkS7nmJhTuH782ES96soPjYREH/fZ
K5TdWn7Se6NcdHgoG5W2voqP3GFUyvKxRNLSK/tjN1UGYKx/AoIBAQDX0LSDjqKX
nn+kZBHVXmMtEWVu44CijdDvBIkri5rjO5QdEtgk15gxYXwakRiXgmpsDk/fyBEQ
n7iIlao697vNh3cWbe9xuBBhccLcmkrt1qKSO9a1qjbh4lZ10F4SLsZrDz1dTWwf
Xvlofl1oNbh9a39xDT9Pa6qt2tZLThianqjHXssMsaEQPNrWduJmM8um/OT+CHoJ
6XTzX9SZrMOcevPdAWARdqgBohcfMD2LhMkY0HIkZGdP1/FYdAbHqjK+81pvtPYE
JNRQLCgWMWqfUnnay6lMwN/0U7u0AHE4futYMqrn8gGl0JuGLZ6o1BDxpf2Thkfv
KpDLDcyFMBnnAoIBAQDGfXvDZm8sXzde603B0oRYOyasCifoHi0OMg46gwO+OQqc
AVro47o52n/w9aLgY8a+P3baf+Jt55h/BlJN3c/Ngjsm7s+IRJ/QXIdMEEUYMgdd
74AHwmcpFmJP1s5lCruhPAI5GT13zU9DGll4PMTe8hWS6ymYaN3+O2d8XitCBnts
1C4Veq1cTyHjA4tHtHSBBIUenxz2hmoSlcBOBXZcZBSxSt7JAOZyOqgd4uHj1aAV
+V34EqqbM2GkaQipA9qKABZRl7CRLDdti0AMQl9nHazWzqeZ+008+FCnTDChPUqV
3RuuhhZU9OE9RJ7OH3ZT7HJAxy6e0P3igieGZeSxAoIBAQCho2ogAmuavZaCTITi
1w/WyGm9NN26YhczfaUzHRuDx7K2V8/VQDh3+7iUuUm+6GnGxq1iQRku50Gx4s6d
3cAmPqid/vbQqHh0U10MFu+51QDsH68/Xt4+LmRtVwOuAKSRuNdQE1XA5URN1B8n
lty36xSHWtGpLU2navkHa9WXsO9ea4wO1Nd6LuoEqQQGYhLM3iqwbS7iT51NTuAP
vUrA34HYbFhEnCdXGczRijL+VRS85honUZ/jOCxGAJi3YK0jQWbhtZpxHhh6d6gK
fzaJX59ulQ0XNHpIJ5K1TYN/OegQpdpFYIeFZomlZHOppTOPmbAjlvY3lhzeSFZ/
BrjPAoIBAQCsJqoFNpJpJFT/gGL6xWS4O158E5GxYXl3raN/dfBMGZnbTr0nHrbC
4vyrWaQFVsovea7SZnzfLdyesLuJ1FIUhsal166o/g6Vf5wgDn7LHZ202tt2DokV
ECETQTA+VBTXysc7/dwsTohbee7Jg6xZ/qHSdP6nUan9xiC3pOx0G/vT5FaH9kBJ
dJ2mQ93n/l1A6q9Hn5AFyoCqniOszVsQ357N9uxakQiX48JKKWG7+BneKtGzN2bu
9ArlPSNscNDb4yF2fqksTHvIYbGuJ3icbObjWUKOCQbtpva4Rkrnoqqg5nHM0L+f
3tGhl1yrO4/YIpQrp0OgMV1HDYXEOwwI
-----END PRIVATE KEY-----
-1
View File
@@ -1 +0,0 @@
59634A59EBDC029E7D479619E12C1868317CE811
-17
View File
@@ -1,17 +0,0 @@
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext
[dn]
CN = TESTDC.test.example.com
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = TESTDC.test.example.com
DNS.2 = localdc.test.example.com
IP.1 = 192.168.1.222
-26
View File
@@ -1,26 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEUDCCAjigAwIBAgIUWWNKWevcAp59R5YZ4SwYaDF86BEwDQYJKoZIhvcNAQEL
BQAwGDEWMBQGA1UEAwwNU2FtYmEgVGVzdCBDQTAeFw0yNjAxMTgwMTE0MDRaFw0y
ODA0MjIwMTE0MDRaMCIxIDAeBgNVBAMMF1RFU1REQy50ZXN0LmV4YW1wbGUuY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA04ZWa1/UrP6eAkwvc2oL
XCewax+5GWWhIj0XVgglblPNcPbK0dLTienfGnfEYxgrCl4o+H7c+SFYcJ/Sg5jw
W4/POs+NWoo3ixj71TYWwK+7bUPt2RbNadCAxo4SejdB0zOjpTRn4dDIMZ0+wrg5
Ah3jkTnPmwWjpvt280KkojUz+7mhdKFXBBmyjr/ftWU8C+1nyJt5/tVl7PE0VcOL
MBok9djjHlj2aKLCw8Hj0CyL+yYFM4keWvYAguXYjVayMC2w8VffvjjO3Wd7/LWi
AkDIAhnKyc1oJ8X4h9XK1irEw8lgWH93jyRx54eG32/C3HuNRQA9oQgJrfaK5YCJ
kQIDAQABo4GHMIGEMEIGA1UdEQQ7MDmCF1RFU1REQy50ZXN0LmV4YW1wbGUuY29t
ghhsb2NhbGRjLnRlc3QuZXhhbXBsZS5jb22HBMCoAd4wHQYDVR0OBBYEFJDd+Fmx
vsrKEvBMXBwtBeFxjVjWMB8GA1UdIwQYMBaAFIBTmRi7ZsLnQPLVWini76MFUCzG
MA0GCSqGSIb3DQEBCwUAA4ICAQBwS8/1iAFnopOui1V/qdRBsBTWcXdQS7x1PqVU
nJkd+T5AYtLu3tJ+PBO9rfgDNVWVz37GB8CTgr4TpGOt7ruaVSZvw9uMRBxYeeit
Kf11gssI2eTZESv8yqsa1DtLheQS0AQ7IVjq9wZSw+i3zQ8lQDvFoCWa8nv+C+YZ
cfFSnhfXNRQIM+lxn6vrtZa/GgJh6MTF+vCfLvStveCsTvT7i/w0EzO8NFqGBrsX
ldombU/WNketQXQEaLAU6NQVvJCjkC9Wgc+KcOQOV77U7CHi3lsc2TAoGlMuJ1lP
zyQWJqHKkuWGODeBSd9FfjoZv81+OGPaCAh7bkOHwqAUjgEIL8SV1fX8i13HTkG5
nhbN6XoiezjKixfH/EAQHiKhi6/7nzYltz6bJFHpIfBa097l7Yhx/o/HIdKDWV2S
VnLIJMJpf/Qn80led1HQPeRWR1EC+fWhBzOg2mCJJpYkpqaOlHVujZ2c5JLckhxH
WuIkicvR+LE07IjgZFWUwCXW/PkDDHtiJ0MD6RAiFzFbnuGGMadv3lUBJBUeKL3P
PaDC/pue9AAgbWN9ndg8CTorDR2HHjjOyVTkum5bPL2vChuG3/mx+KHcgwDyEWt8
cJTxXNaid928rR0aSPsSd4WNlCTDwXhUpClaVRaip/rcfrhJaaFUe7xWpQe8dkvO
hiuYEQ==
-----END CERTIFICATE-----
-17
View File
@@ -1,17 +0,0 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICvDCCAaQCAQAwIjEgMB4GA1UEAwwXVEVTVERDLnRlc3QuZXhhbXBsZS5jb20w
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDThlZrX9Ss/p4CTC9zagtc
J7BrH7kZZaEiPRdWCCVuU81w9srR0tOJ6d8ad8RjGCsKXij4ftz5IVhwn9KDmPBb
j886z41aijeLGPvVNhbAr7ttQ+3ZFs1p0IDGjhJ6N0HTM6OlNGfh0MgxnT7CuDkC
HeOROc+bBaOm+3bzQqSiNTP7uaF0oVcEGbKOv9+1ZTwL7WfIm3n+1WXs8TRVw4sw
GiT12OMeWPZoosLDwePQLIv7JgUziR5a9gCC5diNVrIwLbDxV9++OM7dZ3v8taIC
QMgCGcrJzWgnxfiH1crWKsTDyWBYf3ePJHHnh4bfb8Lce41FAD2hCAmt9orlgImR
AgMBAAGgVTBTBgkqhkiG9w0BCQ4xRjBEMEIGA1UdEQQ7MDmCF1RFU1REQy50ZXN0
LmV4YW1wbGUuY29tghhsb2NhbGRjLnRlc3QuZXhhbXBsZS5jb22HBMCoAd4wDQYJ
KoZIhvcNAQELBQADggEBAAQGVIMVIWPbCG3blO8iNHetydfz8XWC3w9zYI03QQBv
QdiAYZ9sI+9fxZdsBOOt+vSNyqlwuuQYmmMtMJbUezeOQ8Z4zhkWEzTI4ohhOlzV
sq+7aE+PNKw8CYvOkL4ssVIDU99Hm4ppJbo6sRa9YAXPDU3z0UJhMiGZL7o11048
W8VcWOzyNmEHYL6/+DXwXGiaLiJmMOJiwMPu8TZVnli4Q0k/j7KGdeh8s2MXLwi8
NT0ppSxm+MUIm014OEMA/LOPwRVttHca1VkGR15MJQElakWSaaix533p7lpH3Q3Q
tKZc7RIWeoXs5wyo7Tx7Tx7QdmNJIzA2gh4tRiQvm1o=
-----END CERTIFICATE REQUEST-----
-28
View File
@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDThlZrX9Ss/p4C
TC9zagtcJ7BrH7kZZaEiPRdWCCVuU81w9srR0tOJ6d8ad8RjGCsKXij4ftz5IVhw
n9KDmPBbj886z41aijeLGPvVNhbAr7ttQ+3ZFs1p0IDGjhJ6N0HTM6OlNGfh0Mgx
nT7CuDkCHeOROc+bBaOm+3bzQqSiNTP7uaF0oVcEGbKOv9+1ZTwL7WfIm3n+1WXs
8TRVw4swGiT12OMeWPZoosLDwePQLIv7JgUziR5a9gCC5diNVrIwLbDxV9++OM7d
Z3v8taICQMgCGcrJzWgnxfiH1crWKsTDyWBYf3ePJHHnh4bfb8Lce41FAD2hCAmt
9orlgImRAgMBAAECggEAFTygZ5EMWr6zjC/W9xj3Vq4bbciWaRYwNS5PWKa3ugR1
lLkKcuzeVTM4YEFpuQ3qSv+vewd4VcDtzrI/zKY/F4pFjYuHZHGKaGTpP9D5kX3z
QjdMOtFUbU0Zk2schXhlG6MhyR/iVXnZ55/4dvdPrfE58aY4EZc22jiBYE9ZanmL
Nxqby63ntT/8ZqQpi5iu458TrWTAhOqF+0g5Aj8bWnk6xIcauvFuLORfAcg2kig6
+/oUZiQ4U65gvBODckADjTtKmVUlBFFc22xsR5pSm08dI06Fc+1ZWSa3smyA/a+d
iOx2Bb+wD8zQMq20pm3R7Kx/yaTLy+AubBzc7OYQMwKBgQDxrgQnMzjLpLEBe+kp
8DKSUpy06G176Zoz65NP5BiY1S12YSqu9ydapalIKKH32yu6Gzw0JsTDa0z8glDH
Z9VeB9ZM3q+jsPrg7pUUQKC+Yn/Msba5a4BLmdO61qAk1/zPsc/bEIxC6HBXuR5k
7bYRivARdGtYRqkkvVKnn5uWqwKBgQDgDuhC4u9ZBx2QN+bDyT+Ppqd+nLLZemTF
bJRRbfXsMRpgAvQl5f4mTxu/KqtKm/kKGY7F66B1XuSmZqAEsvVw0oM+0+rCDfdk
Iir87ZsdpfoRA5x775zaa2GrW7/hhpvBrenD9vNwo6/G927EjMAhhPaOelxpf+dS
fXBrTOKQswKBgQDC+pp9KbTzjo4DXX2SCSgzppSo2y+hHaj7pF33wVUa0DnaXK/7
8of8eNRm0+lANsFDZz+d730lD8dPnK8hASNBtl7tK2dWT61HlRQO/8jvcDYc5W8+
jn02AQexoAAZWWusAI9p9CLExBQGoeHkmWcfJhFic6M6198UNe2eMIVs+wKBgQCR
D1W0KDSJ0R+ExYxz6ZFrMZxzToREZQdlAh0scyKqnkfTLVZgSv02VDVEmR15Gm4r
6cwTu6+RDbS/PuYO5MYfG0u5m3370QsAG1b1lee9VD4IUew4GTPV/Xuoc6hRHNMu
m6gjJXkKzg75pCxkuDOT//+Y0wONki9zqp7j+U0eHQKBgCkyJ/E+hNFlzqFHugaR
ZC8ccttxs2ibTK4J861EvjA7zFkbnAHy2NfsrNPKm6t+TJOkeJ4XrST1vfS3aNJk
swHRQz8tWwtnJCsvTF5nCXU7dDQPsyxwRHB39Eq9KtXp7F+PD7kaMk8DbYIzcQ55
pe3uxsvKvS6R++L2eg3TfdSB
-----END PRIVATE KEY-----
+122 -148
View File
@@ -3,152 +3,126 @@ package config
import "time"
// config file
type (
Backend struct {
BaseDN string
Datastore string
Insecure bool // For LDAP and owncloud backend only
Servers []string // For LDAP and owncloud backend only
NameFormat string // e.g. cn, ou, uid, or a comma separated list of them
NameFormatAsArray []string // we will explode NameFormat on commas
GroupFormat string // e.g. cn, ou, gid, or a comma separated list of them
GroupFormatAsArray []string // we will explode GroupFormat on commas
SSHKeyAttr string
UseGraphAPI bool // For ownCloud backend only
Plugin string // Path to plugin library, for plugin backend only
PluginHandler string // Name of plugin's main handler function
Database string // For Database backends only
GroupWithSearchCapability string // For PamLinux backend only
AnonymousDSE bool // For Config and Database backends only
}
type Backend struct {
BaseDN string
Datastore string
Insecure bool // For LDAP and owncloud backend only
Servers []string // For LDAP and owncloud backend only
NameFormat string
GroupFormat string
SSHKeyAttr string
UseGraphAPI bool // For ownCloud backend only
Plugin string // Path to plugin library, for plugin backend only
PluginHandler string // Name of plugin's main handler function
Database string // For Database backends only
GroupWithSearchCapability string // For PamLinux backend only
AnonymousDSE bool // For Config and Database backends only
}
type Helper struct {
Enabled bool
BaseDN string
Datastore string
Plugin string // Path to plugin library, for plugin backend only
PluginHandler string // Name of plugin's main handler function
Database string // For MySQL backend only TODO REname to match plugin
}
type Frontend struct {
AllowedBaseDNs []string // For LDAP backend only
Listen string
Cert string
Key string
TLS bool
}
type LDAP struct {
Enabled bool
Listen string
// StartTLS parameters
TLS bool
TLSCert string
TLSKey string
TLSCertPath string
TLSKeyPath string
}
type LDAPS struct {
Enabled bool
Listen string
Cert string
Key string
}
type API struct {
Cert string
Enabled bool
Internals bool
Key string
Listen string
SecretToken string
TLS bool
}
type Behaviors struct {
IgnoreCapabilities bool
LimitFailedBinds bool
NumberOfFailedBinds int
PeriodOfFailedBinds time.Duration
BlockFailedBindsFor time.Duration
PruneSourceTableEvery time.Duration
PruneSourcesOlderThan time.Duration
LegacyVersion int
}
type Capability struct {
Action string
Object string
}
Helper struct {
Enabled bool
BaseDN string
Datastore string
Plugin string // Path to plugin library, for plugin backend only
PluginHandler string // Name of plugin's main handler function
Database string // For MySQL backend only TODO REname to match plugin
}
Frontend struct {
AllowedBaseDNs []string // For LDAP backend only
Listen string
Cert string
Key string
TLS bool
}
LDAP struct {
Enabled bool
Listen string
// StartTLS parameters
TLS bool
TLSCert string
TLSKey string
TLSCertPath string
TLSKeyPath string
LegacyTLS bool
}
LDAPS struct {
Enabled bool
Listen string
// LDAPS TLS parameters
Cert string
Key string
CertPath string
KeyPath string
LegacyTLS bool
}
API struct {
Cert string
Enabled bool
Internals bool
Key string
Listen string
SecretToken string
TLS bool
}
Behaviors struct {
IgnoreCapabilities bool
LimitFailedBinds bool
NumberOfFailedBinds int
PeriodOfFailedBinds time.Duration
BlockFailedBindsFor time.Duration
PruneSourceTableEvery time.Duration
PruneSourcesOlderThan time.Duration
LegacyVersion int
}
Capability struct {
Action string
Object string
}
// UserAuthenticator authenticates a user via custom auth from a backend
UserAuthenticator func(user *User, pw string) error
User struct {
Name string
OtherGroups []int
PassSHA256 string
PassBcrypt string
PassAppSHA256 []string
PassAppBcrypt []string
PassAppCustom UserAuthenticator `toml:"-"`
PrimaryGroup int
Capabilities []Capability
SSHKeys []string
OTPSecret string
Yubikey string
Disabled bool
UnixID int // TODO: remove after deprecating UnixID on User and Group
UIDNumber int
Mail string
LoginShell string
GivenName string
SN string
Homedir string
CustomAttrs map[string]interface{}
}
Group struct {
Name string
UnixID int // TODO: remove after deprecating UnixID on User and Group
GIDNumber int
Capabilities []Capability
IncludeGroups []int
}
Tracing struct {
Enabled bool
GRPCEndpoint string
HTTPEndpoint string
}
Config struct {
API API
Backend Backend // Deprecated
Backends []Backend
Helper Helper
Behaviors Behaviors
Debug bool
Syslog bool
StructuredLog bool
WatchConfig bool
YubikeyClientID string
YubikeySecret string
Frontend Frontend
LDAP LDAP
LDAPS LDAPS
Groups []Group
Users []User
Tracing Tracing
ConfigFile string
AwsAccessKeyId string
AwsSecretAccessKey string
AwsRegion string
}
)
// UserAuthenticator authenticates a user via custom auth from a backend
type UserAuthenticator func(user *User, pw string) error
type User struct {
Name string
OtherGroups []int
PassSHA256 string
PassBcrypt string
PassAppSHA256 []string
PassAppBcrypt []string
PassAppCustom UserAuthenticator
PrimaryGroup int
Capabilities []Capability
SSHKeys []string
OTPSecret string
Yubikey string
Disabled bool
UnixID int // TODO: remove after deprecating UnixID on User and Group
UIDNumber int
Mail string
LoginShell string
GivenName string
SN string
Homedir string
CustomAttrs map[string]interface{}
}
type Group struct {
Name string
UnixID int // TODO: remove after deprecating UnixID on User and Group
GIDNumber int
IncludeGroups []int
}
type Config struct {
API API
Backend Backend // Deprecated
Backends []Backend
Helper Helper
Behaviors Behaviors
Debug bool
Syslog bool
StructuredLog bool
WatchConfig bool
YubikeyClientID string
YubikeySecret string
Frontend Frontend
LDAP LDAP
LDAPS LDAPS
Groups []Group
Users []User
ConfigFile string
AwsAccessKeyId string
AwsSecretAccessKey string
AwsRegion string
}
+27 -74
View File
@@ -1,7 +1,6 @@
package handler
import (
"context"
"fmt"
"net"
"regexp"
@@ -10,7 +9,6 @@ import (
"time"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/GeertJohan/yubigo"
"github.com/glauth/glauth/v2/internal/monitoring"
@@ -28,7 +26,6 @@ type configHandler struct {
attmatcher *regexp.Regexp
monitor monitoring.MonitorInterface
tracer trace.Tracer
}
// NewConfigHandler creates a new config backed handler
@@ -43,7 +40,6 @@ func NewConfigHandler(opts ...Option) Handler {
ldohelper: options.LDAPHelper,
attmatcher: configattributematcher,
monitor: options.Monitor,
tracer: options.Tracer,
}
return handler
}
@@ -63,9 +59,6 @@ func (h configHandler) GetYubikeyAuth() *yubigo.YubiAuth {
// Bind implements a bind request against the config file
func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (result ldap.LDAPResultCode, err error) {
ctx, span := h.tracer.Start(context.Background(), "handler.configHandler.Bind")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -73,14 +66,11 @@ func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (result
time.Since(start).Seconds(),
)
}()
return h.ldohelper.Bind(ctx, h, bindDN, bindSimplePw, conn)
return h.ldohelper.Bind(h, bindDN, bindSimplePw, conn)
}
// Search implements a search request against the config file
func (h configHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
ctx, span := h.tracer.Start(context.Background(), "handler.configHandler.Search")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -88,14 +78,11 @@ func (h configHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn
time.Since(start).Seconds(),
)
}()
return h.ldohelper.Search(ctx, h, bindDN, searchReq, conn)
return h.ldohelper.Search(h, bindDN, searchReq, conn)
}
// Add is not supported for a static config file
func (h configHandler) Add(boundDN string, req ldap.AddRequest, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "handler.configHandler.Add")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -108,9 +95,6 @@ func (h configHandler) Add(boundDN string, req ldap.AddRequest, conn net.Conn) (
// Modify is not supported for a static config file
func (h configHandler) Modify(boundDN string, req ldap.ModifyRequest, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "handler.configHandler.Modify")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -123,9 +107,6 @@ func (h configHandler) Modify(boundDN string, req ldap.ModifyRequest, conn net.C
// Delete is not supported for a static config file
func (h configHandler) Delete(boundDN string, deleteDN string, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "handler.configHandler.Delete")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -136,9 +117,7 @@ func (h configHandler) Delete(boundDN string, deleteDN string, conn net.Conn) (r
return ldap.LDAPResultInsufficientAccessRights, nil
}
func (h configHandler) FindUser(ctx context.Context, userName string, searchByUPN bool) (f bool, u config.User, err error) {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.FindUser")
defer span.End()
func (h configHandler) FindUser(userName string, searchByUPN bool) (f bool, u config.User, err error) {
user := config.User{}
found := false
@@ -159,9 +138,7 @@ func (h configHandler) FindUser(ctx context.Context, userName string, searchByUP
return found, user, nil
}
func (h configHandler) FindGroup(ctx context.Context, groupName string) (f bool, g config.Group, err error) {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.FindGroup")
defer span.End()
func (h configHandler) FindGroup(groupName string) (f bool, g config.Group, err error) {
// TODO Does g get erased, and above does u get erased?
// TODO and what about f?
group := config.Group{}
@@ -175,17 +152,13 @@ func (h configHandler) FindGroup(ctx context.Context, groupName string) (f bool,
return found, group, nil
}
func (h configHandler) FindPosixAccounts(ctx context.Context, hierarchy string) (entrylist []*ldap.Entry, err error) {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.FindPosixAccounts")
defer span.End()
func (h configHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.Entry, err error) {
entries := []*ldap.Entry{}
for _, u := range h.cfg.Users {
attrs := []*ldap.EntryAttribute{}
for _, nameAttr := range h.backend.NameFormatAsArray {
attrs = append(attrs, &ldap.EntryAttribute{Name: nameAttr, Values: []string{u.Name}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.NameFormat, Values: []string{u.Name}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{u.Name}})
if len(u.GivenName) > 0 {
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{u.GivenName}})
@@ -195,7 +168,7 @@ func (h configHandler) FindPosixAccounts(ctx context.Context, hierarchy string)
attrs = append(attrs, &ldap.EntryAttribute{Name: "sn", Values: []string{u.SN}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(ctx, u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uidNumber", Values: []string{fmt.Sprintf("%d", u.UIDNumber)}})
if u.Disabled {
@@ -226,7 +199,7 @@ func (h configHandler) FindPosixAccounts(ctx context.Context, hierarchy string)
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s", u.Name)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "gecos", Values: []string{fmt.Sprintf("%s", u.Name)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: h.getGroupDNs(ctx, append(u.OtherGroups, u.PrimaryGroup))})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: h.getGroupDNs(append(u.OtherGroups, u.PrimaryGroup))})
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowExpire", Values: []string{"-1"}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "shadowFlag", Values: []string{"134538308"}})
@@ -261,9 +234,9 @@ func (h configHandler) FindPosixAccounts(ctx context.Context, hierarchy string)
}
var dn string
if hierarchy == "" {
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), h.backend.BaseDN)
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), h.backend.BaseDN)
} else {
dn = fmt.Sprintf("%s=%s,%s=%s,%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), hierarchy, h.backend.BaseDN)
dn = fmt.Sprintf("%s=%s,%s=%s,%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), hierarchy, h.backend.BaseDN)
}
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
}
@@ -271,30 +244,25 @@ func (h configHandler) FindPosixAccounts(ctx context.Context, hierarchy string)
return entries, nil
}
func (h configHandler) FindPosixGroups(ctx context.Context, hierarchy string) (entrylist []*ldap.Entry, err error) {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.FindPosixGroups")
defer span.End()
func (h configHandler) FindPosixGroups(hierarchy string) (entrylist []*ldap.Entry, err error) {
asGroupOfUniqueNames := hierarchy == "ou=groups"
entries := []*ldap.Entry{}
for _, g := range h.cfg.Groups {
attrs := []*ldap.EntryAttribute{}
for _, groupAttr := range h.backend.GroupFormatAsArray {
attrs = append(attrs, &ldap.EntryAttribute{Name: groupAttr, Values: []string{g.Name}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.GroupFormat, Values: []string{g.Name}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{g.Name}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s", g.Name)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", g.GIDNumber)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(ctx, g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(g.GIDNumber)})
if asGroupOfUniqueNames {
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"groupOfUniqueNames", "top"}})
} else {
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(ctx, g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixGroup", "top"}})
}
dn := fmt.Sprintf("%s=%s,%s,%s", h.backend.GroupFormatAsArray[0], g.Name, hierarchy, h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,%s,%s", h.backend.GroupFormat, g.Name, hierarchy, h.backend.BaseDN)
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
}
@@ -303,17 +271,11 @@ func (h configHandler) FindPosixGroups(ctx context.Context, hierarchy string) (e
// Close does not actually close anything, because the config data is kept in memory
func (h configHandler) Close(boundDn string, conn net.Conn) error {
_, span := h.tracer.Start(context.Background(), "handler.configHandler.Close")
defer span.End()
stats.Frontend.Add("closes", 1)
return nil
}
func (h configHandler) getGroupMemberDNs(ctx context.Context, gid int) []string {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.getGroupMemberDNs")
defer span.End()
func (h configHandler) getGroupMemberDNs(gid int) []string {
var insertOuUsers string
if h.cfg.Behaviors.LegacyVersion > 0 && h.cfg.Behaviors.LegacyVersion <= 20100 {
insertOuUsers = ""
@@ -323,12 +285,12 @@ func (h configHandler) getGroupMemberDNs(ctx context.Context, gid int) []string
members := make(map[string]bool)
for _, u := range h.cfg.Users {
if u.PrimaryGroup == gid {
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
members[dn] = true
} else {
for _, othergid := range u.OtherGroups {
if othergid == gid {
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
members[dn] = true
}
}
@@ -339,7 +301,7 @@ func (h configHandler) getGroupMemberDNs(ctx context.Context, gid int) []string
if gid == g.GIDNumber {
for _, includegroupid := range g.IncludeGroups {
if includegroupid != gid {
includegroupmembers := h.getGroupMemberDNs(ctx, includegroupid)
includegroupmembers := h.getGroupMemberDNs(includegroupid)
for _, includegroupmember := range includegroupmembers {
members[includegroupmember] = true
@@ -359,10 +321,7 @@ func (h configHandler) getGroupMemberDNs(ctx context.Context, gid int) []string
return m
}
func (h configHandler) getGroupMemberIDs(ctx context.Context, gid int) []string {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.getGroupMemberIDs")
defer span.End()
func (h configHandler) getGroupMemberIDs(gid int) []string {
members := make(map[string]bool)
for _, u := range h.cfg.Users {
if u.PrimaryGroup == gid {
@@ -382,7 +341,7 @@ func (h configHandler) getGroupMemberIDs(ctx context.Context, gid int) []string
if includegroupid == gid {
h.log.Warn().Int("groupid", includegroupid).Msg("Ignoring myself as included group")
} else {
includegroupmemberids := h.getGroupMemberIDs(ctx, includegroupid)
includegroupmemberids := h.getGroupMemberIDs(includegroupid)
for _, includegroupmemberid := range includegroupmemberids {
members[includegroupmemberid] = true
@@ -403,21 +362,18 @@ func (h configHandler) getGroupMemberIDs(ctx context.Context, gid int) []string
}
// Converts an array of GUIDs into an array of DNs
func (h configHandler) getGroupDNs(ctx context.Context, gids []int) []string {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.getGroupDNs")
defer span.End()
func (h configHandler) getGroupDNs(gids []int) []string {
groups := make(map[string]bool)
for _, gid := range gids {
for _, g := range h.cfg.Groups {
if g.GIDNumber == gid {
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormatAsArray[0], g.Name, h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormat, g.Name, h.backend.BaseDN)
groups[dn] = true
}
for _, includegroupid := range g.IncludeGroups {
if includegroupid == gid && g.GIDNumber != gid {
includegroupdns := h.getGroupDNs(ctx, []int{g.GIDNumber})
includegroupdns := h.getGroupDNs([]int{g.GIDNumber})
for _, includegroupdn := range includegroupdns {
groups[includegroupdn] = true
@@ -437,10 +393,7 @@ func (h configHandler) getGroupDNs(ctx context.Context, gids []int) []string {
return g
}
func (h configHandler) getGroupName(ctx context.Context, gid int) string {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.getGroupName")
defer span.End()
func (h configHandler) getGroupName(gid int) string {
for _, g := range h.cfg.Groups {
if g.GIDNumber == gid {
return g.Name
+2 -4
View File
@@ -1,15 +1,13 @@
package handler
import (
"context"
"github.com/glauth/glauth/v2/pkg/config"
"github.com/glauth/ldap"
)
type HelperMaker interface {
FindUser(ctx context.Context, userName string, searchByUPN bool) (bool, config.User, error)
FindGroup(ctx context.Context, groupName string) (bool, config.Group, error)
FindUser(userName string, searchByUPN bool) (bool, config.User, error)
FindGroup(groupName string) (bool, config.Group, error)
}
// Handler is the common interface for all datastores
+10 -61
View File
@@ -1,7 +1,6 @@
package handler
import (
"context"
"crypto/sha256"
"crypto/tls"
"encoding/json"
@@ -16,7 +15,6 @@ import (
"time"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/glauth/glauth/v2/internal/monitoring"
"github.com/glauth/glauth/v2/pkg/config"
@@ -40,7 +38,6 @@ type ldapHandler struct {
attm *regexp.Regexp
monitor monitoring.MonitorInterface
tracer trace.Tracer
}
// global lock for ldapHandler sessions & servers manipulation
@@ -79,7 +76,6 @@ func NewLdapHandler(opts ...Option) Handler {
lock: &ldaplock,
attm: ldapattributematcher,
monitor: options.Monitor,
tracer: options.Tracer,
}
// parse LDAP URLs
for _, ldapurl := range handler.backend.Servers {
@@ -98,9 +94,6 @@ func NewLdapHandler(opts ...Option) Handler {
}
func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (result ldap.LDAPResultCode, err error) {
ctx, span := h.tracer.Start(context.Background(), "handler.ldapHandler.Bind")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -117,7 +110,7 @@ func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (result ld
lowerBindDN := strings.ToLower(bindDN)
baseDN := strings.ToLower("," + h.backend.BaseDN)
parts := strings.Split(strings.TrimSuffix(lowerBindDN, baseDN), ",")
userName := strings.TrimPrefix(parts[0], h.backend.NameFormatAsArray[0]+"=")
userName := strings.TrimPrefix(parts[0], h.backend.NameFormat+"=")
validotp := false
@@ -127,7 +120,7 @@ func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (result ld
user := config.User{}
found := false
for i, handler := range h.handlers.Handlers {
found, user, _ = handler.FindUser(ctx, userName, false)
found, user, _ = handler.FindUser(userName, false)
if found {
break
}
@@ -174,9 +167,6 @@ func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (result ld
}
func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
ctx, span := h.tracer.Start(context.Background(), "handler.ldapHandler.Search")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -210,20 +200,6 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
stats.Frontend.Add("search_ldapSession_errors", 1)
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, nil
}
/*
delete_idx := -1
pagingSize := uint32(0)
for idx, control := range searchReq.Controls {
if control.GetControlType() == ldap.ControlTypePaging {
fmt.Println(control.GetControlType())
pagingSize = control.(*ldap.ControlPaging).PagingSize
delete_idx = idx
}
}
if delete_idx >= 0 {
searchReq.Controls = append(searchReq.Controls[:delete_idx], searchReq.Controls[delete_idx+1:]...)
}
*/
search := ldap.NewSearchRequest(
searchReq.BaseDN,
searchReq.Scope,
@@ -237,15 +213,6 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
)
h.log.Debug().Interface("request", search).Msg("Search request to backend")
/*
var sr *ldap.SearchResult
if pagingSize > 0 {
fmt.Printf("Searching with page size == %d\n", pagingSize)
sr, err = s.ldap.SearchWithPaging(search, pagingSize)
} else {
sr, err = s.ldap.Search(search)
}
*/
sr, err := s.ldap.Search(search)
h.log.Debug().Interface("result", sr).Msg("Backend Search result")
@@ -287,7 +254,7 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
h.log.Debug().Str("type", "Root search detected").Msg("AP: Search Info")
}
filters := h.buildReqAttributesList(ctx, searchReq.Filter, []string{})
filters := h.buildReqAttributesList(searchReq.Filter, []string{})
for _, filter := range filters {
attbits := h.attm.FindStringSubmatch(filter)
@@ -309,10 +276,9 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
}
ssr := ldap.ServerSearchResult{
Entries: sr.Entries,
Referrals: sr.Referrals,
Controls: sr.Controls,
ResultCode: ldap.LDAPResultSuccess,
Entries: sr.Entries,
Referrals: sr.Referrals,
Controls: sr.Controls,
}
h.log.Debug().Interface("result", ssr).Msg("Frontend Search result")
if err != nil {
@@ -327,10 +293,7 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
return ssr, nil
}
func (h ldapHandler) buildReqAttributesList(ctx context.Context, filter string, filters []string) []string {
ctx, span := h.tracer.Start(ctx, "handler.ldapHandler.buildReqAttributesList")
defer span.End()
func (h ldapHandler) buildReqAttributesList(filter string, filters []string) []string {
maxp := len(filter)
start := -1
descended := false
@@ -342,7 +305,7 @@ func (h ldapHandler) buildReqAttributesList(ctx context.Context, filter string,
} else if c == ')' {
if start > -1 {
descended = true
filters = h.buildReqAttributesList(ctx, filter[start:p], filters)
filters = h.buildReqAttributesList(filter[start:p], filters)
}
start = -1
}
@@ -355,9 +318,6 @@ func (h ldapHandler) buildReqAttributesList(ctx context.Context, filter string,
// Add is not yet supported for the ldap backend
func (h ldapHandler) Add(boundDN string, req ldap.AddRequest, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "handler.ldapHandler.Add")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -370,9 +330,6 @@ func (h ldapHandler) Add(boundDN string, req ldap.AddRequest, conn net.Conn) (re
// Modify is not yet supported for the ldap backend
func (h ldapHandler) Modify(boundDN string, req ldap.ModifyRequest, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "handler.ldapHandler.Modify")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -385,9 +342,6 @@ func (h ldapHandler) Modify(boundDN string, req ldap.ModifyRequest, conn net.Con
// Delete is not yet supported for the ldap backend
func (h ldapHandler) Delete(boundDN string, deleteDN string, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "handler.ldapHandler.Delete")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -398,16 +352,11 @@ func (h ldapHandler) Delete(boundDN string, deleteDN string, conn net.Conn) (res
return ldap.LDAPResultInsufficientAccessRights, nil
}
func (h ldapHandler) FindUser(ctx context.Context, userName string, searchByUPN bool) (found bool, user config.User, err error) {
ctx, span := h.tracer.Start(ctx, "handler.ldapHandler.FindUser")
defer span.End()
func (h ldapHandler) FindUser(userName string, searchByUPN bool) (found bool, user config.User, err error) {
return false, config.User{}, nil
}
func (h ldapHandler) FindGroup(ctx context.Context, groupName string) (found bool, group config.Group, err error) {
ctx, span := h.tracer.Start(ctx, "handler.ldapHandler.FindGroup")
defer span.End()
func (h ldapHandler) FindGroup(groupName string) (found bool, group config.Group, err error) {
return false, config.Group{}, nil
}
+65 -116
View File
@@ -2,7 +2,6 @@ package handler
import (
"bufio"
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
@@ -14,7 +13,6 @@ import (
"time"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/GeertJohan/yubigo"
"github.com/glauth/glauth/v2/pkg/config"
@@ -33,10 +31,10 @@ type LDAPOpsHandler interface {
GetCfg() *config.Config
GetYubikeyAuth() *yubigo.YubiAuth
FindUser(ctx context.Context, userName string, searchByUPN bool) (f bool, u config.User, err error)
FindGroup(ctx context.Context, groupName string) (f bool, g config.Group, err error)
FindPosixAccounts(ctx context.Context, hierarchy string) (entrylist []*ldap.Entry, err error)
FindPosixGroups(ctx context.Context, hierarchy string) (entrylist []*ldap.Entry, err error)
FindUser(userName string, searchByUPN bool) (f bool, u config.User, err error)
FindGroup(groupName string) (f bool, g config.Group, err error)
FindPosixAccounts(hierarchy string) (entrylist []*ldap.Entry, err error)
FindPosixGroups(hierarchy string) (entrylist []*ldap.Entry, err error)
}
type failedBind struct {
@@ -52,24 +50,18 @@ type sourceInfo struct {
type LDAPOpsHelper struct {
sources map[string]*sourceInfo
nextPruning time.Time
tracer trace.Tracer
}
func NewLDAPOpsHelper(tracer trace.Tracer) LDAPOpsHelper {
func NewLDAPOpsHelper() LDAPOpsHelper {
helper := LDAPOpsHelper{
sources: make(map[string]*sourceInfo),
nextPruning: time.Now(),
tracer: tracer,
}
return helper
}
func (l LDAPOpsHelper) Bind(ctx context.Context, h LDAPOpsHandler, bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.Bind")
defer span.End()
if l.isInTimeout(ctx, h, conn) {
func (l LDAPOpsHelper) Bind(h LDAPOpsHandler, bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
if l.isInTimeout(h, conn) {
return ldap.LDAPResultUnwillingToPerform, nil
}
@@ -86,7 +78,7 @@ func (l LDAPOpsHelper) Bind(ctx context.Context, h LDAPOpsHandler, bindDN, bindS
return ldap.LDAPResultSuccess, nil
}
user, ldapcode := l.findUser(ctx, h, bindDN, true /* checkGroup */)
user, ldapcode := l.findUser(h, bindDN, true /* checkGroup */)
if ldapcode != ldap.LDAPResultSuccess {
return ldapcode, nil
}
@@ -184,7 +176,7 @@ func (l LDAPOpsHelper) Bind(ctx context.Context, h LDAPOpsHandler, bindDN, bindS
}
if bcrypt.CompareHashAndPassword(decoded, []byte(bindSimplePw)) != nil {
h.GetLog().Info().Str("binddn", bindDN).Str("src", conn.RemoteAddr().String()).Msg("invalid credentials")
l.maybePutInTimeout(ctx, h, conn, true)
l.maybePutInTimeout(h, conn, true)
return ldap.LDAPResultInvalidCredentials, nil
}
}
@@ -193,7 +185,7 @@ func (l LDAPOpsHelper) Bind(ctx context.Context, h LDAPOpsHandler, bindDN, bindS
hash.Write([]byte(bindSimplePw))
if user.PassSHA256 != hex.EncodeToString(hash.Sum(nil)) {
h.GetLog().Info().Str("binddn", bindDN).Str("src", conn.RemoteAddr().String()).Msg("invalid credentials")
l.maybePutInTimeout(ctx, h, conn, true)
l.maybePutInTimeout(h, conn, true)
return ldap.LDAPResultInvalidCredentials, nil
}
}
@@ -218,11 +210,8 @@ func (l LDAPOpsHelper) Bind(ctx context.Context, h LDAPOpsHandler, bindDN, bindS
* TODO #5:
* Document roll out of schemas
*/
func (l LDAPOpsHelper) Search(ctx context.Context, h LDAPOpsHandler, bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.Search")
defer span.End()
if l.isInTimeout(ctx, h, conn) {
func (l LDAPOpsHelper) Search(h LDAPOpsHandler, bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
if l.isInTimeout(h, conn) {
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultUnwillingToPerform}, fmt.Errorf("Source is in a timeout")
}
@@ -236,7 +225,7 @@ func (l LDAPOpsHelper) Search(ctx context.Context, h LDAPOpsHandler, bindDN stri
var ldapcode ldap.LDAPResultCode
if !anonymous {
if bindDN, boundUser, ldapcode = l.searchCheckBindDN(ctx, h, baseDN, bindDN, anonymous); ldapcode != ldap.LDAPResultSuccess {
if bindDN, boundUser, ldapcode = l.searchCheckBindDN(h, baseDN, bindDN, anonymous); ldapcode != ldap.LDAPResultSuccess {
return ldap.ServerSearchResult{ResultCode: ldapcode}, fmt.Errorf("Search Error: Potential bypass of BindDN %s", bindDN)
}
}
@@ -244,7 +233,7 @@ func (l LDAPOpsHelper) Search(ctx context.Context, h LDAPOpsHandler, bindDN stri
h.GetLog().Info().Str("binddn", bindDN).Str("basedn", baseDN).Str("searchbasedn", searchBaseDN).Str("src", conn.RemoteAddr().String()).Int("scope", searchReq.Scope).Str("filter", searchReq.Filter).Msg("Search request")
stats.Frontend.Add("search_reqs", 1)
switch entries, ldapcode := l.searchMaybeRootDSEQuery(ctx, h, baseDN, searchBaseDN, searchReq, anonymous); ldapcode {
switch entries, ldapcode := l.searchMaybeRootDSEQuery(h, baseDN, searchBaseDN, searchReq, anonymous); ldapcode {
case ldap.LDAPResultUnwillingToPerform:
return ldap.ServerSearchResult{ResultCode: ldapcode}, fmt.Errorf("Search Error: No BaseDN provided")
case ldap.LDAPResultInsufficientAccessRights:
@@ -258,7 +247,7 @@ func (l LDAPOpsHelper) Search(ctx context.Context, h LDAPOpsHandler, bindDN stri
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: Anonymous BindDN not allowed %s", bindDN)
}
switch entries, ldapcode, attributename := l.searchMaybeSchemaQuery(ctx, h, baseDN, searchBaseDN, searchReq, anonymous); ldapcode {
switch entries, ldapcode, attributename := l.searchMaybeSchemaQuery(h, baseDN, searchBaseDN, searchReq, anonymous); ldapcode {
case ldap.LDAPResultOperationsError:
return ldap.ServerSearchResult{ResultCode: ldapcode}, fmt.Errorf("Schema Error: attribute %s cannot be read", *attributename)
case ldap.LDAPResultSuccess:
@@ -275,21 +264,21 @@ func (l LDAPOpsHelper) Search(ctx context.Context, h LDAPOpsHandler, bindDN stri
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: search BaseDN %s is not in our BaseDN %s", searchBaseDN, h.GetBackend().BaseDN)
}
// Unless globally ignored, we will check that a user has capabilities allowing them to perform a search in the requested BaseDN
if !h.GetCfg().Behaviors.IgnoreCapabilities && !l.checkCapability(ctx, *boundUser, "search", []string{"*", searchBaseDN}) {
if !h.GetCfg().Behaviors.IgnoreCapabilities && !l.checkCapability(*boundUser, "search", []string{"*", searchBaseDN}) {
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: no capability allowing BindDN %s to perform search in %s", bindDN, searchBaseDN)
}
switch entries, ldapcode := l.searchMaybeTopLevelNodes(ctx, h, baseDN, searchBaseDN, searchReq); ldapcode {
switch entries, ldapcode := l.searchMaybeTopLevelNodes(h, baseDN, searchBaseDN, searchReq); ldapcode {
case ldap.LDAPResultSuccess:
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldapcode}, nil
}
switch entries, ldapcode := l.searchMaybeTopLevelGroupsNode(ctx, h, baseDN, searchBaseDN, searchReq); ldapcode {
switch entries, ldapcode := l.searchMaybeTopLevelGroupsNode(h, baseDN, searchBaseDN, searchReq); ldapcode {
case ldap.LDAPResultSuccess:
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldapcode}, nil
}
switch entries, ldapcode := l.searchMaybeTopLevelUsersNode(ctx, h, baseDN, searchBaseDN, searchReq); ldapcode {
switch entries, ldapcode := l.searchMaybeTopLevelUsersNode(h, baseDN, searchBaseDN, searchReq); ldapcode {
case ldap.LDAPResultSuccess:
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldapcode}, nil
}
@@ -299,12 +288,12 @@ func (l LDAPOpsHelper) Search(ctx context.Context, h LDAPOpsHandler, bindDN stri
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", searchReq.Filter)
}
switch entries, ldapcode := l.searchMaybePosixGroups(ctx, h, baseDN, searchBaseDN, searchReq, filterEntity); ldapcode {
switch entries, ldapcode := l.searchMaybePosixGroups(h, baseDN, searchBaseDN, searchReq, filterEntity); ldapcode {
case ldap.LDAPResultSuccess:
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldapcode}, nil
}
switch entries, ldapcode := l.searchMaybePosixAccounts(ctx, h, baseDN, searchBaseDN, searchReq, filterEntity); ldapcode {
switch entries, ldapcode := l.searchMaybePosixAccounts(h, baseDN, searchBaseDN, searchReq, filterEntity); ldapcode {
case ldap.LDAPResultSuccess:
stats.Frontend.Add("search_successes", 1)
h.GetLog().Info().Str("filter", searchReq.Filter).Msg("AP: Search OK")
@@ -317,11 +306,8 @@ func (l LDAPOpsHelper) Search(ctx context.Context, h LDAPOpsHandler, bindDN stri
}
// Returns: LDAPResultSuccess or any ldap code returned by findUser
func (l LDAPOpsHelper) searchCheckBindDN(ctx context.Context, h LDAPOpsHandler, baseDN string, bindDN string, anonymous bool) (newBindDN string, boundUser *config.User, ldapresultcode ldap.LDAPResultCode) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.searchCheckBindDN")
defer span.End()
boundUser, ldapcode := l.findUser(ctx, h, bindDN, false /* checkGroup */)
func (l LDAPOpsHelper) searchCheckBindDN(h LDAPOpsHandler, baseDN string, bindDN string, anonymous bool) (newBindDN string, boundUser *config.User, ldapresultcode ldap.LDAPResultCode) {
boundUser, ldapcode := l.findUser(h, bindDN, false /* checkGroup */)
if ldapcode != ldap.LDAPResultSuccess {
return "", nil, ldapcode
}
@@ -337,10 +323,7 @@ func (l LDAPOpsHelper) searchCheckBindDN(ctx context.Context, h LDAPOpsHandler,
// Search RootDSE and return information on the server
// Returns: LDAPResultSuccess, LDAPResultOther, LDAPResultUnwillingToPerform, LDAPResultInsufficientAccessRights
func (l LDAPOpsHelper) searchMaybeRootDSEQuery(ctx context.Context, h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, anonymous bool) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.searchMaybeRootDSEQuery")
defer span.End()
func (l LDAPOpsHelper) searchMaybeRootDSEQuery(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, anonymous bool) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
if searchBaseDN != "" {
return nil, ldap.LDAPResultOther // OK
}
@@ -359,7 +342,6 @@ func (l LDAPOpsHelper) searchMaybeRootDSEQuery(ctx context.Context, h LDAPOpsHan
// unfortunately, objectClass is not to be included so we will respect that
// attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"*"}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedSASLMechanisms", Values: []string{}})
//attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedSASLMechanisms", Values: []string{"GSSAPI", "PLAIN", "EXTERNAL"}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedLDAPVersion", Values: []string{"3"}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedControl", Values: []string{}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedCapabilities", Values: []string{}})
@@ -367,7 +349,7 @@ func (l LDAPOpsHelper) searchMaybeRootDSEQuery(ctx context.Context, h LDAPOpsHan
attrs = append(attrs, &ldap.EntryAttribute{Name: "serverName", Values: []string{"unknown"}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "namingContexts", Values: []string{baseDN}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "defaultNamingContext", Values: []string{baseDN}})
attrs = l.collectRequestedAttributesBack(ctx, attrs, searchReq)
attrs = l.collectRequestedAttributesBack(attrs, searchReq)
entries = append(entries, &ldap.Entry{DN: searchBaseDN, Attributes: attrs})
stats.Frontend.Add("search_successes", 1)
h.GetLog().Info().Str("filter", searchReq.Filter).Msg("AP: Root Search OK")
@@ -376,10 +358,7 @@ func (l LDAPOpsHelper) searchMaybeRootDSEQuery(ctx context.Context, h LDAPOpsHan
// Search and return the information, after indirection from the RootDSE
// Returns: LDAPResultSuccess, LDAPResultOther, LDAPResultOperationsError
func (l LDAPOpsHelper) searchMaybeSchemaQuery(ctx context.Context, h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, anonymous bool) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode, attributename *string) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.searchMaybeSchemaQuery")
defer span.End()
func (l LDAPOpsHelper) searchMaybeSchemaQuery(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, anonymous bool) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode, attributename *string) {
if searchBaseDN != "cn=schema" {
return nil, ldap.LDAPResultOther, nil // OK
}
@@ -409,7 +388,7 @@ func (l LDAPOpsHelper) searchMaybeSchemaQuery(ctx context.Context, h LDAPOpsHand
}
attrs = append(attrs, &ldap.EntryAttribute{Name: filename.Name(), Values: values})
}
attrs = l.collectRequestedAttributesBack(ctx, attrs, searchReq)
attrs = l.collectRequestedAttributesBack(attrs, searchReq)
entries = append(entries, &ldap.Entry{DN: searchBaseDN, Attributes: attrs})
stats.Frontend.Add("search_successes", 1)
h.GetLog().Info().Str("filter", searchReq.Filter).Msg("AP: Schema Discovery OK")
@@ -418,28 +397,25 @@ func (l LDAPOpsHelper) searchMaybeSchemaQuery(ctx context.Context, h LDAPOpsHand
// Retrieve the top-levell nodes, i.e. the baseDN, groups, members...
// Returns: LDAPResultSuccess, LDAPResultOther
func (l LDAPOpsHelper) searchMaybeTopLevelNodes(ctx context.Context, h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.searchMaybeTopLevelNodes")
defer span.End()
func (l LDAPOpsHelper) searchMaybeTopLevelNodes(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
if baseDN != searchBaseDN {
return nil, ldap.LDAPResultOther // OK
}
h.GetLog().Info().Str("special case", "top-level browse").Msg("Search request")
entries := []*ldap.Entry{}
if searchReq.Scope == ldap.ScopeBaseObject || searchReq.Scope == ldap.ScopeWholeSubtree {
entries = append(entries, l.topLevelRootNode(ctx, searchBaseDN))
entries = append(entries, l.topLevelRootNode(searchBaseDN))
}
entries = append(entries, l.topLevelGroupsNode(ctx, searchBaseDN, "groups"))
entries = append(entries, l.topLevelUsersNode(ctx, searchBaseDN))
entries = append(entries, l.topLevelGroupsNode(searchBaseDN, "groups"))
entries = append(entries, l.topLevelUsersNode(searchBaseDN))
if searchReq.Scope == ldap.ScopeWholeSubtree {
groupentries, err := h.FindPosixGroups(ctx, "ou=users")
groupentries, err := h.FindPosixGroups("ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
entries = append(entries, groupentries...)
userentries, err := h.FindPosixAccounts(ctx, "ou=users")
userentries, err := h.FindPosixAccounts("ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
@@ -452,20 +428,17 @@ func (l LDAPOpsHelper) searchMaybeTopLevelNodes(ctx context.Context, h LDAPOpsHa
// Search starting from and including the ou=groups node
// Returns: LDAPResultSuccess, LDAPResultOther
func (l LDAPOpsHelper) searchMaybeTopLevelGroupsNode(ctx context.Context, h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.searchMaybeTopLevelGroupsNode")
defer span.End()
func (l LDAPOpsHelper) searchMaybeTopLevelGroupsNode(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
if searchBaseDN != fmt.Sprintf("ou=groups,%s", baseDN) {
return nil, ldap.LDAPResultOther // OK
}
h.GetLog().Info().Str("special case", "top-level groups node").Msg("Search request")
entries := []*ldap.Entry{}
if searchReq.Scope == ldap.ScopeBaseObject || searchReq.Scope == ldap.ScopeWholeSubtree {
entries = append(entries, l.topLevelGroupsNode(ctx, searchBaseDN, "groups"))
entries = append(entries, l.topLevelGroupsNode(searchBaseDN, "groups"))
}
if searchReq.Scope == ldap.ScopeSingleLevel || searchReq.Scope == ldap.ScopeWholeSubtree {
groupentries, err := h.FindPosixGroups(ctx, "ou=groups")
groupentries, err := h.FindPosixGroups("ou=groups")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
@@ -478,27 +451,24 @@ func (l LDAPOpsHelper) searchMaybeTopLevelGroupsNode(ctx context.Context, h LDAP
// Search starting from and including the ou=users node
// Returns: LDAPResultSuccess, LDAPResultOther
func (l LDAPOpsHelper) searchMaybeTopLevelUsersNode(ctx context.Context, h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.searchMaybeTopLevelUsersNode")
defer span.End()
func (l LDAPOpsHelper) searchMaybeTopLevelUsersNode(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
if searchBaseDN != fmt.Sprintf("ou=users,%s", baseDN) {
return nil, ldap.LDAPResultOther // OK
}
h.GetLog().Info().Str("special case", "top-level users node").Msg("Search request")
entries := []*ldap.Entry{}
if searchReq.Scope == ldap.ScopeBaseObject || searchReq.Scope == ldap.ScopeWholeSubtree {
entries = append(entries, l.topLevelUsersNode(ctx, searchBaseDN))
entries = append(entries, l.topLevelUsersNode(searchBaseDN))
}
if searchReq.Scope == ldap.ScopeSingleLevel || searchReq.Scope == ldap.ScopeWholeSubtree {
groupentries, err := h.FindPosixGroups(ctx, "ou=users")
groupentries, err := h.FindPosixGroups("ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
entries = append(entries, groupentries...)
}
if searchReq.Scope == ldap.ScopeWholeSubtree {
userentries, err := h.FindPosixAccounts(ctx, "ou=users")
userentries, err := h.FindPosixAccounts("ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
@@ -511,10 +481,7 @@ func (l LDAPOpsHelper) searchMaybeTopLevelUsersNode(ctx context.Context, h LDAPO
// Look up posixgroup entries, either through objectlass or parent is ou=groups or ou=users
// Returns: LDAPResultSuccess, LDAPResultOther, LDAPResultOperationsError
func (l LDAPOpsHelper) searchMaybePosixGroups(ctx context.Context, h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, filterEntity string) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.searchMaybePosixGroups")
defer span.End()
func (l LDAPOpsHelper) searchMaybePosixGroups(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, filterEntity string) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
hierarchy := "ou=groups"
if filterEntity != "posixgroup" {
bits := strings.Split(strings.Replace(searchBaseDN, baseDN, "", 1), ",")
@@ -526,19 +493,19 @@ func (l LDAPOpsHelper) searchMaybePosixGroups(ctx context.Context, h LDAPOpsHand
h.GetLog().Info().Str("special case", "posix groups").Msg("Search request")
entries := []*ldap.Entry{}
if searchReq.Scope == ldap.ScopeBaseObject || searchReq.Scope == ldap.ScopeWholeSubtree {
groupentries, err := h.FindPosixGroups(ctx, hierarchy)
groupentries, err := h.FindPosixGroups(hierarchy)
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
entries = append(entries, l.preFilterEntries(ctx, searchBaseDN, groupentries)...)
entries = append(entries, l.preFilterEntries(searchBaseDN, groupentries)...)
}
if searchReq.Scope == ldap.ScopeSingleLevel || searchReq.Scope == ldap.ScopeWholeSubtree {
if hierarchy == "ou=users" {
userentries, err := h.FindPosixAccounts(ctx, "ou=users")
userentries, err := h.FindPosixAccounts("ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
entries = append(entries, l.preFilterEntries(ctx, searchBaseDN, userentries)...)
entries = append(entries, l.preFilterEntries(searchBaseDN, userentries)...)
}
}
stats.Frontend.Add("search_successes", 1)
@@ -549,10 +516,7 @@ func (l LDAPOpsHelper) searchMaybePosixGroups(ctx context.Context, h LDAPOpsHand
// Lookup posixaccount entries
// Returns: LDAPResultSuccess, LDAPResultOther, LDAPResultOperationsError
// This function ignores scopes... for now
func (l LDAPOpsHelper) searchMaybePosixAccounts(ctx context.Context, h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, filterEntity string) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.searchMaybePosixAccounts")
defer span.End()
func (l LDAPOpsHelper) searchMaybePosixAccounts(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, filterEntity string) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
switch filterEntity {
case "posixaccount", "shadowaccount", "":
h.GetLog().Info().Str("default case", filterEntity).Msg("Search request")
@@ -566,7 +530,7 @@ func (l LDAPOpsHelper) searchMaybePosixAccounts(ctx context.Context, h LDAPOpsHa
hierarchyString = "ou=users"
}
unscopedEntries, err := h.FindPosixAccounts(ctx, hierarchyString)
unscopedEntries, err := h.FindPosixAccounts(hierarchyString)
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
@@ -584,7 +548,7 @@ func (l LDAPOpsHelper) searchMaybePosixAccounts(ctx context.Context, h LDAPOpsHa
return entries, ldap.LDAPResultSuccess
}
func (l LDAPOpsHelper) topLevelRootNode(ctx context.Context, searchBaseDN string) *ldap.Entry {
func (l LDAPOpsHelper) topLevelRootNode(searchBaseDN string) *ldap.Entry {
attrs := []*ldap.EntryAttribute{}
dnBits := strings.Split(searchBaseDN, ",")
for _, dnBit := range dnBits {
@@ -595,7 +559,7 @@ func (l LDAPOpsHelper) topLevelRootNode(ctx context.Context, searchBaseDN string
return &ldap.Entry{DN: searchBaseDN, Attributes: attrs}
}
func (l LDAPOpsHelper) topLevelGroupsNode(ctx context.Context, searchBaseDN string, hierarchy string) *ldap.Entry {
func (l LDAPOpsHelper) topLevelGroupsNode(searchBaseDN string, hierarchy string) *ldap.Entry {
attrs := []*ldap.EntryAttribute{}
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{"groups"}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"organizationalUnit", "top"}})
@@ -607,7 +571,7 @@ func (l LDAPOpsHelper) topLevelGroupsNode(ctx context.Context, searchBaseDN stri
return &ldap.Entry{DN: dn, Attributes: attrs}
}
func (l LDAPOpsHelper) topLevelUsersNode(ctx context.Context, searchBaseDN string) *ldap.Entry {
func (l LDAPOpsHelper) topLevelUsersNode(searchBaseDN string) *ldap.Entry {
attrs := []*ldap.EntryAttribute{}
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{"users"}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"organizationalUnit", "top"}})
@@ -622,7 +586,7 @@ func (l LDAPOpsHelper) topLevelUsersNode(ctx context.Context, searchBaseDN strin
// querying groups and users under a certain node (e.g. ou=users) with a scope of "sub"
// (and only in this scenario!) will defeat the LDAP library's filtering capabilities.
// Some day, hopefully, I'll fix this directly in the library.
func (l LDAPOpsHelper) preFilterEntries(ctx context.Context, searchBaseDN string, entries []*ldap.Entry) (resultentries []*ldap.Entry) {
func (l LDAPOpsHelper) preFilterEntries(searchBaseDN string, entries []*ldap.Entry) (resultentries []*ldap.Entry) {
filteredEntries := []*ldap.Entry{}
for _, entry := range entries {
if strings.HasSuffix(entry.DN, searchBaseDN) {
@@ -632,9 +596,7 @@ func (l LDAPOpsHelper) preFilterEntries(ctx context.Context, searchBaseDN string
return filteredEntries
}
func (l LDAPOpsHelper) findUser(ctx context.Context, h LDAPOpsHandler, bindDN string, checkGroup bool) (userWhenFound *config.User, resultCode ldap.LDAPResultCode) {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.findUser")
defer span.End()
func (l LDAPOpsHelper) findUser(h LDAPOpsHandler, bindDN string, checkGroup bool) (userWhenFound *config.User, resultCode ldap.LDAPResultCode) {
var user config.User
@@ -644,7 +606,7 @@ func (l LDAPOpsHelper) findUser(ctx context.Context, h LDAPOpsHandler, bindDN st
// Not using mail.ParseAddress/1 because we would allow incorrectly formatted UPNs
if emailmatcher.MatchString(bindDN) {
var foundUser bool // = false
foundUser, user, _ = h.FindUser(ctx, bindDN, true)
foundUser, user, _ = h.FindUser(bindDN, true)
if !foundUser {
h.GetLog().Info().Str("userprincipalname", bindDN).Msg("User not found")
return nil, ldap.LDAPResultInvalidCredentials
@@ -660,10 +622,10 @@ func (l LDAPOpsHelper) findUser(ctx context.Context, h LDAPOpsHandler, bindDN st
groupName := ""
userName := ""
if len(parts) == 1 {
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormatAsArray[0]+"=")
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormat+"=")
} else if len(parts) == 2 || (len(parts) == 3 && parts[2] == "ou=users") {
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormatAsArray[0]+"=")
groupName = strings.TrimPrefix(parts[1], h.GetBackend().GroupFormatAsArray[0]+"=")
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormat+"=")
groupName = strings.TrimPrefix(parts[1], h.GetBackend().GroupFormat+"=")
} else {
h.GetLog().Info().Str("binddn", bindDN).Int("numparts", len(parts)).Msg("BindDN should have only one or two parts")
for _, part := range parts {
@@ -674,7 +636,7 @@ func (l LDAPOpsHelper) findUser(ctx context.Context, h LDAPOpsHandler, bindDN st
// find the user
var foundUser bool // = false
foundUser, user, _ = h.FindUser(ctx, userName, false)
foundUser, user, _ = h.FindUser(userName, false)
if !foundUser {
h.GetLog().Info().Str("username", userName).Msg("User not found")
return nil, ldap.LDAPResultInvalidCredentials
@@ -684,7 +646,7 @@ func (l LDAPOpsHelper) findUser(ctx context.Context, h LDAPOpsHandler, bindDN st
var group config.Group // = nil
var foundGroup bool // = false
if groupName != "" {
foundGroup, group, _ = h.FindGroup(ctx, groupName)
foundGroup, group, _ = h.FindGroup(groupName)
if !foundGroup {
h.GetLog().Info().Str("groupname", groupName).Msg("Group not found")
return nil, ldap.LDAPResultInvalidCredentials
@@ -702,8 +664,7 @@ func (l LDAPOpsHelper) findUser(ctx context.Context, h LDAPOpsHandler, bindDN st
return &user, ldap.LDAPResultSuccess
}
func (l LDAPOpsHelper) checkCapability(ctx context.Context, user config.User, action string, objects []string) bool {
// User-level?
func (l LDAPOpsHelper) checkCapability(user config.User, action string, objects []string) bool {
for _, capability := range user.Capabilities {
if capability.Action == action {
for _, object := range objects {
@@ -719,10 +680,7 @@ func (l LDAPOpsHelper) checkCapability(ctx context.Context, user config.User, ac
// If your query is for, say 'objectClass', then our LDAP
// library will weed out this entry since it does *not* contain an objectclass attribute
// so we are going to re-inject it to keep the LDAP library happy
func (l LDAPOpsHelper) collectRequestedAttributesBack(ctx context.Context, attrs []*ldap.EntryAttribute, searchReq ldap.SearchRequest) []*ldap.EntryAttribute {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.collectRequestedAttributesBack")
defer span.End()
func (l LDAPOpsHelper) collectRequestedAttributesBack(attrs []*ldap.EntryAttribute, searchReq ldap.SearchRequest) []*ldap.EntryAttribute {
attbits := configattributematcher.FindStringSubmatch(searchReq.Filter)
if len(attbits) == 3 {
foundattname := false
@@ -741,16 +699,13 @@ func (l LDAPOpsHelper) collectRequestedAttributesBack(ctx context.Context, attrs
}
// return true if we should not process the current operation
func (l LDAPOpsHelper) isInTimeout(ctx context.Context, handler LDAPOpsHandler, conn net.Conn) bool {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.isInTimeout")
defer span.End()
func (l LDAPOpsHelper) isInTimeout(handler LDAPOpsHandler, conn net.Conn) bool {
cfg := handler.GetCfg()
if !cfg.Behaviors.LimitFailedBinds {
return false
}
remoteAddr := l.getAddr(ctx, conn)
remoteAddr := l.getAddr(conn)
now := time.Now()
info, ok := l.sources[remoteAddr]
if !ok {
@@ -770,16 +725,13 @@ func (l LDAPOpsHelper) isInTimeout(ctx context.Context, handler LDAPOpsHandler,
return false
}
func (l LDAPOpsHelper) maybePutInTimeout(ctx context.Context, handler LDAPOpsHandler, conn net.Conn, noteFailure bool) bool {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.maybePutInTimeout")
defer span.End()
func (l LDAPOpsHelper) maybePutInTimeout(handler LDAPOpsHandler, conn net.Conn, noteFailure bool) bool {
cfg := handler.GetCfg()
if !cfg.Behaviors.LimitFailedBinds {
return false
}
remoteAddr := l.getAddr(ctx, conn)
remoteAddr := l.getAddr(conn)
now := time.Now()
info, _ := l.sources[remoteAddr]
// if we have a failed bind...
@@ -813,10 +765,7 @@ func (l LDAPOpsHelper) maybePutInTimeout(ctx context.Context, handler LDAPOpsHan
return false
}
func (l LDAPOpsHelper) getAddr(ctx context.Context, conn net.Conn) string {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.getAddr")
defer span.End()
func (l LDAPOpsHelper) getAddr(conn net.Conn) string {
fullAddr := conn.RemoteAddr().String()
sep := strings.LastIndex(fullAddr, ":")
if sep == -1 {
-9
View File
@@ -4,7 +4,6 @@ import (
"context"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/GeertJohan/yubigo"
"github.com/glauth/glauth/v2/internal/monitoring"
@@ -25,7 +24,6 @@ type Options struct {
Helper Handler
LDAPHelper LDAPOpsHelper
Monitor monitoring.MonitorInterface
Tracer trace.Tracer
}
// newOptions initializes the available default options.
@@ -112,10 +110,3 @@ func Monitor(val monitoring.MonitorInterface) Option {
o.Monitor = val
}
}
// Tracer provides a function to set the tracer option.
func Tracer(val trace.Tracer) Option {
return func(o *Options) {
o.Tracer = val
}
}
+29 -44
View File
@@ -14,7 +14,6 @@ import (
"time"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/glauth/glauth/v2/internal/monitoring"
"github.com/glauth/glauth/v2/pkg/config"
@@ -39,35 +38,11 @@ type ownCloudHandler struct {
lock *sync.Mutex
monitor monitoring.MonitorInterface
tracer trace.Tracer
}
// global lock for ownCloudHandler sessions & servers manipulation
var ownCloudLock sync.Mutex
func NewOwnCloudHandler(opts ...Option) Handler {
options := newOptions(opts...)
return ownCloudHandler{
backend: options.Backend,
log: options.Logger,
sessions: make(map[string]ownCloudSession),
lock: &ownCloudLock,
client: &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: options.Backend.Insecure,
},
},
},
monitor: options.Monitor,
tracer: options.Tracer,
}
}
func (h ownCloudHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (result ldap.LDAPResultCode, err error) {
start := time.Now()
defer func() {
@@ -167,9 +142,7 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
}
for _, g := range groups {
attrs := []*ldap.EntryAttribute{}
for _, groupAttr := range h.backend.GroupFormatAsArray {
attrs = append(attrs, &ldap.EntryAttribute{Name: groupAttr, Values: []string{*g.ID}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.GroupFormat, Values: []string{*g.ID}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s from ownCloud", *g.ID)}})
// attrs = append(attrs, &ldap.EntryAttribute{"gidNumber", []string{fmt.Sprintf("%d", g.GIDNumber)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixGroup"}})
@@ -181,7 +154,7 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: members})
}
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormatAsArray[0], *g.ID, h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormat, *g.ID, h.backend.BaseDN)
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
}
case "posixaccount", "":
@@ -199,9 +172,8 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
}
for _, u := range users {
attrs := []*ldap.EntryAttribute{}
for _, nameAttr := range h.backend.NameFormatAsArray {
attrs = append(attrs, &ldap.EntryAttribute{Name: nameAttr, Values: []string{*u.ID}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.NameFormat, Values: []string{*u.ID}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{*u.ID}})
if u.DisplayName != nil {
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{*u.DisplayName}})
}
@@ -212,7 +184,7 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixAccount"}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s from ownCloud", *u.ID)}})
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormatAsArray[0], *u.ID, h.backend.GroupFormatAsArray[0], "users", h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, *u.ID, h.backend.GroupFormat, "users", h.backend.BaseDN)
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
}
}
@@ -247,9 +219,6 @@ func (h ownCloudHandler) Modify(boundDN string, req ldap.ModifyRequest, conn net
// Delete is not yet supported for the owncloud backend
func (h ownCloudHandler) Delete(boundDN string, deleteDN string, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "handler.configHandler.Delete")
defer span.End()
start := time.Now()
defer func() {
h.monitor.SetResponseTimeMetric(
@@ -261,17 +230,11 @@ func (h ownCloudHandler) Delete(boundDN string, deleteDN string, conn net.Conn)
}
// FindUser with the given username. Called by the ldap backend to authenticate the bind. Optional
func (h ownCloudHandler) FindUser(ctx context.Context, userName string, searchByUPN bool) (found bool, user config.User, err error) {
_, span := h.tracer.Start(ctx, "handler.ownCloudHandler.FindUser")
defer span.End()
func (h ownCloudHandler) FindUser(userName string, searchByUPN bool) (found bool, user config.User, err error) {
return false, config.User{}, nil
}
func (h ownCloudHandler) FindGroup(ctx context.Context, groupName string) (found bool, group config.Group, err error) {
_, span := h.tracer.Start(ctx, "handler.ownCloudHandler.FindGroup")
defer span.End()
func (h ownCloudHandler) FindGroup(groupName string) (found bool, group config.Group, err error) {
return false, config.Group{}, nil
}
@@ -431,3 +394,25 @@ func (s ownCloudSession) redirectPolicyFunc(req *http.Request, via []*http.Reque
req.SetBasicAuth(s.user, s.password)
return nil
}
func NewOwnCloudHandler(opts ...Option) Handler {
options := newOptions(opts...)
return ownCloudHandler{
backend: options.Backend,
log: options.Logger,
sessions: make(map[string]ownCloudSession),
lock: &ownCloudLock,
client: &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: options.Backend.Insecure,
},
},
},
monitor: options.Monitor,
}
}
+52 -153
View File
@@ -1,7 +1,6 @@
package plugins
import (
"context"
"database/sql"
"encoding/json"
"errors"
@@ -14,10 +13,6 @@ import (
"strings"
"github.com/rs/zerolog"
"github.com/uptrace/opentelemetry-go-extra/otelsql"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
"go.opentelemetry.io/otel/trace"
"github.com/GeertJohan/yubigo"
"github.com/glauth/glauth/v2/pkg/config"
@@ -54,21 +49,13 @@ type databaseHandler struct {
MemGroups []config.Group
ldohelper handler.LDAPOpsHelper
attmatcher *regexp.Regexp
tracer trace.Tracer
}
func NewDatabaseHandler(sqlBackend SqlBackend, opts ...handler.Option) handler.Handler {
options := handler.NewOptions(opts...)
// Note: we will never terminate this connection pool.
db, err := otelsql.Open(
sqlBackend.GetDriverName(),
options.Backend.Database,
otelsql.WithAttributes(otlpDriverAttribute(sqlBackend)),
otelsql.WithDBName(options.Backend.Database),
)
db, err := sql.Open(sqlBackend.GetDriverName(), options.Backend.Database)
if err != nil {
options.Logger.Error().Err(err).Msg(fmt.Sprintf("unable to open SQL database named '%s'", options.Backend.Database))
os.Exit(1)
@@ -92,38 +79,23 @@ func NewDatabaseHandler(sqlBackend SqlBackend, opts ...handler.Option) handler.H
sqlBackend: sqlBackend,
database: dbInfo,
ldohelper: options.LDAPHelper,
attmatcher: configattributematcher,
tracer: options.Tracer,
}
attmatcher: configattributematcher}
sqlBackend.CreateSchema(db)
sqlBackend.MigrateSchema(db, ColumnExists)
options.Logger.Debug().Msg("Database (" + sqlBackend.GetDriverName() + "::" + options.Backend.Database + ") Plugin: Ready")
options.Logger.Info().Msg("Database (" + sqlBackend.GetDriverName() + "::" + options.Backend.Database + ") Plugin: Ready")
return handler
}
func ColumnExists(db *sql.DB, tableName string, columnName string) bool {
var found string
err := db.QueryRowContext(context.Background(), fmt.Sprintf(`SELECT COUNT(%s) FROM %s`, columnName, tableName)).Scan(
err := db.QueryRow(fmt.Sprintf(`SELECT COUNT(%s) FROM %s`, columnName, tableName)).Scan(
&found)
return err == nil
}
func otlpDriverAttribute(backend SqlBackend) attribute.KeyValue {
switch backend.GetDriverName() {
case "sqlite3":
return semconv.DBSystemSqlite
case "postgres":
return semconv.DBSystemPostgreSQL
case "mysql":
return semconv.DBSystemMySQL
default:
return semconv.DBSystemOtherSQL
}
}
func (h databaseHandler) GetBackend() config.Backend {
return h.backend
}
@@ -138,47 +110,29 @@ func (h databaseHandler) GetYubikeyAuth() *yubigo.YubiAuth {
}
func (h databaseHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
ctx, span := h.tracer.Start(context.Background(), "plugins.databaseHandler.Bind")
defer span.End()
return h.ldohelper.Bind(ctx, h, bindDN, bindSimplePw, conn)
return h.ldohelper.Bind(h, bindDN, bindSimplePw, conn)
}
func (h databaseHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
ctx, span := h.tracer.Start(context.Background(), "plugins.databaseHandler.Search")
defer span.End()
return h.ldohelper.Search(ctx, h, bindDN, searchReq, conn)
return h.ldohelper.Search(h, bindDN, searchReq, conn)
}
// Add is not yet supported for the sql backend
func (h databaseHandler) Add(boundDN string, req ldap.AddRequest, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "plugins.databaseHandler.Add")
defer span.End()
return ldap.LDAPResultInsufficientAccessRights, nil
}
// Modify is not yet supported for the sql backend
func (h databaseHandler) Modify(boundDN string, req ldap.ModifyRequest, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "plugins.databaseHandler.Modify")
defer span.End()
return ldap.LDAPResultInsufficientAccessRights, nil
}
// Delete is not yet supported for the sql backend
func (h databaseHandler) Delete(boundDN string, deleteDN string, conn net.Conn) (result ldap.LDAPResultCode, err error) {
_, span := h.tracer.Start(context.Background(), "plugins.databaseHandler.Delete")
defer span.End()
return ldap.LDAPResultInsufficientAccessRights, nil
}
func (h databaseHandler) FindUser(ctx context.Context, userName string, searchByUPN bool) (f bool, u config.User, err error) {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.FindUser")
defer span.End()
func (h databaseHandler) FindUser(userName string, searchByUPN bool) (f bool, u config.User, err error) {
var criterion string
if searchByUPN {
criterion = "lower(u.mail)"
@@ -190,14 +144,11 @@ func (h databaseHandler) FindUser(ctx context.Context, userName string, searchBy
found := false
var disabled int
err = h.database.cnx.QueryRowContext(
ctx,
fmt.Sprintf(`
err = h.database.cnx.QueryRow(fmt.Sprintf(`
SELECT u.uidnumber,u.primarygroup,u.passbcrypt,u.passsha256,u.otpsecret,u.yubikey,u.disabled
FROM users u WHERE %s=%s`,
criterion,
h.sqlBackend.GetPrepareSymbol(),
), userName).Scan(
criterion,
h.sqlBackend.GetPrepareSymbol()), userName).Scan(
&user.UIDNumber, &user.PrimaryGroup, &user.PassBcrypt, &user.PassSHA256, &user.OTPSecret, &user.Yubikey, &disabled)
if err == nil {
user.Disabled = h.intToBool(disabled)
@@ -206,7 +157,7 @@ func (h databaseHandler) FindUser(ctx context.Context, userName string, searchBy
if !h.cfg.Behaviors.IgnoreCapabilities {
capability := config.Capability{}
rows, err := h.database.cnx.QueryContext(ctx, fmt.Sprintf(`
rows, err := h.database.cnx.Query(fmt.Sprintf(`
SELECT c.action,c.object
FROM capabilities c WHERE userid=%s`,
h.sqlBackend.GetPrepareSymbol()), user.UIDNumber)
@@ -226,16 +177,11 @@ func (h databaseHandler) FindUser(ctx context.Context, userName string, searchBy
return found, user, err
}
func (h databaseHandler) FindGroup(ctx context.Context, groupName string) (f bool, g config.Group, err error) {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.FindGroup")
defer span.End()
func (h databaseHandler) FindGroup(groupName string) (f bool, g config.Group, err error) {
group := config.Group{}
found := false
err = h.database.cnx.QueryRowContext(
ctx,
fmt.Sprintf(`
err = h.database.cnx.QueryRow(fmt.Sprintf(`
SELECT g.gidnumber FROM ldapgroups g WHERE lower(name)=%s`, h.sqlBackend.GetPrepareSymbol()), groupName).Scan(
&group.GIDNumber)
if err == nil {
@@ -245,20 +191,15 @@ func (h databaseHandler) FindGroup(ctx context.Context, groupName string) (f boo
return found, group, err
}
func (h databaseHandler) FindPosixAccounts(ctx context.Context, hierarchy string) (entrylist []*ldap.Entry, err error) {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.FindPosixAccounts")
defer span.End()
func (h databaseHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.Entry, err error) {
entries := []*ldap.Entry{}
h.MemGroups, err = h.memoizeGroups(ctx)
h.MemGroups, err = h.memoizeGroups()
if err != nil {
return entries, err
}
rows, err := h.database.cnx.QueryContext(
ctx,
`
rows, err := h.database.cnx.Query(`
SELECT u.name,u.uidnumber,u.primarygroup,u.passbcrypt,u.passsha256,u.otpsecret,u.yubikey,u.othergroups,u.givenname,u.sn,u.mail,u.loginshell,u.homedirectory,u.disabled,u.sshkeys,u.custattr
FROM users u`)
if err != nil {
@@ -276,11 +217,11 @@ func (h databaseHandler) FindPosixAccounts(ctx context.Context, hierarchy string
if err != nil {
return entries, err
}
u.OtherGroups = h.commaListToIntTable(ctx, otherGroups)
u.OtherGroups = h.commaListToIntTable(otherGroups)
u.Disabled = h.intToBool(disabled)
u.SSHKeys = h.commaListToStringTable(ctx, sshKeys)
u.SSHKeys = h.commaListToStringTable(sshKeys)
entry := h.getAccount(ctx, hierarchy, u)
entry := h.getAccount(hierarchy, u)
if custattrstr != "{}" {
var r map[string]interface{}
@@ -313,19 +254,16 @@ func (h databaseHandler) FindPosixAccounts(ctx context.Context, hierarchy string
return entries, nil
}
func (h databaseHandler) FindPosixGroups(ctx context.Context, hierarchy string) (entrylist []*ldap.Entry, err error) {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.FindPosixGroups")
defer span.End()
func (h databaseHandler) FindPosixGroups(hierarchy string) (entrylist []*ldap.Entry, err error) {
entries := []*ldap.Entry{}
h.MemGroups, err = h.memoizeGroups(ctx)
h.MemGroups, err = h.memoizeGroups()
if err != nil {
return entries, err
}
for _, g := range h.MemGroups {
info := h.getGroup(ctx, hierarchy, g)
info := h.getGroup(hierarchy, g)
if hierarchy != "groups" {
info.DN = strings.Replace(info.DN, ",ou=groups,", fmt.Sprintf(",%s,", hierarchy), 1)
}
@@ -336,9 +274,6 @@ func (h databaseHandler) FindPosixGroups(ctx context.Context, hierarchy string)
}
func (h databaseHandler) Close(boundDn string, conn net.Conn) error {
_, span := h.tracer.Start(context.Background(), "plugins.databaseHandler.Close")
defer span.End()
stats.Frontend.Add("closes", 1)
return nil
}
@@ -350,10 +285,7 @@ func (h databaseHandler) intToBool(value int) bool {
return true
}
func (h databaseHandler) commaListToIntTable(ctx context.Context, commaList string) []int {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.commaListToIntTable")
defer span.End()
func (h databaseHandler) commaListToIntTable(commaList string) []int {
if len(commaList) == 0 {
return make([]int, 0)
}
@@ -369,24 +301,16 @@ func (h databaseHandler) commaListToIntTable(ctx context.Context, commaList stri
return rowsAsInts
}
func (h databaseHandler) commaListToStringTable(ctx context.Context, commaList string) []string {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.commaListToStringTable")
defer span.End()
func (h databaseHandler) commaListToStringTable(commaList string) []string {
if len(commaList) == 0 {
return make([]string, 0)
}
return strings.Split(commaList, ",")
}
func (h databaseHandler) memoizeGroups(ctx context.Context) ([]config.Group, error) {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.memoizeGroups")
defer span.End()
func (h databaseHandler) memoizeGroups() ([]config.Group, error) {
workMemGroups := make([]*config.Group, 0)
rows, err := h.database.cnx.QueryContext(
ctx,
`
rows, err := h.database.cnx.Query(`
SELECT g1.name,g1.gidnumber,ig.includegroupid
FROM ldapgroups g1
LEFT JOIN includegroups ig ON g1.gidnumber=ig.parentgroupid
@@ -423,10 +347,7 @@ func (h databaseHandler) memoizeGroups(ctx context.Context) ([]config.Group, err
return memGroups, nil
}
func (h databaseHandler) getGroupMemberDNs(ctx context.Context, gid int) []string {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.getGroupMemberDNs")
defer span.End()
func (h databaseHandler) getGroupMemberDNs(gid int) []string {
var insertOuUsers string
if h.cfg.Behaviors.LegacyVersion > 0 && h.cfg.Behaviors.LegacyVersion <= 20100 {
insertOuUsers = ""
@@ -435,9 +356,7 @@ func (h databaseHandler) getGroupMemberDNs(ctx context.Context, gid int) []strin
}
members := make(map[string]bool)
rows, err := h.database.cnx.QueryContext(
ctx,
`
rows, err := h.database.cnx.Query(`
SELECT u.name,u.uidnumber,u.primarygroup,u.passbcrypt,u.passsha256,u.otpsecret,u.yubikey,u.othergroups
FROM users u`)
if err != nil {
@@ -454,13 +373,13 @@ func (h databaseHandler) getGroupMemberDNs(ctx context.Context, gid int) []strin
return []string{}
}
if u.PrimaryGroup == gid {
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
members[dn] = true
} else {
u.OtherGroups = h.commaListToIntTable(ctx, otherGroups)
u.OtherGroups = h.commaListToIntTable(otherGroups)
for _, othergid := range u.OtherGroups {
if othergid == gid {
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
members[dn] = true
}
}
@@ -471,7 +390,7 @@ func (h databaseHandler) getGroupMemberDNs(ctx context.Context, gid int) []strin
if gid == g.GIDNumber {
for _, includegroupid := range g.IncludeGroups {
if includegroupid != gid {
includegroupmembers := h.getGroupMemberDNs(ctx, includegroupid)
includegroupmembers := h.getGroupMemberDNs(includegroupid)
for _, includegroupmember := range includegroupmembers {
members[includegroupmember] = true
@@ -492,14 +411,9 @@ func (h databaseHandler) getGroupMemberDNs(ctx context.Context, gid int) []strin
}
// Used exclusively when looking up Posix Groups
func (h databaseHandler) getGroupMemberIDs(ctx context.Context, gid int) []string {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.getGroupMemberIDs")
defer span.End()
func (h databaseHandler) getGroupMemberIDs(gid int) []string {
members := make(map[string]bool)
rows, err := h.database.cnx.QueryContext(
ctx,
`
rows, err := h.database.cnx.Query(`
SELECT u.name,u.uidnumber,u.primarygroup,u.passbcrypt,u.passsha256,u.otpsecret,u.yubikey,u.othergroups
FROM users u`)
if err != nil {
@@ -518,7 +432,7 @@ func (h databaseHandler) getGroupMemberIDs(ctx context.Context, gid int) []strin
if u.PrimaryGroup == gid {
members[u.Name] = true
} else {
u.OtherGroups = h.commaListToIntTable(ctx, otherGroups)
u.OtherGroups = h.commaListToIntTable(otherGroups)
for _, othergid := range u.OtherGroups {
if othergid == gid {
members[u.Name] = true
@@ -533,7 +447,7 @@ func (h databaseHandler) getGroupMemberIDs(ctx context.Context, gid int) []strin
if includegroupid == gid {
h.log.Warn().Msg(fmt.Sprintf("Group: %d - Ignoring myself as included group", includegroupid))
} else {
includegroupmemberids := h.getGroupMemberIDs(ctx, includegroupid)
includegroupmemberids := h.getGroupMemberIDs(includegroupid)
for _, includegroupmemberid := range includegroupmemberids {
members[includegroupmemberid] = true
@@ -554,21 +468,18 @@ func (h databaseHandler) getGroupMemberIDs(ctx context.Context, gid int) []strin
}
// Invoked for every user being returned from our database
func (h databaseHandler) getGroupDNs(ctx context.Context, gids []int) []string {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.getGroupDNs")
defer span.End()
func (h databaseHandler) getGroupDNs(gids []int) []string {
groups := make(map[string]bool)
for _, gid := range gids {
for _, g := range h.MemGroups {
if g.GIDNumber == gid {
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormatAsArray[0], g.Name, h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormat, g.Name, h.backend.BaseDN)
groups[dn] = true
}
for _, includegroupid := range g.IncludeGroups {
if includegroupid == gid && g.GIDNumber != gid {
includegroupdns := h.getGroupDNs(ctx, []int{g.GIDNumber})
includegroupdns := h.getGroupDNs([]int{g.GIDNumber})
for _, includegroupdn := range includegroupdns {
groups[includegroupdn] = true
@@ -589,10 +500,7 @@ func (h databaseHandler) getGroupDNs(ctx context.Context, gids []int) []string {
}
// Invoked for every user being returned from our database
func (h databaseHandler) getGroupName(ctx context.Context, gid int) string {
_, span := h.tracer.Start(ctx, "plugins.databaseHandler.getGroupName")
defer span.End()
func (h databaseHandler) getGroupName(gid int) string {
for _, g := range h.MemGroups {
if g.GIDNumber == gid {
return g.Name
@@ -602,37 +510,28 @@ func (h databaseHandler) getGroupName(ctx context.Context, gid int) string {
}
// Toolbox
func (h databaseHandler) getGroup(ctx context.Context, hierarchy string, g config.Group) *ldap.Entry {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.getGroup")
defer span.End()
func (h databaseHandler) getGroup(hierarchy string, g config.Group) *ldap.Entry {
asGroupOfUniqueNames := hierarchy == "ou=groups"
attrs := []*ldap.EntryAttribute{}
for _, groupAttr := range h.backend.GroupFormatAsArray {
attrs = append(attrs, &ldap.EntryAttribute{Name: groupAttr, Values: []string{g.Name}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.GroupFormat, Values: []string{g.Name}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s via LDAP", g.Name)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", g.GIDNumber)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(ctx, g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(g.GIDNumber)})
if asGroupOfUniqueNames {
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"groupOfUniqueNames", "top"}})
} else {
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(ctx, g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixGroup", "top"}})
}
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormatAsArray[0], g.Name, h.backend.BaseDN)
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormat, g.Name, h.backend.BaseDN)
return &ldap.Entry{DN: dn, Attributes: attrs}
}
func (h databaseHandler) getAccount(ctx context.Context, hierarchy string, u config.User) *ldap.Entry {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.getAccount")
defer span.End()
func (h databaseHandler) getAccount(hierarchy string, u config.User) *ldap.Entry {
attrs := []*ldap.EntryAttribute{}
for _, nameAttr := range h.backend.NameFormatAsArray {
attrs = append(attrs, &ldap.EntryAttribute{Name: nameAttr, Values: []string{u.Name}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.NameFormat, Values: []string{u.Name}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{u.Name}})
if len(u.GivenName) > 0 {
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{u.GivenName}})
@@ -642,7 +541,7 @@ func (h databaseHandler) getAccount(ctx context.Context, hierarchy string, u con
attrs = append(attrs, &ldap.EntryAttribute{Name: "sn", Values: []string{u.SN}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(ctx, u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uidNumber", Values: []string{fmt.Sprintf("%d", u.UIDNumber)}})
if u.Disabled {
@@ -673,15 +572,15 @@ func (h databaseHandler) getAccount(ctx context.Context, hierarchy string, u con
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s via LDAP", u.Name)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "gecos", Values: []string{fmt.Sprintf("%s via LDAP", u.Name)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: h.getGroupDNs(ctx, append(u.OtherGroups, u.PrimaryGroup))})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: h.getGroupDNs(append(u.OtherGroups, u.PrimaryGroup))})
if len(u.SSHKeys) > 0 {
attrs = append(attrs, &ldap.EntryAttribute{Name: "sshPublicKey", Values: u.SSHKeys})
}
var dn string
if hierarchy == "" {
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), h.backend.BaseDN)
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), h.backend.BaseDN)
} else {
dn = fmt.Sprintf("%s=%s,%s=%s,%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), hierarchy, h.backend.BaseDN)
dn = fmt.Sprintf("%s=%s,%s=%s,%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), hierarchy, h.backend.BaseDN)
}
return &ldap.Entry{DN: dn, Attributes: attrs}
}
+3
View File
@@ -0,0 +1,3 @@
release-glauth-bogus:
@echo Ignoring bogus plugin
-13
View File
@@ -1,13 +0,0 @@
//go:build !(embedsqlite || embedmysql)
package server
import (
"errors"
"github.com/glauth/glauth/v2/pkg/handler"
)
func NewEmbed(opts ...handler.Option) (handler.Handler, error) {
return nil, errors.New("GLAuth was not built with support for an embedded plugin")
}
-12
View File
@@ -1,12 +0,0 @@
//go:build embedsqlite
package server
import (
"github.com/glauth/glauth/v2/pkg/embed"
"github.com/glauth/glauth/v2/pkg/handler"
)
func NewEmbed(opts ...handler.Option) (handler.Handler, error) {
return embed.NewSQLiteHandler(opts...), nil
}
+8 -25
View File
@@ -5,7 +5,6 @@ import (
"crypto/tls"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/glauth/glauth/v2/internal/monitoring"
"github.com/glauth/glauth/v2/pkg/config"
@@ -16,13 +15,11 @@ type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger zerolog.Logger
Config *config.Config
StartTLSConfig *tls.Config
LDAPSTLSConfig *tls.Config
Monitor monitoring.MonitorInterface
Tracer trace.Tracer
Context context.Context
Logger zerolog.Logger
Config *config.Config
Monitor monitoring.MonitorInterface
TLSConfig *tls.Config
Context context.Context
}
// newOptions initializes the available default options.
@@ -57,17 +54,10 @@ func Context(val context.Context) Option {
}
}
// TLSConfig provides a function to set the StartTLS config option.
func StartTLSConfig(val *tls.Config) Option {
// TLSConfig provides a function to set the TLS config option.
func TLSConfig(val *tls.Config) Option {
return func(o *Options) {
o.StartTLSConfig = val
}
}
// TLSConfig provides a function to set the LDAPSTls config option.
func LDAPSTLSConfig(val *tls.Config) Option {
return func(o *Options) {
o.LDAPSTLSConfig = val
o.TLSConfig = val
}
}
@@ -77,10 +67,3 @@ func Monitor(val monitoring.MonitorInterface) Option {
o.Monitor = val
}
}
// Tracer provides a function to set the tracer option.
func Tracer(val trace.Tracer) Option {
return func(o *Options) {
o.Tracer = val
}
}
+11 -50
View File
@@ -1,15 +1,11 @@
package server
import (
"crypto/tls"
"errors"
"fmt"
"plugin"
_tls "github.com/glauth/glauth/v2/internal/tls"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/GeertJohan/yubigo"
"github.com/glauth/glauth/v2/internal/monitoring"
@@ -23,10 +19,8 @@ type LdapSvc struct {
yubiAuth *yubigo.YubiAuth
l *ldap.Server
ldapstls *tls.Config
monitor monitoring.MonitorInterface
tracer trace.Tracer
log zerolog.Logger
monitor monitoring.MonitorInterface
log zerolog.Logger
}
func NewServer(opts ...Option) (*LdapSvc, error) {
@@ -36,7 +30,6 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
log: options.Logger,
c: options.Config,
monitor: options.Monitor,
tracer: options.Tracer,
}
var err error
@@ -51,7 +44,7 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
var helper handler.Handler
loh := handler.NewLDAPOpsHelper(s.tracer)
loh := handler.NewLDAPOpsHelper()
// instantiate the helper, if any
if s.c.Helper.Enabled {
@@ -62,7 +55,6 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
handler.Config(s.c),
handler.YubiAuth(s.yubiAuth),
handler.LDAPHelper(loh),
handler.Tracer(s.tracer),
)
case "plugin":
plug, err := plugin.Open(s.c.Helper.Plugin)
@@ -85,7 +77,6 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
handler.Config(s.c),
handler.YubiAuth(s.yubiAuth),
handler.LDAPHelper(loh),
handler.Tracer(s.tracer),
)
default:
return nil, fmt.Errorf("unsupported helper %s - must be one of 'config', 'plugin'", s.c.Helper.Datastore)
@@ -100,22 +91,9 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
s.l = ldap.NewServer()
s.l.EnforceLDAP = true
if tlsConfig := options.StartTLSConfig; tlsConfig != nil {
if tlsConfig := options.TLSConfig; tlsConfig != nil {
s.l.TLSConfig = tlsConfig
s.log.Info().
Str("tls.min_version", tls.VersionName(tlsConfig.MinVersion)).
Str("tls.max_version", tls.VersionName(tlsConfig.MaxVersion)).
Interface("tls.cipher_suites", _tls.CipherSuiteNames(tlsConfig.CipherSuites)).
Msg("enabling LDAP over TLS")
}
if tlsConfig := options.LDAPSTLSConfig; tlsConfig != nil {
s.ldapstls = tlsConfig
s.log.Info().
Str("tls.min_version", tls.VersionName(tlsConfig.MinVersion)).
Str("tls.max_version", tls.VersionName(tlsConfig.MaxVersion)).
Interface("tls.cipher_suites", _tls.CipherSuiteNames(tlsConfig.CipherSuites)).
Msg("enabling LDAPS")
s.log.Info().Interface("tls.certificates", tlsConfig.Certificates).Msg("enabling LDAP over TLS")
}
for i, backend := range s.c.Backends {
@@ -128,14 +106,12 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
handler.Logger(&s.log),
handler.Helper(helper),
handler.Monitor(s.monitor),
handler.Tracer(s.tracer),
)
case "owncloud":
h = handler.NewOwnCloudHandler(
handler.Backend(backend),
handler.Logger(&s.log),
handler.Monitor(s.monitor),
handler.Tracer(s.tracer),
)
case "config":
h = handler.NewConfigHandler(
@@ -145,12 +121,11 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
handler.YubiAuth(s.yubiAuth),
handler.LDAPHelper(loh),
handler.Monitor(s.monitor),
handler.Tracer(s.tracer),
)
case "plugin":
plug, err := plugin.Open(backend.Plugin)
if err != nil {
return nil, fmt.Errorf("unable to load specified backend plugin: %s", err)
return nil, errors.New(fmt.Sprintf("Unable to load specified backend plugin: %s", err))
}
nph, err := plug.Lookup(backend.PluginHandler)
if err != nil {
@@ -170,21 +145,7 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
handler.YubiAuth(s.yubiAuth),
handler.LDAPHelper(loh),
handler.Monitor(s.monitor),
handler.Tracer(s.tracer),
)
case "embed":
h, err = NewEmbed(
handler.Backend(backend),
handler.Logger(&s.log),
handler.Config(s.c),
handler.YubiAuth(s.yubiAuth),
handler.LDAPHelper(loh),
handler.Monitor(s.monitor),
handler.Tracer(s.tracer),
)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported backend %s - must be one of 'config', 'ldap','owncloud' or 'plugin'", backend.Datastore)
}
@@ -216,11 +177,11 @@ func (s *LdapSvc) ListenAndServe() error {
// ListenAndServeTLS listens on the TCP network address s.c.LDAPS.Listen
func (s *LdapSvc) ListenAndServeTLS() error {
s.log.Info().Str("address", s.c.LDAPS.Listen).Msg("LDAPS server listening")
listener, err := tls.Listen("tcp", s.c.LDAPS.Listen, s.ldapstls)
if err != nil {
return err
}
return s.l.Serve(listener)
return s.l.ListenAndServeTLS(
s.c.LDAPS.Listen,
s.c.LDAPS.Cert,
s.c.LDAPS.Key,
)
}
// Shutdown ends listeners by sending true to the ldap serves quit channel
-42
View File
@@ -1,42 +0,0 @@
#################
# glauth.conf
#################
# General configuration.
#debug = true
syslog = true
#################
# Server configuration.
[ldap]
enabled = true
listen = "0.0.0.0:3893"
[ldaps]
enabled = false
listen = "0.0.0.0:636"
cert = "glauth.crt"
key = "glauth.key"
#################
# The backend section controls the data store.
[[backends]]
datastore = "ldap"
servers = [ "ldap://192.168.1.222:389" ]
[[backends]]
datastore = "config"
[[users]]
name = "otpuser"
otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk"
#################
# Enable and configure the optional REST API here.
[api]
enabled = false
tls = true
listen = "localhost:5555"
cert = "glauth.crt"
key = "glauth.key"
+7 -27
View File
@@ -3,7 +3,7 @@
#################
# General configuration.
debug = false
debug = true
# syslog = true
# structuredlog = true
#
@@ -28,30 +28,22 @@ debug = false
[ldaps]
# to enable ldaps generate a certificate, eg. with:
# openssl req -x509 -newkey rsa:4096 -keyout glauth.key -out glauth.crt -days 365 -nodes -subj '/CN=`hostname`'
enabled = true
enabled = false
listen = "0.0.0.0:3894"
cert = "glauth.crt"
key = "glauth.key"
#################
# Tracing section controls the tracer configuration
[tracing]
# if enabled is set to false, a no-op tracer will be used
enabled = true
# if both grpcEndpoint and httpEndpoint are unset, the default stdout provider will be used
# TODO add allowGRPCInsecure: right now grpc otlp is using the WithInsecure flag so traffic
# will always go without verifying server certificates
# grpcEndpoint = "otlp.monitoring.io:4317"
# httpEndpoint = "http://otlp.monitoring.io:4318"
#################
# The backend section controls the data store.
[backend]
datastore = "config"
baseDN = "dc=glauth,dc=com"
nameformat = "cn"
groupformat = "ou"
# If you are using a client that requires reading the root DSE first
# such as SSSD
anonymousdse = false
# anonymousdse = true
## Configure dn format to use structures like
## "uid=serviceuser,cn=svcaccts,$BASEDN" instead of "cn=serviceuser,ou=svcaccts,$BASEDN"
@@ -145,11 +137,6 @@ debug = false
# passappbcrypt = "243261243130244B62463462656F7265504F762E794F324957746D656541326B4B46596275674A79336A476845764B616D65446169784E41384F4432" # dogood
otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk"
[[users]]
name = "danger"
uidnumber = 5006
primarygroup = 5503
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
#################
# The groups section contains a hardcoded list of valid users.
@@ -162,16 +149,9 @@ debug = false
gidnumber = 5502
[[groups]]
name = "umbrella"
name = "vpn"
gidnumber = 5503
includegroups = [ 5504 ]
[[groups]]
name = "danger"
gidnumber = 5504
[[groups.capabilities]]
action = "search"
object = "dc=glauth,dc=com"
includegroups = [ 5501 ]
#################
# Enable and configure the optional REST API here.
+7 -7
View File
@@ -1,6 +1,6 @@
dn: ou=superheros,ou=users,dc=glauth,dc=com
ou: superheros
cn: superheros
uid: superheros
description: superheros
gidNumber: 5501
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
@@ -20,7 +20,7 @@ objectClass: top
dn: ou=svcaccts,ou=users,dc=glauth,dc=com
ou: svcaccts
cn: svcaccts
uid: svcaccts
description: svcaccts
gidNumber: 5502
uniqueMember: cn=serviceuser,ou=svcaccts,ou=users,dc=glauth,dc=com
@@ -30,7 +30,7 @@ objectClass: top
dn: ou=vpnaccess,ou=users,dc=glauth,dc=com
ou: vpnaccess
cn: vpnaccess
uid: vpnaccess
description: vpnaccess
gidNumber: 5503
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
@@ -50,7 +50,7 @@ objectClass: top
dn: ou=allaccs,ou=users,dc=glauth,dc=com
ou: allaccs
cn: allaccs
uid: allaccs
description: allaccs
gidNumber: 5504
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
@@ -72,7 +72,7 @@ objectClass: top
dn: ou=mailadmin,ou=users,dc=glauth,dc=com
ou: mailadmin
cn: mailadmin
uid: mailadmin
description: mailadmin
gidNumber: 5505
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
@@ -88,7 +88,7 @@ objectClass: top
dn: ou=webmail,ou=users,dc=glauth,dc=com
ou: webmail
cn: webmail
uid: webmail
description: webmail
gidNumber: 5506
objectClass: posixGroup
@@ -96,7 +96,7 @@ objectClass: top
dn: ou=fulltime,ou=users,dc=glauth,dc=com
ou: fulltime
cn: fulltime
uid: fulltime
description: fulltime
gidNumber: 5507
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
+3 -3
View File
@@ -33,14 +33,14 @@ fi
echo "";
echo ""
echo "Version string of tested binary:"
"$CI_BUILD_DIR/bin/$(go env GOOS)$(go env GOARCH)/glauth" --version
"$CI_BUILD_DIR/bin/linuxamd64/glauth" --version
echo ""
# Start in background, capture PID
"$CI_BUILD_DIR/bin/$(go env GOOS)$(go env GOARCH)/glauth" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &> /dev/null &
"$CI_BUILD_DIR/bin/linuxamd64/glauth" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &> /dev/null &
# Use this instead to see glauth logs while running
# "$CI_BUILD_DIR/bin/$(go env GOOS)$(go env GOARCH)/glauth" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &
# "$CI_BUILD_DIR/bin/linuxamd64/glauth" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &
glauthPid="$!"
echo "Running glauth at PID=$glauthPid"