diff --git a/go.mod b/go.mod index 93f24d403..54ca4a1fc 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,11 @@ require ( github.com/alicebob/miniredis/v2 v2.35.0 github.com/dgraph-io/dgo/v210 v210.0.0-20230328113526-b66f8ae53a2d github.com/eclipse/paho.mqtt.golang v1.5.0 + github.com/go-ldap/ldap/v3 v3.4.11 github.com/go-redis/redismock/v9 v9.2.0 github.com/go-sql-driver/mysql v1.9.3 github.com/gogo/protobuf v1.3.2 + github.com/golang-jwt/jwt/v4 v4.5.2 github.com/golang-jwt/jwt/v5 v5.3.0 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 @@ -53,6 +55,7 @@ require ( cloud.google.com/go/compute/metadata v0.7.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -60,6 +63,7 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect diff --git a/go.sum b/go.sum index 121f53752..a9c99f48d 100644 --- a/go.sum +++ b/go.sum @@ -17,11 +17,15 @@ cloud.google.com/go/pubsub v1.49.0 h1:5054IkbslnrMCgA2MAEPcsN3Ky+AyMpEZcii/DoySP cloud.google.com/go/pubsub v1.49.0/go.mod h1:K1FswTWP+C1tI/nfi3HQecoVeFvL4HUOB1tdaNXKhUY= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/XSAM/otelsql v0.39.0 h1:4o374mEIMweaeevL7fd8Q3C710Xi2Jh/c8G4Qy9bvCY= github.com/XSAM/otelsql v0.39.0/go.mod h1:uMOXLUX+wkuAuP0AR3B45NXX7E9lJS2mERa8gqdU8R0= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -57,7 +61,11 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU= +github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= @@ -71,6 +79,8 @@ github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI6 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -119,6 +129,20 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDa github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= diff --git a/go.work.sum b/go.work.sum index b18de40ab..9cd2de359 100644 --- a/go.work.sum +++ b/go.work.sum @@ -32,6 +32,8 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= cloud.google.com/go v0.118.3/go.mod h1:Lhs3YLnBlwJ4KA6nuObNMZ/fCbOQBPuWKPoE0Wa/9Vc= +cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= +cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= cloud.google.com/go/accessapproval v1.8.2/go.mod h1:aEJvHZtpjqstffVwF/2mCXXSQmpskyzvw6zKLvLutZM= cloud.google.com/go/accessapproval v1.8.3 h1:axlU03FRiXDNupsmPG7LKzuS4Enk1gf598M62lWVB74= cloud.google.com/go/accessapproval v1.8.3/go.mod h1:3speETyAv63TDrDmo5lIkpVueFkQcQchkiw/TAMbBo4= @@ -108,6 +110,8 @@ cloud.google.com/go/auth v0.12.1/go.mod h1:BFMu+TNpF3DmvfBO9ClqTR/SiqVIm7LukKF9m cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8= +cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/automl v1.14.2/go.mod h1:mIat+Mf77W30eWQ/vrhjXsXaRh8Qfu4WiymR0hR6Uxk= cloud.google.com/go/automl v1.14.4 h1:vkD+hQ75SMINMgJBT/KDpFYvfQLzJbtIQZdw0AWq8Rs= @@ -388,6 +392,7 @@ cloud.google.com/go/gkemulticloud v1.5.3 h1:334aZmOzIt3LVBpguCof8IHaLaftcZlx+L0T cloud.google.com/go/gkemulticloud v1.5.3/go.mod h1:KPFf+/RcfvmuScqwS9/2MF5exZAmXSuoSLPuaQ98Xlk= cloud.google.com/go/grafeas v0.3.11 h1:CobnwnyeY1j1Defi5vbEircI+jfrk3ci5m004ZjiFP4= cloud.google.com/go/grafeas v0.3.11/go.mod h1:dcQyG2+T4tBgG0MvJAh7g2wl/xHV2w+RZIqivwuLjNg= +cloud.google.com/go/grafeas v0.3.15/go.mod h1:irwcwIQOBlLBotGdMwme8PipnloOPqILfIvMwlmu8Pk= cloud.google.com/go/gsuiteaddons v1.7.2/go.mod h1:GD32J2rN/4APilqZw4JKmwV84+jowYYMkEVwQEYuAWc= cloud.google.com/go/gsuiteaddons v1.7.3 h1:QafYhVhyFGpidBUUlVhy6lUHFogFOycVYm9DV7MinhA= cloud.google.com/go/gsuiteaddons v1.7.3/go.mod h1:0rR+LC21v1Sx1Yb6uohHI/F8DF3h2arSJSHvfi3GmyQ= @@ -429,6 +434,7 @@ cloud.google.com/go/logging v1.12.0/go.mod h1:wwYBt5HlYP1InnrtYI0wtwttpVU1rifnMT cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= +cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw= cloud.google.com/go/managedidentities v1.7.2/go.mod h1:t0WKYzagOoD3FNtJWSWcU8zpWZz2i9cw2sKa9RiPx5I= cloud.google.com/go/managedidentities v1.7.3 h1:b9xGs24BIjfyvLgCtJoClOZpPi8d8owPgWe5JEINgaY= cloud.google.com/go/managedidentities v1.7.3/go.mod h1:H9hO2aMkjlpY+CNnKWRh+WoQiUIDO8457wWzUGsdtLA= @@ -651,6 +657,7 @@ cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyX cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs= cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY= +cloud.google.com/go/storage v1.53.0/go.mod h1:7/eO2a/srr9ImZW9k5uufcNahT2+fPb8w5it1i5boaA= cloud.google.com/go/storagetransfer v1.11.2/go.mod h1:FcM29aY4EyZ3yVPmW5SxhqUdhjgPBUOFyy4rqiQbias= cloud.google.com/go/storagetransfer v1.12.1 h1:W3v9A7MGBN7H9sAFstyciwP/1XEQhUhZfrjclmDnpMs= cloud.google.com/go/storagetransfer v1.12.1/go.mod h1:hQqbfs8/LTmObJyCC0KrlBw8yBJ2bSFlaGila0qBMk4= @@ -772,14 +779,17 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49 github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0/go.mod h1:6fTWu4m3jocfUZLYF5KsZC1TUfRvEjs7lM4crme/irw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0 h1:5IT7xOdq17MtcdtL/vtl6mGfzhaq4m4vpollPRmlsBQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0/go.mod h1:ZV4VOm0/eHR06JLrXWe09068dHpr3TRpY9Uo7T+anuA= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0 h1:jJKWl98inONJAr/IZrdFQUWcwUO95DLY1XMD1ZIut+g= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.49.0/go.mod h1:l2fIqmwB+FKSfvn3bAD/0i+AXAxhIZjTK2svT/mgUXs= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.50.0 h1:nNMpRpnkWDAaqcpxMJvxa/Ud98gjbYwayJY4/9bdjiU= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.50.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 h1:GYUJLfvd++4DMuMhCFLgLXvFwofIxh/qOwoGuS/LTew= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0/go.mod h1:wRbFgBQUVm1YXrvWKofAEmq9HNJTDphbAaJSSX01KUI= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0 h1:ig/FpDD2JofP/NExKQUbn7uOSZzJAQqogfqluZK4ed4= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= github.com/IBM/sarama v1.43.1 h1:Z5uz65Px7f4DhI/jQqEm/tV9t8aU+JUdTyW/K/fCXpA= github.com/IBM/sarama v1.43.1/go.mod h1:GG5q1RURtDNPz8xxJs3mgX6Ytak8Z9eLhAkJPObe2xE= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= @@ -869,6 +879,7 @@ github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswgg github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw= github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.3.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -1001,10 +1012,9 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= @@ -1027,16 +1037,6 @@ github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= -github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= -github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= -github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= -github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= -github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= -github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= -github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= -github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -1201,10 +1201,12 @@ go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8F go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0/go.mod h1:3qi2EEwMgB4xnKgPLqsDP3j9qxnHDZeHsnAxfjQqTko= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= @@ -1218,6 +1220,7 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMey go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY= go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= @@ -1231,7 +1234,9 @@ go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxt go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= @@ -1253,8 +1258,9 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1349,6 +1355,7 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1399,11 +1406,13 @@ golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1480,6 +1489,9 @@ google.golang.org/api v0.219.0/go.mod h1:K6OmjGm+NtLrIkHxv1U3a0qIf/0JOvAHd5O/6Ao google.golang.org/api v0.222.0/go.mod h1:efZia3nXpWELrwMlN5vyQrD4GmJN1Vw0x68Et3r+a9c= google.golang.org/api v0.224.0/go.mod h1:3V39my2xAGkodXy0vEqcEtkqgw2GtrFL5WuBZlCTCOQ= google.golang.org/api v0.227.0/go.mod h1:EIpaG6MbTgQarWF5xJvX0eOJPK9n/5D4Bynb9j2HXvQ= +google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0= +google.golang.org/api v0.232.0/go.mod h1:p9QCfBWZk1IJETUdbTKloR5ToFdKbYh2fkjsUL6vNoY= +google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= @@ -1522,6 +1534,7 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY= google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= +google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= @@ -1536,7 +1549,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go. google.golang.org/genproto/googleapis/api v0.0.0-20250219182151-9fdb1cabc7b2/go.mod h1:W9ynFDP/shebLB1Hl/ESTOap2jHd6pmLXPNZC7SVDbA= google.golang.org/genproto/googleapis/api v0.0.0-20250227231956-55c901821b1e/go.mod h1:Xsh8gBVxGCcbV8ZeTB9wI5XPyZ5RvC6V3CTeeplHbiA= google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= -google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8= +google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A= +google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ= google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250106144421-5f5ef82da422 h1:w6g+P/ZscmNlGxVVXGaPVQOLu1q19ubsTOZKwaDqm4k= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250106144421-5f5ef82da422/go.mod h1:s4mHJ3FfG8P6A3O+gZ8TVqB3ufjOl9UG3ANCMMwCHmo= @@ -1554,6 +1568,7 @@ google.golang.org/genproto/googleapis/bytestream v0.0.0-20250512202823-5a2f75b73 google.golang.org/genproto/googleapis/bytestream v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822 h1:zWFRixYR5QlotL+Uv3YfsPRENIrQFXiGs+iwqel6fOQ= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20250715232539-7130f93afb79/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250728155136-f173205681a0 h1:HyHZz/b6hYFm/aS2F0DOAyjK5mQw0Jh8YiZyqlXMfic= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250728155136-f173205681a0/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y= google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= @@ -1574,6 +1589,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1594,6 +1611,7 @@ google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe0 google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= diff --git a/internal/auth/jwt/jwt.go b/internal/auth/jwt/jwt.go new file mode 100644 index 000000000..c287471a0 --- /dev/null +++ b/internal/auth/jwt/jwt.go @@ -0,0 +1,123 @@ +package jwt + +import ( + // Standard library. + "errors" + "fmt" + "log" + "time" + + // Third-party. + "github.com/golang-jwt/jwt/v4" +) + +var ( + ErrTokenSigningEmptyKey = errors.New("token signing error: no secret configured") + ErrUnexpectedSigningMethod = errors.New("unexpected signing method") + ErrInvalidToken = errors.New("invalid token") + ErrInvalidClaims = errors.New("invalid claims") + ErrMissingSubClaim = errors.New("missing sub claim") +) + +// User interface to avoid circular import. +type User interface { + GetDN() string + GetUsername() string + GetEmail() string + GetFullName() string + GetGroups() []string + GetDepartment() string +} + +// Issuer implements TokenIssuer interface for JWT tokens. +type Issuer struct { + secret string + ttl time.Duration + includeUserInfo bool +} + +// NewIssuer creates a new JWT token issuer. +func NewIssuer(secret string, ttl time.Duration, includeUserInfo bool) *Issuer { + return &Issuer{ + secret: secret, + ttl: ttl, + includeUserInfo: includeUserInfo, + } +} + +// IssueToken creates and signs a JWT token for the given user. +func (j *Issuer) IssueToken(user User) (string, error) { + if j.secret == "" { + return "", ErrTokenSigningEmptyKey + } + + claims := jwt.MapClaims{ + "sub": user.GetUsername(), + "exp": time.Now().Add(j.ttl).Unix(), + "iat": time.Now().Unix(), + } + + // Optionally include user information in token claims. + if j.includeUserInfo { + if email := user.GetEmail(); email != "" { + claims["email"] = email + } + + if fullName := user.GetFullName(); fullName != "" { + claims["name"] = fullName + } + + if dept := user.GetDepartment(); dept != "" { + claims["department"] = dept + } + + if groups := user.GetGroups(); len(groups) > 0 { + claims["groups"] = groups + } + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + signed, err := token.SignedString([]byte(j.secret)) + if err != nil { + log.Printf("token signing error: %v", err) + return "", ErrTokenSigningEmptyKey + } + + return signed, nil +} + +// ValidateToken parses and validates a JWT, returning the 'sub' claim. +func (j *Issuer) ValidateToken(tokenStr string) (string, error) { + keyFn := func(token *jwt.Token) (any, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + log.Printf("unexpected signing method: %v", token.Header["alg"]) + return nil, ErrUnexpectedSigningMethod + } + + secret := []byte(j.secret) + + return secret, nil + } + + token, err := jwt.Parse(tokenStr, keyFn) + if err != nil { + return "", fmt.Errorf("token parse error: %w", err) + } + + if !token.Valid { + return "", ErrInvalidToken + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return "", ErrInvalidClaims + } + + sub, ok := claims["sub"].(string) + if !ok { + return "", ErrMissingSubClaim + } + + return sub, nil +} diff --git a/internal/auth/ldapauth/ldapauth.go b/internal/auth/ldapauth/ldapauth.go new file mode 100644 index 000000000..a2fea2f1d --- /dev/null +++ b/internal/auth/ldapauth/ldapauth.go @@ -0,0 +1,255 @@ +package ldapauth + +import ( + "errors" + "fmt" + + "github.com/go-ldap/ldap/v3" + + "gofr.dev/internal/auth/jwt" +) + +var ( + ErrUserNotFound = errors.New("user not found") + ErrMultipleUsersFound = errors.New("multiple users found - LDAP configuration error") +) + +// User represents LDAP user information. +type User struct { + DN string `json:"dn"` + Username string `json:"username"` + Email string `json:"email,omitempty"` + FullName string `json:"full_name,omitempty"` + Groups []string `json:"groups,omitempty"` + Department string `json:"department,omitempty"` + Attributes map[string]string `json:"attributes,omitempty"` +} + +// GetDN returns the distinguished name. +func (u *User) GetDN() string { return u.DN } + +// GetUsername returns the username. +func (u *User) GetUsername() string { return u.Username } + +// GetEmail returns the email. +func (u *User) GetEmail() string { return u.Email } + +// GetFullName returns the full name. +func (u *User) GetFullName() string { return u.FullName } + +// GetGroups returns the groups. +func (u *User) GetGroups() []string { return u.Groups } + +// GetDepartment returns the department. +func (u *User) GetDepartment() string { return u.Department } + +// Conn abstracts ldap.Conn methods for easier testing. +type Conn interface { + Bind(username, password string) error + Search(searchReq *ldap.SearchRequest) (*ldap.SearchResult, error) + Close() error +} + +// TokenIssuer interface for token issuance - allows different implementations. +type TokenIssuer interface { + IssueToken(user jwt.User) (string, error) + ValidateToken(token string) (string, error) +} + +// dialerFunc connects to LDAP and returns a Conn. +type dialerFunc func(addr string, opts ...ldap.DialOpt) (Conn, error) + +// defaultDialer uses ldap.DialURL under the hood. +func defaultDialer(addr string, opts ...ldap.DialOpt) (Conn, error) { + return ldap.DialURL(addr, opts...) +} + +// Config holds LDAP settings and token issuer. +type Config struct { + Addr string + BaseDN string + BindUserDN string + BindPassword string + TokenIssuer TokenIssuer + UserAttributes []string + UsernameAttr string + EmailAttr string + FullNameAttr string + DepartmentAttr string +} + +// Authenticator handles LDAP authentication and token issuance. +type Authenticator struct { + cfg Config + dialFn dialerFunc +} + +// New returns an Authenticator with the default dialer. +func New(cfg *Config) *Authenticator { + // Set default attribute mappings if not specified. + if cfg.UsernameAttr == "" { + cfg.UsernameAttr = "uid" + } + + if cfg.EmailAttr == "" { + cfg.EmailAttr = "mail" + } + + if cfg.FullNameAttr == "" { + cfg.FullNameAttr = "cn" + } + + if cfg.DepartmentAttr == "" { + cfg.DepartmentAttr = "ou" + } + + // Default attributes to retrieve if not specified. + if len(cfg.UserAttributes) == 0 { + cfg.UserAttributes = []string{ + "dn", cfg.UsernameAttr, cfg.EmailAttr, + cfg.FullNameAttr, cfg.DepartmentAttr, "memberOf", + } + } + + return &Authenticator{ + cfg: *cfg, + dialFn: defaultDialer, + } +} + +// WithDialer allows injecting a custom dialer (for tests). +func (a *Authenticator) WithDialer(d dialerFunc) { + a.dialFn = d +} + +// Authenticate binds to LDAP, validates credentials, and returns a signed token. +func (a *Authenticator) Authenticate(username, password string) (string, error) { + conn, err := a.dialFn("ldap://" + a.cfg.Addr) + if err != nil { + return "", fmt.Errorf("failed to connect LDAP: %w", err) + } + defer conn.Close() + + if a.cfg.BindUserDN != "" { + bindErr := conn.Bind(a.cfg.BindUserDN, a.cfg.BindPassword) + if bindErr != nil { + return "", fmt.Errorf("service bind failed: %w", bindErr) + } + } + + user, err := a.lookupUser(conn, username) + if err != nil { + return "", err + } + + authErr := bindUser(conn, user.DN, password) + if authErr != nil { + return "", authErr + } + + token, err := a.cfg.TokenIssuer.IssueToken(user) + if err != nil { + return "", fmt.Errorf("token issuance failed: %w", err) + } + + return token, nil +} + +// GetUserInfo retrieves user information without authentication. +func (a *Authenticator) GetUserInfo(username string) (*User, error) { + conn, err := a.dialFn("ldap://" + a.cfg.Addr) + if err != nil { + return nil, fmt.Errorf("failed to connect LDAP: %w", err) + } + defer conn.Close() + + if a.cfg.BindUserDN != "" { + bindErr := conn.Bind(a.cfg.BindUserDN, a.cfg.BindPassword) + if bindErr != nil { + return nil, fmt.Errorf("service bind failed: %w", bindErr) + } + } + + return a.lookupUser(conn, username) +} + +// ValidateToken validates a token using the configured token issuer. +func (a *Authenticator) ValidateToken(token string) (string, error) { + return a.cfg.TokenIssuer.ValidateToken(token) +} + +// lookupUser retrieves comprehensive user information from LDAP. +func (a *Authenticator) lookupUser(conn Conn, username string) (*User, error) { + searchReq := ldap.NewSearchRequest( + a.cfg.BaseDN, + ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, + fmt.Sprintf("(%s=%s)", a.cfg.UsernameAttr, ldap.EscapeFilter(username)), + a.cfg.UserAttributes, + nil, + ) + + result, err := conn.Search(searchReq) + if err != nil { + return nil, fmt.Errorf("search error: %w", err) + } + + // Handle different result scenarios separately. + switch len(result.Entries) { + case 0: + return nil, ErrUserNotFound + case 1: + return a.buildUserFromEntry(result.Entries[0], username), nil + default: + return nil, ErrMultipleUsersFound + } +} + +// buildUserFromEntry constructs a User object from LDAP entry. +func (a *Authenticator) buildUserFromEntry(entry *ldap.Entry, username string) *User { + user := &User{ + DN: entry.DN, + Username: username, + Attributes: make(map[string]string), + } + + // Extract standard attributes. + if email := entry.GetAttributeValue(a.cfg.EmailAttr); email != "" { + user.Email = email + } + + if fullName := entry.GetAttributeValue(a.cfg.FullNameAttr); fullName != "" { + user.FullName = fullName + } + + if dept := entry.GetAttributeValue(a.cfg.DepartmentAttr); dept != "" { + user.Department = dept + } + + // Extract group memberships. + if groups := entry.GetAttributeValues("memberOf"); len(groups) > 0 { + user.Groups = groups + } + + // Extract all other attributes into the Attributes map. + for _, attr := range entry.Attributes { + // Skip attributes we've already processed. + switch attr.Name { + case a.cfg.EmailAttr, a.cfg.FullNameAttr, a.cfg.DepartmentAttr, "memberOf": + continue + default: + if len(attr.Values) > 0 { + user.Attributes[attr.Name] = attr.Values[0] + } + } + } + + return user +} + +func bindUser(conn Conn, userDN, password string) error { + if err := conn.Bind(userDN, password); err != nil { + return fmt.Errorf("invalid credentials: %w", err) + } + + return nil +} diff --git a/internal/auth/ldapauth/ldapauth_test.go b/internal/auth/ldapauth/ldapauth_test.go new file mode 100644 index 000000000..39808038c --- /dev/null +++ b/internal/auth/ldapauth/ldapauth_test.go @@ -0,0 +1,261 @@ +package ldapauth + +import ( + "errors" + "testing" + + "github.com/go-ldap/ldap/v3" + + "gofr.dev/internal/auth/jwt" +) + +// Static sentinel errors for tests (avoid dynamic errors per err113). +var ( + errDial = errors.New("dial error") + errBind = errors.New("uhoh") + errBad = errors.New("bad") + errExpiredCause = errors.New("expired") + errSearchDown = errors.New("search down") + errTokenIssueFailed = errors.New("token issue failed") +) + +// mockTokenIssuer for testing. +type mockTokenIssuer struct { + issueErr error + validateErr error + token string + username string +} + +func (m *mockTokenIssuer) IssueToken(_ jwt.User) (string, error) { + if m.issueErr != nil { + return "", m.issueErr + } + + return m.token, nil +} + +func (m *mockTokenIssuer) ValidateToken(_ string) (string, error) { + if m.validateErr != nil { + return "", m.validateErr + } + + return m.username, nil +} + +// mockConn implements Conn for controlled test behavior. +type mockConn struct { + bindErr map[string]error + searchResult *ldap.SearchResult + searchErr error + closed bool +} + +func (m *mockConn) Bind(username, password string) error { + if err, ok := m.bindErr[username+"|"+password]; ok { + return err + } + + return nil +} + +func (m *mockConn) Search(_ *ldap.SearchRequest) (*ldap.SearchResult, error) { + return m.searchResult, m.searchErr +} + +func (m *mockConn) Close() error { + m.closed = true + return nil +} + +func TestAuthenticate_LDAPDestinationDoesNotExist(t *testing.T) { + tokenIssuer := &mockTokenIssuer{token: "test-token"} + auth := New(&Config{ + Addr: "x", + BaseDN: "d", + TokenIssuer: tokenIssuer, + }) + auth.WithDialer(func(_ string, _ ...ldap.DialOpt) (Conn, error) { + return nil, errDial + }) + + _, err := auth.Authenticate("jdoe", "ignored") + if err == nil || err.Error() != "failed to connect LDAP: dial error" { + t.Fatalf("expected connection error, got %v", err) + } +} + +func TestAuthenticate_ServiceBindUnauthorized(t *testing.T) { + mc := &mockConn{ + bindErr: map[string]error{"cn=admin,dc=ex,dc=com|bad": errBind}, + searchResult: &ldap.SearchResult{Entries: []*ldap.Entry{{DN: "uid=jdoe,dc=ex,dc=com"}}}, + } + + tokenIssuer := &mockTokenIssuer{token: "test-token"} + auth := New(&Config{ + Addr: "x", + BaseDN: "d", + TokenIssuer: tokenIssuer, + BindUserDN: "cn=admin,dc=ex,dc=com", + BindPassword: "bad", + }) + auth.WithDialer(func(_ string, _ ...ldap.DialOpt) (Conn, error) { return mc, nil }) + + _, err := auth.Authenticate("jdoe", "secret") + if err == nil || err.Error() != "service bind failed: uhoh" { + t.Fatalf("expected bind error, got %v", err) + } +} + +func TestAuthenticate_UserNotFound(t *testing.T) { + mc := &mockConn{ + searchResult: &ldap.SearchResult{Entries: []*ldap.Entry{}}, + } + + tokenIssuer := &mockTokenIssuer{token: "test-token"} + auth := New(&Config{ + Addr: "x", + BaseDN: "d", + TokenIssuer: tokenIssuer, + }) + auth.WithDialer(func(_ string, _ ...ldap.DialOpt) (Conn, error) { return mc, nil }) + + _, err := auth.Authenticate("nonexistent", "secret") + if !errors.Is(err, ErrUserNotFound) { + t.Fatalf("expected ErrUserNotFound, got %v", err) + } +} + +func TestAuthenticate_MultipleUsersFound(t *testing.T) { + mc := &mockConn{ + searchResult: &ldap.SearchResult{ + Entries: []*ldap.Entry{ + {DN: "uid=jdoe1,dc=ex,dc=com"}, + {DN: "uid=jdoe2,dc=ex,dc=com"}, + }, + }, + } + + tokenIssuer := &mockTokenIssuer{token: "test-token"} + auth := New(&Config{ + Addr: "x", + BaseDN: "d", + TokenIssuer: tokenIssuer, + }) + auth.WithDialer(func(_ string, _ ...ldap.DialOpt) (Conn, error) { return mc, nil }) + + _, err := auth.Authenticate("jdoe", "secret") + if !errors.Is(err, ErrMultipleUsersFound) { + t.Fatalf("expected ErrMultipleUsersFound, got %v", err) + } +} + +func TestAuthenticate_InvalidCredentials(t *testing.T) { + mc := &mockConn{ + bindErr: map[string]error{"uid=jdoe,dc=ex,dc=com|wrong": errBad}, + searchResult: &ldap.SearchResult{Entries: []*ldap.Entry{{DN: "uid=jdoe,dc=ex,dc=com"}}}, + } + + tokenIssuer := &mockTokenIssuer{token: "test-token"} + auth := New(&Config{ + Addr: "x", + BaseDN: "d", + TokenIssuer: tokenIssuer, + }) + auth.WithDialer(func(_ string, _ ...ldap.DialOpt) (Conn, error) { return mc, nil }) + + _, err := auth.Authenticate("jdoe", "wrong") + if err == nil || err.Error() != "invalid credentials: bad" { + t.Fatalf("expected invalid credentials error, got %v", err) + } +} + +func TestAuthenticate_ExpiredPassword(t *testing.T) { + errExpired := ldap.NewError(ldap.LDAPResultInvalidCredentials, errExpiredCause) + + mc := &mockConn{ + bindErr: map[string]error{"uid=jdoe,dc=ex,dc=com|secret": errExpired}, + searchResult: &ldap.SearchResult{Entries: []*ldap.Entry{{DN: "uid=jdoe,dc=ex,dc=com"}}}, + } + + tokenIssuer := &mockTokenIssuer{token: "test-token"} + auth := New(&Config{ + Addr: "x", + BaseDN: "d", + TokenIssuer: tokenIssuer, + }) + auth.WithDialer(func(_ string, _ ...ldap.DialOpt) (Conn, error) { return mc, nil }) + + _, err := auth.Authenticate("jdoe", "secret") + if err == nil || err.Error() != "invalid credentials: LDAP Result Code 49 \"Invalid Credentials\": expired" { + t.Fatalf("expected expired password error, got %v", err) + } +} + +func TestAuthenticate_SearchError(t *testing.T) { + mc := &mockConn{searchErr: errSearchDown} + + tokenIssuer := &mockTokenIssuer{token: "test-token"} + auth := New(&Config{ + Addr: "x", + BaseDN: "d", + TokenIssuer: tokenIssuer, + }) + auth.WithDialer(func(_ string, _ ...ldap.DialOpt) (Conn, error) { return mc, nil }) + + _, err := auth.Authenticate("jdoe", "secret") + if err == nil || err.Error() != "search error: search down" { + t.Fatalf("expected search failure error, got %v", err) + } +} + +func TestAuthenticate_TokenIssuanceFailed(t *testing.T) { + mc := &mockConn{ + searchResult: &ldap.SearchResult{Entries: []*ldap.Entry{{DN: "uid=jdoe,dc=ex,dc=com"}}}, + } + + tokenIssuer := &mockTokenIssuer{issueErr: errTokenIssueFailed} + auth := New(&Config{ + Addr: "x", + BaseDN: "d", + TokenIssuer: tokenIssuer, + }) + auth.WithDialer(func(_ string, _ ...ldap.DialOpt) (Conn, error) { return mc, nil }) + + _, err := auth.Authenticate("jdoe", "secret") + if err == nil || err.Error() != "token issuance failed: token issue failed" { + t.Fatalf("expected token issuance error, got %v", err) + } +} + +func TestAuthenticate_Successful(t *testing.T) { + mc := &mockConn{ + searchResult: &ldap.SearchResult{Entries: []*ldap.Entry{{DN: "uid=jdoe,dc=ex,dc=com"}}}, + } + + tokenIssuer := &mockTokenIssuer{token: "test-token", username: "jdoe"} + auth := New(&Config{ + Addr: "x", + BaseDN: "d", + TokenIssuer: tokenIssuer, + }) + auth.WithDialer(func(_ string, _ ...ldap.DialOpt) (Conn, error) { return mc, nil }) + + token, err := auth.Authenticate("jdoe", "secret") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if token != "test-token" { + t.Fatalf("expected token=test-token; got %s", token) + } + + sub, err := auth.ValidateToken(token) + if err != nil { + t.Fatalf("token validation failed: %v", err) + } + + if sub != "jdoe" { + t.Fatalf("expected sub=jdoe; got %s", sub) + } +} diff --git a/mainFile/main.go b/mainFile/main.go new file mode 100644 index 000000000..4b19fc930 --- /dev/null +++ b/mainFile/main.go @@ -0,0 +1,115 @@ +package main + +import ( + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "time" + + "gofr.dev/internal/auth/jwt" + "gofr.dev/internal/auth/ldapauth" +) + +func main() { + jwtIssuer := jwt.NewIssuer("super-secret-key", 1*time.Hour, true) + + cfg := ldapauth.Config{ + Addr: "localhost:389", + BaseDN: "dc=example,dc=com", + BindUserDN: "cn=admin,dc=example,dc=com", + BindPassword: "admin", + TokenIssuer: jwtIssuer, + UserAttributes: []string{ + "dn", "uid", "mail", "cn", "ou", "memberOf", "telephoneNumber", + }, + UsernameAttr: "uid", + EmailAttr: "mail", + FullNameAttr: "cn", + DepartmentAttr: "ou", + } + + authenticator := ldapauth.New(&cfg) + + http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + + var creds struct { + Username string `json:"username"` + Password string `json:"password"` + } + + if err := json.NewDecoder(r.Body).Decode(&creds); err != nil { + http.Error(w, "invalid request body", http.StatusBadRequest) + return + } + + token, err := authenticator.Authenticate(creds.Username, creds.Password) + if err != nil { + switch { + case errors.Is(err, ldapauth.ErrUserNotFound): + http.Error(w, err.Error(), http.StatusUnauthorized) // 401 + case errors.Is(err, ldapauth.ErrMultipleUsersFound): + http.Error(w, err.Error(), http.StatusInternalServerError) // 500 + default: + http.Error(w, err.Error(), http.StatusUnauthorized) // default to 401 for bad creds + } + + return + } + + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(map[string]string{"token": token}) + }) + + http.HandleFunc("/userinfo", func(w http.ResponseWriter, r *http.Request) { + userInfoHandler(w, r, authenticator) + }) + + fmt.Println("Listening on :8080") + + srv := &http.Server{ + Addr: ":8080", + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 120 * time.Second, + } + + log.Fatal(srv.ListenAndServe()) +} + +func userInfoHandler(w http.ResponseWriter, r *http.Request, authenticator *ldapauth.Authenticator) { + username := r.URL.Query().Get("username") + if username == "" { + http.Error(w, "username parameter required", http.StatusBadRequest) + return + } + + user, err := authenticator.GetUserInfo(username) + if err != nil { + statusCode := getHTTPStatusForError(err) + http.Error(w, err.Error(), statusCode) + + return + } + + if err := json.NewEncoder(w).Encode(user); err != nil { + log.Println("encode error:", err) + http.Error(w, "failed to write response", http.StatusInternalServerError) + } +} + +func getHTTPStatusForError(err error) int { + switch { + case errors.Is(err, ldapauth.ErrUserNotFound): + return http.StatusUnauthorized + case errors.Is(err, ldapauth.ErrMultipleUsersFound): + return http.StatusInternalServerError + default: + return http.StatusUnauthorized + } +} diff --git a/mainFile/testuser.ldif b/mainFile/testuser.ldif new file mode 100644 index 000000000..3d40a3035 --- /dev/null +++ b/mainFile/testuser.ldif @@ -0,0 +1,10 @@ +dn: ou=users,dc=example,dc=com +objectClass: organizationalUnit +ou: users + +dn: uid=testuser,ou=users,dc=example,dc=com +objectClass: inetOrgPerson +uid: testuser +sn: User +cn: Test User +userPassword: testpass diff --git a/pkg/gofr/version/version.go b/pkg/gofr/version/version.go index 4060342d1..0169db196 100644 --- a/pkg/gofr/version/version.go +++ b/pkg/gofr/version/version.go @@ -1,3 +1,3 @@ package version -const Framework = "dev" +const Framework = "v1.42.3" diff --git a/testuser.ldif b/testuser.ldif new file mode 100644 index 000000000..3d40a3035 --- /dev/null +++ b/testuser.ldif @@ -0,0 +1,10 @@ +dn: ou=users,dc=example,dc=com +objectClass: organizationalUnit +ou: users + +dn: uid=testuser,ou=users,dc=example,dc=com +objectClass: inetOrgPerson +uid: testuser +sn: User +cn: Test User +userPassword: testpass