mirror of
https://github.com/glauth/glauth.git
synced 2026-10-27 06:26:59 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bbb9f4a25e | |||
| 0c0d742ea9 |
@@ -4,13 +4,13 @@ on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- dev
|
||||
jobs:
|
||||
build:
|
||||
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
|
||||
|
||||
@@ -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 }}"
|
||||
|
||||
@@ -2,7 +2,7 @@ on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- dev
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
@@ -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
|
||||
|
||||
+4
-4
@@ -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
|
||||
|
||||
@@ -1,40 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
|
||||
+17
-28
@@ -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 )
|
||||
@@ -23,8 +21,8 @@ BUILD_FILES=.
|
||||
TRIM_FLAGS>?=-trimpath
|
||||
|
||||
# Targets
|
||||
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
|
||||
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}; })
|
||||
@@ -77,12 +75,6 @@ setup: getdeps format
|
||||
# Subcommands
|
||||
#####################
|
||||
|
||||
prepbuild:
|
||||
@if [ ! -e $M/.ignore ] ; \
|
||||
then \
|
||||
mkdir -p buildlogs;\
|
||||
fi
|
||||
|
||||
# Run integration test
|
||||
runtest:
|
||||
./scripts/ci/integration-test.sh cleanup
|
||||
@@ -95,7 +87,7 @@ updatetest:
|
||||
./scripts/ci/integration-test.sh
|
||||
|
||||
format:
|
||||
go fmt ./...
|
||||
go fmt
|
||||
|
||||
devrun:
|
||||
go run ${BUILD_FILES} -c sample-simple.cfg
|
||||
@@ -106,7 +98,7 @@ mkbindir:
|
||||
.PHONY: mkbindir
|
||||
|
||||
build: mkbindir
|
||||
@go build ${TRIM_FLAGS} -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
|
||||
|
||||
@@ -141,15 +133,16 @@ winamd64:
|
||||
verify:
|
||||
@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-release: @ pull plugins dependencies for local building
|
||||
prepare-plugins-release:
|
||||
@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 && \
|
||||
@@ -164,16 +157,12 @@ forget-plugins:
|
||||
done
|
||||
|
||||
#releasemain: @ build main binaries for distribution
|
||||
releasemain: prepbuild
|
||||
releasemain:
|
||||
@xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out glauth -dest bin -buildvcs=false --targets="${MAIN_TARGETS}" .
|
||||
|
||||
releaseplugin: prepbuild
|
||||
@echo "Building $P plugin"; \
|
||||
if [ ! -e $M/.ignore ] ; \
|
||||
then \
|
||||
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); \
|
||||
fi
|
||||
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)
|
||||
|
||||
#releaseplugins: @ build base plugins for distribution
|
||||
releaseplugins:
|
||||
@@ -247,4 +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 darwinamd64 darwinarm64 win386 winamd64 verify pull-plugin pull-base-plugins forget-plugin forget-plugins releasemain releaseplugin release releaseplugins releasedockermain releaserdockerplugins releasedocker testdocker
|
||||
.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
|
||||
|
||||
+1
-11
@@ -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,14 +130,6 @@ func startService() {
|
||||
}
|
||||
|
||||
monitor := monitoring.NewMonitor(&log)
|
||||
tracer := tracing.NewTracer(
|
||||
tracing.NewConfig(
|
||||
activeConfig.Tracing.Enabled,
|
||||
activeConfig.Tracing.GRPCEndpoint,
|
||||
activeConfig.Tracing.HTTPEndpoint,
|
||||
&log,
|
||||
),
|
||||
)
|
||||
|
||||
startConfigWatcher()
|
||||
|
||||
@@ -156,9 +147,8 @@ func startService() {
|
||||
s, err := server.NewServer(
|
||||
server.Logger(log),
|
||||
server.Config(activeConfig),
|
||||
server.TLSConfig(tlsConfig),
|
||||
server.Monitor(monitor),
|
||||
server.Tracer(tracer),
|
||||
server.TLSConfig(tlsConfig),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
||||
+164
-210
@@ -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)
|
||||
}
|
||||
|
||||
// -----=============================================================================----
|
||||
|
||||
@@ -1,59 +1,48 @@
|
||||
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/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.4 // indirect
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // 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
|
||||
)
|
||||
|
||||
replace github.com/nmcclain/ldap => github.com/shipperizer/ldap v0.0.0-20231117095347-c1d6afe484ca
|
||||
|
||||
// replace github.com/nmcclain/ldap => ../../../ldap
|
||||
|
||||
@@ -7,119 +7,94 @@ 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/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/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/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/shipperizer/ldap v0.0.0-20231117095347-c1d6afe484ca h1:KSpZYIDb2ei4d+AxsFmC9KJaTNlmSiONSl6hLd5Qmfg=
|
||||
github.com/shipperizer/ldap v0.0.0-20231117095347-c1d6afe484ca/go.mod h1:/KinL0zHM54Sk4gMgvODL26YGG7u4SFBOAKNpJmsJvc=
|
||||
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=
|
||||
@@ -128,8 +103,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=
|
||||
@@ -139,32 +113,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=
|
||||
@@ -172,6 +137,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=
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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.3.1" // x-release-please-version
|
||||
const Version = "v2.3.0" // x-release-please-version
|
||||
|
||||
+122
-140
@@ -3,144 +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
|
||||
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 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
|
||||
}
|
||||
|
||||
LDAPS struct {
|
||||
Enabled bool
|
||||
Listen string
|
||||
Cert string
|
||||
Key string
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
+21
-65
@@ -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,10 +152,7 @@ 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 {
|
||||
@@ -194,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 {
|
||||
@@ -225,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"}})
|
||||
@@ -260,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.NameFormat, u.Name, h.backend.GroupFormat, 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.NameFormat, u.Name, h.backend.GroupFormat, 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})
|
||||
}
|
||||
@@ -270,10 +244,7 @@ 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{}
|
||||
@@ -284,11 +255,11 @@ func (h configHandler) FindPosixGroups(ctx context.Context, hierarchy string) (e
|
||||
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.GroupFormat, g.Name, hierarchy, h.backend.BaseDN)
|
||||
@@ -300,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 = ""
|
||||
@@ -320,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.NameFormat, u.Name, h.backend.GroupFormat, 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.NameFormat, u.Name, h.backend.GroupFormat, 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
|
||||
}
|
||||
}
|
||||
@@ -336,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
|
||||
@@ -356,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 {
|
||||
@@ -379,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
|
||||
@@ -400,10 +362,7 @@ 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 {
|
||||
@@ -414,7 +373,7 @@ func (h configHandler) getGroupDNs(ctx context.Context, gids []int) []string {
|
||||
|
||||
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
|
||||
@@ -434,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
|
||||
|
||||
@@ -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
|
||||
|
||||
+6
-33
@@ -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(
|
||||
@@ -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(
|
||||
@@ -264,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)
|
||||
@@ -303,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
|
||||
@@ -318,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
|
||||
}
|
||||
@@ -331,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(
|
||||
@@ -346,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(
|
||||
@@ -361,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(
|
||||
@@ -374,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
|
||||
}
|
||||
|
||||
|
||||
+62
-111
@@ -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
|
||||
}
|
||||
@@ -366,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")
|
||||
@@ -375,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
|
||||
}
|
||||
@@ -408,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")
|
||||
@@ -417,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
|
||||
}
|
||||
@@ -451,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
|
||||
}
|
||||
@@ -477,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
|
||||
}
|
||||
@@ -510,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), ",")
|
||||
@@ -525,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)
|
||||
@@ -548,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")
|
||||
@@ -565,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
|
||||
}
|
||||
@@ -583,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 {
|
||||
@@ -594,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"}})
|
||||
@@ -606,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"}})
|
||||
@@ -621,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) {
|
||||
@@ -631,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
|
||||
|
||||
@@ -643,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
|
||||
@@ -673,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
|
||||
@@ -683,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
|
||||
@@ -701,7 +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 {
|
||||
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 {
|
||||
@@ -717,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
|
||||
@@ -739,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 {
|
||||
@@ -768,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...
|
||||
@@ -811,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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+24
-36
@@ -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() {
|
||||
@@ -244,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(
|
||||
@@ -258,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
|
||||
}
|
||||
|
||||
@@ -428,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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,9 +79,7 @@ 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)
|
||||
@@ -106,24 +91,11 @@ func NewDatabaseHandler(sqlBackend SqlBackend, opts ...handler.Option) handler.H
|
||||
|
||||
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.NameFormat, u.Name, h.backend.GroupFormat, 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.NameFormat, u.Name, h.backend.GroupFormat, 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,10 +468,7 @@ 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 {
|
||||
@@ -568,7 +479,7 @@ func (h databaseHandler) getGroupDNs(ctx context.Context, gids []int) []string {
|
||||
|
||||
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,31 +510,25 @@ 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{}
|
||||
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.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{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.NameFormat, Values: []string{u.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{u.Name}})
|
||||
@@ -639,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 {
|
||||
@@ -670,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.NameFormat, u.Name, h.backend.GroupFormat, 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.NameFormat, u.Name, h.backend.GroupFormat, 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}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -18,9 +17,8 @@ type Option func(o *Options)
|
||||
type Options struct {
|
||||
Logger zerolog.Logger
|
||||
Config *config.Config
|
||||
TLSConfig *tls.Config
|
||||
Monitor monitoring.MonitorInterface
|
||||
Tracer trace.Tracer
|
||||
TLSConfig *tls.Config
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
@@ -69,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
|
||||
}
|
||||
}
|
||||
|
||||
+1
-10
@@ -6,7 +6,6 @@ import (
|
||||
"plugin"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/GeertJohan/yubigo"
|
||||
"github.com/glauth/glauth/v2/internal/monitoring"
|
||||
@@ -21,7 +20,6 @@ type LdapSvc struct {
|
||||
l *ldap.Server
|
||||
|
||||
monitor monitoring.MonitorInterface
|
||||
tracer trace.Tracer
|
||||
log zerolog.Logger
|
||||
}
|
||||
|
||||
@@ -32,7 +30,6 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
||||
log: options.Logger,
|
||||
c: options.Config,
|
||||
monitor: options.Monitor,
|
||||
tracer: options.Tracer,
|
||||
}
|
||||
|
||||
var err error
|
||||
@@ -47,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 {
|
||||
@@ -58,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)
|
||||
@@ -81,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)
|
||||
@@ -111,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(
|
||||
@@ -128,7 +121,6 @@ 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)
|
||||
@@ -153,7 +145,6 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
||||
handler.YubiAuth(s.yubiAuth),
|
||||
handler.LDAPHelper(loh),
|
||||
handler.Monitor(s.monitor),
|
||||
handler.Tracer(s.tracer),
|
||||
)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported backend %s - must be one of 'config', 'ldap','owncloud' or 'plugin'", backend.Datastore)
|
||||
|
||||
@@ -34,16 +34,6 @@ debug = true
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user