mirror of
https://github.com/glauth/glauth.git
synced 2026-10-27 06:26:59 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dd5befc4f2 | |||
| 596d28efbd | |||
| 7f925565a6 | |||
| f5ea3d93bf | |||
| 34a6b30b8f | |||
| 9bbad511cb | |||
| 7cef07931c | |||
| 37fa74892e | |||
| efbd64504d | |||
| 1920c4324f | |||
| 7e7a5f59d1 | |||
| 83f4305e36 | |||
| b45259d567 | |||
| 3f9f67375f | |||
| cb761e8e70 | |||
| 7c3314a504 | |||
| 690917e4e0 | |||
| 0ccf4926ff | |||
| 598a688214 | |||
| 0e7769ff84 | |||
| 6500bbaf36 | |||
| e92197ac08 | |||
| aadf150fec |
@@ -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"
|
||||
}
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.16.x, 1.17.x]
|
||||
go-version: [1.19.x, 1.20.x]
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master", "dev" ]
|
||||
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@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
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 }}
|
||||
@@ -3,3 +3,4 @@ v2/certs/
|
||||
v2/bin
|
||||
v2/docker/assets/linux
|
||||
v2/gl.db
|
||||
.vscode/
|
||||
|
||||
@@ -19,7 +19,23 @@ Go-lang LDAP Authentication (GLAuth) is a secure, easy-to-use, LDAP server w/ co
|
||||
|
||||
Use it to centralize account management across your Linux servers, your OSX machines, and your support applications (Jenkins, Apache/Nginx, Graylog2, and many more!).
|
||||
|
||||
<hr>
|
||||
### Contributing
|
||||
- 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. 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
|
||||
|
||||
|
||||
+15
-8
@@ -1,3 +1,5 @@
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
VERSION=$(shell bin/linuxamd64/glauth --version)
|
||||
|
||||
GIT_COMMIT=$(shell git rev-list -1 HEAD )
|
||||
@@ -23,28 +25,32 @@ MAIN_TARGETS=linux/amd64,linux/386,linux/arm64,linux/arm-7,darwin/amd64,darwin/a
|
||||
PLUGIN_TARGETS=linux/amd64,linux/386,linux/arm64,linux/arm-7,darwin/amd64,darwin/arm64
|
||||
|
||||
# Plugins
|
||||
include pkg/plugins/*/Makefile
|
||||
-include pkg/plugins/*/Makefile
|
||||
|
||||
#####################
|
||||
# High level commands
|
||||
#####################
|
||||
|
||||
# Build and run - used for development
|
||||
#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
|
||||
|
||||
# Run the integration test on linuxamd64 (eventually allow the binary to be set)
|
||||
#test: @ runs the integration test on linuxamd64 (eventually allow the binary to be set)
|
||||
test: runtest
|
||||
|
||||
# Run build process for all binaries
|
||||
#all: @ run build process for all binaries
|
||||
all: setup binaries verify
|
||||
|
||||
# Run build process for only linuxamd64
|
||||
#fast: @ run build process for only linuxamd64
|
||||
fast: setup linuxamd64
|
||||
|
||||
# list of binary formats to build
|
||||
#binaries: @ list of binary formats to build
|
||||
binaries: linux386 linuxamd64 linuxarm linuxarm64 darwinamd64 darwinarm64 win386 winamd64
|
||||
|
||||
# Setup commands to always run
|
||||
#setup: @ setup commands to always run
|
||||
setup: getdeps format
|
||||
|
||||
#####################
|
||||
@@ -121,7 +127,7 @@ releasemain:
|
||||
|
||||
releaseplugin:
|
||||
@xgo -v -ldflags="${BUILD_VARS}" -trimpath -go 1.18.1 -out $P -dest bin -buildvcs=false -buildmode=plugin --targets="${PLUGIN_TARGETS}" --pkg $M/$P.go . && \
|
||||
(cd bin && for lib in $$(ls $$P-*); do mv $$lib $$lib.so; done)
|
||||
(cd bin && for lib in $$(ls $$P-*); do sudo mv $$lib $$lib.so; done)
|
||||
|
||||
releaseplugins:
|
||||
@for pkg in pkg/plugins/*/go.mod; do\
|
||||
@@ -154,6 +160,7 @@ releasedockerplugins:
|
||||
|
||||
releasedocker: releasedockermain releasedockerplugins
|
||||
|
||||
#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..." && \
|
||||
|
||||
+2
-3
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/rs/zerolog"
|
||||
"gopkg.in/amz.v3/aws"
|
||||
"gopkg.in/amz.v3/s3"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -328,11 +327,11 @@ func parseConfigFile(configFileLocation string) (*config.Config, error) {
|
||||
}
|
||||
*/
|
||||
|
||||
files, _ := ioutil.ReadDir(configFileLocation)
|
||||
files, _ := os.ReadDir(configFileLocation)
|
||||
for _, f := range files {
|
||||
canonicalName := filepath.Join(configFileLocation, f.Name())
|
||||
|
||||
bs, _ := ioutil.ReadFile(canonicalName)
|
||||
bs, _ := os.ReadFile(canonicalName)
|
||||
var curRawCfgStruct interface{}
|
||||
if err := toml.Unmarshal(bs, &curRawCfgStruct); err != nil {
|
||||
return &cfg, err
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/glauth/glauth/v2
|
||||
|
||||
go 1.16
|
||||
go 1.19
|
||||
|
||||
// Do not mistake /vendored for /vendor!
|
||||
replace github.com/hydronica/toml => ./vendored/toml
|
||||
@@ -8,7 +8,6 @@ replace github.com/hydronica/toml => ./vendored/toml
|
||||
require (
|
||||
github.com/GeertJohan/yubigo v0.0.0-20190917122436-175bc097e60e
|
||||
github.com/arl/statsviz v0.4.0
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/hydronica/toml v0.4.2
|
||||
@@ -19,7 +18,27 @@ require (
|
||||
github.com/rs/zerolog v1.28.0
|
||||
github.com/smartystreets/goconvey v1.6.4
|
||||
github.com/yaegashi/msgraph.go v0.1.1-0.20200221123608-2d438cf2a7cc
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
|
||||
golang.org/x/crypto v0.1.0
|
||||
gopkg.in/amz.v3 v3.0.0-20201001071545-24fc1eceb27b
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/jtolds/gls v4.20.0+incompatible // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
|
||||
golang.org/x/sys v0.1.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
)
|
||||
|
||||
@@ -124,7 +124,6 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@@ -251,8 +250,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
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.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -311,7 +310,6 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
@@ -331,7 +329,6 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -373,8 +370,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -3,5 +3,6 @@ package assets
|
||||
import "embed"
|
||||
|
||||
// Content is the embedded assets.
|
||||
//
|
||||
//go:embed *.tgz js/* css/* *.html
|
||||
var Content embed.FS
|
||||
|
||||
@@ -60,6 +60,7 @@ type Behaviors struct {
|
||||
BlockFailedBindsFor time.Duration
|
||||
PruneSourceTableEvery time.Duration
|
||||
PruneSourcesOlderThan time.Duration
|
||||
LegacyVersion int
|
||||
}
|
||||
type Capability struct {
|
||||
Action string
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/rs/zerolog"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
@@ -100,7 +100,7 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("Error reading body of %q: %v", c.url, err)
|
||||
return
|
||||
|
||||
@@ -116,7 +116,7 @@ func (h configHandler) FindPosixAccounts(hierarchy string) (entrylist []*ldap.En
|
||||
|
||||
for _, u := range h.cfg.Users {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{u.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.NameFormat, Values: []string{u.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{u.Name}})
|
||||
|
||||
if len(u.GivenName) > 0 {
|
||||
@@ -210,7 +210,7 @@ func (h configHandler) FindPosixGroups(hierarchy string) (entrylist []*ldap.Entr
|
||||
|
||||
for _, g := range h.cfg.Groups {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{g.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.GroupFormat, Values: []string{g.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{g.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s", g.Name)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "gidNumber", Values: []string{fmt.Sprintf("%d", g.GIDNumber)}})
|
||||
@@ -235,15 +235,21 @@ func (h configHandler) Close(boundDn string, conn net.Conn) error {
|
||||
}
|
||||
|
||||
func (h configHandler) getGroupMemberDNs(gid int) []string {
|
||||
var insertOuUsers string
|
||||
if h.cfg.Behaviors.LegacyVersion > 0 && h.cfg.Behaviors.LegacyVersion <= 20100 {
|
||||
insertOuUsers = ""
|
||||
} else {
|
||||
insertOuUsers = ",ou=users"
|
||||
}
|
||||
members := make(map[string]bool)
|
||||
for _, u := range h.cfg.Users {
|
||||
if u.PrimaryGroup == gid {
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), h.backend.BaseDN)
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
||||
members[dn] = true
|
||||
} else {
|
||||
for _, othergid := range u.OtherGroups {
|
||||
if othergid == gid {
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), h.backend.BaseDN)
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
||||
members[dn] = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,6 @@ func NewLdapHandler(opts ...Option) Handler {
|
||||
return handler
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
|
||||
h.log.Debug().Str("binddn", bindDN).Str("src", conn.RemoteAddr().String()).Msg("Bind request")
|
||||
|
||||
@@ -154,7 +153,6 @@ func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCod
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
|
||||
wantAttributes := true
|
||||
wantTypesOnly := false
|
||||
@@ -362,7 +360,6 @@ func (h *ldapHandler) monitorServers() {
|
||||
}()
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) getSession(conn net.Conn) (ldapSession, error) {
|
||||
id := connID(conn)
|
||||
h.lock.Lock()
|
||||
@@ -399,7 +396,6 @@ func (h ldapHandler) getSession(conn net.Conn) (ldapSession, error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) ping() error {
|
||||
healthy := false
|
||||
for k, s := range h.servers {
|
||||
@@ -442,7 +438,6 @@ func (h ldapHandler) ping() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
func (h ldapHandler) getBestServer() (ldapBackend, error) {
|
||||
favorite := ldapBackend{}
|
||||
forever, err := time.ParseDuration("30m")
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/rs/zerolog"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -371,7 +370,7 @@ func (l LDAPOpsHelper) searchMaybeSchemaQuery(h LDAPOpsHandler, baseDN string, s
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "modifiersName", Values: []string{"cn=Directory Manager"}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "modifyTimeStamp", Values: []string{"Mar 8, 2021, 12:46:29 PM PST (20210308204629Z)"}})
|
||||
// Iterate through schema attributes provided in schema/ directory
|
||||
filenames, _ := ioutil.ReadDir("schema")
|
||||
filenames, _ := os.ReadDir("schema")
|
||||
for _, filename := range filenames {
|
||||
attributename := new(string)
|
||||
*attributename = filename.Name()
|
||||
@@ -530,10 +529,19 @@ func (l LDAPOpsHelper) searchMaybePosixAccounts(h LDAPOpsHandler, baseDN string,
|
||||
hierarchyString = "ou=users"
|
||||
}
|
||||
|
||||
entries, err := h.FindPosixAccounts(hierarchyString)
|
||||
unscopedEntries, err := h.FindPosixAccounts(hierarchyString)
|
||||
if err != nil {
|
||||
return nil, ldap.LDAPResultOperationsError
|
||||
}
|
||||
|
||||
// Filter out entries, that are not in the search base dn
|
||||
entries := []*ldap.Entry{}
|
||||
for _, e := range unscopedEntries {
|
||||
if strings.HasSuffix(e.DN, searchBaseDN) {
|
||||
entries = append(entries, e)
|
||||
}
|
||||
}
|
||||
|
||||
stats.Frontend.Add("search_successes", 1)
|
||||
h.GetLog().Info().Str("filter", searchReq.Filter).Msg("AP: Account Search OK")
|
||||
return entries, ldap.LDAPResultSuccess
|
||||
@@ -614,7 +622,7 @@ func (l LDAPOpsHelper) findUser(h LDAPOpsHandler, bindDN string, checkGroup bool
|
||||
userName := ""
|
||||
if len(parts) == 1 {
|
||||
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormat+"=")
|
||||
} else if len(parts) == 2 || (len(parts) == 3 && parts[2] == fmt.Sprintf("%s=users", h.GetBackend().GroupFormat)) {
|
||||
} else if len(parts) == 2 || (len(parts) == 3 && parts[2] == "ou=users") {
|
||||
userName = strings.TrimPrefix(parts[0], h.GetBackend().NameFormat+"=")
|
||||
groupName = strings.TrimPrefix(parts[1], h.GetBackend().GroupFormat+"=")
|
||||
} else {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/rs/zerolog"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -121,7 +121,7 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
|
||||
}
|
||||
for _, g := range groups {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{*g.ID}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.GroupFormat, Values: []string{*g.ID}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "description", Values: []string{fmt.Sprintf("%s from ownCloud", *g.ID)}})
|
||||
// attrs = append(attrs, &ldap.EntryAttribute{"gidNumber", []string{fmt.Sprintf("%d", g.GIDNumber)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "objectClass", Values: []string{"posixGroup"}})
|
||||
@@ -133,7 +133,7 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
|
||||
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "memberUid", Values: members})
|
||||
}
|
||||
dn := fmt.Sprintf("cn=%s,%s=groups,%s", *g.ID, h.backend.GroupFormat, h.backend.BaseDN)
|
||||
dn := fmt.Sprintf("%s=%s,ou=groups,%s", h.backend.GroupFormat, *g.ID, h.backend.BaseDN)
|
||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
case "posixaccount", "":
|
||||
@@ -151,7 +151,7 @@ func (h ownCloudHandler) Search(bindDN string, searchReq ldap.SearchRequest, con
|
||||
}
|
||||
for _, u := range users {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "cn", Values: []string{*u.ID}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: h.backend.NameFormat, Values: []string{*u.ID}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "uid", Values: []string{*u.ID}})
|
||||
if u.DisplayName != nil {
|
||||
attrs = append(attrs, &ldap.EntryAttribute{Name: "givenName", Values: []string{*u.DisplayName}})
|
||||
@@ -255,7 +255,7 @@ func (s ownCloudSession) getGroups() ([]msgraph.Group, error) {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -326,7 +326,7 @@ func (s ownCloudSession) getUsers(userName string) ([]msgraph.User, error) {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -350,6 +350,12 @@ func (h databaseHandler) memoizeGroups() ([]config.Group, error) {
|
||||
}
|
||||
|
||||
func (h databaseHandler) getGroupMemberDNs(gid int) []string {
|
||||
var insertOuUsers string
|
||||
if h.cfg.Behaviors.LegacyVersion > 0 && h.cfg.Behaviors.LegacyVersion <= 20100 {
|
||||
insertOuUsers = ""
|
||||
} else {
|
||||
insertOuUsers = ",ou=users"
|
||||
}
|
||||
members := make(map[string]bool)
|
||||
|
||||
rows, err := h.database.cnx.Query(`
|
||||
@@ -369,13 +375,13 @@ func (h databaseHandler) getGroupMemberDNs(gid int) []string {
|
||||
return []string{}
|
||||
}
|
||||
if u.PrimaryGroup == gid {
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), h.backend.BaseDN)
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
||||
members[dn] = true
|
||||
} else {
|
||||
u.OtherGroups = h.commaListToIntTable(otherGroups)
|
||||
for _, othergid := range u.OtherGroups {
|
||||
if othergid == gid {
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), h.backend.BaseDN)
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s%s,%s", h.backend.NameFormat, u.Name, h.backend.GroupFormat, h.getGroupName(u.PrimaryGroup), insertOuUsers, h.backend.BaseDN)
|
||||
members[dn] = true
|
||||
}
|
||||
}
|
||||
@@ -510,7 +516,7 @@ func (h databaseHandler) getGroup(hierarchy string, g config.Group) *ldap.Entry
|
||||
asGroupOfUniqueNames := hierarchy == "ou=groups"
|
||||
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"cn", []string{g.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{h.backend.GroupFormat, []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.GIDNumber)}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"uniqueMember", h.getGroupMemberDNs(g.GIDNumber)})
|
||||
@@ -526,7 +532,7 @@ func (h databaseHandler) getGroup(hierarchy string, g config.Group) *ldap.Entry
|
||||
|
||||
func (h databaseHandler) getAccount(hierarchy string, u config.User) *ldap.Entry {
|
||||
attrs := []*ldap.EntryAttribute{}
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"cn", []string{u.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{h.backend.NameFormat, []string{u.Name}})
|
||||
attrs = append(attrs, &ldap.EntryAttribute{"uid", []string{u.Name}})
|
||||
|
||||
if len(u.GivenName) > 0 {
|
||||
|
||||
@@ -23,7 +23,7 @@ debug = true
|
||||
listen = "0.0.0.0:3893"
|
||||
|
||||
[ldaps]
|
||||
# to enable ldaps genrerate a certificate, eg. with:
|
||||
# to enable ldaps generate a certificate, eg. with:
|
||||
# openssl req -x509 -newkey rsa:4096 -keyout glauth.key -out glauth.crt -days 365 -nodes -subj '/CN=`hostname`'
|
||||
enabled = false
|
||||
listen = "0.0.0.0:3894"
|
||||
@@ -37,7 +37,11 @@ debug = true
|
||||
baseDN = "dc=glauth,dc=com"
|
||||
nameformat = "cn"
|
||||
groupformat = "ou"
|
||||
|
||||
|
||||
# If you are using a client that requires reading the root DSE first
|
||||
# such as SSSD
|
||||
# anonymousdse = true
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
dn: ou=superheros,ou=users,dc=glauth,dc=com
|
||||
cn: superheros
|
||||
ou: superheros
|
||||
uid: superheros
|
||||
description: superheros
|
||||
gidNumber: 5501
|
||||
uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=hackers,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=johndoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=johndoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
memberUid: alexdoe
|
||||
memberUid: hackers
|
||||
memberUid: jackdoe
|
||||
@@ -19,26 +19,26 @@ objectClass: posixGroup
|
||||
objectClass: top
|
||||
|
||||
dn: ou=svcaccts,ou=users,dc=glauth,dc=com
|
||||
cn: svcaccts
|
||||
ou: svcaccts
|
||||
uid: svcaccts
|
||||
description: svcaccts
|
||||
gidNumber: 5502
|
||||
uniqueMember: cn=serviceuser,ou=svcaccts,dc=glauth,dc=com
|
||||
uniqueMember: cn=serviceuser,ou=svcaccts,ou=users,dc=glauth,dc=com
|
||||
memberUid: serviceuser
|
||||
objectClass: posixGroup
|
||||
objectClass: top
|
||||
|
||||
dn: ou=vpnaccess,ou=users,dc=glauth,dc=com
|
||||
cn: vpnaccess
|
||||
ou: vpnaccess
|
||||
uid: vpnaccess
|
||||
description: vpnaccess
|
||||
gidNumber: 5503
|
||||
uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=hackers,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=johndoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=johndoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
memberUid: alexdoe
|
||||
memberUid: hackers
|
||||
memberUid: jackdoe
|
||||
@@ -49,17 +49,17 @@ objectClass: posixGroup
|
||||
objectClass: top
|
||||
|
||||
dn: ou=allaccs,ou=users,dc=glauth,dc=com
|
||||
cn: allaccs
|
||||
ou: allaccs
|
||||
uid: allaccs
|
||||
description: allaccs
|
||||
gidNumber: 5504
|
||||
uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=hackers,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=johndoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=serviceuser,ou=svcaccts,dc=glauth,dc=com
|
||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=johndoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=serviceuser,ou=svcaccts,ou=users,dc=glauth,dc=com
|
||||
memberUid: alexdoe
|
||||
memberUid: hackers
|
||||
memberUid: jackdoe
|
||||
@@ -71,14 +71,14 @@ objectClass: posixGroup
|
||||
objectClass: top
|
||||
|
||||
dn: ou=mailadmin,ou=users,dc=glauth,dc=com
|
||||
cn: mailadmin
|
||||
ou: mailadmin
|
||||
uid: mailadmin
|
||||
description: mailadmin
|
||||
gidNumber: 5505
|
||||
uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
memberUid: alexdoe
|
||||
memberUid: jackdoe
|
||||
memberUid: jamesdoe
|
||||
@@ -87,7 +87,7 @@ objectClass: posixGroup
|
||||
objectClass: top
|
||||
|
||||
dn: ou=webmail,ou=users,dc=glauth,dc=com
|
||||
cn: webmail
|
||||
ou: webmail
|
||||
uid: webmail
|
||||
description: webmail
|
||||
gidNumber: 5506
|
||||
@@ -95,14 +95,14 @@ objectClass: posixGroup
|
||||
objectClass: top
|
||||
|
||||
dn: ou=fulltime,ou=users,dc=glauth,dc=com
|
||||
cn: fulltime
|
||||
ou: fulltime
|
||||
uid: fulltime
|
||||
description: fulltime
|
||||
gidNumber: 5507
|
||||
uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,dc=glauth,dc=com
|
||||
uniqueMember: cn=alexdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jackdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=jamesdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
uniqueMember: cn=sarahdoe,ou=superheros,ou=users,dc=glauth,dc=com
|
||||
memberUid: alexdoe
|
||||
memberUid: jackdoe
|
||||
memberUid: jamesdoe
|
||||
|
||||
@@ -88,7 +88,7 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||
// a byte string and given to the value's UnmarshalText method. See the
|
||||
// Unmarshaler example for a demonstration with time duration strings.
|
||||
//
|
||||
// Key mapping
|
||||
// # Key mapping
|
||||
//
|
||||
// TOML keys can map to either keys in a Go map or field names in a Go
|
||||
// struct. The special `toml` struct tag may be used to map TOML keys to
|
||||
|
||||
@@ -10,7 +10,7 @@ The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
|
||||
whether a file is a valid TOML document. It can also be used to print the
|
||||
type of each key in a TOML document.
|
||||
|
||||
Testing
|
||||
# Testing
|
||||
|
||||
There are two important types of tests used for this package. The first is
|
||||
contained inside '*_test.go' files and uses the standard Go unit testing
|
||||
|
||||
@@ -642,7 +642,7 @@ func lexRawString(lx *lexer) stateFn {
|
||||
}
|
||||
|
||||
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
|
||||
// a string. It assumes that the beginning "'''" has already been consumed and
|
||||
// a string. It assumes that the beginning "”'" has already been consumed and
|
||||
// ignored.
|
||||
func lexMultilineRawString(lx *lexer) stateFn {
|
||||
switch lx.next() {
|
||||
|
||||
Reference in New Issue
Block a user