mirror of
https://github.com/glauth/glauth.git
synced 2026-10-27 06:26:59 +00:00
Compare commits
325 Commits
v1.0.0
...
GLAuth-v2.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| a3797bbe08 | |||
| dc90cd6819 | |||
| c2aca63246 | |||
| 60ac4368c6 | |||
| 64fbf20dcd | |||
| de571e8cb6 | |||
| 18d128dd0c | |||
| f317b73009 | |||
| efe89aff4b | |||
| c232ee0476 | |||
| 4f82bf2baf | |||
| 17bce790a9 | |||
| 5aa56138ce | |||
| 8b00a524fb | |||
| 41ec0fdb10 | |||
| 7608bc0133 | |||
| 2ae84a9034 | |||
| ac85255d86 | |||
| 2a16b13a01 | |||
| 5b84deb1c1 | |||
| d1d51d5c7c | |||
| 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
|
||||
+20
-4
@@ -1,5 +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/
|
||||
|
||||
# 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
|
||||
|
||||
# Ignore the built binary during testing
|
||||
glauth
|
||||
|
||||
+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"
|
||||
}
|
||||
@@ -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,24 +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.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
* 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 autonmatically 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. Install GLAuth on a test server
|
||||
1. Clone the repo: `git clone https://github.com/nmcclain/glauth`
|
||||
2. Start the GLAuth server: `cd glauth; sudo bin/glauth32 -c sample-simple.cfg`
|
||||
2. Test with traditional LDAP tools
|
||||
1. `ldapsearch -LLL -H ldap://localhost:389 -D cn=serviceuser,ou=svcaccts,dc=glauth,dc=com -w mysecret -x -bdc=glauth,dc=com cn=hackers`
|
||||
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/v2/sample-simple.cfg).
|
||||
3. Start the GLAuth server, referencing the path to the desired config file with `-c`.
|
||||
- `./glauth64 -c sample-simple.cfg`
|
||||
4. Test with traditional LDAP tools
|
||||
- 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:
|
||||
```
|
||||
@@ -34,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.
|
||||
```
|
||||
@@ -50,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)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
- name: deploy glauth.yml
|
||||
hosts: localhost
|
||||
roles:
|
||||
- glauth
|
||||
@@ -1,2 +0,0 @@
|
||||
localhost ansible_connection=local
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
Name: activate mkhomedir
|
||||
Default: yes
|
||||
Priority: 900
|
||||
Session-Type: Additional
|
||||
Session: required pam_mkhomedir.so
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
- name: restart nscd
|
||||
sudo: true
|
||||
service: name=nscd state=restarted
|
||||
- name: restart sshd
|
||||
sudo: true
|
||||
service: name=ssh state=restarted
|
||||
@@ -1,56 +0,0 @@
|
||||
---
|
||||
- name: install packages needed for glauth
|
||||
sudo: true
|
||||
apt: pkg={{item}} state=installed
|
||||
with_items:
|
||||
- ldap-auth-client
|
||||
- nscd
|
||||
# - ldap-utils
|
||||
# - netcat
|
||||
|
||||
- name: configure nsswitch passwd
|
||||
sudo: true
|
||||
lineinfile: 'dest=/etc/nsswitch.conf state=present backrefs=yes regexp="^passwd:\s+compat" line="passwd: files ldap"'
|
||||
notify: restart nscd
|
||||
- name: configure nsswitch group
|
||||
sudo: true
|
||||
lineinfile: 'dest=/etc/nsswitch.conf state=present backrefs=yes regexp="^group:\s+compat" line="group: files ldap"'
|
||||
notify: restart nscd
|
||||
- name: configure nsswitch shadow
|
||||
sudo: true
|
||||
lineinfile: 'dest=/etc/nsswitch.conf state=present backrefs=yes regexp="^shadow:\s+compat" line="shadow: files ldap"'
|
||||
notify: restart nscd
|
||||
- name: configure pam common-session
|
||||
sudo: true
|
||||
lineinfile: 'dest=/etc/pam.d/common-session state=present regexp="^session\s+required\s+pam_mkhomedir.so" line="session required pam_mkhomedir.so"'
|
||||
notify: restart nscd
|
||||
- name: configure pam common-session-noninteractive
|
||||
sudo: true
|
||||
lineinfile: 'dest=/etc/pam.d/common-session-noninteractive state=present regexp="^session\s+required\s+pam_mkhomedir.so" line="session required pam_mkhomedir.so"'
|
||||
notify: restart nscd
|
||||
- name: copy over ldap.conf file
|
||||
sudo: true
|
||||
template: src=ldap.conf dest=/etc/ldap.conf mode=0600
|
||||
notify: restart nscd
|
||||
- name: copy over mkdhomedir pam config file
|
||||
sudo: true
|
||||
copy: src=mkhomedir dest=/usr/share/pam-configs/my_mkhomedir mode=0600
|
||||
- name: download goklp command
|
||||
sudo: true
|
||||
get_url: url=https://github.com/AppliedTrust/goklp/releases/download/1.4/goklp dest=/usr/local/sbin/goklp mode=0755 owner=root
|
||||
- name: copy over goklp config
|
||||
sudo: true
|
||||
template: src=goklp.ini dest=/usr/local/sbin/goklp.ini mode=0600 owner=root
|
||||
#- name: disable ssh password auth
|
||||
# sudo: true
|
||||
# lineinfile: dest=/etc/ssh/sshd_config state=present regexp="^PasswordAuthentication" line="PasswordAuthentication no"
|
||||
# notify: restart sshd
|
||||
- name: configure ssh AuthorizedKeysCommand for glauth
|
||||
sudo: true
|
||||
lineinfile: dest=/etc/ssh/sshd_config state=present regexp="^AuthorizedKeysCommand\s+" line="AuthorizedKeysCommand /usr/local/sbin/goklp"
|
||||
notify: restart sshd
|
||||
- name: configure ssh AuthorizedKeysCommandUser for glauth
|
||||
sudo: true
|
||||
lineinfile: dest=/etc/ssh/sshd_config state=present regexp="^AuthorizedKeysCommandUser\s+" line="AuthorizedKeysCommandUser root"
|
||||
notify: restart sshd
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
goklp_ldap_uri = {{ glauth_ldap_uri }}
|
||||
goklp_ldap_bind_dn = {{ glauth_bind_dn }}
|
||||
goklp_ldap_base_dn = {{ glauth_base_dn }}
|
||||
goklp_ldap_bind_pw = {{ glauth_bind_pw }}
|
||||
goklp_ldap_timeout_secs = 3
|
||||
@@ -1,7 +0,0 @@
|
||||
ldap_version 3
|
||||
uri {{ glauth_ldap_uri }}
|
||||
base {{ glauth_base_dn }}
|
||||
binddn {{ glauth_bind_dn }}
|
||||
bindpw {{ glauth_bind_pw }}
|
||||
pam_password_prohibit_message Please change your password in the central system.
|
||||
nss_initgroups_ignoreusers root,daemon,bin,sys,sync,games,man,lp,mail,news,uucp,proxy,www-data,backup,list,irc,gnats,nobody,libuuid,syslog,messagebus,landscape,sshd,pollinate,ubuntu
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
glauth_ldap_uri: ldap://localhost:389
|
||||
glauth_bind_dn: cn=serviceuser,ou=svcaccts,dc=glauth,dc=com
|
||||
glauth_base_dn: dc=glauth,dc=com
|
||||
glauth_bind_pw: mysecret
|
||||
glauth_timeout_secs: 5
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
-223
@@ -1,223 +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,264 +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"
|
||||
"launchpad.net/goamz/aws"
|
||||
"launchpad.net/goamz/s3"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var version = "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,56 +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:389"
|
||||
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
|
||||
|
||||
[[users]]
|
||||
name = "serviceuser"
|
||||
unixid = 5002
|
||||
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)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user