mirror of
https://github.com/glauth/glauth.git
synced 2026-10-27 06:26:59 +00:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 251ec3ef66 | |||
| cf78b04400 | |||
| 0479c455fb | |||
| 156e917697 | |||
| 7832f9e94d | |||
| e8951481c8 | |||
| 4f5795965b | |||
| 752333e274 | |||
| 8d1ea390ba | |||
| 48981b9462 | |||
| 80314d335b | |||
| 2ee3dbf3c7 | |||
| d7069b027b | |||
| 882714c9dc | |||
| 07e59076e4 | |||
| 5147d1165a | |||
| 374041c358 | |||
| 5bdeb5118b | |||
| 319cc9a3c7 | |||
| 26cd4447c8 | |||
| 96a283fea2 | |||
| c07a1c978c | |||
| c1c57c62e9 | |||
| 700745e640 | |||
| 1c497d76ba | |||
| cf0eb7f43f | |||
| fb65713fbd | |||
| cb121cdc2c | |||
| 4b2b1398b8 | |||
| be396ae635 | |||
| 719f6a2a2d | |||
| ff7a9e6215 | |||
| 45185dafd1 | |||
| aedc0f2867 | |||
| 0774c95c1a | |||
| 9e04c8b756 | |||
| d3df7252ec | |||
| 5123a3da8e | |||
| eabf67e266 | |||
| d68c78a18b | |||
| 645dbb2266 | |||
| eea7bfbb4f | |||
| b498736cfd | |||
| f8dee8da87 | |||
| c4a020a4f5 | |||
| e92008680c | |||
| 8f972db4cf | |||
| e9a4a5623a | |||
| 8e042199a2 | |||
| c0ed90822f | |||
| a5ecc26e06 | |||
| a90f37b23b | |||
| 8476506b8c |
@@ -7,13 +7,13 @@ on:
|
|||||||
- master
|
- master
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.21.x]
|
go-version: [1.25.x]
|
||||||
steps:
|
steps:
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v7
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
- name: Updating packages database
|
- name: Updating packages database
|
||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Install CLI Dependencies
|
- name: Install CLI Dependencies
|
||||||
run: sudo apt-get install -y ldap-utils oathtool libpam0g-dev
|
run: sudo apt-get install -y ldap-utils oathtool libpam0g-dev
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
- name: Fetch Go dependencies
|
- name: Fetch Go dependencies
|
||||||
working-directory: ./v2
|
working-directory: ./v2
|
||||||
run: go get -t -v ./...
|
run: go get -t -v ./...
|
||||||
|
|||||||
@@ -24,18 +24,18 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v3
|
uses: github/codeql-action/init@v4
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
queries: +security-and-quality
|
queries: +security-and-quality
|
||||||
|
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v3
|
uses: github/codeql-action/autobuild@v4
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v3
|
uses: github/codeql-action/analyze@v4
|
||||||
with:
|
with:
|
||||||
category: "/language:${{ matrix.language }}"
|
category: "/language:${{ matrix.language }}"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
name: release-please
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
@@ -8,20 +9,12 @@ permissions:
|
|||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
||||||
name: release-please
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release-please:
|
release-please:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: google-github-actions/release-please-action@v4
|
||||||
- uses: google-github-actions/release-please-action@v3
|
|
||||||
with:
|
with:
|
||||||
release-type: go
|
|
||||||
package-name: GLAuth
|
|
||||||
path: v2
|
|
||||||
default-branch: master
|
|
||||||
pull-request-title-pattern: "ci: release ${version}"
|
|
||||||
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
||||||
extra-files: |
|
config-file: release-please-config.json
|
||||||
v2/internal/version/const.go
|
manifest-file: .release-please-manifest.json
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
name: stale
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# Daily, off the hour to avoid GitHub's scheduling congestion at :00
|
||||||
|
- cron: '17 4 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v11
|
||||||
|
with:
|
||||||
|
days-before-stale: 60
|
||||||
|
days-before-close: 14
|
||||||
|
|
||||||
|
stale-issue-label: stale
|
||||||
|
stale-pr-label: stale
|
||||||
|
|
||||||
|
stale-issue-message: >
|
||||||
|
This issue has had no activity for 60 days and has been marked stale.
|
||||||
|
It will be closed in 14 days unless there is new activity. If it is
|
||||||
|
still relevant, a comment saying so is enough to keep it open.
|
||||||
|
|
||||||
|
stale-pr-message: >
|
||||||
|
This pull request has had no activity for 60 days and has been marked
|
||||||
|
stale. It will be closed in 14 days unless there is new activity. If
|
||||||
|
you intend to continue the work, a comment saying so is enough to keep
|
||||||
|
it open.
|
||||||
|
|
||||||
|
close-issue-message: >
|
||||||
|
Closing this issue after 14 days with no further activity. If it is
|
||||||
|
still relevant, please comment and it can be reopened.
|
||||||
|
|
||||||
|
close-pr-message: >
|
||||||
|
Closing this pull request after 14 days with no further activity.
|
||||||
|
Please comment if you would like to pick the work back up.
|
||||||
|
|
||||||
|
# Never touch anything deliberately kept open.
|
||||||
|
exempt-issue-labels: 'pinned,security,blocked,help wanted,good first issue'
|
||||||
|
exempt-pr-labels: 'pinned,security,blocked,dependencies'
|
||||||
|
exempt-all-milestones: true
|
||||||
|
|
||||||
|
# Restarts the clock when someone comments, so an active discussion is
|
||||||
|
# never swept up.
|
||||||
|
remove-stale-when-updated: true
|
||||||
|
|
||||||
|
# Oldest first, so the genuine backlog is handled before recent items.
|
||||||
|
ascending: true
|
||||||
+24
@@ -4,7 +4,9 @@ v2/bin
|
|||||||
v2/docker/assets/linux
|
v2/docker/assets/linux
|
||||||
v2/gl.db
|
v2/gl.db
|
||||||
v2/buildlogs
|
v2/buildlogs
|
||||||
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
@@ -13,6 +15,28 @@ v2/buildlogs
|
|||||||
/vendor/
|
/vendor/
|
||||||
/Godeps/
|
/Godeps/
|
||||||
|
|
||||||
|
# Various
|
||||||
|
go.work.sum
|
||||||
|
|
||||||
# gomocks auto-generated
|
# gomocks auto-generated
|
||||||
**/mock_*.go
|
**/mock_*.go
|
||||||
|
|
||||||
|
# Secrets & credentials
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
|
*.crt
|
||||||
|
*.p12
|
||||||
|
*.pfx
|
||||||
|
*.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
*.tfvars
|
||||||
|
credentials.json
|
||||||
|
secrets.yaml
|
||||||
|
secrets.yml
|
||||||
|
|
||||||
|
# Local GLAuth config that may contain bind passwords / secrets
|
||||||
|
config/*.cfg
|
||||||
|
!config/sample-simple.cfg
|
||||||
|
!config/sample-*.cfg
|
||||||
|
*.local.cfg
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"v2": "2.5.4"
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Contributing to GLAuth
|
||||||
|
|
||||||
|
Thanks for your interest in improving GLAuth! This guide covers how to set up your environment, submit changes, and work with the maintainers. Starting with GLAuth 2.4.0, we reworked and optimized the build workflow, and this contribution process reflects that.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
1. Fork the repository and clone your fork locally.
|
||||||
|
2. Review the [Building](https://glauth.github.io/docs/building.html) docs to compile GLAuth from source.
|
||||||
|
3. Review the [Testing](https://glauth.github.io/docs/testing.html) docs to run the test suite before submitting changes.
|
||||||
|
4. Create a topic branch for your work off of `master`.
|
||||||
|
|
||||||
|
## Reporting Issues
|
||||||
|
|
||||||
|
- Open an issue on the [GLAuth issue tracker](https://github.com/glauth/glauth/issues) for bugs and feature requests.
|
||||||
|
- Include your GLAuth version, configuration (with secrets redacted), and clear steps to reproduce.
|
||||||
|
|
||||||
|
## Preparing to Commit
|
||||||
|
|
||||||
|
Format your code automatically using `gofmt -d ./` before committing. If you forget this step, a subsequent pull request may fail.
|
||||||
|
|
||||||
|
## Writing Commit Messages
|
||||||
|
|
||||||
|
Commit messages must be semantically correct. We follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
|
||||||
|
|
||||||
|
A commit message contains a prefix, followed by a short explanation. It may also contain "footer" annotations, but these are not mandatory (though appreciated).
|
||||||
|
|
||||||
|
Please don't bundle multiple unrelated items in the same commit (e.g., a new feature and a bug fix).
|
||||||
|
|
||||||
|
### Commit Prefix
|
||||||
|
|
||||||
|
A prefix is written imperatively, for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(plugins)!: Change the plugins API to allow NoSQL databases.
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a new feature (`feat`), optionally scoped to an area of GLAuth (`(plugins)`), with `!` warning of a breaking change.
|
||||||
|
|
||||||
|
A more innocuous change:
|
||||||
|
|
||||||
|
```
|
||||||
|
chore: Add more comments in all modules.
|
||||||
|
```
|
||||||
|
|
||||||
|
Available prefixes: `feat`, `fix`, `chore`, `build`, `ci`, `perf`, `refactor`, `test`, `style`.
|
||||||
|
|
||||||
|
### Commit Footer Annotations
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
Reviewed-by: John Romero <john@romero.com>
|
||||||
|
Tested-by: Joel Spolsky <joel@joelonsoftware.com>
|
||||||
|
BREAKING-CHANGE: I broke the plugin
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018 Ned McClain & Ben Yanke
|
Copyright (c) 2018 Ned McClain & Ben Yanke & Chris Ravenscroft
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
# GLAuth: LDAP authentication server for developers
|
|
||||||
Go-lang LDAP Authentication (GLAuth) is a secure, easy-to-use, LDAP server w/ configurable backends.
|
|
||||||
|
|
||||||
[](https://gitter.im/glauth/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
# GLAuth: LDAP authentication server for developers
|
||||||
[](hey)
|
[](https://glauth.github.io/)
|
||||||
|
[](https://github.com/fusion/kittendns)
|
||||||
|
[](https://github.com/fusion/wing-vpn)
|
||||||
|
|
||||||
|
Go-lang LDAP Authentication (GLAuth) is a secure, easy-to-use, LDAP server w/ configurable backends.
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||

|

|
||||||

|
|
||||||
|
|
||||||
* Centrally manage accounts across your infrastructure
|
* Centrally manage accounts across your infrastructure
|
||||||
* Centrally manage SSH keys, Linux accounts, and passwords for cloud servers.
|
* Centrally manage SSH keys, Linux accounts, and passwords for cloud servers.
|
||||||
@@ -21,7 +21,7 @@ Use it to centralize account management across your Linux servers, your OSX mach
|
|||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
- Please base all Pull Requests on [dev](https://github.com/glauth/glauth/tree/dev), not master.
|
- Please base all Pull Requests on [dev](https://github.com/glauth/glauth/tree/dev), not master.
|
||||||
- Format your code autonmatically using `gofmt -d ./` before committing
|
- Format your code automatically using `gofmt -d ./` before committing
|
||||||
|
|
||||||
### Quickstart
|
### Quickstart
|
||||||
This quickstart is a great way to try out GLAuth in a non-production environment. *Be warned that you should take the extra steps to setup SSL (TLS) for production use!*
|
This quickstart is a great way to try out GLAuth in a non-production environment. *Be warned that you should take the extra steps to setup SSL (TLS) for production use!*
|
||||||
@@ -110,4 +110,3 @@ For advanced users, GLAuth supports pluggable backends. Currently, it can use a
|
|||||||
# Stargazers over time
|
# Stargazers over time
|
||||||
|
|
||||||
[](https://starchart.cc/glauth/glauth)
|
[](https://starchart.cc/glauth/glauth)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"packages": {
|
||||||
|
"v2": {
|
||||||
|
"release-type": "go",
|
||||||
|
"package-name": "GLAuth",
|
||||||
|
"pull-request-title-pattern": "ci: release ${version}",
|
||||||
|
"extra-files": [
|
||||||
|
"internal/version/const.go"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
|
||||||
|
}
|
||||||
@@ -1,5 +1,87 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [2.5.4](https://github.com/glauth/glauth/compare/GLAuth-v2.5.3...GLAuth-v2.5.4) (2026-09-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* revert pam plugin to msteinert/pam v1 ([#487](https://github.com/glauth/glauth/issues/487)) ([8d1ea39](https://github.com/glauth/glauth/commit/8d1ea390bacc74a54d9b2046e514b7e0336cb08b))
|
||||||
|
|
||||||
|
## [2.5.3](https://github.com/glauth/glauth/compare/GLAuth-v2.5.2...GLAuth-v2.5.3) (2026-09-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* remove repetitions, reduce waitForPort scope, restore arbitrary port ([5bdeb51](https://github.com/glauth/glauth/commit/5bdeb5118b0689d92c4a0d12aea63d8b8d153b71))
|
||||||
|
|
||||||
|
## [2.5.2](https://github.com/glauth/glauth/compare/GLAuth-v2.5.1...GLAuth-v2.5.2) (2026-07-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* check plugin compatibility at release time ([700745e](https://github.com/glauth/glauth/commit/700745e640c5371361a58ef3c90245a4637c5224))
|
||||||
|
|
||||||
|
## [2.5.1](https://github.com/glauth/glauth/compare/GLAuth-v2.5.0...GLAuth-v2.5.1) (2026-07-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* reject disabled users on all backends in Bind ([#470](https://github.com/glauth/glauth/issues/470)) ([fb65713](https://github.com/glauth/glauth/commit/fb65713fbdfd626cb033675fb42724a5fb3d06ff))
|
||||||
|
* team atlanta arbitrary password ([#471](https://github.com/glauth/glauth/issues/471)) ([cb121cd](https://github.com/glauth/glauth/commit/cb121cdc2c9b831abdf7831835ec30ead2536a7a))
|
||||||
|
|
||||||
|
## [2.5.0](https://github.com/glauth/glauth/compare/GLAuth-v2.5.0...GLAuth-v2.5.0) (2026-04-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* allow tracing configuration via main config ([f692394](https://github.com/glauth/glauth/commit/f692394942aa0f93a1aa1572331fd1c3e3553156))
|
||||||
|
* alt container build registry ([f8dee8d](https://github.com/glauth/glauth/commit/f8dee8da879232f5c6ae2a2a19565562c7d0d9fd))
|
||||||
|
* embedded plugins ([c0ed908](https://github.com/glauth/glauth/commit/c0ed90822fd4d2ee7104a1979d423a0c93d758ac))
|
||||||
|
* introduce context for otlp spans into handler pkg ([d05630f](https://github.com/glauth/glauth/commit/d05630f66b80a776fd406782ad1fde5c6c66eac6))
|
||||||
|
* introduce context for otlp spans into plugins pkg ([46e49b6](https://github.com/glauth/glauth/commit/46e49b6976318a9f3670b88bdcb3411dfac0a17c))
|
||||||
|
* introduce legacy behavior, based on past versions ([#318](https://github.com/glauth/glauth/issues/318)) ([34a6b30](https://github.com/glauth/glauth/commit/34a6b30b8fe69c90cab09eb85890ffdfe8fc80fd))
|
||||||
|
* introduce otelsql ([2ca5312](https://github.com/glauth/glauth/commit/2ca53126965aa7d42b23aee15f750df12822d454))
|
||||||
|
* introduce otlp tracer ([0cf0403](https://github.com/glauth/glauth/commit/0cf04037a2a7b38c8ed7af2451b115f48c5427b5))
|
||||||
|
* proxying ldap paging compat ([#422](https://github.com/glauth/glauth/issues/422)) ([8476506](https://github.com/glauth/glauth/commit/8476506b8c51e993eb90c73d612f69fec5350b89))
|
||||||
|
* starttls and ldaps now matching features ([#458](https://github.com/glauth/glauth/issues/458)) ([d68c78a](https://github.com/glauth/glauth/commit/d68c78a18b150679038e5ce549b6b227c31518d7))
|
||||||
|
* wire up basic tracer ([1c2b23c](https://github.com/glauth/glauth/commit/1c2b23c00ff85b83a6d2e4bf4a9a68081aaf2777))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 246 and [#252](https://github.com/glauth/glauth/issues/252) ([ceefc66](https://github.com/glauth/glauth/commit/ceefc66dbba9ae054958269825de31d22d30e262))
|
||||||
|
* config watcher now updates whenf ile added to dir ([#424](https://github.com/glauth/glauth/issues/424)) ([a90f37b](https://github.com/glauth/glauth/commit/a90f37b23b76af22c700392d68bf227b7aee1894))
|
||||||
|
* Credentials leaked on INFO log level ([#451](https://github.com/glauth/glauth/issues/451)) ([645dbb2](https://github.com/glauth/glauth/commit/645dbb226683ae57f3d5382e21ea42444e940752))
|
||||||
|
* drop vendored toml ([24455e3](https://github.com/glauth/glauth/commit/24455e39889716ce7ae1e7e8a7dacfa7d4c96080))
|
||||||
|
* formatting ([c90cbfe](https://github.com/glauth/glauth/commit/c90cbfe5fb090fc19a55d64e01cd0e31c38bf2f0))
|
||||||
|
* go test not checking otp within allowed basedn ([#403](https://github.com/glauth/glauth/issues/403)) ([ed52a91](https://github.com/glauth/glauth/commit/ed52a91ec4117ff58fe606a1d8ba10786501a1e5))
|
||||||
|
* move all toml parsing into a new internal package, drop the mappings in favour of toml.Primitive decoding ([3ba8e11](https://github.com/glauth/glauth/commit/3ba8e1113217be647d240261322453d213ea7da4))
|
||||||
|
* patch group name fetches for the rest of handlers ([#450](https://github.com/glauth/glauth/issues/450)) ([b498736](https://github.com/glauth/glauth/commit/b498736cfdd0ee6f1585d682a5c54c9d927b8dbb))
|
||||||
|
* remove spinlock in monitoring code ([#405](https://github.com/glauth/glauth/issues/405)) ([a2c151b](https://github.com/glauth/glauth/commit/a2c151b0d025332462369a846a51ef4deff5332b))
|
||||||
|
* removed config setup from main, reshoring log configuration ([5fe8aca](https://github.com/glauth/glauth/commit/5fe8aca852bdfe7e375ea99b87074bae35fc3407))
|
||||||
|
* update ldap library to fix [#389](https://github.com/glauth/glauth/issues/389) ([#430](https://github.com/glauth/glauth/issues/430)) ([a5ecc26](https://github.com/glauth/glauth/commit/a5ecc26e064cea9e4dab3dd234ebd5d5eb06be0e))
|
||||||
|
* update tracing code to work with breaking otlp 1.20 changes ([1a37396](https://github.com/glauth/glauth/commit/1a3739610997b58100040d0c8a405596fccc8e23))
|
||||||
|
* upgrade to use BurntSushi/toml ([f9addbc](https://github.com/glauth/glauth/commit/f9addbc2c5b13ccc2779dbabc4c55bc8706f53d6))
|
||||||
|
|
||||||
|
|
||||||
|
### Miscellaneous Chores
|
||||||
|
|
||||||
|
* force release 2.5.0 ([ff7a9e6](https://github.com/glauth/glauth/commit/ff7a9e6215857e0dd3450504b7b063409ccfc374))
|
||||||
|
* release 2.3.1 ([0bf3d4a](https://github.com/glauth/glauth/commit/0bf3d4a82a8451e7bbda74e3730345aab5a855a7))
|
||||||
|
|
||||||
|
## [2.4.0](https://github.com/glauth/glauth/compare/v2.3.2...v2.4.0) (2024-08-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* proxying ldap paging compat ([#422](https://github.com/glauth/glauth/issues/422)) ([8476506](https://github.com/glauth/glauth/commit/8476506b8c51e993eb90c73d612f69fec5350b89))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* config watcher now updates whenf ile added to dir ([#424](https://github.com/glauth/glauth/issues/424)) ([a90f37b](https://github.com/glauth/glauth/commit/a90f37b23b76af22c700392d68bf227b7aee1894))
|
||||||
|
* update ldap library to fix [#389](https://github.com/glauth/glauth/issues/389) ([#430](https://github.com/glauth/glauth/issues/430)) ([a5ecc26](https://github.com/glauth/glauth/commit/a5ecc26e064cea9e4dab3dd234ebd5d5eb06be0e))
|
||||||
|
|
||||||
## [2.3.2](https://github.com/glauth/glauth/compare/v2.3.1...v2.3.2) (2024-02-19)
|
## [2.3.2](https://github.com/glauth/glauth/compare/v2.3.1...v2.3.2) (2024-02-19)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+191
-49
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
MAKEFLAGS += --no-print-directory
|
MAKEFLAGS += --no-print-directory
|
||||||
|
|
||||||
VERSION=$(shell bin/linuxamd64/glauth --version)
|
VERSION=$(shell if [ -x bin/linuxamd64/glauth ]; then bin/linuxamd64/glauth --version; else bin/glauth-linux-amd64 --version; fi)
|
||||||
|
|
||||||
GIT_COMMIT=$(shell git rev-list -1 HEAD )
|
GIT_COMMIT=$(shell git rev-list -1 HEAD )
|
||||||
BUILD_TIME=$(shell date -u +%Y%m%d_%H%M%SZ)
|
BUILD_TIME=$(shell date -u +%Y%m%d_%H%M%SZ)
|
||||||
@@ -21,10 +21,12 @@ GIT_BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
|
|||||||
BUILD_VARS?=-s -w
|
BUILD_VARS?=-s -w
|
||||||
BUILD_FILES=.
|
BUILD_FILES=.
|
||||||
TRIM_FLAGS>?=-trimpath
|
TRIM_FLAGS>?=-trimpath
|
||||||
|
BUILD_TAGS?=noembed
|
||||||
|
|
||||||
# Targets
|
# Targets
|
||||||
MAIN_TARGETS?=linux/amd64,linux/386,linux/arm64,linux/arm-7,darwin/amd64,darwin/arm64,windows/amd64,windows/386
|
MAIN_TARGETS?=linux/amd64,linux/386,linux/arm64,linux/arm-7,linux/riscv64,darwin/amd64,darwin/arm64,windows/amd64,windows/386
|
||||||
PLUGIN_TARGETS?=linux/amd64,linux/386,linux/arm64,linux/arm-7,darwin/amd64,darwin/arm64
|
PLUGIN_TARGETS?=linux/amd64,linux/386,linux/arm64,linux/arm-7,linux/riscv64,darwin/amd64,darwin/arm64
|
||||||
|
EMBED_TARGETS?=windows/amd64
|
||||||
|
|
||||||
# For release process
|
# For release process
|
||||||
GO_RELEASE_V=$(shell go version | { read _ _ v _; echo $${v#go}; })
|
GO_RELEASE_V=$(shell go version | { read _ _ v _; echo $${v#go}; })
|
||||||
@@ -56,10 +58,22 @@ mocks:
|
|||||||
vet:
|
vet:
|
||||||
-go vet ./...
|
-go vet ./...
|
||||||
.PHONY: vet
|
.PHONY: vet
|
||||||
#test: @ runs the integration test on linuxamd64 (eventually allow the binary to be set)
|
#seedplugindb: @ stage the sqlite plugin and seed its test database
|
||||||
test: mocks vet
|
seedplugindb:
|
||||||
# also run unit tests for packages, skip glauth_test.go for now
|
@if [ -f bin/sqlite-linux-amd64.so ]; then \
|
||||||
go test -v -cover -coverprofile coverage.out ./pkg/... ./internal/...
|
echo "- staging sqlite plugin and seeding gl.db"; \
|
||||||
|
cp -f bin/sqlite-linux-amd64.so bin/sqlite.so; \
|
||||||
|
rm -f gl.db; \
|
||||||
|
glauth=$$(ls bin/$(GOOS)$(GOARCH)/glauth bin/glauth-$(GOOS)-$(GOARCH) 2>/dev/null | head -1); \
|
||||||
|
"$$glauth" -c pkg/plugins/glauth-sqlite/sample-database.cfg >/dev/null 2>&1 & \
|
||||||
|
pid=$$!; sleep 2; kill -TERM $$pid 2>/dev/null; wait $$pid 2>/dev/null || true; \
|
||||||
|
sqlite3 gl.db < scripts/ci/seed-sqlite-plugin.sql; \
|
||||||
|
fi
|
||||||
|
.PHONY: seedplugindb
|
||||||
|
|
||||||
|
#test: @ runs package, root integration, and shell integration tests
|
||||||
|
test: mocks vet seedplugindb
|
||||||
|
go test -v -cover -coverprofile coverage.out ./pkg/... ./internal/... .
|
||||||
$(MAKE) runtest
|
$(MAKE) runtest
|
||||||
#all: @ run build process for all binaries
|
#all: @ run build process for all binaries
|
||||||
all: setup binaries verify
|
all: setup binaries verify
|
||||||
@@ -67,8 +81,11 @@ all: setup binaries verify
|
|||||||
#fast: @ run build process for only linuxamd64
|
#fast: @ run build process for only linuxamd64
|
||||||
fast: setup linuxamd64
|
fast: setup linuxamd64
|
||||||
|
|
||||||
|
#fastdebug: @ run build process for only linuxamd64 in debug mode
|
||||||
|
fastdebug: setup linuxamd64debug
|
||||||
|
|
||||||
#binaries: @ list of binary formats to build
|
#binaries: @ list of binary formats to build
|
||||||
binaries: linux386 linuxamd64 linuxarm linuxarm64 darwinamd64 darwinarm64 win386 winamd64
|
binaries: linux386 linuxamd64 linuxarm linuxarm64 linuxriscv64 darwinamd64 darwinarm64 win386 winamd64
|
||||||
|
|
||||||
#setup: @ setup commands to always run
|
#setup: @ setup commands to always run
|
||||||
setup: getdeps format
|
setup: getdeps format
|
||||||
@@ -76,11 +93,26 @@ setup: getdeps format
|
|||||||
#####################
|
#####################
|
||||||
# Subcommands
|
# Subcommands
|
||||||
#####################
|
#####################
|
||||||
|
# @echo \- removing any changes and pulling latest master && \
|
||||||
|
# git reset --hard HEAD >/dev/null 2>&1 && \
|
||||||
|
# git checkout master >/dev/null 2>&1 && \
|
||||||
|
# git pull >/dev/null 2>&1 && \
|
||||||
|
|
||||||
prepbuild:
|
prepbuild:
|
||||||
@if [ ! -e $M/.ignore ] ; \
|
echo \- taking care of ignore files && \
|
||||||
then \
|
sudo rm -rf bin/* >/dev/null && \
|
||||||
mkdir -p buildlogs;\
|
echo \- cleaning up plugins remnants && \
|
||||||
|
make forget-plugins && \
|
||||||
|
make remember-plugins
|
||||||
|
|
||||||
|
forget-embed:
|
||||||
|
@if [ -f pkg/server/embed_sqlite.go ]; then \
|
||||||
|
mv pkg/server/embed_sqlite.go /tmp/; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
remember-embed:
|
||||||
|
@if [ ! -f pkg/server/embed_sqlite.go ]; then \
|
||||||
|
mv /tmp/embed_sqlite.go pkg/server/; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Run integration test
|
# Run integration test
|
||||||
@@ -100,20 +132,61 @@ format:
|
|||||||
devrun:
|
devrun:
|
||||||
go run ${BUILD_FILES} -c sample-simple.cfg
|
go run ${BUILD_FILES} -c sample-simple.cfg
|
||||||
|
|
||||||
|
#testplugin: @ start GLAuth with a dynamically loaded plugin and stop it cleanly
|
||||||
|
GLAUTH_BIN?=bin/glauth-linux-amd64
|
||||||
|
PLUGIN_BIN?=bin/sqlite-linux-amd64.so
|
||||||
|
PLUGIN_CONFIG?=pkg/plugins/glauth-sqlite/sample-database.cfg
|
||||||
|
PLUGIN_LDAP_PORT?=13893
|
||||||
|
PLUGIN_API_PORT?=15555
|
||||||
|
|
||||||
|
testplugin:
|
||||||
|
@set -e; \
|
||||||
|
test -x "$(GLAUTH_BIN)"; \
|
||||||
|
test -r "$(PLUGIN_BIN)"; \
|
||||||
|
test -f "$(PLUGIN_CONFIG)"; \
|
||||||
|
tmpdir=$$(mktemp -d); \
|
||||||
|
trap 'rm -rf "$$tmpdir"' EXIT; \
|
||||||
|
sed \
|
||||||
|
-e 's#^[[:space:]]*plugin = .*# plugin = "$(abspath $(PLUGIN_BIN))"#' \
|
||||||
|
-e "s#^[[:space:]]*database = .*# database = \"$$tmpdir/gl.db\"#" \
|
||||||
|
-e 's#listen = "0.0.0.0:3893"#listen = "127.0.0.1:$(PLUGIN_LDAP_PORT)"#' \
|
||||||
|
-e 's#listen = "0.0.0.0:5555"#listen = "127.0.0.1:$(PLUGIN_API_PORT)"#' \
|
||||||
|
"$(PLUGIN_CONFIG)" > "$$tmpdir/config.cfg"; \
|
||||||
|
"$(GLAUTH_BIN)" -c "$$tmpdir/config.cfg" > "$$tmpdir/glauth.log" 2>&1 & \
|
||||||
|
pid=$$!; \
|
||||||
|
sleep 2; \
|
||||||
|
if ! kill -0 "$$pid" 2>/dev/null; then \
|
||||||
|
set +e; wait "$$pid"; status=$$?; set -e; \
|
||||||
|
cat "$$tmpdir/glauth.log"; \
|
||||||
|
exit $$status; \
|
||||||
|
fi; \
|
||||||
|
kill -TERM "$$pid"; \
|
||||||
|
set +e; wait "$$pid"; status=$$?; set -e; \
|
||||||
|
cat "$$tmpdir/glauth.log"; \
|
||||||
|
exit $$status
|
||||||
|
|
||||||
mkbindir:
|
mkbindir:
|
||||||
@echo "create directory bin/$(GOOS)$(GOARCH)"
|
@echo "create directory bin/$(GOOS)$(GOARCH)"
|
||||||
@mkdir -p bin/$(GOOS)$(GOARCH)
|
@mkdir -p bin/$(GOOS)$(GOARCH)
|
||||||
.PHONY: mkbindir
|
.PHONY: mkbindir
|
||||||
|
|
||||||
build: mkbindir
|
build: mkbindir
|
||||||
@go build ${TRIM_FLAGS} -ldflags "${BUILD_VARS}" -o bin/$(GOOS)$(GOARCH)/glauth -buildvcs .
|
@go build ${TRIM_FLAGS} -tags ${BUILD_TAGS} -ldflags "${BUILD_VARS}" -o bin/$(GOOS)$(GOARCH)/glauth -buildvcs .
|
||||||
$(MAKE) sha256
|
$(MAKE) sha256
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
|
|
||||||
|
builddebug: mkbindir
|
||||||
|
@go build ${TRIM_FLAGS} -tags ${BUILD_TAGS} -gcflags="all=-N -l" -o bin/$(GOOS)$(GOARCH)/glauth -buildvcs .
|
||||||
|
$(MAKE) sha256
|
||||||
|
.PHONY: builddebug
|
||||||
|
|
||||||
sha256:
|
sha256:
|
||||||
@sha256sum bin/$(GOOS)$(GOARCH)/glauth > bin/$(GOOS)$(GOARCH)/glauth.sha256
|
@sha256sum bin/$(GOOS)$(GOARCH)/glauth > bin/$(GOOS)$(GOARCH)/glauth.sha256
|
||||||
.PHONY: sha256
|
.PHONY: sha256
|
||||||
|
|
||||||
|
linuxamd64debug:
|
||||||
|
GOOS=linux GOARCH=amd64 $(MAKE) builddebug
|
||||||
|
|
||||||
linux386:
|
linux386:
|
||||||
GOOS=linux GOARCH=386 $(MAKE) build
|
GOOS=linux GOARCH=386 $(MAKE) build
|
||||||
|
|
||||||
@@ -126,6 +199,16 @@ linuxarm:
|
|||||||
linuxarm64:
|
linuxarm64:
|
||||||
GOOS=linux GOARCH=arm64 $(MAKE) build
|
GOOS=linux GOARCH=arm64 $(MAKE) build
|
||||||
|
|
||||||
|
linuxriscv64:
|
||||||
|
GOOS=linux GOARCH=riscv64 $(MAKE) build
|
||||||
|
|
||||||
|
testing:
|
||||||
|
mkdir -p pkg/embed && \
|
||||||
|
cat pkg/plugins/glauth-sqlite/sqlite.go | sed -e 's/func main() {}//' -e 's/^package main/package embed/' > pkg/embed/sqlite.go && \
|
||||||
|
go mod tidy && \
|
||||||
|
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 BUILD_TAGS=embedsqlite $(MAKE) build && \
|
||||||
|
rm -rf pkg/embed
|
||||||
|
|
||||||
darwinamd64:
|
darwinamd64:
|
||||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 $(MAKE) build
|
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 $(MAKE) build
|
||||||
|
|
||||||
@@ -139,73 +222,128 @@ winamd64:
|
|||||||
GOOS=windows GOARCH=amd64 $(MAKE) build
|
GOOS=windows GOARCH=amd64 $(MAKE) build
|
||||||
|
|
||||||
verify:
|
verify:
|
||||||
@for binary in linux386 linuxamd64 linuxarm linuxarm64 darwinamd64 darwinarm64 win386 winamd64; do cd bin/$$binary && sha256sum glauth.sha256 -c && cd ../..; done
|
@for binary in linux386 linuxamd64 linuxarm linuxarm64 linuxriscv64 darwinamd64 darwinarm64 win386 winamd64; do cd bin/$$binary && sha256sum glauth.sha256 -c && cd ../..; done
|
||||||
|
|
||||||
pull-plugin-dependencies:
|
pull-plugin-dependencies:
|
||||||
(for pkg in $$(cat $$M/go.mod | awk '/^require [a-z]/{print $$2} /^\)/{rblock=0} rblock{if($$4!="indirect" && $$1!~"glauth"){print $$1}} /^require \(/{rblock=1}'); do if [ "$$(grep $$pkg go.mod &>/dev/null)" = "" ]; then go get $$pkg; fi; done)
|
(for pkg in $$(cat $$M/go.mod | awk '/^require [a-z]/{print $$2"@"$$3} /^\)/{rblock=0} rblock{if($$4!="indirect" && $$1!~"glauth"){print $$1"@"$$2}} /^require \(/{rblock=1}'); do if [ "$$(grep $${pkg%@*} go.mod 2>/dev/null)" = "" ]; then go get $$pkg; fi; done)
|
||||||
|
|
||||||
#prepare-plugins-release: @ pull plugins dependencies for local building
|
#prepare-plugins-buid: @ pull plugins dependencies for local building
|
||||||
prepare-plugins-release:
|
prepare-plugins-build:
|
||||||
@M=pkg/plugins/glauth-sqlite make pull-plugin-dependencies && \
|
@M=pkg/plugins/glauth-sqlite make pull-plugin-dependencies && \
|
||||||
M=pkg/plugins/glauth-mysql make pull-plugin-dependencies && \
|
M=pkg/plugins/glauth-mysql make pull-plugin-dependencies && \
|
||||||
M=pkg/plugins/glauth-postgres make pull-plugin-dependencies && \
|
M=pkg/plugins/glauth-postgres make pull-plugin-dependencies && \
|
||||||
M=pkg/plugins/glauth-pam make pull-plugin-dependencies
|
M=pkg/plugins/glauth-pam make pull-plugin-dependencies
|
||||||
|
|
||||||
forget-plugin:
|
forget-plugin:
|
||||||
rm -rf $M ../.git/modules/v2/$M && \
|
rm -rf $M ../.git/modules/v2/$M; \
|
||||||
git config --remove-section submodule.v2/$M && \
|
git config --remove-section submodule.v2/$M; \
|
||||||
git rm --cache $M && \
|
git rm --cache $M; \
|
||||||
go mod tidy
|
go mod tidy; \
|
||||||
|
true
|
||||||
|
|
||||||
#forget-plugin: @ remove plugins, restoring original file structure
|
#forget-plugin: @ remove plugins, restoring original file structure
|
||||||
forget-plugins:
|
forget-plugins:
|
||||||
for pkg in pkg/plugins/*/go.mod; do\
|
for pkg in pkg/plugins/*; do \
|
||||||
P=$$(echo $$pkg | cut -d'/' -f 3) M=$$(dirname $$pkg) make forget-plugin;\
|
if [ -d "$$pkg" ]; then \
|
||||||
done
|
P=$$(echo $$pkg | cut -d'/' -f 3) M=$$pkg make forget-plugin >/dev/null 2>&1;\
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
rm -rf buildlogs
|
||||||
|
|
||||||
#releasemain: @ build main binaries for distribution
|
remember-plugins:
|
||||||
releasemain: prepbuild
|
cd ../ && \
|
||||||
|
for module in $$(cat .gitmodules | awk '/path =/{P=$$3} /url =/{print $$3 "," P}'); do \
|
||||||
|
git submodule add $${module%%,*} $${module#*,}; \
|
||||||
|
done; \
|
||||||
|
git submodule update --init --recursive
|
||||||
|
|
||||||
|
_buildmain:
|
||||||
@xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out glauth -dest bin -buildvcs=false --targets="${MAIN_TARGETS}" .
|
@xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out glauth -dest bin -buildvcs=false --targets="${MAIN_TARGETS}" .
|
||||||
|
|
||||||
releaseplugin: prepbuild
|
#buildmain: @ build main binaries for distribution
|
||||||
@echo "Building $P plugin"; \
|
buildmain: prepbuild _buildmain
|
||||||
if [ ! -e $M/.ignore ] ; \
|
|
||||||
then \
|
buildsingleembed:
|
||||||
xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out $P -dest bin -buildvcs=false -buildmode=plugin --targets="${PLUGIN_TARGETS}" --pkg $M/$P.go . && \
|
git checkout -b build_embeds && \
|
||||||
(cd bin && for lib in $$(ls $$P-*); do sudo mv $$lib $$lib.so; done); \
|
mkdir -p pkg/embed && \
|
||||||
|
cat pkg/plugins/$P/$M | sed -e 's/func main() {}//' -e 's/^package main/package embed/' > pkg/embed/$M && \
|
||||||
|
go mod tidy && \
|
||||||
|
git add pkg/embed/$M go.mod go.sum && \
|
||||||
|
git commit -m "build cruft" && \
|
||||||
|
git push -u origin build_embeds && \
|
||||||
|
xgo -v -ldflags="${BUILD_VARS}" --tags=$T -trimpath -go ${GO_RELEASE_V} -out glauth -dest bin -buildvcs=false --targets="${EMBED_TARGETS}" . && \
|
||||||
|
rm -rf pkg/embed && \
|
||||||
|
git checkout master && \
|
||||||
|
git push -d origin build_embeds && \
|
||||||
|
git branch -D build_embeds
|
||||||
|
|
||||||
|
_buildmainembeds:
|
||||||
|
P=glauth-sqlite M=sqlite.go T=embedsqlite make buildsingleembed
|
||||||
|
|
||||||
|
#buildmainembeds: @ build main binaries for distribution, including embedded plugins
|
||||||
|
buildmainembeds: prepbuild _buildmainembeds
|
||||||
|
|
||||||
|
buildplugin:
|
||||||
|
ifeq ($P,pam)
|
||||||
|
xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out $P -dest bin -buildvcs=false -buildmode=plugin --targets="${PLUGIN_TARGETS}" --pkg $M/$P.go --bringupcmd 'apt update && apt install -y libpam0g-dev' .
|
||||||
|
else
|
||||||
|
xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out $P -dest bin -buildvcs=false -buildmode=plugin --targets="${PLUGIN_TARGETS}" --pkg $M/$P.go .
|
||||||
|
endif
|
||||||
|
(cd bin && for lib in $$(ls $$P-* | grep -v \.so$$); do sudo mv $$lib $$lib.so; done);
|
||||||
|
|
||||||
|
_buildplugins: prepare-plugins-build
|
||||||
|
for pkg in pkg/plugins/*; do \
|
||||||
|
if [ -d "$$pkg" ]; then \
|
||||||
|
M=pkg/plugins/$$(echo $$pkg | cut -d'/' -f 3) && P=$$(echo $$M | grep -oP 'glauth-\K\w+') && M=$$M P=$$P make buildplugin;\
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
|
||||||
|
#buildplugins: @ build base plugins for distribution
|
||||||
|
buildplugins: forget-embed _buildplugins remember-embed
|
||||||
|
|
||||||
|
_checkdockerauth:
|
||||||
|
@if ! grep -q "index.docker.io" $(HOME)/.docker/config.json; then \
|
||||||
|
echo "❌ Not logged in to Docker Hub (index.docker.io not found in config)."; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
if ! grep -q "ghcr.io" $(HOME)/.docker/config.json; then \
|
||||||
|
echo "❌ Not logged in to GitHub Hub (ghcr.io not found in config)."; \
|
||||||
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#releaseplugins: @ build base plugins for distribution
|
builddockermain:
|
||||||
releaseplugins:
|
$(if $(TAG),,$(error ❌ Must set TAG))
|
||||||
@for pkg in pkg/plugins/*/go.mod; do\
|
$(if $(REPO),,$(error ❌ Must set REPO - glauth or other))
|
||||||
M=pkg/plugins/$$(echo $$pkg | cut -d'/' -f 3) && P=$$(echo $$M | grep -oP 'glauth-\K\w+') && M=$$M P=$$P make releaseplugin;\
|
@mkdir -p docker/assets/linux/amd64 docker/assets/linux/arm64 docker/assets/linux/arm/v7 docker/assets/linux/riscv64 && \
|
||||||
done
|
|
||||||
|
|
||||||
releasedockermain:
|
|
||||||
$(if $(TAG),,$(error Must set TAG))
|
|
||||||
$(if $(REPO),,$(error Must set REPO - glauth or other))
|
|
||||||
@mkdir -p docker/assets/linux/amd64 docker/assets/linux/arm64 docker/assets/linux/arm/v7 && \
|
|
||||||
cp -f bin/glauth-linux-amd64 docker/assets/linux/amd64/glauth && \
|
cp -f bin/glauth-linux-amd64 docker/assets/linux/amd64/glauth && \
|
||||||
cp -f bin/glauth-linux-arm64 docker/assets/linux/arm64/glauth && \
|
cp -f bin/glauth-linux-arm64 docker/assets/linux/arm64/glauth && \
|
||||||
cp -f bin/glauth-linux-arm-7 docker/assets/linux/arm/v7/glauth && \
|
cp -f bin/glauth-linux-arm-7 docker/assets/linux/arm/v7/glauth && \
|
||||||
docker buildx build --tag $$REPO/glauth:$$TAG -t $$REPO/glauth:latest -f docker/Dockerfile-standalone --platform linux/amd64,linux/arm64,linux/arm/v7 --push docker
|
cp -f bin/glauth-linux-riscv64 docker/assets/linux/riscv64/glauth && \
|
||||||
|
docker buildx build --tag ghcr.io/$$REPO/glauth:$$TAG -t ghcr.io/$$REPO/glauth:latest -f docker/Dockerfile-standalone --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker && \
|
||||||
|
docker buildx build --tag $$REPO/glauth:$$TAG -t $$REPO/glauth:latest -f docker/Dockerfile-standalone --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker
|
||||||
|
|
||||||
releasedockerplugins:
|
builddockerplugins:
|
||||||
$(if $(TAG),,$(error Must set TAG))
|
$(if $(TAG),,$(error ❌ Must set TAG))
|
||||||
$(if $(REPO),,$(error Must set REPO - glauth or other))
|
$(if $(REPO),,$(error ❌ Must set REPO - glauth or other))
|
||||||
@mkdir -p docker/assets/linux/amd64 docker/assets/linux/arm64 docker/assets/linux/arm/v7 && \
|
@mkdir -p docker/assets/linux/amd64 docker/assets/linux/arm64 docker/assets/linux/arm/v7 docker/assets/linux/riscv64 && \
|
||||||
cp -f bin/sqlite-linux-amd64.so docker/assets/linux/amd64/sqlite.so && \
|
cp -f bin/sqlite-linux-amd64.so docker/assets/linux/amd64/sqlite.so && \
|
||||||
cp -f bin/sqlite-linux-arm64.so docker/assets/linux/arm64/sqlite.so && \
|
cp -f bin/sqlite-linux-arm64.so docker/assets/linux/arm64/sqlite.so && \
|
||||||
cp -f bin/sqlite-linux-arm-7.so docker/assets/linux/arm/v7/sqlite.so && \
|
cp -f bin/sqlite-linux-arm-7.so docker/assets/linux/arm/v7/sqlite.so && \
|
||||||
|
cp -f bin/sqlite-linux-riscv64.so docker/assets/linux/riscv64/sqlite.so && \
|
||||||
cp -f bin/mysql-linux-amd64.so docker/assets/linux/amd64/mysql.so && \
|
cp -f bin/mysql-linux-amd64.so docker/assets/linux/amd64/mysql.so && \
|
||||||
cp -f bin/mysql-linux-arm64.so docker/assets/linux/arm64/mysql.so && \
|
cp -f bin/mysql-linux-arm64.so docker/assets/linux/arm64/mysql.so && \
|
||||||
cp -f bin/mysql-linux-arm-7.so docker/assets/linux/arm/v7/mysql.so && \
|
cp -f bin/mysql-linux-arm-7.so docker/assets/linux/arm/v7/mysql.so && \
|
||||||
|
cp -f bin/mysql-linux-riscv64.so docker/assets/linux/riscv64/mysql.so && \
|
||||||
cp -f bin/postgres-linux-amd64.so docker/assets/linux/amd64/postgres.so && \
|
cp -f bin/postgres-linux-amd64.so docker/assets/linux/amd64/postgres.so && \
|
||||||
cp -f bin/postgres-linux-arm64.so docker/assets/linux/arm64/postgres.so && \
|
cp -f bin/postgres-linux-arm64.so docker/assets/linux/arm64/postgres.so && \
|
||||||
cp -f bin/postgres-linux-arm-7.so docker/assets/linux/arm/v7/postgres.so && \
|
cp -f bin/postgres-linux-arm-7.so docker/assets/linux/arm/v7/postgres.so && \
|
||||||
docker buildx build --tag $$REPO/glauth-plugins:$$TAG -t $$REPO/glauth-plugins:latest -f docker/Dockerfile-plugins --platform linux/amd64,linux/arm64,linux/arm/v7 --push docker
|
cp -f bin/postgres-linux-riscv64.so docker/assets/linux/riscv64/postgres.so && \
|
||||||
|
docker buildx build --tag ghcr.io/$$REPO/glauth-plugins:$$TAG -t ghcr.io/$$REPO/glauth-plugins:latest -f docker/Dockerfile-plugins --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker && \
|
||||||
|
docker buildx build --tag $$REPO/glauth-plugins:$$TAG -t $$REPO/glauth-plugins:latest -f docker/Dockerfile-plugins --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker
|
||||||
|
|
||||||
releasedocker: releasedockermain releasedockerplugins
|
builddocker: _checkdockerauth builddockermain builddockerplugins
|
||||||
|
|
||||||
|
buildeverything: prepbuild forget-embed _buildplugins _buildmain testplugin remember-embed _buildmainembeds builddocker
|
||||||
|
|
||||||
#testdocker: @ run integration test using docker
|
#testdocker: @ run integration test using docker
|
||||||
testdocker:
|
testdocker:
|
||||||
@@ -247,4 +385,8 @@ testdocker:
|
|||||||
docker rm glauth-test && \
|
docker rm glauth-test && \
|
||||||
echo "==> Testing complete."
|
echo "==> Testing complete."
|
||||||
|
|
||||||
.PHONY: all prepbuild run test fast binaries setup getdeps runtest updatetest format devrun linux386 linuxamd64 linuxarm linuxarm64 darwinamd64 darwinarm64 win386 winamd64 verify pull-plugin pull-base-plugins forget-plugin forget-plugins releasemain releaseplugin release releaseplugins releasedockermain releaserdockerplugins releasedocker testdocker
|
.PHONY: all \
|
||||||
|
prepbuild run test fast binaries setup getdeps runtest updatetest format devrun \
|
||||||
|
linux386 linuxamd64 linuxarm linuxarm64 linuxriscv64 darwinamd64 darwinarm64 win386 winamd64 verify \
|
||||||
|
pull-plugin pull-base-plugins forget-plugin forget-plugins buildmain buildplugin build \
|
||||||
|
buildplugins builddockermain builddockerplugins builddocker testdocker testplugin buildeverything
|
||||||
|
|||||||
@@ -10,8 +10,17 @@ RUN apk add --no-cache git make busybox-static dumb-init
|
|||||||
# Run Step
|
# Run Step
|
||||||
#################
|
#################
|
||||||
|
|
||||||
FROM gcr.io/distroless/base-debian11 as run
|
FROM gcr.io/distroless/base-debian13 as run
|
||||||
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>"
|
|
||||||
|
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>" \
|
||||||
|
org.opencontainers.image.title="GLauth" \
|
||||||
|
org.opencontainers.image.description="A simple LDAP server for development, home use, or CI pipelines" \
|
||||||
|
org.opencontainers.image.authors="Ben Yanke, Jörn Friedrich Dreyer, Chris F Ravenscroft" \
|
||||||
|
org.opencontainers.image.source="https://github.com/glauth/glauth" \
|
||||||
|
org.opencontainers.image.licenses="MIT" \
|
||||||
|
org.opencontainers.image.version="latest" \
|
||||||
|
org.opencontainers.image.url="https://github.com/glauth/glauth"
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
# Copy docker specific scripts from build container
|
# Copy docker specific scripts from build container
|
||||||
|
|||||||
@@ -10,8 +10,17 @@ RUN apk add --no-cache git make busybox-static dumb-init
|
|||||||
# Run Step
|
# Run Step
|
||||||
#################
|
#################
|
||||||
|
|
||||||
FROM gcr.io/distroless/base-debian11 as run
|
FROM gcr.io/distroless/base-debian13 as run
|
||||||
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>"
|
|
||||||
|
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>" \
|
||||||
|
org.opencontainers.image.title="GLauth" \
|
||||||
|
org.opencontainers.image.description="A simple LDAP server for development, home use, or CI pipelines" \
|
||||||
|
org.opencontainers.image.authors="Ben Yanke, Jörn Friedrich Dreyer, Chris F Ravenscroft" \
|
||||||
|
org.opencontainers.image.source="https://github.com/glauth/glauth" \
|
||||||
|
org.opencontainers.image.licenses="MIT" \
|
||||||
|
org.opencontainers.image.version="latest" \
|
||||||
|
org.opencontainers.image.url="https://github.com/glauth/glauth"
|
||||||
|
|
||||||
ARG TARGETPLATFORM
|
ARG TARGETPLATFORM
|
||||||
|
|
||||||
# Copy docker specific scripts from build container
|
# Copy docker specific scripts from build container
|
||||||
|
|||||||
+18
-4
@@ -143,20 +143,32 @@ func startService() {
|
|||||||
startConfigWatcher()
|
startConfigWatcher()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
var tlsConfig *tls.Config
|
var starttlsConfig *tls.Config
|
||||||
if c := activeConfig.LDAP; c.Enabled && c.TLS {
|
if c := activeConfig.LDAP; c.Enabled && c.TLS {
|
||||||
// TODO check if tls params are string or bytes and change config accordingly
|
// TODO check if tls params are string or bytes and change config accordingly
|
||||||
tlsConfig, err = _tls.MakeTLS([]byte(c.TLSCert), []byte(c.TLSKey))
|
starttlsConfig, err = _tls.MakeTLS([]byte(c.TLSCert), []byte(c.TLSKey), c.LegacyTLS)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn().Err(err).Msg("unable to configure TLS, proceeding without....StartTLS won't be supported")
|
log.Warn().Err(err).Msg("unable to configure TLS for StartTLS: StartTLS won't be supported")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ldapstlsConfig *tls.Config
|
||||||
|
if c := activeConfig.LDAPS; c.Enabled {
|
||||||
|
// TODO check if tls params are string or bytes and change config accordingly
|
||||||
|
ldapstlsConfig, err = _tls.MakeTLS([]byte(c.Cert), []byte(c.Key), c.LegacyTLS)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Msg("unable to configure TLS for LDAPS")
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := server.NewServer(
|
s, err := server.NewServer(
|
||||||
server.Logger(log),
|
server.Logger(log),
|
||||||
server.Config(activeConfig),
|
server.Config(activeConfig),
|
||||||
server.TLSConfig(tlsConfig),
|
server.StartTLSConfig(starttlsConfig),
|
||||||
|
server.LDAPSTLSConfig(ldapstlsConfig),
|
||||||
server.Monitor(monitor),
|
server.Monitor(monitor),
|
||||||
server.Tracer(tracer),
|
server.Tracer(tracer),
|
||||||
)
|
)
|
||||||
@@ -224,6 +236,8 @@ func startConfigWatcher() {
|
|||||||
isChanged = true
|
isChanged = true
|
||||||
} else if event.Op&fsnotify.Remove == fsnotify.Remove { // vim edit file with rename/remove
|
} else if event.Op&fsnotify.Remove == fsnotify.Remove { // vim edit file with rename/remove
|
||||||
isChanged, isRemoved = true, true
|
isChanged, isRemoved = true, true
|
||||||
|
} else if event.Op&fsnotify.Create == fsnotify.Create { // only when watching a directory
|
||||||
|
isChanged = true
|
||||||
}
|
}
|
||||||
case err := <-watcher.Errors:
|
case err := <-watcher.Errors:
|
||||||
log.Error().Err(err).Msg("watcher error")
|
log.Error().Err(err).Msg("watcher error")
|
||||||
|
|||||||
+296
-140
@@ -1,11 +1,20 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/glauth/ldap"
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testEnv struct {
|
type testEnv struct {
|
||||||
@@ -23,10 +32,31 @@ type testEnv struct {
|
|||||||
checkemployeetype string
|
checkemployeetype string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func glauthBinary() string {
|
||||||
|
if binary := os.Getenv("GLAUTH_TEST_BINARY"); binary != "" {
|
||||||
|
return binary
|
||||||
|
}
|
||||||
|
|
||||||
|
qualified := filepath.Join("bin", runtime.GOOS+runtime.GOARCH, "glauth")
|
||||||
|
if _, err := os.Stat(qualified); err == nil {
|
||||||
|
return qualified
|
||||||
|
}
|
||||||
|
|
||||||
|
distribution := filepath.Join("bin", "glauth-"+runtime.GOOS+"-"+runtime.GOARCH)
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
distribution += ".exe"
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(distribution); err == nil {
|
||||||
|
return distribution
|
||||||
|
}
|
||||||
|
|
||||||
|
return "bin/glauth"
|
||||||
|
}
|
||||||
|
|
||||||
func TestProperBuild(t *testing.T) {
|
func TestProperBuild(t *testing.T) {
|
||||||
info, err := os.Stat("bin/glauth")
|
info, err := os.Stat(glauthBinary())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
mode := uint32(info.Mode())
|
mode := uint32(info.Mode())
|
||||||
if mode&0b001001001 == 0 {
|
if mode&0b001001001 == 0 {
|
||||||
@@ -34,147 +64,229 @@ func TestProperBuild(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigBackendRejectsPasswordlessUserBinds(t *testing.T) {
|
||||||
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
port := listener.Addr().(*net.TCPAddr).Port
|
||||||
|
listener.Close()
|
||||||
|
|
||||||
|
configPath := filepath.Join(t.TempDir(), "passwordless.cfg")
|
||||||
|
config := fmt.Sprintf(`debug = false
|
||||||
|
|
||||||
|
[ldap]
|
||||||
|
enabled = true
|
||||||
|
listen = "127.0.0.1:%d"
|
||||||
|
tls = false
|
||||||
|
|
||||||
|
[ldaps]
|
||||||
|
enabled = false
|
||||||
|
|
||||||
|
[backend]
|
||||||
|
datastore = "config"
|
||||||
|
baseDN = "dc=glauth,dc=com"
|
||||||
|
|
||||||
|
[behaviors]
|
||||||
|
LimitFailedBinds = false
|
||||||
|
|
||||||
|
[[groups]]
|
||||||
|
name = "svc"
|
||||||
|
gidnumber = 5501
|
||||||
|
|
||||||
|
[[users]]
|
||||||
|
name = "nopass"
|
||||||
|
uidnumber = 5001
|
||||||
|
primarygroup = 5501
|
||||||
|
[[users.capabilities]]
|
||||||
|
action = "search"
|
||||||
|
object = "*"
|
||||||
|
`, port)
|
||||||
|
if err := os.WriteFile(configPath, []byte(config), 0o600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
svc := startSvc(t, fmt.Sprintf("127.0.0.1:%d", port), glauthBinary(), "-c", configPath)
|
||||||
|
defer stopSvc(svc)
|
||||||
|
|
||||||
|
bindDN := "cn=nopass,dc=glauth,dc=com"
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
password string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{name: "arbitrary password", password: "definitely-wrong", want: "exit status 49"},
|
||||||
|
{name: "empty password", password: "", want: "exit status 53"},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got := runAndSelect(t, getFirst, "ldapsearch", "-LLL", "-H", fmt.Sprintf("ldap://127.0.0.1:%d", port), "-D", bindDN, "-w", tc.password, "-x", "-b", "dc=glauth,dc=com", "(cn=nopass)")
|
||||||
|
if got != tc.want {
|
||||||
|
t.Fatalf("bind result = %q, want %q", got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ldapOnlyConfig(t *testing.T, source string) string {
|
||||||
|
t.Helper()
|
||||||
|
data, err := os.ReadFile(source)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
contents := string(data)
|
||||||
|
sectionMarker := "\n[ldaps]\n"
|
||||||
|
markerStart := strings.Index(contents, sectionMarker)
|
||||||
|
if markerStart < 0 {
|
||||||
|
t.Fatalf("%s has no [ldaps] section", source)
|
||||||
|
}
|
||||||
|
start := markerStart + 1
|
||||||
|
relEnd := strings.Index(contents[start+len("[ldaps]"):], "\n[")
|
||||||
|
if relEnd < 0 {
|
||||||
|
t.Fatalf("%s has no section after [ldaps]", source)
|
||||||
|
}
|
||||||
|
end := start + len("[ldaps]") + relEnd
|
||||||
|
section := contents[start:end]
|
||||||
|
sectionWithoutLDAPS := strings.Replace(section, "enabled = true", "enabled = false", 1)
|
||||||
|
if section == sectionWithoutLDAPS {
|
||||||
|
t.Fatalf("%s [ldaps] section does not enable LDAPS", source)
|
||||||
|
}
|
||||||
|
|
||||||
|
contents = contents[:start] + sectionWithoutLDAPS + contents[end:]
|
||||||
|
path := filepath.Join(t.TempDir(), filepath.Base(source))
|
||||||
|
if err := os.WriteFile(path, []byte(contents), 0o600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
func batteryOfTests(t *testing.T, env *testEnv) {
|
func batteryOfTests(t *testing.T, env *testEnv) {
|
||||||
|
// We aren't checking that "github.com/pquerna/otp/totp" creates correct values.
|
||||||
|
// That's what their own tests are for.
|
||||||
|
// We are checking that the totp code gets through glauth code successfully
|
||||||
|
otpvalue, err := totp.GenerateCode("3hnvnk4ycv44glzigd6s25j4dougs3rk", time.Now())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Failed to generate totp code:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const addr = "ldap://127.0.0.1:3893"
|
||||||
|
bind := func(dn, password string, rest ...string) []string {
|
||||||
|
return append([]string{"-LLL", "-H", addr, "-D", dn, "-w", password, "-x"}, rest...)
|
||||||
|
}
|
||||||
|
svc := func(rest ...string) []string { return bind(env.svcdn, "mysecret", rest...) }
|
||||||
|
otp := func(password string) []string {
|
||||||
|
return bind(env.otpdn, password, "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
inSuperheros = "should find them in the 'superheros' group"
|
||||||
|
listFromUser = "should get a list starting with the 'hackers' user"
|
||||||
|
badCreds = "should get 'Invalid credentials(49)'"
|
||||||
|
)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
Name string
|
name string
|
||||||
Path string
|
skip bool
|
||||||
Check func(t testing.TB)
|
args []string
|
||||||
|
line func(string) string
|
||||||
|
want string
|
||||||
|
msg string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Name: "searching for the 'hackers' user",
|
name: "searching for the 'hackers' user",
|
||||||
Check: func(t testing.TB) {
|
args: svc("-bdc=glauth,dc=com", "cn=hackers"),
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
want: env.expectedaccount,
|
||||||
if got, want := out, env.expectedaccount; got != want {
|
msg: inSuperheros,
|
||||||
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "searching for the 'hackers' user without binding with a group",
|
name: "searching for the 'hackers' user without binding with a group",
|
||||||
Check: func(t testing.TB) {
|
skip: env.svcdnnogroup == "",
|
||||||
if env.svcdnnogroup == "" {
|
args: bind(env.svcdnnogroup, "mysecret", "-bdc=glauth,dc=com", "cn=hackers"),
|
||||||
t.SkipNow()
|
want: env.expectedaccount,
|
||||||
}
|
msg: inSuperheros,
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdnnogroup, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
|
||||||
if got, want := out, env.expectedaccount; got != want {
|
|
||||||
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "searching for the 'hackers' user after binding using the account's UPN",
|
name: "searching for the 'hackers' user after binding using the account's UPN",
|
||||||
Check: func(t testing.TB) {
|
skip: !env.checkbindUPN,
|
||||||
if !env.checkbindUPN {
|
args: bind("serviceuser@example.com", "mysecret", "-bdc=glauth,dc=com", "cn=hackers"),
|
||||||
t.SkipNow()
|
want: env.expectedaccount,
|
||||||
}
|
msg: inSuperheros,
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", "serviceuser@example.com", "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
|
||||||
if got, want := out, env.expectedaccount; got != want {
|
|
||||||
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "querying the root SDE",
|
name: "querying the root SDE",
|
||||||
Check: func(t testing.TB) {
|
args: svc("-s", "base", "(objectclass=*)"),
|
||||||
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-s", "base", "(objectclass=*)")
|
line: getSecond,
|
||||||
if got, want := out, env.expectedinfo; got != want {
|
want: env.expectedinfo,
|
||||||
t.Fatalf("should get some meta information\ngot: %s\nwant: %s", got, want)
|
msg: "should get some meta information",
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "querying the root SDE anonymously without authorizing in config file",
|
name: "querying the root SDE anonymously without authorizing in config file",
|
||||||
Check: func(t testing.TB) {
|
skip: !env.checkanonymousrootDSE,
|
||||||
if !env.checkanonymousrootDSE {
|
args: []string{"-LLL", "-H", addr, "-x", "-s", "base", "(objectclass=*)"},
|
||||||
t.SkipNow()
|
want: "exit status 50",
|
||||||
}
|
msg: "should get error 50",
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-x", "-s", "base", "(objectclass=*)")
|
|
||||||
if got, want := out, "exit status 50"; got != want {
|
|
||||||
t.Fatalf("should get error 50\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "enumerating posix groups",
|
name: "enumerating posix groups",
|
||||||
Check: func(t testing.TB) {
|
args: svc("-bdc=glauth,dc=com", "(objectclass=posixgroup)"),
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(objectclass=posixgroup)")
|
want: env.expectedgroup,
|
||||||
if got, want := out, env.expectedgroup; got != want {
|
msg: "should get a list starting with the 'superheros' group",
|
||||||
t.Fatalf("should get a list starting with the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "searching for members of the 'superheros' group",
|
name: "searching for members of the 'superheros' group",
|
||||||
Check: func(t testing.TB) {
|
args: svc("-bdc=glauth,dc=com", "(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com)"),
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com)")
|
want: env.expectedfirstaccount,
|
||||||
if got, want := out, env.expectedfirstaccount; got != want {
|
msg: listFromUser,
|
||||||
t.Fatalf("should get a list starting with the 'hackers' user\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "performing a complex search for members of 'superheros' group",
|
name: "performing a complex search for members of 'superheros' group",
|
||||||
Check: func(t testing.TB) {
|
args: svc("-bdc=glauth,dc=com", "(&(objectClass=*)(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com))"),
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(&(objectClass=*)(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com))")
|
want: env.expectedfirstaccount,
|
||||||
if got, want := out, env.expectedfirstaccount; got != want {
|
msg: listFromUser,
|
||||||
t.Fatalf("should get a list starting with the 'hackers' user\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "searching for the 'hacker' user using a TOTP-enabled account",
|
name: "searching for the 'hacker' user using a TOTP-enabled account",
|
||||||
Check: func(t testing.TB) {
|
skip: !env.checkTOTP,
|
||||||
if !env.checkTOTP {
|
args: otp("mysecret" + otpvalue),
|
||||||
t.SkipNow()
|
want: env.scopedaccount,
|
||||||
}
|
msg: inSuperheros,
|
||||||
otpvalue := doRunGetFirst(RD, "oathtool", "--totp", "-b", "-d", "6", "3hnvnk4ycv44glzigd6s25j4dougs3rk")
|
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret"+otpvalue, "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
|
|
||||||
if got, want := out, env.scopedaccount; got != want {
|
|
||||||
t.Fatalf("should find them in in the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "searching for the 'hacker' user using a TOTP-enabled account and no value",
|
name: "searching for the 'hacker' user using a TOTP-enabled account and no value",
|
||||||
Check: func(t testing.TB) {
|
skip: !env.checkTOTP,
|
||||||
if !env.checkTOTP {
|
args: otp("mysecret"),
|
||||||
t.SkipNow()
|
want: "exit status 49",
|
||||||
}
|
msg: badCreds,
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
|
|
||||||
if got, want := out, "exit status 49"; got != want {
|
|
||||||
t.Fatalf("should get 'Invalid credentials(49)'\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "searching for the 'hacker' user using a TOTP-enabled account and the wrong value",
|
name: "searching for the 'hacker' user using a TOTP-enabled account and the wrong value",
|
||||||
Check: func(t testing.TB) {
|
skip: !env.checkTOTP,
|
||||||
if !env.checkTOTP {
|
args: otp("mysecret123456"),
|
||||||
t.SkipNow()
|
want: "exit status 49",
|
||||||
}
|
msg: badCreds,
|
||||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret123456", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
|
|
||||||
if got, want := out, "exit status 49"; got != want {
|
|
||||||
t.Fatalf("should get 'Invalid credentials(49)'\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "searching for the 'hacker' user",
|
name: "searching for the 'hacker' user",
|
||||||
Check: func(t testing.TB) {
|
skip: env.checkemployeetype == "",
|
||||||
if env.checkemployeetype == "" {
|
args: svc("-bdc=glauth,dc=com", env.checkemployeetype, "employeetype"),
|
||||||
t.SkipNow()
|
line: getSecond,
|
||||||
}
|
want: "employeetype: Intern",
|
||||||
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", env.checkemployeetype, "employeetype")
|
msg: "type should be 'Intern'",
|
||||||
if got, want := out, "employeetype: Intern"; got != want {
|
|
||||||
t.Fatalf("type should be 'Intern'\ngot: %s\nwant: %s", got, want)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
tc.Check(t)
|
if tc.skip {
|
||||||
|
t.SkipNow()
|
||||||
|
}
|
||||||
|
line := tc.line
|
||||||
|
if line == nil {
|
||||||
|
line = getFirst
|
||||||
|
}
|
||||||
|
if got := runAndSelect(t, line, "ldapsearch", tc.args...); got != tc.want {
|
||||||
|
t.Fatalf("%s\ngot: %s\nwant: %s", tc.msg, got, tc.want)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,14 +307,15 @@ func TestSampleSimple(t *testing.T) {
|
|||||||
checkemployeetype: "cn=hackers",
|
checkemployeetype: "cn=hackers",
|
||||||
}
|
}
|
||||||
|
|
||||||
svc := startSvc(SD, "bin/glauth", "-c", "sample-simple.cfg")
|
svc := startSvc(t, "127.0.0.1:3893", glauthBinary(), "-c", ldapOnlyConfig(t, "sample-simple.cfg"))
|
||||||
batteryOfTests(t, &env)
|
batteryOfTests(t, &env)
|
||||||
stopSvc(svc)
|
stopSvc(svc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSQLitePlugin(t *testing.T) {
|
func TestSQLitePlugin(t *testing.T) {
|
||||||
matchingLibrary := doRunGetFirst(RD, "ls", "bin/sqlite.so")
|
_, err := os.Stat("bin/sqlite.so")
|
||||||
if matchingLibrary != "bin/sqlite.so" {
|
if err != nil {
|
||||||
|
t.Log("Unable to find sqlite plugin")
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,14 +334,20 @@ func TestSQLitePlugin(t *testing.T) {
|
|||||||
checkemployeetype: "",
|
checkemployeetype: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
svc := startSvc(SD, "bin/glauth", "-c", "pkg/plugins/glauth-sqlite/sample-database.cfg")
|
svc := startSvc(t, "127.0.0.1:3893", glauthBinary(), "-c", "pkg/plugins/glauth-sqlite/sample-database.cfg")
|
||||||
batteryOfTests(t, &env)
|
batteryOfTests(t, &env)
|
||||||
stopSvc(svc)
|
stopSvc(svc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLdapInjection(t *testing.T) {
|
func TestLdapInjection(t *testing.T) {
|
||||||
matchingContainers := doRunGetFirst(RD, "sh", "-c", "docker ps | grep ldap-service | wc -l")
|
out, err := doRun("sh", "-c", "docker ps | grep ldap-service | wc -l")
|
||||||
|
if err != nil {
|
||||||
|
t.Log("Unable to find docker container:", out)
|
||||||
|
t.SkipNow()
|
||||||
|
}
|
||||||
|
matchingContainers := getFirst(out)
|
||||||
if matchingContainers != "1" {
|
if matchingContainers != "1" {
|
||||||
|
t.Log("Unable to find docker container:", out)
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,52 +366,89 @@ func TestLdapInjection(t *testing.T) {
|
|||||||
checkemployeetype: "",
|
checkemployeetype: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
svc := startSvc(SD, "bin/glauth", "-c", "sample-ldap-injection.cfg")
|
svc := startSvc(t, "127.0.0.1:3893", glauthBinary(), "-c", "sample-ldap-injection.cfg")
|
||||||
batteryOfTests(t, &env)
|
batteryOfTests(t, &env)
|
||||||
stopSvc(svc)
|
stopSvc(svc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----=============================================================================----
|
// -----=============================================================================----
|
||||||
|
func waitForPort(host string, timeout time.Duration) error {
|
||||||
const SD = 3 // Start Delay
|
start := time.Now()
|
||||||
const RD = 2 // Response Delay
|
for {
|
||||||
|
conn, err := ldap.Dial("tcp", host)
|
||||||
func startSvc(delay time.Duration, name string, arg ...string) *exec.Cmd {
|
if err == nil {
|
||||||
cmd := exec.Command(name, arg...)
|
err = conn.Bind("_", "_")
|
||||||
cmd.Start()
|
if err == nil {
|
||||||
if delay != 0 {
|
conn.Close()
|
||||||
time.Sleep(time.Second * delay)
|
return fmt.Errorf("Successfully authenticated to glauth. This should not happen")
|
||||||
|
}
|
||||||
|
e := &ldap.Error{}
|
||||||
|
if errors.As(err, &e) && e.ResultCode == 49 {
|
||||||
|
conn.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
// We have an error, it's probably a connection error or an error saying that ldap isn't setup yet
|
||||||
|
// try again
|
||||||
|
}
|
||||||
|
if time.Since(start) > timeout {
|
||||||
|
return fmt.Errorf("timeout waiting for port %s: %w", host, err)
|
||||||
|
}
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func startSvc(t *testing.T, addr string, name string, arg ...string) *exec.Cmd {
|
||||||
|
cmd := exec.Command(name, arg...)
|
||||||
|
cmd.Stderr = t.Output()
|
||||||
|
cmd.Stdout = t.Output()
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
t.Fatal("Failed to start glauth:", err)
|
||||||
|
}
|
||||||
|
if err := waitForPort(addr, time.Second*2); err != nil {
|
||||||
|
t.Fatal("Failed to wait for glauth to start:", err)
|
||||||
|
}
|
||||||
|
// the port is listening but the ldap server may not be accepting connections yet
|
||||||
|
// TODO: make glauth listen as the last part of the initialization that way as soon as it listens it can process connections
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopSvc(svc *exec.Cmd) {
|
func stopSvc(svc *exec.Cmd) {
|
||||||
svc.Process.Kill()
|
svc.Process.Kill()
|
||||||
|
svc.Process.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func doRunGetFirst(delay time.Duration, name string, arg ...string) string {
|
func getFirst(output string) string {
|
||||||
out := strings.SplitN(doRun(delay, name, arg...), "\n", 2)
|
out := strings.SplitN(output, "\n", 2)
|
||||||
if out == nil || len(out) < 1 {
|
if len(out) < 1 {
|
||||||
return "*fail*"
|
return "*fail*"
|
||||||
}
|
}
|
||||||
return out[0]
|
return out[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func doRunGetSecond(delay time.Duration, name string, arg ...string) string {
|
func getSecond(output string) string {
|
||||||
out := strings.SplitN(doRun(delay, name, arg...), "\n", 3)
|
out := strings.SplitN(output, "\n", 3)
|
||||||
if out == nil || len(out) < 2 {
|
if len(out) < 2 {
|
||||||
return "*fail*"
|
return "*fail*"
|
||||||
}
|
}
|
||||||
return out[1]
|
return out[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func doRun(delay time.Duration, name string, arg ...string) string {
|
func doRun(name string, arg ...string) (string, error) {
|
||||||
out, err := exec.Command(name, arg...).Output()
|
out, err := exec.Command(name, arg...).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return string(bytes.TrimSpace(out)), err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(bytes.TrimSpace(out)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runAndSelect(t testing.TB, pick func(string) string, name string, arg ...string) string {
|
||||||
|
t.Helper()
|
||||||
|
out, err := doRun(name, arg...)
|
||||||
|
if err != nil {
|
||||||
|
t.Log(out)
|
||||||
return err.Error()
|
return err.Error()
|
||||||
}
|
}
|
||||||
if delay != 0 {
|
return pick(out)
|
||||||
time.Sleep(time.Second * delay)
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(string(out))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module github.com/glauth/glauth/v2
|
module github.com/glauth/glauth/v2
|
||||||
|
|
||||||
go 1.21
|
go 1.25.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.3.2
|
github.com/BurntSushi/toml v1.3.2
|
||||||
@@ -8,7 +8,7 @@ require (
|
|||||||
github.com/arl/statsviz v0.6.0
|
github.com/arl/statsviz v0.6.0
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||||
github.com/fsnotify/fsnotify v1.7.0
|
github.com/fsnotify/fsnotify v1.7.0
|
||||||
github.com/glauth/ldap v0.0.0-20231210225823-b9bf4d1baf6e
|
github.com/glauth/ldap v0.0.0-20240419171521-1f14f5c1b4ad
|
||||||
github.com/jinzhu/copier v0.4.0
|
github.com/jinzhu/copier v0.4.0
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/prometheus/client_golang v1.18.0
|
github.com/prometheus/client_golang v1.18.0
|
||||||
@@ -16,16 +16,16 @@ require (
|
|||||||
github.com/rs/zerolog v1.31.0
|
github.com/rs/zerolog v1.31.0
|
||||||
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3
|
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3
|
||||||
github.com/yaegashi/msgraph.go v0.1.4
|
github.com/yaegashi/msgraph.go v0.1.4
|
||||||
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1
|
go.opentelemetry.io/contrib/propagators/jaeger v1.46.0
|
||||||
go.opentelemetry.io/otel v1.21.0
|
go.opentelemetry.io/otel v1.46.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0
|
||||||
go.opentelemetry.io/otel/sdk v1.21.0
|
go.opentelemetry.io/otel/sdk v1.46.0
|
||||||
go.opentelemetry.io/otel/trace v1.21.0
|
go.opentelemetry.io/otel/trace v1.46.0
|
||||||
go.uber.org/mock v0.4.0
|
go.uber.org/mock v0.4.0
|
||||||
golang.org/x/crypto v0.18.0
|
golang.org/x/crypto v0.55.0
|
||||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b
|
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,13 +33,15 @@ require (
|
|||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/go-logr/logr v1.3.0 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.4 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||||
@@ -47,13 +49,14 @@ require (
|
|||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/rickb777/date v1.12.4 // indirect
|
github.com/rickb777/date v1.12.4 // indirect
|
||||||
github.com/rickb777/plural v1.2.0 // indirect
|
github.com/rickb777/plural v1.2.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.21.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
go.opentelemetry.io/otel/metric v1.46.0 // indirect
|
||||||
golang.org/x/net v0.17.0 // indirect
|
go.opentelemetry.io/proto/otlp v1.11.0 // indirect
|
||||||
golang.org/x/sys v0.16.0 // indirect
|
golang.org/x/net v0.58.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/sys v0.47.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
|
golang.org/x/text v0.41.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688 // indirect
|
||||||
google.golang.org/grpc v1.59.0 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/grpc v1.83.1 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.12 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,8 +11,12 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8
|
|||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
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/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
@@ -21,13 +25,16 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh
|
|||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
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-20240419171521-1f14f5c1b4ad h1:2ERGXiofR9ISXg4evamCngs2EeuMhVJRuDwWGa6bS6s=
|
||||||
github.com/glauth/ldap v0.0.0-20231210225823-b9bf4d1baf6e/go.mod h1:EHMcFuVSIs0huelHOhaGtj9IKMB/Dmxo+jDheipjtYA=
|
github.com/glauth/ldap v0.0.0-20240419171521-1f14f5c1b4ad/go.mod h1:5ueZMujvJ5nuYPyBj6uQTPV4R1YshboRa/osaP4Emfs=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.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 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
|
||||||
|
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
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/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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
@@ -37,14 +44,23 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
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 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
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/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
|
github.com/gorilla/websocket v1.5.3/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 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 h1:/Tnpcb2E0Pz/tN9s3bfEY2Q8ePCEX9iuS+cneUwncnw=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0/go.mod h1:zOBXOsUaBSjKgmH4OGzV1esUpR3oUSCPYVd2cUBjKYY=
|
||||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
@@ -91,26 +107,64 @@ github.com/yaegashi/msgraph.go v0.1.4/go.mod h1:vgeYhHa5skJt/3lTyjGXThTZhwbhRnGo
|
|||||||
github.com/yaegashi/wtz.go v0.0.2/go.mod h1:nOLA5QXsmdkRxBkP5tljhua13ADHCKirLBrzPf4PEJc=
|
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.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1 h1:f4beMGDKiVzg9IcX7/VuWVy+oGdjx3dNJ72YehmtY5k=
|
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/contrib/propagators/jaeger v1.21.1/go.mod h1:U9jhkEl8d1LL+QXY7q3kneJWJugiN3kZJV2OWz3hkBY=
|
||||||
|
go.opentelemetry.io/contrib/propagators/jaeger v1.46.0 h1:uxl0SGcmuBkHj/Adl9oftEAyiawQBPL5RzMAmt/Yvq4=
|
||||||
|
go.opentelemetry.io/contrib/propagators/jaeger v1.46.0/go.mod h1:LiOkxCIvoLofmRps7f8l0NkBtmObnAyQ5trteFs6wj8=
|
||||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
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 v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
||||||
|
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||||
|
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||||
|
go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
|
||||||
|
go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
|
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 v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0 h1:OFnwLJr+pF3iHrlGSzbxyuo6/6HyBlnlN1CWEJmBVcw=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.46.0/go.mod h1:716wFneO0ov19A2beH5hjfh9AK5z/VWNAtDijp1Y0/g=
|
||||||
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 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/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 h1:qazEJlUOQzhCpzQpFETGby7EdqjI1wsd0W+6Gg1SCTU=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0/go.mod h1:fOD2Yefuxixkx3ahVNf0O/PERb6r4OlbxfATVnYvzCo=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0 h1:w53CDeOA/Kurp7yRsegSr6pbbr759dOvJ+yNmWM6Hxs=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.46.0/go.mod h1:BOmGMCbAtvcJiSJ+hLuhgPLdDbimnraSl8irz3iY8sY=
|
||||||
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 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/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 h1:lgh3PiVrRUWMLOVSkQicxzZll5NjF1r+AtsX1XRIHw0=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0/go.mod h1:5Cnhth3m/AgOeTgE3ex12pPmiu/gGtZit03kSzx9X7s=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0 h1:KrC1YrQeSt46ITMWAbgQx1M1eV1/1TKzttrBzymPmss=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.46.0/go.mod h1:zDSEzoEqsOrgBeGvH66KRgxh90VonFyJqBHA0Pk3+rM=
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec=
|
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/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.44.0 h1:bl2S7Ubua0Nms+D/gAmznQTd4dxxMA93aKbcpKqiTCs=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.44.0/go.mod h1:L0hRV50XdVIODHUfWEqGRCXQvj2rV82STVo12FMFBU0=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0 h1:KdRxPiAoMptR3vfWzvjjvutTsSiwbC2uG0496rzZNfo=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.46.0/go.mod h1:K/qSA+3G7Eovxi4K09wzrAgkWRnosS0DAOZeEpve7sM=
|
||||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
|
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/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
|
||||||
|
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||||
|
go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
|
||||||
|
go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
|
||||||
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
|
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/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.46.0/go.mod h1:GAERFXFt5SYCEB+YiKUbMBeza6UaDH7GmGOZEfh2gSM=
|
||||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
|
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/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
|
||||||
|
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||||
|
go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
|
||||||
|
go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
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.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||||
@@ -120,6 +174,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
|
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
|
||||||
|
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
|
||||||
|
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
|
||||||
|
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
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/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -130,6 +188,10 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
|
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
|
||||||
|
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
|
||||||
|
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
|
||||||
|
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -143,10 +205,18 @@ 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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||||
|
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||||
|
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||||
|
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||||
|
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
|
||||||
|
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
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-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-20200529172331-a64b76657301/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
@@ -161,14 +231,28 @@ google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ19
|
|||||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
|
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
|
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
|
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688 h1:ax2KzoSRIZU/M0cIxri3pKxy99vniH1PVxWC6si/eZI=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688/go.mod h1:1RJ9BQGyNdZwkGc1eTqkErfRZ6RJyYPHZo73BZ1vQqI=
|
||||||
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 h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 h1:cYNAzI2sUwhmCcoj9TxvihSrqsxt6uIkj3rDRhSDmW4=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA=
|
||||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
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/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||||
|
google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y=
|
||||||
|
google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
|
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
||||||
|
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b h1:tdSyAzD5FHJmZAZ13d5WexAo7YJkiyGphhzFfInMnDw=
|
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b h1:tdSyAzD5FHJmZAZ13d5WexAo7YJkiyGphhzFfInMnDw=
|
||||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b/go.mod h1:cE0dCGx2UfBTjLFlzEx4EXJUmoX6BXBoX9GjKOvqha4=
|
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b/go.mod h1:cE0dCGx2UfBTjLFlzEx4EXJUmoX6BXBoX9GjKOvqha4=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
|||||||
+47
-5
@@ -12,8 +12,29 @@ var (
|
|||||||
log zerolog.Logger
|
log zerolog.Logger
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var secureCipherSuites = []uint16{
|
||||||
|
// TLS 1.3 cipher suites (automatically used when TLS 1.3 is negotiated)
|
||||||
|
tls.TLS_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_AES_256_GCM_SHA384,
|
||||||
|
tls.TLS_CHACHA20_POLY1305_SHA256,
|
||||||
|
|
||||||
|
// TLS 1.2 ECDHE cipher suites (Forward Secrecy)
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||||
|
|
||||||
|
// Additional secure TLS 1.2 cipher suites (CBC with HMAC-SHA256)
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
// tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
// tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
||||||
|
}
|
||||||
|
|
||||||
// MakeTLS generates a tls.Config
|
// MakeTLS generates a tls.Config
|
||||||
func MakeTLS(clientCert, key []byte) (*tls.Config, error) {
|
func MakeTLS(clientCert, key []byte, legacy bool) (*tls.Config, error) {
|
||||||
if clientCert == nil && key == nil {
|
if clientCert == nil && key == nil {
|
||||||
return new(tls.Config), nil
|
return new(tls.Config), nil
|
||||||
}
|
}
|
||||||
@@ -55,11 +76,24 @@ func MakeTLS(clientCert, key []byte) (*tls.Config, error) {
|
|||||||
log.Debug().Interface("root.ca", rootCAs)
|
log.Debug().Interface("root.ca", rootCAs)
|
||||||
log.Debug().Interface("certificates", []tls.Certificate{cert})
|
log.Debug().Interface("certificates", []tls.Certificate{cert})
|
||||||
|
|
||||||
|
if legacy {
|
||||||
|
return &tls.Config{
|
||||||
|
RootCAs: rootCAs,
|
||||||
|
MinVersion: tls.VersionTLS10,
|
||||||
|
MaxVersion: tls.VersionTLS13,
|
||||||
|
PreferServerCipherSuites: true,
|
||||||
|
CipherSuites: nil,
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
return &tls.Config{
|
return &tls.Config{
|
||||||
RootCAs: rootCAs,
|
RootCAs: rootCAs,
|
||||||
MinVersion: tls.VersionTLS10,
|
MinVersion: tls.VersionTLS12,
|
||||||
MaxVersion: tls.VersionTLS13,
|
MaxVersion: tls.VersionTLS13,
|
||||||
Certificates: []tls.Certificate{cert},
|
PreferServerCipherSuites: true,
|
||||||
|
CipherSuites: secureCipherSuites,
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,3 +113,11 @@ func DecodePEM(certPEM []byte) tls.Certificate {
|
|||||||
|
|
||||||
return cert
|
return cert
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CipherSuiteNames(suites []uint16) []string {
|
||||||
|
var names []string
|
||||||
|
for _, suite := range suites {
|
||||||
|
names = append(names, tls.CipherSuiteName(suite))
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|||||||
+63
-25
@@ -179,11 +179,13 @@ func parseConfigFile(configFileLocation string, args map[string]interface{}) (*c
|
|||||||
// Patch with default values where not specified
|
// Patch with default values where not specified
|
||||||
for i := range cfg.Backends {
|
for i := range cfg.Backends {
|
||||||
if cfg.Backends[i].NameFormat == "" {
|
if cfg.Backends[i].NameFormat == "" {
|
||||||
cfg.Backends[i].NameFormat = "cn"
|
cfg.Backends[i].NameFormat = "cn,uid"
|
||||||
}
|
}
|
||||||
|
cfg.Backends[i].NameFormatAsArray = strings.Split(cfg.Backends[i].NameFormat, ",")
|
||||||
if cfg.Backends[i].GroupFormat == "" {
|
if cfg.Backends[i].GroupFormat == "" {
|
||||||
cfg.Backends[i].GroupFormat = "ou"
|
cfg.Backends[i].GroupFormat = "ou,cn"
|
||||||
}
|
}
|
||||||
|
cfg.Backends[i].GroupFormatAsArray = strings.Split(cfg.Backends[i].GroupFormat, ",")
|
||||||
if cfg.Backends[i].SSHKeyAttr == "" {
|
if cfg.Backends[i].SSHKeyAttr == "" {
|
||||||
cfg.Backends[i].SSHKeyAttr = "sshPublicKey"
|
cfg.Backends[i].SSHKeyAttr = "sshPublicKey"
|
||||||
}
|
}
|
||||||
@@ -221,9 +223,7 @@ func usersCustomAttributes(location string, config *config.Config) {
|
|||||||
x := make(map[string]interface{})
|
x := make(map[string]interface{})
|
||||||
|
|
||||||
for _, attribute := range user.CustomAttributes {
|
for _, attribute := range user.CustomAttributes {
|
||||||
err := md.PrimitiveDecode(attribute, x)
|
_ = md.PrimitiveDecode(attribute, x)
|
||||||
|
|
||||||
fmt.Println(err, x)
|
|
||||||
|
|
||||||
for k, v := range x {
|
for k, v := range x {
|
||||||
|
|
||||||
@@ -386,13 +386,47 @@ func validateConfig(cfg *config.Config) (*config.Config, error) {
|
|||||||
|
|
||||||
if cfg.LDAPS.Enabled {
|
if cfg.LDAPS.Enabled {
|
||||||
// LDAPS enabled - verify requirements (cert, key, listen)
|
// LDAPS enabled - verify requirements (cert, key, listen)
|
||||||
if len(cfg.LDAPS.Cert) == 0 || len(cfg.LDAPS.Key) == 0 {
|
|
||||||
return cfg, fmt.Errorf("LDAPS was enabled but no certificate or key were specified: please disable LDAPS or use the 'cert' and 'key' options")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cfg.LDAPS.Listen) == 0 {
|
if len(cfg.LDAPS.Listen) == 0 {
|
||||||
return cfg, fmt.Errorf("no LDAPS bind address was specified: please disable LDAPS or use the 'listen' option")
|
return cfg, fmt.Errorf("no LDAPS bind address was specified: please disable LDAPS or use the 'listen' option")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.LDAPS.Cert == "" && cfg.LDAPS.CertPath != "" {
|
||||||
|
byteData, err := os.ReadFile(cfg.LDAPS.CertPath)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("unable to read TLS certificate file")
|
||||||
|
}
|
||||||
|
cfg.LDAPS.Cert = string(byteData)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.LDAPS.Key == "" && cfg.LDAPS.KeyPath != "" {
|
||||||
|
byteData, err := os.ReadFile(cfg.LDAPS.KeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("unable to read TLS key file")
|
||||||
|
}
|
||||||
|
cfg.LDAPS.Key = string(byteData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ugly wart for backward compatibility
|
||||||
|
// In the olden times, we would simply say "please read from this file"
|
||||||
|
// This is now the role of the Path files.
|
||||||
|
if !strings.HasPrefix(cfg.LDAPS.Cert, "-----") {
|
||||||
|
byteData, err := os.ReadFile(cfg.LDAPS.Cert)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("unable to read TLS certificate file")
|
||||||
|
}
|
||||||
|
cfg.LDAPS.Cert = string(byteData)
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(cfg.LDAPS.Key, "-----") {
|
||||||
|
byteData, err := os.ReadFile(cfg.LDAPS.Key)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("unable to read TLS key file")
|
||||||
|
}
|
||||||
|
cfg.LDAPS.Key = string(byteData)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.LDAPS.Cert == "" || cfg.LDAPS.Key == "" {
|
||||||
|
return cfg, fmt.Errorf("LDAPS was enabled but no certificate or key were specified: please disable LDAPS or use the 'cert'/'key' or 'certpath'/'keypath' options")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.LDAP.Enabled {
|
if cfg.LDAP.Enabled {
|
||||||
@@ -401,24 +435,27 @@ func validateConfig(cfg *config.Config) (*config.Config, error) {
|
|||||||
return cfg, fmt.Errorf("no LDAP bind address was specified: please disable LDAP or use the 'listen' option")
|
return cfg, fmt.Errorf("no LDAP bind address was specified: please disable LDAP or use the 'listen' option")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.LDAP.TLS && cfg.LDAP.TLSCert == "" && cfg.LDAP.TLSCertPath != "" {
|
if cfg.LDAP.TLS {
|
||||||
byteData, err := os.ReadFile(cfg.LDAP.TLSCertPath)
|
if cfg.LDAP.TLSCert == "" && cfg.LDAP.TLSCertPath != "" {
|
||||||
cfg.LDAP.TLSCert = string(byteData)
|
byteData, err := os.ReadFile(cfg.LDAP.TLSCertPath)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("unable to read TLS certificate file")
|
||||||
|
}
|
||||||
|
cfg.LDAP.TLSCert = string(byteData)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if cfg.LDAP.TLSKey == "" && cfg.LDAP.TLSKeyPath != "" {
|
||||||
return cfg, fmt.Errorf("unable to read TLS certificate file")
|
byteData, err := os.ReadFile(cfg.LDAP.TLSKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("unable to read TLS key file")
|
||||||
|
}
|
||||||
|
cfg.LDAP.TLSKey = string(byteData)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.LDAP.TLSCert == "" || cfg.LDAP.TLSKey == "" {
|
||||||
|
return cfg, fmt.Errorf("StartTLS was enabled but no certificate or key were specified: please disable StartTLS or use the 'tlscert'/'tlskey' or 'tlscertpath'/'tlskeypath' options")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.LDAP.TLS && cfg.LDAP.TLSKey == "" && cfg.LDAP.TLSKeyPath != "" {
|
|
||||||
byteData, err := os.ReadFile(cfg.LDAP.TLSKeyPath)
|
|
||||||
cfg.LDAP.TLSKey = string(byteData)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return cfg, fmt.Errorf("unable to read TLS key file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//spew.Dump(cfg)
|
//spew.Dump(cfg)
|
||||||
@@ -430,8 +467,9 @@ func validateConfig(cfg *config.Config) (*config.Config, error) {
|
|||||||
case "ldap":
|
case "ldap":
|
||||||
case "owncloud":
|
case "owncloud":
|
||||||
case "plugin":
|
case "plugin":
|
||||||
|
case "embed":
|
||||||
default:
|
default:
|
||||||
return cfg, fmt.Errorf("invalid backend %s - must be 'config', 'ldap', 'owncloud' or 'plugin'", cfg.Backends[i].Datastore)
|
return cfg, fmt.Errorf("invalid backend %s - must be 'config', 'ldap', 'owncloud', 'plugin' or 'embed", cfg.Backends[i].Datastore)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ package version
|
|||||||
|
|
||||||
// Version is the tag of the latest release, it gets changed by the ci
|
// Version is the tag of the latest release, it gets changed by the ci
|
||||||
// process when a release is happening
|
// process when a release is happening
|
||||||
const Version = "v2.3.1" // x-release-please-version
|
const Version = "v2.5.4" // x-release-please-version
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
olcAccess: to dn.subtree="dc=glauth,dc=com"
|
||||||
|
by dn.exact="cn=admin,dc=glauth,dc=com" manage
|
||||||
|
by * break
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
dn: olcDatabase={1}mdb,cn=config
|
||||||
|
changetype: modify
|
||||||
|
delete: olcAccess
|
||||||
|
-
|
||||||
|
add: olcAccess
|
||||||
|
olcAccess: to attrs=userPassword,shadowLastChange by self write by dn="cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com" write by anonymous auth by * none
|
||||||
|
olcAccess: to * by self write by dn="cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com" write by users read by * none
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
dn: cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com
|
||||||
|
changetype: modify
|
||||||
|
replace: userPassword
|
||||||
|
userPassword: mysecret
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
TLS_REQCERT never
|
||||||
|
URI ldaps://192.168.1.222
|
||||||
|
BASE dc=test,dc=example,dc=com
|
||||||
Executable
+83
@@ -0,0 +1,83 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [[ "$arg" == *"="* ]]; then
|
||||||
|
key="${arg%%=*}"
|
||||||
|
value="${arg#*=}"
|
||||||
|
eval "$key"="'$value'"
|
||||||
|
else
|
||||||
|
eval "$arg"=true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$ipaddr" == "" ]]; then
|
||||||
|
echo "Please provide ipaddr=<ip address> to create/use" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$ipmask" == "" ]]; then
|
||||||
|
ipmask=24
|
||||||
|
fi
|
||||||
|
|
||||||
|
eipaddr=$(echo "$ipaddr" | sed 's/\./\\./g')
|
||||||
|
ifname=$(ip -brief addr show | awk "/$eipaddr\// {print \$1}")
|
||||||
|
if [[ "$ifname" == "" ]]; then
|
||||||
|
ping -c 1 $ipaddr &>/dev/null
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
echo "It looks like you specified an already allocated ip address." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$ifname" == "" ]]; then
|
||||||
|
passed=0
|
||||||
|
if [[ "$ipmask" == "" ]]; then
|
||||||
|
passed=1
|
||||||
|
fi
|
||||||
|
if [[ "$iface" == "" ]]; then
|
||||||
|
passed=2
|
||||||
|
fi
|
||||||
|
if [[ $passed -ne 0 ]]; then
|
||||||
|
echo "To create an interface, specify ipaddr=<ip address> ipmask=<mask> iface=<interface name>" >&2
|
||||||
|
echo "Example: ipaddr=192.168.1.222 ipmask=24 iface=en0" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Creating $ipaddr/$ipmask on interface $iface"
|
||||||
|
sudo ip addr add $ipaddr/$ipmask dev $iface
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$domain" == "" ]]; then
|
||||||
|
domain="TEST.EXAMPLE.COM"
|
||||||
|
fi
|
||||||
|
if [[ "$defaultdns" == "" ]]; then
|
||||||
|
defaultdns="192.168.1.1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Running Samba AD, listening on $ipaddr for domain $domain"
|
||||||
|
docker run -d
|
||||||
|
--name ad \
|
||||||
|
--hostname DC1 \
|
||||||
|
--restart unless-stopped \
|
||||||
|
-e REALM='TEST.LOCAL' \
|
||||||
|
-e DOMAIN='TEST' \
|
||||||
|
-e ADMIN_PASS='MySecret2026!' \
|
||||||
|
-e DNS_FORWARDER='8.8.8.8' \
|
||||||
|
-v dc_etc:/usr/local/samba/etc \
|
||||||
|
-v dc_private:/usr/local/samba/private \
|
||||||
|
-v dc_var:/usr/local/samba/var \
|
||||||
|
-p $ipaddr:53:53 \
|
||||||
|
-p $ipaddr:53:53/udp \
|
||||||
|
-p $ipaddr:88:88 \
|
||||||
|
-p $ipaddr:88:88/udp \
|
||||||
|
-p $ipaddr:135:135 \
|
||||||
|
-p $ipaddr:137-138:137-138/udp \
|
||||||
|
-p $ipaddr:139:139 \
|
||||||
|
-p $ipaddr:389:389 \
|
||||||
|
-p $ipaddr:389:389/udp \
|
||||||
|
-p $ipaddr:445:445 \
|
||||||
|
-p $ipaddr:464:464 \
|
||||||
|
-p $ipaddr:464:464/udp \
|
||||||
|
-p $ipaddr:636:636 \
|
||||||
|
-p $ipaddr:1024-1044:1024-1044 \
|
||||||
|
-p $ipaddr:3268-3269:3268-3269 \
|
||||||
|
diegogslomp/samba-ad-dc
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFtDCCA5ygAwIBAgIEhCJsaTANBgkqhkiG9w0BAQsFADB6MR0wGwYDVQQKExRT
|
||||||
|
YW1iYSBBZG1pbmlzdHJhdGlvbjE3MDUGA1UECxMuU2FtYmEgLSB0ZW1wb3Jhcnkg
|
||||||
|
YXV0b2dlbmVyYXRlZCBDQSBjZXJ0aWZpY2F0ZTEgMB4GA1UEAxMXVEVTVERDLnRl
|
||||||
|
c3QuZXhhbXBsZS5jb20wHhcNMjYwMTE4MDAwMDA0WhcNMjcxMjE5MDAwMDA0WjB6
|
||||||
|
MR0wGwYDVQQKExRTYW1iYSBBZG1pbmlzdHJhdGlvbjE3MDUGA1UECxMuU2FtYmEg
|
||||||
|
LSB0ZW1wb3JhcnkgYXV0b2dlbmVyYXRlZCBDQSBjZXJ0aWZpY2F0ZTEgMB4GA1UE
|
||||||
|
AxMXVEVTVERDLnRlc3QuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4IC
|
||||||
|
DwAwggIKAoICAQDuYBt2jNruSR4xL0wI8Nx2uq+jQKpiViWzDPw4eivNrLXc8Bdr
|
||||||
|
o9GqCo4uokPZiFS6jGez3holnMKF1bxU8uES2ma228zRIJVAHo0qU2O8zGoMtAuL
|
||||||
|
Z+F9gZAVSQKUMp0Vl2yyNERY453Ne4B2Oz92G87YtNuDyNYzuK4778FiE5iXjvan
|
||||||
|
CsAENXrspfxvn8QD5IloHPFoieFkfeaigDA6Zjtr2be+LhDbc2wn6YY7t8Z+5wxG
|
||||||
|
UPUy8oYKQ5lyHSn6I7aezAJpJJHSN4eSg76smTMjUOAnLqJJHPurGF9zzq+maRg+
|
||||||
|
M2runjqRcnZzQtkdZJayK8GQ39kEFpHnl1PueexFEIA5PxHaJEbapAiL7nP65bAy
|
||||||
|
Ey6wiOVvuLgztf8CU6hT/Not3qVG5lCGiK1VC9W684X5vQcVnQXTAIY3Edt91u8C
|
||||||
|
/wt4i5j58orVbcghAZMsU3FKjjqyvQMMSD2Pwgf6+m2mVQIAnZOrkErsQrltmFxO
|
||||||
|
CPBbRY+5Yg8v2ZucMWfKNy4IEzm8LyddrZKAENbW73/bZtPCw7cJqeb6ZaWVzrqW
|
||||||
|
BAgMiyrBYq/oGnXP6rHnTpB02LWTx8dvPPmEgvPhjecCRKroesYeKX38KWywGalA
|
||||||
|
xXbs+Eo9ApGst7qhkenAzM3E7Fy56OoELUAKGQW9gtVEnn+8BofLhezUyQIDAQAB
|
||||||
|
o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
|
||||||
|
ShGTEQzxmK0IrRMPiPYbRxfntYQwDQYJKoZIhvcNAQELBQADggIBAFxD6ShgnqwK
|
||||||
|
6oMzXKZOXoVfVu8yFKhL9Z3ui+6Q/duckzLf873sMlxz9msLTjH1O2Pk9gaND9/l
|
||||||
|
25t37BvVLuNTJKHvTfte53l8fQUrqCgOq2feARoXyCAA77bTUh+uSGsjZYGbSJx/
|
||||||
|
M93fOtabElD9T3o3B0L2EJyL7LHZ3in9MOyVBBcCnOMqi+1eoQEnaoj5TRnE8eEu
|
||||||
|
RuTs7Vu3lceZuCvH1mTRPis2D8bPCWa3aAI6w+LZoJNP3B1izo6Arjje7TBHBMGJ
|
||||||
|
A65o9LP1+OeZ5EA+J3nIkU5rSHu+Pk5biBNEThsnkGjEhSTXZPCVgZRQJOgQyvnf
|
||||||
|
LPWUOMdMLsnsO2oW3/BG6zTmbZw4CMzE8yZUtNZxph7+N1ukzYWZbSwDADxxi+dQ
|
||||||
|
vFQk6tguKpxBCko+pWajgNcxG97MFQMMCfGfva7xdaqBSB4R8sdmQm+wknAYQrlm
|
||||||
|
Jc6csvkJgoIHvyBn9yfSKYNvbjh8RUGA2TZMWrbBMdt51ivw6e1NM16OneGtELh+
|
||||||
|
zGlgv0EfJPaf9IG+RWqvMuhGFF1DgqBi8l816XFy4g3SEFC2F0D6VAv9mQZdq8q1
|
||||||
|
9y7B9vpcBQbNiHqJahIEwgp1JlHdoj281Ms2KixBf88O0y7zSMbyejxHtGv8IUVD
|
||||||
|
+Nth1G9FpENenG73njJIh1dLLYyHvxnp
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFETCCAvmgAwIBAgIUHfUrLa/sMlGeT6VIZdkj73UjZfkwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGDEWMBQGA1UEAwwNU2FtYmEgVGVzdCBDQTAeFw0yNjAxMTgwMTEzMzVaFw0z
|
||||||
|
NjAxMTYwMTEzMzVaMBgxFjAUBgNVBAMMDVNhbWJhIFRlc3QgQ0EwggIiMA0GCSqG
|
||||||
|
SIb3DQEBAQUAA4ICDwAwggIKAoICAQC464FD54YJ1rgi/5Z9DQrIbEzED8NhMjo/
|
||||||
|
ndqD+0sfqkiYjQEqAh7Wpj+6r9D9AZ1wnTdF2Ee767OTwkSA2lG5aQAF9HDFzgIJ
|
||||||
|
8yVbeqJIABOzKotLTl1wCNeRx+YeY69xcytzsQ6iNFyOVV/CbkbxtyJvDfxD9rC5
|
||||||
|
Pwf1A7yBLz0H8U+kXBKC0SCDSW4+SAgmJQu3NQ7wd2eg+EBH/cPVhw0F97K3Yfb0
|
||||||
|
c8wekQdqAMrvfo/jq81/JADUEmzi1lyQ34zX2ToBIeu42/oTBmJ8ZX2ZAFgUu0y1
|
||||||
|
Kh+rmmYLhszPLfwB/28j1wizd/iVdpN0+ssJj3y+rEgKeXFfo1x7KSWprHUCJzZk
|
||||||
|
+T7l59tEg7ZiSuRexgkc3Rf+4DYNq7JzCFnVnBvhC++fym29JRrriX0DOUYMGAS3
|
||||||
|
dFBiLJT65kdLCwrgkCAZTbsNKTVkEQx3QYn58dUYMTmQXndg4AEG0VUa4s+oqOFu
|
||||||
|
jokyeqVqp37CUm0MU9cKJVnkMqWkqI9JRTBe90xHSy5xrmB0N1zM/FbUTBvMCh6Z
|
||||||
|
t7ZAiB3gB1LTXaDRWafJ+opYJtPkVhvAlmFjEwuYCYdUM8lz+i/MKK8hrAoztUvr
|
||||||
|
C2n5qoDUX5Tm9VygefWVxzCvyzTy+FKEq+4aU8ye0zohCJ+UP1SMi3j98aGdVjBJ
|
||||||
|
sI9KhOQNmQIDAQABo1MwUTAdBgNVHQ4EFgQUgFOZGLtmwudA8tVaKeLvowVQLMYw
|
||||||
|
HwYDVR0jBBgwFoAUgFOZGLtmwudA8tVaKeLvowVQLMYwDwYDVR0TAQH/BAUwAwEB
|
||||||
|
/zANBgkqhkiG9w0BAQsFAAOCAgEAPNmj5RCacwRbySYERx8XBlcV50DRFnFS51G0
|
||||||
|
EEKObiOBxt/xboAt/bPw+6dVeqS0JILrgMJhHn7dufRTdnGK/z9VkRDrTh6FudAk
|
||||||
|
16qdhglXzPrPzETGl1VHJxQEkqm+qkUeD4r9waUP5ZIXdsUrvGdnCaXgQRA3v2RD
|
||||||
|
NDvNldmgCTScjTPM4ox0B2iL0P0Uo4pRzQTGuPmubCMv2B8EkBOPIQx/TO2svL6M
|
||||||
|
oal/25v06+xUEyVAxWQPD4xolL8ksEjdqa7l5h/1YkpouWq+jaEDpWGzVqt/fLYI
|
||||||
|
cdGUxSNcaueEmHB2QOklrTdDVvvczAE98ytDZ/zswj8cKKLhe2d3Z3ie40xx+4/x
|
||||||
|
NprbosIGWrHnz0NbDlzXRvd8yk7ZWk4QFRycJb7Ve3Za3hPOlDeKgm5iCjafCS4G
|
||||||
|
C1D8r+SwGjCjgsaL7J/zY4IHyxurRVBU+jZSRgy2WQlR/BQ2gSdVt3BhxsEPgbmu
|
||||||
|
jKOiPltNkqPmUHoXFnosJyAblF8yjYkBPBpbM5luAUiKMYBkdkSA3oSJYK3WuIDl
|
||||||
|
UNcKwcC9sJPu63ciPDtEZlgV5blvMr80PPyJZDofo+KHxWweKxoyXxQoIKCrP53D
|
||||||
|
Av2KGBhIZlJUzNrj4LWMGbf+8BAGL+i1oyM77D/N8L589Y0x1mQMa/quQW+TJ8kH
|
||||||
|
g2wgxQw=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQC464FD54YJ1rgi
|
||||||
|
/5Z9DQrIbEzED8NhMjo/ndqD+0sfqkiYjQEqAh7Wpj+6r9D9AZ1wnTdF2Ee767OT
|
||||||
|
wkSA2lG5aQAF9HDFzgIJ8yVbeqJIABOzKotLTl1wCNeRx+YeY69xcytzsQ6iNFyO
|
||||||
|
VV/CbkbxtyJvDfxD9rC5Pwf1A7yBLz0H8U+kXBKC0SCDSW4+SAgmJQu3NQ7wd2eg
|
||||||
|
+EBH/cPVhw0F97K3Yfb0c8wekQdqAMrvfo/jq81/JADUEmzi1lyQ34zX2ToBIeu4
|
||||||
|
2/oTBmJ8ZX2ZAFgUu0y1Kh+rmmYLhszPLfwB/28j1wizd/iVdpN0+ssJj3y+rEgK
|
||||||
|
eXFfo1x7KSWprHUCJzZk+T7l59tEg7ZiSuRexgkc3Rf+4DYNq7JzCFnVnBvhC++f
|
||||||
|
ym29JRrriX0DOUYMGAS3dFBiLJT65kdLCwrgkCAZTbsNKTVkEQx3QYn58dUYMTmQ
|
||||||
|
Xndg4AEG0VUa4s+oqOFujokyeqVqp37CUm0MU9cKJVnkMqWkqI9JRTBe90xHSy5x
|
||||||
|
rmB0N1zM/FbUTBvMCh6Zt7ZAiB3gB1LTXaDRWafJ+opYJtPkVhvAlmFjEwuYCYdU
|
||||||
|
M8lz+i/MKK8hrAoztUvrC2n5qoDUX5Tm9VygefWVxzCvyzTy+FKEq+4aU8ye0zoh
|
||||||
|
CJ+UP1SMi3j98aGdVjBJsI9KhOQNmQIDAQABAoICADiu8APZn2u6pt0LjZytd8Wx
|
||||||
|
9OIQlupfVB2WDJpyWDfPocspRdcTqVJQya43II+9g/42IvBE+NAw0u4TGZ6JzY1R
|
||||||
|
E1G/+SWZHWThZG0jLUV2yJMeEm62CcxC2Zl1NiPQmMHk9MfU2VB9TnXO07isxxBm
|
||||||
|
+6YhGlfW8ZsHKDBBwfGzgjjCDpCqLH5vDlFQG/v5Zo4SwwGYwQiTAXAFSOcIcZQt
|
||||||
|
fp96qwyted669DHWcPhcX9iD6iV2z1oOtjZLo5bw8JT0AZ9UlgQs2q3iuEhGp7/L
|
||||||
|
+HEC+vz34O6Th/u5K1iTLIrBZMNUAkRxMNiaiNd/7nloOv6mPi3Qb5DOYyNW1wzg
|
||||||
|
TlF5fERqz2OeuFqjnEfoE/uFjvBN0bclenuFTCWDeSxEZqni9qjLhnqK4Iot7/D2
|
||||||
|
P148t4UIT8h5l82Wiod05cenlnPfpWbRRdzVXy0NZe1BTf2U8LXRW1ANdJyfVSC6
|
||||||
|
802KPP6noWnaFYfkhIIdD10ZlTd9vTwdcHEYfoJNNbXcwwI/OslGwPB1a+tp+rSd
|
||||||
|
Vr2l8RoF0/28cjsRnDi7hoaMkNIqszXq1WA+d5zOvmOsfuy/32pfnm+rw8HafYNj
|
||||||
|
SNK0t5sh0PCsHrRrCRfTaOIQbFveABcf0uxbM68xSMAIKH8rpTrp4lcEEO5Yrcrj
|
||||||
|
qDFQ7rw+VnRR0Nu4eX+VAoIBAQDbWhvWkZssTNHR8Xs9OtaAiHktEgJbreaRPvCe
|
||||||
|
GgfyuZ+aYj6M9ivY/z99AJqH4pueXWbZuyBHmPp39zvvN44WP6Yc+4EDyDpiRIxi
|
||||||
|
CjofYzbOIMxnMqgXePPWHXv+UA1zaSu1HGF1kMMeU+cT4knQpkQNrbmioYIetOnU
|
||||||
|
BzdKJt/LTK2KRvHn4VN6Tt49ZnIfrAo8UIOZPdpT6qumX/RENw0/66AU220bLtaP
|
||||||
|
xxZNqipjf56wikkQiHbmP85ZW9dPTR2aUtJZkS7nmJhTuH782ES96soPjYREH/fZ
|
||||||
|
K5TdWn7Se6NcdHgoG5W2voqP3GFUyvKxRNLSK/tjN1UGYKx/AoIBAQDX0LSDjqKX
|
||||||
|
nn+kZBHVXmMtEWVu44CijdDvBIkri5rjO5QdEtgk15gxYXwakRiXgmpsDk/fyBEQ
|
||||||
|
n7iIlao697vNh3cWbe9xuBBhccLcmkrt1qKSO9a1qjbh4lZ10F4SLsZrDz1dTWwf
|
||||||
|
Xvlofl1oNbh9a39xDT9Pa6qt2tZLThianqjHXssMsaEQPNrWduJmM8um/OT+CHoJ
|
||||||
|
6XTzX9SZrMOcevPdAWARdqgBohcfMD2LhMkY0HIkZGdP1/FYdAbHqjK+81pvtPYE
|
||||||
|
JNRQLCgWMWqfUnnay6lMwN/0U7u0AHE4futYMqrn8gGl0JuGLZ6o1BDxpf2Thkfv
|
||||||
|
KpDLDcyFMBnnAoIBAQDGfXvDZm8sXzde603B0oRYOyasCifoHi0OMg46gwO+OQqc
|
||||||
|
AVro47o52n/w9aLgY8a+P3baf+Jt55h/BlJN3c/Ngjsm7s+IRJ/QXIdMEEUYMgdd
|
||||||
|
74AHwmcpFmJP1s5lCruhPAI5GT13zU9DGll4PMTe8hWS6ymYaN3+O2d8XitCBnts
|
||||||
|
1C4Veq1cTyHjA4tHtHSBBIUenxz2hmoSlcBOBXZcZBSxSt7JAOZyOqgd4uHj1aAV
|
||||||
|
+V34EqqbM2GkaQipA9qKABZRl7CRLDdti0AMQl9nHazWzqeZ+008+FCnTDChPUqV
|
||||||
|
3RuuhhZU9OE9RJ7OH3ZT7HJAxy6e0P3igieGZeSxAoIBAQCho2ogAmuavZaCTITi
|
||||||
|
1w/WyGm9NN26YhczfaUzHRuDx7K2V8/VQDh3+7iUuUm+6GnGxq1iQRku50Gx4s6d
|
||||||
|
3cAmPqid/vbQqHh0U10MFu+51QDsH68/Xt4+LmRtVwOuAKSRuNdQE1XA5URN1B8n
|
||||||
|
lty36xSHWtGpLU2navkHa9WXsO9ea4wO1Nd6LuoEqQQGYhLM3iqwbS7iT51NTuAP
|
||||||
|
vUrA34HYbFhEnCdXGczRijL+VRS85honUZ/jOCxGAJi3YK0jQWbhtZpxHhh6d6gK
|
||||||
|
fzaJX59ulQ0XNHpIJ5K1TYN/OegQpdpFYIeFZomlZHOppTOPmbAjlvY3lhzeSFZ/
|
||||||
|
BrjPAoIBAQCsJqoFNpJpJFT/gGL6xWS4O158E5GxYXl3raN/dfBMGZnbTr0nHrbC
|
||||||
|
4vyrWaQFVsovea7SZnzfLdyesLuJ1FIUhsal166o/g6Vf5wgDn7LHZ202tt2DokV
|
||||||
|
ECETQTA+VBTXysc7/dwsTohbee7Jg6xZ/qHSdP6nUan9xiC3pOx0G/vT5FaH9kBJ
|
||||||
|
dJ2mQ93n/l1A6q9Hn5AFyoCqniOszVsQ357N9uxakQiX48JKKWG7+BneKtGzN2bu
|
||||||
|
9ArlPSNscNDb4yF2fqksTHvIYbGuJ3icbObjWUKOCQbtpva4Rkrnoqqg5nHM0L+f
|
||||||
|
3tGhl1yrO4/YIpQrp0OgMV1HDYXEOwwI
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
59634A59EBDC029E7D479619E12C1868317CE811
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
[req]
|
||||||
|
default_bits = 2048
|
||||||
|
prompt = no
|
||||||
|
default_md = sha256
|
||||||
|
distinguished_name = dn
|
||||||
|
req_extensions = req_ext
|
||||||
|
|
||||||
|
[dn]
|
||||||
|
CN = TESTDC.test.example.com
|
||||||
|
|
||||||
|
[req_ext]
|
||||||
|
subjectAltName = @alt_names
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
DNS.1 = TESTDC.test.example.com
|
||||||
|
DNS.2 = localdc.test.example.com
|
||||||
|
IP.1 = 192.168.1.222
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEUDCCAjigAwIBAgIUWWNKWevcAp59R5YZ4SwYaDF86BEwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGDEWMBQGA1UEAwwNU2FtYmEgVGVzdCBDQTAeFw0yNjAxMTgwMTE0MDRaFw0y
|
||||||
|
ODA0MjIwMTE0MDRaMCIxIDAeBgNVBAMMF1RFU1REQy50ZXN0LmV4YW1wbGUuY29t
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA04ZWa1/UrP6eAkwvc2oL
|
||||||
|
XCewax+5GWWhIj0XVgglblPNcPbK0dLTienfGnfEYxgrCl4o+H7c+SFYcJ/Sg5jw
|
||||||
|
W4/POs+NWoo3ixj71TYWwK+7bUPt2RbNadCAxo4SejdB0zOjpTRn4dDIMZ0+wrg5
|
||||||
|
Ah3jkTnPmwWjpvt280KkojUz+7mhdKFXBBmyjr/ftWU8C+1nyJt5/tVl7PE0VcOL
|
||||||
|
MBok9djjHlj2aKLCw8Hj0CyL+yYFM4keWvYAguXYjVayMC2w8VffvjjO3Wd7/LWi
|
||||||
|
AkDIAhnKyc1oJ8X4h9XK1irEw8lgWH93jyRx54eG32/C3HuNRQA9oQgJrfaK5YCJ
|
||||||
|
kQIDAQABo4GHMIGEMEIGA1UdEQQ7MDmCF1RFU1REQy50ZXN0LmV4YW1wbGUuY29t
|
||||||
|
ghhsb2NhbGRjLnRlc3QuZXhhbXBsZS5jb22HBMCoAd4wHQYDVR0OBBYEFJDd+Fmx
|
||||||
|
vsrKEvBMXBwtBeFxjVjWMB8GA1UdIwQYMBaAFIBTmRi7ZsLnQPLVWini76MFUCzG
|
||||||
|
MA0GCSqGSIb3DQEBCwUAA4ICAQBwS8/1iAFnopOui1V/qdRBsBTWcXdQS7x1PqVU
|
||||||
|
nJkd+T5AYtLu3tJ+PBO9rfgDNVWVz37GB8CTgr4TpGOt7ruaVSZvw9uMRBxYeeit
|
||||||
|
Kf11gssI2eTZESv8yqsa1DtLheQS0AQ7IVjq9wZSw+i3zQ8lQDvFoCWa8nv+C+YZ
|
||||||
|
cfFSnhfXNRQIM+lxn6vrtZa/GgJh6MTF+vCfLvStveCsTvT7i/w0EzO8NFqGBrsX
|
||||||
|
ldombU/WNketQXQEaLAU6NQVvJCjkC9Wgc+KcOQOV77U7CHi3lsc2TAoGlMuJ1lP
|
||||||
|
zyQWJqHKkuWGODeBSd9FfjoZv81+OGPaCAh7bkOHwqAUjgEIL8SV1fX8i13HTkG5
|
||||||
|
nhbN6XoiezjKixfH/EAQHiKhi6/7nzYltz6bJFHpIfBa097l7Yhx/o/HIdKDWV2S
|
||||||
|
VnLIJMJpf/Qn80led1HQPeRWR1EC+fWhBzOg2mCJJpYkpqaOlHVujZ2c5JLckhxH
|
||||||
|
WuIkicvR+LE07IjgZFWUwCXW/PkDDHtiJ0MD6RAiFzFbnuGGMadv3lUBJBUeKL3P
|
||||||
|
PaDC/pue9AAgbWN9ndg8CTorDR2HHjjOyVTkum5bPL2vChuG3/mx+KHcgwDyEWt8
|
||||||
|
cJTxXNaid928rR0aSPsSd4WNlCTDwXhUpClaVRaip/rcfrhJaaFUe7xWpQe8dkvO
|
||||||
|
hiuYEQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIICvDCCAaQCAQAwIjEgMB4GA1UEAwwXVEVTVERDLnRlc3QuZXhhbXBsZS5jb20w
|
||||||
|
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDThlZrX9Ss/p4CTC9zagtc
|
||||||
|
J7BrH7kZZaEiPRdWCCVuU81w9srR0tOJ6d8ad8RjGCsKXij4ftz5IVhwn9KDmPBb
|
||||||
|
j886z41aijeLGPvVNhbAr7ttQ+3ZFs1p0IDGjhJ6N0HTM6OlNGfh0MgxnT7CuDkC
|
||||||
|
HeOROc+bBaOm+3bzQqSiNTP7uaF0oVcEGbKOv9+1ZTwL7WfIm3n+1WXs8TRVw4sw
|
||||||
|
GiT12OMeWPZoosLDwePQLIv7JgUziR5a9gCC5diNVrIwLbDxV9++OM7dZ3v8taIC
|
||||||
|
QMgCGcrJzWgnxfiH1crWKsTDyWBYf3ePJHHnh4bfb8Lce41FAD2hCAmt9orlgImR
|
||||||
|
AgMBAAGgVTBTBgkqhkiG9w0BCQ4xRjBEMEIGA1UdEQQ7MDmCF1RFU1REQy50ZXN0
|
||||||
|
LmV4YW1wbGUuY29tghhsb2NhbGRjLnRlc3QuZXhhbXBsZS5jb22HBMCoAd4wDQYJ
|
||||||
|
KoZIhvcNAQELBQADggEBAAQGVIMVIWPbCG3blO8iNHetydfz8XWC3w9zYI03QQBv
|
||||||
|
QdiAYZ9sI+9fxZdsBOOt+vSNyqlwuuQYmmMtMJbUezeOQ8Z4zhkWEzTI4ohhOlzV
|
||||||
|
sq+7aE+PNKw8CYvOkL4ssVIDU99Hm4ppJbo6sRa9YAXPDU3z0UJhMiGZL7o11048
|
||||||
|
W8VcWOzyNmEHYL6/+DXwXGiaLiJmMOJiwMPu8TZVnli4Q0k/j7KGdeh8s2MXLwi8
|
||||||
|
NT0ppSxm+MUIm014OEMA/LOPwRVttHca1VkGR15MJQElakWSaaix533p7lpH3Q3Q
|
||||||
|
tKZc7RIWeoXs5wyo7Tx7Tx7QdmNJIzA2gh4tRiQvm1o=
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDThlZrX9Ss/p4C
|
||||||
|
TC9zagtcJ7BrH7kZZaEiPRdWCCVuU81w9srR0tOJ6d8ad8RjGCsKXij4ftz5IVhw
|
||||||
|
n9KDmPBbj886z41aijeLGPvVNhbAr7ttQ+3ZFs1p0IDGjhJ6N0HTM6OlNGfh0Mgx
|
||||||
|
nT7CuDkCHeOROc+bBaOm+3bzQqSiNTP7uaF0oVcEGbKOv9+1ZTwL7WfIm3n+1WXs
|
||||||
|
8TRVw4swGiT12OMeWPZoosLDwePQLIv7JgUziR5a9gCC5diNVrIwLbDxV9++OM7d
|
||||||
|
Z3v8taICQMgCGcrJzWgnxfiH1crWKsTDyWBYf3ePJHHnh4bfb8Lce41FAD2hCAmt
|
||||||
|
9orlgImRAgMBAAECggEAFTygZ5EMWr6zjC/W9xj3Vq4bbciWaRYwNS5PWKa3ugR1
|
||||||
|
lLkKcuzeVTM4YEFpuQ3qSv+vewd4VcDtzrI/zKY/F4pFjYuHZHGKaGTpP9D5kX3z
|
||||||
|
QjdMOtFUbU0Zk2schXhlG6MhyR/iVXnZ55/4dvdPrfE58aY4EZc22jiBYE9ZanmL
|
||||||
|
Nxqby63ntT/8ZqQpi5iu458TrWTAhOqF+0g5Aj8bWnk6xIcauvFuLORfAcg2kig6
|
||||||
|
+/oUZiQ4U65gvBODckADjTtKmVUlBFFc22xsR5pSm08dI06Fc+1ZWSa3smyA/a+d
|
||||||
|
iOx2Bb+wD8zQMq20pm3R7Kx/yaTLy+AubBzc7OYQMwKBgQDxrgQnMzjLpLEBe+kp
|
||||||
|
8DKSUpy06G176Zoz65NP5BiY1S12YSqu9ydapalIKKH32yu6Gzw0JsTDa0z8glDH
|
||||||
|
Z9VeB9ZM3q+jsPrg7pUUQKC+Yn/Msba5a4BLmdO61qAk1/zPsc/bEIxC6HBXuR5k
|
||||||
|
7bYRivARdGtYRqkkvVKnn5uWqwKBgQDgDuhC4u9ZBx2QN+bDyT+Ppqd+nLLZemTF
|
||||||
|
bJRRbfXsMRpgAvQl5f4mTxu/KqtKm/kKGY7F66B1XuSmZqAEsvVw0oM+0+rCDfdk
|
||||||
|
Iir87ZsdpfoRA5x775zaa2GrW7/hhpvBrenD9vNwo6/G927EjMAhhPaOelxpf+dS
|
||||||
|
fXBrTOKQswKBgQDC+pp9KbTzjo4DXX2SCSgzppSo2y+hHaj7pF33wVUa0DnaXK/7
|
||||||
|
8of8eNRm0+lANsFDZz+d730lD8dPnK8hASNBtl7tK2dWT61HlRQO/8jvcDYc5W8+
|
||||||
|
jn02AQexoAAZWWusAI9p9CLExBQGoeHkmWcfJhFic6M6198UNe2eMIVs+wKBgQCR
|
||||||
|
D1W0KDSJ0R+ExYxz6ZFrMZxzToREZQdlAh0scyKqnkfTLVZgSv02VDVEmR15Gm4r
|
||||||
|
6cwTu6+RDbS/PuYO5MYfG0u5m3370QsAG1b1lee9VD4IUew4GTPV/Xuoc6hRHNMu
|
||||||
|
m6gjJXkKzg75pCxkuDOT//+Y0wONki9zqp7j+U0eHQKBgCkyJ/E+hNFlzqFHugaR
|
||||||
|
ZC8ccttxs2ibTK4J861EvjA7zFkbnAHy2NfsrNPKm6t+TJOkeJ4XrST1vfS3aNJk
|
||||||
|
swHRQz8tWwtnJCsvTF5nCXU7dDQPsyxwRHB39Eq9KtXp7F+PD7kaMk8DbYIzcQ55
|
||||||
|
pe3uxsvKvS6R++L2eg3TfdSB
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
+12
-4
@@ -9,8 +9,10 @@ type (
|
|||||||
Datastore string
|
Datastore string
|
||||||
Insecure bool // For LDAP and owncloud backend only
|
Insecure bool // For LDAP and owncloud backend only
|
||||||
Servers []string // For LDAP and owncloud backend only
|
Servers []string // For LDAP and owncloud backend only
|
||||||
NameFormat string
|
NameFormat string // e.g. cn, ou, uid, or a comma separated list of them
|
||||||
GroupFormat string
|
NameFormatAsArray []string // we will explode NameFormat on commas
|
||||||
|
GroupFormat string // e.g. cn, ou, gid, or a comma separated list of them
|
||||||
|
GroupFormatAsArray []string // we will explode GroupFormat on commas
|
||||||
SSHKeyAttr string
|
SSHKeyAttr string
|
||||||
UseGraphAPI bool // For ownCloud backend only
|
UseGraphAPI bool // For ownCloud backend only
|
||||||
Plugin string // Path to plugin library, for plugin backend only
|
Plugin string // Path to plugin library, for plugin backend only
|
||||||
@@ -46,13 +48,18 @@ type (
|
|||||||
TLSKey string
|
TLSKey string
|
||||||
TLSCertPath string
|
TLSCertPath string
|
||||||
TLSKeyPath string
|
TLSKeyPath string
|
||||||
|
LegacyTLS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
LDAPS struct {
|
LDAPS struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Listen string
|
Listen string
|
||||||
Cert string
|
// LDAPS TLS parameters
|
||||||
Key string
|
Cert string
|
||||||
|
Key string
|
||||||
|
CertPath string
|
||||||
|
KeyPath string
|
||||||
|
LegacyTLS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
API struct {
|
API struct {
|
||||||
@@ -111,6 +118,7 @@ type (
|
|||||||
Name string
|
Name string
|
||||||
UnixID int // TODO: remove after deprecating UnixID on User and Group
|
UnixID int // TODO: remove after deprecating UnixID on User and Group
|
||||||
GIDNumber int
|
GIDNumber int
|
||||||
|
Capabilities []Capability
|
||||||
IncludeGroups []int
|
IncludeGroups []int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-10
@@ -183,8 +183,9 @@ func (h configHandler) FindPosixAccounts(ctx context.Context, hierarchy string)
|
|||||||
|
|
||||||
for _, u := range h.cfg.Users {
|
for _, u := range h.cfg.Users {
|
||||||
attrs := []*ldap.EntryAttribute{}
|
attrs := []*ldap.EntryAttribute{}
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.NameFormat, Values: []string{u.Name}})
|
for _, nameAttr := range h.backend.NameFormatAsArray {
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{u.Name}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: nameAttr, Values: []string{u.Name}})
|
||||||
|
}
|
||||||
|
|
||||||
if len(u.GivenName) > 0 {
|
if len(u.GivenName) > 0 {
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{u.GivenName}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{u.GivenName}})
|
||||||
@@ -260,9 +261,9 @@ func (h configHandler) FindPosixAccounts(ctx context.Context, hierarchy string)
|
|||||||
}
|
}
|
||||||
var dn string
|
var dn string
|
||||||
if hierarchy == "" {
|
if hierarchy == "" {
|
||||||
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, u.PrimaryGroup), h.backend.BaseDN)
|
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), h.backend.BaseDN)
|
||||||
} else {
|
} else {
|
||||||
dn = fmt.Sprintf("%s=%s,%s=%s,%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, u.PrimaryGroup), hierarchy, h.backend.BaseDN)
|
dn = fmt.Sprintf("%s=%s,%s=%s,%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), hierarchy, h.backend.BaseDN)
|
||||||
}
|
}
|
||||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||||
}
|
}
|
||||||
@@ -280,8 +281,10 @@ func (h configHandler) FindPosixGroups(ctx context.Context, hierarchy string) (e
|
|||||||
|
|
||||||
for _, g := range h.cfg.Groups {
|
for _, g := range h.cfg.Groups {
|
||||||
attrs := []*ldap.EntryAttribute{}
|
attrs := []*ldap.EntryAttribute{}
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.GroupFormat, Values: []string{g.Name}})
|
for _, groupAttr := range h.backend.GroupFormatAsArray {
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{g.Name}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: groupAttr, Values: []string{g.Name}})
|
||||||
|
}
|
||||||
|
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s", 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: "gidNumber", Values: []string{fmt.Sprintf("%d", g.GIDNumber)}})
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(ctx, g.GIDNumber)})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(ctx, g.GIDNumber)})
|
||||||
@@ -291,7 +294,7 @@ func (h configHandler) FindPosixGroups(ctx context.Context, hierarchy string) (e
|
|||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(ctx, 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"}})
|
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)
|
dn := fmt.Sprintf("%s=%s,%s,%s", h.backend.GroupFormatAsArray[0], g.Name, hierarchy, h.backend.BaseDN)
|
||||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,12 +323,12 @@ func (h configHandler) getGroupMemberDNs(ctx context.Context, gid int) []string
|
|||||||
members := make(map[string]bool)
|
members := make(map[string]bool)
|
||||||
for _, u := range h.cfg.Users {
|
for _, u := range h.cfg.Users {
|
||||||
if u.PrimaryGroup == gid {
|
if u.PrimaryGroup == gid {
|
||||||
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
||||||
members[dn] = true
|
members[dn] = true
|
||||||
} else {
|
} else {
|
||||||
for _, othergid := range u.OtherGroups {
|
for _, othergid := range u.OtherGroups {
|
||||||
if othergid == gid {
|
if othergid == gid {
|
||||||
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
||||||
members[dn] = true
|
members[dn] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,7 +411,7 @@ func (h configHandler) getGroupDNs(ctx context.Context, gids []int) []string {
|
|||||||
for _, gid := range gids {
|
for _, gid := range gids {
|
||||||
for _, g := range h.cfg.Groups {
|
for _, g := range h.cfg.Groups {
|
||||||
if g.GIDNumber == gid {
|
if g.GIDNumber == gid {
|
||||||
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormat, g.Name, h.backend.BaseDN)
|
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormatAsArray[0], g.Name, h.backend.BaseDN)
|
||||||
groups[dn] = true
|
groups[dn] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"go.opentelemetry.io/otel/trace/noop"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
"github.com/glauth/glauth/v2/pkg/config"
|
||||||
|
"github.com/glauth/ldap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type disabledBindTestMonitor struct{}
|
||||||
|
|
||||||
|
func (disabledBindTestMonitor) SetResponseTimeMetric(map[string]string, float64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (disabledBindTestMonitor) SetLDAPMetric(map[string]string, float64) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigBackendDisabledUserCannotBind(t *testing.T) {
|
||||||
|
pw := "correct horse"
|
||||||
|
raw, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.MinCost)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
hexHash := hex.EncodeToString(raw)
|
||||||
|
|
||||||
|
cfg := &config.Config{}
|
||||||
|
cfg.Users = []config.User{
|
||||||
|
{Name: "activeuser", PrimaryGroup: 5501, PassBcrypt: hexHash, Disabled: false},
|
||||||
|
{Name: "disableduser", PrimaryGroup: 5501, PassBcrypt: hexHash, Disabled: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := zerolog.Nop()
|
||||||
|
tracer := noop.NewTracerProvider().Tracer("f001")
|
||||||
|
helper := NewLDAPOpsHelper(tracer)
|
||||||
|
h := configHandler{
|
||||||
|
backend: config.Backend{
|
||||||
|
BaseDN: "dc=example,dc=com",
|
||||||
|
NameFormatAsArray: []string{"cn"},
|
||||||
|
GroupFormatAsArray: []string{"ou"},
|
||||||
|
},
|
||||||
|
log: &logger,
|
||||||
|
cfg: cfg,
|
||||||
|
ldohelper: helper,
|
||||||
|
monitor: disabledBindTestMonitor{},
|
||||||
|
tracer: tracer,
|
||||||
|
}
|
||||||
|
_, server := net.Pipe()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
bind := func(dn, pass string) ldap.LDAPResultCode {
|
||||||
|
code, _ := h.Bind(dn, pass, server)
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
if code := bind("cn=activeuser,dc=example,dc=com", pw); code != ldap.LDAPResultSuccess {
|
||||||
|
t.Fatalf("active user with correct pw should bind, got %d", code)
|
||||||
|
}
|
||||||
|
if code := bind("cn=disableduser,dc=example,dc=com", pw); code != ldap.LDAPResultInvalidCredentials {
|
||||||
|
t.Errorf("disabled user must be rejected; got code %d, want InvalidCredentials(49)", code)
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
-4
@@ -117,10 +117,12 @@ func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (result ld
|
|||||||
lowerBindDN := strings.ToLower(bindDN)
|
lowerBindDN := strings.ToLower(bindDN)
|
||||||
baseDN := strings.ToLower("," + h.backend.BaseDN)
|
baseDN := strings.ToLower("," + h.backend.BaseDN)
|
||||||
parts := strings.Split(strings.TrimSuffix(lowerBindDN, baseDN), ",")
|
parts := strings.Split(strings.TrimSuffix(lowerBindDN, baseDN), ",")
|
||||||
userName := strings.TrimPrefix(parts[0], h.backend.NameFormat+"=")
|
userName := strings.TrimPrefix(parts[0], h.backend.NameFormatAsArray[0]+"=")
|
||||||
|
|
||||||
validotp := false
|
validotp := false
|
||||||
|
|
||||||
|
// Local records augment proxy authentication with OTP/YubiKey checks;
|
||||||
|
// password authentication remains delegated to the upstream LDAP server.
|
||||||
// Find the user
|
// Find the user
|
||||||
// We are going to go through all backends and ask
|
// We are going to go through all backends and ask
|
||||||
// until we find our user or die of boredom.
|
// until we find our user or die of boredom.
|
||||||
@@ -210,6 +212,20 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
|
|||||||
stats.Frontend.Add("search_ldapSession_errors", 1)
|
stats.Frontend.Add("search_ldapSession_errors", 1)
|
||||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, nil
|
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, nil
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
delete_idx := -1
|
||||||
|
pagingSize := uint32(0)
|
||||||
|
for idx, control := range searchReq.Controls {
|
||||||
|
if control.GetControlType() == ldap.ControlTypePaging {
|
||||||
|
fmt.Println(control.GetControlType())
|
||||||
|
pagingSize = control.(*ldap.ControlPaging).PagingSize
|
||||||
|
delete_idx = idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if delete_idx >= 0 {
|
||||||
|
searchReq.Controls = append(searchReq.Controls[:delete_idx], searchReq.Controls[delete_idx+1:]...)
|
||||||
|
}
|
||||||
|
*/
|
||||||
search := ldap.NewSearchRequest(
|
search := ldap.NewSearchRequest(
|
||||||
searchReq.BaseDN,
|
searchReq.BaseDN,
|
||||||
searchReq.Scope,
|
searchReq.Scope,
|
||||||
@@ -223,6 +239,15 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
|
|||||||
)
|
)
|
||||||
|
|
||||||
h.log.Debug().Interface("request", search).Msg("Search request to backend")
|
h.log.Debug().Interface("request", search).Msg("Search request to backend")
|
||||||
|
/*
|
||||||
|
var sr *ldap.SearchResult
|
||||||
|
if pagingSize > 0 {
|
||||||
|
fmt.Printf("Searching with page size == %d\n", pagingSize)
|
||||||
|
sr, err = s.ldap.SearchWithPaging(search, pagingSize)
|
||||||
|
} else {
|
||||||
|
sr, err = s.ldap.Search(search)
|
||||||
|
}
|
||||||
|
*/
|
||||||
sr, err := s.ldap.Search(search)
|
sr, err := s.ldap.Search(search)
|
||||||
h.log.Debug().Interface("result", sr).Msg("Backend Search result")
|
h.log.Debug().Interface("result", sr).Msg("Backend Search result")
|
||||||
|
|
||||||
@@ -286,9 +311,10 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
|
|||||||
}
|
}
|
||||||
|
|
||||||
ssr := ldap.ServerSearchResult{
|
ssr := ldap.ServerSearchResult{
|
||||||
Entries: sr.Entries,
|
Entries: sr.Entries,
|
||||||
Referrals: sr.Referrals,
|
Referrals: sr.Referrals,
|
||||||
Controls: sr.Controls,
|
Controls: sr.Controls,
|
||||||
|
ResultCode: ldap.LDAPResultSuccess,
|
||||||
}
|
}
|
||||||
h.log.Debug().Interface("result", ssr).Msg("Frontend Search result")
|
h.log.Debug().Interface("result", ssr).Msg("Frontend Search result")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ func NewLDAPOpsHelper(tracer trace.Tracer) LDAPOpsHelper {
|
|||||||
return helper
|
return helper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isUnauthenticatedSimpleBind(bindDN, bindSimplePw string) bool {
|
||||||
|
return bindDN != "" && bindSimplePw == ""
|
||||||
|
}
|
||||||
|
|
||||||
func (l LDAPOpsHelper) Bind(ctx context.Context, h LDAPOpsHandler, bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
|
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")
|
ctx, span := l.tracer.Start(ctx, "handler.LDAPOpsHelper.Bind")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
@@ -86,11 +90,24 @@ func (l LDAPOpsHelper) Bind(ctx context.Context, h LDAPOpsHandler, bindDN, bindS
|
|||||||
return ldap.LDAPResultSuccess, nil
|
return ldap.LDAPResultSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A non-empty DN with an empty password is LDAP's unauthenticated bind
|
||||||
|
// mechanism. It must not establish the named user's authorization state.
|
||||||
|
if isUnauthenticatedSimpleBind(bindDN, bindSimplePw) {
|
||||||
|
h.GetLog().Info().Str("binddn", bindDN).Str("src", conn.RemoteAddr().String()).Msg("unauthenticated bind rejected")
|
||||||
|
return ldap.LDAPResultUnwillingToPerform, nil
|
||||||
|
}
|
||||||
|
|
||||||
user, ldapcode := l.findUser(ctx, h, bindDN, true /* checkGroup */)
|
user, ldapcode := l.findUser(ctx, h, bindDN, true /* checkGroup */)
|
||||||
if ldapcode != ldap.LDAPResultSuccess {
|
if ldapcode != ldap.LDAPResultSuccess {
|
||||||
return ldapcode, nil
|
return ldapcode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a disabled account must never authenticate, on any backend
|
||||||
|
if user.Disabled {
|
||||||
|
h.GetLog().Info().Str("binddn", bindDN).Str("src", conn.RemoteAddr().String()).Msg("Bind attempt on disabled account")
|
||||||
|
return ldap.LDAPResultInvalidCredentials, nil
|
||||||
|
}
|
||||||
|
|
||||||
validotp := false
|
validotp := false
|
||||||
|
|
||||||
if len(user.Yubikey) == 0 && len(user.OTPSecret) == 0 {
|
if len(user.Yubikey) == 0 && len(user.OTPSecret) == 0 {
|
||||||
@@ -175,6 +192,15 @@ func (l LDAPOpsHelper) Bind(ctx context.Context, h LDAPOpsHandler, bindDN, bindS
|
|||||||
return ldap.LDAPResultInvalidCredentials, nil
|
return ldap.LDAPResultInvalidCredentials, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reaching this point without a configured primary password verifier must
|
||||||
|
// not be treated as successful authentication. App-password matches and
|
||||||
|
// custom authentication return above when they succeed.
|
||||||
|
if user.PassBcrypt == "" && user.PassSHA256 == "" {
|
||||||
|
h.GetLog().Info().Str("binddn", bindDN).Str("src", conn.RemoteAddr().String()).Msg("invalid credentials")
|
||||||
|
l.maybePutInTimeout(ctx, h, conn, true)
|
||||||
|
return ldap.LDAPResultInvalidCredentials, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Now, check the pasword hash
|
// Now, check the pasword hash
|
||||||
if user.PassBcrypt != "" {
|
if user.PassBcrypt != "" {
|
||||||
decoded, err := hex.DecodeString(user.PassBcrypt)
|
decoded, err := hex.DecodeString(user.PassBcrypt)
|
||||||
@@ -359,6 +385,7 @@ func (l LDAPOpsHelper) searchMaybeRootDSEQuery(ctx context.Context, h LDAPOpsHan
|
|||||||
// unfortunately, objectClass is not to be included so we will respect that
|
// unfortunately, objectClass is not to be included so we will respect that
|
||||||
// attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"*"}})
|
// attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"*"}})
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedSASLMechanisms", Values: []string{}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedSASLMechanisms", Values: []string{}})
|
||||||
|
//attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedSASLMechanisms", Values: []string{"GSSAPI", "PLAIN", "EXTERNAL"}})
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedLDAPVersion", Values: []string{"3"}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedLDAPVersion", Values: []string{"3"}})
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedControl", Values: []string{}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedControl", Values: []string{}})
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedCapabilities", Values: []string{}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "supportedCapabilities", Values: []string{}})
|
||||||
@@ -659,10 +686,10 @@ func (l LDAPOpsHelper) findUser(ctx context.Context, h LDAPOpsHandler, bindDN st
|
|||||||
groupName := ""
|
groupName := ""
|
||||||
userName := ""
|
userName := ""
|
||||||
if len(parts) == 1 {
|
if len(parts) == 1 {
|
||||||
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormat+"=")
|
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormatAsArray[0]+"=")
|
||||||
} else if len(parts) == 2 || (len(parts) == 3 && parts[2] == "ou=users") {
|
} else if len(parts) == 2 || (len(parts) == 3 && parts[2] == "ou=users") {
|
||||||
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormat+"=")
|
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormatAsArray[0]+"=")
|
||||||
groupName = strings.TrimPrefix(parts[1], h.GetBackend().GroupFormat+"=")
|
groupName = strings.TrimPrefix(parts[1], h.GetBackend().GroupFormatAsArray[0]+"=")
|
||||||
} else {
|
} else {
|
||||||
h.GetLog().Info().Str("binddn", bindDN).Int("numparts", len(parts)).Msg("BindDN should have only one or two parts")
|
h.GetLog().Info().Str("binddn", bindDN).Int("numparts", len(parts)).Msg("BindDN should have only one or two parts")
|
||||||
for _, part := range parts {
|
for _, part := range parts {
|
||||||
@@ -702,6 +729,7 @@ func (l LDAPOpsHelper) findUser(ctx context.Context, h LDAPOpsHandler, bindDN st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l LDAPOpsHelper) checkCapability(ctx context.Context, user config.User, action string, objects []string) bool {
|
func (l LDAPOpsHelper) checkCapability(ctx context.Context, user config.User, action string, objects []string) bool {
|
||||||
|
// User-level?
|
||||||
for _, capability := range user.Capabilities {
|
for _, capability := range user.Capabilities {
|
||||||
if capability.Action == action {
|
if capability.Action == action {
|
||||||
for _, object := range objects {
|
for _, object := range objects {
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GeertJohan/yubigo"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
|
||||||
|
"github.com/glauth/glauth/v2/pkg/config"
|
||||||
|
"github.com/glauth/ldap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bindTestHandler struct {
|
||||||
|
backend config.Backend
|
||||||
|
cfg config.Config
|
||||||
|
log zerolog.Logger
|
||||||
|
user config.User
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *bindTestHandler) GetBackend() config.Backend { return h.backend }
|
||||||
|
func (h *bindTestHandler) GetLog() *zerolog.Logger { return &h.log }
|
||||||
|
func (h *bindTestHandler) GetCfg() *config.Config { return &h.cfg }
|
||||||
|
func (h *bindTestHandler) GetYubikeyAuth() *yubigo.YubiAuth {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *bindTestHandler) FindUser(_ context.Context, userName string, _ bool) (bool, config.User, error) {
|
||||||
|
if userName == h.user.Name {
|
||||||
|
return true, h.user, nil
|
||||||
|
}
|
||||||
|
return false, config.User{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *bindTestHandler) FindGroup(context.Context, string) (bool, config.Group, error) {
|
||||||
|
return false, config.Group{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *bindTestHandler) FindPosixAccounts(context.Context, string) ([]*ldap.Entry, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *bindTestHandler) FindPosixGroups(context.Context, string) ([]*ldap.Entry, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sha256Password(password string) string {
|
||||||
|
hash := sha256.Sum256([]byte(password))
|
||||||
|
return hex.EncodeToString(hash[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLDAPOpsHelperBindRejectsUnauthenticatedAndPasswordlessBinds(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
password string
|
||||||
|
user config.User
|
||||||
|
wantResult ldap.LDAPResultCode
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "named empty password is unauthenticated bind",
|
||||||
|
password: "",
|
||||||
|
wantResult: ldap.LDAPResultUnwillingToPerform,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "arbitrary password without verifier",
|
||||||
|
password: "definitely-wrong",
|
||||||
|
wantResult: ldap.LDAPResultInvalidCredentials,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "failed app password does not fall through",
|
||||||
|
user: config.User{
|
||||||
|
Name: "nopass",
|
||||||
|
PassAppSHA256: []string{sha256Password("expected")},
|
||||||
|
},
|
||||||
|
password: "definitely-wrong",
|
||||||
|
wantResult: ldap.LDAPResultInvalidCredentials,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matching primary password succeeds",
|
||||||
|
user: config.User{
|
||||||
|
Name: "nopass",
|
||||||
|
PassSHA256: sha256Password("correct"),
|
||||||
|
},
|
||||||
|
password: "correct",
|
||||||
|
wantResult: ldap.LDAPResultSuccess,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
user := tt.user
|
||||||
|
if user.Name == "" {
|
||||||
|
user.Name = "nopass"
|
||||||
|
}
|
||||||
|
h := &bindTestHandler{
|
||||||
|
backend: config.Backend{
|
||||||
|
BaseDN: "dc=glauth,dc=com",
|
||||||
|
NameFormatAsArray: []string{"cn"},
|
||||||
|
GroupFormatAsArray: []string{"ou"},
|
||||||
|
},
|
||||||
|
user: user,
|
||||||
|
log: zerolog.Nop(),
|
||||||
|
}
|
||||||
|
conn, peer := net.Pipe()
|
||||||
|
defer conn.Close()
|
||||||
|
defer peer.Close()
|
||||||
|
|
||||||
|
helper := NewLDAPOpsHelper(trace.NewNoopTracerProvider().Tracer("bind-test"))
|
||||||
|
got, err := helper.Bind(context.Background(), h, "cn=nopass,dc=glauth,dc=com", tt.password, conn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Bind returned error: %v", err)
|
||||||
|
}
|
||||||
|
if got != tt.wantResult {
|
||||||
|
t.Fatalf("Bind result = %v, want %v", got, tt.wantResult)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLDAPOpsHelperBindAllowsAnonymousBind(t *testing.T) {
|
||||||
|
h := &bindTestHandler{
|
||||||
|
backend: config.Backend{BaseDN: "dc=glauth,dc=com"},
|
||||||
|
log: zerolog.Nop(),
|
||||||
|
}
|
||||||
|
conn, peer := net.Pipe()
|
||||||
|
defer conn.Close()
|
||||||
|
defer peer.Close()
|
||||||
|
|
||||||
|
helper := NewLDAPOpsHelper(trace.NewNoopTracerProvider().Tracer("bind-test"))
|
||||||
|
got, err := helper.Bind(context.Background(), h, "", "", conn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Bind returned error: %v", err)
|
||||||
|
}
|
||||||
|
if got != ldap.LDAPResultSuccess {
|
||||||
|
t.Fatalf("Bind result = %v, want %v", got, ldap.LDAPResultSuccess)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -167,7 +167,9 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
|
|||||||
}
|
}
|
||||||
for _, g := range groups {
|
for _, g := range groups {
|
||||||
attrs := []*ldap.EntryAttribute{}
|
attrs := []*ldap.EntryAttribute{}
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.GroupFormat, Values: []string{*g.ID}})
|
for _, groupAttr := range h.backend.GroupFormatAsArray {
|
||||||
|
attrs = append(attrs, &ldap.EntryAttribute{Name: groupAttr, Values: []string{*g.ID}})
|
||||||
|
}
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s from ownCloud", *g.ID)}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s from ownCloud", *g.ID)}})
|
||||||
// attrs = append(attrs, &ldap.EntryAttribute{"gidNumber", []string{fmt.Sprintf("%d", g.GIDNumber)}})
|
// attrs = append(attrs, &ldap.EntryAttribute{"gidNumber", []string{fmt.Sprintf("%d", g.GIDNumber)}})
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixGroup"}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixGroup"}})
|
||||||
@@ -179,7 +181,7 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
|
|||||||
|
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: members})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: members})
|
||||||
}
|
}
|
||||||
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormat, *g.ID, h.backend.BaseDN)
|
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormatAsArray[0], *g.ID, h.backend.BaseDN)
|
||||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||||
}
|
}
|
||||||
case "posixaccount", "":
|
case "posixaccount", "":
|
||||||
@@ -197,8 +199,9 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
|
|||||||
}
|
}
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
attrs := []*ldap.EntryAttribute{}
|
attrs := []*ldap.EntryAttribute{}
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.NameFormat, Values: []string{*u.ID}})
|
for _, nameAttr := range h.backend.NameFormatAsArray {
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{*u.ID}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: nameAttr, Values: []string{*u.ID}})
|
||||||
|
}
|
||||||
if u.DisplayName != nil {
|
if u.DisplayName != nil {
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{*u.DisplayName}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{*u.DisplayName}})
|
||||||
}
|
}
|
||||||
@@ -209,7 +212,7 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
|
|||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixAccount"}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixAccount"}})
|
||||||
|
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s from ownCloud", *u.ID)}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s from ownCloud", *u.ID)}})
|
||||||
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, *u.ID, h.backend.GroupFormat, "users", h.backend.BaseDN)
|
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormatAsArray[0], *u.ID, h.backend.GroupFormatAsArray[0], "users", h.backend.BaseDN)
|
||||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,12 +44,11 @@ func InitLogging(reqdebug bool, reqsyslog bool, reqstructlog bool) zerolog.Logge
|
|||||||
var logr zerolog.Logger
|
var logr zerolog.Logger
|
||||||
if reqsyslog {
|
if reqsyslog {
|
||||||
s, err := syslog.New(syslog.LOG_INFO, "glauth")
|
s, err := syslog.New(syslog.LOG_INFO, "glauth")
|
||||||
if err != nil {
|
if err == nil {
|
||||||
|
logr = zerolog.New(zerolog.SyslogLevelWriter(s)).Level(level).With().Timestamp().Logger()
|
||||||
|
} else {
|
||||||
fmt.Println("Unable to write to syslog: ignoring...")
|
fmt.Println("Unable to write to syslog: ignoring...")
|
||||||
reqsyslog = false
|
reqsyslog = false
|
||||||
} else {
|
|
||||||
writers := zerolog.MultiLevelWriter(mainWriter, zerolog.SyslogLevelWriter(s))
|
|
||||||
logr = zerolog.New(writers).Level(level).With().Timestamp().Logger()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,14 +56,13 @@ func InitLogging(reqdebug bool, reqsyslog bool, reqstructlog bool) zerolog.Logge
|
|||||||
logr = zerolog.New(mainWriter).Level(level).With().Timestamp().Logger()
|
logr = zerolog.New(mainWriter).Level(level).With().Timestamp().Logger()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.SetOutput(customWriter{logr: logr, structlog: reqstructlog})
|
log.SetOutput(customWriter{logr: logr})
|
||||||
|
|
||||||
return logr
|
return logr
|
||||||
}
|
}
|
||||||
|
|
||||||
type customWriter struct {
|
type customWriter struct {
|
||||||
logr zerolog.Logger
|
logr zerolog.Logger
|
||||||
structlog bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e customWriter) Write(p []byte) (int, error) {
|
func (e customWriter) Write(p []byte) (int, error) {
|
||||||
@@ -76,10 +74,6 @@ func (e customWriter) Write(p []byte) (int, error) {
|
|||||||
if msg == "" {
|
if msg == "" {
|
||||||
msg = strings.TrimSpace(string(p))
|
msg = strings.TrimSpace(string(p))
|
||||||
}
|
}
|
||||||
if e.structlog {
|
e.logr.Info().Msg(msg)
|
||||||
fmt.Fprintf(os.Stderr, "{\"level\":\"info\",\"time\":\"%s\",\"message\":\"%s\"}\n", time.Now().Format(time.RFC1123Z), strings.Replace(strings.TrimSpace(msg), `"`, `\"`, -1))
|
|
||||||
} else {
|
|
||||||
e.logr.Info().Msg(msg)
|
|
||||||
}
|
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// customWriter adapts log output from libraries that emit unstructured text.
|
||||||
|
// Everything it receives must go through the logger, so that it lands wherever
|
||||||
|
// the logger points - notably syslog only, when syslog is enabled.
|
||||||
|
func TestCustomWriterEmitsValidJSONThroughTheLogger(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
in string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"plain", "something happened", "something happened"},
|
||||||
|
{"quotes", `bind for "cn=foo"`, `bind for "cn=foo"`},
|
||||||
|
{"backslashes", `path C:\Users\x`, `path C:\Users\x`},
|
||||||
|
{"control characters", "tab\there\nand a newline", "tab\there\nand a newline"},
|
||||||
|
{
|
||||||
|
"library timestamp prefix is stripped",
|
||||||
|
"2026/09/13 16:50:54 connection closed",
|
||||||
|
"connection closed",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := customWriter{logr: zerolog.New(&buf).With().Timestamp().Logger()}
|
||||||
|
|
||||||
|
if _, err := w.Write([]byte(tc.in)); err != nil {
|
||||||
|
t.Fatalf("Write: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// One record, one line: an unescaped newline would split this.
|
||||||
|
if got := strings.Count(strings.TrimRight(buf.String(), "\n"), "\n"); got != 0 {
|
||||||
|
t.Fatalf("expected a single log line, got %d extra newlines in %q", got, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var record struct {
|
||||||
|
Level string `json:"level"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(buf.Bytes(), &record); err != nil {
|
||||||
|
t.Fatalf("emitted invalid JSON (%v): %s", err, buf.String())
|
||||||
|
}
|
||||||
|
if record.Message != tc.want {
|
||||||
|
t.Errorf("message = %q, want %q", record.Message, tc.want)
|
||||||
|
}
|
||||||
|
if record.Level != "info" {
|
||||||
|
t.Errorf("level = %q, want %q", record.Level, "info")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@@ -42,14 +41,13 @@ func InitLogging(reqdebug bool, reqsyslog bool, reqstructlog bool) zerolog.Logge
|
|||||||
|
|
||||||
logr := zerolog.New(mainWriter).Level(level).With().Timestamp().Logger()
|
logr := zerolog.New(mainWriter).Level(level).With().Timestamp().Logger()
|
||||||
|
|
||||||
log.SetOutput(customWriter{logr: logr, structlog: reqstructlog})
|
log.SetOutput(customWriter{logr: logr})
|
||||||
|
|
||||||
return logr
|
return logr
|
||||||
}
|
}
|
||||||
|
|
||||||
type customWriter struct {
|
type customWriter struct {
|
||||||
logr zerolog.Logger
|
logr zerolog.Logger
|
||||||
structlog bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e customWriter) Write(p []byte) (int, error) {
|
func (e customWriter) Write(p []byte) (int, error) {
|
||||||
@@ -61,10 +59,6 @@ func (e customWriter) Write(p []byte) (int, error) {
|
|||||||
if msg == "" {
|
if msg == "" {
|
||||||
msg = strings.TrimSpace(string(p))
|
msg = strings.TrimSpace(string(p))
|
||||||
}
|
}
|
||||||
if e.structlog {
|
e.logr.Info().Msg(msg)
|
||||||
fmt.Fprintf(os.Stderr, "{\"level\":\"info\",\"time\":\"%s\",\"message\":\"%s\"}\n", time.Now().Format(time.RFC1123Z), strings.Replace(strings.TrimSpace(msg), `"`, `\"`, -1))
|
|
||||||
} else {
|
|
||||||
e.logr.Info().Msg(msg)
|
|
||||||
}
|
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ func NewDatabaseHandler(sqlBackend SqlBackend, opts ...handler.Option) handler.H
|
|||||||
sqlBackend.CreateSchema(db)
|
sqlBackend.CreateSchema(db)
|
||||||
sqlBackend.MigrateSchema(db, ColumnExists)
|
sqlBackend.MigrateSchema(db, ColumnExists)
|
||||||
|
|
||||||
options.Logger.Info().Msg("Database (" + sqlBackend.GetDriverName() + "::" + options.Backend.Database + ") Plugin: Ready")
|
options.Logger.Debug().Msg("Database (" + sqlBackend.GetDriverName() + "::" + options.Backend.Database + ") Plugin: Ready")
|
||||||
|
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
@@ -454,13 +454,13 @@ func (h databaseHandler) getGroupMemberDNs(ctx context.Context, gid int) []strin
|
|||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
if u.PrimaryGroup == gid {
|
if u.PrimaryGroup == gid {
|
||||||
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
||||||
members[dn] = true
|
members[dn] = true
|
||||||
} else {
|
} else {
|
||||||
u.OtherGroups = h.commaListToIntTable(ctx, otherGroups)
|
u.OtherGroups = h.commaListToIntTable(ctx, otherGroups)
|
||||||
for _, othergid := range u.OtherGroups {
|
for _, othergid := range u.OtherGroups {
|
||||||
if othergid == gid {
|
if othergid == gid {
|
||||||
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
||||||
members[dn] = true
|
members[dn] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -562,7 +562,7 @@ func (h databaseHandler) getGroupDNs(ctx context.Context, gids []int) []string {
|
|||||||
for _, gid := range gids {
|
for _, gid := range gids {
|
||||||
for _, g := range h.MemGroups {
|
for _, g := range h.MemGroups {
|
||||||
if g.GIDNumber == gid {
|
if g.GIDNumber == gid {
|
||||||
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormat, g.Name, h.backend.BaseDN)
|
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormatAsArray[0], g.Name, h.backend.BaseDN)
|
||||||
groups[dn] = true
|
groups[dn] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,7 +609,9 @@ func (h databaseHandler) getGroup(ctx context.Context, hierarchy string, g confi
|
|||||||
asGroupOfUniqueNames := hierarchy == "ou=groups"
|
asGroupOfUniqueNames := hierarchy == "ou=groups"
|
||||||
|
|
||||||
attrs := []*ldap.EntryAttribute{}
|
attrs := []*ldap.EntryAttribute{}
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.GroupFormat, Values: []string{g.Name}})
|
for _, groupAttr := range h.backend.GroupFormatAsArray {
|
||||||
|
attrs = append(attrs, &ldap.EntryAttribute{Name: groupAttr, 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: "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: "gidNumber", Values: []string{fmt.Sprintf("%d", g.GIDNumber)}})
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(ctx, g.GIDNumber)})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "uniqueMember", Values: h.getGroupMemberDNs(ctx, g.GIDNumber)})
|
||||||
@@ -619,7 +621,7 @@ func (h databaseHandler) getGroup(ctx context.Context, hierarchy string, g confi
|
|||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: h.getGroupMemberIDs(ctx, 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"}})
|
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)
|
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormatAsArray[0], g.Name, h.backend.BaseDN)
|
||||||
return &ldap.Entry{DN: dn, Attributes: attrs}
|
return &ldap.Entry{DN: dn, Attributes: attrs}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,8 +630,9 @@ func (h databaseHandler) getAccount(ctx context.Context, hierarchy string, u con
|
|||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
attrs := []*ldap.EntryAttribute{}
|
attrs := []*ldap.EntryAttribute{}
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.NameFormat, Values: []string{u.Name}})
|
for _, nameAttr := range h.backend.NameFormatAsArray {
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{u.Name}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: nameAttr, Values: []string{u.Name}})
|
||||||
|
}
|
||||||
|
|
||||||
if len(u.GivenName) > 0 {
|
if len(u.GivenName) > 0 {
|
||||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{u.GivenName}})
|
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{u.GivenName}})
|
||||||
@@ -676,9 +679,9 @@ func (h databaseHandler) getAccount(ctx context.Context, hierarchy string, u con
|
|||||||
}
|
}
|
||||||
var dn string
|
var dn string
|
||||||
if hierarchy == "" {
|
if hierarchy == "" {
|
||||||
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, u.PrimaryGroup), h.backend.BaseDN)
|
dn = fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), h.backend.BaseDN)
|
||||||
} else {
|
} else {
|
||||||
dn = fmt.Sprintf("%s=%s,%s=%s,%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(ctx, u.PrimaryGroup), hierarchy, h.backend.BaseDN)
|
dn = fmt.Sprintf("%s=%s,%s=%s,%s,%s", h.backend.NameFormatAsArray[0], u.Name, h.backend.GroupFormatAsArray[0], h.getGroupName(ctx, u.PrimaryGroup), hierarchy, h.backend.BaseDN)
|
||||||
}
|
}
|
||||||
return &ldap.Entry{DN: dn, Attributes: attrs}
|
return &ldap.Entry{DN: dn, Attributes: attrs}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
release-glauth-bogus:
|
|
||||||
@echo Ignoring bogus plugin
|
|
||||||
Submodule v2/pkg/plugins/glauth-mysql updated: 8379828f13...37dae36d57
Submodule v2/pkg/plugins/glauth-pam updated: 0e6e4240ef...aed21903e1
Submodule v2/pkg/plugins/glauth-postgres updated: 61fa8ee872...81d4006ec2
Submodule v2/pkg/plugins/glauth-sqlite updated: e8b3b6a8b0...fdfef39435
@@ -0,0 +1,13 @@
|
|||||||
|
//go:build !(embedsqlite || embedmysql)
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/glauth/glauth/v2/pkg/handler"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEmbed(opts ...handler.Option) (handler.Handler, error) {
|
||||||
|
return nil, errors.New("GLAuth was not built with support for an embedded plugin")
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//go:build embedsqlite
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/glauth/glauth/v2/pkg/embed"
|
||||||
|
"github.com/glauth/glauth/v2/pkg/handler"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEmbed(opts ...handler.Option) (handler.Handler, error) {
|
||||||
|
return embed.NewSQLiteHandler(opts...), nil
|
||||||
|
}
|
||||||
@@ -16,12 +16,13 @@ type Option func(o *Options)
|
|||||||
|
|
||||||
// Options defines the available options for this package.
|
// Options defines the available options for this package.
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Logger zerolog.Logger
|
Logger zerolog.Logger
|
||||||
Config *config.Config
|
Config *config.Config
|
||||||
TLSConfig *tls.Config
|
StartTLSConfig *tls.Config
|
||||||
Monitor monitoring.MonitorInterface
|
LDAPSTLSConfig *tls.Config
|
||||||
Tracer trace.Tracer
|
Monitor monitoring.MonitorInterface
|
||||||
Context context.Context
|
Tracer trace.Tracer
|
||||||
|
Context context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// newOptions initializes the available default options.
|
// newOptions initializes the available default options.
|
||||||
@@ -56,10 +57,17 @@ func Context(val context.Context) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TLSConfig provides a function to set the TLS config option.
|
// TLSConfig provides a function to set the StartTLS config option.
|
||||||
func TLSConfig(val *tls.Config) Option {
|
func StartTLSConfig(val *tls.Config) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.TLSConfig = val
|
o.StartTLSConfig = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLSConfig provides a function to set the LDAPSTls config option.
|
||||||
|
func LDAPSTLSConfig(val *tls.Config) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.LDAPSTLSConfig = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-11
@@ -1,10 +1,13 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"plugin"
|
"plugin"
|
||||||
|
|
||||||
|
_tls "github.com/glauth/glauth/v2/internal/tls"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
|
||||||
@@ -20,9 +23,10 @@ type LdapSvc struct {
|
|||||||
yubiAuth *yubigo.YubiAuth
|
yubiAuth *yubigo.YubiAuth
|
||||||
l *ldap.Server
|
l *ldap.Server
|
||||||
|
|
||||||
monitor monitoring.MonitorInterface
|
ldapstls *tls.Config
|
||||||
tracer trace.Tracer
|
monitor monitoring.MonitorInterface
|
||||||
log zerolog.Logger
|
tracer trace.Tracer
|
||||||
|
log zerolog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(opts ...Option) (*LdapSvc, error) {
|
func NewServer(opts ...Option) (*LdapSvc, error) {
|
||||||
@@ -96,9 +100,22 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
|||||||
s.l = ldap.NewServer()
|
s.l = ldap.NewServer()
|
||||||
s.l.EnforceLDAP = true
|
s.l.EnforceLDAP = true
|
||||||
|
|
||||||
if tlsConfig := options.TLSConfig; tlsConfig != nil {
|
if tlsConfig := options.StartTLSConfig; tlsConfig != nil {
|
||||||
s.l.TLSConfig = tlsConfig
|
s.l.TLSConfig = tlsConfig
|
||||||
s.log.Info().Interface("tls.certificates", tlsConfig.Certificates).Msg("enabling LDAP over TLS")
|
s.log.Info().
|
||||||
|
Str("tls.min_version", tls.VersionName(tlsConfig.MinVersion)).
|
||||||
|
Str("tls.max_version", tls.VersionName(tlsConfig.MaxVersion)).
|
||||||
|
Interface("tls.cipher_suites", _tls.CipherSuiteNames(tlsConfig.CipherSuites)).
|
||||||
|
Msg("enabling LDAP over TLS")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tlsConfig := options.LDAPSTLSConfig; tlsConfig != nil {
|
||||||
|
s.ldapstls = tlsConfig
|
||||||
|
s.log.Info().
|
||||||
|
Str("tls.min_version", tls.VersionName(tlsConfig.MinVersion)).
|
||||||
|
Str("tls.max_version", tls.VersionName(tlsConfig.MaxVersion)).
|
||||||
|
Interface("tls.cipher_suites", _tls.CipherSuiteNames(tlsConfig.CipherSuites)).
|
||||||
|
Msg("enabling LDAPS")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, backend := range s.c.Backends {
|
for i, backend := range s.c.Backends {
|
||||||
@@ -133,7 +150,7 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
|||||||
case "plugin":
|
case "plugin":
|
||||||
plug, err := plugin.Open(backend.Plugin)
|
plug, err := plugin.Open(backend.Plugin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to load specified backend plugin: %s", err))
|
return nil, fmt.Errorf("unable to load specified backend plugin: %s", err)
|
||||||
}
|
}
|
||||||
nph, err := plug.Lookup(backend.PluginHandler)
|
nph, err := plug.Lookup(backend.PluginHandler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -155,6 +172,19 @@ func NewServer(opts ...Option) (*LdapSvc, error) {
|
|||||||
handler.Monitor(s.monitor),
|
handler.Monitor(s.monitor),
|
||||||
handler.Tracer(s.tracer),
|
handler.Tracer(s.tracer),
|
||||||
)
|
)
|
||||||
|
case "embed":
|
||||||
|
h, err = NewEmbed(
|
||||||
|
handler.Backend(backend),
|
||||||
|
handler.Logger(&s.log),
|
||||||
|
handler.Config(s.c),
|
||||||
|
handler.YubiAuth(s.yubiAuth),
|
||||||
|
handler.LDAPHelper(loh),
|
||||||
|
handler.Monitor(s.monitor),
|
||||||
|
handler.Tracer(s.tracer),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported backend %s - must be one of 'config', 'ldap','owncloud' or 'plugin'", backend.Datastore)
|
return nil, fmt.Errorf("unsupported backend %s - must be one of 'config', 'ldap','owncloud' or 'plugin'", backend.Datastore)
|
||||||
}
|
}
|
||||||
@@ -186,11 +216,11 @@ func (s *LdapSvc) ListenAndServe() error {
|
|||||||
// ListenAndServeTLS listens on the TCP network address s.c.LDAPS.Listen
|
// ListenAndServeTLS listens on the TCP network address s.c.LDAPS.Listen
|
||||||
func (s *LdapSvc) ListenAndServeTLS() error {
|
func (s *LdapSvc) ListenAndServeTLS() error {
|
||||||
s.log.Info().Str("address", s.c.LDAPS.Listen).Msg("LDAPS server listening")
|
s.log.Info().Str("address", s.c.LDAPS.Listen).Msg("LDAPS server listening")
|
||||||
return s.l.ListenAndServeTLS(
|
listener, err := tls.Listen("tcp", s.c.LDAPS.Listen, s.ldapstls)
|
||||||
s.c.LDAPS.Listen,
|
if err != nil {
|
||||||
s.c.LDAPS.Cert,
|
return err
|
||||||
s.c.LDAPS.Key,
|
}
|
||||||
)
|
return s.l.Serve(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown ends listeners by sending true to the ldap serves quit channel
|
// Shutdown ends listeners by sending true to the ldap serves quit channel
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#################
|
||||||
|
# glauth.conf
|
||||||
|
|
||||||
|
#################
|
||||||
|
# General configuration.
|
||||||
|
#debug = true
|
||||||
|
syslog = true
|
||||||
|
|
||||||
|
#################
|
||||||
|
# Server configuration.
|
||||||
|
[ldap]
|
||||||
|
enabled = true
|
||||||
|
listen = "0.0.0.0:3893"
|
||||||
|
|
||||||
|
[ldaps]
|
||||||
|
enabled = false
|
||||||
|
listen = "0.0.0.0:636"
|
||||||
|
cert = "glauth.crt"
|
||||||
|
key = "glauth.key"
|
||||||
|
|
||||||
|
#################
|
||||||
|
# The backend section controls the data store.
|
||||||
|
[[backends]]
|
||||||
|
datastore = "ldap"
|
||||||
|
servers = [ "ldap://192.168.1.222:389" ]
|
||||||
|
|
||||||
|
[[backends]]
|
||||||
|
datastore = "config"
|
||||||
|
|
||||||
|
[[users]]
|
||||||
|
name = "otpuser"
|
||||||
|
otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk"
|
||||||
|
|
||||||
|
#################
|
||||||
|
# Enable and configure the optional REST API here.
|
||||||
|
[api]
|
||||||
|
enabled = false
|
||||||
|
tls = true
|
||||||
|
listen = "localhost:5555"
|
||||||
|
cert = "glauth.crt"
|
||||||
|
key = "glauth.key"
|
||||||
|
|
||||||
+17
-7
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#################
|
#################
|
||||||
# General configuration.
|
# General configuration.
|
||||||
debug = true
|
debug = false
|
||||||
# syslog = true
|
# syslog = true
|
||||||
# structuredlog = true
|
# structuredlog = true
|
||||||
#
|
#
|
||||||
@@ -28,7 +28,7 @@ debug = true
|
|||||||
[ldaps]
|
[ldaps]
|
||||||
# to enable ldaps generate a certificate, eg. with:
|
# to enable ldaps generate a certificate, eg. with:
|
||||||
# openssl req -x509 -newkey rsa:4096 -keyout glauth.key -out glauth.crt -days 365 -nodes -subj '/CN=`hostname`'
|
# openssl req -x509 -newkey rsa:4096 -keyout glauth.key -out glauth.crt -days 365 -nodes -subj '/CN=`hostname`'
|
||||||
enabled = false
|
enabled = true
|
||||||
listen = "0.0.0.0:3894"
|
listen = "0.0.0.0:3894"
|
||||||
cert = "glauth.crt"
|
cert = "glauth.crt"
|
||||||
key = "glauth.key"
|
key = "glauth.key"
|
||||||
@@ -48,12 +48,10 @@ debug = true
|
|||||||
[backend]
|
[backend]
|
||||||
datastore = "config"
|
datastore = "config"
|
||||||
baseDN = "dc=glauth,dc=com"
|
baseDN = "dc=glauth,dc=com"
|
||||||
nameformat = "cn"
|
|
||||||
groupformat = "ou"
|
|
||||||
|
|
||||||
# If you are using a client that requires reading the root DSE first
|
# If you are using a client that requires reading the root DSE first
|
||||||
# such as SSSD
|
# such as SSSD
|
||||||
# anonymousdse = true
|
anonymousdse = false
|
||||||
|
|
||||||
## Configure dn format to use structures like
|
## Configure dn format to use structures like
|
||||||
## "uid=serviceuser,cn=svcaccts,$BASEDN" instead of "cn=serviceuser,ou=svcaccts,$BASEDN"
|
## "uid=serviceuser,cn=svcaccts,$BASEDN" instead of "cn=serviceuser,ou=svcaccts,$BASEDN"
|
||||||
@@ -147,6 +145,11 @@ debug = true
|
|||||||
# passappbcrypt = "243261243130244B62463462656F7265504F762E794F324957746D656541326B4B46596275674A79336A476845764B616D65446169784E41384F4432" # dogood
|
# passappbcrypt = "243261243130244B62463462656F7265504F762E794F324957746D656541326B4B46596275674A79336A476845764B616D65446169784E41384F4432" # dogood
|
||||||
otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk"
|
otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk"
|
||||||
|
|
||||||
|
[[users]]
|
||||||
|
name = "danger"
|
||||||
|
uidnumber = 5006
|
||||||
|
primarygroup = 5503
|
||||||
|
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# The groups section contains a hardcoded list of valid users.
|
# The groups section contains a hardcoded list of valid users.
|
||||||
@@ -159,9 +162,16 @@ debug = true
|
|||||||
gidnumber = 5502
|
gidnumber = 5502
|
||||||
|
|
||||||
[[groups]]
|
[[groups]]
|
||||||
name = "vpn"
|
name = "umbrella"
|
||||||
gidnumber = 5503
|
gidnumber = 5503
|
||||||
includegroups = [ 5501 ]
|
includegroups = [ 5504 ]
|
||||||
|
|
||||||
|
[[groups]]
|
||||||
|
name = "danger"
|
||||||
|
gidnumber = 5504
|
||||||
|
[[groups.capabilities]]
|
||||||
|
action = "search"
|
||||||
|
object = "dc=glauth,dc=com"
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# Enable and configure the optional REST API here.
|
# Enable and configure the optional REST API here.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
dn: ou=superheros,ou=users,dc=glauth,dc=com
|
dn: ou=superheros,ou=users,dc=glauth,dc=com
|
||||||
ou: superheros
|
ou: superheros
|
||||||
uid: superheros
|
cn: superheros
|
||||||
description: superheros
|
description: superheros
|
||||||
gidNumber: 5501
|
gidNumber: 5501
|
||||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||||
@@ -20,7 +20,7 @@ objectClass: top
|
|||||||
|
|
||||||
dn: ou=svcaccts,ou=users,dc=glauth,dc=com
|
dn: ou=svcaccts,ou=users,dc=glauth,dc=com
|
||||||
ou: svcaccts
|
ou: svcaccts
|
||||||
uid: svcaccts
|
cn: svcaccts
|
||||||
description: svcaccts
|
description: svcaccts
|
||||||
gidNumber: 5502
|
gidNumber: 5502
|
||||||
uniqueMember: cn=serviceuser,ou=svcaccts,ou=users,dc=glauth,dc=com
|
uniqueMember: cn=serviceuser,ou=svcaccts,ou=users,dc=glauth,dc=com
|
||||||
@@ -30,7 +30,7 @@ objectClass: top
|
|||||||
|
|
||||||
dn: ou=vpnaccess,ou=users,dc=glauth,dc=com
|
dn: ou=vpnaccess,ou=users,dc=glauth,dc=com
|
||||||
ou: vpnaccess
|
ou: vpnaccess
|
||||||
uid: vpnaccess
|
cn: vpnaccess
|
||||||
description: vpnaccess
|
description: vpnaccess
|
||||||
gidNumber: 5503
|
gidNumber: 5503
|
||||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||||
@@ -50,7 +50,7 @@ objectClass: top
|
|||||||
|
|
||||||
dn: ou=allaccs,ou=users,dc=glauth,dc=com
|
dn: ou=allaccs,ou=users,dc=glauth,dc=com
|
||||||
ou: allaccs
|
ou: allaccs
|
||||||
uid: allaccs
|
cn: allaccs
|
||||||
description: allaccs
|
description: allaccs
|
||||||
gidNumber: 5504
|
gidNumber: 5504
|
||||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||||
@@ -72,7 +72,7 @@ objectClass: top
|
|||||||
|
|
||||||
dn: ou=mailadmin,ou=users,dc=glauth,dc=com
|
dn: ou=mailadmin,ou=users,dc=glauth,dc=com
|
||||||
ou: mailadmin
|
ou: mailadmin
|
||||||
uid: mailadmin
|
cn: mailadmin
|
||||||
description: mailadmin
|
description: mailadmin
|
||||||
gidNumber: 5505
|
gidNumber: 5505
|
||||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||||
@@ -88,7 +88,7 @@ objectClass: top
|
|||||||
|
|
||||||
dn: ou=webmail,ou=users,dc=glauth,dc=com
|
dn: ou=webmail,ou=users,dc=glauth,dc=com
|
||||||
ou: webmail
|
ou: webmail
|
||||||
uid: webmail
|
cn: webmail
|
||||||
description: webmail
|
description: webmail
|
||||||
gidNumber: 5506
|
gidNumber: 5506
|
||||||
objectClass: posixGroup
|
objectClass: posixGroup
|
||||||
@@ -96,7 +96,7 @@ objectClass: top
|
|||||||
|
|
||||||
dn: ou=fulltime,ou=users,dc=glauth,dc=com
|
dn: ou=fulltime,ou=users,dc=glauth,dc=com
|
||||||
ou: fulltime
|
ou: fulltime
|
||||||
uid: fulltime
|
cn: fulltime
|
||||||
description: fulltime
|
description: fulltime
|
||||||
gidNumber: 5507
|
gidNumber: 5507
|
||||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||||
|
|||||||
@@ -24,6 +24,22 @@ echo "Fixing CI_BUILD_DIR"
|
|||||||
|
|
||||||
# This script requires that "$CI_BUILD_DIR" is set to the repo root
|
# This script requires that "$CI_BUILD_DIR" is set to the repo root
|
||||||
|
|
||||||
|
GOOS="$(go env GOOS)"
|
||||||
|
GOARCH="$(go env GOARCH)"
|
||||||
|
if [[ "$GOARCH" = "arm" ]]; then
|
||||||
|
DIST_ARCH="arm-$(go env GOARM)"
|
||||||
|
else
|
||||||
|
DIST_ARCH="$GOARCH"
|
||||||
|
fi
|
||||||
|
GLAUTH_BINARY="$CI_BUILD_DIR/bin/$GOOS$GOARCH/glauth"
|
||||||
|
if [[ ! -x "$GLAUTH_BINARY" ]]; then
|
||||||
|
GLAUTH_BINARY="$CI_BUILD_DIR/bin/glauth-$GOOS-$DIST_ARCH"
|
||||||
|
fi
|
||||||
|
if [[ ! -x "$GLAUTH_BINARY" ]]; then
|
||||||
|
echo "Unable to find a runnable GLAuth binary: $GLAUTH_BINARY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Ensure ldap utils are installed (for example - when running this outside of CI)
|
# Ensure ldap utils are installed (for example - when running this outside of CI)
|
||||||
if [[ ! `which ldapsearch` ]]; then
|
if [[ ! `which ldapsearch` ]]; then
|
||||||
sudo apt-get -qq update && sudo apt-get -qq install -y ldap-utils || exit 1;
|
sudo apt-get -qq update && sudo apt-get -qq install -y ldap-utils || exit 1;
|
||||||
@@ -33,14 +49,14 @@ fi
|
|||||||
echo "";
|
echo "";
|
||||||
echo ""
|
echo ""
|
||||||
echo "Version string of tested binary:"
|
echo "Version string of tested binary:"
|
||||||
"$CI_BUILD_DIR/bin/linuxamd64/glauth" --version
|
"$GLAUTH_BINARY" --version
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Start in background, capture PID
|
# Start in background, capture PID
|
||||||
"$CI_BUILD_DIR/bin/linuxamd64/glauth" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &> /dev/null &
|
"$GLAUTH_BINARY" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &> /dev/null &
|
||||||
|
|
||||||
# Use this instead to see glauth logs while running
|
# Use this instead to see glauth logs while running
|
||||||
# "$CI_BUILD_DIR/bin/linuxamd64/glauth" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &
|
# "$CI_BUILD_DIR/bin/$(go env GOOS)$(go env GOARCH)/glauth" -c "$CI_BUILD_DIR/scripts/ci/test-config.cfg" &
|
||||||
glauthPid="$!"
|
glauthPid="$!"
|
||||||
|
|
||||||
echo "Running glauth at PID=$glauthPid"
|
echo "Running glauth at PID=$glauthPid"
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
-- Seed data for TestSQLitePlugin. The schema itself is created by the plugin's
|
||||||
|
-- CreateSchema() on first start, so this file only inserts rows.
|
||||||
|
|
||||||
|
INSERT INTO ldapgroups(name, gidnumber)
|
||||||
|
VALUES('superheros', 5501);
|
||||||
|
INSERT INTO ldapgroups(name, gidnumber)
|
||||||
|
VALUES('svcaccts', 5502);
|
||||||
|
INSERT INTO ldapgroups(name, gidnumber)
|
||||||
|
VALUES('civilians', 5503);
|
||||||
|
INSERT INTO ldapgroups(name, gidnumber)
|
||||||
|
VALUES('caped', 5504);
|
||||||
|
INSERT INTO ldapgroups(name, gidnumber)
|
||||||
|
VALUES('lovesailing', 5505);
|
||||||
|
INSERT INTO ldapgroups(name, gidnumber)
|
||||||
|
VALUES('smoker', 5506);
|
||||||
|
INSERT INTO includegroups(parentgroupid, includegroupid)
|
||||||
|
VALUES(5503, 5501);
|
||||||
|
INSERT INTO includegroups(parentgroupid, includegroupid)
|
||||||
|
VALUES(5504, 5502);
|
||||||
|
INSERT INTO includegroups(parentgroupid, includegroupid)
|
||||||
|
VALUES(5504, 5501);
|
||||||
|
INSERT INTO users(name, uidnumber, primarygroup, passsha256)
|
||||||
|
VALUES('hackers', 5001, 5501,
|
||||||
|
'6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a');
|
||||||
|
INSERT INTO users(name, uidnumber, primarygroup, passsha256)
|
||||||
|
VALUES('johndoe', 5002, 5502,
|
||||||
|
'6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a');
|
||||||
|
INSERT INTO users(name, mail, uidnumber, primarygroup, passsha256)
|
||||||
|
VALUES('serviceuser', "serviceuser@example.com", 5003, 5502,
|
||||||
|
'652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0');
|
||||||
|
INSERT INTO users(name, uidnumber, primarygroup, passsha256, othergroups)
|
||||||
|
VALUES('user4', 5004, 5504,
|
||||||
|
'652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0',
|
||||||
|
'5505,5506');
|
||||||
|
INSERT INTO capabilities(userid, action, object)
|
||||||
|
VALUES(5001, "search", "ou=superheros,dc=glauth,dc=com");
|
||||||
|
INSERT INTO capabilities(userid, action, object)
|
||||||
|
VALUES(5003, "search", "*");
|
||||||
Reference in New Issue
Block a user