Compare commits

...

19 Commits

Author SHA1 Message Date
Chris F Ravenscroft 7f925565a6 Merge branch 'candlerb-candlerb/rdn' into dev 2023-07-03 22:43:22 +00:00
Chris F Ravenscroft f5ea3d93bf Merge branch 'candlerb/rdn' of github.com:candlerb/glauth into candlerb-candlerb/rdn 2023-07-03 22:37:56 +00:00
Chris F Ravenscroft 34a6b30b8f Feature: introduce legacy behavior, based on past versions (#318) 2023-07-03 15:33:01 -07:00
Chris F Ravenscroft 9bbad511cb Merge branch 'candlerb-candlerb/uniquemember' into dev 2023-07-03 14:59:17 -07:00
Nick Borgers 7cef07931c Update go.work to 1.19 (#315) 2023-05-28 13:18:00 -07:00
Konstantin Shalygin 37fa74892e Added anonymousdse backend option to config sample (#316)
Fixes #83
2023-05-28 13:12:07 -07:00
Nick Borgers efbd64504d add help command to Makefile (#307)
* add fanciness to Makefile
2023-04-22 13:36:40 -07:00
Nick Borgers 1920c4324f Add devcontainer (#306)
* add option for devcontainer
2023-04-22 13:31:35 -07:00
Chris F Ravenscroft 7e7a5f59d1 Update Go Versions to 1.19, 1.20 (#314)
* Update Go Versions to 1.19, 1.20
2023-04-22 13:28:21 -07:00
NW 83f4305e36 searchMaybePosixAccounts: add filter to respect searchBaseDN (#304)
* searchMaybePosixAccounts: add filter to respect searchBaseDN
2023-04-22 13:09:05 -07:00
dependabot[bot] b45259d567 Bump golang.org/x/crypto from 0.0.0-20210711020723-a769d52b0f97 to 0.1.0 in /v2 (#303)
* Bump golang.org/x/crypto in /v2

Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.0.0-20210711020723-a769d52b0f97 to 0.1.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/commits/v0.1.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-22 13:01:02 -07:00
lgtm-com[bot] 3f9f67375f Add CodeQL workflow for GitHub code scanning (#295) 2023-04-22 12:56:32 -07:00
Sven Wick cb761e8e70 Update sample-simple.cfg (#275)
Fix typo
2023-04-22 12:44:03 -07:00
securitytime 7c3314a504 Update README.md (#266)
Fixed a broken link

Co-authored-by: Chris F Ravenscroft <chris@voilaweb.com>
2023-04-22 12:38:28 -07:00
Brian Candler 690917e4e0 Use NameFormat/GroupFormat when constructing RDN attributes
Before:

dn: ou=vpn,ou=users,dc=glauth,dc=com
cn: vpn

After:

dn: ou=vpn,ou=users,dc=glauth,dc=com
ou: vpn    <<< THIS HAS CHANGED

NOTE: whereas previously a search filter (cn=vpn) would have found the
group, now you need (ou=vpn)
2023-04-12 16:23:55 +01:00
Brian Candler 0ccf4926ff Construct DNs under ou=users for uniqueMember group attribute
Before:

dn: ou=vpn,ou=users,dc=glauth,dc=com
...
uniqueMember: cn=hackers,ou=superheros,dc=glauth,dc=com

After:

dn: ou=vpn,ou=users,dc=glauth,dc=com
...
uniqueMember: cn=hackers,ou=superheros,ou=users,dc=glauth,dc=com
                                       ^^^^^^^^
2023-04-12 16:01:07 +01:00
Chris F Ravenscroft 598a688214 CodeSee integration 2022-12-24 13:42:20 -08:00
Chris F Ravenscroft 0e7769ff84 No SysLog on Windows (#289) (#290) 2022-11-12 14:59:43 -08:00
Chris F Ravenscroft 6500bbaf36 No SysLog on Windows (#289) 2022-11-12 14:55:55 -08:00
25 changed files with 368 additions and 122 deletions
+54
View File
@@ -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"
}
+1 -1
View File
@@ -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
+41
View File
@@ -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 }}
+1
View File
@@ -3,3 +3,4 @@ v2/certs/
v2/bin
v2/docker/assets/linux
v2/gl.db
.vscode/
+17 -1
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
go 1.19
use ./v2
+14 -7
View File
@@ -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
#####################
@@ -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..." && \
+1 -40
View File
@@ -17,9 +17,7 @@ import (
"github.com/rs/zerolog"
"gopkg.in/amz.v3/aws"
"gopkg.in/amz.v3/s3"
"io"
"io/ioutil"
"log/syslog"
"net/http"
"os"
"path/filepath"
@@ -768,7 +766,7 @@ func doConfig(checkConfig bool) error {
// Handle logging settings for new config
// - we do this last to make sure we only respect a fully validated config
initLogging(activeConfig.Debug, activeConfig.Syslog, activeConfig.StructuredLog)
log = logging.InitLogging(activeConfig.Debug, activeConfig.Syslog, activeConfig.StructuredLog)
if !checkConfig {
if activeConfig.Debug {
@@ -781,40 +779,3 @@ func doConfig(checkConfig bool) error {
return nil
}
// initLogging sets up logging to stderr
func initLogging(reqdebug bool, reqsyslog bool, reqstructlog bool) {
var level zerolog.Level
if reqdebug {
level = zerolog.DebugLevel
} else {
level = zerolog.InfoLevel
}
var mainWriter io.Writer
if reqstructlog {
// Vroom vroom
mainWriter = os.Stderr
zerolog.TimeFieldFormat = time.RFC1123Z
} else {
// This is the inefficient writer
mainWriter = zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC1123Z}
}
if reqsyslog {
s, err := syslog.New(syslog.LOG_INFO, "glauth")
if err != nil {
fmt.Println("Unable to write to syslog: ignoring...")
reqsyslog = false
} else {
writers := zerolog.MultiLevelWriter(mainWriter, zerolog.SyslogLevelWriter(s))
log = zerolog.New(writers).Level(level).With().Timestamp().Logger()
}
}
if !reqsyslog {
log = zerolog.New(mainWriter).Level(level).With().Timestamp().Logger()
}
logging.RewireLogging(log, reqstructlog)
}
+22 -5
View File
@@ -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,20 +8,37 @@ 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/go-logr/logr v0.4.0
github.com/hydronica/toml v0.4.2
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pquerna/otp v1.3.0
github.com/prometheus/client_golang v1.13.0
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
)
+4 -11
View File
@@ -81,8 +81,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -126,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=
@@ -188,8 +185,6 @@ github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 h1:D9EvfGQvlkKaD
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484/go.mod h1:O1EljZ+oHprtxDDPHiMWVo/5dBT6PlvWX5PSwj80aBA=
github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba h1:DO8NFYdcRv1dnyAINJIBm6Bw2XibtLvQniNFGzf2W8E=
github.com/nmcclain/ldap v0.0.0-20210720162743-7f8d1e44eeba/go.mod h1:4S0XndRL8HNOaQBfdViJ2F/GPCgL524xlXRuXFH12/U=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -255,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=
@@ -315,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=
@@ -335,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=
@@ -377,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=
+1
View File
@@ -3,5 +3,6 @@ package assets
import "embed"
// Content is the embedded assets.
//
//go:embed *.tgz js/* css/* *.html
var Content embed.FS
+1
View File
@@ -60,6 +60,7 @@ type Behaviors struct {
BlockFailedBindsFor time.Duration
PruneSourceTableEvery time.Duration
PruneSourcesOlderThan time.Duration
LegacyVersion int
}
type Capability struct {
Action string
+10 -4
View File
@@ -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
}
}
-5
View File
@@ -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")
+10 -1
View File
@@ -530,10 +530,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
+2 -2
View File
@@ -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"}})
@@ -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}})
+84
View File
@@ -0,0 +1,84 @@
//go:build !windows
// +build !windows
package logging
import (
"fmt"
"github.com/rs/zerolog"
"io"
"log"
"log/syslog"
"os"
"regexp"
"strings"
"time"
)
// We will use this package to wrap log messages coming from libraries who have no interest
// in generating structured output.
var (
ldapliblogmatcher = regexp.MustCompile(`^\d{4}\/\d{1,2}\/\d{1,2} \d{1,2}\:\d{1,2}\:\d{1,2} `)
)
func InitLogging(reqdebug bool, reqsyslog bool, reqstructlog bool) zerolog.Logger {
var level zerolog.Level
if reqdebug {
level = zerolog.DebugLevel
} else {
level = zerolog.InfoLevel
}
var mainWriter io.Writer
if reqstructlog {
// Vroom vroom
mainWriter = os.Stderr
zerolog.TimeFieldFormat = time.RFC1123Z
} else {
// This is the inefficient writer
mainWriter = zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC1123Z}
}
var logr zerolog.Logger
if reqsyslog {
s, err := syslog.New(syslog.LOG_INFO, "glauth")
if err != nil {
fmt.Println("Unable to write to syslog: ignoring...")
reqsyslog = false
} else {
writers := zerolog.MultiLevelWriter(mainWriter, zerolog.SyslogLevelWriter(s))
logr = zerolog.New(writers).Level(level).With().Timestamp().Logger()
}
}
if !reqsyslog {
logr = zerolog.New(mainWriter).Level(level).With().Timestamp().Logger()
}
log.SetOutput(customWriter{logr: logr, structlog: reqstructlog})
return logr
}
type customWriter struct {
logr zerolog.Logger
structlog bool
}
func (e customWriter) Write(p []byte) (int, error) {
submatchall := ldapliblogmatcher.FindAllString(string(p), 1)
var msg string
for _, element := range submatchall {
msg = strings.TrimSpace(string(p[len(element):]))
}
if msg == "" {
msg = strings.TrimSpace(string(p))
}
if e.structlog {
fmt.Fprintf(os.Stderr, "{\"level\":\"info\",\"time\":\"%s\",\"message\":\"%s\"}\n", time.Now().Format(time.RFC1123Z), strings.Replace(strings.TrimSpace(msg), `"`, `\"`, -1))
} else {
e.logr.Info().Msg(msg)
}
return len(p), nil
}
@@ -1,8 +1,12 @@
//go:build windows
// +build windows
package logging
import (
"fmt"
"github.com/rs/zerolog"
"io"
"log"
"os"
"regexp"
@@ -17,8 +21,29 @@ var (
ldapliblogmatcher = regexp.MustCompile(`^\d{4}\/\d{1,2}\/\d{1,2} \d{1,2}\:\d{1,2}\:\d{1,2} `)
)
func RewireLogging(logr zerolog.Logger, reqstructlog bool) {
func InitLogging(reqdebug bool, reqsyslog bool, reqstructlog bool) zerolog.Logger {
var level zerolog.Level
if reqdebug {
level = zerolog.DebugLevel
} else {
level = zerolog.InfoLevel
}
var mainWriter io.Writer
if reqstructlog {
// Vroom vroom
mainWriter = os.Stderr
zerolog.TimeFieldFormat = time.RFC1123Z
} else {
// This is the inefficient writer
mainWriter = zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC1123Z}
}
logr := zerolog.New(mainWriter).Level(level).With().Timestamp().Logger()
log.SetOutput(customWriter{logr: logr, structlog: reqstructlog})
return logr
}
type customWriter struct {
+10 -4
View File
@@ -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 {
+6 -2
View File
@@ -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
+35 -35
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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() {