mirror of
https://github.com/glauth/glauth.git
synced 2026-10-27 14:36:59 +00:00
Compare commits
317 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2eb84d080 | |||
| be396ae635 | |||
| 719f6a2a2d | |||
| ff7a9e6215 | |||
| 45185dafd1 | |||
| aedc0f2867 | |||
| 0774c95c1a | |||
| 9e04c8b756 | |||
| d3df7252ec | |||
| 5123a3da8e | |||
| eabf67e266 | |||
| d68c78a18b | |||
| 645dbb2266 | |||
| eea7bfbb4f | |||
| b498736cfd | |||
| f8dee8da87 | |||
| c4a020a4f5 | |||
| e92008680c | |||
| 8f972db4cf | |||
| e9a4a5623a | |||
| 8e042199a2 | |||
| c0ed90822f | |||
| a5ecc26e06 | |||
| a90f37b23b | |||
| 8476506b8c | |||
| 262b5061ca | |||
| a2c151b0d0 | |||
| 42c448f3c7 | |||
| ed52a91ec4 | |||
| 6d161b7033 | |||
| 5eafb3bc15 | |||
| bc29d321bf | |||
| 540631cc9d | |||
| 3c3ac7e148 | |||
| 14bb205f90 | |||
| 10613f37df | |||
| 56ccb881b5 | |||
| 837da62607 | |||
| 0bf3d4a82a | |||
| f5bb80e024 | |||
| 1a37396109 | |||
| d178281474 | |||
| a0d1069841 | |||
| 67d77324a3 | |||
| 01bdb7148e | |||
| f692394942 | |||
| 46e49b6976 | |||
| 52a0adcbcf | |||
| 2ca5312696 | |||
| 6ee78cd881 | |||
| 1c2b23c00f | |||
| d05630f66b | |||
| 0cf04037a2 | |||
| 7174aba5ab | |||
| 5ddbd4f610 | |||
| 0b6cfcb1b4 | |||
| f3342fa709 | |||
| 545188e5f2 | |||
| c90cbfe5fb | |||
| 1721e5701d | |||
| ebdeae7073 | |||
| 94fe62cfe1 | |||
| f9addbc2c5 | |||
| 5fe8aca852 | |||
| 24455e3988 | |||
| 3ba8e11132 | |||
| accf15410c | |||
| 8739fd6e4f | |||
| 97118ff186 | |||
| 3943e7dc21 | |||
| 114b36f677 | |||
| 0904a24564 | |||
| 498cad48b1 | |||
| 19fa5045ee | |||
| 08a89a9861 | |||
| a4450d4558 | |||
| 0b7910c03c | |||
| 944d602077 | |||
| 596d28efbd | |||
| 6a58f35b14 | |||
| 7f925565a6 | |||
| f5ea3d93bf | |||
| 34a6b30b8f | |||
| 9bbad511cb | |||
| 7cef07931c | |||
| 37fa74892e | |||
| efbd64504d | |||
| 1920c4324f | |||
| 7e7a5f59d1 | |||
| 83f4305e36 | |||
| b45259d567 | |||
| 3f9f67375f | |||
| cb761e8e70 | |||
| 7c3314a504 | |||
| 690917e4e0 | |||
| 0ccf4926ff | |||
| 598a688214 | |||
| 0e7769ff84 | |||
| 6500bbaf36 | |||
| e92197ac08 | |||
| 65385fb82d | |||
| aadf150fec | |||
| 122c86c446 | |||
| 0d03b226b6 | |||
| f41b5ee19e | |||
| aad166b3ec | |||
| 6b14714eb4 | |||
| 3db5c5e54a | |||
| 1a78b51174 | |||
| 9865de68ac | |||
| 32750d2abd | |||
| 021324c775 | |||
| edaddca4e7 | |||
| 1af3cf4f69 | |||
| 3e2e24cadb | |||
| 249388fdd1 | |||
| 45651645e7 | |||
| 42ff05f141 | |||
| 598d746ee8 | |||
| 6800da8bf8 | |||
| 57ee724556 | |||
| ea4cd57233 | |||
| 5d79fd9b03 | |||
| 385cc335ca | |||
| 851c21df04 | |||
| ceefc66dbb | |||
| e26219c2f4 | |||
| 2222a791e4 | |||
| eef3a5c6a0 | |||
| e7195ed983 | |||
| 1299a6d002 | |||
| 95ac9708ed | |||
| 363cd76fa2 | |||
| 82bc471735 | |||
| e1e586f464 | |||
| 31fbd790e8 | |||
| ef3151c287 | |||
| de3d1cec1c | |||
| 7faac6df69 | |||
| e86d6000d9 | |||
| c7098406d0 | |||
| 911e933020 | |||
| 53eddd67c9 | |||
| c2360259af | |||
| 7e49d25591 | |||
| 7267d7b129 | |||
| 0e8937c61e | |||
| fd85683ff0 | |||
| 2b45aefd74 | |||
| 05c537dabd | |||
| 8c8bc06c3b | |||
| fed91e4aef | |||
| 7be05404e1 | |||
| af9062f1a1 | |||
| aed137909a | |||
| 846f0509d6 | |||
| 06afbdcee5 | |||
| 2e0f7f7335 | |||
| b07cd1f256 | |||
| 2ccb8ce02e | |||
| 5dfbbb2f4b | |||
| 3a30656c18 | |||
| 3f53bb983a | |||
| 3b7a548389 | |||
| 0ec6f15957 | |||
| be26675ef8 | |||
| 8ef3e2b8d8 | |||
| ccb839f0a5 | |||
| 1b92cfbae6 | |||
| 8223029345 | |||
| 7c7934aea3 | |||
| 9c9294485b | |||
| 4cf38893ac | |||
| 674a6bdbf4 | |||
| 7b082dccb8 | |||
| 10b0191818 | |||
| 53ddd3c4f4 | |||
| 2065fc39f4 | |||
| e2724eadc2 | |||
| 9c197cc35e | |||
| 25a1648706 | |||
| cbb84b8641 | |||
| 2eb2215ae4 | |||
| 225f1b441b | |||
| 5681dc4d02 | |||
| bf5ddba2be | |||
| fcf784ecf0 | |||
| 07763f52e6 | |||
| 262465d63b | |||
| f28f1a115b | |||
| f4ceb0c3d4 | |||
| 9fb9c87625 | |||
| faed82ad44 | |||
| fd3ac7e4bb | |||
| 4f029234b2 | |||
| d6ba7d0cbc | |||
| 4d42af8aac | |||
| fda48f5524 | |||
| b7cfc11f5c | |||
| bbb381a68e | |||
| 28136302b7 | |||
| 4e600736f2 | |||
| 2d4f5d5476 | |||
| 29cf021694 | |||
| 592fdf4e79 | |||
| a92f9a7028 | |||
| 182d7c0496 | |||
| 6278bc34d4 | |||
| 78a98d75a9 | |||
| 6928b3b608 | |||
| ac16a07a63 | |||
| 363336bf94 | |||
| 07644bd957 | |||
| 558c7de15a | |||
| 9b90466286 | |||
| 3445f388b0 | |||
| 14139e878d | |||
| b6c6730cfd | |||
| b93d612e36 | |||
| 63879925c5 | |||
| 0ff1daac96 | |||
| bc4ab91888 | |||
| b8fd08b92f | |||
| c9b40b87d4 | |||
| c69168c3d1 | |||
| 98ea83c9e0 | |||
| 2243d3d049 | |||
| f793f3a08c | |||
| ba364f12c9 | |||
| 28802ff87d | |||
| 75fa168e9a | |||
| 7a573aad93 | |||
| 9f349d10c8 | |||
| a02544ac8b | |||
| 3acd492e61 | |||
| bd9a5e47ee | |||
| 2e70a47dd6 | |||
| e546a1a289 | |||
| c550eb60e9 | |||
| 2b4aa3b78d | |||
| 6fbd8105cd | |||
| a03a26960d | |||
| 45a2671f46 | |||
| 5e1ed70865 | |||
| 3a13387be2 | |||
| e606ecbb56 | |||
| d9183b8f74 | |||
| 72c8e84a0d | |||
| c162ed8366 | |||
| 986a9187ee | |||
| a835e569cd | |||
| d410b01955 | |||
| ff6cb9a9d5 | |||
| 6516741b3c | |||
| 5c1a39bd47 | |||
| a21d93bbd7 | |||
| 3a513c4ee6 | |||
| 6a3f96c04d | |||
| 2020579614 | |||
| 47401aac5f | |||
| 6cd27aa790 | |||
| 9495943701 | |||
| 8de56c87a9 | |||
| 208fb1e33d | |||
| 32a13ec85a | |||
| a75743ef7d | |||
| fef26916e9 | |||
| 8e48638f05 | |||
| 93a6a5542f | |||
| c431a6e426 | |||
| a9837f3112 | |||
| 2d7a2ab8ce | |||
| bc94f47c9e | |||
| 39b50ec92a | |||
| 50a78e3c56 | |||
| 5e2114e04b | |||
| 706c144f82 | |||
| 5519634a3e | |||
| b32db95f4f | |||
| 0b1c979247 | |||
| b04ff2dd67 | |||
| 94574e50a7 | |||
| 1155d214ed | |||
| 9ae4613a7f | |||
| 8d808c80a0 | |||
| 5728484e61 | |||
| 6df835dd68 | |||
| 80883e4a57 | |||
| 02970c82ff | |||
| 7124c108a7 | |||
| 136d7d7833 | |||
| f0cf6488e4 | |||
| 1876eb9ff7 | |||
| dc90cd6819 | |||
| c2aca63246 | |||
| 60ac4368c6 | |||
| 64fbf20dcd | |||
| de571e8cb6 | |||
| c232ee0476 | |||
| 4f82bf2baf | |||
| 7608bc0133 | |||
| 2ae84a9034 | |||
| ac85255d86 | |||
| 2a16b13a01 | |||
| 5b84deb1c1 | |||
| c5cc0f5572 | |||
| dd71d9ac4e | |||
| 5f5c12e78d | |||
| d5a1b6f216 | |||
| 82bff3fc36 | |||
| fd9aaa243d | |||
| e2c9210beb | |||
| e03e9216fa | |||
| 70ff3600ec | |||
| 68edcdc228 | |||
| f076f868dc | |||
| f039bbb964 |
@@ -0,0 +1,54 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/go
|
||||
{
|
||||
"name": "glauth",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/go:0-1.19-bullseye",
|
||||
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
"features": {
|
||||
"docker-in-docker": {
|
||||
"version": "latest",
|
||||
"moby": true
|
||||
},
|
||||
"ghcr.io/rocker-org/devcontainer-features/apt-packages:1": {
|
||||
"packages": "oathtool,ldap-utils"
|
||||
}
|
||||
},
|
||||
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
// Configure properties specific to VS Code.
|
||||
"vscode": {
|
||||
"settings": {},
|
||||
"extensions": [
|
||||
"golang.go",
|
||||
"ms-azuretools.vscode-docker"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"containerEnv": {
|
||||
"REPO": "glauth"
|
||||
},
|
||||
|
||||
"capAdd": ["SYS_PTRACE"],
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [9000],
|
||||
|
||||
// Use 'portsAttributes' to set default properties for specific forwarded ports.
|
||||
// More info: https://containers.dev/implementors/json_reference/#port-attributes
|
||||
"portsAttributes": {
|
||||
"3893": {
|
||||
"label": "LDAP",
|
||||
"onAutoForward": "notify"
|
||||
},
|
||||
"5555": {
|
||||
"label": "Web UI",
|
||||
"onAutoForward": "openBrowser"
|
||||
}
|
||||
},
|
||||
|
||||
"postCreateCommand": "cd v2 && make setup"
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
# \todo Eliminate duplication when/if Dependabot supports YAML anchors
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
labels:
|
||||
- dependencies
|
||||
- actions
|
||||
schedule:
|
||||
day: sunday
|
||||
interval: weekly
|
||||
- package-ecosystem: gomod
|
||||
directory: /v2
|
||||
labels:
|
||||
- dependencies
|
||||
- go
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: friday
|
||||
@@ -0,0 +1,25 @@
|
||||
Thank you for making a pull request!
|
||||
|
||||
A few things to be aware of as you're working on your PR:
|
||||
|
||||
## WIP Tag
|
||||
Incomplete PRs are more than welcome - it can be useful to collaborate before
|
||||
implementation of an idea is complete. However, if your PR is not ready
|
||||
for merge, please add [WIP] to the end of the title (work-in-progress).
|
||||
|
||||
## Tests
|
||||
Before committing, you are encouraged to run the small but growing test
|
||||
suite. This is accomplished by `make test`. Additionally, if you are adding
|
||||
new functionality, consider adding tests covering your feature.
|
||||
|
||||
## CI
|
||||
Each push to a branch connected to a PR will be run through GLAuth's
|
||||
CI system. Please use these to your advantage. In particular, the Github Actions
|
||||
integration tests rely on the LDAP queries returning with a set result,
|
||||
so if your changes will change the output, CI will likely fail.
|
||||
|
||||
To update, run `make fast && make updatetest && make test`. This will
|
||||
delete the output snapshots provided and make new ones. You can then
|
||||
inspect the changes and commit them.
|
||||
|
||||
Similarly, check codeclimate and try to fix what you find there if it fails.
|
||||
@@ -0,0 +1,39 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.21.x]
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Updating packages database
|
||||
run: sudo apt-get -qq update
|
||||
- name: Install CLI Dependencies
|
||||
run: sudo apt-get install -y ldap-utils oathtool libpam0g-dev
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Fetch Go dependencies
|
||||
working-directory: ./v2
|
||||
run: go get -t -v ./...
|
||||
- name: Fail if a .go file hasn't been formatted with 'go fmt'
|
||||
working-directory: ./v2
|
||||
run: diff -u <(echo -n) <(gofmt -d ./)
|
||||
- name: Full compile test
|
||||
working-directory: ./v2
|
||||
run: make fast
|
||||
- name: Output hashes to the build log
|
||||
working-directory: ./v2
|
||||
run: cat bin/*/glauth.sha256
|
||||
- name: Integration test with compiled binary
|
||||
working-directory: ./v2
|
||||
run: make test
|
||||
@@ -0,0 +1,41 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: "46 1 * * 3"
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ javascript ]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{ matrix.language }}"
|
||||
@@ -0,0 +1,22 @@
|
||||
# This workflow was added by CodeSee. Learn more at https://codesee.io/
|
||||
# This is v2.0 of this workflow file
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
name: CodeSee
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
codesee:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
name: Analyze the repo with CodeSee
|
||||
steps:
|
||||
- uses: Codesee-io/codesee-action@v2
|
||||
with:
|
||||
codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
|
||||
@@ -0,0 +1,20 @@
|
||||
name: release-please
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
||||
config-file: release-please-config.json
|
||||
manifest-file: .release-please-manifest.json
|
||||
+19
-5
@@ -1,7 +1,21 @@
|
||||
# Ignore default config file for testing
|
||||
glauth.cfg
|
||||
.*.swp
|
||||
v2/certs/
|
||||
v2/bin
|
||||
v2/docker/assets/linux
|
||||
v2/gl.db
|
||||
v2/buildlogs
|
||||
.vscode/
|
||||
|
||||
# Ignore the built binary during testing
|
||||
glauth
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
### Go Patch ###
|
||||
/vendor/
|
||||
/Godeps/
|
||||
|
||||
# Various
|
||||
go.work.sum
|
||||
|
||||
# gomocks auto-generated
|
||||
**/mock_*.go
|
||||
|
||||
bin
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
[submodule "v2/pkg/plugins/glauth-sqlite"]
|
||||
path = v2/pkg/plugins/glauth-sqlite
|
||||
url = git@github.com:glauth/glauth-sqlite
|
||||
[submodule "v2/pkg/plugins/glauth-mysql"]
|
||||
path = v2/pkg/plugins/glauth-mysql
|
||||
url = git@github.com:glauth/glauth-mysql
|
||||
[submodule "v2/pkg/plugins/glauth-postgres"]
|
||||
path = v2/pkg/plugins/glauth-postgres
|
||||
url = git@github.com:glauth/glauth-postgres
|
||||
[submodule "v2/pkg/plugins/glauth-pam"]
|
||||
path = v2/pkg/plugins/glauth-pam
|
||||
url = git@github.com:glauth/glauth-pam
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"v2": "2.5.0"
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.3.x # Test an old version, to be sure it works
|
||||
- 1.9.x # last version
|
||||
- 1.10.x # current version
|
||||
|
||||
# Speed up git clones
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
|
||||
# Anything in before_script that returns a nonzero exit code will
|
||||
# flunk the build and immediately stop. It's sorta like having
|
||||
# set -e enabled in bash.
|
||||
before_script:
|
||||
- GO_FILES=$(find . -iname '*.go' -type f | grep -v /vendor/) # All the .go files, excluding vendor/
|
||||
#- go get github.com/golang/lint/golint # Linter
|
||||
#- go get honnef.co/go/tools/cmd/megacheck # Badass static analyzer/linter
|
||||
# - go get github.com/fzipp/gocyclo
|
||||
|
||||
|
||||
# Fetch dependencies
|
||||
- go get -t -v ./...
|
||||
|
||||
|
||||
script:
|
||||
- diff -u <(echo -n) <(gofmt -d ./) # Fail if a .go file hasn't been formatted with 'go fmt'
|
||||
# - go test -v -race ./... # Run all the tests with the race detector enabled
|
||||
# - go vet ./... # go vet is the official Go static analyzer
|
||||
# - megacheck ./... # "go vet on steroids" + linter
|
||||
# - gocyclo -over 19 $GO_FILES # forbid code with huge functions
|
||||
# - golint -set_exit_status $(go list ./...) # one last linter
|
||||
|
||||
|
||||
|
||||
# Unit tests
|
||||
# - tbd - use 'go test' here when we have unit tests written. example command below. This will generate output for codecov
|
||||
# - go test -race -coverprofile=coverage.txt -covermode=atomic
|
||||
|
||||
# Full compile test
|
||||
- go build -o ./glauth glauth.go bindata.go ldapbackend.go webapi.go configbackend.go
|
||||
|
||||
# Integration test with compiled binary
|
||||
- scripts/travis/integration-test.sh "scripts/travis/test-config.cfg"
|
||||
|
||||
|
||||
# after_success:
|
||||
# - bash <(curl -s https://codecov.io/bash)
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
#################
|
||||
# Build Step
|
||||
#################
|
||||
|
||||
FROM golang:alpine as build
|
||||
MAINTAINER Ben Yanke <ben@benyanke.com>
|
||||
|
||||
# Setup work env
|
||||
RUN mkdir /app /tmp/gocode
|
||||
ADD . /app/
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
# Required envs for GO
|
||||
ENV GOPATH=/tmp/gocode
|
||||
ENV GOOS=linux
|
||||
ENV GOARCH=amd64
|
||||
|
||||
# Only needed for alpine builds
|
||||
RUN apk add --no-cache git bzr
|
||||
|
||||
# Install deps
|
||||
RUN go get -d -v ./...
|
||||
|
||||
# Build
|
||||
RUN go build -o /app/glauth glauth.go bindata.go ldapbackend.go webapi.go configbackend.go
|
||||
|
||||
#################
|
||||
# Run Step
|
||||
#################
|
||||
|
||||
FROM golang:alpine as run
|
||||
MAINTAINER Ben Yanke <ben@benyanke.com>
|
||||
|
||||
# Copies a sample config to be used if a volume isn't mounted with user's config
|
||||
ADD sample-simple.cfg /app/config/config.cfg
|
||||
|
||||
# Copy binary from build container
|
||||
COPY --from=build /app/glauth /app/glauth
|
||||
|
||||
# Copy docker specific scripts from build container
|
||||
COPY --from=build /app/scripts/docker/start.sh /app/docker/
|
||||
COPY --from=build /app/scripts/docker/default-config.cfg /app/docker/
|
||||
|
||||
# Install init
|
||||
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64 && chmod +x /usr/local/bin/dumb-init
|
||||
|
||||
# Expose web and LDAP ports
|
||||
EXPOSE 389 5555
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
|
||||
CMD ["/bin/sh", "/app/docker/start.sh"]
|
||||
@@ -1,6 +1,6 @@
|
||||
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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
VERSION=$(shell bin/glauth64 --version)
|
||||
|
||||
|
||||
run:
|
||||
go run glauth.go bindata.go ldapbackend.go webapi.go configbackend.go -c glauth.cfg
|
||||
|
||||
all: bindata binaries
|
||||
|
||||
binaries: bindata linux32 linux64 darwin64
|
||||
|
||||
bindata:
|
||||
go-bindata -pkg=main assets
|
||||
|
||||
linux32: bindata
|
||||
GOOS=linux GOARCH=386 go build -o bin/glauth32 glauth.go bindata.go ldapbackend.go webapi.go configbackend.go
|
||||
|
||||
linux64: bindata
|
||||
GOOS=linux GOARCH=amd64 go build -o bin/glauth64 glauth.go bindata.go ldapbackend.go webapi.go configbackend.go
|
||||
|
||||
darwin64: bindata
|
||||
GOOS=darwin GOARCH=amd64 go build -o bin/glauthOSX glauth.go bindata.go ldapbackend.go webapi.go configbackend.go
|
||||
|
||||
@@ -1,36 +1,51 @@
|
||||
|
||||
# GLAuth: LDAP authentication server for developers
|
||||
[](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.
|
||||
|
||||
[](https://travis-ci.org/glauth/glauth)
|
||||
[](https://github.com/glauth/glauth/graphs/commit-activity)
|
||||
|
||||
[](https://hub.docker.com/r/glauth/glauth/)
|
||||
[](https://hub.docker.com/r/glauth/glauth/)
|
||||
|
||||
[](https://codeclimate.com/github/glauth/glauth/maintainability)
|
||||
[](https://codeclimate.com/github/glauth/glauth/test_coverage)
|
||||

|
||||

|
||||

|
||||
|
||||
* Centrally manage accounts across your infrastructure
|
||||
* Centrally manage SSH keys, Linux accounts, and passwords for cloud servers.
|
||||
* Lightweight alternative to OpenLDAP and Active Directory for development, or a homelab.
|
||||
* Store your user directory in a local file, S3 or proxy to existing LDAP servers.
|
||||
* Store your user directory in a file, local or in S3; SQL database; or proxy to existing LDAP servers.
|
||||
* Two Factor Authentication (transparent to applications)
|
||||
* Multiple backends can be chained to inject features
|
||||
|
||||
Use it to centralize account management across your Linux servers, your OSX machines, and your support applications (Jenkins, Apache/Nginx, Graylog2, and many more!).
|
||||
|
||||
### Contributing
|
||||
Please base all PRs on [dev](https://github.com/nmcclain/glauth/tree/dev), not master.
|
||||
- Please base all Pull Requests on [dev](https://github.com/glauth/glauth/tree/dev), not master.
|
||||
- Format your code automatically using `gofmt -d ./` before committing
|
||||
|
||||
### 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!*
|
||||
|
||||
1. Download a precompiled binary from the [releases](https://github.com/glauth/glauth/releases) page.
|
||||
2. Download the [example config file](https://github.com/glauth/glauth/blob/master/sample-simple.cfg).
|
||||
2. Download the [example config file](https://github.com/glauth/glauth/blob/master/v2/sample-simple.cfg).
|
||||
3. Start the GLAuth server, referencing the path to the desired config file with `-c`.
|
||||
- `sudo ./glauth64 -c sample-simple.cfg`
|
||||
- `./glauth64 -c sample-simple.cfg`
|
||||
4. Test with traditional LDAP tools
|
||||
- For example: `ldapsearch -LLL -H ldap://localhost:389 -D cn=serviceuser,ou=svcaccts,dc=glauth,dc=com -w mysecret -x -bdc=glauth,dc=com cn=hackers`
|
||||
- For example: `ldapsearch -LLL -H ldap://localhost:3893 -D cn=serviceuser,ou=svcaccts,dc=glauth,dc=com -w mysecret -x -bdc=glauth,dc=com cn=hackers`
|
||||
|
||||
### Make Commands
|
||||
|
||||
Note - makefile uses git data to inject build-time variables. For best results, run in the context of the git repo.
|
||||
|
||||
### Documentation
|
||||
|
||||
<h4 align="center">:point_right: The latest version of GLauth's documentation is available at https://glauth.github.io/ :point_left:</h4>
|
||||
|
||||
<hr>
|
||||
|
||||
### Quickstart
|
||||
|
||||
Get started in three short [steps](https://glauth.github.io/docs/quickstart.html)
|
||||
|
||||
### Usage:
|
||||
```
|
||||
@@ -46,6 +61,10 @@ Options:
|
||||
-K <aws_key_id> AWS Key ID.
|
||||
-S <aws_secret_key> AWS Secret Key.
|
||||
-r <aws_region> AWS Region [default: us-east-1].
|
||||
--ldap <address> Listen address for the LDAP server.
|
||||
--ldaps <address> Listen address for the LDAPS server.
|
||||
--ldaps-cert <cert-file> Path to cert file for the LDAPS server.
|
||||
--ldaps-key <key-file> Path to key file for the LDAPS server.
|
||||
-h, --help Show this screen.
|
||||
--version Show version.
|
||||
```
|
||||
@@ -62,81 +81,32 @@ Here's a sample config wth hardcoded users and groups:
|
||||
baseDN = "dc=glauth,dc=com"
|
||||
[[users]]
|
||||
name = "hackers"
|
||||
unixid = 5001
|
||||
uidnumber = 5001
|
||||
primarygroup = 5501
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
sshkeys = [ "ssh-dss AAAAB3..." ]
|
||||
[[users]]
|
||||
name = "uberhackers"
|
||||
uidnumber = 5006
|
||||
primarygroup = 5501
|
||||
passbcrypt = "243261243130244B62463462656F7265504F762E794F324957746D656541326B4B46596275674A79336A476845764B616D65446169784E41384F4432" # dogood
|
||||
[[groups]]
|
||||
name = "superheros"
|
||||
unixid = 5501
|
||||
gidnumber = 5501
|
||||
```
|
||||
To create the password SHA hash, use this command: `echo -n "mysecret" | openssl dgst -sha256`
|
||||
Instead of a local configuration file, GLAuth can fetch its configuration from S3. This is an easy way to ensure redundant GLAuth servers are always in-sync.
|
||||
```unix
|
||||
glauth -c s3://bucketname/glauth.cfg
|
||||
```
|
||||
In order to use S3, you must set your AWS credentials. Either:
|
||||
|
||||
1. set the -K and -S command-line flags **OR**
|
||||
2. set the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables.
|
||||
|
||||
More configuration options are documented here: https://github.com/nmcclain/glauth/blob/master/sample-simple.cfg
|
||||
|
||||
### Required Fields
|
||||
* Name
|
||||
* The user's username
|
||||
* ou
|
||||
* ID of the user's primary group
|
||||
* uidbumber
|
||||
* The user's unix user id
|
||||
* sshPublicKey
|
||||
* Specify an array of public keys
|
||||
|
||||
### Optional Fields
|
||||
* givenname
|
||||
* First name
|
||||
* Example: John
|
||||
* default = blank
|
||||
* sn
|
||||
* Last name
|
||||
* Example: Doe
|
||||
* default = blank
|
||||
* disabled
|
||||
* Specify if account is active.
|
||||
* Set to 'true' (without quotes) to make the LDAP entry add 'AccountStatus = inactive'
|
||||
* default = false (active)
|
||||
* mail
|
||||
* Specify an email
|
||||
* example: jdoe@example.com
|
||||
* default = blank
|
||||
* loginshell
|
||||
* Specify a different login shell for the user
|
||||
* Example: /bin/sh, or /sbin/nologin
|
||||
* default = /bin/bash
|
||||
* homedirectory
|
||||
* Specify an overridden home directory for the user
|
||||
* Example: /home/itadmin
|
||||
* default = /home/[username]
|
||||
|
||||
|
||||
### OpenSSH keys:
|
||||
GLAuth can store a user's SSH authorized keys. Add one or more keys per user as shown above, then setup the goklp helper: https://github.com/appliedtrust/goklp
|
||||
More configuration options are documented [here](https://glauth.github.io/docs/file.html) and in this [sample file](https://github.com/glauth/glauth/blob/master/v2/sample-simple.cfg)
|
||||
|
||||
### Backends:
|
||||
For advanced users, GLAuth supports pluggable backends. Currently, it can use a local file, S3 or an existing LDAP infrastructure. In the future, we hope to have backends that support Mongo, SQL, and other datastores.
|
||||
|
||||
For advanced users, GLAuth supports pluggable backends. Currently, it can use a local file, S3 or an existing LDAP infrastructure. Through the use of optional plugins, you can connect SQL databases, PAM, and other datastores.
|
||||
|
||||
```toml
|
||||
[backend]
|
||||
datastore = "ldap"
|
||||
servers = [ "ldaps://server1:636", "ldaps://server2:636" ]
|
||||
```
|
||||
|
||||
### Production:
|
||||
Any of the architectures above will work for production. Just remember:
|
||||
# Stargazers over time
|
||||
|
||||
* Always use legit SSL certs for production!
|
||||
|
||||
### Building:
|
||||
You'll need go-bindata to build GLAuth:
|
||||
```unix
|
||||
go get github.com/jteeuwen/go-bindata/...
|
||||
```
|
||||
[](https://starchart.cc/glauth/glauth)
|
||||
|
||||
-221
@@ -1,221 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
func bindata_read(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, gz)
|
||||
gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func assets_glauth_css() ([]byte, error) {
|
||||
return bindata_read([]byte{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0x8c, 0x8f,
|
||||
0xc1, 0x72, 0x83, 0x20, 0x14, 0x45, 0xf7, 0x7c, 0xc5, 0x9b, 0x71, 0x1d,
|
||||
0x47, 0x0d, 0xa6, 0x60, 0xbe, 0x86, 0x07, 0x4f, 0xa5, 0x35, 0xe0, 0x00,
|
||||
0x69, 0x3b, 0xed, 0xf4, 0xdf, 0x1b, 0xcd, 0x98, 0x29, 0x71, 0xd3, 0x2d,
|
||||
0xf7, 0xdc, 0x7b, 0x78, 0xac, 0x7c, 0xbd, 0x5e, 0xd0, 0xa7, 0xe0, 0x1d,
|
||||
0x7c, 0x33, 0x00, 0xed, 0x27, 0x1f, 0x3a, 0x28, 0x74, 0x75, 0x94, 0x0d,
|
||||
0x9e, 0x6f, 0x2f, 0xa8, 0xf4, 0xdb, 0x10, 0xfc, 0xd5, 0x99, 0xc3, 0x16,
|
||||
0x92, 0xee, 0xab, 0xbe, 0x3e, 0xb3, 0x1f, 0xc6, 0x8a, 0x98, 0x54, 0x8a,
|
||||
0xb3, 0x72, 0x34, 0x65, 0xfd, 0x23, 0xe7, 0xb2, 0xa5, 0x1d, 0x52, 0x5e,
|
||||
0x28, 0x05, 0xab, 0x9f, 0x50, 0x29, 0x0c, 0xfe, 0x41, 0xb3, 0x54, 0x62,
|
||||
0x2b, 0xf1, 0xb4, 0x7c, 0x64, 0x56, 0xc6, 0x58, 0x37, 0x74, 0x20, 0xe6,
|
||||
0xcf, 0x85, 0x2e, 0x22, 0x85, 0x77, 0x0a, 0xff, 0xc5, 0xd9, 0xd8, 0x2c,
|
||||
0xe4, 0x06, 0x36, 0x52, 0x54, 0x28, 0xef, 0xd6, 0xa4, 0xec, 0x04, 0x69,
|
||||
0xcc, 0x86, 0x5e, 0x7a, 0xa1, 0x85, 0x59, 0x3d, 0xf7, 0xd8, 0xac, 0xf1,
|
||||
0x63, 0x95, 0x2f, 0xab, 0xfb, 0x7b, 0x01, 0x7a, 0xef, 0xd2, 0x21, 0xda,
|
||||
0x2f, 0xea, 0xa0, 0xde, 0xd4, 0xdb, 0x44, 0xe9, 0xe7, 0x4c, 0x22, 0x88,
|
||||
0x73, 0x65, 0x1e, 0xad, 0x0f, 0xb2, 0xc3, 0x98, 0x3a, 0x40, 0x3f, 0x65,
|
||||
0xe6, 0x5b, 0xad, 0x44, 0xeb, 0x4c, 0xd6, 0xad, 0x4f, 0xaa, 0x12, 0xed,
|
||||
0x33, 0x16, 0x49, 0x05, 0x9d, 0x5f, 0x52, 0x2b, 0xd4, 0x52, 0xaf, 0xff,
|
||||
0xf8, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x91, 0x33, 0xcc, 0x6e, 0xee, 0x01,
|
||||
0x00, 0x00,
|
||||
},
|
||||
"assets/glauth.css",
|
||||
)
|
||||
}
|
||||
|
||||
func assets_glauth_js() ([]byte, error) {
|
||||
return bindata_read([]byte{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0xa4, 0x54,
|
||||
0x5d, 0x6b, 0xdb, 0x30, 0x14, 0x7d, 0xcf, 0xaf, 0xb8, 0xf3, 0x02, 0x95,
|
||||
0x59, 0x26, 0x87, 0xbd, 0x86, 0xee, 0xad, 0xd0, 0x0e, 0xd6, 0xc1, 0x96,
|
||||
0x3f, 0xa0, 0x58, 0xd7, 0x89, 0x98, 0x3e, 0x8c, 0x2c, 0x27, 0x1b, 0xc5,
|
||||
0xff, 0x7d, 0x57, 0x96, 0x9d, 0xb8, 0x69, 0x0b, 0x1d, 0x7e, 0x88, 0x13,
|
||||
0xae, 0xce, 0x39, 0x3e, 0xbe, 0xe7, 0xc4, 0x47, 0xe1, 0x41, 0xd9, 0x80,
|
||||
0xfe, 0x28, 0x34, 0xdc, 0xc2, 0x97, 0xf5, 0x7a, 0xbd, 0x59, 0x2c, 0x96,
|
||||
0xac, 0x6a, 0x6d, 0x19, 0x94, 0xb3, 0x2c, 0x87, 0xa7, 0x05, 0x40, 0x5b,
|
||||
0x4b, 0x11, 0xf0, 0x3b, 0x06, 0xaf, 0xca, 0x86, 0xe5, 0x1b, 0x1a, 0x15,
|
||||
0x45, 0x1a, 0x6e, 0x85, 0xd2, 0x71, 0xd2, 0xd1, 0x67, 0x11, 0xe5, 0x02,
|
||||
0x0d, 0x1e, 0x24, 0x89, 0x45, 0xa5, 0x51, 0xe7, 0x5a, 0xa1, 0x57, 0x8d,
|
||||
0x68, 0x93, 0x26, 0x04, 0x5f, 0xf2, 0x3d, 0x86, 0x6f, 0xbf, 0x7e, 0x3c,
|
||||
0x32, 0xc8, 0x0a, 0x89, 0xbb, 0x76, 0x5f, 0x10, 0xa0, 0xc9, 0x56, 0x70,
|
||||
0x36, 0x23, 0x13, 0x2f, 0x31, 0x03, 0x9a, 0x5a, 0x93, 0x26, 0x51, 0xef,
|
||||
0x85, 0x95, 0x1a, 0x77, 0x84, 0xe6, 0xa5, 0x33, 0xb5, 0xd2, 0xc8, 0x60,
|
||||
0xc9, 0xb2, 0x8f, 0x4d, 0x10, 0xa1, 0xa9, 0x85, 0x45, 0xfd, 0x79, 0x44,
|
||||
0x67, 0x39, 0x3f, 0x04, 0x43, 0x8e, 0xa1, 0x7f, 0x8a, 0x24, 0x15, 0x27,
|
||||
0xf1, 0xf7, 0xed, 0x59, 0x94, 0x6e, 0x95, 0x8e, 0x9f, 0xcb, 0x8c, 0xec,
|
||||
0x78, 0x99, 0xf0, 0xdf, 0x6b, 0x65, 0xbe, 0x8b, 0x19, 0x06, 0x28, 0x63,
|
||||
0xf4, 0x33, 0x2d, 0x24, 0x8d, 0x17, 0x26, 0xba, 0x9c, 0x2e, 0xbc, 0x8a,
|
||||
0x4d, 0xb8, 0x2a, 0xce, 0x5b, 0x0b, 0xcc, 0xee, 0xbc, 0x77, 0xfe, 0x43,
|
||||
0x36, 0xa1, 0x0b, 0x7d, 0x12, 0x7f, 0x9b, 0x97, 0x02, 0x0d, 0x86, 0xad,
|
||||
0x32, 0xe8, 0xda, 0xc0, 0x9e, 0x95, 0x68, 0x35, 0xf6, 0x76, 0xd0, 0xa0,
|
||||
0x0a, 0x5e, 0xd7, 0x2d, 0x75, 0xf3, 0xdc, 0xb5, 0xd8, 0xcc, 0xeb, 0xa2,
|
||||
0xc5, 0x59, 0x91, 0xc1, 0xa7, 0xb1, 0xb6, 0xaf, 0xb5, 0x4d, 0xf2, 0xca,
|
||||
0xf9, 0x3b, 0x51, 0x1e, 0x2e, 0xe6, 0x70, 0x3c, 0x03, 0x50, 0x15, 0x30,
|
||||
0xe4, 0x44, 0xfd, 0x3a, 0x68, 0x5c, 0x8e, 0xe0, 0xf2, 0x67, 0x88, 0x88,
|
||||
0xcd, 0x30, 0xee, 0xfa, 0xef, 0xee, 0xff, 0xf2, 0x8b, 0x4a, 0x33, 0xc2,
|
||||
0xeb, 0xb3, 0xe2, 0x07, 0x25, 0x91, 0xe5, 0xbc, 0xf6, 0x58, 0xa3, 0x95,
|
||||
0x5b, 0x37, 0xe8, 0x92, 0x5c, 0x25, 0x24, 0x3e, 0x58, 0x16, 0x5f, 0x00,
|
||||
0xef, 0x8a, 0x74, 0xa0, 0xcd, 0x0e, 0x33, 0x46, 0xf4, 0x5a, 0x92, 0x8b,
|
||||
0xc9, 0x1e, 0x3c, 0xee, 0x55, 0x43, 0x88, 0x7b, 0xd4, 0x35, 0x7a, 0x76,
|
||||
0x13, 0x79, 0x3f, 0x91, 0x1e, 0x50, 0x1d, 0xf1, 0x66, 0x12, 0x58, 0xe9,
|
||||
0x48, 0xe7, 0x4f, 0x58, 0xc1, 0x4e, 0xbb, 0xf2, 0x77, 0xba, 0x65, 0x4c,
|
||||
0xe7, 0xa4, 0xac, 0x74, 0x27, 0x6e, 0x9c, 0x41, 0x1b, 0x46, 0x27, 0x45,
|
||||
0xe1, 0x31, 0xb4, 0xde, 0x42, 0x1a, 0x8f, 0x64, 0xda, 0x84, 0x77, 0xe6,
|
||||
0xd1, 0x9d, 0xd8, 0xb0, 0xba, 0xb7, 0x50, 0xce, 0x1b, 0x11, 0x12, 0xa8,
|
||||
0x43, 0xdd, 0xe0, 0xd3, 0x14, 0x3d, 0xc0, 0xfa, 0xc3, 0xe1, 0xd5, 0xf8,
|
||||
0x2f, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x12, 0x43, 0xad, 0x6a, 0x05, 0x00,
|
||||
0x00,
|
||||
},
|
||||
"assets/glauth.js",
|
||||
)
|
||||
}
|
||||
|
||||
func assets_index_html() ([]byte, error) {
|
||||
return bindata_read([]byte{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0xb4, 0x57,
|
||||
0xeb, 0x6e, 0xdb, 0x36, 0x14, 0xfe, 0x9f, 0xa7, 0x60, 0xb4, 0xbf, 0x93,
|
||||
0x34, 0xa7, 0xeb, 0x96, 0x15, 0xb2, 0x81, 0x2e, 0xcd, 0xd6, 0x00, 0xed,
|
||||
0x1a, 0x24, 0x19, 0xb6, 0xa1, 0x28, 0x0a, 0x9a, 0x3c, 0xb6, 0xe8, 0x50,
|
||||
0xa2, 0x42, 0x52, 0x8e, 0x0d, 0xc1, 0xef, 0xbe, 0x43, 0x51, 0xb6, 0x25,
|
||||
0xcf, 0xf1, 0x0d, 0x2b, 0x10, 0xc4, 0xbc, 0x7c, 0xe7, 0x7e, 0xe1, 0x51,
|
||||
0x72, 0xfe, 0xee, 0xd3, 0xd5, 0xc3, 0x3f, 0xb7, 0xd7, 0x24, 0xb5, 0x99,
|
||||
0x1c, 0x9c, 0x25, 0xee, 0x87, 0x48, 0x9a, 0x8f, 0xfb, 0x01, 0xe4, 0xc1,
|
||||
0xe0, 0x8c, 0x90, 0x24, 0x05, 0xca, 0xdd, 0x02, 0x97, 0x19, 0x58, 0x4a,
|
||||
0x58, 0x4a, 0xb5, 0x01, 0xdb, 0x0f, 0x4a, 0x3b, 0x0a, 0x2f, 0x83, 0xf6,
|
||||
0x55, 0x6a, 0x6d, 0x11, 0xc2, 0x53, 0x29, 0xa6, 0xfd, 0xe0, 0xef, 0xf0,
|
||||
0xcf, 0xb7, 0xe1, 0x95, 0xca, 0x0a, 0x6a, 0xc5, 0x50, 0x42, 0x40, 0x98,
|
||||
0xca, 0x2d, 0xe4, 0x48, 0x77, 0x73, 0xdd, 0x07, 0x3e, 0x86, 0x0e, 0x65,
|
||||
0x4e, 0x33, 0xe8, 0x07, 0x53, 0x01, 0xcf, 0x85, 0xd2, 0xb6, 0x05, 0x7e,
|
||||
0x16, 0xdc, 0xa6, 0x7d, 0x0e, 0x53, 0xc1, 0x20, 0xac, 0x37, 0xdf, 0x13,
|
||||
0x91, 0x0b, 0x2b, 0xa8, 0x0c, 0x0d, 0xa3, 0x12, 0xfa, 0xbd, 0x2d, 0x8c,
|
||||
0x38, 0x18, 0xa6, 0x45, 0x61, 0x85, 0xca, 0x5b, 0xbc, 0xb6, 0x00, 0x69,
|
||||
0x69, 0x53, 0xa5, 0xbb, 0x18, 0x0f, 0xb2, 0xc2, 0x4a, 0x18, 0xfc, 0xfe,
|
||||
0xe1, 0x2d, 0x22, 0xc8, 0xbd, 0xa5, 0xb6, 0x34, 0x49, 0xec, 0x0f, 0x1b,
|
||||
0x84, 0x14, 0xf9, 0x23, 0xd1, 0x20, 0xfb, 0x81, 0xb1, 0x73, 0x09, 0x26,
|
||||
0x05, 0x40, 0xcd, 0x53, 0x0d, 0xa3, 0x7e, 0xe0, 0x3c, 0x61, 0xde, 0xc4,
|
||||
0x71, 0x46, 0x67, 0x8c, 0xe7, 0xd1, 0x50, 0x29, 0x6b, 0xac, 0xa6, 0x85,
|
||||
0xdb, 0x30, 0x95, 0xc5, 0xab, 0x83, 0xf8, 0x55, 0x74, 0x11, 0xfd, 0x10,
|
||||
0x33, 0x63, 0xd6, 0x67, 0x51, 0x26, 0x10, 0x65, 0xcc, 0x52, 0xdf, 0x6f,
|
||||
0x26, 0x28, 0xb4, 0x29, 0x64, 0x70, 0x8c, 0x38, 0x6a, 0x30, 0xf4, 0x26,
|
||||
0x1e, 0x4b, 0xe7, 0xb8, 0x86, 0xc8, 0x53, 0x9d, 0x87, 0x21, 0x79, 0xff,
|
||||
0xf0, 0xf1, 0xc3, 0x6b, 0x62, 0x52, 0x91, 0x11, 0x9a, 0x73, 0x72, 0x07,
|
||||
0xa6, 0x50, 0x39, 0x8f, 0x26, 0x86, 0xdc, 0x5c, 0x5f, 0x12, 0x53, 0x16,
|
||||
0x2e, 0xb8, 0x44, 0x8d, 0x1a, 0x20, 0x48, 0x94, 0x9e, 0x5b, 0x53, 0x83,
|
||||
0x33, 0xe0, 0x82, 0x92, 0xa7, 0x12, 0xb4, 0x00, 0x43, 0xc2, 0x70, 0xb0,
|
||||
0x62, 0xfb, 0x59, 0x8c, 0x88, 0xb4, 0xc8, 0x82, 0xfc, 0xf2, 0xc5, 0x9f,
|
||||
0xe2, 0xb9, 0x8f, 0x2f, 0x31, 0x9a, 0xad, 0x7d, 0xa0, 0x8c, 0x89, 0x1a,
|
||||
0x3f, 0x38, 0xd3, 0x5d, 0x2e, 0xbf, 0x46, 0x65, 0xa6, 0x68, 0xfa, 0xcf,
|
||||
0xd1, 0xc5, 0x7a, 0x5f, 0x1b, 0x3c, 0x41, 0xd5, 0x93, 0xd8, 0xb3, 0x39,
|
||||
0x86, 0xab, 0xf6, 0x46, 0xc5, 0xbd, 0xe8, 0x47, 0xe4, 0xd9, 0xec, 0x5e,
|
||||
0xe0, 0x98, 0x9c, 0x7f, 0x86, 0x9c, 0x8b, 0xd1, 0x17, 0x6f, 0x4e, 0x12,
|
||||
0xfb, 0x5a, 0x72, 0xcb, 0xa1, 0xe2, 0x73, 0xa2, 0x95, 0x74, 0xc9, 0xaa,
|
||||
0x58, 0xe9, 0xfc, 0xb0, 0x72, 0x25, 0x17, 0x53, 0xc2, 0x24, 0xba, 0xba,
|
||||
0x1f, 0xb8, 0xbc, 0xa4, 0x22, 0x07, 0x4d, 0xea, 0x50, 0x85, 0x26, 0x55,
|
||||
0xcf, 0x8c, 0x1a, 0x2c, 0x27, 0x4f, 0x9b, 0xe1, 0xe5, 0x92, 0xae, 0x09,
|
||||
0xc2, 0x47, 0x3c, 0x22, 0x93, 0x32, 0x1b, 0x2a, 0xab, 0x55, 0x4e, 0x46,
|
||||
0x4a, 0x13, 0x4a, 0x0a, 0x2d, 0x32, 0xaa, 0xe7, 0x04, 0xff, 0x3d, 0x82,
|
||||
0x15, 0xf9, 0x18, 0xfd, 0x6d, 0x0c, 0x1d, 0x03, 0xc1, 0x6b, 0x2c, 0x23,
|
||||
0x49, 0xac, 0x22, 0x94, 0xb9, 0x82, 0x59, 0xf9, 0xbe, 0xab, 0xc9, 0x8a,
|
||||
0x63, 0xb0, 0xbc, 0x5d, 0x21, 0x04, 0x77, 0xa9, 0x42, 0xad, 0x29, 0x68,
|
||||
0x0e, 0x32, 0x58, 0x52, 0xd4, 0x3b, 0x52, 0xff, 0x0f, 0x39, 0x8c, 0x68,
|
||||
0x89, 0x41, 0x2c, 0x4a, 0x29, 0x43, 0x2d, 0xc6, 0xa9, 0xed, 0xb2, 0x89,
|
||||
0x91, 0xcf, 0xfa, 0x20, 0x49, 0x7b, 0x4d, 0xe5, 0xa1, 0xcb, 0x7a, 0xad,
|
||||
0xf3, 0x62, 0xf0, 0x90, 0x0a, 0x83, 0xba, 0x2a, 0x49, 0xf0, 0x17, 0x0d,
|
||||
0xc5, 0xce, 0x00, 0x52, 0x15, 0xce, 0x7f, 0x24, 0x24, 0xb9, 0xb2, 0x98,
|
||||
0x42, 0xc2, 0x02, 0xe6, 0x2f, 0x45, 0x07, 0x3b, 0xe3, 0x0b, 0xad, 0x78,
|
||||
0x59, 0x5b, 0x76, 0x9e, 0xc4, 0xc5, 0xda, 0x57, 0x5e, 0xe4, 0x16, 0x4b,
|
||||
0xb5, 0x7a, 0x6e, 0x29, 0xd7, 0x8d, 0x86, 0x0c, 0x67, 0x26, 0xec, 0x5d,
|
||||
0x10, 0xb7, 0x32, 0x59, 0xf8, 0x53, 0xd7, 0x8a, 0xf4, 0x62, 0x50, 0xfb,
|
||||
0x01, 0xb5, 0xbe, 0x78, 0xd9, 0x4b, 0xc1, 0x1e, 0x97, 0x6e, 0xf8, 0xa2,
|
||||
0xa3, 0xe7, 0xd1, 0xfa, 0x0c, 0x29, 0x7b, 0xc4, 0x1c, 0x24, 0x06, 0xf4,
|
||||
0x14, 0xf4, 0x0e, 0xcd, 0xfc, 0xfd, 0x49, 0xba, 0xfd, 0x57, 0x51, 0xbf,
|
||||
0xf6, 0xf9, 0x18, 0xaf, 0x73, 0xd8, 0x65, 0xd6, 0x59, 0xbb, 0xd0, 0xba,
|
||||
0x99, 0x13, 0x5a, 0xc8, 0x0a, 0x49, 0x2d, 0x66, 0xb7, 0x9d, 0x17, 0x98,
|
||||
0xdd, 0x16, 0x66, 0x36, 0x9e, 0x85, 0x29, 0xf6, 0x07, 0x09, 0x43, 0x7c,
|
||||
0x76, 0xd6, 0x88, 0xed, 0x01, 0xf2, 0x6c, 0x5c, 0x6d, 0x75, 0xd4, 0x76,
|
||||
0x02, 0xf1, 0x6a, 0x89, 0xc2, 0xfe, 0xaf, 0x05, 0x0b, 0x06, 0x98, 0x19,
|
||||
0xb3, 0x79, 0xe4, 0xcc, 0xc6, 0xe4, 0x78, 0x83, 0xa5, 0x8b, 0x98, 0x01,
|
||||
0xa9, 0xaa, 0xce, 0xf9, 0x62, 0x91, 0x0c, 0xf5, 0x56, 0x93, 0xd7, 0xb5,
|
||||
0xbe, 0xdd, 0xa6, 0x53, 0xcc, 0x79, 0x59, 0xcf, 0xaf, 0x23, 0x5d, 0xbf,
|
||||
0x51, 0x3c, 0x1a, 0x8a, 0x9c, 0x7f, 0xd5, 0xf0, 0x64, 0x36, 0x55, 0xde,
|
||||
0x02, 0xe9, 0x68, 0x7f, 0x30, 0x73, 0x53, 0x32, 0x86, 0xed, 0x01, 0xf6,
|
||||
0x49, 0x58, 0xe1, 0x4e, 0x13, 0x03, 0x5a, 0x2b, 0xbd, 0x4f, 0x86, 0x07,
|
||||
0x1d, 0x2d, 0xc0, 0x00, 0xd5, 0x2c, 0xdd, 0xe3, 0xa6, 0x16, 0xe8, 0x54,
|
||||
0x01, 0x07, 0xb8, 0x6a, 0x13, 0x79, 0xaa, 0xa8, 0x7d, 0xee, 0xea, 0xc0,
|
||||
0x8e, 0x16, 0xc2, 0xa4, 0xda, 0x69, 0x85, 0xbf, 0x6f, 0xb1, 0xdd, 0x95,
|
||||
0xfe, 0xbe, 0x99, 0x9c, 0x52, 0x00, 0x55, 0xf5, 0x1d, 0x50, 0x96, 0x12,
|
||||
0x2f, 0xbd, 0xe9, 0x5e, 0x51, 0xc3, 0x70, 0xb1, 0x38, 0xdb, 0x59, 0xd0,
|
||||
0x55, 0x75, 0xcf, 0xdc, 0x33, 0xb9, 0x58, 0xe0, 0xbb, 0x5d, 0x55, 0xef,
|
||||
0x95, 0xb1, 0x6e, 0xcc, 0xc3, 0x6d, 0x55, 0xdd, 0xe2, 0xe8, 0x81, 0xda,
|
||||
0xaf, 0xcc, 0xbb, 0xc5, 0x47, 0x70, 0xb1, 0xc0, 0x85, 0x9f, 0xed, 0x70,
|
||||
0xd9, 0x72, 0x58, 0x55, 0xc5, 0x4e, 0x8b, 0x46, 0xde, 0x0e, 0x4b, 0xb1,
|
||||
0xb1, 0x9d, 0xd4, 0xb6, 0x12, 0xeb, 0x9a, 0xd4, 0xba, 0xad, 0x2c, 0xcd,
|
||||
0xb6, 0xf8, 0xbc, 0xb5, 0xad, 0xb4, 0x7a, 0x69, 0xe3, 0x66, 0x43, 0xb3,
|
||||
0x7c, 0x79, 0xa3, 0x0a, 0x24, 0xff, 0x54, 0x2c, 0x16, 0xce, 0x01, 0xee,
|
||||
0x17, 0xe7, 0x54, 0x7e, 0x18, 0xfa, 0x57, 0xac, 0xb0, 0x77, 0x7f, 0x1c,
|
||||
0x43, 0x71, 0x5f, 0x27, 0xd9, 0x1d, 0x3c, 0x45, 0xbf, 0x09, 0x69, 0x41,
|
||||
0xef, 0xa1, 0x75, 0x24, 0x38, 0x06, 0xe2, 0xd3, 0x7f, 0xa5, 0x38, 0x1c,
|
||||
0x00, 0x5e, 0xf2, 0x77, 0x24, 0xe6, 0x00, 0xfc, 0x95, 0x14, 0xf8, 0xf4,
|
||||
0xdf, 0xdc, 0x1e, 0x00, 0xe5, 0x18, 0x80, 0x3b, 0xc0, 0x30, 0x88, 0x29,
|
||||
0x90, 0xbf, 0x52, 0xc8, 0x37, 0x69, 0x70, 0xa7, 0xdb, 0x21, 0x69, 0xe7,
|
||||
0x40, 0x37, 0x64, 0x2f, 0x64, 0x44, 0x67, 0x6e, 0xa4, 0x13, 0x3a, 0x8b,
|
||||
0xc6, 0x4a, 0x8d, 0x25, 0xd0, 0x42, 0x98, 0x7a, 0x78, 0x74, 0x67, 0xb1,
|
||||
0x14, 0x43, 0x13, 0x4f, 0xdc, 0xa4, 0x3b, 0xc7, 0x29, 0xb2, 0x87, 0x7f,
|
||||
0xcd, 0xee, 0xa5, 0x29, 0x72, 0x1b, 0xf7, 0x43, 0xe7, 0xfd, 0xc9, 0xe6,
|
||||
0x77, 0xc5, 0x81, 0xfc, 0x91, 0xdf, 0xc4, 0xb8, 0xa2, 0x2f, 0xf9, 0x48,
|
||||
0x52, 0x0d, 0x1b, 0xea, 0xaf, 0x73, 0x1b, 0x19, 0xc6, 0x28, 0x08, 0x45,
|
||||
0xb5, 0xce, 0xfe, 0x3f, 0x41, 0x99, 0x72, 0xa3, 0x9d, 0x17, 0x72, 0x19,
|
||||
0xbd, 0x6a, 0xf6, 0xf8, 0x25, 0x68, 0xd3, 0x50, 0x2a, 0xf7, 0x01, 0x78,
|
||||
0x90, 0xb4, 0xee, 0x77, 0xcb, 0x26, 0x38, 0x89, 0x7d, 0x68, 0x93, 0xd8,
|
||||
0x7f, 0x06, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x08, 0x9c, 0x44, 0x70,
|
||||
0x17, 0x0f, 0x00, 0x00,
|
||||
},
|
||||
"assets/index.html",
|
||||
)
|
||||
}
|
||||
|
||||
// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
if f, ok := _bindata[name]; ok {
|
||||
return f()
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() ([]byte, error){
|
||||
"assets/glauth.css": assets_glauth_css,
|
||||
"assets/glauth.js": assets_glauth_js,
|
||||
"assets/index.html": assets_index_html,
|
||||
}
|
||||
@@ -1,263 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/nmcclain/ldap"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type configHandler struct {
|
||||
cfg *config
|
||||
}
|
||||
|
||||
func newConfigHandler(cfg *config) Backend {
|
||||
handler := configHandler{
|
||||
cfg: cfg,
|
||||
}
|
||||
return handler
|
||||
}
|
||||
|
||||
//
|
||||
func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower("," + h.cfg.Backend.BaseDN)
|
||||
log.Debug("Bind request as %s from %s", bindDN, conn.RemoteAddr().String())
|
||||
stats_frontend.Add("bind_reqs", 1)
|
||||
|
||||
// parse the bindDN
|
||||
if !strings.HasSuffix(bindDN, baseDN) {
|
||||
log.Warning(fmt.Sprintf("Bind Error: BindDN %s not our BaseDN %s", bindDN, h.cfg.Backend.BaseDN))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
parts := strings.Split(strings.TrimSuffix(bindDN, baseDN), ",")
|
||||
groupName := ""
|
||||
userName := ""
|
||||
if len(parts) == 1 {
|
||||
userName = strings.TrimPrefix(parts[0], "cn=")
|
||||
} else if len(parts) == 2 {
|
||||
userName = strings.TrimPrefix(parts[0], "cn=")
|
||||
groupName = strings.TrimPrefix(parts[1], "ou=")
|
||||
} else {
|
||||
log.Warning(fmt.Sprintf("Bind Error: BindDN %s should have only one or two parts (has %d)", bindDN, len(parts)))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
// find the user
|
||||
user := configUser{}
|
||||
found := false
|
||||
for _, u := range h.cfg.Users {
|
||||
if u.Name == userName {
|
||||
found = true
|
||||
user = u
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
log.Warning(fmt.Sprintf("Bind Error: User %s not found.", user))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
// find the group
|
||||
group := configGroup{}
|
||||
found = false
|
||||
for _, g := range h.cfg.Groups {
|
||||
if g.Name == groupName {
|
||||
found = true
|
||||
group = g
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
log.Warning(fmt.Sprintf("Bind Error: Group %s not found.", group))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
// validate group membership
|
||||
if user.PrimaryGroup != group.UnixID {
|
||||
log.Warning(fmt.Sprintf("Bind Error: User %s primary group is not %s.", userName, groupName))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
// finally, validate user's pw
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(bindSimplePw))
|
||||
if user.PassSHA256 != hex.EncodeToString(hash.Sum(nil)) {
|
||||
log.Warning(fmt.Sprintf("Bind Error: invalid credentials as %s from %s", bindDN, conn.RemoteAddr().String()))
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
stats_frontend.Add("bind_successes", 1)
|
||||
log.Debug("Bind success as %s from %s", bindDN, conn.RemoteAddr().String())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
|
||||
//
|
||||
func (h configHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower("," + h.cfg.Backend.BaseDN)
|
||||
searchBaseDN := strings.ToLower(searchReq.BaseDN)
|
||||
log.Debug("Search request as %s from %s for %s", bindDN, conn.RemoteAddr().String(), searchReq.Filter)
|
||||
stats_frontend.Add("search_reqs", 1)
|
||||
|
||||
// validate the user is authenticated and has appropriate access
|
||||
if len(bindDN) < 1 {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: Anonymous BindDN not allowed %s", bindDN)
|
||||
}
|
||||
if !strings.HasSuffix(bindDN, baseDN) {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: BindDN %s not in our BaseDN %s", bindDN, h.cfg.Backend.BaseDN)
|
||||
}
|
||||
if !strings.HasSuffix(searchBaseDN, h.cfg.Backend.BaseDN) {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultInsufficientAccessRights}, fmt.Errorf("Search Error: search BaseDN %s is not in our BaseDN %s", searchBaseDN, h.cfg.Backend.BaseDN)
|
||||
}
|
||||
// return all users in the config file - the LDAP library will filter results for us
|
||||
entries := []*ldap.Entry{}
|
||||
filterEntity, err := ldap.GetFilterObjectClass(searchReq.Filter)
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", searchReq.Filter)
|
||||
}
|
||||
switch filterEntity {
|
||||
default:
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, searchReq.Filter)
|
||||
case "posixgroup":
|
||||
for _, g := range h.cfg.Groups {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"cn", []string{g.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"description", []string{fmt.Sprintf("%s via LDAP", g.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"gidNumber", []string{fmt.Sprintf("%d", g.UnixID)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"objectClass", []string{"posixGroup"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"uniqueMember", h.getGroupMembers(g.UnixID)})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"memberUid", h.getGroupMemberIDs(g.UnixID)})
|
||||
dn := fmt.Sprintf("cn=%s,ou=groups,%s", g.Name, h.cfg.Backend.BaseDN)
|
||||
entries = append(entries, &ldap.Entry{dn, attrs})
|
||||
}
|
||||
case "posixaccount", "":
|
||||
for _, u := range h.cfg.Users {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"cn", []string{u.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"uid", []string{u.Name}})
|
||||
|
||||
if len(u.GivenName) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"givenName", []string{u.GivenName}})
|
||||
}
|
||||
|
||||
if len(u.SN) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"sn", []string{u.SN}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"ou", []string{h.getGroupName(u.PrimaryGroup)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"uidNumber", []string{fmt.Sprintf("%d", u.UnixID)}})
|
||||
|
||||
if u.Disabled {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"accountStatus", []string{"inactive"}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"accountStatus", []string{"active"}})
|
||||
}
|
||||
|
||||
if len(u.Mail) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"mail", []string{u.Mail}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"objectClass", []string{"posixAccount"}})
|
||||
|
||||
if len(u.LoginShell) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"loginShell", []string{u.LoginShell}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"loginShell", []string{"/bin/bash"}})
|
||||
}
|
||||
|
||||
if len(u.Homedir) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"homeDirectory", []string{u.Homedir}})
|
||||
} else {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"homeDirectory", []string{"/home/" + u.Name}})
|
||||
}
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"description", []string{fmt.Sprintf("%s via LDAP", u.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"gecos", []string{fmt.Sprintf("%s via LDAP", u.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"gidNumber", []string{fmt.Sprintf("%d", u.PrimaryGroup)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"memberOf", h.getGroupDNs(u.OtherGroups)})
|
||||
if len(u.SSHKeys) > 0 {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"sshPublicKey", u.SSHKeys})
|
||||
}
|
||||
dn := fmt.Sprintf("cn=%s,ou=%s,%s", u.Name, h.getGroupName(u.PrimaryGroup), h.cfg.Backend.BaseDN)
|
||||
entries = append(entries, &ldap.Entry{dn, attrs})
|
||||
}
|
||||
}
|
||||
stats_frontend.Add("search_successes", 1)
|
||||
log.Debug("AP: Search OK: %s", searchReq.Filter)
|
||||
return ldap.ServerSearchResult{entries, []string{}, []ldap.Control{}, ldap.LDAPResultSuccess}, nil
|
||||
}
|
||||
|
||||
//
|
||||
func (h configHandler) Close(boundDn string, conn net.Conn) error {
|
||||
stats_frontend.Add("closes", 1)
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
func (h configHandler) getGroupMembers(gid int) []string {
|
||||
members := make(map[string]bool)
|
||||
for _, u := range h.cfg.Users {
|
||||
if u.PrimaryGroup == gid {
|
||||
dn := fmt.Sprintf("cn=%s,ou=%s,%s", u.Name, h.getGroupName(u.PrimaryGroup), h.cfg.Backend.BaseDN)
|
||||
members[dn] = true
|
||||
} else {
|
||||
for _, othergid := range u.OtherGroups {
|
||||
if othergid == gid {
|
||||
dn := fmt.Sprintf("cn=%s,ou=%s,%s", u.Name, h.getGroupName(u.PrimaryGroup), h.cfg.Backend.BaseDN)
|
||||
members[dn] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m := []string{}
|
||||
for k, _ := range members {
|
||||
m = append(m, k)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
//
|
||||
func (h configHandler) getGroupMemberIDs(gid int) []string {
|
||||
members := make(map[string]bool)
|
||||
for _, u := range h.cfg.Users {
|
||||
if u.PrimaryGroup == gid {
|
||||
members[u.Name] = true
|
||||
} else {
|
||||
for _, othergid := range u.OtherGroups {
|
||||
if othergid == gid {
|
||||
members[u.Name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m := []string{}
|
||||
for k, _ := range members {
|
||||
m = append(m, k)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
//
|
||||
func (h configHandler) getGroupDNs(gids []int) []string {
|
||||
groups := make(map[string]bool)
|
||||
for _, gid := range gids {
|
||||
for _, g := range h.cfg.Groups {
|
||||
if g.UnixID == gid {
|
||||
dn := fmt.Sprintf("cn=%s,ou=groups,%s", g.Name, h.cfg.Backend.BaseDN)
|
||||
groups[dn] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
g := []string{}
|
||||
for k, _ := range groups {
|
||||
g = append(g, k)
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
//
|
||||
func (h configHandler) getGroupName(gid int) string {
|
||||
for _, g := range h.cfg.Groups {
|
||||
if g.UnixID == gid {
|
||||
return g.Name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/docopt/docopt-go"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/op/go-logging"
|
||||
"gopkg.in/amz.v1/aws"
|
||||
"gopkg.in/amz.v1/s3"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var version = "1.0.1"
|
||||
|
||||
const programName = "glauth"
|
||||
|
||||
var usage = `glauth: securely expose your LDAP for external auth
|
||||
|
||||
Usage:
|
||||
glauth [options] -c <file|s3url>
|
||||
glauth -h --help
|
||||
glauth --version
|
||||
|
||||
Options:
|
||||
-c, --config <file> Config file.
|
||||
-K <aws_key_id> AWS Key ID.
|
||||
-S <aws_secret_key> AWS Secret Key.
|
||||
-r <aws_region> AWS Region [default: us-east-1].
|
||||
-h, --help Show this screen.
|
||||
--version Show version.
|
||||
`
|
||||
|
||||
// exposed expvar variables
|
||||
var stats_frontend = expvar.NewMap("proxy_frontend")
|
||||
var stats_backend = expvar.NewMap("proxy_backend")
|
||||
var stats_general = expvar.NewMap("proxy")
|
||||
|
||||
// interface for backend handler
|
||||
type Backend interface {
|
||||
ldap.Binder
|
||||
ldap.Searcher
|
||||
ldap.Closer
|
||||
}
|
||||
|
||||
// config file
|
||||
type configBackend struct {
|
||||
BaseDN string
|
||||
Datastore string
|
||||
Insecure bool // For LDAP backend only
|
||||
Servers []string // For LDAP backend only
|
||||
}
|
||||
type configFrontend struct {
|
||||
AllowedBaseDNs []string // For LDAP backend only
|
||||
Cert string
|
||||
Key string
|
||||
Listen string
|
||||
TLS bool
|
||||
}
|
||||
type configAPI struct {
|
||||
Cert string
|
||||
Enabled bool
|
||||
Key string
|
||||
Listen string
|
||||
SecretToken string
|
||||
TLS bool
|
||||
}
|
||||
type configUser struct {
|
||||
Name string
|
||||
OtherGroups []int
|
||||
PassSHA256 string
|
||||
PrimaryGroup int
|
||||
SSHKeys []string
|
||||
Disabled bool
|
||||
UnixID int
|
||||
Mail string
|
||||
LoginShell string
|
||||
GivenName string
|
||||
SN string
|
||||
Homedir string
|
||||
}
|
||||
type configGroup struct {
|
||||
Name string
|
||||
UnixID int
|
||||
}
|
||||
type config struct {
|
||||
API configAPI
|
||||
Backend configBackend
|
||||
Debug bool
|
||||
Frontend configFrontend
|
||||
Groups []configGroup
|
||||
Syslog bool
|
||||
Users []configUser
|
||||
ConfigFile string
|
||||
AwsAccessKeyId string
|
||||
AwsSecretAccessKey string
|
||||
AwsRegion string
|
||||
}
|
||||
|
||||
var log = logging.MustGetLogger(programName)
|
||||
|
||||
func main() {
|
||||
stderr := initLogging()
|
||||
log.Debug("AP start")
|
||||
|
||||
cfg, err := doConfig()
|
||||
if err != nil {
|
||||
log.Fatalf("Configuration file error: %s", err.Error())
|
||||
}
|
||||
if cfg.Syslog {
|
||||
enableSyslog(stderr)
|
||||
}
|
||||
|
||||
// stats
|
||||
stats_general.Set("version", stringer(version))
|
||||
|
||||
// web API
|
||||
if cfg.API.Enabled {
|
||||
log.Debug("Web API enabled")
|
||||
go RunAPI(cfg)
|
||||
}
|
||||
|
||||
// configure the backend
|
||||
s := ldap.NewServer()
|
||||
s.EnforceLDAP = true
|
||||
var handler Backend
|
||||
switch cfg.Backend.Datastore {
|
||||
case "ldap":
|
||||
handler = newLdapHandler(cfg)
|
||||
case "config":
|
||||
handler = newConfigHandler(cfg)
|
||||
default:
|
||||
log.Fatalf("Unsupported backend %s - must be 'config' or 'ldap'.", cfg.Backend.Datastore)
|
||||
}
|
||||
log.Notice(fmt.Sprintf("Using %s backend", cfg.Backend.Datastore))
|
||||
s.BindFunc("", handler)
|
||||
s.SearchFunc("", handler)
|
||||
s.CloseFunc("", handler)
|
||||
|
||||
// start the frontend server
|
||||
if cfg.Frontend.TLS {
|
||||
log.Notice(fmt.Sprintf("Frontend LDAPS server listening on %s", cfg.Frontend.Listen))
|
||||
if err := s.ListenAndServeTLS(cfg.Frontend.Listen, cfg.Frontend.Cert, cfg.Frontend.Key); err != nil {
|
||||
log.Fatalf("LDAP Server Failed: %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
log.Notice(fmt.Sprintf("Frontend LDAP server listening on %s", cfg.Frontend.Listen))
|
||||
if err := s.ListenAndServe(cfg.Frontend.Listen); err != nil {
|
||||
log.Fatalf("LDAP Server Failed: %s", err.Error())
|
||||
}
|
||||
}
|
||||
log.Critical("AP exit")
|
||||
}
|
||||
|
||||
// doConfig reads the cli flags and config file
|
||||
func doConfig() (*config, error) {
|
||||
cfg := config{}
|
||||
// setup defaults
|
||||
cfg.Frontend.TLS = true
|
||||
|
||||
// parse the command-line args
|
||||
args, err := docopt.Parse(usage, nil, true, version, false)
|
||||
if err != nil {
|
||||
return &cfg, err
|
||||
}
|
||||
|
||||
// parse the config file
|
||||
if strings.HasPrefix(args["--config"].(string), "s3://") {
|
||||
if _, present := aws.Regions[args["-r"].(string)]; present == false {
|
||||
return &cfg, fmt.Errorf("Invalid AWS region: %s", args["-r"])
|
||||
}
|
||||
region := aws.Regions[args["-r"].(string)]
|
||||
auth, err := aws.EnvAuth()
|
||||
if err != nil {
|
||||
if args["-K"] == nil || args["-S"] == nil {
|
||||
return &cfg, fmt.Errorf("AWS credentials not found: must use -K and -S flags, or set these env vars:\n\texport AWS_ACCESS_KEY_ID=\"AAA...\"\n\texport AWS_SECRET_ACCESS_KEY=\"BBBB...\"\n")
|
||||
}
|
||||
auth = aws.Auth{
|
||||
AccessKey: args["-K"].(string),
|
||||
SecretKey: args["-S"].(string),
|
||||
}
|
||||
}
|
||||
// parse S3 url
|
||||
s3url := strings.TrimPrefix(args["--config"].(string), "s3://")
|
||||
parts := strings.SplitN(s3url, "/", 2)
|
||||
if len(parts) != 2 {
|
||||
return &cfg, fmt.Errorf("Invalid S3 URL: %s", s3url)
|
||||
}
|
||||
b := s3.New(auth, region).Bucket(parts[0])
|
||||
tomlData, err := b.Get(parts[1])
|
||||
if err != nil {
|
||||
return &cfg, err
|
||||
}
|
||||
if _, err := toml.Decode(string(tomlData), &cfg); err != nil {
|
||||
return &cfg, err
|
||||
}
|
||||
} else { // local config file
|
||||
if _, err := toml.DecodeFile(args["--config"].(string), &cfg); err != nil {
|
||||
return &cfg, err
|
||||
}
|
||||
}
|
||||
// enable features
|
||||
if cfg.Debug {
|
||||
logging.SetLevel(logging.DEBUG, programName)
|
||||
log.Debug("Debugging enabled")
|
||||
}
|
||||
switch cfg.Backend.Datastore {
|
||||
case "":
|
||||
cfg.Backend.Datastore = "config"
|
||||
case "config":
|
||||
case "ldap":
|
||||
default:
|
||||
return &cfg, fmt.Errorf("Invalid backend %s - must be 'config' or 'ldap'.", cfg.Backend.Datastore)
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// initLogging sets up logging to stderr
|
||||
func initLogging() *logging.LogBackend {
|
||||
format := "%{color}%{time:15:04:05.000000} %{shortfunc} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}"
|
||||
logBackend := logging.NewLogBackend(os.Stderr, "", 0)
|
||||
logging.SetBackend(logBackend)
|
||||
logging.SetLevel(logging.NOTICE, programName)
|
||||
logging.SetFormatter(logging.MustStringFormatter(format))
|
||||
return logBackend
|
||||
}
|
||||
|
||||
// enableSyslog turns on syslog and turns off color
|
||||
func enableSyslog(stderrBackend *logging.LogBackend) {
|
||||
format := "%{time:15:04:05.000000} %{shortfunc} ▶ %{level:.4s} %{id:03x} %{message}"
|
||||
logging.SetFormatter(logging.MustStringFormatter(format))
|
||||
syslogBackend, err := logging.NewSyslogBackend("")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
logging.SetBackend(stderrBackend, syslogBackend)
|
||||
log.Debug("Syslog enabled")
|
||||
}
|
||||
-294
@@ -1,294 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/kr/pretty"
|
||||
"github.com/nmcclain/ldap"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ldapHandler struct {
|
||||
sessions map[string]ldapSession
|
||||
servers []ldapBackend
|
||||
lock sync.Mutex // for sessions and servers
|
||||
doPing chan bool
|
||||
cfg *config
|
||||
}
|
||||
|
||||
type ldapSession struct {
|
||||
id string
|
||||
c net.Conn
|
||||
ldap *ldap.Conn
|
||||
}
|
||||
type ldapBackendStatus int
|
||||
|
||||
const (
|
||||
Down ldapBackendStatus = iota
|
||||
Up
|
||||
)
|
||||
|
||||
type ldapBackend struct {
|
||||
Scheme string
|
||||
Hostname string
|
||||
Port int
|
||||
Status ldapBackendStatus
|
||||
Ping time.Duration
|
||||
}
|
||||
|
||||
func newLdapHandler(cfg *config) Backend {
|
||||
handler := ldapHandler{ // set non-zero-value defaults here
|
||||
sessions: make(map[string]ldapSession),
|
||||
doPing: make(chan bool),
|
||||
cfg: cfg,
|
||||
}
|
||||
// parse LDAP URLs
|
||||
for _, ldapurl := range cfg.Backend.Servers {
|
||||
l, err := parseURL(ldapurl)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
handler.servers = append(handler.servers, l)
|
||||
}
|
||||
|
||||
// test server connectivity before listening, then keep it updated
|
||||
handler.monitorServers()
|
||||
|
||||
return handler
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
|
||||
log.Debug("Bind request as %s from %s", bindDN, conn.RemoteAddr().String())
|
||||
stats_frontend.Add("bind_reqs", 1)
|
||||
s, err := h.getSession(conn)
|
||||
if err != nil {
|
||||
stats_frontend.Add("bind_ldapSession_errors", 1)
|
||||
log.Debug("Bind ops error as %s from %s == %s", bindDN, conn.RemoteAddr().String(), err.Error())
|
||||
return ldap.LDAPResultOperationsError, err
|
||||
}
|
||||
if err := s.ldap.Bind(bindDN, bindSimplePw); err != nil {
|
||||
stats_frontend.Add("bind_errors", 1)
|
||||
log.Debug("Bind invalid creds as %s from %s", bindDN, conn.RemoteAddr().String())
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
stats_frontend.Add("bind_successes", 1)
|
||||
log.Debug("Bind success as %s from %s", bindDN, conn.RemoteAddr().String())
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
|
||||
log.Debug("Search request as %s from %s for %s", boundDN, conn.RemoteAddr().String(), searchReq.Filter)
|
||||
stats_frontend.Add("search_reqs", 1)
|
||||
s, err := h.getSession(conn)
|
||||
if err != nil {
|
||||
stats_frontend.Add("search_ldapSession_errors", 1)
|
||||
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, nil
|
||||
}
|
||||
search := ldap.NewSearchRequest(
|
||||
searchReq.BaseDN,
|
||||
searchReq.Scope,
|
||||
searchReq.DerefAliases,
|
||||
searchReq.SizeLimit,
|
||||
searchReq.TimeLimit,
|
||||
searchReq.TypesOnly,
|
||||
searchReq.Filter,
|
||||
searchReq.Attributes,
|
||||
searchReq.Controls,
|
||||
)
|
||||
|
||||
log.Debug("Search req to backend: %# v", pretty.Formatter(search))
|
||||
sr, err := s.ldap.Search(search)
|
||||
log.Debug("Backend Search result: %# v", pretty.Formatter(sr))
|
||||
ssr := ldap.ServerSearchResult{
|
||||
Entries: sr.Entries,
|
||||
Referrals: sr.Referrals,
|
||||
Controls: sr.Controls,
|
||||
}
|
||||
log.Debug("Frontend Search result: %# v", pretty.Formatter(ssr))
|
||||
if err != nil {
|
||||
e := err.(*ldap.Error)
|
||||
log.Debug("Search Err: %# v", pretty.Formatter(err))
|
||||
stats_frontend.Add("search_errors", 1)
|
||||
ssr.ResultCode = ldap.LDAPResultCode(e.ResultCode)
|
||||
return ssr, err
|
||||
}
|
||||
stats_frontend.Add("search_successes", 1)
|
||||
log.Debug("AP: Search OK: %s -> num of entries = %d\n", search.Filter, len(ssr.Entries))
|
||||
return ssr, nil
|
||||
}
|
||||
func (h ldapHandler) Close(boundDn string, conn net.Conn) error {
|
||||
conn.Close() // close connection to the server when then client is closed
|
||||
h.lock.Lock()
|
||||
defer h.lock.Unlock()
|
||||
delete(h.sessions, connID(conn))
|
||||
stats_frontend.Add("closes", 1)
|
||||
stats_backend.Add("closes", 1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// monitorServers tests server connectivity before listening, then keeps it updated
|
||||
func (h *ldapHandler) monitorServers() {
|
||||
err := h.ping()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-h.doPing:
|
||||
log.Notice("doPing requested due to server failure")
|
||||
err = h.ping()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case <-time.NewTimer(60 * time.Second).C:
|
||||
log.Debug("doPing after timeout")
|
||||
err = h.ping()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) getSession(conn net.Conn) (ldapSession, error) {
|
||||
id := connID(conn)
|
||||
h.lock.Lock()
|
||||
s, ok := h.sessions[id] // use server connection if it exists
|
||||
h.lock.Unlock()
|
||||
if !ok { // open a new server connection if not
|
||||
var l *ldap.Conn
|
||||
server, err := h.getBestServer() // pick the best server
|
||||
if err != nil {
|
||||
return ldapSession{}, err
|
||||
}
|
||||
dest := fmt.Sprintf("%s:%d", server.Hostname, server.Port)
|
||||
if server.Scheme == "ldaps" {
|
||||
tlsCfg := &tls.Config{}
|
||||
if h.cfg.Backend.Insecure {
|
||||
tlsCfg.InsecureSkipVerify = true
|
||||
}
|
||||
l, err = ldap.DialTLS("tcp", dest, tlsCfg)
|
||||
} else if server.Scheme == "ldap" {
|
||||
l, err = ldap.Dial("tcp", dest)
|
||||
}
|
||||
if err != nil {
|
||||
select {
|
||||
case h.doPing <- true: // non-blocking send
|
||||
default:
|
||||
}
|
||||
return ldapSession{}, err
|
||||
}
|
||||
s = ldapSession{id: id, c: conn, ldap: l}
|
||||
h.lock.Lock()
|
||||
h.sessions[s.id] = s
|
||||
h.lock.Unlock()
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) ping() error {
|
||||
healthy := false
|
||||
for k, s := range h.servers {
|
||||
var l *ldap.Conn
|
||||
var err error
|
||||
dest := fmt.Sprintf("%s:%d", s.Hostname, s.Port)
|
||||
start := time.Now()
|
||||
if h.servers[0].Scheme == "ldaps" {
|
||||
tlsCfg := &tls.Config{}
|
||||
if h.cfg.Backend.Insecure {
|
||||
tlsCfg.InsecureSkipVerify = true
|
||||
}
|
||||
l, err = ldap.DialTLS("tcp", dest, tlsCfg)
|
||||
} else if h.servers[0].Scheme == "ldap" {
|
||||
l, err = ldap.Dial("tcp", dest)
|
||||
}
|
||||
elapsed := time.Since(start)
|
||||
h.lock.Lock()
|
||||
if err != nil || l == nil {
|
||||
log.Error(fmt.Sprintf("Server %s:%d ping failed: %s", s.Hostname, s.Port, err.Error()))
|
||||
h.servers[k].Ping = 0
|
||||
h.servers[k].Status = Down
|
||||
} else {
|
||||
healthy = true
|
||||
h.servers[k].Ping = elapsed
|
||||
h.servers[k].Status = Up
|
||||
l.Close() // prank caller
|
||||
}
|
||||
h.lock.Unlock()
|
||||
}
|
||||
log.Debug("Server health: %# v", pretty.Formatter(h.servers))
|
||||
b, err := json.Marshal(h.servers)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("Error encoding tail data: %s", err.Error()))
|
||||
}
|
||||
stats_backend.Set("servers", stringer(string(b)))
|
||||
if healthy == false {
|
||||
return fmt.Errorf("No healthy servers")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) getBestServer() (ldapBackend, error) {
|
||||
favorite := ldapBackend{}
|
||||
forever, err := time.ParseDuration("30m")
|
||||
if err != nil {
|
||||
return ldapBackend{}, err
|
||||
}
|
||||
bestping := forever
|
||||
for _, s := range h.servers {
|
||||
if s.Status == Up && s.Ping < bestping {
|
||||
favorite = s
|
||||
bestping = s.Ping
|
||||
}
|
||||
}
|
||||
if bestping == forever {
|
||||
return ldapBackend{}, fmt.Errorf("No healthy servers found")
|
||||
}
|
||||
log.Debug("Best server: %# v", pretty.Formatter(favorite))
|
||||
return favorite, nil
|
||||
}
|
||||
|
||||
// helper functions
|
||||
func connID(conn net.Conn) string {
|
||||
h := sha256.New()
|
||||
h.Write([]byte(conn.LocalAddr().String() + conn.RemoteAddr().String()))
|
||||
sha := fmt.Sprintf("% x", h.Sum(nil))
|
||||
return string(sha)
|
||||
}
|
||||
func parseURL(ldapurl string) (ldapBackend, error) {
|
||||
u, err := url.Parse(ldapurl)
|
||||
if err != nil {
|
||||
return ldapBackend{}, err
|
||||
}
|
||||
var port int
|
||||
if u.Scheme == "ldaps" {
|
||||
port = 636
|
||||
} else if u.Scheme == "ldap" {
|
||||
port = 389
|
||||
} else {
|
||||
return ldapBackend{}, fmt.Errorf("Unknown LDAP scheme: %s", u.Scheme)
|
||||
}
|
||||
parts := strings.Split(u.Host, ":")
|
||||
hostname := parts[0]
|
||||
if len(parts) > 1 {
|
||||
port, err = strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return ldapBackend{}, err
|
||||
}
|
||||
}
|
||||
return ldapBackend{Scheme: u.Scheme, Hostname: hostname, Port: port}, nil
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"packages": {
|
||||
"v2": {
|
||||
"release-type": "go",
|
||||
"package-name": "GLAuth",
|
||||
"pull-request-title-pattern": "ci: release ${version}",
|
||||
"extra-files": [
|
||||
"v2/internal/version/const.go"
|
||||
]
|
||||
}
|
||||
},
|
||||
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#################
|
||||
# glauth.conf
|
||||
|
||||
#################
|
||||
# General configuration.
|
||||
debug = true
|
||||
#syslog = true
|
||||
|
||||
#################
|
||||
# The frontend section controls how clients connect to the proxy.
|
||||
[frontend]
|
||||
tls = false # enable TLS for production!!
|
||||
listen = "localhost:3893"
|
||||
cert = "cert.pem"
|
||||
key = "key.pem"
|
||||
|
||||
#################
|
||||
# The backend section controls the data store.
|
||||
[backend]
|
||||
datastore = "config"
|
||||
baseDN = "dc=glauth,dc=com"
|
||||
|
||||
#################
|
||||
# The users section contains a hardcoded list of valid users.
|
||||
# to create a passSHA256: echo -n "mysecret" | openssl dgst -sha256
|
||||
[[users]]
|
||||
name = "hackers"
|
||||
unixid = 5001
|
||||
primarygroup = 5501
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
|
||||
# This user record shows all of the possible fields available
|
||||
[[users]]
|
||||
name = "johndoe"
|
||||
givenname="John"
|
||||
sn="Doe"
|
||||
mail = "jdoe@example.com"
|
||||
unixid = 5002
|
||||
primarygroup = 5501
|
||||
loginShell = "/bin/sh"
|
||||
homeDir = "/root"
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
sshkeys = ["ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwVw3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4hC/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLVIfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XBYnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+txSuhw== rsa-key-20160209"]
|
||||
|
||||
|
||||
[[users]]
|
||||
name = "serviceuser"
|
||||
unixid = 5003
|
||||
primarygroup = 5502
|
||||
passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret
|
||||
|
||||
#################
|
||||
# The groups section contains a hardcoded list of valid users.
|
||||
[[groups]]
|
||||
name = "superheros"
|
||||
unixid = 5501
|
||||
|
||||
[[groups]]
|
||||
name = "svcaccts"
|
||||
unixid = 5502
|
||||
|
||||
#################
|
||||
# Enable and configure the optional REST API here.
|
||||
[api]
|
||||
enabled = true
|
||||
tls = false # enable TLS for production!!
|
||||
listen = "localhost:5555"
|
||||
cert = "cert.pem"
|
||||
key = "key.pem"
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#################
|
||||
# glauth.conf
|
||||
|
||||
#################
|
||||
# General configuration.
|
||||
debug = true
|
||||
#syslog = true
|
||||
|
||||
#################
|
||||
# The frontend section controls how clients connect to the proxy.
|
||||
[frontend]
|
||||
tls = false # enable TLS for production!!
|
||||
listen = "localhost:3893"
|
||||
cert = "cert.pem"
|
||||
key = "key.pem"
|
||||
|
||||
#################
|
||||
# The backend section controls the data store.
|
||||
[backend]
|
||||
datastore = "config"
|
||||
baseDN = "dc=glauth,dc=com"
|
||||
|
||||
#################
|
||||
# The users section contains a hardcoded list of valid users.
|
||||
# to create a passSHA256: echo -n "mysecret" | openssl dgst -sha256
|
||||
[[users]]
|
||||
name = "hackers"
|
||||
unixid = 5001
|
||||
primarygroup = 5501
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
|
||||
# This user record shows all of the possible fields available
|
||||
[[users]]
|
||||
name = "johndoe"
|
||||
givenname="John"
|
||||
sn="Doe"
|
||||
mail = "jdoe@example.com"
|
||||
unixid = 5002
|
||||
primarygroup = 5501
|
||||
loginShell = "/bin/sh"
|
||||
homeDir = "/root"
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
sshkeys = ["ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwVw3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4hC/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLVIfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XBYnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+txSuhw== rsa-key-20160209"]
|
||||
|
||||
|
||||
[[users]]
|
||||
name = "serviceuser"
|
||||
unixid = 5003
|
||||
primarygroup = 5502
|
||||
passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret
|
||||
|
||||
#################
|
||||
# The groups section contains a hardcoded list of valid users.
|
||||
[[groups]]
|
||||
name = "superheros"
|
||||
unixid = 5501
|
||||
|
||||
[[groups]]
|
||||
name = "svcaccts"
|
||||
unixid = 5502
|
||||
|
||||
#################
|
||||
# Enable and configure the optional REST API here.
|
||||
[api]
|
||||
enabled = true
|
||||
tls = false # enable TLS for production!!
|
||||
listen = "localhost:5555"
|
||||
cert = "cert.pem"
|
||||
key = "key.pem"
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copy config file if it doesn't exist so that the app can start
|
||||
if [ ! -f /app/config/config.cfg ] ; then
|
||||
cp /app/docker/default-config.cfg /app/config/config.cfg;
|
||||
fi
|
||||
|
||||
# Run app
|
||||
/app/glauth -c /app/config/config.cfg
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
img="localhost/glauth-dev"
|
||||
|
||||
sudo docker rmi -f "$img"
|
||||
|
||||
sudo docker build -f Dockerfile -t "$img" .
|
||||
|
||||
sudo docker run -P "$img"
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
sudo apt-get -qq update && sudo apt-get -qq install -y ldap-utils &&
|
||||
|
||||
$TRAVIS_BUILD_DIR/glauth -c "$TRAVIS_BUILD_DIR/$1" &
|
||||
glauthPid="$!"
|
||||
|
||||
echo "Running at $glauthPid"
|
||||
sleep 2;
|
||||
kill $glauthPid;
|
||||
echo "done."
|
||||
@@ -1,70 +0,0 @@
|
||||
#################
|
||||
# glauth.conf
|
||||
|
||||
#################
|
||||
# General configuration.
|
||||
debug = true
|
||||
#syslog = true
|
||||
|
||||
#################
|
||||
# The frontend section controls how clients connect to the proxy.
|
||||
[frontend]
|
||||
tls = false # enable TLS for production!!
|
||||
listen = "localhost:3893"
|
||||
cert = "cert.pem"
|
||||
key = "key.pem"
|
||||
|
||||
#################
|
||||
# The backend section controls the data store.
|
||||
[backend]
|
||||
datastore = "config"
|
||||
baseDN = "dc=glauth,dc=com"
|
||||
|
||||
#################
|
||||
# The users section contains a hardcoded list of valid users.
|
||||
# to create a passSHA256: echo -n "mysecret" | openssl dgst -sha256
|
||||
[[users]]
|
||||
name = "hackers"
|
||||
unixid = 5001
|
||||
primarygroup = 5501
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
|
||||
# This user record shows all of the possible fields available
|
||||
[[users]]
|
||||
name = "johndoe"
|
||||
givenname="John"
|
||||
sn="Doe"
|
||||
mail = "jdoe@example.com"
|
||||
unixid = 5002
|
||||
primarygroup = 5501
|
||||
loginShell = "/bin/sh"
|
||||
homeDir = "/root"
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
sshkeys = ["ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwVw3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4hC/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLVIfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XBYnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+txSuhw== rsa-key-20160209"]
|
||||
|
||||
|
||||
[[users]]
|
||||
name = "serviceuser"
|
||||
unixid = 5003
|
||||
primarygroup = 5502
|
||||
passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret
|
||||
|
||||
#################
|
||||
# The groups section contains a hardcoded list of valid users.
|
||||
[[groups]]
|
||||
name = "superheros"
|
||||
unixid = 5501
|
||||
|
||||
[[groups]]
|
||||
name = "svcaccts"
|
||||
unixid = 5502
|
||||
|
||||
#################
|
||||
# Enable and configure the optional REST API here.
|
||||
[api]
|
||||
enabled = true
|
||||
tls = false # enable TLS for production!!
|
||||
listen = "localhost:5555"
|
||||
cert = "cert.pem"
|
||||
key = "key.pem"
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
# Changelog
|
||||
|
||||
## [2.5.0](https://github.com/glauth/glauth/compare/GLAuth-v2.5.0...GLAuth-v2.5.0) (2026-04-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow tracing configuration via main config ([f692394](https://github.com/glauth/glauth/commit/f692394942aa0f93a1aa1572331fd1c3e3553156))
|
||||
* alt container build registry ([f8dee8d](https://github.com/glauth/glauth/commit/f8dee8da879232f5c6ae2a2a19565562c7d0d9fd))
|
||||
* embedded plugins ([c0ed908](https://github.com/glauth/glauth/commit/c0ed90822fd4d2ee7104a1979d423a0c93d758ac))
|
||||
* introduce context for otlp spans into handler pkg ([d05630f](https://github.com/glauth/glauth/commit/d05630f66b80a776fd406782ad1fde5c6c66eac6))
|
||||
* introduce context for otlp spans into plugins pkg ([46e49b6](https://github.com/glauth/glauth/commit/46e49b6976318a9f3670b88bdcb3411dfac0a17c))
|
||||
* introduce legacy behavior, based on past versions ([#318](https://github.com/glauth/glauth/issues/318)) ([34a6b30](https://github.com/glauth/glauth/commit/34a6b30b8fe69c90cab09eb85890ffdfe8fc80fd))
|
||||
* introduce otelsql ([2ca5312](https://github.com/glauth/glauth/commit/2ca53126965aa7d42b23aee15f750df12822d454))
|
||||
* introduce otlp tracer ([0cf0403](https://github.com/glauth/glauth/commit/0cf04037a2a7b38c8ed7af2451b115f48c5427b5))
|
||||
* proxying ldap paging compat ([#422](https://github.com/glauth/glauth/issues/422)) ([8476506](https://github.com/glauth/glauth/commit/8476506b8c51e993eb90c73d612f69fec5350b89))
|
||||
* starttls and ldaps now matching features ([#458](https://github.com/glauth/glauth/issues/458)) ([d68c78a](https://github.com/glauth/glauth/commit/d68c78a18b150679038e5ce549b6b227c31518d7))
|
||||
* wire up basic tracer ([1c2b23c](https://github.com/glauth/glauth/commit/1c2b23c00ff85b83a6d2e4bf4a9a68081aaf2777))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 246 and [#252](https://github.com/glauth/glauth/issues/252) ([ceefc66](https://github.com/glauth/glauth/commit/ceefc66dbba9ae054958269825de31d22d30e262))
|
||||
* config watcher now updates whenf ile added to dir ([#424](https://github.com/glauth/glauth/issues/424)) ([a90f37b](https://github.com/glauth/glauth/commit/a90f37b23b76af22c700392d68bf227b7aee1894))
|
||||
* Credentials leaked on INFO log level ([#451](https://github.com/glauth/glauth/issues/451)) ([645dbb2](https://github.com/glauth/glauth/commit/645dbb226683ae57f3d5382e21ea42444e940752))
|
||||
* drop vendored toml ([24455e3](https://github.com/glauth/glauth/commit/24455e39889716ce7ae1e7e8a7dacfa7d4c96080))
|
||||
* formatting ([c90cbfe](https://github.com/glauth/glauth/commit/c90cbfe5fb090fc19a55d64e01cd0e31c38bf2f0))
|
||||
* go test not checking otp within allowed basedn ([#403](https://github.com/glauth/glauth/issues/403)) ([ed52a91](https://github.com/glauth/glauth/commit/ed52a91ec4117ff58fe606a1d8ba10786501a1e5))
|
||||
* move all toml parsing into a new internal package, drop the mappings in favour of toml.Primitive decoding ([3ba8e11](https://github.com/glauth/glauth/commit/3ba8e1113217be647d240261322453d213ea7da4))
|
||||
* patch group name fetches for the rest of handlers ([#450](https://github.com/glauth/glauth/issues/450)) ([b498736](https://github.com/glauth/glauth/commit/b498736cfdd0ee6f1585d682a5c54c9d927b8dbb))
|
||||
* remove spinlock in monitoring code ([#405](https://github.com/glauth/glauth/issues/405)) ([a2c151b](https://github.com/glauth/glauth/commit/a2c151b0d025332462369a846a51ef4deff5332b))
|
||||
* removed config setup from main, reshoring log configuration ([5fe8aca](https://github.com/glauth/glauth/commit/5fe8aca852bdfe7e375ea99b87074bae35fc3407))
|
||||
* update ldap library to fix [#389](https://github.com/glauth/glauth/issues/389) ([#430](https://github.com/glauth/glauth/issues/430)) ([a5ecc26](https://github.com/glauth/glauth/commit/a5ecc26e064cea9e4dab3dd234ebd5d5eb06be0e))
|
||||
* update tracing code to work with breaking otlp 1.20 changes ([1a37396](https://github.com/glauth/glauth/commit/1a3739610997b58100040d0c8a405596fccc8e23))
|
||||
* upgrade to use BurntSushi/toml ([f9addbc](https://github.com/glauth/glauth/commit/f9addbc2c5b13ccc2779dbabc4c55bc8706f53d6))
|
||||
|
||||
|
||||
### Miscellaneous Chores
|
||||
|
||||
* force release 2.5.0 ([ff7a9e6](https://github.com/glauth/glauth/commit/ff7a9e6215857e0dd3450504b7b063409ccfc374))
|
||||
* release 2.3.1 ([0bf3d4a](https://github.com/glauth/glauth/commit/0bf3d4a82a8451e7bbda74e3730345aab5a855a7))
|
||||
|
||||
## [2.4.0](https://github.com/glauth/glauth/compare/v2.3.2...v2.4.0) (2024-08-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* proxying ldap paging compat ([#422](https://github.com/glauth/glauth/issues/422)) ([8476506](https://github.com/glauth/glauth/commit/8476506b8c51e993eb90c73d612f69fec5350b89))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* config watcher now updates whenf ile added to dir ([#424](https://github.com/glauth/glauth/issues/424)) ([a90f37b](https://github.com/glauth/glauth/commit/a90f37b23b76af22c700392d68bf227b7aee1894))
|
||||
* update ldap library to fix [#389](https://github.com/glauth/glauth/issues/389) ([#430](https://github.com/glauth/glauth/issues/430)) ([a5ecc26](https://github.com/glauth/glauth/commit/a5ecc26e064cea9e4dab3dd234ebd5d5eb06be0e))
|
||||
|
||||
## [2.3.2](https://github.com/glauth/glauth/compare/v2.3.1...v2.3.2) (2024-02-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove spinlock in monitoring code ([#405](https://github.com/glauth/glauth/issues/405)) ([a2c151b](https://github.com/glauth/glauth/commit/a2c151b0d025332462369a846a51ef4deff5332b))
|
||||
|
||||
## [2.3.1](https://github.com/glauth/glauth/compare/v2.2.1...v2.3.1) (2024-02-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow tracing configuration via main config ([f692394](https://github.com/glauth/glauth/commit/f692394942aa0f93a1aa1572331fd1c3e3553156))
|
||||
* introduce context for otlp spans into handler pkg ([d05630f](https://github.com/glauth/glauth/commit/d05630f66b80a776fd406782ad1fde5c6c66eac6))
|
||||
* introduce context for otlp spans into plugins pkg ([46e49b6](https://github.com/glauth/glauth/commit/46e49b6976318a9f3670b88bdcb3411dfac0a17c))
|
||||
* introduce otelsql ([2ca5312](https://github.com/glauth/glauth/commit/2ca53126965aa7d42b23aee15f750df12822d454))
|
||||
* introduce otlp tracer ([0cf0403](https://github.com/glauth/glauth/commit/0cf04037a2a7b38c8ed7af2451b115f48c5427b5))
|
||||
* wire up basic tracer ([1c2b23c](https://github.com/glauth/glauth/commit/1c2b23c00ff85b83a6d2e4bf4a9a68081aaf2777))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* drop vendored toml ([24455e3](https://github.com/glauth/glauth/commit/24455e39889716ce7ae1e7e8a7dacfa7d4c96080))
|
||||
* formatting ([c90cbfe](https://github.com/glauth/glauth/commit/c90cbfe5fb090fc19a55d64e01cd0e31c38bf2f0))
|
||||
* go test not checking otp within allowed basedn ([#403](https://github.com/glauth/glauth/issues/403)) ([ed52a91](https://github.com/glauth/glauth/commit/ed52a91ec4117ff58fe606a1d8ba10786501a1e5))
|
||||
* move all toml parsing into a new internal package, drop the mappings in favour of toml.Primitive decoding ([3ba8e11](https://github.com/glauth/glauth/commit/3ba8e1113217be647d240261322453d213ea7da4))
|
||||
* removed config setup from main, reshoring log configuration ([5fe8aca](https://github.com/glauth/glauth/commit/5fe8aca852bdfe7e375ea99b87074bae35fc3407))
|
||||
* update tracing code to work with breaking otlp 1.20 changes ([1a37396](https://github.com/glauth/glauth/commit/1a3739610997b58100040d0c8a405596fccc8e23))
|
||||
* upgrade to use BurntSushi/toml ([f9addbc](https://github.com/glauth/glauth/commit/f9addbc2c5b13ccc2779dbabc4c55bc8706f53d6))
|
||||
|
||||
|
||||
### Miscellaneous Chores
|
||||
|
||||
* release 2.3.1 ([0bf3d4a](https://github.com/glauth/glauth/commit/0bf3d4a82a8451e7bbda74e3730345aab5a855a7))
|
||||
|
||||
## [2.3.0](https://github.com/glauth/glauth/compare/v2.2.0...v2.3.0) (2023-10-02)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **plugins:** Rename the groups table to ldapgroups ([#326](https://github.com/glauth/glauth/issues/326))
|
||||
|
||||
### Features
|
||||
|
||||
* Update migration code to support table names ([#339](https://github.com/glauth/glauth/issues/339)) ([349431c](https://github.com/glauth/glauth/commit/349431c6caa0388d17ab987621eb9be5f019155e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **plugins:** Rename the groups table to ldapgroups ([#326](https://github.com/glauth/glauth/issues/326)) ([675b236](https://github.com/glauth/glauth/commit/675b236328a21a65daa7876a1a3c6900b85b1964))
|
||||
|
||||
|
||||
### Miscellaneous Chores
|
||||
|
||||
* release 2.3.0 ([0c11325](https://github.com/glauth/glauth/commit/0c11325a2482d5067c805a4c7ed948a5e337b8f8))
|
||||
@@ -0,0 +1,5 @@
|
||||
# Contributor Code of Conduct
|
||||
|
||||
This project adheres to No Code of Conduct. We are all adults. We accept anyone's contributions. Nothing else matters.
|
||||
|
||||
For more information please visit the [No Code of Conduct](https://github.com/domgetter/NCoC) homepage.
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
MAKEFLAGS += --no-print-directory
|
||||
|
||||
VERSION=$(shell bin/linuxamd64/glauth --version)
|
||||
|
||||
GIT_COMMIT=$(shell git rev-list -1 HEAD )
|
||||
BUILD_TIME=$(shell date -u +%Y%m%d_%H%M%SZ)
|
||||
GIT_CLEAN=$(shell git status | grep -E "working (tree|directory) clean" | wc -l | sed 's/^[ ]*//')
|
||||
|
||||
# Last git tag
|
||||
LAST_GIT_TAG=$(shell git describe --abbrev=0 --tags 2> /dev/null)
|
||||
|
||||
# this=1 if the current commit is the tagged commit (ie, if this is a release build)
|
||||
GIT_IS_TAG_COMMIT=$(shell git describe --abbrev=0 --tags > /dev/null 2> /dev/null && echo "1" || echo "0")
|
||||
|
||||
# Used when a tag isn't available
|
||||
GIT_BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
# Build variables
|
||||
BUILD_VARS?=-s -w
|
||||
BUILD_FILES=.
|
||||
TRIM_FLAGS>?=-trimpath
|
||||
BUILD_TAGS?=noembed
|
||||
|
||||
# Targets
|
||||
MAIN_TARGETS?=linux/amd64,linux/386,linux/arm64,linux/arm-7,linux/riscv64,darwin/amd64,darwin/arm64,windows/amd64,windows/386
|
||||
PLUGIN_TARGETS?=linux/amd64,linux/386,linux/arm64,linux/arm-7,linux/riscv64,darwin/amd64,darwin/arm64
|
||||
EMBED_TARGETS?=windows/amd64
|
||||
|
||||
# For release process
|
||||
GO_RELEASE_V=$(shell go version | { read _ _ v _; echo $${v#go}; })
|
||||
|
||||
# Build
|
||||
GOOS?=linux
|
||||
GOARCH?=amd64
|
||||
|
||||
# Plugins
|
||||
-include pkg/plugins/*/Makefile
|
||||
|
||||
#####################
|
||||
# High level commands
|
||||
#####################
|
||||
|
||||
#help: @ List available tasks on this project
|
||||
help:
|
||||
@grep -E '[a-zA-Z\.\-]+:.*?@ .*$$' $(MAKEFILE_LIST)| tr -d '#' | sed -E 's/Makefile.//' | awk 'BEGIN {FS = ":.*?@ "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
#run: @ build and run - used for development
|
||||
run: setup devrun
|
||||
|
||||
mocks:
|
||||
go install go.uber.org/mock/mockgen@v0.3.0
|
||||
# generate gomocks
|
||||
go generate ./...
|
||||
.PHONY: mocks
|
||||
|
||||
vet:
|
||||
-go vet ./...
|
||||
.PHONY: vet
|
||||
#test: @ runs the integration test on linuxamd64 (eventually allow the binary to be set)
|
||||
test: mocks vet
|
||||
# also run unit tests for packages, skip glauth_test.go for now
|
||||
go test -v -cover -coverprofile coverage.out ./pkg/... ./internal/...
|
||||
$(MAKE) runtest
|
||||
#all: @ run build process for all binaries
|
||||
all: setup binaries verify
|
||||
|
||||
#fast: @ run build process for only linuxamd64
|
||||
fast: setup linuxamd64
|
||||
|
||||
#fastdebug: @ run build process for only linuxamd64 in debug mode
|
||||
fastdebug: setup linuxamd64debug
|
||||
|
||||
#binaries: @ list of binary formats to build
|
||||
binaries: linux386 linuxamd64 linuxarm linuxarm64 linuxriscv64 darwinamd64 darwinarm64 win386 winamd64
|
||||
|
||||
#setup: @ setup commands to always run
|
||||
setup: getdeps format
|
||||
|
||||
#####################
|
||||
# Subcommands
|
||||
#####################
|
||||
# @echo \- removing any changes and pulling latest master && \
|
||||
# git reset --hard HEAD >/dev/null 2>&1 && \
|
||||
# git checkout master >/dev/null 2>&1 && \
|
||||
# git pull >/dev/null 2>&1 && \
|
||||
|
||||
prepbuild:
|
||||
echo \- taking care of ignore files && \
|
||||
sudo rm -rf bin/* >/dev/null && \
|
||||
echo \- cleaning up plugins remnants && \
|
||||
make forget-plugins && \
|
||||
make remember-plugins
|
||||
|
||||
forget-embed:
|
||||
@if [ -f pkg/server/embed_sqlite.go ]; then \
|
||||
mv pkg/server/embed_sqlite.go /tmp/; \
|
||||
fi
|
||||
|
||||
remember-embed:
|
||||
@if [ ! -f pkg/server/embed_sqlite.go ]; then \
|
||||
mv /tmp/embed_sqlite.go pkg/server/; \
|
||||
fi
|
||||
|
||||
# Run integration test
|
||||
runtest:
|
||||
./scripts/ci/integration-test.sh cleanup
|
||||
|
||||
# Get all dependencies
|
||||
getdeps:
|
||||
go get -d ./...
|
||||
|
||||
updatetest:
|
||||
./scripts/ci/integration-test.sh
|
||||
|
||||
format:
|
||||
go fmt ./...
|
||||
|
||||
devrun:
|
||||
go run ${BUILD_FILES} -c sample-simple.cfg
|
||||
|
||||
mkbindir:
|
||||
@echo "create directory bin/$(GOOS)$(GOARCH)"
|
||||
@mkdir -p bin/$(GOOS)$(GOARCH)
|
||||
.PHONY: mkbindir
|
||||
|
||||
build: mkbindir
|
||||
@go build ${TRIM_FLAGS} -tags ${BUILD_TAGS} -ldflags "${BUILD_VARS}" -o bin/$(GOOS)$(GOARCH)/glauth -buildvcs .
|
||||
$(MAKE) sha256
|
||||
.PHONY: build
|
||||
|
||||
builddebug: mkbindir
|
||||
@go build ${TRIM_FLAGS} -tags ${BUILD_TAGS} -gcflags="all=-N -l" -o bin/$(GOOS)$(GOARCH)/glauth -buildvcs .
|
||||
$(MAKE) sha256
|
||||
.PHONY: builddebug
|
||||
|
||||
sha256:
|
||||
@sha256sum bin/$(GOOS)$(GOARCH)/glauth > bin/$(GOOS)$(GOARCH)/glauth.sha256
|
||||
.PHONY: sha256
|
||||
|
||||
linuxamd64debug:
|
||||
GOOS=linux GOARCH=amd64 $(MAKE) builddebug
|
||||
|
||||
linux386:
|
||||
GOOS=linux GOARCH=386 $(MAKE) build
|
||||
|
||||
linuxamd64:
|
||||
GOOS=linux GOARCH=amd64 $(MAKE) build
|
||||
|
||||
linuxarm:
|
||||
GOOS=linux GOARCH=arm $(MAKE) build
|
||||
|
||||
linuxarm64:
|
||||
GOOS=linux GOARCH=arm64 $(MAKE) build
|
||||
|
||||
linuxriscv64:
|
||||
GOOS=linux GOARCH=riscv64 $(MAKE) build
|
||||
|
||||
testing:
|
||||
mkdir -p pkg/embed && \
|
||||
cat pkg/plugins/glauth-sqlite/sqlite.go | sed -e 's/func main() {}//' -e 's/^package main/package embed/' > pkg/embed/sqlite.go && \
|
||||
go mod tidy && \
|
||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 BUILD_TAGS=embedsqlite $(MAKE) build && \
|
||||
rm -rf pkg/embed
|
||||
|
||||
darwinamd64:
|
||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 $(MAKE) build
|
||||
|
||||
darwinarm64:
|
||||
GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 $(MAKE) build
|
||||
|
||||
win386:
|
||||
GOOS=windows GOARCH=386 $(MAKE) build
|
||||
|
||||
winamd64:
|
||||
GOOS=windows GOARCH=amd64 $(MAKE) build
|
||||
|
||||
verify:
|
||||
@for binary in linux386 linuxamd64 linuxarm linuxarm64 linuxriscv64 darwinamd64 darwinarm64 win386 winamd64; do cd bin/$$binary && sha256sum glauth.sha256 -c && cd ../..; done
|
||||
|
||||
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)
|
||||
|
||||
#prepare-plugins-buid: @ pull plugins dependencies for local building
|
||||
prepare-plugins-build:
|
||||
@M=pkg/plugins/glauth-sqlite make pull-plugin-dependencies && \
|
||||
M=pkg/plugins/glauth-mysql make pull-plugin-dependencies && \
|
||||
M=pkg/plugins/glauth-postgres make pull-plugin-dependencies && \
|
||||
M=pkg/plugins/glauth-pam make pull-plugin-dependencies
|
||||
|
||||
forget-plugin:
|
||||
rm -rf $M ../.git/modules/v2/$M; \
|
||||
git config --remove-section submodule.v2/$M; \
|
||||
git rm --cache $M; \
|
||||
go mod tidy; \
|
||||
true
|
||||
|
||||
#forget-plugin: @ remove plugins, restoring original file structure
|
||||
forget-plugins:
|
||||
for pkg in pkg/plugins/*; do \
|
||||
if [ -d "$$pkg" ]; then \
|
||||
P=$$(echo $$pkg | cut -d'/' -f 3) M=$$pkg make forget-plugin >/dev/null 2>&1;\
|
||||
fi; \
|
||||
done; \
|
||||
rm -rf buildlogs
|
||||
|
||||
remember-plugins:
|
||||
cd ../ && \
|
||||
for module in $$(cat .gitmodules | awk '/path =/{P=$$3} /url =/{print $$3 "," P}'); do \
|
||||
git submodule add $${module%%,*} $${module#*,}; \
|
||||
done; \
|
||||
git submodule update --init --recursive
|
||||
|
||||
_buildmain:
|
||||
@xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out glauth -dest bin -buildvcs=false --targets="${MAIN_TARGETS}" .
|
||||
|
||||
#buildmain: @ build main binaries for distribution
|
||||
buildmain: prepbuild _buildmain
|
||||
|
||||
buildsingleembed:
|
||||
git checkout -b build_embeds && \
|
||||
mkdir -p pkg/embed && \
|
||||
cat pkg/plugins/$P/$M | sed -e 's/func main() {}//' -e 's/^package main/package embed/' > pkg/embed/$M && \
|
||||
go mod tidy && \
|
||||
git add pkg/embed/$M go.mod go.sum && \
|
||||
git commit -m "build cruft" && \
|
||||
git push -u origin build_embeds && \
|
||||
xgo -v -ldflags="${BUILD_VARS}" --tags=$T -trimpath -go ${GO_RELEASE_V} -out glauth -dest bin -buildvcs=false --targets="${EMBED_TARGETS}" . && \
|
||||
rm -rf pkg/embed && \
|
||||
git checkout master && \
|
||||
git push -d origin build_embeds && \
|
||||
git branch -D build_embeds
|
||||
|
||||
_buildmainembeds:
|
||||
P=glauth-sqlite M=sqlite.go T=embedsqlite make buildsingleembed
|
||||
|
||||
#buildmainembeds: @ build main binaries for distribution, including embedded plugins
|
||||
buildmainembeds: prepbuild _buildmainembeds
|
||||
|
||||
buildplugin:
|
||||
ifeq ($P,pam)
|
||||
xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out $P -dest bin -buildvcs=false -buildmode=plugin --targets="${PLUGIN_TARGETS}" --pkg $M/$P.go --bringupcmd 'apt update && apt install -y libpam0g-dev' .
|
||||
else
|
||||
xgo -v -ldflags="${BUILD_VARS}" -trimpath -go ${GO_RELEASE_V} -out $P -dest bin -buildvcs=false -buildmode=plugin --targets="${PLUGIN_TARGETS}" --pkg $M/$P.go .
|
||||
endif
|
||||
(cd bin && for lib in $$(ls $$P-* | grep -v \.so$$); do sudo mv $$lib $$lib.so; done);
|
||||
|
||||
_buildplugins: prepare-plugins-build
|
||||
for pkg in pkg/plugins/*; do \
|
||||
if [ -d "$$pkg" ]; then \
|
||||
M=pkg/plugins/$$(echo $$pkg | cut -d'/' -f 3) && P=$$(echo $$M | grep -oP 'glauth-\K\w+') && M=$$M P=$$P make buildplugin;\
|
||||
fi; \
|
||||
done; \
|
||||
|
||||
#buildplugins: @ build base plugins for distribution
|
||||
buildplugins: forget-embed _buildplugins remember-embed
|
||||
|
||||
_checkdockerauth:
|
||||
@if ! grep -q "index.docker.io" $(HOME)/.docker/config.json; then \
|
||||
echo "❌ Not logged in to Docker Hub (index.docker.io not found in config)."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
if ! grep -q "ghcr.io" $(HOME)/.docker/config.json; then \
|
||||
echo "❌ Not logged in to GitHub Hub (ghcr.io not found in config)."; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
builddockermain:
|
||||
$(if $(TAG),,$(error ❌ Must set TAG))
|
||||
$(if $(REPO),,$(error ❌ Must set REPO - glauth or other))
|
||||
@mkdir -p docker/assets/linux/amd64 docker/assets/linux/arm64 docker/assets/linux/arm/v7 && \
|
||||
cp -f bin/glauth-linux-amd64 docker/assets/linux/amd64/glauth && \
|
||||
cp -f bin/glauth-linux-arm64 docker/assets/linux/arm64/glauth && \
|
||||
cp -f bin/glauth-linux-arm-7 docker/assets/linux/arm/v7/glauth && \
|
||||
cp -f bin/glauth-linux-riscv64 docker/assets/linux/riscv64/glauth && \
|
||||
docker buildx build --tag ghcr.io/$$REPO/glauth:$$TAG -t ghcr.io/$$REPO/glauth:latest -f docker/Dockerfile-standalone --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker && \
|
||||
docker buildx build --tag $$REPO/glauth:$$TAG -t $$REPO/glauth:latest -f docker/Dockerfile-standalone --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker
|
||||
|
||||
builddockerplugins:
|
||||
$(if $(TAG),,$(error ❌ Must set TAG))
|
||||
$(if $(REPO),,$(error ❌ Must set REPO - glauth or other))
|
||||
@mkdir -p docker/assets/linux/amd64 docker/assets/linux/arm64 docker/assets/linux/arm/v7 && \
|
||||
cp -f bin/sqlite-linux-amd64.so docker/assets/linux/amd64/sqlite.so && \
|
||||
cp -f bin/sqlite-linux-arm64.so docker/assets/linux/arm64/sqlite.so && \
|
||||
cp -f bin/sqlite-linux-arm-7.so docker/assets/linux/arm/v7/sqlite.so && \
|
||||
cp -f bin/sqlite-linux-riscv64.so docker/assets/linux/riscv64/sqlite.so && \
|
||||
cp -f bin/mysql-linux-amd64.so docker/assets/linux/amd64/mysql.so && \
|
||||
cp -f bin/mysql-linux-arm64.so docker/assets/linux/arm64/mysql.so && \
|
||||
cp -f bin/mysql-linux-arm-7.so docker/assets/linux/arm/v7/mysql.so && \
|
||||
cp -f bin/mysql-linux-riscv64.so docker/assets/linux/riscv64/mysql.so && \
|
||||
cp -f bin/postgres-linux-amd64.so docker/assets/linux/amd64/postgres.so && \
|
||||
cp -f bin/postgres-linux-arm64.so docker/assets/linux/arm64/postgres.so && \
|
||||
cp -f bin/postgres-linux-arm-7.so docker/assets/linux/arm/v7/postgres.so && \
|
||||
cp -f bin/postgres-linux-riscv64.so docker/assets/linux/riscv64/postgres.so && \
|
||||
docker buildx build --tag ghcr.io/$$REPO/glauth-plugins:$$TAG -t ghcr.io/$$REPO/glauth-plugins:latest -f docker/Dockerfile-plugins --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker && \
|
||||
docker buildx build --tag $$REPO/glauth-plugins:$$TAG -t $$REPO/glauth-plugins:latest -f docker/Dockerfile-plugins --platform linux/amd64,linux/arm64,linux/arm/v7,linux/riscv64 --push docker
|
||||
|
||||
builddocker: _checkdockerauth builddockermain builddockerplugins
|
||||
|
||||
buildeverything: prepbuild forget-embed _buildmain _buildplugins remember-embed _buildmainembeds builddocker
|
||||
|
||||
#testdocker: @ run integration test using docker
|
||||
testdocker:
|
||||
$(if $(REPO),,$(error Must set REPO - glauth or other))
|
||||
@echo "==> Cleaning up any existing image to be on the safe side..." && \
|
||||
(for image in $$(docker image ls -q "$$REPO/glauth*"); do \
|
||||
for container in $$(docker container ls -a -q -f ancestor=$$image); do \
|
||||
docker stop $$container; \
|
||||
while [ "$$(docker container ls -q -f ancestor=$$image)" != "" ]; do sleep 1; done; \
|
||||
docker rm $$container; \
|
||||
done; \
|
||||
docker rmi $$image; \
|
||||
done) && \
|
||||
echo "==> Running glauth main container..." && \
|
||||
docker run -d --name glauth-test -p 3893:3893 $$REPO/glauth:latest && \
|
||||
sleep 5 && \
|
||||
if [ "$$(ldapsearch -LLL -H ldap://localhost:3893 -D cn=serviceuser,ou=svcaccts,dc=glauth,dc=com -w mysecret -x -bdc=glauth,dc=com cn=hackers | grep posixAccount)" != "" ]; then \
|
||||
echo "Checked: Glauth is responding properly to ldapsearch query."; \
|
||||
else \
|
||||
echo "glauth check did not pass. Aborting."; \
|
||||
exit 1; \
|
||||
fi && \
|
||||
echo "==> Stopping glauth main container..." && \
|
||||
docker stop glauth-test && \
|
||||
while [ "$$(docker ps -q -f name=glauth-test)" != "" ]; do sleep 1; done; \
|
||||
docker rm glauth-test && \
|
||||
echo "==> Running glauth plugins container..." && \
|
||||
docker run -d --name glauth-test -p 3893:3893 $$REPO/glauth-plugins:latest && \
|
||||
sleep 5 && \
|
||||
if [ "$$(ldapsearch -LLL -H ldap://localhost:3893 -D cn=serviceuser,ou=svcaccts,dc=glauth,dc=com -w mysecret -x -bdc=glauth,dc=com cn=hackers | grep posixAccount)" != "" ]; then \
|
||||
echo "Checked: Glauth is responding properly to ldapsearch query."; \
|
||||
else \
|
||||
echo "glauth check did not pass. Aborting."; \
|
||||
exit 1; \
|
||||
fi && \
|
||||
echo "==> Stopping glauth plugins container..." && \
|
||||
docker stop glauth-test && \
|
||||
while [ "$$(docker ps -q -f name=glauth-test)" != "" ]; do sleep 1; done; \
|
||||
docker rm glauth-test && \
|
||||
echo "==> Testing complete."
|
||||
|
||||
.PHONY: all \
|
||||
prepbuild run test fast binaries setup getdeps runtest updatetest format devrun \
|
||||
linux386 linuxamd64 linuxarm linuxarm64 linuxriscv64 darwinamd64 darwinarm64 win386 winamd64 verify \
|
||||
pull-plugin pull-base-plugins forget-plugin forget-plugins buildmain buildplugin build \
|
||||
buildplugins builddockermain builddockerplugins builddocker testdocker buildeverything
|
||||
@@ -0,0 +1,44 @@
|
||||
#################
|
||||
# Build Step
|
||||
#################
|
||||
|
||||
FROM alpine:latest as build
|
||||
|
||||
RUN apk add --no-cache git make busybox-static dumb-init
|
||||
|
||||
#################
|
||||
# Run Step
|
||||
#################
|
||||
|
||||
FROM gcr.io/distroless/base-debian13 as run
|
||||
|
||||
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>" \
|
||||
org.opencontainers.image.title="GLauth" \
|
||||
org.opencontainers.image.description="A simple LDAP server for development, home use, or CI pipelines" \
|
||||
org.opencontainers.image.authors="Ben Yanke, Jörn Friedrich Dreyer, Chris F Ravenscroft" \
|
||||
org.opencontainers.image.source="https://github.com/glauth/glauth" \
|
||||
org.opencontainers.image.licenses="MIT" \
|
||||
org.opencontainers.image.version="latest" \
|
||||
org.opencontainers.image.url="https://github.com/glauth/glauth"
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Copy docker specific scripts from build container
|
||||
COPY assets/start-plugins.sh /app/docker/start-plugins.sh
|
||||
COPY assets/default-config-plugins.cfg /app/docker/default-config-plugins.cfg
|
||||
COPY assets/gl.db /app/docker/gl.db
|
||||
COPY assets/$TARGETPLATFORM/glauth /app/glauth
|
||||
COPY assets/$TARGETPLATFORM/*.so /app/
|
||||
|
||||
# Just what we need
|
||||
COPY --from=build /usr/bin/dumb-init /usr/bin/dumb-init
|
||||
COPY --from=build /bin/busybox.static /bin/sh
|
||||
COPY --from=build /bin/busybox.static /bin/ln
|
||||
COPY --from=build /bin/busybox.static /bin/rm
|
||||
RUN ln /bin/sh /usr/bin/cp && ln /bin/sh /usr/bin/mkdir && rm /bin/ln /bin/rm
|
||||
|
||||
# Expose web and LDAP ports
|
||||
EXPOSE 389 636 5555
|
||||
|
||||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||
CMD ["/bin/sh", "/app/docker/start-plugins.sh"]
|
||||
@@ -0,0 +1,42 @@
|
||||
#################
|
||||
# Build Step
|
||||
#################
|
||||
|
||||
FROM alpine:latest as build
|
||||
|
||||
RUN apk add --no-cache git make busybox-static dumb-init
|
||||
|
||||
#################
|
||||
# Run Step
|
||||
#################
|
||||
|
||||
FROM gcr.io/distroless/base-debian13 as run
|
||||
|
||||
LABEL maintainers="Ben Yanke <ben@benyanke.com>, Jörn Friedrich Dreyer <jfd@butonic.de>, Chris F Ravenscroft <chris@voilaweb.com>" \
|
||||
org.opencontainers.image.title="GLauth" \
|
||||
org.opencontainers.image.description="A simple LDAP server for development, home use, or CI pipelines" \
|
||||
org.opencontainers.image.authors="Ben Yanke, Jörn Friedrich Dreyer, Chris F Ravenscroft" \
|
||||
org.opencontainers.image.source="https://github.com/glauth/glauth" \
|
||||
org.opencontainers.image.licenses="MIT" \
|
||||
org.opencontainers.image.version="latest" \
|
||||
org.opencontainers.image.url="https://github.com/glauth/glauth"
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Copy docker specific scripts from build container
|
||||
COPY assets/start-standalone.sh /app/docker/start-standalone.sh
|
||||
COPY assets/default-config-standalone.cfg /app/docker/default-config-standalone.cfg
|
||||
COPY assets/$TARGETPLATFORM/glauth /app/glauth
|
||||
|
||||
# Just what we need
|
||||
COPY --from=build /usr/bin/dumb-init /usr/bin/dumb-init
|
||||
COPY --from=build /bin/busybox.static /bin/sh
|
||||
COPY --from=build /bin/busybox.static /bin/ln
|
||||
COPY --from=build /bin/busybox.static /bin/rm
|
||||
RUN ln /bin/sh /usr/bin/cp && ln /bin/sh /usr/bin/mkdir && rm /bin/ln /bin/rm
|
||||
|
||||
# Expose web and LDAP ports
|
||||
EXPOSE 389 636 5555
|
||||
|
||||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||
CMD ["/bin/sh", "/app/docker/start-standalone.sh"]
|
||||
@@ -0,0 +1,38 @@
|
||||
#################
|
||||
# glauth.conf
|
||||
|
||||
#################
|
||||
# General configuration.
|
||||
debug = true
|
||||
#syslog = true
|
||||
|
||||
#################
|
||||
[ldap]
|
||||
enabled = true
|
||||
listen = "0.0.0.0:3893"
|
||||
|
||||
[ldaps]
|
||||
enabled = false
|
||||
listen = "0.0.0.0:3894"
|
||||
cert = "cert.pem"
|
||||
key = "key.pem"
|
||||
|
||||
#################
|
||||
# The backend section controls the data store.
|
||||
[backend]
|
||||
datastore = "plugin"
|
||||
# If "plugin," uncomment the line below
|
||||
plugin = "/app/sqlite.so"
|
||||
pluginhandler = "NewSQLiteHandler"
|
||||
baseDN = "dc=glauth,dc=com"
|
||||
database = "/app/config/gl.db"
|
||||
|
||||
#################
|
||||
# Enable and configure the optional REST API here.
|
||||
[api]
|
||||
enabled = true
|
||||
tls = false # enable TLS for production!!
|
||||
listen = "localhost:5555"
|
||||
cert = "cert.pem"
|
||||
key = "key.pem"
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
#################
|
||||
# glauth.conf
|
||||
|
||||
#################
|
||||
# General configuration.
|
||||
debug = true
|
||||
# syslog = true
|
||||
#
|
||||
# Enable hot-reload of configuration on changes
|
||||
# - does NOT work [ldap], [ldaps], [backend] or [api] sections
|
||||
# watchconfig = true
|
||||
|
||||
#################
|
||||
# yubikeyclientid = "yubi-api-clientid"
|
||||
# yubikeysecret = "yubi-api-secret"
|
||||
|
||||
#################
|
||||
# Server configuration.
|
||||
[ldap]
|
||||
enabled = true
|
||||
# run on a non privileged port
|
||||
listen = "0.0.0.0:3893"
|
||||
|
||||
[ldaps]
|
||||
# to enable ldaps genrerate a certificate, eg. with:
|
||||
# openssl req -x509 -newkey rsa:4096 -keyout glauth.key -out glauth.crt -days 365 -nodes -subj '/CN=`hostname`'
|
||||
enabled = false
|
||||
listen = "0.0.0.0:3894"
|
||||
cert = "glauth.crt"
|
||||
key = "glauth.key"
|
||||
|
||||
#################
|
||||
# The backend section controls the data store.
|
||||
[backend]
|
||||
datastore = "config"
|
||||
baseDN = "dc=glauth,dc=com"
|
||||
|
||||
## Configure dn format to use structures like
|
||||
## "uid=serviceuser,cn=svcaccts,$BASEDN" instead of "cn=serviceuser,ou=svcaccts,$BASEDN"
|
||||
## to help ease migrations from other LDAP systems
|
||||
# nameformat = "uid"
|
||||
# groupformat = "cn"
|
||||
|
||||
## Configure ssh-key attribute name, default is 'sshPublicKey'
|
||||
# sshkeyattr = "ipaSshPubKey"
|
||||
|
||||
[behaviors]
|
||||
# Ignore all capabilities restrictions, for instance allowing every user to perform a search
|
||||
IgnoreCapabilities = false
|
||||
# Enable a "fail2ban" type backoff mechanism temporarily banning repeated failed login attempts
|
||||
LimitFailedBinds = true
|
||||
# How many failed login attempts are allowed before a ban is imposed
|
||||
NumberOfFailedBinds = 3
|
||||
# How long (in seconds) is the window for failed login attempts
|
||||
PeriodOfFailedBinds = 10
|
||||
# How long (in seconds) is the ban duration
|
||||
BlockFailedBindsFor = 60
|
||||
# Clean learnt IP addresses every N seconds
|
||||
PruneSourceTableEvery = 600
|
||||
# Clean learnt IP addresses not seen in N seconds
|
||||
PruneSourcesOlderThan = 600
|
||||
|
||||
#################
|
||||
# The users section contains a hardcoded list of valid users.
|
||||
# to create a passSHA256: echo -n "mysecret" | openssl dgst -sha256
|
||||
[[users]]
|
||||
name = "hackers"
|
||||
uidnumber = 5001
|
||||
primarygroup = 5501
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
[[users.capabilities]]
|
||||
action = "search"
|
||||
object = "ou=superheros,dc=glauth,dc=com"
|
||||
|
||||
# This user record shows all of the possible fields available
|
||||
[[users]]
|
||||
name = "johndoe"
|
||||
givenname="John"
|
||||
sn="Doe"
|
||||
mail = "jdoe@example.com"
|
||||
uidnumber = 5002
|
||||
primarygroup = 5501
|
||||
loginShell = "/bin/sh"
|
||||
homeDir = "/root"
|
||||
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
|
||||
sshkeys = ["ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwVw3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4hC/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLVIfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XBYnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+txSuhw== rsa-key-20160209"]
|
||||
passappsha256 = [
|
||||
"c32255dbf6fd6b64883ec8801f793bccfa2a860f2b1ae1315cd95cdac1338efa", # TestAppPw1
|
||||
"c9853d5f2599e90497e9f8cc671bd2022b0fb5d1bd7cfff92f079e8f8f02b8d3", # TestAppPw2
|
||||
"4939efa7c87095dacb5e7e8b8cfb3a660fa1f5edcc9108f6d7ec20ea4d6b3a88", # TestAppPw3
|
||||
]
|
||||
|
||||
[[users]]
|
||||
name = "serviceuser"
|
||||
mail = "serviceuser@example.com"
|
||||
uidnumber = 5003
|
||||
primarygroup = 5502
|
||||
passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret
|
||||
[[users.capabilities]]
|
||||
action = "search"
|
||||
object = "*"
|
||||
|
||||
# Test user showing 2 factor auth authentication
|
||||
[[users]]
|
||||
name = "otpuser"
|
||||
uidnumber = 5004
|
||||
primarygroup = 5501
|
||||
passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret
|
||||
otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk"
|
||||
yubikey = "vvjrcfalhlaa"
|
||||
[[users.capabilities]]
|
||||
action = "search"
|
||||
object = "ou=superheros,dc=glauth,dc=com"
|
||||
|
||||
[[users]]
|
||||
name = "uberhackers"
|
||||
uidnumber = 5005
|
||||
primarygroup = 5501
|
||||
# bcrypt format: hex($2y$2^<number of rounds>$<salt>$<hash>)
|
||||
passappbcrypt = [
|
||||
"243261243130244B62463462656F7265504F762E794F324957746D656541326B4B46596275674A79336A476845764B616D65446169784E41384F4432" # dogood
|
||||
]
|
||||
# uncomment and comment out above array to test password with otp code
|
||||
# passappbcrypt = "243261243130244B62463462656F7265504F762E794F324957746D656541326B4B46596275674A79336A476845764B616D65446169784E41384F4432" # dogood
|
||||
otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk"
|
||||
|
||||
|
||||
#################
|
||||
# The groups section contains a hardcoded list of valid users.
|
||||
[[groups]]
|
||||
name = "superheros"
|
||||
gidnumber = 5501
|
||||
|
||||
[[groups]]
|
||||
name = "svcaccts"
|
||||
gidnumber = 5502
|
||||
|
||||
[[groups]]
|
||||
name = "vpn"
|
||||
gidnumber = 5503
|
||||
includegroups = [ 5501 ]
|
||||
|
||||
#################
|
||||
# Enable and configure the optional REST API here.
|
||||
[api]
|
||||
enabled = true
|
||||
tls = false # enable TLS for production!!
|
||||
listen = "0.0.0.0:5555"
|
||||
cert = "cert.pem"
|
||||
key = "key.pem"
|
||||
Binary file not shown.
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copy config file if it doesn't exist so that the app can start
|
||||
if [ ! -f /app/config/config.cfg ] ; then
|
||||
echo "Config file not found at /app/config/config.cfg"
|
||||
echo "Copying example configuration file to run."
|
||||
mkdir -p /app/config
|
||||
cp /app/docker/default-config-plugins.cfg /app/config/config.cfg || exit 1
|
||||
# This file will be ignored when switching away from the default (sqlite)
|
||||
cp /app/docker/gl.db /app/config/gl.db || exit 1
|
||||
fi
|
||||
|
||||
|
||||
echo "";
|
||||
echo "Version and build information:";
|
||||
echo "";
|
||||
|
||||
# Output version string to logs
|
||||
/app/glauth --version
|
||||
|
||||
|
||||
echo "";
|
||||
echo "Starting GLauth now.";
|
||||
echo "";
|
||||
|
||||
# Run app
|
||||
cd /app
|
||||
/app/glauth -c /app/config/config.cfg
|
||||
|
||||
echo ""
|
||||
echo "GLauth has exited."
|
||||
echo "Exiting."
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copy config file if it doesn't exist so that the app can start
|
||||
if [ ! -f /app/config/config.cfg ] ; then
|
||||
echo "Config file not found at /app/config/config.cfg"
|
||||
echo "Copying example configuration file to run."
|
||||
mkdir -p /app/config
|
||||
cp /app/docker/default-config-standalone.cfg /app/config/config.cfg || exit 1
|
||||
fi
|
||||
|
||||
|
||||
echo "";
|
||||
echo "Version and build information:";
|
||||
echo "";
|
||||
|
||||
# Output version string to logs
|
||||
/app/glauth --version
|
||||
|
||||
|
||||
echo "";
|
||||
echo "Starting GLauth now.";
|
||||
echo "";
|
||||
|
||||
# Run app
|
||||
/app/glauth -c /app/config/config.cfg
|
||||
|
||||
echo ""
|
||||
echo "GLauth has exited."
|
||||
echo "Exiting."
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/GeertJohan/yubigo"
|
||||
"github.com/arl/statsviz"
|
||||
docopt "github.com/docopt/docopt-go"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/glauth/glauth/v2/internal/monitoring"
|
||||
_tls "github.com/glauth/glauth/v2/internal/tls"
|
||||
"github.com/glauth/glauth/v2/internal/toml"
|
||||
"github.com/glauth/glauth/v2/internal/tracing"
|
||||
"github.com/glauth/glauth/v2/internal/version"
|
||||
"github.com/glauth/glauth/v2/pkg/config"
|
||||
"github.com/glauth/glauth/v2/pkg/frontend"
|
||||
"github.com/glauth/glauth/v2/pkg/logging"
|
||||
"github.com/glauth/glauth/v2/pkg/server"
|
||||
"github.com/glauth/glauth/v2/pkg/stats"
|
||||
"github.com/jinzhu/copier"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const programName = "glauth"
|
||||
|
||||
var usage = `glauth: securely expose your LDAP for external auth
|
||||
|
||||
Usage:
|
||||
glauth [options] -c <file|s3 url>
|
||||
glauth -h --help
|
||||
glauth --version
|
||||
|
||||
Options:
|
||||
-c, --config <file> Config file.
|
||||
-K <aws_key_id> AWS Key ID.
|
||||
-S <aws_secret_key> AWS Secret Key.
|
||||
-r <aws_region> AWS Region [default: us-east-1].
|
||||
--aws_endpoint_url <url> Custom S3 endpoint.
|
||||
--ldap <address> Listen address for the LDAP server.
|
||||
--ldaps <address> Listen address for the LDAPS server.
|
||||
--ldaps-cert <cert-file> Path to cert file for the LDAPS server.
|
||||
--ldaps-key <key-file> Path to key file for the LDAPS server.
|
||||
--check-config Check configuration file and exit.
|
||||
-h, --help Show this screen.
|
||||
--version Show version.
|
||||
`
|
||||
|
||||
var (
|
||||
log zerolog.Logger
|
||||
args map[string]interface{}
|
||||
yubiAuth *yubigo.YubiAuth
|
||||
|
||||
activeConfig = &config.Config{}
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
if err := parseArgs(); err != nil {
|
||||
fmt.Println("Could not parse command-line arguments")
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
checkConfig := false
|
||||
if cc, ok := args["--check-config"]; ok {
|
||||
if cc == true {
|
||||
checkConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
cfg, err := toml.NewConfig(checkConfig, getConfigLocation(), args)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Configuration file error")
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if checkConfig {
|
||||
fmt.Println("Config file seems ok (but I am not checking much at this time)")
|
||||
return
|
||||
}
|
||||
|
||||
if err := copier.Copy(activeConfig, cfg); err != nil {
|
||||
log.Info().Err(err).Msg("Could not save reloaded config. Holding on to old config")
|
||||
}
|
||||
|
||||
log = logging.InitLogging(activeConfig.Debug, activeConfig.Syslog, activeConfig.StructuredLog)
|
||||
|
||||
if !checkConfig {
|
||||
if cfg.Debug {
|
||||
log.Info().Msg("Debugging enabled")
|
||||
}
|
||||
if cfg.Syslog {
|
||||
log.Info().Msg("Syslog enabled")
|
||||
}
|
||||
}
|
||||
|
||||
log.Info().Msg("AP start")
|
||||
|
||||
startService()
|
||||
}
|
||||
|
||||
func startService() {
|
||||
// stats
|
||||
stats.General.Set("version", stats.Stringer(version.Version))
|
||||
|
||||
// web API
|
||||
if activeConfig.API.Enabled {
|
||||
log.Info().Msg("Web API enabled")
|
||||
|
||||
if activeConfig.API.Internals {
|
||||
statsviz.Register(
|
||||
http.DefaultServeMux,
|
||||
statsviz.Root("/internals"),
|
||||
statsviz.SendFrequency(1000*time.Millisecond),
|
||||
)
|
||||
}
|
||||
|
||||
go frontend.RunAPI(
|
||||
frontend.Logger(log),
|
||||
frontend.Config(&activeConfig.API),
|
||||
)
|
||||
}
|
||||
|
||||
monitor := monitoring.NewMonitor(&log)
|
||||
tracer := tracing.NewTracer(
|
||||
tracing.NewConfig(
|
||||
activeConfig.Tracing.Enabled,
|
||||
activeConfig.Tracing.GRPCEndpoint,
|
||||
activeConfig.Tracing.HTTPEndpoint,
|
||||
&log,
|
||||
),
|
||||
)
|
||||
|
||||
startConfigWatcher()
|
||||
|
||||
var err error
|
||||
var starttlsConfig *tls.Config
|
||||
if c := activeConfig.LDAP; c.Enabled && c.TLS {
|
||||
// TODO check if tls params are string or bytes and change config accordingly
|
||||
starttlsConfig, err = _tls.MakeTLS([]byte(c.TLSCert), []byte(c.TLSKey), c.LegacyTLS)
|
||||
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("unable to configure TLS for StartTLS: StartTLS won't be supported")
|
||||
}
|
||||
}
|
||||
|
||||
var ldapstlsConfig *tls.Config
|
||||
if c := activeConfig.LDAPS; c.Enabled {
|
||||
// TODO check if tls params are string or bytes and change config accordingly
|
||||
ldapstlsConfig, err = _tls.MakeTLS([]byte(c.Cert), []byte(c.Key), c.LegacyTLS)
|
||||
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("unable to configure TLS for LDAPS")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
s, err := server.NewServer(
|
||||
server.Logger(log),
|
||||
server.Config(activeConfig),
|
||||
server.StartTLSConfig(starttlsConfig),
|
||||
server.LDAPSTLSConfig(ldapstlsConfig),
|
||||
server.Monitor(monitor),
|
||||
server.Tracer(tracer),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not create server")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if activeConfig.LDAP.Enabled {
|
||||
go func() {
|
||||
if err := s.ListenAndServe(); err != nil {
|
||||
log.Error().Err(err).Msg("could not start LDAP server")
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if activeConfig.LDAPS.Enabled {
|
||||
go func() {
|
||||
if err := s.ListenAndServeTLS(); err != nil {
|
||||
log.Error().Err(err).Msg("could not start LDAPS server")
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
// Block until we receive our signal.
|
||||
<-c
|
||||
|
||||
// Doesn't block if no connections, but will otherwise wait
|
||||
// until the timeout deadline.
|
||||
s.Shutdown()
|
||||
|
||||
// Optionally, you could run srv.Shutdown in a goroutine and block on
|
||||
// <-ctx.Done() if your application should wait for other services
|
||||
// to finalize based on context cancellation.
|
||||
log.Info().Msg("AP exit")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func startConfigWatcher() {
|
||||
configFileLocation := getConfigLocation()
|
||||
if !activeConfig.WatchConfig || strings.HasPrefix(configFileLocation, "s3://") {
|
||||
return
|
||||
}
|
||||
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not start config-watcher")
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
go func() {
|
||||
isChanged, isRemoved := false, false
|
||||
for {
|
||||
select {
|
||||
case event := <-watcher.Events:
|
||||
log.Info().Str("e", event.Op.String()).Msg("watcher got event")
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
isChanged = true
|
||||
} else if event.Op&fsnotify.Remove == fsnotify.Remove { // vim edit file with rename/remove
|
||||
isChanged, isRemoved = true, true
|
||||
} else if event.Op&fsnotify.Create == fsnotify.Create { // only when watching a directory
|
||||
isChanged = true
|
||||
}
|
||||
case err := <-watcher.Errors:
|
||||
log.Error().Err(err).Msg("watcher error")
|
||||
case <-ticker.C:
|
||||
// wakeup, try finding removed config
|
||||
}
|
||||
if _, err := os.Stat(configFileLocation); !os.IsNotExist(err) && (isRemoved || isChanged) {
|
||||
if isRemoved {
|
||||
log.Info().Str("file", configFileLocation).Msg("rewatching config")
|
||||
watcher.Add(configFileLocation) // overwrite
|
||||
isChanged, isRemoved = true, false
|
||||
}
|
||||
if isChanged {
|
||||
|
||||
cfg, err := toml.NewConfig(false, configFileLocation, args)
|
||||
|
||||
if err != nil {
|
||||
log.Info().Err(err).Msg("Could not reload config. Holding on to old config")
|
||||
} else {
|
||||
log.Info().Msg("Config was reloaded")
|
||||
|
||||
if err := copier.Copy(activeConfig, cfg); err != nil {
|
||||
log.Info().Err(err).Msg("Could not save reloaded config. Holding on to old config")
|
||||
}
|
||||
}
|
||||
isChanged = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
watcher.Add(configFileLocation)
|
||||
}
|
||||
|
||||
func parseArgs() error {
|
||||
var err error
|
||||
|
||||
if args, err = docopt.Parse(usage, nil, true, version.GetVersion(), false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getConfigLocation() string {
|
||||
return args["--config"].(string)
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type testEnv struct {
|
||||
checkanonymousrootDSE bool
|
||||
checkTOTP bool
|
||||
checkbindUPN bool
|
||||
svcdn string
|
||||
svcdnnogroup string
|
||||
otpdn string
|
||||
expectedinfo string
|
||||
expectedaccount string
|
||||
scopedaccount string
|
||||
expectedfirstaccount string
|
||||
expectedgroup string
|
||||
checkemployeetype string
|
||||
}
|
||||
|
||||
func TestProperBuild(t *testing.T) {
|
||||
info, err := os.Stat("bin/glauth")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
mode := uint32(info.Mode())
|
||||
if mode&0b001001001 == 0 {
|
||||
t.Fatalf("bad file mode: %b", mode)
|
||||
}
|
||||
}
|
||||
|
||||
func batteryOfTests(t *testing.T, env *testEnv) {
|
||||
tests := []struct {
|
||||
Name string
|
||||
Path string
|
||||
Check func(t testing.TB)
|
||||
}{
|
||||
{
|
||||
Name: "searching for the 'hackers' user",
|
||||
Check: func(t testing.TB) {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
||||
if got, want := out, env.expectedaccount; got != want {
|
||||
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "searching for the 'hackers' user without binding with a group",
|
||||
Check: func(t testing.TB) {
|
||||
if env.svcdnnogroup == "" {
|
||||
t.SkipNow()
|
||||
}
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdnnogroup, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
||||
if got, want := out, env.expectedaccount; got != want {
|
||||
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "searching for the 'hackers' user after binding using the account's UPN",
|
||||
Check: func(t testing.TB) {
|
||||
if !env.checkbindUPN {
|
||||
t.SkipNow()
|
||||
}
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", "serviceuser@example.com", "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "cn=hackers")
|
||||
if got, want := out, env.expectedaccount; got != want {
|
||||
t.Fatalf("should find them in the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "querying the root SDE",
|
||||
Check: func(t testing.TB) {
|
||||
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-s", "base", "(objectclass=*)")
|
||||
if got, want := out, env.expectedinfo; got != want {
|
||||
t.Fatalf("should get some meta information\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "querying the root SDE anonymously without authorizing in config file",
|
||||
Check: func(t testing.TB) {
|
||||
if !env.checkanonymousrootDSE {
|
||||
t.SkipNow()
|
||||
}
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-x", "-s", "base", "(objectclass=*)")
|
||||
if got, want := out, "exit status 50"; got != want {
|
||||
t.Fatalf("should get error 50\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "enumerating posix groups",
|
||||
Check: func(t testing.TB) {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(objectclass=posixgroup)")
|
||||
if got, want := out, env.expectedgroup; got != want {
|
||||
t.Fatalf("should get a list starting with the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "searching for members of the 'superheros' group",
|
||||
Check: func(t testing.TB) {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com)")
|
||||
if got, want := out, env.expectedfirstaccount; got != want {
|
||||
t.Fatalf("should get a list starting with the 'hackers' user\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "performing a complex search for members of 'superheros' group",
|
||||
Check: func(t testing.TB) {
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", "(&(objectClass=*)(memberOf=ou=superheros,ou=groups,dc=glauth,dc=com))")
|
||||
if got, want := out, env.expectedfirstaccount; got != want {
|
||||
t.Fatalf("should get a list starting with the 'hackers' user\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "searching for the 'hacker' user using a TOTP-enabled account",
|
||||
Check: func(t testing.TB) {
|
||||
if !env.checkTOTP {
|
||||
t.SkipNow()
|
||||
}
|
||||
otpvalue := doRunGetFirst(RD, "oathtool", "--totp", "-b", "-d", "6", "3hnvnk4ycv44glzigd6s25j4dougs3rk")
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret"+otpvalue, "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
|
||||
if got, want := out, env.scopedaccount; got != want {
|
||||
t.Fatalf("should find them in in the 'superheros' group\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "searching for the 'hacker' user using a TOTP-enabled account and no value",
|
||||
Check: func(t testing.TB) {
|
||||
if !env.checkTOTP {
|
||||
t.SkipNow()
|
||||
}
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
|
||||
if got, want := out, "exit status 49"; got != want {
|
||||
t.Fatalf("should get 'Invalid credentials(49)'\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "searching for the 'hacker' user using a TOTP-enabled account and the wrong value",
|
||||
Check: func(t testing.TB) {
|
||||
if !env.checkTOTP {
|
||||
t.SkipNow()
|
||||
}
|
||||
out := doRunGetFirst(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.otpdn, "-w", "mysecret123456", "-x", "-bou=superheros,dc=glauth,dc=com", "cn=hackers")
|
||||
if got, want := out, "exit status 49"; got != want {
|
||||
t.Fatalf("should get 'Invalid credentials(49)'\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "searching for the 'hacker' user",
|
||||
Check: func(t testing.TB) {
|
||||
if env.checkemployeetype == "" {
|
||||
t.SkipNow()
|
||||
}
|
||||
out := doRunGetSecond(RD, "ldapsearch", "-LLL", "-H", "ldap://localhost:3893", "-D", env.svcdn, "-w", "mysecret", "-x", "-bdc=glauth,dc=com", env.checkemployeetype, "employeetype")
|
||||
if got, want := out, "employeetype: Intern"; got != want {
|
||||
t.Fatalf("type should be 'Intern'\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
tc.Check(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSampleSimple(t *testing.T) {
|
||||
env := testEnv{
|
||||
checkanonymousrootDSE: true,
|
||||
checkTOTP: true,
|
||||
checkbindUPN: true,
|
||||
expectedinfo: "supportedLDAPVersion: 3",
|
||||
svcdn: "cn=serviceuser,ou=svcaccts,dc=glauth,dc=com",
|
||||
svcdnnogroup: "cn=serviceuser,dc=glauth,dc=com",
|
||||
otpdn: "cn=otpuser,ou=superheros,dc=glauth,dc=com",
|
||||
expectedaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
|
||||
scopedaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
|
||||
expectedfirstaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
|
||||
expectedgroup: "dn: ou=superheros,ou=users,dc=glauth,dc=com",
|
||||
checkemployeetype: "cn=hackers",
|
||||
}
|
||||
|
||||
svc := startSvc(SD, "bin/glauth", "-c", "sample-simple.cfg")
|
||||
batteryOfTests(t, &env)
|
||||
stopSvc(svc)
|
||||
}
|
||||
|
||||
func TestSQLitePlugin(t *testing.T) {
|
||||
matchingLibrary := doRunGetFirst(RD, "ls", "bin/sqlite.so")
|
||||
if matchingLibrary != "bin/sqlite.so" {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
env := testEnv{
|
||||
checkanonymousrootDSE: true,
|
||||
checkTOTP: false,
|
||||
checkbindUPN: true,
|
||||
expectedinfo: "supportedLDAPVersion: 3",
|
||||
svcdn: "cn=serviceuser,ou=svcaccts,dc=glauth,dc=com",
|
||||
svcdnnogroup: "cn=serviceuser,dc=glauth,dc=com",
|
||||
otpdn: "cn=otpuser,ou=superheros,dc=glauth,dc=com",
|
||||
expectedaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
|
||||
scopedaccount: "dn: cn=hackers,ou=superheros,dc=glauth,dc=com",
|
||||
expectedfirstaccount: "dn: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com",
|
||||
expectedgroup: "dn: ou=superheros,ou=users,dc=glauth,dc=com",
|
||||
checkemployeetype: "",
|
||||
}
|
||||
|
||||
svc := startSvc(SD, "bin/glauth", "-c", "pkg/plugins/glauth-sqlite/sample-database.cfg")
|
||||
batteryOfTests(t, &env)
|
||||
stopSvc(svc)
|
||||
}
|
||||
|
||||
func TestLdapInjection(t *testing.T) {
|
||||
matchingContainers := doRunGetFirst(RD, "sh", "-c", "docker ps | grep ldap-service | wc -l")
|
||||
if matchingContainers != "1" {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
env := testEnv{
|
||||
checkanonymousrootDSE: false,
|
||||
checkTOTP: true,
|
||||
checkbindUPN: false,
|
||||
expectedinfo: "objectClass: top",
|
||||
svcdn: "cn=serviceuser,cn=svcaccts,ou=users,dc=glauth,dc=com",
|
||||
svcdnnogroup: "", // ignore
|
||||
otpdn: "cn=otpuser,cn=superheros,ou=users,dc=glauth,dc=com",
|
||||
expectedaccount: "dn: cn=hackers,cn=superheros,ou=users,dc=glauth,dc=com",
|
||||
scopedaccount: "dn: cn=hackers,cn=superheros,ou=users,dc=glauth,dc=com",
|
||||
expectedfirstaccount: "dn: cn=johndoe,cn=superheros,ou=users,dc=glauth,dc=com",
|
||||
expectedgroup: "dn: ou=superheros,ou=users,dc=glauth,dc=com",
|
||||
checkemployeetype: "",
|
||||
}
|
||||
|
||||
svc := startSvc(SD, "bin/glauth", "-c", "sample-ldap-injection.cfg")
|
||||
batteryOfTests(t, &env)
|
||||
stopSvc(svc)
|
||||
}
|
||||
|
||||
// -----=============================================================================----
|
||||
|
||||
const SD = 3 // Start Delay
|
||||
const RD = 2 // Response Delay
|
||||
|
||||
func startSvc(delay time.Duration, name string, arg ...string) *exec.Cmd {
|
||||
cmd := exec.Command(name, arg...)
|
||||
cmd.Start()
|
||||
if delay != 0 {
|
||||
time.Sleep(time.Second * delay)
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func stopSvc(svc *exec.Cmd) {
|
||||
svc.Process.Kill()
|
||||
}
|
||||
|
||||
func doRunGetFirst(delay time.Duration, name string, arg ...string) string {
|
||||
out := strings.SplitN(doRun(delay, name, arg...), "\n", 2)
|
||||
if out == nil || len(out) < 1 {
|
||||
return "*fail*"
|
||||
}
|
||||
return out[0]
|
||||
}
|
||||
|
||||
func doRunGetSecond(delay time.Duration, name string, arg ...string) string {
|
||||
out := strings.SplitN(doRun(delay, name, arg...), "\n", 3)
|
||||
if out == nil || len(out) < 2 {
|
||||
return "*fail*"
|
||||
}
|
||||
return out[1]
|
||||
}
|
||||
|
||||
func doRun(delay time.Duration, name string, arg ...string) string {
|
||||
out, err := exec.Command(name, arg...).Output()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
if delay != 0 {
|
||||
time.Sleep(time.Second * delay)
|
||||
}
|
||||
return strings.TrimSpace(string(out))
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
module github.com/glauth/glauth/v2
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.3.2
|
||||
github.com/GeertJohan/yubigo v0.0.0-20190917122436-175bc097e60e
|
||||
github.com/arl/statsviz v0.6.0
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/glauth/ldap v0.0.0-20240419171521-1f14f5c1b4ad
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/prometheus/client_model v0.5.0
|
||||
github.com/rs/zerolog v1.31.0
|
||||
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3
|
||||
github.com/yaegashi/msgraph.go v0.1.4
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1
|
||||
go.opentelemetry.io/otel v1.21.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0
|
||||
go.opentelemetry.io/otel/sdk v1.21.0
|
||||
go.opentelemetry.io/otel/trace v1.21.0
|
||||
go.uber.org/mock v0.4.0
|
||||
golang.org/x/crypto v0.18.0
|
||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/prometheus/common v0.45.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/rickb777/date v1.12.4 // indirect
|
||||
github.com/rickb777/plural v1.2.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.21.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/grpc v1.59.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,175 @@
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/GeertJohan/yubigo v0.0.0-20190917122436-175bc097e60e h1:Bqtt5C+uVk+vH/t5dmB47uDCTwxw16EYHqvJnmY2aQc=
|
||||
github.com/GeertJohan/yubigo v0.0.0-20190917122436-175bc097e60e/go.mod h1:njRCDrl+1RQ/A/+KVU8Ho2EWAxUSkohOWczdW3dzDG0=
|
||||
github.com/arl/statsviz v0.6.0 h1:jbW1QJkEYQkufd//4NDYRSNBpwJNrdzPahF7ZmoGdyE=
|
||||
github.com/arl/statsviz v0.6.0/go.mod h1:0toboo+YGSUXDaS4g1D5TVS4dXs7S7YYT5J/qnW2h8s=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/glauth/ldap v0.0.0-20240419171521-1f14f5c1b4ad h1:2ERGXiofR9ISXg4evamCngs2EeuMhVJRuDwWGa6bS6s=
|
||||
github.com/glauth/ldap v0.0.0-20240419171521-1f14f5c1b4ad/go.mod h1:5ueZMujvJ5nuYPyBj6uQTPV4R1YshboRa/osaP4Emfs=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
|
||||
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.1.1/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/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
||||
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
|
||||
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/rickb777/date v1.12.4 h1:+6IzcCCS/1t17DrmnEvrznyq7nM8vPwir6/UhlyohKw=
|
||||
github.com/rickb777/date v1.12.4/go.mod h1:xP0eo/I5qmUt97yRGClHZfyLZ3ikMw6v6SU5MOGZTE0=
|
||||
github.com/rickb777/plural v1.2.0 h1:5tvEc7UBCZ7l8h/2UeybSkt/uu1DQsZFOFdNevmUhlE=
|
||||
github.com/rickb777/plural v1.2.0/go.mod h1:UdpyWFCGbo3mvK3f/PfZOAOrkjzJlYN/sD46XNWJ+Es=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
|
||||
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3 h1:LNi0Qa7869/loPjz2kmMvp/jwZZnMZ9scMJKhDJ1DIo=
|
||||
github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3/go.mod h1:jyigonKik3C5V895QNiAGpKYKEvFuqjw9qAEZks1mUg=
|
||||
github.com/yaegashi/msgraph.go v0.1.4 h1:leDXSczAbwBpYFSmmZrdByTiPoUw8dbTfNMetAjJvbw=
|
||||
github.com/yaegashi/msgraph.go v0.1.4/go.mod h1:vgeYhHa5skJt/3lTyjGXThTZhwbhRnGo6uUxzoJIGME=
|
||||
github.com/yaegashi/wtz.go v0.0.2/go.mod h1:nOLA5QXsmdkRxBkP5tljhua13ADHCKirLBrzPf4PEJc=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1 h1:f4beMGDKiVzg9IcX7/VuWVy+oGdjx3dNJ72YehmtY5k=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.21.1/go.mod h1:U9jhkEl8d1LL+QXY7q3kneJWJugiN3kZJV2OWz3hkBY=
|
||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYfrPk5SOryw1e9LDDTZCbIPFrho0ec=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E=
|
||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
|
||||
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
|
||||
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
|
||||
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
|
||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
|
||||
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200529172331-a64b76657301/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY=
|
||||
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b h1:tdSyAzD5FHJmZAZ13d5WexAo7YJkiyGphhzFfInMnDw=
|
||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b/go.mod h1:cE0dCGx2UfBTjLFlzEx4EXJUmoX6BXBoX9GjKOvqha4=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -0,0 +1,28 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type API struct {
|
||||
logger zerolog.Logger
|
||||
}
|
||||
|
||||
func (a *API) RegisterEndpoints(router *http.ServeMux) {
|
||||
router.HandleFunc("/metrics", a.prometheusHTTP)
|
||||
}
|
||||
|
||||
func (a *API) prometheusHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
promhttp.Handler().ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func NewAPI(logger zerolog.Logger) *API {
|
||||
a := new(API)
|
||||
|
||||
a.logger = logger
|
||||
|
||||
return a
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package monitoring
|
||||
|
||||
import "github.com/glauth/ldap"
|
||||
|
||||
type MonitorInterface interface {
|
||||
SetResponseTimeMetric(map[string]string, float64) error
|
||||
SetLDAPMetric(map[string]string, float64) error
|
||||
}
|
||||
|
||||
type LDAPServerInterface interface {
|
||||
SetStats(bool)
|
||||
GetStats() ldap.Stats
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type LDAPMonitorWatcher struct {
|
||||
syncTicker *time.Ticker
|
||||
|
||||
ldap LDAPServerInterface
|
||||
|
||||
monitor MonitorInterface
|
||||
logger *zerolog.Logger
|
||||
}
|
||||
|
||||
func (m *LDAPMonitorWatcher) sync() {
|
||||
for {
|
||||
select {
|
||||
case tick := <-m.syncTicker.C:
|
||||
m.logger.Debug().Time("value", tick).Msg("Tick")
|
||||
m.storeMetrics()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *LDAPMonitorWatcher) storeMetrics() {
|
||||
stats := m.ldap.GetStats()
|
||||
|
||||
if err := m.monitor.SetLDAPMetric(map[string]string{"type": "conns"}, float64(stats.Conns)); err != nil {
|
||||
m.logger.Error().Err(err).Msg("failed to set metric")
|
||||
}
|
||||
if err := m.monitor.SetLDAPMetric(map[string]string{"type": "binds"}, float64(stats.Binds)); err != nil {
|
||||
m.logger.Error().Err(err).Msg("failed to set metric")
|
||||
}
|
||||
if err := m.monitor.SetLDAPMetric(map[string]string{"type": "unbinds"}, float64(stats.Unbinds)); err != nil {
|
||||
m.logger.Error().Err(err).Msg("failed to set metric")
|
||||
}
|
||||
if err := m.monitor.SetLDAPMetric(map[string]string{"type": "searches"}, float64(stats.Searches)); err != nil {
|
||||
m.logger.Error().Err(err).Msg("failed to set metric")
|
||||
}
|
||||
}
|
||||
|
||||
func NewLDAPMonitorWatcher(ldap LDAPServerInterface, monitor MonitorInterface, logger *zerolog.Logger) *LDAPMonitorWatcher {
|
||||
m := new(LDAPMonitorWatcher)
|
||||
|
||||
m.syncTicker = time.NewTicker(15 * time.Second)
|
||||
m.ldap = ldap
|
||||
m.monitor = monitor
|
||||
m.logger = logger
|
||||
|
||||
m.ldap.SetStats(true)
|
||||
|
||||
go m.sync()
|
||||
|
||||
return m
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/glauth/ldap"
|
||||
"github.com/rs/zerolog"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
//go:generate mockgen -build_flags=--mod=mod -package monitoring -destination ./mock_interfaces.go -source=./interfaces.go
|
||||
|
||||
func TestNewLDAPMonitorWatcherRunsOnASchedule(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
mockMonitor := NewMockMonitorInterface(ctrl)
|
||||
mockLDAPServer := NewMockLDAPServerInterface(ctrl)
|
||||
|
||||
stats := ldap.Stats{}
|
||||
|
||||
mockLDAPServer.EXPECT().SetStats(true).Times(1)
|
||||
mockLDAPServer.EXPECT().GetStats().MinTimes(1).Return(stats)
|
||||
mockMonitor.EXPECT().SetLDAPMetric(map[string]string{"type": "conns"}, float64(0)).MinTimes(1)
|
||||
mockMonitor.EXPECT().SetLDAPMetric(map[string]string{"type": "binds"}, float64(0)).MinTimes(1)
|
||||
mockMonitor.EXPECT().SetLDAPMetric(map[string]string{"type": "unbinds"}, float64(0)).MinTimes(1)
|
||||
mockMonitor.EXPECT().SetLDAPMetric(map[string]string{"type": "searches"}, float64(0)).MinTimes(1)
|
||||
|
||||
logger := zerolog.Nop()
|
||||
m := NewLDAPMonitorWatcher(mockLDAPServer, mockMonitor, &logger)
|
||||
|
||||
m.syncTicker = time.NewTicker(5 * time.Microsecond)
|
||||
|
||||
// allow goroutine to start and ticker to tick
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// The code below liberally borrows from https://github.com/albertito/prometheus-expvar-exporter
|
||||
// and is adapted (just a little) for our purpose.
|
||||
|
||||
type Collector struct {
|
||||
url string
|
||||
names map[string]string
|
||||
helps map[string]string
|
||||
labelName map[string]string
|
||||
}
|
||||
|
||||
func (c *Collector) Describe(ch chan<- *prometheus.Desc) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Collector) Collect(ch chan<- prometheus.Metric) {
|
||||
resp, err := http.Get(c.url)
|
||||
if err != nil {
|
||||
log.Printf("Error scraping %q: %v", c.url, err)
|
||||
return
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("Error reading body of %q: %v", c.url, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Replace "\xNN" with "?" because the default parser doesn't handle them
|
||||
// well.
|
||||
re := regexp.MustCompile(`\\x..`)
|
||||
body = re.ReplaceAllFunc(body, func(s []byte) []byte {
|
||||
return []byte("?")
|
||||
})
|
||||
|
||||
var vs map[string]interface{}
|
||||
err = json.Unmarshal(body, &vs)
|
||||
if err != nil {
|
||||
log.Printf("Error unmarshalling json from %q: %v", c.url, err)
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range vs {
|
||||
name := strings.ReplaceAll(k, "/", "_")
|
||||
if n, ok := c.names[k]; ok {
|
||||
name = n
|
||||
}
|
||||
|
||||
help := fmt.Sprintf("expvar %q", k)
|
||||
if h, ok := c.helps[k]; ok {
|
||||
help = h
|
||||
}
|
||||
|
||||
lnames := []string{}
|
||||
if ln, ok := c.labelName[k]; ok {
|
||||
lnames = append(lnames, ln)
|
||||
}
|
||||
|
||||
desc := prometheus.NewDesc(name, help, lnames, nil)
|
||||
|
||||
switch v := v.(type) {
|
||||
case float64:
|
||||
ch <- prometheus.MustNewConstMetric(desc, prometheus.UntypedValue, v)
|
||||
case bool:
|
||||
ch <- prometheus.MustNewConstMetric(desc, prometheus.UntypedValue,
|
||||
valToFloat(v))
|
||||
case map[string]interface{}:
|
||||
// We only support explicitly written label names.
|
||||
if len(lnames) != 1 {
|
||||
continue
|
||||
}
|
||||
for lk, lv := range v {
|
||||
ch <- prometheus.MustNewConstMetric(desc, prometheus.UntypedValue,
|
||||
valToFloat(lv), lk)
|
||||
}
|
||||
case string:
|
||||
// Not supported by Prometheus.
|
||||
continue
|
||||
case []interface{}:
|
||||
// Not supported by Prometheus.
|
||||
continue
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewCollector(url string) *Collector {
|
||||
c := new(Collector)
|
||||
c.url = url
|
||||
c.names = map[string]string{
|
||||
"proxy": "glauth_proxy",
|
||||
"proxy_frontend": "glauth_proxy_frontend",
|
||||
"proxy_backend": "glauth_proxy_backend",
|
||||
}
|
||||
c.helps = map[string]string{
|
||||
"proxy": "General Metrics",
|
||||
"proxy_frontend": "Frontend Metrics",
|
||||
"proxy_backend": "Backend Metrics",
|
||||
}
|
||||
c.labelName = map[string]string{
|
||||
"proxy": "metric",
|
||||
"proxy_frontend": "metric",
|
||||
"proxy_backend": "metric",
|
||||
}
|
||||
|
||||
prometheus.MustRegister(c)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func valToFloat(v interface{}) float64 {
|
||||
switch v := v.(type) {
|
||||
case float64:
|
||||
return v
|
||||
case bool:
|
||||
if v {
|
||||
return 1.0
|
||||
}
|
||||
return 0.0
|
||||
case string:
|
||||
return 0.0
|
||||
}
|
||||
log.Printf("unexpected value type: %#v", v)
|
||||
return 0.0
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type Monitor struct {
|
||||
responseTime *prometheus.HistogramVec
|
||||
ldapMetric *prometheus.GaugeVec
|
||||
|
||||
logger *zerolog.Logger
|
||||
}
|
||||
|
||||
func (m *Monitor) SetResponseTimeMetric(tags map[string]string, value float64) error {
|
||||
if m.responseTime == nil {
|
||||
return fmt.Errorf("metric not instantiated")
|
||||
}
|
||||
|
||||
m.responseTime.With(tags).Observe(value)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Monitor) SetLDAPMetric(tags map[string]string, value float64) error {
|
||||
if m.ldapMetric == nil {
|
||||
return fmt.Errorf("metric not instantiated")
|
||||
}
|
||||
|
||||
m.ldapMetric.With(tags).Set(value)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Monitor) constLabels() map[string]string {
|
||||
return map[string]string{
|
||||
"library": "github.com/glauth/glauth",
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (m *Monitor) registerHistograms() {
|
||||
histograms := make([]*prometheus.HistogramVec, 0)
|
||||
|
||||
m.responseTime = prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "tcp_response_time_seconds",
|
||||
Help: "tcp_response_time_seconds",
|
||||
ConstLabels: m.constLabels(),
|
||||
},
|
||||
[]string{"operation", "status"},
|
||||
)
|
||||
|
||||
histograms = append(histograms, m.responseTime)
|
||||
|
||||
for _, histogram := range histograms {
|
||||
err := prometheus.Register(histogram)
|
||||
|
||||
switch err.(type) {
|
||||
case nil:
|
||||
return
|
||||
case prometheus.AlreadyRegisteredError:
|
||||
m.logger.Debug().Interface("metric", histogram).Msg("metric already registered")
|
||||
default:
|
||||
m.logger.Error().Interface("metric", histogram).Msg("metric could not be registered")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Monitor) registerGauges() {
|
||||
gauges := make([]*prometheus.GaugeVec, 0)
|
||||
|
||||
m.ldapMetric = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "ldap_metric",
|
||||
Help: "ldap_metric",
|
||||
ConstLabels: m.constLabels(),
|
||||
},
|
||||
[]string{"type"},
|
||||
)
|
||||
|
||||
gauges = append(gauges, m.ldapMetric)
|
||||
|
||||
for _, gauge := range gauges {
|
||||
err := prometheus.Register(gauge)
|
||||
|
||||
switch err.(type) {
|
||||
case nil:
|
||||
return
|
||||
case prometheus.AlreadyRegisteredError:
|
||||
m.logger.Debug().Interface("metric", gauge).Msg("metric already registered")
|
||||
default:
|
||||
m.logger.Error().Interface("metric", gauge).Msg("metric could not be registered")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewMonitor(logger *zerolog.Logger) *Monitor {
|
||||
m := new(Monitor)
|
||||
|
||||
m.logger = logger
|
||||
|
||||
m.registerHistograms()
|
||||
m.registerGauges()
|
||||
|
||||
return m
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package monitoring
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
func TestNewMonitorImplementsInterface(t *testing.T) {
|
||||
logger := zerolog.Nop()
|
||||
m := NewMonitor(&logger)
|
||||
|
||||
i := reflect.TypeOf((*MonitorInterface)(nil)).Elem()
|
||||
|
||||
if !reflect.TypeOf(m).Implements(i) {
|
||||
t.Fatal("Monitor doesn't implement MonitorInterface")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonitorSetLDAPMetricSucceeds(t *testing.T) {
|
||||
logger := zerolog.Nop()
|
||||
m := NewMonitor(&logger)
|
||||
|
||||
labels := map[string]string{"type": "test"}
|
||||
m.SetLDAPMetric(labels, float64(10))
|
||||
|
||||
mLDAPMetric := dto.Metric{}
|
||||
m.ldapMetric.With(labels).Write(&mLDAPMetric)
|
||||
|
||||
if mLDAPMetric.GetGauge().GetValue() != float64(10) {
|
||||
t.Fatalf("metric value should have been set to %v", float64(10))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonitorSetResponseTimeMetricSucceeds(t *testing.T) {
|
||||
logger := zerolog.Nop()
|
||||
m := NewMonitor(&logger)
|
||||
|
||||
labels := map[string]string{"operation": "test", "status": "0"}
|
||||
m.SetResponseTimeMetric(labels, float64(10))
|
||||
|
||||
mResponseTimeMetric := dto.Metric{}
|
||||
m.responseTime.With(labels).(prometheus.Metric).Write(&mResponseTimeMetric)
|
||||
|
||||
if mResponseTimeMetric.GetHistogram().GetSampleSum() != float64(10) {
|
||||
t.Fatalf("metric value should have been set to %v", float64(10))
|
||||
}
|
||||
|
||||
for _, bucket := range mResponseTimeMetric.GetHistogram().GetBucket() {
|
||||
if bucket.GetUpperBound() < float64(10) && bucket.GetCumulativeCount() != 0 {
|
||||
t.Fatal("there should be no count for this metric bucket")
|
||||
}
|
||||
|
||||
if bucket.GetUpperBound() >= float64(10) && bucket.GetCumulativeCount() != 1 {
|
||||
t.Fatal("there should be one entry into this metric bucket")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package tls
|
||||
|
||||
import (
|
||||
tls "crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
var (
|
||||
log zerolog.Logger
|
||||
)
|
||||
|
||||
var secureCipherSuites = []uint16{
|
||||
// TLS 1.3 cipher suites (automatically used when TLS 1.3 is negotiated)
|
||||
tls.TLS_AES_128_GCM_SHA256,
|
||||
tls.TLS_AES_256_GCM_SHA384,
|
||||
tls.TLS_CHACHA20_POLY1305_SHA256,
|
||||
|
||||
// TLS 1.2 ECDHE cipher suites (Forward Secrecy)
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
|
||||
// Additional secure TLS 1.2 cipher suites (CBC with HMAC-SHA256)
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
// tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||
// tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
||||
}
|
||||
|
||||
// MakeTLS generates a tls.Config
|
||||
func MakeTLS(clientCert, key []byte, legacy bool) (*tls.Config, error) {
|
||||
if clientCert == nil && key == nil {
|
||||
return new(tls.Config), nil
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
cert, err := tls.X509KeyPair(clientCert, key)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug().Str("key", string(key))
|
||||
log.Debug().Str("client.certificate", string(clientCert))
|
||||
log.Debug().Interface("certificate", cert)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the SystemCertPool, continue with an empty pool on error
|
||||
rootCAs, err := x509.SystemCertPool()
|
||||
|
||||
if rootCAs == nil {
|
||||
rootCAs = x509.NewCertPool()
|
||||
log.Warn().Err(err).Msg("Using empty cert-pool")
|
||||
} else {
|
||||
log.Info().Msg("Using system cert-pool")
|
||||
}
|
||||
|
||||
for _, cert := range DecodePEM(clientCert).Certificate {
|
||||
x509Cert, err := x509.ParseCertificate(cert)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("issue parsing cert PEM")
|
||||
}
|
||||
rootCAs.AddCert(x509Cert)
|
||||
}
|
||||
|
||||
log.Debug().Interface("root.ca", rootCAs)
|
||||
log.Debug().Interface("certificates", []tls.Certificate{cert})
|
||||
|
||||
if legacy {
|
||||
return &tls.Config{
|
||||
RootCAs: rootCAs,
|
||||
MinVersion: tls.VersionTLS10,
|
||||
MaxVersion: tls.VersionTLS13,
|
||||
PreferServerCipherSuites: true,
|
||||
CipherSuites: nil,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
RootCAs: rootCAs,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
MaxVersion: tls.VersionTLS13,
|
||||
PreferServerCipherSuites: true,
|
||||
CipherSuites: secureCipherSuites,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DecodePEM builds a PEM certificate object
|
||||
func DecodePEM(certPEM []byte) tls.Certificate {
|
||||
var cert tls.Certificate
|
||||
var certDER *pem.Block
|
||||
for {
|
||||
certDER, certPEM = pem.Decode(certPEM)
|
||||
if certDER == nil {
|
||||
break
|
||||
}
|
||||
if certDER.Type == "CERTIFICATE" {
|
||||
cert.Certificate = append(cert.Certificate, certDER.Bytes)
|
||||
}
|
||||
}
|
||||
|
||||
return cert
|
||||
}
|
||||
|
||||
func CipherSuiteNames(suites []uint16) []string {
|
||||
var names []string
|
||||
for _, suite := range suites {
|
||||
names = append(names, tls.CipherSuiteName(suite))
|
||||
}
|
||||
return names
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/GeertJohan/yubigo"
|
||||
"github.com/glauth/glauth/v2/pkg/config"
|
||||
"github.com/rs/zerolog/log"
|
||||
"gopkg.in/amz.v3/aws"
|
||||
"gopkg.in/amz.v3/s3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Users []toml.Primitive
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
CustomAttributes []toml.Primitive
|
||||
}
|
||||
|
||||
// NewConfig reads the cli flags and config file
|
||||
func NewConfig(checkConfig bool, location string, args map[string]interface{}) (*config.Config, error) {
|
||||
// Parse config-file into config{} struct
|
||||
cfg, err := parseConfigFile(location, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Handle parsed flags
|
||||
cfg, err = handleArgs(cfg, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Handle parsing of legacy [frontend] section into [ldap] and/or [ldaps] sections
|
||||
cfg, err = handleLegacyConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg, err = validateConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO @shipperizer reinstate this
|
||||
// // Before greenlighting new config entirely, lets make sure the yubiauth works - in case they changed
|
||||
|
||||
if _, err := yubigo.NewYubiAuth(cfg.YubikeyClientID, cfg.YubikeySecret); err != nil && len(cfg.YubikeyClientID) > 0 && len(cfg.YubikeySecret) > 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func parseConfigFile(configFileLocation string, args map[string]interface{}) (*config.Config, error) {
|
||||
cfg := new(config.Config)
|
||||
// setup defaults
|
||||
cfg.LDAP.Enabled = false
|
||||
cfg.LDAPS.Enabled = true
|
||||
|
||||
// parse the config file
|
||||
if strings.HasPrefix(configFileLocation, "s3://") {
|
||||
region, present := aws.Regions[args["-r"].(string)]
|
||||
if !present {
|
||||
return cfg, fmt.Errorf("invalid AWS region: %s", args["-r"])
|
||||
}
|
||||
if args["--aws_endpoint_url"] != nil {
|
||||
region = aws.Region{
|
||||
Name: "User defined",
|
||||
S3Endpoint: args["--aws_endpoint_url"].(string),
|
||||
}
|
||||
present = true
|
||||
}
|
||||
auth, err := aws.EnvAuth()
|
||||
if err != nil {
|
||||
if args["-K"] == nil || args["-S"] == nil {
|
||||
return cfg, fmt.Errorf("AWS credentials not found: must use -K and -S flags, or set these env vars:\n\texport AWS_ACCESS_KEY_ID=\"AAA...\"\n\texport AWS_SECRET_ACCESS_KEY=\"BBBB...\"\n")
|
||||
}
|
||||
auth = aws.Auth{
|
||||
AccessKey: args["-K"].(string),
|
||||
SecretKey: args["-S"].(string),
|
||||
}
|
||||
}
|
||||
// parse S3 url
|
||||
s3url := strings.TrimPrefix(configFileLocation, "s3://")
|
||||
parts := strings.SplitN(s3url, "/", 2)
|
||||
if len(parts) != 2 {
|
||||
return cfg, fmt.Errorf("invalid S3 URL: %s", s3url)
|
||||
}
|
||||
b, err := s3.New(auth, region).Bucket(parts[0])
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
tomlData, err := b.Get(parts[1])
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
if _, err := toml.Decode(string(tomlData), cfg); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
} else { // local config file
|
||||
fInfo, err := os.Stat(configFileLocation)
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("non-existent config path: %s", configFileLocation)
|
||||
}
|
||||
|
||||
if fInfo.IsDir() { // multiple files in a directory
|
||||
rawCfgStruct := make(map[string]interface{})
|
||||
|
||||
// To keep things simple, we are not going to use the default values built in Cfg
|
||||
// so far (LDAP.Enabled, LDAPS.Enabled, etc) so do not forget to specify them!
|
||||
/*
|
||||
sourcebuf := new(bytes.Buffer)
|
||||
err = toml.NewEncoder(sourcebuf).Encode(cfg)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
var initialRawCfgStruct interface{}
|
||||
if err := toml.Unmarshal(sourcebuf.Bytes(), &initialRawCfgStruct); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
if err = mergeConfigs(&rawCfgStruct, initialRawCfgStruct); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
*/
|
||||
|
||||
files, _ := os.ReadDir(configFileLocation)
|
||||
for _, f := range files {
|
||||
canonicalName := filepath.Join(configFileLocation, f.Name())
|
||||
|
||||
bs, _ := os.ReadFile(canonicalName)
|
||||
var curRawCfgStruct interface{}
|
||||
if err := toml.Unmarshal(bs, &curRawCfgStruct); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
if err = mergeConfigs(&rawCfgStruct, curRawCfgStruct); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
}
|
||||
|
||||
destbuf := new(bytes.Buffer)
|
||||
err = toml.NewEncoder(destbuf).Encode(rawCfgStruct)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
fmt.Println(destbuf.String())
|
||||
merged := config.Config{}
|
||||
if _, err = toml.Decode(destbuf.String(), &merged); err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
cfg = &merged
|
||||
} else {
|
||||
_, err = toml.DecodeFile(configFileLocation, cfg)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
}
|
||||
|
||||
usersCustomAttributes(configFileLocation, cfg)
|
||||
}
|
||||
|
||||
// Backward Compability
|
||||
if cfg.Backend.Datastore != "" {
|
||||
if cfg.Backends != nil {
|
||||
return cfg, fmt.Errorf("you cannot specify both [Backend] and [[Backends]] directives in the same configuration ")
|
||||
} else {
|
||||
cfg.Backends = append(cfg.Backends, cfg.Backend)
|
||||
}
|
||||
}
|
||||
|
||||
// Patch with default values where not specified
|
||||
for i := range cfg.Backends {
|
||||
if cfg.Backends[i].NameFormat == "" {
|
||||
cfg.Backends[i].NameFormat = "cn,uid"
|
||||
}
|
||||
cfg.Backends[i].NameFormatAsArray = strings.Split(cfg.Backends[i].NameFormat, ",")
|
||||
if cfg.Backends[i].GroupFormat == "" {
|
||||
cfg.Backends[i].GroupFormat = "ou,cn"
|
||||
}
|
||||
cfg.Backends[i].GroupFormatAsArray = strings.Split(cfg.Backends[i].GroupFormat, ",")
|
||||
if cfg.Backends[i].SSHKeyAttr == "" {
|
||||
cfg.Backends[i].SSHKeyAttr = "sshPublicKey"
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// usersCustomAttributes changes config passed in by adding extra information coming from the custom attributes
|
||||
func usersCustomAttributes(location string, config *config.Config) {
|
||||
// TODO @shipperizer deal with multiple files like in line #126
|
||||
c := new(Config)
|
||||
|
||||
md, err := toml.DecodeFile(location, c)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("issues parsing users...keep going")
|
||||
return
|
||||
}
|
||||
|
||||
for _, u := range c.Users {
|
||||
user := new(User)
|
||||
md.PrimitiveDecode(u, user)
|
||||
|
||||
if user.CustomAttributes == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for idx, cUser := range config.Users {
|
||||
if cUser.Name != user.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
x := make(map[string]interface{})
|
||||
|
||||
for _, attribute := range user.CustomAttributes {
|
||||
_ = md.PrimitiveDecode(attribute, x)
|
||||
|
||||
for k, v := range x {
|
||||
|
||||
if config.Users[idx].CustomAttrs == nil {
|
||||
config.Users[idx].CustomAttrs = make(map[string]interface{})
|
||||
}
|
||||
|
||||
config.Users[idx].CustomAttrs[k] = v
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mergeConfigs(config1 interface{}, config2 interface{}) error {
|
||||
var merger func(int, string, interface{}, interface{}) error
|
||||
merger = func(depth int, keyName string, cfg1 interface{}, cfg2 interface{}) error {
|
||||
//fmt.Println(strings.Repeat(" ", depth), "Handling element: ", keyName, " for: ", cfg2)
|
||||
switch element2 := cfg2.(type) {
|
||||
case map[string]interface{}:
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - A map")
|
||||
element2, ok := cfg2.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("config source: %s is not a map", keyName)
|
||||
}
|
||||
element1, ok := cfg1.(*map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("config dest: %s is not a map", keyName)
|
||||
}
|
||||
for k, _ := range element2 {
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - key: ", k)
|
||||
_, ok := (*element1)[k]
|
||||
if !ok {
|
||||
(*element1)[k] = element2[k]
|
||||
} else {
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - merging: ", element2[k])
|
||||
asanarrayptr, ok := (*element1)[k].([]map[string]interface{})
|
||||
if ok {
|
||||
if err := merger(depth+1, k, &asanarrayptr, element2[k]); err != nil {
|
||||
return err
|
||||
}
|
||||
(*element1)[k] = asanarrayptr
|
||||
} else {
|
||||
asamapptr, ok := (*element1)[k].(map[string]interface{})
|
||||
if ok {
|
||||
if err := merger(depth+1, k, &asamapptr, element2[k]); err != nil {
|
||||
return err
|
||||
}
|
||||
(*element1)[k] = asamapptr
|
||||
} else {
|
||||
return fmt.Errorf("config dest: %s does not make a valid map/array ptr", keyName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case []map[string]interface{}:
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - An array")
|
||||
element2, ok := cfg2.([]map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("config source: %s is not a map array", keyName)
|
||||
}
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - element2: ", element2)
|
||||
element1, ok := cfg1.(*[]map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("config dest: %s is not a map array", keyName)
|
||||
}
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - element1: ", element1)
|
||||
for index, _ := range element2 {
|
||||
*element1 = append(*element1, element2[index])
|
||||
}
|
||||
case string:
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - A string")
|
||||
element2, ok := cfg2.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("config: %s is not a string", keyName)
|
||||
}
|
||||
case bool:
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - A boolean")
|
||||
element2, ok := cfg2.(bool)
|
||||
if !ok {
|
||||
return fmt.Errorf("config: %s is not a boolean value", keyName)
|
||||
}
|
||||
case float64:
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - A float64")
|
||||
element2, ok := cfg2.(float64)
|
||||
if !ok {
|
||||
return fmt.Errorf("config: %s is not a float64 value", keyName)
|
||||
}
|
||||
case nil:
|
||||
//fmt.Println(strings.Repeat(" ", depth), " - Nil")
|
||||
default:
|
||||
log.Info().Str("type", reflect.TypeOf(element2).String()).Msg("Unknown element type found in configuration file. Ignoring.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
err := merger(0, "TOP", config1, config2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleArgs(cfg *config.Config, args map[string]interface{}) (*config.Config, error) {
|
||||
// LDAP flags
|
||||
if ldap, ok := args["--ldap"].(string); ok && ldap != "" {
|
||||
cfg.LDAP.Enabled = true
|
||||
cfg.LDAP.Listen = ldap
|
||||
}
|
||||
|
||||
// LDAPS flags
|
||||
if ldaps, ok := args["--ldaps"].(string); ok && ldaps != "" {
|
||||
cfg.LDAPS.Enabled = true
|
||||
cfg.LDAPS.Listen = ldaps
|
||||
}
|
||||
if ldapsCert, ok := args["--ldaps-cert"].(string); ok && ldapsCert != "" {
|
||||
cfg.LDAPS.Cert = ldapsCert
|
||||
}
|
||||
if ldapsKey, ok := args["--ldaps-key"].(string); ok && ldapsKey != "" {
|
||||
cfg.LDAPS.Key = ldapsKey
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func handleLegacyConfig(cfg *config.Config) (*config.Config, error) {
|
||||
if len(cfg.Frontend.Listen) > 0 && (len(cfg.LDAP.Listen) > 0 || len(cfg.LDAPS.Listen) > 0) {
|
||||
// Both old server-config and new - dont allow
|
||||
return cfg, fmt.Errorf("both old and new server-config in use - please remove old format ([frontend]) and migrate to new format ([ldap], [ldaps])")
|
||||
}
|
||||
|
||||
if len(cfg.Frontend.Listen) > 0 {
|
||||
// We're going with old format - parse it into new
|
||||
log.Info().Msg("Config [frontend] is deprecated - please move to [ldap] and [ldaps] as-per documentation")
|
||||
|
||||
cfg.LDAP.Enabled = !cfg.Frontend.TLS
|
||||
cfg.LDAPS.Enabled = cfg.Frontend.TLS
|
||||
|
||||
if cfg.Frontend.TLS {
|
||||
cfg.LDAPS.Listen = cfg.Frontend.Listen
|
||||
} else {
|
||||
cfg.LDAP.Listen = cfg.Frontend.Listen
|
||||
}
|
||||
|
||||
if len(cfg.Frontend.Cert) > 0 {
|
||||
cfg.LDAPS.Cert = cfg.Frontend.Cert
|
||||
}
|
||||
if len(cfg.Frontend.Key) > 0 {
|
||||
cfg.LDAPS.Key = cfg.Frontend.Key
|
||||
}
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
func validateConfig(cfg *config.Config) (*config.Config, error) {
|
||||
|
||||
if !cfg.LDAP.Enabled && !cfg.LDAPS.Enabled {
|
||||
return cfg, fmt.Errorf("no server configuration found: please provide either LDAP or LDAPS configuration")
|
||||
}
|
||||
|
||||
if cfg.LDAPS.Enabled {
|
||||
// LDAPS enabled - verify requirements (cert, key, listen)
|
||||
if len(cfg.LDAPS.Listen) == 0 {
|
||||
return cfg, fmt.Errorf("no LDAPS bind address was specified: please disable LDAPS or use the 'listen' option")
|
||||
}
|
||||
|
||||
if cfg.LDAPS.Cert == "" && cfg.LDAPS.CertPath != "" {
|
||||
byteData, err := os.ReadFile(cfg.LDAPS.CertPath)
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("unable to read TLS certificate file")
|
||||
}
|
||||
cfg.LDAPS.Cert = string(byteData)
|
||||
}
|
||||
|
||||
if cfg.LDAPS.Key == "" && cfg.LDAPS.KeyPath != "" {
|
||||
byteData, err := os.ReadFile(cfg.LDAPS.KeyPath)
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("unable to read TLS key file")
|
||||
}
|
||||
cfg.LDAPS.Key = string(byteData)
|
||||
}
|
||||
|
||||
// Ugly wart for backward compatibility
|
||||
// In the olden times, we would simply say "please read from this file"
|
||||
// This is now the role of the Path files.
|
||||
if !strings.HasPrefix(cfg.LDAPS.Cert, "-----") {
|
||||
byteData, err := os.ReadFile(cfg.LDAPS.Cert)
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("unable to read TLS certificate file")
|
||||
}
|
||||
cfg.LDAPS.Cert = string(byteData)
|
||||
}
|
||||
if !strings.HasPrefix(cfg.LDAPS.Key, "-----") {
|
||||
byteData, err := os.ReadFile(cfg.LDAPS.Key)
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("unable to read TLS key file")
|
||||
}
|
||||
cfg.LDAPS.Key = string(byteData)
|
||||
}
|
||||
|
||||
if cfg.LDAPS.Cert == "" || cfg.LDAPS.Key == "" {
|
||||
return cfg, fmt.Errorf("LDAPS was enabled but no certificate or key were specified: please disable LDAPS or use the 'cert'/'key' or 'certpath'/'keypath' options")
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.LDAP.Enabled {
|
||||
// LDAP enabled - verify listen
|
||||
if len(cfg.LDAP.Listen) == 0 {
|
||||
return cfg, fmt.Errorf("no LDAP bind address was specified: please disable LDAP or use the 'listen' option")
|
||||
}
|
||||
|
||||
if cfg.LDAP.TLS {
|
||||
if cfg.LDAP.TLSCert == "" && cfg.LDAP.TLSCertPath != "" {
|
||||
byteData, err := os.ReadFile(cfg.LDAP.TLSCertPath)
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("unable to read TLS certificate file")
|
||||
}
|
||||
cfg.LDAP.TLSCert = string(byteData)
|
||||
}
|
||||
|
||||
if cfg.LDAP.TLSKey == "" && cfg.LDAP.TLSKeyPath != "" {
|
||||
byteData, err := os.ReadFile(cfg.LDAP.TLSKeyPath)
|
||||
if err != nil {
|
||||
return cfg, fmt.Errorf("unable to read TLS key file")
|
||||
}
|
||||
cfg.LDAP.TLSKey = string(byteData)
|
||||
}
|
||||
|
||||
if cfg.LDAP.TLSCert == "" || cfg.LDAP.TLSKey == "" {
|
||||
return cfg, fmt.Errorf("StartTLS was enabled but no certificate or key were specified: please disable StartTLS or use the 'tlscert'/'tlskey' or 'tlscertpath'/'tlskeypath' options")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//spew.Dump(cfg)
|
||||
for i := range cfg.Backends {
|
||||
switch cfg.Backends[i].Datastore {
|
||||
case "":
|
||||
cfg.Backends[i].Datastore = "config"
|
||||
case "config":
|
||||
case "ldap":
|
||||
case "owncloud":
|
||||
case "plugin":
|
||||
case "embed":
|
||||
default:
|
||||
return cfg, fmt.Errorf("invalid backend %s - must be 'config', 'ldap', 'owncloud', 'plugin' or 'embed", cfg.Backends[i].Datastore)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove after deprecating UnixID on User and Group
|
||||
for _, user := range cfg.Users {
|
||||
if user.UnixID != 0 {
|
||||
user.UIDNumber = user.UnixID
|
||||
log.Info().Msg(fmt.Sprintf("User '%s': 'unixid' is deprecated - please move to 'uidnumber' as per documentation", user.Name))
|
||||
}
|
||||
}
|
||||
for _, group := range cfg.Groups {
|
||||
if group.UnixID != 0 {
|
||||
group.GIDNumber = group.UnixID
|
||||
log.Info().Msg(fmt.Sprintf("Group '%s': 'unixid' is deprecated - please move to 'gidnumber' as per documentation", group.Name))
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package tracing
|
||||
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
OtelHTTPEndpoint string
|
||||
OtelGRPCEndpoint string
|
||||
Logger *zerolog.Logger
|
||||
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
func NewConfig(enabled bool, otelGRPCEndpoint, otelHTTPEndpoint string, logger *zerolog.Logger) *Config {
|
||||
c := new(Config)
|
||||
|
||||
c.OtelGRPCEndpoint = otelGRPCEndpoint
|
||||
c.OtelHTTPEndpoint = otelHTTPEndpoint
|
||||
c.Logger = logger
|
||||
c.Enabled = enabled
|
||||
|
||||
return c
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package tracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"go.opentelemetry.io/contrib/propagators/jaeger"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
||||
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.opentelemetry.io/otel/trace/embedded"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
)
|
||||
|
||||
type Tracer struct {
|
||||
embedded.Tracer
|
||||
|
||||
tracer trace.Tracer
|
||||
|
||||
logger *zerolog.Logger
|
||||
}
|
||||
|
||||
func (t *Tracer) init(service string, e sdktrace.SpanExporter) {
|
||||
traceProvider := sdktrace.NewTracerProvider(
|
||||
sdktrace.WithSampler(sdktrace.AlwaysSample()),
|
||||
sdktrace.WithBatcher(e),
|
||||
sdktrace.WithResource(
|
||||
t.buildResource(service),
|
||||
),
|
||||
)
|
||||
|
||||
otel.SetTracerProvider(traceProvider)
|
||||
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}, jaeger.Jaeger{}))
|
||||
|
||||
t.tracer = otel.Tracer(service)
|
||||
}
|
||||
|
||||
func (t *Tracer) gitRevision(settings []debug.BuildSetting) string {
|
||||
for _, setting := range settings {
|
||||
if setting.Key == "vcs.revision" {
|
||||
return setting.Value
|
||||
}
|
||||
}
|
||||
|
||||
return "n/a"
|
||||
}
|
||||
|
||||
func (t *Tracer) buildResource(service string) *resource.Resource {
|
||||
var res *resource.Resource
|
||||
|
||||
res = resource.NewWithAttributes(
|
||||
semconv.SchemaURL,
|
||||
semconv.ServiceName(service),
|
||||
semconv.ServiceVersion("n/a"),
|
||||
)
|
||||
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
if service == "" {
|
||||
service = info.Path
|
||||
}
|
||||
|
||||
res = resource.NewWithAttributes(
|
||||
semconv.SchemaURL,
|
||||
semconv.ServiceName(service),
|
||||
attribute.String("git_sha", t.gitRevision(info.Settings)),
|
||||
attribute.String("app", info.Main.Path),
|
||||
)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (t *Tracer) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
|
||||
return t.tracer.Start(ctx, spanName, opts...)
|
||||
}
|
||||
|
||||
// basic tracer implementation of trace.Tracer, just adding some extra configuration
|
||||
func NewTracer(cfg *Config) *Tracer {
|
||||
t := new(Tracer)
|
||||
|
||||
t.logger = cfg.Logger
|
||||
|
||||
// if tracing disabled skip the config
|
||||
if !cfg.Enabled {
|
||||
t.tracer = noop.NewTracerProvider().Tracer("github.com/glauth/glauth")
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
var err error
|
||||
var exporter sdktrace.SpanExporter
|
||||
|
||||
if cfg.OtelGRPCEndpoint != "" {
|
||||
exporter, err = otlptrace.New(
|
||||
context.TODO(),
|
||||
otlptracegrpc.NewClient(
|
||||
otlptracegrpc.WithEndpoint(cfg.OtelGRPCEndpoint),
|
||||
otlptracegrpc.WithInsecure(),
|
||||
),
|
||||
)
|
||||
} else if cfg.OtelHTTPEndpoint != "" {
|
||||
exporter, err = otlptrace.New(
|
||||
context.TODO(),
|
||||
otlptracehttp.NewClient(
|
||||
otlptracehttp.WithEndpoint(cfg.OtelHTTPEndpoint),
|
||||
otlptracehttp.WithInsecure(),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
exporter, err = stdouttrace.New(
|
||||
stdouttrace.WithPrettyPrint(),
|
||||
)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.logger.Error().Err(err).Msg("unable to initialize tracing exporter")
|
||||
return nil
|
||||
}
|
||||
|
||||
// set tracer provider and propagator properly, this is to ensure all
|
||||
// instrumentation library could run well
|
||||
t.init("github.com/glauth/glauth", exporter)
|
||||
|
||||
return t
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package version
|
||||
|
||||
// Version is the tag of the latest release, it gets changed by the ci
|
||||
// process when a release is happening
|
||||
const Version = "v2.5.0" // x-release-please-version
|
||||
@@ -0,0 +1,68 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
type gitInfo struct {
|
||||
BuildTime string
|
||||
Commit string
|
||||
Dirty bool
|
||||
}
|
||||
|
||||
// GetVersion reads builtime vars and returns a full string containing info about
|
||||
// the currently running version of the software. Primarily used by the
|
||||
// --version flag at runtime.
|
||||
func GetVersion() string {
|
||||
|
||||
// TODO @shipperizer see if it's worth replacing with info.Main.Path
|
||||
// aka github.com/glauth/glauth/v2 - not great but worth checking
|
||||
|
||||
name := "GLauth"
|
||||
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
|
||||
if !ok {
|
||||
return fmt.Sprintf(`
|
||||
%s
|
||||
Non-release build`,
|
||||
name)
|
||||
}
|
||||
|
||||
gitInfo := vcsInfo(info.Settings)
|
||||
|
||||
// If a release, use the tag
|
||||
if !gitInfo.Dirty {
|
||||
return fmt.Sprintf(`%s %s
|
||||
Build time: %s
|
||||
Commit: %s`, name, Version, gitInfo.BuildTime, gitInfo.Commit)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`%s
|
||||
Non-release build based on tag %s
|
||||
Build time: %s
|
||||
Commit: %s`, name, Version, gitInfo.BuildTime, gitInfo.Commit)
|
||||
|
||||
}
|
||||
|
||||
func vcsInfo(settings []debug.BuildSetting) *gitInfo {
|
||||
info := new(gitInfo)
|
||||
|
||||
info.BuildTime = "unknown"
|
||||
info.Commit = "unknown"
|
||||
info.Dirty = false
|
||||
|
||||
for _, v := range settings {
|
||||
switch v.Key {
|
||||
case "vcs.revision":
|
||||
info.Commit = v.Value
|
||||
case "vcs.modified":
|
||||
info.Dirty = v.Value == "true"
|
||||
case "vcs.time":
|
||||
info.BuildTime = v.Value
|
||||
}
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 e5ffe9fd
|
||||
dn: cn=config
|
||||
objectClass: olcGlobal
|
||||
cn: config
|
||||
olcArgsFile: /var/run/slapd/slapd.args
|
||||
olcLogLevel: none
|
||||
olcPidFile: /var/run/slapd/slapd.pid
|
||||
olcToolThreads: 1
|
||||
structuralObjectClass: olcGlobal
|
||||
entryUUID: 5c21e0e8-7ddc-103b-9ebb-c740e015b81b
|
||||
creatorsName: cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
olcTLSCipherSuite: SECURE256:+SECURE128:-VERS-TLS-ALL:+VERS-TLS1.2:-RSA:-DHE
|
||||
-DSS:-CAMELLIA-128-CBC:-CAMELLIA-256-CBC
|
||||
olcTLSCACertificateFile: /container/service/slapd/assets/certs/ca.crt
|
||||
olcTLSCertificateFile: /container/service/slapd/assets/certs/ldap.crt
|
||||
olcTLSCertificateKeyFile: /container/service/slapd/assets/certs/ldap.key
|
||||
olcTLSDHParamFile: /container/service/slapd/assets/certs/dhparam.pem
|
||||
olcTLSVerifyClient: demand
|
||||
entryCSN: 20210812002157.868917Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210812002157Z
|
||||
@@ -0,0 +1,16 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 2aabc521
|
||||
dn: cn=module{0}
|
||||
objectClass: olcModuleList
|
||||
cn: module{0}
|
||||
olcModulePath: /usr/lib/ldap
|
||||
olcModuleLoad: {0}back_mdb
|
||||
olcModuleLoad: {1}memberof
|
||||
olcModuleLoad: {2}refint
|
||||
structuralObjectClass: olcModuleList
|
||||
entryUUID: 5c2b1fb4-7ddc-103b-9ec3-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.856380Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,12 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 bc37faae
|
||||
dn: cn=schema
|
||||
objectClass: olcSchemaConfig
|
||||
cn: schema
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c2570a0-7ddc-103b-9ebe-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.316331Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,249 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 57d21f8c
|
||||
dn: cn={0}core
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {0}core
|
||||
olcAttributeTypes: {0}( 2.5.4.2 NAME 'knowledgeInformation' DESC 'RFC2256: k
|
||||
nowledge information' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.15{32768} )
|
||||
olcAttributeTypes: {1}( 2.5.4.4 NAME ( 'sn' 'surname' ) DESC 'RFC2256: last
|
||||
(family) name(s) for which the entity is known by' SUP name )
|
||||
olcAttributeTypes: {2}( 2.5.4.5 NAME 'serialNumber' DESC 'RFC2256: serial nu
|
||||
mber of the entity' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{64} )
|
||||
olcAttributeTypes: {3}( 2.5.4.6 NAME ( 'c' 'countryName' ) DESC 'RFC4519: tw
|
||||
o-letter ISO-3166 country code' SUP name SYNTAX 1.3.6.1.4.1.1466.115.121.1.
|
||||
11 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 2.5.4.7 NAME ( 'l' 'localityName' ) DESC 'RFC2256: l
|
||||
ocality which this object resides in' SUP name )
|
||||
olcAttributeTypes: {5}( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' ) DESC 'RF
|
||||
C2256: state or province which this object resides in' SUP name )
|
||||
olcAttributeTypes: {6}( 2.5.4.9 NAME ( 'street' 'streetAddress' ) DESC 'RFC2
|
||||
256: street address of this object' EQUALITY caseIgnoreMatch SUBSTR caseIgn
|
||||
oreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {7}( 2.5.4.10 NAME ( 'o' 'organizationName' ) DESC 'RFC22
|
||||
56: organization this object belongs to' SUP name )
|
||||
olcAttributeTypes: {8}( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' ) DESC
|
||||
'RFC2256: organizational unit this object belongs to' SUP name )
|
||||
olcAttributeTypes: {9}( 2.5.4.12 NAME 'title' DESC 'RFC2256: title associate
|
||||
d with the entity' SUP name )
|
||||
olcAttributeTypes: {10}( 2.5.4.14 NAME 'searchGuide' DESC 'RFC2256: search g
|
||||
uide, deprecated by enhancedSearchGuide' SYNTAX 1.3.6.1.4.1.1466.115.121.1.
|
||||
25 )
|
||||
olcAttributeTypes: {11}( 2.5.4.15 NAME 'businessCategory' DESC 'RFC2256: bus
|
||||
iness category' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch S
|
||||
YNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {12}( 2.5.4.16 NAME 'postalAddress' DESC 'RFC2256: postal
|
||||
address' EQUALITY caseIgnoreListMatch SUBSTR caseIgnoreListSubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
|
||||
olcAttributeTypes: {13}( 2.5.4.17 NAME 'postalCode' DESC 'RFC2256: postal co
|
||||
de' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.15{40} )
|
||||
olcAttributeTypes: {14}( 2.5.4.18 NAME 'postOfficeBox' DESC 'RFC2256: Post O
|
||||
ffice Box' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX
|
||||
1.3.6.1.4.1.1466.115.121.1.15{40} )
|
||||
olcAttributeTypes: {15}( 2.5.4.19 NAME 'physicalDeliveryOfficeName' DESC 'RF
|
||||
C2256: Physical Delivery Office Name' EQUALITY caseIgnoreMatch SUBSTR caseI
|
||||
gnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {16}( 2.5.4.20 NAME 'telephoneNumber' DESC 'RFC2256: Tele
|
||||
phone Number' EQUALITY telephoneNumberMatch SUBSTR telephoneNumberSubstring
|
||||
sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
|
||||
olcAttributeTypes: {17}( 2.5.4.21 NAME 'telexNumber' DESC 'RFC2256: Telex Nu
|
||||
mber' SYNTAX 1.3.6.1.4.1.1466.115.121.1.52 )
|
||||
olcAttributeTypes: {18}( 2.5.4.22 NAME 'teletexTerminalIdentifier' DESC 'RFC
|
||||
2256: Teletex Terminal Identifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.51 )
|
||||
olcAttributeTypes: {19}( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' )
|
||||
DESC 'RFC2256: Facsimile (Fax) Telephone Number' SYNTAX 1.3.6.1.4.1.1466.11
|
||||
5.121.1.22 )
|
||||
olcAttributeTypes: {20}( 2.5.4.24 NAME 'x121Address' DESC 'RFC2256: X.121 Ad
|
||||
dress' EQUALITY numericStringMatch SUBSTR numericStringSubstringsMatch SYNT
|
||||
AX 1.3.6.1.4.1.1466.115.121.1.36{15} )
|
||||
olcAttributeTypes: {21}( 2.5.4.25 NAME 'internationaliSDNNumber' DESC 'RFC22
|
||||
56: international ISDN number' EQUALITY numericStringMatch SUBSTR numericSt
|
||||
ringSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.36{16} )
|
||||
olcAttributeTypes: {22}( 2.5.4.26 NAME 'registeredAddress' DESC 'RFC2256: re
|
||||
gistered postal address' SUP postalAddress SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.41 )
|
||||
olcAttributeTypes: {23}( 2.5.4.27 NAME 'destinationIndicator' DESC 'RFC2256:
|
||||
destination indicator' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstring
|
||||
sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44{128} )
|
||||
olcAttributeTypes: {24}( 2.5.4.28 NAME 'preferredDeliveryMethod' DESC 'RFC22
|
||||
56: preferred delivery method' SYNTAX 1.3.6.1.4.1.1466.115.121.1.14 SINGLE-
|
||||
VALUE )
|
||||
olcAttributeTypes: {25}( 2.5.4.29 NAME 'presentationAddress' DESC 'RFC2256:
|
||||
presentation address' EQUALITY presentationAddressMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.43 SINGLE-VALUE )
|
||||
olcAttributeTypes: {26}( 2.5.4.30 NAME 'supportedApplicationContext' DESC 'R
|
||||
FC2256: supported application context' EQUALITY objectIdentifierMatch SYNTA
|
||||
X 1.3.6.1.4.1.1466.115.121.1.38 )
|
||||
olcAttributeTypes: {27}( 2.5.4.31 NAME 'member' DESC 'RFC2256: member of a g
|
||||
roup' SUP distinguishedName )
|
||||
olcAttributeTypes: {28}( 2.5.4.32 NAME 'owner' DESC 'RFC2256: owner (of the
|
||||
object)' SUP distinguishedName )
|
||||
olcAttributeTypes: {29}( 2.5.4.33 NAME 'roleOccupant' DESC 'RFC2256: occupan
|
||||
t of role' SUP distinguishedName )
|
||||
olcAttributeTypes: {30}( 2.5.4.36 NAME 'userCertificate' DESC 'RFC2256: X.50
|
||||
9 user certificate, use ;binary' EQUALITY certificateExactMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.8 )
|
||||
olcAttributeTypes: {31}( 2.5.4.37 NAME 'cACertificate' DESC 'RFC2256: X.509
|
||||
CA certificate, use ;binary' EQUALITY certificateExactMatch SYNTAX 1.3.6.1.
|
||||
4.1.1466.115.121.1.8 )
|
||||
olcAttributeTypes: {32}( 2.5.4.38 NAME 'authorityRevocationList' DESC 'RFC22
|
||||
56: X.509 authority revocation list, use ;binary' SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.9 )
|
||||
olcAttributeTypes: {33}( 2.5.4.39 NAME 'certificateRevocationList' DESC 'RFC
|
||||
2256: X.509 certificate revocation list, use ;binary' SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.9 )
|
||||
olcAttributeTypes: {34}( 2.5.4.40 NAME 'crossCertificatePair' DESC 'RFC2256:
|
||||
X.509 cross certificate pair, use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121
|
||||
.1.10 )
|
||||
olcAttributeTypes: {35}( 2.5.4.42 NAME ( 'givenName' 'gn' ) DESC 'RFC2256: f
|
||||
irst name(s) for which the entity is known by' SUP name )
|
||||
olcAttributeTypes: {36}( 2.5.4.43 NAME 'initials' DESC 'RFC2256: initials of
|
||||
some or all of names, but not the surname(s).' SUP name )
|
||||
olcAttributeTypes: {37}( 2.5.4.44 NAME 'generationQualifier' DESC 'RFC2256:
|
||||
name qualifier indicating a generation' SUP name )
|
||||
olcAttributeTypes: {38}( 2.5.4.45 NAME 'x500UniqueIdentifier' DESC 'RFC2256:
|
||||
X.500 unique identifier' EQUALITY bitStringMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.6 )
|
||||
olcAttributeTypes: {39}( 2.5.4.46 NAME 'dnQualifier' DESC 'RFC2256: DN quali
|
||||
fier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR case
|
||||
IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
|
||||
olcAttributeTypes: {40}( 2.5.4.47 NAME 'enhancedSearchGuide' DESC 'RFC2256:
|
||||
enhanced search guide' SYNTAX 1.3.6.1.4.1.1466.115.121.1.21 )
|
||||
olcAttributeTypes: {41}( 2.5.4.48 NAME 'protocolInformation' DESC 'RFC2256:
|
||||
protocol information' EQUALITY protocolInformationMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.42 )
|
||||
olcAttributeTypes: {42}( 2.5.4.50 NAME 'uniqueMember' DESC 'RFC2256: unique
|
||||
member of a group' EQUALITY uniqueMemberMatch SYNTAX 1.3.6.1.4.1.1466.115.1
|
||||
21.1.34 )
|
||||
olcAttributeTypes: {43}( 2.5.4.51 NAME 'houseIdentifier' DESC 'RFC2256: hous
|
||||
e identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYN
|
||||
TAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
|
||||
olcAttributeTypes: {44}( 2.5.4.52 NAME 'supportedAlgorithms' DESC 'RFC2256:
|
||||
supported algorithms' SYNTAX 1.3.6.1.4.1.1466.115.121.1.49 )
|
||||
olcAttributeTypes: {45}( 2.5.4.53 NAME 'deltaRevocationList' DESC 'RFC2256:
|
||||
delta revocation list; use ;binary' SYNTAX 1.3.6.1.4.1.1466.115.121.1.9 )
|
||||
olcAttributeTypes: {46}( 2.5.4.54 NAME 'dmdName' DESC 'RFC2256: name of DMD'
|
||||
SUP name )
|
||||
olcAttributeTypes: {47}( 2.5.4.65 NAME 'pseudonym' DESC 'X.520(4th): pseudon
|
||||
ym for the object' SUP name )
|
||||
olcAttributeTypes: {48}( 0.9.2342.19200300.100.1.3 NAME ( 'mail' 'rfc822Mail
|
||||
box' ) DESC 'RFC1274: RFC822 Mailbox' EQUALITY caseIgnoreIA5Match SUBST
|
||||
R caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
|
||||
)
|
||||
olcAttributeTypes: {49}( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domainCompo
|
||||
nent' ) DESC 'RFC1274/2247: domain component' EQUALITY caseIgnoreIA5Match S
|
||||
UBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SIN
|
||||
GLE-VALUE )
|
||||
olcAttributeTypes: {50}( 0.9.2342.19200300.100.1.37 NAME 'associatedDomain'
|
||||
DESC 'RFC1274: domain associated with object' EQUALITY caseIgnoreIA5Match S
|
||||
UBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {51}( 1.2.840.113549.1.9.1 NAME ( 'email' 'emailAddress'
|
||||
'pkcs9email' ) DESC 'RFC3280: legacy attribute for email addresses in DNs'
|
||||
EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.26{128} )
|
||||
olcObjectClasses: {0}( 2.5.6.2 NAME 'country' DESC 'RFC2256: a country' SUP
|
||||
top STRUCTURAL MUST c MAY ( searchGuide $ description ) )
|
||||
olcObjectClasses: {1}( 2.5.6.3 NAME 'locality' DESC 'RFC2256: a locality' SU
|
||||
P top STRUCTURAL MAY ( street $ seeAlso $ searchGuide $ st $ l $ descriptio
|
||||
n ) )
|
||||
olcObjectClasses: {2}( 2.5.6.4 NAME 'organization' DESC 'RFC2256: an organiz
|
||||
ation' SUP top STRUCTURAL MUST o MAY ( userPassword $ searchGuide $ seeAlso
|
||||
$ businessCategory $ x121Address $ registeredAddress $ destinationIndicato
|
||||
r $ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $ tel
|
||||
ephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $ street
|
||||
$ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName
|
||||
$ st $ l $ description ) )
|
||||
olcObjectClasses: {3}( 2.5.6.5 NAME 'organizationalUnit' DESC 'RFC2256: an o
|
||||
rganizational unit' SUP top STRUCTURAL MUST ou MAY ( userPassword $ searchG
|
||||
uide $ seeAlso $ businessCategory $ x121Address $ registeredAddress $ desti
|
||||
nationIndicator $ preferredDeliveryMethod $ telexNumber $ teletexTerminalId
|
||||
entifier $ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNu
|
||||
mber $ street $ postOfficeBox $ postalCode $ postalAddress $ physicalDelive
|
||||
ryOfficeName $ st $ l $ description ) )
|
||||
olcObjectClasses: {4}( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP to
|
||||
p STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAls
|
||||
o $ description ) )
|
||||
olcObjectClasses: {5}( 2.5.6.7 NAME 'organizationalPerson' DESC 'RFC2256: an
|
||||
organizational person' SUP person STRUCTURAL MAY ( title $ x121Address $ r
|
||||
egisteredAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNu
|
||||
mber $ teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumbe
|
||||
r $ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $ posta
|
||||
lAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
|
||||
olcObjectClasses: {6}( 2.5.6.8 NAME 'organizationalRole' DESC 'RFC2256: an o
|
||||
rganizational role' SUP top STRUCTURAL MUST cn MAY ( x121Address $ register
|
||||
edAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNumber $
|
||||
teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $ fac
|
||||
simileTelephoneNumber $ seeAlso $ roleOccupant $ preferredDeliveryMethod $
|
||||
street $ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOffic
|
||||
eName $ ou $ st $ l $ description ) )
|
||||
olcObjectClasses: {7}( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of
|
||||
names (DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategor
|
||||
y $ seeAlso $ owner $ ou $ o $ description ) )
|
||||
olcObjectClasses: {8}( 2.5.6.10 NAME 'residentialPerson' DESC 'RFC2256: an r
|
||||
esidential person' SUP person STRUCTURAL MUST l MAY ( businessCategory $ x1
|
||||
21Address $ registeredAddress $ destinationIndicator $ preferredDeliveryMet
|
||||
hod $ telexNumber $ teletexTerminalIdentifier $ telephoneNumber $ internati
|
||||
onaliSDNNumber $ facsimileTelephoneNumber $ preferredDeliveryMethod $ stree
|
||||
t $ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName
|
||||
$ st $ l ) )
|
||||
olcObjectClasses: {9}( 2.5.6.11 NAME 'applicationProcess' DESC 'RFC2256: an
|
||||
application process' SUP top STRUCTURAL MUST cn MAY ( seeAlso $ ou $ l $ de
|
||||
scription ) )
|
||||
olcObjectClasses: {10}( 2.5.6.12 NAME 'applicationEntity' DESC 'RFC2256: an
|
||||
application entity' SUP top STRUCTURAL MUST ( presentationAddress $ cn ) MA
|
||||
Y ( supportedApplicationContext $ seeAlso $ ou $ o $ l $ description ) )
|
||||
olcObjectClasses: {11}( 2.5.6.13 NAME 'dSA' DESC 'RFC2256: a directory syste
|
||||
m agent (a server)' SUP applicationEntity STRUCTURAL MAY knowledgeInformati
|
||||
on )
|
||||
olcObjectClasses: {12}( 2.5.6.14 NAME 'device' DESC 'RFC2256: a device' SUP
|
||||
top STRUCTURAL MUST cn MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $
|
||||
description ) )
|
||||
olcObjectClasses: {13}( 2.5.6.15 NAME 'strongAuthenticationUser' DESC 'RFC22
|
||||
56: a strong authentication user' SUP top AUXILIARY MUST userCertificate )
|
||||
olcObjectClasses: {14}( 2.5.6.16 NAME 'certificationAuthority' DESC 'RFC2256
|
||||
: a certificate authority' SUP top AUXILIARY MUST ( authorityRevocationList
|
||||
$ certificateRevocationList $ cACertificate ) MAY crossCertificatePair )
|
||||
olcObjectClasses: {15}( 2.5.6.17 NAME 'groupOfUniqueNames' DESC 'RFC2256: a
|
||||
group of unique names (DN and Unique Identifier)' SUP top STRUCTURAL MUST (
|
||||
uniqueMember $ cn ) MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ de
|
||||
scription ) )
|
||||
olcObjectClasses: {16}( 2.5.6.18 NAME 'userSecurityInformation' DESC 'RFC225
|
||||
6: a user security information' SUP top AUXILIARY MAY ( supportedAlgorithms
|
||||
) )
|
||||
olcObjectClasses: {17}( 2.5.6.16.2 NAME 'certificationAuthority-V2' SUP cert
|
||||
ificationAuthority AUXILIARY MAY ( deltaRevocationList ) )
|
||||
olcObjectClasses: {18}( 2.5.6.19 NAME 'cRLDistributionPoint' SUP top STRUCTU
|
||||
RAL MUST ( cn ) MAY ( certificateRevocationList $ authorityRevocationList $
|
||||
deltaRevocationList ) )
|
||||
olcObjectClasses: {19}( 2.5.6.20 NAME 'dmd' SUP top STRUCTURAL MUST ( dmdNam
|
||||
e ) MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $ x121Add
|
||||
ress $ registeredAddress $ destinationIndicator $ preferredDeliveryMethod $
|
||||
telexNumber $ teletexTerminalIdentifier $ telephoneNumber $ internationali
|
||||
SDNNumber $ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode
|
||||
$ postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )
|
||||
olcObjectClasses: {20}( 2.5.6.21 NAME 'pkiUser' DESC 'RFC2587: a PKI user' S
|
||||
UP top AUXILIARY MAY userCertificate )
|
||||
olcObjectClasses: {21}( 2.5.6.22 NAME 'pkiCA' DESC 'RFC2587: PKI certificate
|
||||
authority' SUP top AUXILIARY MAY ( authorityRevocationList $ certificateRe
|
||||
vocationList $ cACertificate $ crossCertificatePair ) )
|
||||
olcObjectClasses: {22}( 2.5.6.23 NAME 'deltaCRL' DESC 'RFC2587: PKI user' SU
|
||||
P top AUXILIARY MAY deltaRevocationList )
|
||||
olcObjectClasses: {23}( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject' DESC 'R
|
||||
FC2079: object that contains the URI attribute type' MAY ( labeledURI ) SUP
|
||||
top AUXILIARY )
|
||||
olcObjectClasses: {24}( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObjec
|
||||
t' DESC 'RFC1274: simple security object' SUP top AUXILIARY MUST userPasswo
|
||||
rd )
|
||||
olcObjectClasses: {25}( 1.3.6.1.4.1.1466.344 NAME 'dcObject' DESC 'RFC2247:
|
||||
domain component object' SUP top AUXILIARY MUST dc )
|
||||
olcObjectClasses: {26}( 1.3.6.1.1.3.1 NAME 'uidObject' DESC 'RFC2377: uid ob
|
||||
ject' SUP top AUXILIARY MUST uid )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c26a290-7ddc-103b-9ebf-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.324162Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,178 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 3133677b
|
||||
dn: cn={1}cosine
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {1}cosine
|
||||
olcAttributeTypes: {0}( 0.9.2342.19200300.100.1.2 NAME 'textEncodedORAddress
|
||||
' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.
|
||||
4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {1}( 0.9.2342.19200300.100.1.4 NAME 'info' DESC 'RFC1274:
|
||||
general information' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{2048} )
|
||||
olcAttributeTypes: {2}( 0.9.2342.19200300.100.1.5 NAME ( 'drink' 'favouriteD
|
||||
rink' ) DESC 'RFC1274: favorite drink' EQUALITY caseIgnoreMatch SUBSTR case
|
||||
IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {3}( 0.9.2342.19200300.100.1.6 NAME 'roomNumber' DESC 'RF
|
||||
C1274: room number' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {4}( 0.9.2342.19200300.100.1.7 NAME 'photo' DESC 'RFC1274
|
||||
: photo (G3 fax)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.23{25000} )
|
||||
olcAttributeTypes: {5}( 0.9.2342.19200300.100.1.8 NAME 'userClass' DESC 'RFC
|
||||
1274: category of user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstring
|
||||
sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {6}( 0.9.2342.19200300.100.1.9 NAME 'host' DESC 'RFC1274:
|
||||
host computer' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch S
|
||||
YNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {7}( 0.9.2342.19200300.100.1.10 NAME 'manager' DESC 'RFC1
|
||||
274: DN of manager' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466
|
||||
.115.121.1.12 )
|
||||
olcAttributeTypes: {8}( 0.9.2342.19200300.100.1.11 NAME 'documentIdentifier'
|
||||
DESC 'RFC1274: unique identifier of document' EQUALITY caseIgnoreMatch SUB
|
||||
STR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {9}( 0.9.2342.19200300.100.1.12 NAME 'documentTitle' DESC
|
||||
'RFC1274: title of document' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSub
|
||||
stringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {10}( 0.9.2342.19200300.100.1.13 NAME 'documentVersion' D
|
||||
ESC 'RFC1274: version of document' EQUALITY caseIgnoreMatch SUBSTR caseIgno
|
||||
reSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {11}( 0.9.2342.19200300.100.1.14 NAME 'documentAuthor' DE
|
||||
SC 'RFC1274: DN of author of document' EQUALITY distinguishedNameMatch SYNT
|
||||
AX 1.3.6.1.4.1.1466.115.121.1.12 )
|
||||
olcAttributeTypes: {12}( 0.9.2342.19200300.100.1.15 NAME 'documentLocation'
|
||||
DESC 'RFC1274: location of document original' EQUALITY caseIgnoreMatch SUBS
|
||||
TR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {13}( 0.9.2342.19200300.100.1.20 NAME ( 'homePhone' 'home
|
||||
TelephoneNumber' ) DESC 'RFC1274: home telephone number' EQUALITY telephone
|
||||
NumberMatch SUBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.50 )
|
||||
olcAttributeTypes: {14}( 0.9.2342.19200300.100.1.21 NAME 'secretary' DESC 'R
|
||||
FC1274: DN of secretary' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1
|
||||
.1466.115.121.1.12 )
|
||||
olcAttributeTypes: {15}( 0.9.2342.19200300.100.1.22 NAME 'otherMailbox' SYNT
|
||||
AX 1.3.6.1.4.1.1466.115.121.1.39 )
|
||||
olcAttributeTypes: {16}( 0.9.2342.19200300.100.1.26 NAME 'aRecord' EQUALITY
|
||||
caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {17}( 0.9.2342.19200300.100.1.27 NAME 'mDRecord' EQUALITY
|
||||
caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {18}( 0.9.2342.19200300.100.1.28 NAME 'mXRecord' EQUALITY
|
||||
caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {19}( 0.9.2342.19200300.100.1.29 NAME 'nSRecord' EQUALITY
|
||||
caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {20}( 0.9.2342.19200300.100.1.30 NAME 'sOARecord' EQUALIT
|
||||
Y caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {21}( 0.9.2342.19200300.100.1.31 NAME 'cNAMERecord' EQUAL
|
||||
ITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {22}( 0.9.2342.19200300.100.1.38 NAME 'associatedName' DE
|
||||
SC 'RFC1274: DN of entry associated with domain' EQUALITY distinguishedName
|
||||
Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
|
||||
olcAttributeTypes: {23}( 0.9.2342.19200300.100.1.39 NAME 'homePostalAddress'
|
||||
DESC 'RFC1274: home postal address' EQUALITY caseIgnoreListMatch SUBSTR ca
|
||||
seIgnoreListSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )
|
||||
olcAttributeTypes: {24}( 0.9.2342.19200300.100.1.40 NAME 'personalTitle' DES
|
||||
C 'RFC1274: personal title' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubst
|
||||
ringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {25}( 0.9.2342.19200300.100.1.41 NAME ( 'mobile' 'mobileT
|
||||
elephoneNumber' ) DESC 'RFC1274: mobile telephone number' EQUALITY telephon
|
||||
eNumberMatch SUBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.
|
||||
115.121.1.50 )
|
||||
olcAttributeTypes: {26}( 0.9.2342.19200300.100.1.42 NAME ( 'pager' 'pagerTel
|
||||
ephoneNumber' ) DESC 'RFC1274: pager telephone number' EQUALITY telephoneNu
|
||||
mberMatch SUBSTR telephoneNumberSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115
|
||||
.121.1.50 )
|
||||
olcAttributeTypes: {27}( 0.9.2342.19200300.100.1.43 NAME ( 'co' 'friendlyCou
|
||||
ntryName' ) DESC 'RFC1274: friendly country name' EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {28}( 0.9.2342.19200300.100.1.44 NAME 'uniqueIdentifier'
|
||||
DESC 'RFC1274: unique identifer' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {29}( 0.9.2342.19200300.100.1.45 NAME 'organizationalStat
|
||||
us' DESC 'RFC1274: organizational status' EQUALITY caseIgnoreMatch SUBSTR c
|
||||
aseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {30}( 0.9.2342.19200300.100.1.46 NAME 'janetMailbox' DESC
|
||||
'RFC1274: Janet mailbox' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5S
|
||||
ubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
|
||||
olcAttributeTypes: {31}( 0.9.2342.19200300.100.1.47 NAME 'mailPreferenceOpti
|
||||
on' DESC 'RFC1274: mail preference option' SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.27 )
|
||||
olcAttributeTypes: {32}( 0.9.2342.19200300.100.1.48 NAME 'buildingName' DESC
|
||||
'RFC1274: name of building' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubs
|
||||
tringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {33}( 0.9.2342.19200300.100.1.49 NAME 'dSAQuality' DESC '
|
||||
RFC1274: DSA Quality' SYNTAX 1.3.6.1.4.1.1466.115.121.1.19 SINGLE-VALUE )
|
||||
olcAttributeTypes: {34}( 0.9.2342.19200300.100.1.50 NAME 'singleLevelQuality
|
||||
' DESC 'RFC1274: Single Level Quality' SYNTAX 1.3.6.1.4.1.1466.115.121.1.13
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {35}( 0.9.2342.19200300.100.1.51 NAME 'subtreeMinimumQual
|
||||
ity' DESC 'RFC1274: Subtree Mininum Quality' SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.13 SINGLE-VALUE )
|
||||
olcAttributeTypes: {36}( 0.9.2342.19200300.100.1.52 NAME 'subtreeMaximumQual
|
||||
ity' DESC 'RFC1274: Subtree Maximun Quality' SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.13 SINGLE-VALUE )
|
||||
olcAttributeTypes: {37}( 0.9.2342.19200300.100.1.53 NAME 'personalSignature'
|
||||
DESC 'RFC1274: Personal Signature (G3 fax)' SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.23 )
|
||||
olcAttributeTypes: {38}( 0.9.2342.19200300.100.1.54 NAME 'dITRedirect' DESC
|
||||
'RFC1274: DIT Redirect' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.12 )
|
||||
olcAttributeTypes: {39}( 0.9.2342.19200300.100.1.55 NAME 'audio' DESC 'RFC12
|
||||
74: audio (u-law)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.4{25000} )
|
||||
olcAttributeTypes: {40}( 0.9.2342.19200300.100.1.56 NAME 'documentPublisher'
|
||||
DESC 'RFC1274: publisher of document' EQUALITY caseIgnoreMatch SUBSTR case
|
||||
IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcObjectClasses: {0}( 0.9.2342.19200300.100.4.4 NAME ( 'pilotPerson' 'newPi
|
||||
lotPerson' ) SUP person STRUCTURAL MAY ( userid $ textEncodedORAddress $ rf
|
||||
c822Mailbox $ favouriteDrink $ roomNumber $ userClass $ homeTelephoneNumber
|
||||
$ homePostalAddress $ secretary $ personalTitle $ preferredDeliveryMethod
|
||||
$ businessCategory $ janetMailbox $ otherMailbox $ mobileTelephoneNumber $
|
||||
pagerTelephoneNumber $ organizationalStatus $ mailPreferenceOption $ person
|
||||
alSignature ) )
|
||||
olcObjectClasses: {1}( 0.9.2342.19200300.100.4.5 NAME 'account' SUP top STRU
|
||||
CTURAL MUST userid MAY ( description $ seeAlso $ localityName $ organizatio
|
||||
nName $ organizationalUnitName $ host ) )
|
||||
olcObjectClasses: {2}( 0.9.2342.19200300.100.4.6 NAME 'document' SUP top STR
|
||||
UCTURAL MUST documentIdentifier MAY ( commonName $ description $ seeAlso $
|
||||
localityName $ organizationName $ organizationalUnitName $ documentTitle $
|
||||
documentVersion $ documentAuthor $ documentLocation $ documentPublisher ) )
|
||||
olcObjectClasses: {3}( 0.9.2342.19200300.100.4.7 NAME 'room' SUP top STRUCTU
|
||||
RAL MUST commonName MAY ( roomNumber $ description $ seeAlso $ telephoneNum
|
||||
ber ) )
|
||||
olcObjectClasses: {4}( 0.9.2342.19200300.100.4.9 NAME 'documentSeries' SUP t
|
||||
op STRUCTURAL MUST commonName MAY ( description $ seeAlso $ telephonenumber
|
||||
$ localityName $ organizationName $ organizationalUnitName ) )
|
||||
olcObjectClasses: {5}( 0.9.2342.19200300.100.4.13 NAME 'domain' SUP top STRU
|
||||
CTURAL MUST domainComponent MAY ( associatedName $ organizationName $ descr
|
||||
iption $ businessCategory $ seeAlso $ searchGuide $ userPassword $ locality
|
||||
Name $ stateOrProvinceName $ streetAddress $ physicalDeliveryOfficeName $ p
|
||||
ostalAddress $ postalCode $ postOfficeBox $ streetAddress $ facsimileTeleph
|
||||
oneNumber $ internationalISDNNumber $ telephoneNumber $ teletexTerminalIden
|
||||
tifier $ telexNumber $ preferredDeliveryMethod $ destinationIndicator $ reg
|
||||
isteredAddress $ x121Address ) )
|
||||
olcObjectClasses: {6}( 0.9.2342.19200300.100.4.14 NAME 'RFC822localPart' SUP
|
||||
domain STRUCTURAL MAY ( commonName $ surname $ description $ seeAlso $ tel
|
||||
ephoneNumber $ physicalDeliveryOfficeName $ postalAddress $ postalCode $ po
|
||||
stOfficeBox $ streetAddress $ facsimileTelephoneNumber $ internationalISDNN
|
||||
umber $ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $ preferr
|
||||
edDeliveryMethod $ destinationIndicator $ registeredAddress $ x121Address )
|
||||
)
|
||||
olcObjectClasses: {7}( 0.9.2342.19200300.100.4.15 NAME 'dNSDomain' SUP domai
|
||||
n STRUCTURAL MAY ( ARecord $ MDRecord $ MXRecord $ NSRecord $ SOARecord $ C
|
||||
NAMERecord ) )
|
||||
olcObjectClasses: {8}( 0.9.2342.19200300.100.4.17 NAME 'domainRelatedObject'
|
||||
DESC 'RFC1274: an object related to an domain' SUP top AUXILIARY MUST asso
|
||||
ciatedDomain )
|
||||
olcObjectClasses: {9}( 0.9.2342.19200300.100.4.18 NAME 'friendlyCountry' SUP
|
||||
country STRUCTURAL MUST friendlyCountryName )
|
||||
olcObjectClasses: {10}( 0.9.2342.19200300.100.4.20 NAME 'pilotOrganization'
|
||||
SUP ( organization $ organizationalUnit ) STRUCTURAL MAY buildingName )
|
||||
olcObjectClasses: {11}( 0.9.2342.19200300.100.4.21 NAME 'pilotDSA' SUP dsa S
|
||||
TRUCTURAL MAY dSAQuality )
|
||||
olcObjectClasses: {12}( 0.9.2342.19200300.100.4.22 NAME 'qualityLabelledData
|
||||
' SUP top AUXILIARY MUST dsaQuality MAY ( subtreeMinimumQuality $ subtreeMa
|
||||
ximumQuality ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c286ac6-7ddc-103b-9ec0-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.335841Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,108 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 8c7d43da
|
||||
dn: cn={2}nis
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {2}nis
|
||||
olcAttributeTypes: {0}( 1.3.6.1.1.1.1.2 NAME 'gecos' DESC 'The GECOS field;
|
||||
the common name' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5Substrings
|
||||
Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.1.1.1.3 NAME 'homeDirectory' DESC 'The absol
|
||||
ute path to the home directory' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.1.1.1.4 NAME 'loginShell' DESC 'The path to
|
||||
the login shell' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121
|
||||
.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange' EQUALITY int
|
||||
egerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.1.1.1.6 NAME 'shadowMin' EQUALITY integerMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.1.1.1.7 NAME 'shadowMax' EQUALITY integerMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.1.1.1.8 NAME 'shadowWarning' EQUALITY intege
|
||||
rMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.1.1.1.9 NAME 'shadowInactive' EQUALITY integ
|
||||
erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.1.1.1.10 NAME 'shadowExpire' EQUALITY intege
|
||||
rMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.1.1.1.11 NAME 'shadowFlag' EQUALITY integerM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {10}( 1.3.6.1.1.1.1.12 NAME 'memberUid' EQUALITY caseExac
|
||||
tIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.26 )
|
||||
olcAttributeTypes: {11}( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup' EQUALITY
|
||||
caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.146
|
||||
6.115.121.1.26 )
|
||||
olcAttributeTypes: {12}( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple' DESC 'Net
|
||||
group triple' SYNTAX 1.3.6.1.1.1.0.0 )
|
||||
olcAttributeTypes: {13}( 1.3.6.1.1.1.1.15 NAME 'ipServicePort' EQUALITY inte
|
||||
gerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {14}( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol' SUP name
|
||||
)
|
||||
olcAttributeTypes: {15}( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber' EQUALITY i
|
||||
ntegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {16}( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber' EQUALITY integ
|
||||
erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {17}( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber' DESC 'IP addre
|
||||
ss' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
|
||||
olcAttributeTypes: {18}( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber' DESC 'IP ne
|
||||
twork' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128
|
||||
} SINGLE-VALUE )
|
||||
olcAttributeTypes: {19}( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber' DESC 'IP ne
|
||||
tmask' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128
|
||||
} SINGLE-VALUE )
|
||||
olcAttributeTypes: {20}( 1.3.6.1.1.1.1.22 NAME 'macAddress' DESC 'MAC addres
|
||||
s' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
|
||||
olcAttributeTypes: {21}( 1.3.6.1.1.1.1.23 NAME 'bootParameter' DESC 'rpc.boo
|
||||
tparamd parameter' SYNTAX 1.3.6.1.1.1.0.1 )
|
||||
olcAttributeTypes: {22}( 1.3.6.1.1.1.1.24 NAME 'bootFile' DESC 'Boot image n
|
||||
ame' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {23}( 1.3.6.1.1.1.1.26 NAME 'nisMapName' SUP name )
|
||||
olcAttributeTypes: {24}( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry' EQUALITY caseEx
|
||||
actIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.26{1024} SINGLE-VALUE )
|
||||
olcObjectClasses: {0}( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction
|
||||
of an account with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ u
|
||||
idNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ ge
|
||||
cos $ description ) )
|
||||
olcObjectClasses: {1}( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' DESC 'Additional
|
||||
attributes for shadow passwords' SUP top AUXILIARY MUST uid MAY ( userPass
|
||||
word $ shadowLastChange $ shadowMin $ shadowMax $ shadowWarning $ shadowIna
|
||||
ctive $ shadowExpire $ shadowFlag $ description ) )
|
||||
olcObjectClasses: {2}( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction o
|
||||
f a group of accounts' SUP top STRUCTURAL MUST ( cn $ gidNumber ) MAY ( use
|
||||
rPassword $ memberUid $ description ) )
|
||||
olcObjectClasses: {3}( 1.3.6.1.1.1.2.3 NAME 'ipService' DESC 'Abstraction an
|
||||
Internet Protocol service' SUP top STRUCTURAL MUST ( cn $ ipServicePort $
|
||||
ipServiceProtocol ) MAY description )
|
||||
olcObjectClasses: {4}( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' DESC 'Abstraction o
|
||||
f an IP protocol' SUP top STRUCTURAL MUST ( cn $ ipProtocolNumber $ descrip
|
||||
tion ) MAY description )
|
||||
olcObjectClasses: {5}( 1.3.6.1.1.1.2.5 NAME 'oncRpc' DESC 'Abstraction of an
|
||||
ONC/RPC binding' SUP top STRUCTURAL MUST ( cn $ oncRpcNumber $ description
|
||||
) MAY description )
|
||||
olcObjectClasses: {6}( 1.3.6.1.1.1.2.6 NAME 'ipHost' DESC 'Abstraction of a
|
||||
host, an IP device' SUP top AUXILIARY MUST ( cn $ ipHostNumber ) MAY ( l $
|
||||
description $ manager ) )
|
||||
olcObjectClasses: {7}( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' DESC 'Abstraction of
|
||||
an IP network' SUP top STRUCTURAL MUST ( cn $ ipNetworkNumber ) MAY ( ipNe
|
||||
tmaskNumber $ l $ description $ manager ) )
|
||||
olcObjectClasses: {8}( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' DESC 'Abstraction
|
||||
of a netgroup' SUP top STRUCTURAL MUST cn MAY ( nisNetgroupTriple $ memberN
|
||||
isNetgroup $ description ) )
|
||||
olcObjectClasses: {9}( 1.3.6.1.1.1.2.9 NAME 'nisMap' DESC 'A generic abstrac
|
||||
tion of a NIS map' SUP top STRUCTURAL MUST nisMapName MAY description )
|
||||
olcObjectClasses: {10}( 1.3.6.1.1.1.2.10 NAME 'nisObject' DESC 'An entry in
|
||||
a NIS map' SUP top STRUCTURAL MUST ( cn $ nisMapEntry $ nisMapName ) MAY de
|
||||
scription )
|
||||
olcObjectClasses: {11}( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' DESC 'A device
|
||||
with a MAC address' SUP top AUXILIARY MAY macAddress )
|
||||
olcObjectClasses: {12}( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' DESC 'A devic
|
||||
e with boot parameters' SUP top AUXILIARY MAY ( bootFile $ bootParameter )
|
||||
)
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c2966ce-7ddc-103b-9ec1-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.342294Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,49 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 b409a0c2
|
||||
dn: cn={3}inetorgperson
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {3}inetorgperson
|
||||
olcAttributeTypes: {0}( 2.16.840.1.113730.3.1.1 NAME 'carLicense' DESC 'RFC2
|
||||
798: vehicle license or registration plate' EQUALITY caseIgnoreMatch SUBSTR
|
||||
caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {1}( 2.16.840.1.113730.3.1.2 NAME 'departmentNumber' DESC
|
||||
'RFC2798: identifies a department within an organization' EQUALITY caseIgn
|
||||
oreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
|
||||
.15 )
|
||||
olcAttributeTypes: {2}( 2.16.840.1.113730.3.1.241 NAME 'displayName' DESC 'R
|
||||
FC2798: preferred name to be used when displaying entries' EQUALITY caseIgn
|
||||
oreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
|
||||
.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 2.16.840.1.113730.3.1.3 NAME 'employeeNumber' DESC '
|
||||
RFC2798: numerically identifies an employee within an organization' EQUALIT
|
||||
Y caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.
|
||||
115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 2.16.840.1.113730.3.1.4 NAME 'employeeType' DESC 'RF
|
||||
C2798: type of employment for a person' EQUALITY caseIgnoreMatch SUBSTR cas
|
||||
eIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {5}( 0.9.2342.19200300.100.1.60 NAME 'jpegPhoto' DESC 'RF
|
||||
C2798: a JPEG image' SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 )
|
||||
olcAttributeTypes: {6}( 2.16.840.1.113730.3.1.39 NAME 'preferredLanguage' DE
|
||||
SC 'RFC2798: preferred written or spoken language for a person' EQUALITY ca
|
||||
seIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 2.16.840.1.113730.3.1.40 NAME 'userSMIMECertificate'
|
||||
DESC 'RFC2798: PKCS#7 SignedData used to support S/MIME' SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.5 )
|
||||
olcAttributeTypes: {8}( 2.16.840.1.113730.3.1.216 NAME 'userPKCS12' DESC 'RF
|
||||
C2798: personal identity information, a PKCS #12 PFX' SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.5 )
|
||||
olcObjectClasses: {0}( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'RF
|
||||
C2798: Internet Organizational Person' SUP organizationalPerson STRUCTURAL
|
||||
MAY ( audio $ businessCategory $ carLicense $ departmentNumber $ displayNam
|
||||
e $ employeeNumber $ employeeType $ givenName $ homePhone $ homePostalAddre
|
||||
ss $ initials $ jpegPhoto $ labeledURI $ mail $ manager $ mobile $ o $ page
|
||||
r $ photo $ roomNumber $ secretary $ uid $ userCertificate $ x500uniqueIden
|
||||
tifier $ preferredLanguage $ userSMIMECertificate $ userPKCS12 ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c2a5016-7ddc-103b-9ec2-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.348266Z#000000#000#000000
|
||||
modifiersName: cn=admin,cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,65 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 cded21ef
|
||||
dn: cn={4}ppolicy
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {4}ppolicy
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.42.2.27.8.1.1 NAME 'pwdAttribute' EQUALI
|
||||
TY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.4.1.42.2.27.8.1.2 NAME 'pwdMinAge' EQUALITY
|
||||
integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.4.1.42.2.27.8.1.3 NAME 'pwdMaxAge' EQUALITY
|
||||
integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.4.1.42.2.27.8.1.4 NAME 'pwdInHistory' EQUALI
|
||||
TY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.1
|
||||
21.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.4.1.42.2.27.8.1.5 NAME 'pwdCheckQuality' EQU
|
||||
ALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.11
|
||||
5.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.4.1.42.2.27.8.1.6 NAME 'pwdMinLength' EQUALI
|
||||
TY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.4.1.42.2.27.8.1.7 NAME 'pwdExpireWarning' EQ
|
||||
UALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.
|
||||
115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.4.1.42.2.27.8.1.8 NAME 'pwdGraceAuthNLimit'
|
||||
EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.146
|
||||
6.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.4.1.42.2.27.8.1.9 NAME 'pwdLockout' EQUALITY
|
||||
booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.4.1.42.2.27.8.1.10 NAME 'pwdLockoutDuration'
|
||||
EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {10}( 1.3.6.1.4.1.42.2.27.8.1.11 NAME 'pwdMaxFailure' EQU
|
||||
ALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {11}( 1.3.6.1.4.1.42.2.27.8.1.12 NAME 'pwdFailureCountInt
|
||||
erval' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.
|
||||
4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {12}( 1.3.6.1.4.1.42.2.27.8.1.13 NAME 'pwdMustChange' EQU
|
||||
ALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {13}( 1.3.6.1.4.1.42.2.27.8.1.14 NAME 'pwdAllowUserChange
|
||||
' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {14}( 1.3.6.1.4.1.42.2.27.8.1.15 NAME 'pwdSafeModify' EQU
|
||||
ALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {15}( 1.3.6.1.4.1.4754.1.99.1 NAME 'pwdCheckModule' DESC
|
||||
'Loadable module that instantiates "check_password() function' EQUALITY cas
|
||||
eExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {16}( 1.3.6.1.4.1.42.2.27.8.1.30 NAME 'pwdMaxRecordedFail
|
||||
ure' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.4754.2.99.1 NAME 'pwdPolicyChecker' SUP t
|
||||
op AUXILIARY MAY pwdCheckModule )
|
||||
olcObjectClasses: {1}( 1.3.6.1.4.1.42.2.27.8.2.1 NAME 'pwdPolicy' SUP top AU
|
||||
XILIARY MUST pwdAttribute MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdC
|
||||
heckQuality $ pwdMinLength $ pwdExpireWarning $ pwdGraceAuthNLimit $ pwdLoc
|
||||
kout $ pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $ pwdMu
|
||||
stChange $ pwdAllowUserChange $ pwdSafeModify $ pwdMaxRecordedFailure ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c51364a-7ddc-103b-8d41-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.603187Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,175 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 7d21399c
|
||||
dn: cn={5}kopano
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {5}kopano
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.47732.1.1.1.1 NAME 'kopanoQuotaOverride'
|
||||
DESC 'KOPANO: Override child quota' EQUALITY integerMatch SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.4.1.47732.1.1.1.2 NAME 'kopanoQuotaWarn' DES
|
||||
C 'KOPANO: Warning quota size in MB' EQUALITY integerMatch SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.4.1.47732.1.1.1.3 NAME 'kopanoQuotaSoft' DES
|
||||
C 'KOPANO: Soft quota size in MB' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.4.1.47732.1.1.1.4 NAME 'kopanoQuotaHard' DES
|
||||
C 'KOPANO: Hard quota size in MB' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.4.1.47732.1.1.1.5 NAME 'kopanoUserDefaultQuo
|
||||
taOverride' DESC 'KOPANO: Override User default quota for children' EQUALIT
|
||||
Y integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.4.1.47732.1.1.1.6 NAME 'kopanoUserDefaultQuo
|
||||
taWarn' DESC 'KOPANO: User default warning quota size in MB' EQUALITY integ
|
||||
erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.4.1.47732.1.1.1.7 NAME 'kopanoUserDefaultQuo
|
||||
taSoft' DESC 'KOPANO: User default soft quota size in MB' EQUALITY integerM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.4.1.47732.1.1.1.8 NAME 'kopanoUserDefaultQuo
|
||||
taHard' DESC 'KOPANO: User default hard quota size in MB' EQUALITY integerM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.4.1.47732.1.1.2.1 NAME 'kopanoAdmin' DESC 'K
|
||||
OPANO: Administrator of kopano' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.4.1.47732.1.1.2.2 NAME 'kopanoSharedStoreOnl
|
||||
y' DESC 'KOPANO: is store a shared store' EQUALITY integerMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {10}( 1.3.6.1.4.1.47732.1.1.2.3 NAME 'kopanoAccount' DESC
|
||||
'KOPANO: entry is a part of kopano' EQUALITY integerMatch SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {11}( 1.3.6.1.4.1.47732.1.1.2.4 NAME 'kopanoSendAsPrivile
|
||||
ge' DESC 'KOPANO: Users may directly send email as this user' EQUALITY case
|
||||
IgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.15 )
|
||||
olcAttributeTypes: {12}( 1.3.6.1.4.1.47732.1.1.2.5 NAME 'kopanoMrAccept' DES
|
||||
C 'KOPANO: user should auto-accept meeting requests' EQUALITY integerMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {13}( 1.3.6.1.4.1.47732.1.1.2.6 NAME 'kopanoMrDeclineConf
|
||||
lict' DESC 'KOPANO: user should automatically decline conflicting meeting r
|
||||
equests' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-
|
||||
VALUE )
|
||||
olcAttributeTypes: {14}( 1.3.6.1.4.1.47732.1.1.2.7 NAME 'kopanoMrDeclineRecu
|
||||
rring' DESC 'KOPANO: user should automatically decline recurring meeting re
|
||||
quests' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-V
|
||||
ALUE )
|
||||
olcAttributeTypes: {15}( 1.3.6.1.4.1.47732.1.1.2.8 NAME 'kopanoId' DESC 'KOP
|
||||
ANO: Generic unique ID' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.40 SINGLE-VALUE )
|
||||
olcAttributeTypes: {16}( 1.3.6.1.4.1.47732.1.1.2.9 NAME 'kopanoResourceType'
|
||||
DESC 'KOPANO: for shared stores, resource is type Room or Equipment' EQUAL
|
||||
ITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.146
|
||||
6.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {17}( 1.3.6.1.4.1.47732.1.1.2.10 NAME 'kopanoResourceCapa
|
||||
city' DESC 'KOPANO: number of rooms or equipment available' EQUALITY intege
|
||||
rMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {18}( 1.3.6.1.4.1.47732.1.1.2.11 NAME 'kopanoHidden' DESC
|
||||
'KOPANO: This object should be hidden from address book' EQUALITY integerM
|
||||
atch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {19}( 1.3.6.1.4.1.47732.1.1.2.13 NAME 'kopanoEnabledFeatu
|
||||
res' DESC 'KOPANO: This user has these features explicitly enabled' EQUALIT
|
||||
Y caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
|
||||
olcAttributeTypes: {20}( 1.3.6.1.4.1.47732.1.1.2.14 NAME 'kopanoDisabledFeat
|
||||
ures' DESC 'KOPANO: This user has these features explicitly disabled' EQUAL
|
||||
ITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
|
||||
olcAttributeTypes: {21}( 1.3.6.1.4.1.47732.1.1.3.1 NAME 'kopanoAliases' DESC
|
||||
'KOPANO: All other email addresses for this user' EQUALITY caseIgnoreMatch
|
||||
SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {22}( 1.3.6.1.4.1.47732.1.1.4.1 NAME 'kopanoUserServer' D
|
||||
ESC 'KOPANO: Home server for the user' EQUALITY caseIgnoreMatch SUBSTR case
|
||||
IgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {23}( 1.3.6.1.4.1.47732.1.1.6.1 NAME 'kopanoUserArchiveSe
|
||||
rvers' DESC 'KOPANO: List of server names that contain an archive store for
|
||||
the user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX
|
||||
1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {24}( 1.3.6.1.4.1.47732.1.1.6.2 NAME 'kopanoUserArchiveCo
|
||||
uplings' DESC 'KOPANO: List of username:foldername pairs that specify many-
|
||||
to-one archive locations' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstri
|
||||
ngsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {25}( 1.3.6.1.4.1.47732.1.2.2.1 NAME 'kopanoSecurityGroup
|
||||
' DESC 'KOPANO: group has security possibilities' EQUALITY integerMatch SYN
|
||||
TAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {26}( 1.3.6.1.4.1.47732.1.3.2.4 NAME 'kopanoViewPrivilege
|
||||
' DESC 'KOPANO: Companies with view privileges over selected company' EQUAL
|
||||
ITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.146
|
||||
6.115.121.1.15 )
|
||||
olcAttributeTypes: {27}( 1.3.6.1.4.1.47732.1.3.2.5 NAME 'kopanoAdminPrivileg
|
||||
e' DESC 'KOPANO: Users from different companies which are administrator ove
|
||||
r selected company' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {28}( 1.3.6.1.4.1.47732.1.3.2.6 NAME 'kopanoSystemAdmin'
|
||||
DESC 'KOPANO: The user who is the system administrator for this company' EQ
|
||||
UALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.
|
||||
1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {29}( 1.3.6.1.4.1.47732.1.3.1.5 NAME 'kopanoQuotaUserWarn
|
||||
ingRecipients' DESC 'KOPANO: Users who will receive a notification email wh
|
||||
en a user exceeds his quota' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubs
|
||||
tringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {30}( 1.3.6.1.4.1.47732.1.3.1.6 NAME 'kopanoQuotaCompanyW
|
||||
arningRecipients' DESC 'KOPANO: Users who will receive a notification email
|
||||
when a company exceeds its quota' EQUALITY caseIgnoreMatch SUBSTR caseIgno
|
||||
reSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
||||
olcAttributeTypes: {31}( 1.3.6.1.4.1.47732.1.3.4.1 NAME 'kopanoCompanyServer
|
||||
' DESC 'KOPANO: Home server for the public folders for a company' EQUALITY
|
||||
caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.11
|
||||
5.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {32}( 1.3.6.1.4.1.47732.1.4.4.1 NAME 'kopanoHttpPort' DES
|
||||
C 'KOPANO: Port for the http connection' EQUALITY integerMatch SYNTAX 1.3.6
|
||||
.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {33}( 1.3.6.1.4.1.47732.1.4.4.2 NAME 'kopanoSslPort' DESC
|
||||
'KOPANO: Port for the ssl connection' EQUALITY integerMatch SYNTAX 1.3.6.1
|
||||
.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {34}( 1.3.6.1.4.1.47732.1.4.4.3 NAME 'kopanoFilePath' DES
|
||||
C 'KOPANO: The Unix socket or named pipe to the server' EQUALITY caseIgnore
|
||||
Match SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {35}( 1.3.6.1.4.1.47732.1.4.4.4 NAME 'kopanoContainsPubli
|
||||
c' DESC 'KOPANO: This server contains the public store' EQUALITY integerMat
|
||||
ch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {36}( 1.3.6.1.4.1.47732.1.4.4.6 NAME 'kopanoProxyURL' DES
|
||||
C 'KOPANO: Full proxy URL for this server' EQUALITY caseIgnoreMatch SUBSTR
|
||||
caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
|
||||
)
|
||||
olcAttributeTypes: {37}( 1.3.6.1.4.1.47732.1.5.5.1 NAME 'kopanoFilter' DESC
|
||||
'KOPANO: LDAP Filter to apply' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSu
|
||||
bstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcAttributeTypes: {38}( 1.3.6.1.4.1.47732.1.5.5.2 NAME 'kopanoBase' DESC 'K
|
||||
OPANO: LDAP Search base to apply' EQUALITY caseIgnoreMatch SUBSTR caseIgnor
|
||||
eSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.47732.1.1.0.0 NAME 'kopano-user' DESC 'KO
|
||||
PANO: an user of Kopano' SUP top AUXILIARY MUST cn MAY ( kopanoQuotaOverrid
|
||||
e $ kopanoQuotaWarn $ kopanoQuotaSoft $ kopanoSendAsPrivilege $ kopanoQuota
|
||||
Hard $ kopanoAdmin $ kopanoSharedStoreOnly $ kopanoResourceType $ kopanoRes
|
||||
ourceCapacity $ kopanoAccount $ kopanoHidden $ kopanoAliases $ kopanoUserSe
|
||||
rver $ kopanoEnabledFeatures $ kopanoDisabledFeatures $ kopanoUserArchiveSe
|
||||
rvers $ kopanoUserArchiveCouplings $ uidNumber ) )
|
||||
olcObjectClasses: {1}( 1.3.6.1.4.1.47732.1.6.0.0 NAME 'kopano-contact' DESC
|
||||
'KOPANO: a contact of Kopano' SUP top AUXILIARY MUST ( cn $ uidNumber ) MAY
|
||||
( kopanoSendAsPrivilege $ kopanoHidden $ kopanoAliases $ kopanoAccount ) )
|
||||
olcObjectClasses: {2}( 1.3.6.1.4.1.47732.1.2.0.0 NAME 'kopano-group' DESC 'K
|
||||
OPANO: a group of Kopano' SUP top AUXILIARY MUST cn MAY ( kopanoAccount $ k
|
||||
opanoHidden $ mail $ kopanoAliases $ kopanoSecurityGroup $ kopanoSendAsPriv
|
||||
ilege $ gidNumber ) )
|
||||
olcObjectClasses: {3}( 1.3.6.1.4.1.47732.1.3.0.0 NAME 'kopano-company' DESC
|
||||
'KOPANO: a company of Kopano' SUP top AUXILIARY MUST ou MAY ( kopanoAccount
|
||||
$ kopanoHidden $ kopanoViewPrivilege $ kopanoAdminPrivilege $ kopanoSystem
|
||||
Admin $ kopanoQuotaOverride $ kopanoQuotaWarn $ kopanoUserDefaultQuotaOverr
|
||||
ide $ kopanoUserDefaultQuotaWarn $ kopanoUserDefaultQuotaSoft $ kopanoUserD
|
||||
efaultQuotaHard $ kopanoQuotaUserWarningRecipients $ kopanoQuotaCompanyWarn
|
||||
ingRecipients $ kopanoCompanyServer ) )
|
||||
olcObjectClasses: {4}( 1.3.6.1.4.1.47732.1.4.0.0 NAME 'kopano-server' DESC '
|
||||
KOPANO: a Kopano server' SUP top AUXILIARY MUST cn MAY ( kopanoAccount $ ko
|
||||
panoHidden $ kopanoHttpPort $ kopanoSslPort $ kopanoFilePath $ kopanoContai
|
||||
nsPublic $ kopanoProxyURL ) )
|
||||
olcObjectClasses: {5}( 1.3.6.1.4.1.47732.1.5.0.0 NAME 'kopano-addresslist' D
|
||||
ESC 'KOPANO: a Kopano Addresslist' SUP top STRUCTURAL MUST cn MAY ( kopanoA
|
||||
ccount $ kopanoHidden $ kopanoFilter $ kopanoBase ) )
|
||||
olcObjectClasses: {6}( 1.3.6.1.4.1.47732.1.7.0.0 NAME 'kopano-dynamicgroup'
|
||||
DESC 'KOPANO: a Kopano dynamic group' SUP top STRUCTURAL MUST cn MAY ( kopa
|
||||
noAccount $ kopanoHidden $ mail $ kopanoAliases $ kopanoFilter $ kopanoBase
|
||||
) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c5ee420-7ddc-103b-8d42-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.692846Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,18 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 815bdd09
|
||||
dn: cn={6}openssh-lpk
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {6}openssh-lpk
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' D
|
||||
ESC 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.40 )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' DE
|
||||
SC 'MANDATORY: OpenSSH LPK objectclass' SUP top AUXILIARY MAY ( sshPublicKe
|
||||
y $ uid ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c6226ee-7ddc-103b-8d43-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.714216Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,50 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 38be59a6
|
||||
dn: cn={7}postfix-book
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {7}postfix-book
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.29426.1.10.1 NAME 'mailHomeDirectory' DE
|
||||
SC 'The absolute path to the mail user home directory' EQUALITY caseExactIA
|
||||
5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.4.1.29426.1.10.2 NAME 'mailAlias' DESC 'RFC8
|
||||
22 Mailbox - mail alias' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5Su
|
||||
bstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.4.1.29426.1.10.3 NAME 'mailUidNumber' DESC '
|
||||
UID required to access the mailbox' EQUALITY integerMatch SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.4.1.29426.1.10.4 NAME 'mailGidNumber' DESC '
|
||||
GID required to access the mailbox' EQUALITY integerMatch SYNTAX 1.3.6.1.4.
|
||||
1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.4.1.29426.1.10.5 NAME 'mailEnabled' DESC 'TR
|
||||
UE to enable, FALSE to disable account' EQUALITY booleanMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.4.1.29426.1.10.6 NAME 'mailGroupMember' DESC
|
||||
'Name of a mail distribution list' EQUALITY caseExactIA5Match SYNTAX 1.3.6
|
||||
.1.4.1.1466.115.121.1.26 )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.4.1.29426.1.10.7 NAME 'mailQuota' DESC 'Mail
|
||||
quota limit in kilobytes' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.14
|
||||
66.115.121.1.26 )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.4.1.29426.1.10.8 NAME 'mailStorageDirectory'
|
||||
DESC 'The absolute path to the mail users mailbox' EQUALITY caseExactIA5Ma
|
||||
tch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.4.1.29426.1.10.9 NAME 'mailSieveRuleSource'
|
||||
DESC 'Sun ONE Messaging Server defined attribute' SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.26 X-ORIGIN 'Sun ONE Messaging Server' )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.4.1.29426.1.10.10 NAME 'mailForwardingAddres
|
||||
s' DESC 'Address(es) to forward all incoming messages to.' EQUALITY caseIgn
|
||||
oreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{320} )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.29426.1.2.2.1 NAME 'PostfixBookMailAccoun
|
||||
t' DESC 'Mail account used in Postfix Book' SUP top AUXILIARY MUST mail MAY
|
||||
( mailHomeDirectory $ mailAlias $ mailGroupMember $ mailUidNumber $ mailGi
|
||||
dNumber $ mailEnabled $ mailQuota $ mailStorageDirectory $ mailSieveRuleSou
|
||||
rce ) )
|
||||
olcObjectClasses: {1}( 1.3.6.1.4.1.29426.1.2.2.2 NAME 'PostfixBookMailForwar
|
||||
d' DESC 'Mail forward used in Postfix Book' SUP top AUXILIARY MUST ( mail $
|
||||
mailAlias ) MAY mailForwardingAddress )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c658af0-7ddc-103b-8d44-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.736438Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,235 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 41b81a66
|
||||
dn: cn={8}samba
|
||||
objectClass: olcSchemaConfig
|
||||
cn: {8}samba
|
||||
olcAttributeTypes: {0}( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC
|
||||
'LanManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.26{32} SINGLE-VALUE )
|
||||
olcAttributeTypes: {1}( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC
|
||||
'MD4 hash of the unicode password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6
|
||||
.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
|
||||
olcAttributeTypes: {2}( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC '
|
||||
Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.26{16} SINGLE-VALUE )
|
||||
olcAttributeTypes: {3}( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC
|
||||
'Timestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {4}( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DES
|
||||
C 'Timestamp of when the user is allowed to update the password' EQUALITY i
|
||||
ntegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {5}( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DE
|
||||
SC 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTA
|
||||
X 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {6}( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC '
|
||||
Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {7}( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC
|
||||
'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.11
|
||||
5.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {8}( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC
|
||||
'Timestamp of when the user will be logged off automatically' EQUALITY int
|
||||
egerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {9}( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount'
|
||||
DESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1
|
||||
.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {10}( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime'
|
||||
DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX
|
||||
1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {11}( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC
|
||||
'Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.
|
||||
1.26{42} SINGLE-VALUE )
|
||||
olcAttributeTypes: {12}( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC
|
||||
'Driver letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTA
|
||||
X 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )
|
||||
olcAttributeTypes: {13}( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DES
|
||||
C 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.
|
||||
121.1.15{255} SINGLE-VALUE )
|
||||
olcAttributeTypes: {14}( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DES
|
||||
C 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.15{255} SINGLE-VALUE )
|
||||
olcAttributeTypes: {15}( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations
|
||||
' DESC 'List of user workstations the user is allowed to logon to' EQUALITY
|
||||
caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
|
||||
olcAttributeTypes: {16}( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC '
|
||||
Home directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.15{128} )
|
||||
olcAttributeTypes: {17}( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC
|
||||
'Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYN
|
||||
TAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {18}( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC
|
||||
'Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.15{1050} )
|
||||
olcAttributeTypes: {19}( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory'
|
||||
DESC 'Concatenated MD5 hashes of the salted NT passwords used on this acco
|
||||
unt' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} )
|
||||
olcAttributeTypes: {20}( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Secur
|
||||
ity ID' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNT
|
||||
AX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
|
||||
olcAttributeTypes: {21}( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID'
|
||||
DESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
|
||||
olcAttributeTypes: {22}( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'S
|
||||
ecurity ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.12
|
||||
1.1.26{64} )
|
||||
olcAttributeTypes: {23}( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC
|
||||
'NT Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {24}( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DES
|
||||
C 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.
|
||||
4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {25}( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DE
|
||||
SC 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.
|
||||
1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {26}( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'N
|
||||
ext NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4
|
||||
.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {27}( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBa
|
||||
se' DESC 'Base at which the samba RID generation algorithm should operate'
|
||||
EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {28}( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC
|
||||
'Share Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {29}( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC
|
||||
'Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SY
|
||||
NTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
|
||||
olcAttributeTypes: {30}( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC
|
||||
'A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
|
||||
.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: {31}( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' D
|
||||
ESC 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.1
|
||||
21.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {32}( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DE
|
||||
SC 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115
|
||||
.121.1.26 SINGLE-VALUE )
|
||||
olcAttributeTypes: {33}( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption
|
||||
' DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1
|
||||
466.115.121.1.15 )
|
||||
olcAttributeTypes: {34}( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC
|
||||
'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466
|
||||
.115.121.1.26 )
|
||||
olcAttributeTypes: {35}( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DE
|
||||
SC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.
|
||||
6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {36}( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength
|
||||
' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY in
|
||||
tegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {37}( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' D
|
||||
ESC 'Force Users to logon for password change (default: 0 => off, 2 => on)'
|
||||
EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {38}( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC
|
||||
'Maximum password age, in seconds (default: -1 => never expire passwords)'
|
||||
EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {39}( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC
|
||||
'Minimum password age, in seconds (default: 0 => allow immediate password c
|
||||
hange)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-V
|
||||
ALUE )
|
||||
olcAttributeTypes: {40}( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration'
|
||||
DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY i
|
||||
ntegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {41}( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservati
|
||||
onWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY
|
||||
integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {42}( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold
|
||||
' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALIT
|
||||
Y integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {43}( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DES
|
||||
C 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUA
|
||||
LITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {44}( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwd
|
||||
Change' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY
|
||||
integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {45}( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPasswor
|
||||
d' DESC 'Clear text password (used for trusted domain passwords)' EQUALITY
|
||||
octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
|
||||
olcAttributeTypes: {46}( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTex
|
||||
tPassword' DESC 'Previous clear text password (used for trusted domain pass
|
||||
words)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
|
||||
olcAttributeTypes: {47}( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC
|
||||
'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
||||
SINGLE-VALUE )
|
||||
olcAttributeTypes: {48}( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes'
|
||||
DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX
|
||||
1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {49}( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection'
|
||||
DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.1
|
||||
15.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {50}( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DE
|
||||
SC 'Fully qualified name of the domain with which a trust exists' EQUALITY
|
||||
caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: {51}( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC '
|
||||
NetBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.
|
||||
115.121.1.15{128} )
|
||||
olcAttributeTypes: {52}( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoin
|
||||
g' DESC 'Authentication information for the outgoing portion of a trust' EQ
|
||||
UALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
|
||||
olcAttributeTypes: {53}( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncomin
|
||||
g' DESC 'Authentication information for the incoming portion of a trust' EQ
|
||||
UALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
|
||||
olcAttributeTypes: {54}( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifi
|
||||
er' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseE
|
||||
xactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALU
|
||||
E )
|
||||
olcAttributeTypes: {55}( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrust
|
||||
Info' DESC 'Forest trust information for a trusted domain object' EQUALITY
|
||||
caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
|
||||
olcAttributeTypes: {56}( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset
|
||||
' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1
|
||||
466.115.121.1.27 SINGLE-VALUE )
|
||||
olcAttributeTypes: {57}( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncrypt
|
||||
ionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatc
|
||||
h SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
|
||||
olcObjectClasses: {0}( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' DESC 'S
|
||||
amba 3.0 Auxilary SAM Account' SUP top AUXILIARY MUST ( uid $ sambaSID ) MA
|
||||
Y ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTi
|
||||
me $ sambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustC
|
||||
hange $ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sam
|
||||
baLogonScript $ sambaProfilePath $ description $ sambaUserWorkstations $ sa
|
||||
mbaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCo
|
||||
unt $ sambaBadPasswordTime $ sambaPasswordHistory $ sambaLogonHours ) )
|
||||
olcObjectClasses: {1}( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' DESC
|
||||
'Samba Group Mapping' SUP top AUXILIARY MUST ( gidNumber $ sambaSID $ samba
|
||||
GroupType ) MAY ( displayName $ description $ sambaSIDList ) )
|
||||
olcObjectClasses: {2}( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' DES
|
||||
C 'Samba Trust Password' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaN
|
||||
TPassword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet ) )
|
||||
olcObjectClasses: {3}( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassw
|
||||
ord' DESC 'Samba Trusted Domain Password' SUP top STRUCTURAL MUST ( sambaDo
|
||||
mainName $ sambaSID $ sambaClearTextPassword $ sambaPwdLastSet ) MAY sambaP
|
||||
reviousClearTextPassword )
|
||||
olcObjectClasses: {4}( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' DESC 'Samba
|
||||
Domain Information' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaSID )
|
||||
MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithm
|
||||
icRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd
|
||||
$ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObse
|
||||
rvationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachi
|
||||
nePwdChange ) )
|
||||
olcObjectClasses: {5}( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' DESC 'P
|
||||
ool for allocating UNIX uids/gids' SUP top AUXILIARY MUST ( uidNumber $ gid
|
||||
Number ) )
|
||||
olcObjectClasses: {6}( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' DESC 'M
|
||||
apping from a SID to an ID' SUP top AUXILIARY MUST sambaSID MAY ( uidNumber
|
||||
$ gidNumber ) )
|
||||
olcObjectClasses: {7}( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' DESC 'Str
|
||||
uctural Class for a SID' SUP top STRUCTURAL MUST sambaSID )
|
||||
olcObjectClasses: {8}( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' DESC 'Samb
|
||||
a Configuration Section' SUP top AUXILIARY MAY description )
|
||||
olcObjectClasses: {9}( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' DESC 'Samba
|
||||
Share Section' SUP top STRUCTURAL MUST sambaShareName MAY description )
|
||||
olcObjectClasses: {10}( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' DES
|
||||
C 'Samba Configuration Option' SUP top STRUCTURAL MUST sambaOptionName MAY
|
||||
( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringLis
|
||||
toption $ description ) )
|
||||
olcObjectClasses: {11}( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' DE
|
||||
SC 'Samba Trusted Domain Object' SUP top STRUCTURAL MUST cn MAY ( sambaTrus
|
||||
tType $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sa
|
||||
mbaFlatName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecuri
|
||||
tyIdentifier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSup
|
||||
portedEncryptionTypes ) )
|
||||
structuralObjectClass: olcSchemaConfig
|
||||
entryUUID: 5c692e8a-7ddc-103b-8d45-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.760287Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,18 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 6d98bb57
|
||||
dn: olcDatabase={-1}frontend
|
||||
objectClass: olcDatabaseConfig
|
||||
objectClass: olcFrontendConfig
|
||||
olcDatabase: {-1}frontend
|
||||
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=extern
|
||||
al,cn=auth manage by * break
|
||||
olcAccess: {1}to dn.exact="" by * read
|
||||
olcAccess: {2}to dn.base="cn=Subschema" by * read
|
||||
olcSizeLimit: 500
|
||||
structuralObjectClass: olcDatabaseConfig
|
||||
entryUUID: 5c22f244-7ddc-103b-9ebc-c740e015b81b
|
||||
creatorsName: cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.299952Z#000000#000#000000
|
||||
modifiersName: cn=config
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,16 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 4503eefa
|
||||
dn: olcDatabase={0}config
|
||||
objectClass: olcDatabaseConfig
|
||||
olcDatabase: {0}config
|
||||
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=extern
|
||||
al,cn=auth manage by * break
|
||||
olcRootDN: cn=admin,cn=config
|
||||
structuralObjectClass: olcDatabaseConfig
|
||||
entryUUID: 5c248d0c-7ddc-103b-9ebd-c740e015b81b
|
||||
creatorsName: cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
olcRootPW:: e1NTSEF9eGNpMDV6aExUSXhxL3k0NHYyVHlBR2p0bCsxblV1UHc=
|
||||
entryCSN: 20210812002157.882687Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210812002157Z
|
||||
@@ -0,0 +1,31 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 506f4bf6
|
||||
dn: olcDatabase={1}mdb
|
||||
objectClass: olcDatabaseConfig
|
||||
objectClass: olcMdbConfig
|
||||
olcDatabase: {1}mdb
|
||||
olcDbDirectory: /var/lib/ldap
|
||||
olcSuffix: dc=glauth,dc=com
|
||||
olcLastMod: TRUE
|
||||
olcRootDN: cn=admin,dc=glauth,dc=com
|
||||
olcDbCheckpoint: 512 30
|
||||
olcDbMaxSize: 1073741824
|
||||
structuralObjectClass: olcMdbConfig
|
||||
entryUUID: 5c2cdd40-7ddc-103b-9ec4-c740e015b81b
|
||||
creatorsName: cn=admin,cn=config
|
||||
createTimestamp: 20210720192809Z
|
||||
olcDbIndex: uid eq
|
||||
olcDbIndex: mail eq
|
||||
olcDbIndex: memberOf eq
|
||||
olcDbIndex: entryCSN eq
|
||||
olcDbIndex: entryUUID eq
|
||||
olcDbIndex: objectClass eq
|
||||
olcAccess: {0}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: {1}to * by self write by dn="cn=serviceuser,cn=svcaccts,ou=users,
|
||||
dc=glauth,dc=com" write by users read by * none
|
||||
olcRootPW:: e1NTSEF9TzNabzVITEhzQXU1dkg5a0txNTlEVFhGclpPVDBPQUg=
|
||||
entryCSN: 20210812002157.895969Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210812002157Z
|
||||
@@ -0,0 +1,18 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 5273ae52
|
||||
dn: olcOverlay={0}memberof
|
||||
objectClass: olcOverlayConfig
|
||||
objectClass: olcMemberOf
|
||||
olcOverlay: {0}memberof
|
||||
olcMemberOfDangling: ignore
|
||||
olcMemberOfRefInt: TRUE
|
||||
olcMemberOfGroupOC: groupOfUniqueNames
|
||||
olcMemberOfMemberAD: uniqueMember
|
||||
olcMemberOfMemberOfAD: memberOf
|
||||
structuralObjectClass: olcMemberOf
|
||||
entryUUID: 5c74c556-7ddc-103b-8d46-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.836237Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,18 @@
|
||||
# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
|
||||
# CRC32 a7700674
|
||||
dn: olcOverlay={1}refint
|
||||
objectClass: olcOverlayConfig
|
||||
objectClass: olcRefintConfig
|
||||
olcOverlay: {1}refint
|
||||
olcRefintAttribute: owner
|
||||
olcRefintAttribute: manager
|
||||
olcRefintAttribute: uniqueMember
|
||||
olcRefintAttribute: member
|
||||
olcRefintAttribute: memberOf
|
||||
structuralObjectClass: olcRefintConfig
|
||||
entryUUID: 5c78d98e-7ddc-103b-8d47-8b35b6446851
|
||||
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
createTimestamp: 20210720192809Z
|
||||
entryCSN: 20210720192809.862968Z#000000#000#000000
|
||||
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
|
||||
modifyTimestamp: 20210720192809Z
|
||||
@@ -0,0 +1,4 @@
|
||||
export PREVIOUS_LDAP_TLS_CA_CRT_PATH=/container/service/slapd/assets/certs/ca.crt
|
||||
export PREVIOUS_LDAP_TLS_CRT_PATH=/container/service/slapd/assets/certs/ldap.crt
|
||||
export PREVIOUS_LDAP_TLS_KEY_PATH=/container/service/slapd/assets/certs/ldap.key
|
||||
export PREVIOUS_LDAP_TLS_DH_PARAM_PATH=/container/service/slapd/assets/certs/dhparam.pem
|
||||
Binary file not shown.
Binary file not shown.
@@ -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-----
|
||||
+5
File diff suppressed because one or more lines are too long
Vendored
+5
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
package assets
|
||||
|
||||
import "embed"
|
||||
|
||||
// Content is the embedded assets.
|
||||
//
|
||||
//go:embed *.tgz js/* css/* *.html
|
||||
var Content embed.FS
|
||||
Binary file not shown.
@@ -0,0 +1,39 @@
|
||||
package assets
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type API struct {
|
||||
fileServer http.Handler
|
||||
|
||||
logger zerolog.Logger
|
||||
}
|
||||
|
||||
func (a *API) RegisterEndpoints(router *http.ServeMux) {
|
||||
router.HandleFunc("/", a.assets)
|
||||
router.Handle("/assets/", http.StripPrefix("/assets/", a.fileServer))
|
||||
}
|
||||
|
||||
func (a *API) assets(w http.ResponseWriter, r *http.Request) {
|
||||
a.logger.Info().Str("path", r.URL.Path).Msg("Web")
|
||||
|
||||
if r.URL.Path != "/" {
|
||||
log.Info().Msg("Web 404")
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
a.fileServer.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func NewAPI(logger zerolog.Logger) *API {
|
||||
a := new(API)
|
||||
|
||||
a.logger = logger
|
||||
a.fileServer = http.FileServer(http.FS(Content))
|
||||
return a
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package assets
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// TestAPI is a small test to make sure that behavior didn't change for the
|
||||
// worse when switching over to the go1.16+ "embed" package from go-bindata.
|
||||
func TestAPIAssets(t *testing.T) {
|
||||
tt := []struct {
|
||||
Name string
|
||||
Path string
|
||||
Check func(testing.TB, *http.Response)
|
||||
}{
|
||||
{
|
||||
Name: "Root",
|
||||
Path: "/",
|
||||
Check: func(t testing.TB, res *http.Response) {
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Fatalf("unexpected response: %v", res.Status)
|
||||
return
|
||||
}
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, res.Body); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if got, want := h.Sum(nil), mkDigest(t, "index.html"); !bytes.Equal(got, want) {
|
||||
t.Fatalf("bad digest: got: %x, want %x", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "NotFound",
|
||||
Path: "/glauth.js",
|
||||
Check: func(t testing.TB, res *http.Response) {
|
||||
if res.StatusCode != http.StatusNotFound {
|
||||
t.Fatalf("unexpected response: %v", res.Status)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Content-Type",
|
||||
Path: "/assets/js/glauth.js",
|
||||
Check: func(t testing.TB, res *http.Response) {
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Fatalf("unexpected response: %v", res.Status)
|
||||
}
|
||||
if got, want := res.Header.Get("Content-Type"), `text/javascript; charset=utf-8`; got != want {
|
||||
t.Fatalf("bad content-type: got: %q, want %q", got, want)
|
||||
}
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, res.Body); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if got, want := h.Sum(nil), mkDigest(t, "js/glauth.js"); !bytes.Equal(got, want) {
|
||||
t.Fatalf("bad digest: got: %x, want %x", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Content-Type",
|
||||
Path: "/assets/css/glauth.css",
|
||||
Check: func(t testing.TB, res *http.Response) {
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Fatalf("unexpected response: %v", res.Status)
|
||||
}
|
||||
// This isn't exactly the same, it adds a charset argument.
|
||||
if got, want := res.Header.Get("Content-Type"), `text/css; charset=utf-8`; got != want {
|
||||
t.Fatalf("bad content-type: got: %q, want %q", got, want)
|
||||
}
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, res.Body); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if got, want := h.Sum(nil), mkDigest(t, "css/glauth.css"); !bytes.Equal(got, want) {
|
||||
t.Fatalf("bad digest: got: %x, want %x", got, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
log := zerolog.New(os.Stdout).Level(zerolog.InfoLevel)
|
||||
NewAPI(log).RegisterEndpoints(mux)
|
||||
srv := httptest.NewServer(mux)
|
||||
defer srv.Close()
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
req, err := http.NewRequest(http.MethodGet, srv.URL+tc.Path, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res, err := srv.Client().Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
tc.Check(t, res)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func mkDigest(t testing.TB, path string) []byte {
|
||||
f, err := Content.Open(path)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer f.Close()
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
return h.Sum(nil)
|
||||
}
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
<title>GLAuth Status</title>
|
||||
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
|
||||
<link rel="stylesheet" href="assets/glauth.css">
|
||||
<link rel="stylesheet" href="assets/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="assets/css/bootstrap-theme.min.css">
|
||||
<link rel="stylesheet" href="assets/css/glauth.css">
|
||||
|
||||
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!--[if lt IE 9]>
|
||||
@@ -29,19 +29,18 @@
|
||||
<div id="statspanel" class="panel panel-default pull-right">
|
||||
</div>
|
||||
<h1>GLAuth</h1>
|
||||
<p>This tool is in development - not quite ready for production!</p>
|
||||
|
||||
<div id="headerpanel"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<h2>stats</h2>
|
||||
<h2>frontend stats</h2>
|
||||
<div id="stats" class="jumbotron">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-6">
|
||||
<h2>backend servers</h2>
|
||||
<h2>backend (LDAP) servers</h2>
|
||||
<div id="servers" class="jumbotron">
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,6 +48,12 @@
|
||||
|
||||
</div> <!-- /container -->
|
||||
|
||||
<script id="header-messages-template" type="text/x-handlebars-template">
|
||||
{{#each header.messages}}
|
||||
<span>{{{message}}}</span><br>
|
||||
{{/each}}
|
||||
</script>
|
||||
|
||||
<script id="statspanel-template" type="text/x-handlebars-template">
|
||||
<div class="panel-body">
|
||||
<span class="metric">proxy.version:</span> {{proxy.version}}<br>
|
||||
@@ -87,10 +92,10 @@
|
||||
<tbody>
|
||||
</script>
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment-with-locales.min.js"></script>
|
||||
<script src="assets/glauth.js"></script>
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/handlebars.min.js"></script>
|
||||
<script src="assets/js/moment-with-locales.min.js"></script>
|
||||
<script src="assets/js/glauth.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Vendored
+6
File diff suppressed because one or more lines are too long
@@ -1,14 +1,32 @@
|
||||
var interval = 2000;
|
||||
|
||||
var internalsEnabled = false;
|
||||
|
||||
$(function() {
|
||||
updateMetrics();
|
||||
//updateTail();
|
||||
$.get("/internals", function() {
|
||||
internalsEnabled = true;
|
||||
})
|
||||
.always(function() {
|
||||
updateMetrics();
|
||||
//updateTail();
|
||||
})
|
||||
});
|
||||
|
||||
var tailId = 0;
|
||||
|
||||
function updateMetrics() {
|
||||
var metrics = $.getJSON( "/debug/vars", function(d) {
|
||||
var template = Handlebars.compile( $("#header-messages-template").html() );
|
||||
var messages = [];
|
||||
if(internalsEnabled) {
|
||||
messages.push({"message": "Also available: <a href='/internals'>Internals: heap, cache, objects, etc.</a>"});
|
||||
}
|
||||
var html = template({
|
||||
"header": {
|
||||
"messages": messages
|
||||
}
|
||||
});
|
||||
$("#headerpanel").html(html);
|
||||
var template = Handlebars.compile( $("#statspanel-template").html() );
|
||||
var html = template(d);
|
||||
$("#statspanel").html(html);
|
||||
Vendored
+28
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user