Compare commits

..

15 Commits

Author SHA1 Message Date
Chris F Ravenscroft c05df847dc chore: release 2.3.1
Release-As: 2.3.1
2023-12-18 00:12:58 +00:00
Chris F Ravenscroft f5bb80e024 Update release-please to use master branch 2023-12-17 15:55:36 -08:00
Chris F Ravenscroft 1a37396109 fix: update tracing code to work with breaking otlp 1.20 changes 2023-12-11 01:36:58 +00:00
Chris F Ravenscroft d178281474 Merge branch 'shipperizer-otlp' 2023-12-11 00:36:53 +00:00
Chris F Ravenscroft a0d1069841 Merge branch 'master' into otlp 2023-12-10 16:34:56 -08:00
Chris F Ravenscroft 67d77324a3 chore: reweure ldap packages (#370) 2023-12-10 15:32:24 -08:00
Alessandro Cabbia 01bdb7148e startTLS: ldap over TLS functionality (#364)
* feat: introduce tls parameters in config to allow startTLS

* feat: pass tls config for startTLS to ldap server

* build: update libs to use newer ldap

* feat: allow tls config for startTLS
2023-12-10 15:20:29 -08:00
shipperizer f692394942 feat: allow tracing configuration via main config 2023-12-10 17:34:33 +00:00
shipperizer 46e49b6976 feat: introduce context for otlp spans into plugins pkg 2023-12-10 10:13:10 +00:00
shipperizer 52a0adcbcf ci: add go1.21 2023-12-10 09:59:57 +00:00
shipperizer 2ca5312696 feat: introduce otelsql 2023-12-10 09:59:55 +00:00
shipperizer 6ee78cd881 build: update deps with otlp libs 2023-12-10 09:59:04 +00:00
shipperizer 1c2b23c00f feat: wire up basic tracer 2023-12-10 09:59:04 +00:00
shipperizer d05630f66b feat: introduce context for otlp spans into handler pkg 2023-11-20 14:10:29 +00:00
shipperizer 0cf04037a2 feat: introduce otlp tracer 2023-11-20 14:10:29 +00:00
20 changed files with 704 additions and 205 deletions
+2 -2
View File
@@ -4,13 +4,13 @@ on:
pull_request:
push:
branches:
- dev
- master
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
go-version: [1.19.x, 1.20.x]
go-version: [1.19.x, 1.20.x, 1.21.x]
steps:
- name: Install Go
uses: actions/setup-go@v4
+1 -1
View File
@@ -2,7 +2,7 @@ name: "CodeQL"
on:
push:
branches: [ "master", "dev" ]
branches: [ "master" ]
pull_request:
branches: [ "master" ]
schedule:
+1 -1
View File
@@ -2,7 +2,7 @@ on:
pull_request:
push:
branches:
- dev
- master
permissions:
contents: write
+11 -1
View File
@@ -17,6 +17,7 @@ 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"
@@ -130,6 +131,14 @@ func startService() {
}
monitor := monitoring.NewMonitor(&log)
tracer := tracing.NewTracer(
tracing.NewConfig(
activeConfig.Tracing.Enabled,
activeConfig.Tracing.GRPCEndpoint,
activeConfig.Tracing.HTTPEndpoint,
&log,
),
)
startConfigWatcher()
@@ -147,8 +156,9 @@ func startService() {
s, err := server.NewServer(
server.Logger(log),
server.Config(activeConfig),
server.Monitor(monitor),
server.TLSConfig(tlsConfig),
server.Monitor(monitor),
server.Tracer(tracer),
)
if err != nil {
+27 -8
View File
@@ -7,7 +7,7 @@ require (
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.6.0
github.com/fsnotify/fsnotify v1.7.0
github.com/glauth/ldap v0.0.0-20231210225823-b9bf4d1baf6e
github.com/jinzhu/copier v0.4.0
github.com/pquerna/otp v1.4.0
@@ -15,30 +15,49 @@ require (
github.com/prometheus/client_model v0.5.0
github.com/rs/zerolog v1.31.0
github.com/smartystreets/goconvey v1.8.1
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3
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.3.0
golang.org/x/crypto v0.14.0
golang.org/x/crypto v0.16.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 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/cenkalti/backoff/v4 v4.2.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 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.20.5 // indirect
github.com/rickb777/plural v1.4.1 // indirect
github.com/prometheus/procfs v0.11.1 // indirect
github.com/rickb777/date v1.12.4 // indirect
github.com/rickb777/plural v1.2.0 // indirect
github.com/smarty/assertions v1.15.0 // indirect
golang.org/x/sys v0.13.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.15.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
google.golang.org/protobuf v1.31.0 // indirect
)
+59 -24
View File
@@ -7,9 +7,10 @@ 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/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
github.com/boombuler/barcode v1.0.1/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/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=
@@ -17,32 +18,38 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/glauth/ldap v0.0.0-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/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.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
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/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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
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=
@@ -50,7 +57,6 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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=
@@ -62,14 +68,12 @@ github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cY
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
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/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
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/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 h1:5tvEc7UBCZ7l8h/2UeybSkt/uu1DQsZFOFdNevmUhlE=
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/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
@@ -79,20 +83,43 @@ github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+
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/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/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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
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=
@@ -101,7 +128,8 @@ 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.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
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=
@@ -111,23 +139,30 @@ 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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
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/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.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
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/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=
+24
View File
@@ -0,0 +1,24 @@
package tracing
import (
"github.com/rs/zerolog"
)
type Config struct {
OtelHTTPEndpoint string
OtelGRPCEndpoint string
Logger *zerolog.Logger
Enabled bool
}
func NewConfig(enabled bool, otelGRPCEndpoint, otelHTTPEndpoint string, logger *zerolog.Logger) *Config {
c := new(Config)
c.OtelGRPCEndpoint = otelGRPCEndpoint
c.OtelHTTPEndpoint = otelHTTPEndpoint
c.Logger = logger
c.Enabled = enabled
return c
}
+134
View File
@@ -0,0 +1,134 @@
package tracing
import (
"context"
"runtime/debug"
"github.com/rs/zerolog"
"go.opentelemetry.io/contrib/propagators/jaeger"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/embedded"
"go.opentelemetry.io/otel/trace/noop"
)
type Tracer struct {
embedded.Tracer
tracer trace.Tracer
logger *zerolog.Logger
}
func (t *Tracer) init(service string, e sdktrace.SpanExporter) {
traceProvider := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(e),
sdktrace.WithResource(
t.buildResource(service),
),
)
otel.SetTracerProvider(traceProvider)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}, jaeger.Jaeger{}))
t.tracer = otel.Tracer(service)
}
func (t *Tracer) gitRevision(settings []debug.BuildSetting) string {
for _, setting := range settings {
if setting.Key == "vcs.revision" {
return setting.Value
}
}
return "n/a"
}
func (t *Tracer) buildResource(service string) *resource.Resource {
var res *resource.Resource
res = resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(service),
semconv.ServiceVersion("n/a"),
)
if info, ok := debug.ReadBuildInfo(); ok {
if service == "" {
service = info.Path
}
res = resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(service),
attribute.String("git_sha", t.gitRevision(info.Settings)),
attribute.String("app", info.Main.Path),
)
}
return res
}
func (t *Tracer) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
return t.tracer.Start(ctx, spanName, opts...)
}
// basic tracer implementation of trace.Tracer, just adding some extra configuration
func NewTracer(cfg *Config) *Tracer {
t := new(Tracer)
t.logger = cfg.Logger
// if tracing disabled skip the config
if !cfg.Enabled {
t.tracer = noop.NewTracerProvider().Tracer("github.com/glauth/glauth")
return t
}
var err error
var exporter sdktrace.SpanExporter
if cfg.OtelGRPCEndpoint != "" {
exporter, err = otlptrace.New(
context.TODO(),
otlptracegrpc.NewClient(
otlptracegrpc.WithEndpoint(cfg.OtelGRPCEndpoint),
otlptracegrpc.WithInsecure(),
),
)
} else if cfg.OtelHTTPEndpoint != "" {
exporter, err = otlptrace.New(
context.TODO(),
otlptracehttp.NewClient(
otlptracehttp.WithEndpoint(cfg.OtelHTTPEndpoint),
otlptracehttp.WithInsecure(),
),
)
} else {
exporter, err = stdouttrace.New(
stdouttrace.WithPrettyPrint(),
)
}
if err != nil {
t.logger.Error().Err(err).Msg("unable to initialize tracing exporter")
return nil
}
// set tracer provider and propagator properly, this is to ensure all
// instrumentation library could run well
t.init("github.com/glauth/glauth", exporter)
return t
}
+1 -1
View File
@@ -2,4 +2,4 @@ package version
// Version is the tag of the latest release, it gets changed by the ci
// process when a release is happening
const Version = "v2.3.0" // x-release-please-version
const Version = "v2.3.1" // x-release-please-version
+8
View File
@@ -104,6 +104,13 @@ type Group struct {
GIDNumber int
IncludeGroups []int
}
type Tracing struct {
Enabled bool
GRPCEndpoint string
HTTPEndpoint string
}
type Config struct {
API API
Backend Backend // Deprecated
@@ -121,6 +128,7 @@ type Config struct {
LDAPS LDAPS
Groups []Group
Users []User
Tracing Tracing
ConfigFile string
AwsAccessKeyId string
AwsSecretAccessKey string
+65 -21
View File
@@ -1,6 +1,7 @@
package handler
import (
"context"
"fmt"
"net"
"regexp"
@@ -9,6 +10,7 @@ import (
"time"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/GeertJohan/yubigo"
"github.com/glauth/glauth/v2/internal/monitoring"
@@ -26,6 +28,7 @@ type configHandler struct {
attmatcher *regexp.Regexp
monitor monitoring.MonitorInterface
tracer trace.Tracer
}
// NewConfigHandler creates a new config backed handler
@@ -40,6 +43,7 @@ func NewConfigHandler(opts ...Option) Handler {
ldohelper: options.LDAPHelper,
attmatcher: configattributematcher,
monitor: options.Monitor,
tracer: options.Tracer,
}
return handler
}
@@ -59,6 +63,9 @@ 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(
@@ -66,11 +73,14 @@ func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (result
time.Since(start).Seconds(),
)
}()
return h.ldohelper.Bind(h, bindDN, bindSimplePw, conn)
return h.ldohelper.Bind(ctx, 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(
@@ -78,11 +88,14 @@ func (h configHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn
time.Since(start).Seconds(),
)
}()
return h.ldohelper.Search(h, bindDN, searchReq, conn)
return h.ldohelper.Search(ctx, 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(
@@ -95,6 +108,9 @@ 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(
@@ -107,6 +123,9 @@ 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(
@@ -117,7 +136,9 @@ func (h configHandler) Delete(boundDN string, deleteDN string, conn net.Conn) (r
return ldap.LDAPResultInsufficientAccessRights, nil
}
func (h configHandler) FindUser(userName string, searchByUPN bool) (f bool, u config.User, err error) {
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()
user := config.User{}
found := false
@@ -138,7 +159,9 @@ func (h configHandler) FindUser(userName string, searchByUPN bool) (f bool, u co
return found, user, nil
}
func (h configHandler) FindGroup(groupName string) (f bool, g config.Group, err error) {
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()
// TODO Does g get erased, and above does u get erased?
// TODO and what about f?
group := config.Group{}
@@ -152,7 +175,10 @@ func (h configHandler) FindGroup(groupName string) (f bool, g config.Group, err
return found, group, nil
}
func (h configHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.Entry, err error) {
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()
entries := []*ldap.Entry{}
for _, u := range h.cfg.Users {
@@ -168,7 +194,7 @@ func (h configHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.En
attrs = append(attrs, &ldap.EntryAttribute{Name: "sn", Values: []string{u.SN}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(ctx, u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uidNumber", Values: []string{fmt.Sprintf("%d", u.UIDNumber)}})
if u.Disabled {
@@ -199,7 +225,7 @@ func (h configHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.En
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(append(u.OtherGroups, u.PrimaryGroup))})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: h.getGroupDNs(ctx, 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"}})
@@ -234,9 +260,9 @@ func (h configHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.En
}
var dn string
if hierarchy == "" {
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), h.backend.BaseDN)
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, 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(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(ctx, u.PrimaryGroup), hierarchy, h.backend.BaseDN)
}
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
}
@@ -244,7 +270,10 @@ func (h configHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.En
return entries, nil
}
func (h configHandler) FindPosixGroups(hierarchy string) (entrylist []*ldap.Entry, err error) {
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()
asGroupOfUniqueNames := hierarchy == "ou=groups"
entries := []*ldap.Entry{}
@@ -255,11 +284,11 @@ func (h configHandler) FindPosixGroups(hierarchy string) (entrylist []*ldap.Entr
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(g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(ctx, 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(g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(ctx, 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)
@@ -271,11 +300,17 @@ func (h configHandler) FindPosixGroups(hierarchy string) (entrylist []*ldap.Entr
// 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(gid int) []string {
func (h configHandler) getGroupMemberDNs(ctx context.Context, gid int) []string {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.getGroupMemberDNs")
defer span.End()
var insertOuUsers string
if h.cfg.Behaviors.LegacyVersion > 0 && h.cfg.Behaviors.LegacyVersion <= 20100 {
insertOuUsers = ""
@@ -285,12 +320,12 @@ func (h configHandler) getGroupMemberDNs(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(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(ctx, 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(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(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
members[dn] = true
}
}
@@ -301,7 +336,7 @@ func (h configHandler) getGroupMemberDNs(gid int) []string {
if gid == g.GIDNumber {
for _, includegroupid := range g.IncludeGroups {
if includegroupid != gid {
includegroupmembers := h.getGroupMemberDNs(includegroupid)
includegroupmembers := h.getGroupMemberDNs(ctx, includegroupid)
for _, includegroupmember := range includegroupmembers {
members[includegroupmember] = true
@@ -321,7 +356,10 @@ func (h configHandler) getGroupMemberDNs(gid int) []string {
return m
}
func (h configHandler) getGroupMemberIDs(gid int) []string {
func (h configHandler) getGroupMemberIDs(ctx context.Context, gid int) []string {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.getGroupMemberIDs")
defer span.End()
members := make(map[string]bool)
for _, u := range h.cfg.Users {
if u.PrimaryGroup == gid {
@@ -341,7 +379,7 @@ func (h configHandler) getGroupMemberIDs(gid int) []string {
if includegroupid == gid {
h.log.Warn().Int("groupid", includegroupid).Msg("Ignoring myself as included group")
} else {
includegroupmemberids := h.getGroupMemberIDs(includegroupid)
includegroupmemberids := h.getGroupMemberIDs(ctx, includegroupid)
for _, includegroupmemberid := range includegroupmemberids {
members[includegroupmemberid] = true
@@ -362,7 +400,10 @@ func (h configHandler) getGroupMemberIDs(gid int) []string {
}
// Converts an array of GUIDs into an array of DNs
func (h configHandler) getGroupDNs(gids []int) []string {
func (h configHandler) getGroupDNs(ctx context.Context, gids []int) []string {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.getGroupDNs")
defer span.End()
groups := make(map[string]bool)
for _, gid := range gids {
for _, g := range h.cfg.Groups {
@@ -373,7 +414,7 @@ func (h configHandler) getGroupDNs(gids []int) []string {
for _, includegroupid := range g.IncludeGroups {
if includegroupid == gid && g.GIDNumber != gid {
includegroupdns := h.getGroupDNs([]int{g.GIDNumber})
includegroupdns := h.getGroupDNs(ctx, []int{g.GIDNumber})
for _, includegroupdn := range includegroupdns {
groups[includegroupdn] = true
@@ -393,7 +434,10 @@ func (h configHandler) getGroupDNs(gids []int) []string {
return g
}
func (h configHandler) getGroupName(gid int) string {
func (h configHandler) getGroupName(ctx context.Context, gid int) string {
ctx, span := h.tracer.Start(ctx, "handler.configHandler.getGroupName")
defer span.End()
for _, g := range h.cfg.Groups {
if g.GIDNumber == gid {
return g.Name
+4 -2
View File
@@ -1,13 +1,15 @@
package handler
import (
"context"
"github.com/glauth/glauth/v2/pkg/config"
"github.com/glauth/ldap"
)
type HelperMaker interface {
FindUser(userName string, searchByUPN bool) (bool, config.User, error)
FindGroup(groupName string) (bool, config.Group, error)
FindUser(ctx context.Context, userName string, searchByUPN bool) (bool, config.User, error)
FindGroup(ctx context.Context, groupName string) (bool, config.Group, error)
}
// Handler is the common interface for all datastores
+33 -6
View File
@@ -1,6 +1,7 @@
package handler
import (
"context"
"crypto/sha256"
"crypto/tls"
"encoding/json"
@@ -15,6 +16,7 @@ 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"
@@ -38,6 +40,7 @@ type ldapHandler struct {
attm *regexp.Regexp
monitor monitoring.MonitorInterface
tracer trace.Tracer
}
// global lock for ldapHandler sessions & servers manipulation
@@ -76,6 +79,7 @@ func NewLdapHandler(opts ...Option) Handler {
lock: &ldaplock,
attm: ldapattributematcher,
monitor: options.Monitor,
tracer: options.Tracer,
}
// parse LDAP URLs
for _, ldapurl := range handler.backend.Servers {
@@ -94,6 +98,9 @@ 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(
@@ -120,7 +127,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(userName, false)
found, user, _ = handler.FindUser(ctx, userName, false)
if found {
break
}
@@ -167,6 +174,9 @@ 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(
@@ -254,7 +264,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(searchReq.Filter, []string{})
filters := h.buildReqAttributesList(ctx, searchReq.Filter, []string{})
for _, filter := range filters {
attbits := h.attm.FindStringSubmatch(filter)
@@ -293,7 +303,10 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
return ssr, nil
}
func (h ldapHandler) buildReqAttributesList(filter string, filters []string) []string {
func (h ldapHandler) buildReqAttributesList(ctx context.Context, filter string, filters []string) []string {
ctx, span := h.tracer.Start(ctx, "handler.ldapHandler.buildReqAttributesList")
defer span.End()
maxp := len(filter)
start := -1
descended := false
@@ -305,7 +318,7 @@ func (h ldapHandler) buildReqAttributesList(filter string, filters []string) []s
} else if c == ')' {
if start > -1 {
descended = true
filters = h.buildReqAttributesList(filter[start:p], filters)
filters = h.buildReqAttributesList(ctx, filter[start:p], filters)
}
start = -1
}
@@ -318,6 +331,9 @@ func (h ldapHandler) buildReqAttributesList(filter string, filters []string) []s
// 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(
@@ -330,6 +346,9 @@ 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(
@@ -342,6 +361,9 @@ 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(
@@ -352,11 +374,16 @@ func (h ldapHandler) Delete(boundDN string, deleteDN string, conn net.Conn) (res
return ldap.LDAPResultInsufficientAccessRights, nil
}
func (h ldapHandler) FindUser(userName string, searchByUPN bool) (found bool, user config.User, err error) {
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()
return false, config.User{}, nil
}
func (h ldapHandler) FindGroup(groupName string) (found bool, group config.Group, err error) {
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()
return false, config.Group{}, nil
}
+111 -62
View File
@@ -2,6 +2,7 @@ package handler
import (
"bufio"
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
@@ -13,6 +14,7 @@ import (
"time"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/GeertJohan/yubigo"
"github.com/glauth/glauth/v2/pkg/config"
@@ -31,10 +33,10 @@ type LDAPOpsHandler interface {
GetCfg() *config.Config
GetYubikeyAuth() *yubigo.YubiAuth
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)
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)
}
type failedBind struct {
@@ -50,18 +52,24 @@ type sourceInfo struct {
type LDAPOpsHelper struct {
sources map[string]*sourceInfo
nextPruning time.Time
tracer trace.Tracer
}
func NewLDAPOpsHelper() LDAPOpsHelper {
func NewLDAPOpsHelper(tracer trace.Tracer) LDAPOpsHelper {
helper := LDAPOpsHelper{
sources: make(map[string]*sourceInfo),
nextPruning: time.Now(),
tracer: tracer,
}
return helper
}
func (l LDAPOpsHelper) Bind(h LDAPOpsHandler, bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
if l.isInTimeout(h, conn) {
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) {
return ldap.LDAPResultUnwillingToPerform, nil
}
@@ -78,7 +86,7 @@ func (l LDAPOpsHelper) Bind(h LDAPOpsHandler, bindDN, bindSimplePw string, conn
return ldap.LDAPResultSuccess, nil
}
user, ldapcode := l.findUser(h, bindDN, true /* checkGroup */)
user, ldapcode := l.findUser(ctx, h, bindDN, true /* checkGroup */)
if ldapcode != ldap.LDAPResultSuccess {
return ldapcode, nil
}
@@ -176,7 +184,7 @@ func (l LDAPOpsHelper) Bind(h LDAPOpsHandler, bindDN, bindSimplePw string, conn
}
if bcrypt.CompareHashAndPassword(decoded, []byte(bindSimplePw)) != nil {
h.GetLog().Info().Str("binddn", bindDN).Str("src", conn.RemoteAddr().String()).Msg("invalid credentials")
l.maybePutInTimeout(h, conn, true)
l.maybePutInTimeout(ctx, h, conn, true)
return ldap.LDAPResultInvalidCredentials, nil
}
}
@@ -185,7 +193,7 @@ func (l LDAPOpsHelper) Bind(h LDAPOpsHandler, bindDN, bindSimplePw string, conn
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(h, conn, true)
l.maybePutInTimeout(ctx, h, conn, true)
return ldap.LDAPResultInvalidCredentials, nil
}
}
@@ -210,8 +218,11 @@ func (l LDAPOpsHelper) Bind(h LDAPOpsHandler, bindDN, bindSimplePw string, conn
* TODO #5:
* Document roll out of schemas
*/
func (l LDAPOpsHelper) Search(h LDAPOpsHandler, bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
if l.isInTimeout(h, conn) {
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) {
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultUnwillingToPerform}, fmt.Errorf("Source is in a timeout")
}
@@ -225,7 +236,7 @@ func (l LDAPOpsHelper) Search(h LDAPOpsHandler, bindDN string, searchReq ldap.Se
var ldapcode ldap.LDAPResultCode
if !anonymous {
if bindDN, boundUser, ldapcode = l.searchCheckBindDN(h, baseDN, bindDN, anonymous); ldapcode != ldap.LDAPResultSuccess {
if bindDN, boundUser, ldapcode = l.searchCheckBindDN(ctx, h, baseDN, bindDN, anonymous); ldapcode != ldap.LDAPResultSuccess {
return ldap.ServerSearchResult{ResultCode: ldapcode}, fmt.Errorf("Search Error: Potential bypass of BindDN %s", bindDN)
}
}
@@ -233,7 +244,7 @@ func (l LDAPOpsHelper) Search(h LDAPOpsHandler, bindDN string, searchReq ldap.Se
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(h, baseDN, searchBaseDN, searchReq, anonymous); ldapcode {
switch entries, ldapcode := l.searchMaybeRootDSEQuery(ctx, h, baseDN, searchBaseDN, searchReq, anonymous); ldapcode {
case ldap.LDAPResultUnwillingToPerform:
return ldap.ServerSearchResult{ResultCode: ldapcode}, fmt.Errorf("Search Error: No BaseDN provided")
case ldap.LDAPResultInsufficientAccessRights:
@@ -247,7 +258,7 @@ func (l LDAPOpsHelper) Search(h LDAPOpsHandler, bindDN string, searchReq ldap.Se
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: Anonymous BindDN not allowed %s", bindDN)
}
switch entries, ldapcode, attributename := l.searchMaybeSchemaQuery(h, baseDN, searchBaseDN, searchReq, anonymous); ldapcode {
switch entries, ldapcode, attributename := l.searchMaybeSchemaQuery(ctx, 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:
@@ -264,21 +275,21 @@ func (l LDAPOpsHelper) Search(h LDAPOpsHandler, bindDN string, searchReq ldap.Se
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(*boundUser, "search", []string{"*", searchBaseDN}) {
if !h.GetCfg().Behaviors.IgnoreCapabilities && !l.checkCapability(ctx, *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(h, baseDN, searchBaseDN, searchReq); ldapcode {
switch entries, ldapcode := l.searchMaybeTopLevelNodes(ctx, 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(h, baseDN, searchBaseDN, searchReq); ldapcode {
switch entries, ldapcode := l.searchMaybeTopLevelGroupsNode(ctx, 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(h, baseDN, searchBaseDN, searchReq); ldapcode {
switch entries, ldapcode := l.searchMaybeTopLevelUsersNode(ctx, h, baseDN, searchBaseDN, searchReq); ldapcode {
case ldap.LDAPResultSuccess:
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldapcode}, nil
}
@@ -288,12 +299,12 @@ func (l LDAPOpsHelper) Search(h LDAPOpsHandler, bindDN string, searchReq ldap.Se
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", searchReq.Filter)
}
switch entries, ldapcode := l.searchMaybePosixGroups(h, baseDN, searchBaseDN, searchReq, filterEntity); ldapcode {
switch entries, ldapcode := l.searchMaybePosixGroups(ctx, 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(h, baseDN, searchBaseDN, searchReq, filterEntity); ldapcode {
switch entries, ldapcode := l.searchMaybePosixAccounts(ctx, 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")
@@ -306,8 +317,11 @@ func (l LDAPOpsHelper) Search(h LDAPOpsHandler, bindDN string, searchReq ldap.Se
}
// Returns: LDAPResultSuccess or any ldap code returned by findUser
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 */)
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 */)
if ldapcode != ldap.LDAPResultSuccess {
return "", nil, ldapcode
}
@@ -323,7 +337,10 @@ func (l LDAPOpsHelper) searchCheckBindDN(h LDAPOpsHandler, baseDN string, bindDN
// Search RootDSE and return information on the server
// Returns: LDAPResultSuccess, LDAPResultOther, LDAPResultUnwillingToPerform, LDAPResultInsufficientAccessRights
func (l LDAPOpsHelper) searchMaybeRootDSEQuery(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, anonymous bool) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
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()
if searchBaseDN != "" {
return nil, ldap.LDAPResultOther // OK
}
@@ -349,7 +366,7 @@ func (l LDAPOpsHelper) searchMaybeRootDSEQuery(h LDAPOpsHandler, baseDN string,
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(attrs, searchReq)
attrs = l.collectRequestedAttributesBack(ctx, 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")
@@ -358,7 +375,10 @@ func (l LDAPOpsHelper) searchMaybeRootDSEQuery(h LDAPOpsHandler, baseDN string,
// Search and return the information, after indirection from the RootDSE
// Returns: LDAPResultSuccess, LDAPResultOther, LDAPResultOperationsError
func (l LDAPOpsHelper) searchMaybeSchemaQuery(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, anonymous bool) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode, attributename *string) {
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()
if searchBaseDN != "cn=schema" {
return nil, ldap.LDAPResultOther, nil // OK
}
@@ -388,7 +408,7 @@ func (l LDAPOpsHelper) searchMaybeSchemaQuery(h LDAPOpsHandler, baseDN string, s
}
attrs = append(attrs, &ldap.EntryAttribute{Name: filename.Name(), Values: values})
}
attrs = l.collectRequestedAttributesBack(attrs, searchReq)
attrs = l.collectRequestedAttributesBack(ctx, 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")
@@ -397,25 +417,28 @@ func (l LDAPOpsHelper) searchMaybeSchemaQuery(h LDAPOpsHandler, baseDN string, s
// Retrieve the top-levell nodes, i.e. the baseDN, groups, members...
// Returns: LDAPResultSuccess, LDAPResultOther
func (l LDAPOpsHelper) searchMaybeTopLevelNodes(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
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()
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(searchBaseDN))
entries = append(entries, l.topLevelRootNode(ctx, searchBaseDN))
}
entries = append(entries, l.topLevelGroupsNode(searchBaseDN, "groups"))
entries = append(entries, l.topLevelUsersNode(searchBaseDN))
entries = append(entries, l.topLevelGroupsNode(ctx, searchBaseDN, "groups"))
entries = append(entries, l.topLevelUsersNode(ctx, searchBaseDN))
if searchReq.Scope == ldap.ScopeWholeSubtree {
groupentries, err := h.FindPosixGroups("ou=users")
groupentries, err := h.FindPosixGroups(ctx, "ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
entries = append(entries, groupentries...)
userentries, err := h.FindPosixAccounts("ou=users")
userentries, err := h.FindPosixAccounts(ctx, "ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
@@ -428,17 +451,20 @@ func (l LDAPOpsHelper) searchMaybeTopLevelNodes(h LDAPOpsHandler, baseDN string,
// Search starting from and including the ou=groups node
// Returns: LDAPResultSuccess, LDAPResultOther
func (l LDAPOpsHelper) searchMaybeTopLevelGroupsNode(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
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()
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(searchBaseDN, "groups"))
entries = append(entries, l.topLevelGroupsNode(ctx, searchBaseDN, "groups"))
}
if searchReq.Scope == ldap.ScopeSingleLevel || searchReq.Scope == ldap.ScopeWholeSubtree {
groupentries, err := h.FindPosixGroups("ou=groups")
groupentries, err := h.FindPosixGroups(ctx, "ou=groups")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
@@ -451,24 +477,27 @@ func (l LDAPOpsHelper) searchMaybeTopLevelGroupsNode(h LDAPOpsHandler, baseDN st
// Search starting from and including the ou=users node
// Returns: LDAPResultSuccess, LDAPResultOther
func (l LDAPOpsHelper) searchMaybeTopLevelUsersNode(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
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()
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(searchBaseDN))
entries = append(entries, l.topLevelUsersNode(ctx, searchBaseDN))
}
if searchReq.Scope == ldap.ScopeSingleLevel || searchReq.Scope == ldap.ScopeWholeSubtree {
groupentries, err := h.FindPosixGroups("ou=users")
groupentries, err := h.FindPosixGroups(ctx, "ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
entries = append(entries, groupentries...)
}
if searchReq.Scope == ldap.ScopeWholeSubtree {
userentries, err := h.FindPosixAccounts("ou=users")
userentries, err := h.FindPosixAccounts(ctx, "ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
@@ -481,7 +510,10 @@ func (l LDAPOpsHelper) searchMaybeTopLevelUsersNode(h LDAPOpsHandler, baseDN str
// Look up posixgroup entries, either through objectlass or parent is ou=groups or ou=users
// Returns: LDAPResultSuccess, LDAPResultOther, LDAPResultOperationsError
func (l LDAPOpsHelper) searchMaybePosixGroups(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, filterEntity string) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
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()
hierarchy := "ou=groups"
if filterEntity != "posixgroup" {
bits := strings.Split(strings.Replace(searchBaseDN, baseDN, "", 1), ",")
@@ -493,19 +525,19 @@ func (l LDAPOpsHelper) searchMaybePosixGroups(h LDAPOpsHandler, baseDN string, s
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(hierarchy)
groupentries, err := h.FindPosixGroups(ctx, hierarchy)
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
entries = append(entries, l.preFilterEntries(searchBaseDN, groupentries)...)
entries = append(entries, l.preFilterEntries(ctx, searchBaseDN, groupentries)...)
}
if searchReq.Scope == ldap.ScopeSingleLevel || searchReq.Scope == ldap.ScopeWholeSubtree {
if hierarchy == "ou=users" {
userentries, err := h.FindPosixAccounts("ou=users")
userentries, err := h.FindPosixAccounts(ctx, "ou=users")
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
entries = append(entries, l.preFilterEntries(searchBaseDN, userentries)...)
entries = append(entries, l.preFilterEntries(ctx, searchBaseDN, userentries)...)
}
}
stats.Frontend.Add("search_successes", 1)
@@ -516,7 +548,10 @@ func (l LDAPOpsHelper) searchMaybePosixGroups(h LDAPOpsHandler, baseDN string, s
// Lookup posixaccount entries
// Returns: LDAPResultSuccess, LDAPResultOther, LDAPResultOperationsError
// This function ignores scopes... for now
func (l LDAPOpsHelper) searchMaybePosixAccounts(h LDAPOpsHandler, baseDN string, searchBaseDN string, searchReq ldap.SearchRequest, filterEntity string) (resultentries []*ldap.Entry, ldapresultcode ldap.LDAPResultCode) {
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()
switch filterEntity {
case "posixaccount", "shadowaccount", "":
h.GetLog().Info().Str("default case", filterEntity).Msg("Search request")
@@ -530,7 +565,7 @@ func (l LDAPOpsHelper) searchMaybePosixAccounts(h LDAPOpsHandler, baseDN string,
hierarchyString = "ou=users"
}
unscopedEntries, err := h.FindPosixAccounts(hierarchyString)
unscopedEntries, err := h.FindPosixAccounts(ctx, hierarchyString)
if err != nil {
return nil, ldap.LDAPResultOperationsError
}
@@ -548,7 +583,7 @@ func (l LDAPOpsHelper) searchMaybePosixAccounts(h LDAPOpsHandler, baseDN string,
return entries, ldap.LDAPResultSuccess
}
func (l LDAPOpsHelper) topLevelRootNode(searchBaseDN string) *ldap.Entry {
func (l LDAPOpsHelper) topLevelRootNode(ctx context.Context, searchBaseDN string) *ldap.Entry {
attrs := []*ldap.EntryAttribute{}
dnBits := strings.Split(searchBaseDN, ",")
for _, dnBit := range dnBits {
@@ -559,7 +594,7 @@ func (l LDAPOpsHelper) topLevelRootNode(searchBaseDN string) *ldap.Entry {
return &ldap.Entry{DN: searchBaseDN, Attributes: attrs}
}
func (l LDAPOpsHelper) topLevelGroupsNode(searchBaseDN string, hierarchy string) *ldap.Entry {
func (l LDAPOpsHelper) topLevelGroupsNode(ctx context.Context, 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"}})
@@ -571,7 +606,7 @@ func (l LDAPOpsHelper) topLevelGroupsNode(searchBaseDN string, hierarchy string)
return &ldap.Entry{DN: dn, Attributes: attrs}
}
func (l LDAPOpsHelper) topLevelUsersNode(searchBaseDN string) *ldap.Entry {
func (l LDAPOpsHelper) topLevelUsersNode(ctx context.Context, 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"}})
@@ -586,7 +621,7 @@ func (l LDAPOpsHelper) topLevelUsersNode(searchBaseDN string) *ldap.Entry {
// 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(searchBaseDN string, entries []*ldap.Entry) (resultentries []*ldap.Entry) {
func (l LDAPOpsHelper) preFilterEntries(ctx context.Context, searchBaseDN string, entries []*ldap.Entry) (resultentries []*ldap.Entry) {
filteredEntries := []*ldap.Entry{}
for _, entry := range entries {
if strings.HasSuffix(entry.DN, searchBaseDN) {
@@ -596,7 +631,9 @@ func (l LDAPOpsHelper) preFilterEntries(searchBaseDN string, entries []*ldap.Ent
return filteredEntries
}
func (l LDAPOpsHelper) findUser(h LDAPOpsHandler, bindDN string, checkGroup bool) (userWhenFound *config.User, resultCode ldap.LDAPResultCode) {
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()
var user config.User
@@ -606,7 +643,7 @@ func (l LDAPOpsHelper) findUser(h LDAPOpsHandler, bindDN string, checkGroup bool
// Not using mail.ParseAddress/1 because we would allow incorrectly formatted UPNs
if emailmatcher.MatchString(bindDN) {
var foundUser bool // = false
foundUser, user, _ = h.FindUser(bindDN, true)
foundUser, user, _ = h.FindUser(ctx, bindDN, true)
if !foundUser {
h.GetLog().Info().Str("userprincipalname", bindDN).Msg("User not found")
return nil, ldap.LDAPResultInvalidCredentials
@@ -636,7 +673,7 @@ func (l LDAPOpsHelper) findUser(h LDAPOpsHandler, bindDN string, checkGroup bool
// find the user
var foundUser bool // = false
foundUser, user, _ = h.FindUser(userName, false)
foundUser, user, _ = h.FindUser(ctx, userName, false)
if !foundUser {
h.GetLog().Info().Str("username", userName).Msg("User not found")
return nil, ldap.LDAPResultInvalidCredentials
@@ -646,7 +683,7 @@ func (l LDAPOpsHelper) findUser(h LDAPOpsHandler, bindDN string, checkGroup bool
var group config.Group // = nil
var foundGroup bool // = false
if groupName != "" {
foundGroup, group, _ = h.FindGroup(groupName)
foundGroup, group, _ = h.FindGroup(ctx, groupName)
if !foundGroup {
h.GetLog().Info().Str("groupname", groupName).Msg("Group not found")
return nil, ldap.LDAPResultInvalidCredentials
@@ -664,7 +701,7 @@ func (l LDAPOpsHelper) findUser(h LDAPOpsHandler, bindDN string, checkGroup bool
return &user, ldap.LDAPResultSuccess
}
func (l LDAPOpsHelper) checkCapability(user config.User, action string, objects []string) bool {
func (l LDAPOpsHelper) checkCapability(ctx context.Context, user config.User, action string, objects []string) bool {
for _, capability := range user.Capabilities {
if capability.Action == action {
for _, object := range objects {
@@ -680,7 +717,10 @@ func (l LDAPOpsHelper) checkCapability(user config.User, action string, objects
// 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(attrs []*ldap.EntryAttribute, searchReq ldap.SearchRequest) []*ldap.EntryAttribute {
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()
attbits := configattributematcher.FindStringSubmatch(searchReq.Filter)
if len(attbits) == 3 {
foundattname := false
@@ -699,13 +739,16 @@ func (l LDAPOpsHelper) collectRequestedAttributesBack(attrs []*ldap.EntryAttribu
}
// return true if we should not process the current operation
func (l LDAPOpsHelper) isInTimeout(handler LDAPOpsHandler, conn net.Conn) bool {
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()
cfg := handler.GetCfg()
if !cfg.Behaviors.LimitFailedBinds {
return false
}
remoteAddr := l.getAddr(conn)
remoteAddr := l.getAddr(ctx, conn)
now := time.Now()
info, ok := l.sources[remoteAddr]
if !ok {
@@ -725,13 +768,16 @@ func (l LDAPOpsHelper) isInTimeout(handler LDAPOpsHandler, conn net.Conn) bool {
return false
}
func (l LDAPOpsHelper) maybePutInTimeout(handler LDAPOpsHandler, conn net.Conn, noteFailure bool) bool {
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()
cfg := handler.GetCfg()
if !cfg.Behaviors.LimitFailedBinds {
return false
}
remoteAddr := l.getAddr(conn)
remoteAddr := l.getAddr(ctx, conn)
now := time.Now()
info, _ := l.sources[remoteAddr]
// if we have a failed bind...
@@ -765,7 +811,10 @@ func (l LDAPOpsHelper) maybePutInTimeout(handler LDAPOpsHandler, conn net.Conn,
return false
}
func (l LDAPOpsHelper) getAddr(conn net.Conn) string {
func (l LDAPOpsHelper) getAddr(ctx context.Context, conn net.Conn) string {
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.getAddr")
defer span.End()
fullAddr := conn.RemoteAddr().String()
sep := strings.LastIndex(fullAddr, ":")
if sep == -1 {
+9
View File
@@ -4,6 +4,7 @@ import (
"context"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/GeertJohan/yubigo"
"github.com/glauth/glauth/v2/internal/monitoring"
@@ -24,6 +25,7 @@ type Options struct {
Helper Handler
LDAPHelper LDAPOpsHelper
Monitor monitoring.MonitorInterface
Tracer trace.Tracer
}
// newOptions initializes the available default options.
@@ -110,3 +112,10 @@ 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
}
}
+36 -24
View File
@@ -14,6 +14,7 @@ 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"
@@ -38,11 +39,35 @@ 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() {
@@ -219,6 +244,9 @@ 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(
@@ -230,11 +258,17 @@ 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(userName string, searchByUPN bool) (found bool, user config.User, err error) {
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()
return false, config.User{}, nil
}
func (h ownCloudHandler) FindGroup(groupName string) (found bool, group config.Group, err error) {
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()
return false, config.Group{}, nil
}
@@ -394,25 +428,3 @@ 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,
}
}
+144 -46
View File
@@ -1,6 +1,7 @@
package plugins
import (
"context"
"database/sql"
"encoding/json"
"errors"
@@ -13,6 +14,10 @@ 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"
@@ -49,13 +54,21 @@ 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 := sql.Open(sqlBackend.GetDriverName(), options.Backend.Database)
db, err := otelsql.Open(
sqlBackend.GetDriverName(),
options.Backend.Database,
otelsql.WithAttributes(otlpDriverAttribute(sqlBackend)),
otelsql.WithDBName(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)
@@ -79,7 +92,9 @@ func NewDatabaseHandler(sqlBackend SqlBackend, opts ...handler.Option) handler.H
sqlBackend: sqlBackend,
database: dbInfo,
ldohelper: options.LDAPHelper,
attmatcher: configattributematcher}
attmatcher: configattributematcher,
tracer: options.Tracer,
}
sqlBackend.CreateSchema(db)
sqlBackend.MigrateSchema(db, ColumnExists)
@@ -91,11 +106,24 @@ func NewDatabaseHandler(sqlBackend SqlBackend, opts ...handler.Option) handler.H
func ColumnExists(db *sql.DB, tableName string, columnName string) bool {
var found string
err := db.QueryRow(fmt.Sprintf(`SELECT COUNT(%s) FROM %s`, columnName, tableName)).Scan(
err := db.QueryRowContext(context.Background(), 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
}
@@ -110,29 +138,47 @@ func (h databaseHandler) GetYubikeyAuth() *yubigo.YubiAuth {
}
func (h databaseHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
return h.ldohelper.Bind(h, bindDN, bindSimplePw, conn)
ctx, span := h.tracer.Start(context.Background(), "plugins.databaseHandler.Bind")
defer span.End()
return h.ldohelper.Bind(ctx, h, bindDN, bindSimplePw, conn)
}
func (h databaseHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
return h.ldohelper.Search(h, bindDN, searchReq, conn)
ctx, span := h.tracer.Start(context.Background(), "plugins.databaseHandler.Search")
defer span.End()
return h.ldohelper.Search(ctx, 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(userName string, searchByUPN bool) (f bool, u config.User, err error) {
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()
var criterion string
if searchByUPN {
criterion = "lower(u.mail)"
@@ -144,11 +190,14 @@ func (h databaseHandler) FindUser(userName string, searchByUPN bool) (f bool, u
found := false
var disabled int
err = h.database.cnx.QueryRow(fmt.Sprintf(`
err = h.database.cnx.QueryRowContext(
ctx,
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)
@@ -157,7 +206,7 @@ func (h databaseHandler) FindUser(userName string, searchByUPN bool) (f bool, u
if !h.cfg.Behaviors.IgnoreCapabilities {
capability := config.Capability{}
rows, err := h.database.cnx.Query(fmt.Sprintf(`
rows, err := h.database.cnx.QueryContext(ctx, fmt.Sprintf(`
SELECT c.action,c.object
FROM capabilities c WHERE userid=%s`,
h.sqlBackend.GetPrepareSymbol()), user.UIDNumber)
@@ -177,11 +226,16 @@ func (h databaseHandler) FindUser(userName string, searchByUPN bool) (f bool, u
return found, user, err
}
func (h databaseHandler) FindGroup(groupName string) (f bool, g config.Group, err error) {
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()
group := config.Group{}
found := false
err = h.database.cnx.QueryRow(fmt.Sprintf(`
err = h.database.cnx.QueryRowContext(
ctx,
fmt.Sprintf(`
SELECT g.gidnumber FROM ldapgroups g WHERE lower(name)=%s`, h.sqlBackend.GetPrepareSymbol()), groupName).Scan(
&group.GIDNumber)
if err == nil {
@@ -191,15 +245,20 @@ func (h databaseHandler) FindGroup(groupName string) (f bool, g config.Group, er
return found, group, err
}
func (h databaseHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.Entry, err error) {
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()
entries := []*ldap.Entry{}
h.MemGroups, err = h.memoizeGroups()
h.MemGroups, err = h.memoizeGroups(ctx)
if err != nil {
return entries, err
}
rows, err := h.database.cnx.Query(`
rows, err := h.database.cnx.QueryContext(
ctx,
`
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 {
@@ -217,11 +276,11 @@ func (h databaseHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.
if err != nil {
return entries, err
}
u.OtherGroups = h.commaListToIntTable(otherGroups)
u.OtherGroups = h.commaListToIntTable(ctx, otherGroups)
u.Disabled = h.intToBool(disabled)
u.SSHKeys = h.commaListToStringTable(sshKeys)
u.SSHKeys = h.commaListToStringTable(ctx, sshKeys)
entry := h.getAccount(hierarchy, u)
entry := h.getAccount(ctx, hierarchy, u)
if custattrstr != "{}" {
var r map[string]interface{}
@@ -254,16 +313,19 @@ func (h databaseHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.
return entries, nil
}
func (h databaseHandler) FindPosixGroups(hierarchy string) (entrylist []*ldap.Entry, err error) {
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()
entries := []*ldap.Entry{}
h.MemGroups, err = h.memoizeGroups()
h.MemGroups, err = h.memoizeGroups(ctx)
if err != nil {
return entries, err
}
for _, g := range h.MemGroups {
info := h.getGroup(hierarchy, g)
info := h.getGroup(ctx, hierarchy, g)
if hierarchy != "groups" {
info.DN = strings.Replace(info.DN, ",ou=groups,", fmt.Sprintf(",%s,", hierarchy), 1)
}
@@ -274,6 +336,9 @@ func (h databaseHandler) FindPosixGroups(hierarchy string) (entrylist []*ldap.En
}
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
}
@@ -285,7 +350,10 @@ func (h databaseHandler) intToBool(value int) bool {
return true
}
func (h databaseHandler) commaListToIntTable(commaList string) []int {
func (h databaseHandler) commaListToIntTable(ctx context.Context, commaList string) []int {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.commaListToIntTable")
defer span.End()
if len(commaList) == 0 {
return make([]int, 0)
}
@@ -301,16 +369,24 @@ func (h databaseHandler) commaListToIntTable(commaList string) []int {
return rowsAsInts
}
func (h databaseHandler) commaListToStringTable(commaList string) []string {
func (h databaseHandler) commaListToStringTable(ctx context.Context, commaList string) []string {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.commaListToStringTable")
defer span.End()
if len(commaList) == 0 {
return make([]string, 0)
}
return strings.Split(commaList, ",")
}
func (h databaseHandler) memoizeGroups() ([]config.Group, error) {
func (h databaseHandler) memoizeGroups(ctx context.Context) ([]config.Group, error) {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.memoizeGroups")
defer span.End()
workMemGroups := make([]*config.Group, 0)
rows, err := h.database.cnx.Query(`
rows, err := h.database.cnx.QueryContext(
ctx,
`
SELECT g1.name,g1.gidnumber,ig.includegroupid
FROM ldapgroups g1
LEFT JOIN includegroups ig ON g1.gidnumber=ig.parentgroupid
@@ -347,7 +423,10 @@ func (h databaseHandler) memoizeGroups() ([]config.Group, error) {
return memGroups, nil
}
func (h databaseHandler) getGroupMemberDNs(gid int) []string {
func (h databaseHandler) getGroupMemberDNs(ctx context.Context, gid int) []string {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.getGroupMemberDNs")
defer span.End()
var insertOuUsers string
if h.cfg.Behaviors.LegacyVersion > 0 && h.cfg.Behaviors.LegacyVersion <= 20100 {
insertOuUsers = ""
@@ -356,7 +435,9 @@ func (h databaseHandler) getGroupMemberDNs(gid int) []string {
}
members := make(map[string]bool)
rows, err := h.database.cnx.Query(`
rows, err := h.database.cnx.QueryContext(
ctx,
`
SELECT u.name,u.uidnumber,u.primarygroup,u.passbcrypt,u.passsha256,u.otpsecret,u.yubikey,u.othergroups
FROM users u`)
if err != nil {
@@ -373,13 +454,13 @@ func (h databaseHandler) getGroupMemberDNs(gid int) []string {
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(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(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
members[dn] = true
} else {
u.OtherGroups = h.commaListToIntTable(otherGroups)
u.OtherGroups = h.commaListToIntTable(ctx, 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(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(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
members[dn] = true
}
}
@@ -390,7 +471,7 @@ func (h databaseHandler) getGroupMemberDNs(gid int) []string {
if gid == g.GIDNumber {
for _, includegroupid := range g.IncludeGroups {
if includegroupid != gid {
includegroupmembers := h.getGroupMemberDNs(includegroupid)
includegroupmembers := h.getGroupMemberDNs(ctx, includegroupid)
for _, includegroupmember := range includegroupmembers {
members[includegroupmember] = true
@@ -411,9 +492,14 @@ func (h databaseHandler) getGroupMemberDNs(gid int) []string {
}
// Used exclusively when looking up Posix Groups
func (h databaseHandler) getGroupMemberIDs(gid int) []string {
func (h databaseHandler) getGroupMemberIDs(ctx context.Context, gid int) []string {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.getGroupMemberIDs")
defer span.End()
members := make(map[string]bool)
rows, err := h.database.cnx.Query(`
rows, err := h.database.cnx.QueryContext(
ctx,
`
SELECT u.name,u.uidnumber,u.primarygroup,u.passbcrypt,u.passsha256,u.otpsecret,u.yubikey,u.othergroups
FROM users u`)
if err != nil {
@@ -432,7 +518,7 @@ func (h databaseHandler) getGroupMemberIDs(gid int) []string {
if u.PrimaryGroup == gid {
members[u.Name] = true
} else {
u.OtherGroups = h.commaListToIntTable(otherGroups)
u.OtherGroups = h.commaListToIntTable(ctx, otherGroups)
for _, othergid := range u.OtherGroups {
if othergid == gid {
members[u.Name] = true
@@ -447,7 +533,7 @@ func (h databaseHandler) getGroupMemberIDs(gid int) []string {
if includegroupid == gid {
h.log.Warn().Msg(fmt.Sprintf("Group: %d - Ignoring myself as included group", includegroupid))
} else {
includegroupmemberids := h.getGroupMemberIDs(includegroupid)
includegroupmemberids := h.getGroupMemberIDs(ctx, includegroupid)
for _, includegroupmemberid := range includegroupmemberids {
members[includegroupmemberid] = true
@@ -468,7 +554,10 @@ func (h databaseHandler) getGroupMemberIDs(gid int) []string {
}
// Invoked for every user being returned from our database
func (h databaseHandler) getGroupDNs(gids []int) []string {
func (h databaseHandler) getGroupDNs(ctx context.Context, gids []int) []string {
ctx, span := h.tracer.Start(ctx, "plugins.databaseHandler.getGroupDNs")
defer span.End()
groups := make(map[string]bool)
for _, gid := range gids {
for _, g := range h.MemGroups {
@@ -479,7 +568,7 @@ func (h databaseHandler) getGroupDNs(gids []int) []string {
for _, includegroupid := range g.IncludeGroups {
if includegroupid == gid && g.GIDNumber != gid {
includegroupdns := h.getGroupDNs([]int{g.GIDNumber})
includegroupdns := h.getGroupDNs(ctx, []int{g.GIDNumber})
for _, includegroupdn := range includegroupdns {
groups[includegroupdn] = true
@@ -500,7 +589,10 @@ func (h databaseHandler) getGroupDNs(gids []int) []string {
}
// Invoked for every user being returned from our database
func (h databaseHandler) getGroupName(gid int) string {
func (h databaseHandler) getGroupName(ctx context.Context, gid int) string {
_, span := h.tracer.Start(ctx, "plugins.databaseHandler.getGroupName")
defer span.End()
for _, g := range h.MemGroups {
if g.GIDNumber == gid {
return g.Name
@@ -510,25 +602,31 @@ func (h databaseHandler) getGroupName(gid int) string {
}
// Toolbox
func (h databaseHandler) getGroup(hierarchy string, g config.Group) *ldap.Entry {
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()
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(g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(ctx, 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(g.GIDNumber)})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(ctx, 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(hierarchy string, u config.User) *ldap.Entry {
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()
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}})
@@ -541,7 +639,7 @@ func (h databaseHandler) getAccount(hierarchy string, u config.User) *ldap.Entry
attrs = append(attrs, &ldap.EntryAttribute{Name: "sn", Values: []string{u.SN}})
}
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "ou", Values: []string{h.getGroupName(ctx, u.PrimaryGroup)}})
attrs = append(attrs, &ldap.EntryAttribute{Name: "uidNumber", Values: []string{fmt.Sprintf("%d", u.UIDNumber)}})
if u.Disabled {
@@ -572,15 +670,15 @@ func (h databaseHandler) getAccount(hierarchy string, u config.User) *ldap.Entry
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(append(u.OtherGroups, u.PrimaryGroup))})
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberOf", Values: h.getGroupDNs(ctx, 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(u.PrimaryGroup), h.backend.BaseDN)
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, 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(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(ctx, u.PrimaryGroup), hierarchy, h.backend.BaseDN)
}
return &ldap.Entry{DN: dn, Attributes: attrs}
}
+14 -5
View File
@@ -5,6 +5,7 @@ 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"
@@ -15,11 +16,12 @@ type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger zerolog.Logger
Config *config.Config
Monitor monitoring.MonitorInterface
TLSConfig *tls.Config
Context context.Context
Logger zerolog.Logger
Config *config.Config
TLSConfig *tls.Config
Monitor monitoring.MonitorInterface
Tracer trace.Tracer
Context context.Context
}
// newOptions initializes the available default options.
@@ -67,3 +69,10 @@ 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
}
}
+10 -1
View File
@@ -6,6 +6,7 @@ import (
"plugin"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/trace"
"github.com/GeertJohan/yubigo"
"github.com/glauth/glauth/v2/internal/monitoring"
@@ -20,6 +21,7 @@ type LdapSvc struct {
l *ldap.Server
monitor monitoring.MonitorInterface
tracer trace.Tracer
log zerolog.Logger
}
@@ -30,6 +32,7 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
log: options.Logger,
c: options.Config,
monitor: options.Monitor,
tracer: options.Tracer,
}
var err error
@@ -44,7 +47,7 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
var helper handler.Handler
loh := handler.NewLDAPOpsHelper()
loh := handler.NewLDAPOpsHelper(s.tracer)
// instantiate the helper, if any
if s.c.Helper.Enabled {
@@ -55,6 +58,7 @@ 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)
@@ -77,6 +81,7 @@ 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)
@@ -106,12 +111,14 @@ 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(
@@ -121,6 +128,7 @@ 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)
@@ -145,6 +153,7 @@ 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)
+10
View File
@@ -34,6 +34,16 @@ 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"