From 6a3f96c04d418403a8c8c88214679840176eff90 Mon Sep 17 00:00:00 2001 From: Ben Yanke Date: Fri, 20 Jul 2018 23:31:55 -0500 Subject: [PATCH 1/3] Pulling from Dev for v1.1 (#48) Includes a number of fixes and improvements: - Add 2 factor auth (thanks @ryskov) - Dockerfile imporvements - Removing repo cruft - Improving travis builds and integration tests - Fixing broken amazon s3 packages (thanks @ryskov) - Vastly improved version string - now autogenerates based on git status in the repo at the time of build - Starting on travis builds for releases (currently built on my workstation) - Starting framework for unit tests - Add codecov to CI --- .gitignore | 6 + .travis.yml | 45 +- Dockerfile | 9 +- Makefile | 89 +++- README.md | 50 ++- bindata.go | 414 ++++++++++-------- configbackend.go | 115 ++++- glauth.go | 76 +++- glauth_test.go | 32 ++ sample-simple.cfg | 19 +- scripts/docker/start.sh | 4 + scripts/travis/.gitignore | 1 + scripts/travis/good-results/posixAccountList0 | 104 +++++ scripts/travis/good-results/posixGroupList0 | 78 ++++ .../good-results/userFetchNonexistentUser0 | 0 .../good-results/userFetchNonexistentUser1 | 0 scripts/travis/good-results/userFetchTest0 | 16 + scripts/travis/good-results/userFetchTest1 | 25 ++ scripts/travis/good-results/userFetchTest2 | 15 + scripts/travis/good-results/userFetchTest3 | 27 ++ scripts/travis/good-results/userFetchTest4 | 21 + scripts/travis/integration-test.sh | 191 +++++++- scripts/travis/test-config.cfg | 54 ++- 23 files changed, 1166 insertions(+), 225 deletions(-) create mode 100644 glauth_test.go create mode 100644 scripts/travis/.gitignore create mode 100644 scripts/travis/good-results/posixAccountList0 create mode 100644 scripts/travis/good-results/posixGroupList0 create mode 100644 scripts/travis/good-results/userFetchNonexistentUser0 create mode 100644 scripts/travis/good-results/userFetchNonexistentUser1 create mode 100644 scripts/travis/good-results/userFetchTest0 create mode 100644 scripts/travis/good-results/userFetchTest1 create mode 100644 scripts/travis/good-results/userFetchTest2 create mode 100644 scripts/travis/good-results/userFetchTest3 create mode 100644 scripts/travis/good-results/userFetchTest4 diff --git a/.gitignore b/.gitignore index 6bc118b..d3fcf26 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,12 @@ glauth.cfg # Ignore the built binary during testing glauth +# Built binaries bin +bindata.go + .*.swp + +# Ignoring travis CLI tool logs +*travis.log diff --git a/.travis.yml b/.travis.yml index 94f61e7..a3441a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: go +# USE THIS alongside makefile tag detection: $TRAVIS_TAG + go: - - 1.3.x # Test an old version, to be sure it works - 1.9.x # last version - 1.10.x # current version @@ -14,20 +15,26 @@ git: # flunk the build and immediately stop. It's sorta like having # set -e enabled in bash. before_script: - - GO_FILES=$(find . -iname '*.go' -type f | grep -v /vendor/) # All the .go files, excluding vendor/ - #- go get github.com/golang/lint/golint # Linter - #- go get honnef.co/go/tools/cmd/megacheck # Badass static analyzer/linter - # - go get github.com/fzipp/gocyclo + - sudo apt-get -qq update && sudo apt-get install -y ldap-utils oathtool # need this for integration tests + - sudo apt-get -qq update && sudo apt-get install -y go-bindata # need this for makefile + - GO_FILES=$(find . -iname '*.go' -type f | grep -v /vendor/) # All the .go files, excluding vendor/ + #- go get github.com/golang/lint/golint # Linter + #- go get honnef.co/go/tools/cmd/megacheck # Badass static analyzer/linter + # - go get github.com/fzipp/gocyclo # Not sure what this is +# Run bindata for assets + - make bindata # Fetch dependencies - go get -t -v ./... script: + - env # Dump the env to make debugging easier - diff -u <(echo -n) <(gofmt -d ./) # Fail if a .go file hasn't been formatted with 'go fmt' + # - go vet ./... " # go vet is the official Go static analyzer + # - go test -v -race ./... # Run all the tests with the race detector enabled - # - go vet ./... # go vet is the official Go static analyzer # - megacheck ./... # "go vet on steroids" + linter # - gocyclo -over 19 $GO_FILES # forbid code with huge functions # - golint -set_exit_status $(go list ./...) # one last linter @@ -39,11 +46,33 @@ script: # - go test -race -coverprofile=coverage.txt -covermode=atomic # Full compile test - - go build -o ./glauth glauth.go bindata.go ldapbackend.go webapi.go configbackend.go + # - go build -o ./glauth glauth.go bindata.go ldapbackend.go webapi.go configbackend.go + - make all + + # Output hashes to the build log + - cat bin/*.sha256 # Integration test with compiled binary - - scripts/travis/integration-test.sh "scripts/travis/test-config.cfg" + - make test + # after_success: # - bash <(curl -s https://codecov.io/bash) + +deploy: + provider: releases + api_key: + secure: CsQb802CJJlum5suwo3Yvw1TkmX56O6TPrtJqMI0Qm6A878dhrZIjyVmfG3Iq9rtZvfFhK+Y3SIfPZp8BjV3cicc+X1Yh1VvMG12ukqHSruvGvLG49dtnq40P31u85Y4HdBk+W8YIsCQHEonsID9l+q2LbhuiC358UF+HNgzESEz6ZyTZz0AvAJzm1uyiUiPTHMFwqN7qQsookmLXf490rqp9YmFFqte+o3/JwoYXc3pE/rBMJitPSJNGULzu2QofV5gJ0JxgPWlfF5DsHHEi1jhpBcTfiFzEvkdcl1SVme9MMNPue7j8u9+PLJ6uIdlnTeBcMPKgtzOg/kBqY4+3QzY4aPXjKm3+MF3Cau66+g3QC7dKenvYefapQYN7t1SSpiR9X3TLWZrBbw2ovMe3em+uMnIM08bemzj8DapRgKXmYKWnwTlA9KLf0Vl22255OzMGarkhx94cDvUHmEkNo7qBXqmUxPo0Fc5XJyD7JmUNgYoWj0/NjyN09VG22FL2FW44HR3eitq2wSFSMO/jsC2rLuCnyLHViP+O2YJu0T4Q3gdQUcdQmjT7y8ogH5Shn9t2wY4NRxI3MyXO7+fGEOj1DaD6CFQwcSwbJVpIzS6J8z7+rRrzE9QkXeCmwNNt5UkpR9lYmOEzpc00rTRimwjfmJn/nTXsIDiQg9iZJM= + file_glob: true + file: bin/* + draft: true + name: "DRAFT RELEASE: $TRAVIS_TAG" + body: "Draft release, committed with message: $TRAVIS_COMMIT_MESSAGE" + body: "# Commit Details
$TRAVIS_COMMIT_MESSAGE

# Note About Non-Linux 64bit Files
While I expect the code is system-independent, there is not a good (and free) CI system which can be easily used to continuously test releases on ARM, BSD, Linux-32bit, and Windows.

As such, the primary release platform is Linux 64 bit. The extent of testing on these packages consists solely of cross-compiling for these architectures from a linux 64 bit system.

We will accept PRs which fix bugs on these platforms, but be aware these binaries will not be tested regularly, and instead are provided for the convenience of those who feel comfortable using them with this knowledge." + + skip_cleanup: true + on: + branch: master + tags: true + condition: $TRAVIS_GO_VERSION = "1.10.1" diff --git a/Dockerfile b/Dockerfile index 516dabf..30343bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,13 +17,16 @@ ENV GOOS=linux ENV GOARCH=amd64 # Only needed for alpine builds -RUN apk add --no-cache git bzr +RUN apk add --no-cache git bzr make # Install deps RUN go get -d -v ./... -# Build -RUN go build -o /app/glauth glauth.go bindata.go ldapbackend.go webapi.go configbackend.go +# Run go-bindata to embed data for API +RUN go get -u github.com/jteeuwen/go-bindata/... && $GOPATH/bin/go-bindata -pkg=main assets && gofmt -w bindata.go + +# Build and copy final result +RUN make linux64 && cp ./bin/glauth64 /app/glauth ################# # Run Step diff --git a/Makefile b/Makefile index 8d08e03..abc08c0 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,89 @@ VERSION=$(shell bin/glauth64 --version) +GIT_COMMIT=$(shell git rev-list -1 HEAD ) +BUILD_TIME=$(shell date --utc +%Y%m%d_%H%M%SZ) +GIT_CLEAN=$(shell git status | grep -E "working (tree|directory) clean" | wc -l) -run: - go run glauth.go bindata.go ldapbackend.go webapi.go configbackend.go -c glauth.cfg +# 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=-X main.GitCommit=${GIT_COMMIT} -X main.GitBranch=${GIT_BRANCH} -X main.BuildTime=${BUILD_TIME} -X main.GitClean=${GIT_CLEAN} -X main.LastGitTag=${LAST_GIT_TAG} -X main.GitTagIsCommit=${GIT_IS_TAG_COMMIT} +BUILD_FILES=glauth.go bindata.go ldapbackend.go webapi.go configbackend.go + +##################### +# High level commands +##################### + +# Build and run - used for development +run: setup devrun cleanup + +# Run the integration test on linux64 (eventually allow the binary to be set) +test: runtest + +# Run build process for all binaries +all: setup binaries verify cleanup + +# Run build process for only linux64 +fast: setup linux64 verify cleanup + +# list of binary formats to build +binaries: linux32 linux64 linuxarm32 linuxarm64 darwin64 win32 win64 + +# Setup commands to always run +setup: bindata format + +##################### +# Subcommands +##################### + +# Run integration test +runtest: + ./scripts/travis/integration-test.sh cleanup -all: bindata binaries -binaries: bindata linux32 linux64 darwin64 bindata: - go-bindata -pkg=main assets + go get -u github.com/jteeuwen/go-bindata/... && ${GOPATH}/bin/go-bindata -pkg=main assets && gofmt -w bindata.go -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 +cleanup: + rm bindata.go -darwin64: bindata - GOOS=darwin GOARCH=amd64 go build -o bin/glauthOSX glauth.go bindata.go ldapbackend.go webapi.go configbackend.go +format: + go fmt +devrun: + go run ${BUILD_FILES} -c glauth.cfg + + +linux32: + GOOS=linux GOARCH=386 go build -ldflags "${BUILD_VARS}" -o bin/glauth32 ${BUILD_FILES} && cd bin && sha256sum glauth32 > glauth32.sha256 + +linux64: + GOOS=linux GOARCH=amd64 go build -ldflags "${BUILD_VARS}" -o bin/glauth64 ${BUILD_FILES} && cd bin && sha256sum glauth64 > glauth64.sha256 + +linuxarm32: + GOOS=linux GOARCH=386 go build -ldflags "${BUILD_VARS}" -o bin/glauth-arm32 ${BUILD_FILES} && cd bin && sha256sum glauth-arm32 > glauth-arm32.sha256 + +linuxarm64: + GOOS=linux GOARCH=arm64 go build -ldflags "${BUILD_VARS}" -o bin/glauth-arm64 ${BUILD_FILES} && cd bin && sha256sum glauth-arm64 > glauth-arm64.sha256 + +darwin64: + GOOS=darwin GOARCH=amd64 go build -ldflags "${BUILD_VARS}" -o bin/glauthOSX ${BUILD_FILES} && cd bin && sha256sum glauthOSX > glauthOSX.sha256 + +win32: + GOOS=windows GOARCH=386 go build -ldflags "${BUILD_VARS}" -o bin/glauth-win32 ${BUILD_FILES} && cd bin && sha256sum glauth-win32 > glauth-win32.sha256 + +win64: + GOOS=windows GOARCH=amd64 go build -ldflags "${BUILD_VARS}" -o bin/glauth-win64 ${BUILD_FILES} && cd bin && sha256sum glauth-win64 > glauth-win64.sha256 + + +verify: + cd bin && sha256sum *.sha256 -c && cd ../; diff --git a/README.md b/README.md index 167886a..86ab744 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,16 @@ This quickstart is a great way to try out GLAuth in a non-production environment - For example: `ldapsearch -LLL -H ldap://localhost:389 -D cn=serviceuser,ou=svcaccts,dc=glauth,dc=com -w mysecret -x -bdc=glauth,dc=com cn=hackers` + +### Make Commands + +Note - makefile uses git data to inject build-time variables. For best results, run in the context of the git repo. + +*make all* - run build binaries for platforms +*make fast* - run build for only linux 64 bit +*make run* - wrapper for the 'go run' command, setting up the needed tooling +*make test* - run the integration test on linux64 binary + ### Usage: ``` glauth: securely expose your LDAP for external auth @@ -95,6 +105,10 @@ More configuration options are documented here: https://github.com/nmcclain/glau * Specify an array of public keys ### Optional Fields + * otherGroups + * Array of IDs of groups the user is a member of. + * Example: [5501, 5002] + * default = blank * givenname * First name * Example: John @@ -119,11 +133,39 @@ More configuration options are documented here: https://github.com/nmcclain/glau * Specify an overridden home directory for the user * Example: /home/itadmin * default = /home/[username] + * otpsecret + * Specify OTP secret used to validate OTP passcode + * Example: 3hnvnk4ycv44glzigd6s25j4dougs3rk + * default = blank + * yubikey + * Specify Yubikey ID for maching Yubikey OTP against the user + * Example: cccjgjgkhcbb + * default = blank ### 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 + +### Two Factor Authentication +GLAuth can be configured to accept OTP tokens as appended to a users password. Support is added for both **TOTP tokens** (often known by it's most prominent implementation, "Google Authenticator") and **Yubikey OTP tokens**. + +When using 2FA, append the 2FA code to the end of the password when authenticating. For example, if your password is "monkey" and your otp is "123456", enter "monkey123456" as your password. + +#### TOTP Configuration +To enable TOTP authentication on a user, you can use a tool [like this](https://freeotp.github.io/qrcode.html) to generate a QR code (pick 'Timeout' and optionally let it generate a random secret for you), which can be scanned and used with the [Google Authenticator](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en) app. To enable TOTP authentication, configure the `otpsecret` for the user with the TOTP secret. + +#### Yubikey Configuration +For Yubikey OTP token authentication, first [configure your Yubikey](https://www.yubico.com/products/services-software/personalization-tools/yubikey-otp/). After this, make sure to [request a `Client ID` and `Secret key` pair](https://upgrade.yubico.com/getapikey/). + +Now configure the the `yubikeyclientid` and `yubikeysecret` fields in the general section in the configuration file. + +To enable Yubikey OTP authentication for a user, you must specify their Yubikey ID on the users `yubikey` field. The Yubikey ID is the first 12 characters of the Yubikey OTP, as explained in the below chart. + +![Yubikey OTP](https://developers.yubico.com/OTP/otp_details.png) + +When a user has been configured with either one of the OTP options, the OTP authentication is required for the user. If both are configured, either one will work. + ### 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. ```toml @@ -136,11 +178,17 @@ For advanced users, GLAuth supports pluggable backends. Currently, it can use a Any of the architectures above will work for production. Just remember: * Always use legit SSL certs for production! + +# Other Architectures +A small note about other architectures: while I expect the code is, for the most part, system-independent, there is not a good (and free) CI system which can be easily used to continuously test releases on ARM, BSD, Linux-32bit, and Windows. As such, all of the non-linux-64bit packages are provided as is. The extent of testing on these packages consists solely of cross-compiling for these architectures from a linux 64 bit system. + +We will accept PRs which fix bugs on these platforms, but be aware these binaries will not be tested regularly, and instead are provided for the convenience of those who feel comfortable with this. ### Building: -You'll need go-bindata to build GLAuth: +You'll need go-bindata to build GLAuth. Then use the Makefile. ```unix go get github.com/jteeuwen/go-bindata/... +make all ``` ### Support diff --git a/bindata.go b/bindata.go index 1ec8585..fccfd16 100644 --- a/bindata.go +++ b/bindata.go @@ -1,3 +1,10 @@ +// Code generated by go-bindata. +// sources: +// assets/glauth.css +// assets/glauth.js +// assets/index.html +// DO NOT EDIT! + package main import ( @@ -5,9 +12,14 @@ import ( "compress/gzip" "fmt" "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" ) -func bindata_read(data []byte, name string) ([]byte, error) { +func bindataRead(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) @@ -15,207 +27,257 @@ func bindata_read(data []byte, name string) ([]byte, error) { var buf bytes.Buffer _, err = io.Copy(&buf, gz) - gz.Close() + clErr := gz.Close() if err != nil { return nil, fmt.Errorf("Read %q: %v", name, err) } + if clErr != nil { + return nil, 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, - }, +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _assetsGlauthCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x8f\x41\x6e\xc3\x20\x10\x45\xf7\x9c\x62\x24\xaf\x63\xd9\x0e\x4e\xc1\x39\x0d\x03\x63\x9b\xd6\x01\x04\xa4\xad\x5a\xf5\xee\x95\x1d\x39\x2a\xc9\xa6\xeb\xff\xfe\x7f\x33\xac\x7e\xbd\x5e\xd0\xe7\xe8\x1d\x7c\x33\x00\xed\x17\x1f\x07\xa8\x74\x73\x94\x1d\x9e\x19\x00\x2a\xfd\x36\x45\x7f\x75\xe6\xb0\x87\xa4\xc7\x66\x6c\xcf\xec\x87\xb1\x2a\x65\x95\x53\x50\x8e\x96\xa2\x7f\xe4\x5c\xf6\xf4\x84\xd4\x17\xca\xd1\xea\x07\x54\x0a\x83\x7f\xd0\x22\x95\xd8\x4b\x3c\xad\x87\x04\x65\x8c\x75\xd3\x00\x22\x7c\xae\x74\x95\x28\xbe\x53\xfc\x2f\xce\xe6\x6e\x25\x77\xb0\x93\xa2\x41\x79\xb3\x66\x65\x17\xc8\x73\x31\xf4\x32\x0a\x2d\xcc\xe6\xb9\xc5\x66\x8b\xef\xab\x7c\x5d\x7d\xfe\x17\x60\xf4\x2e\x1f\x92\xfd\xa2\x01\xda\x5d\xbd\x4f\xd4\x3e\x14\x12\x41\x9c\x2b\x73\x6f\x7d\x90\x9d\xe6\x3c\x00\xfa\xa5\x30\xd7\x3e\xd4\x68\x9d\x29\xba\xed\x49\x35\xa2\x7f\xc4\x12\xa9\xa8\xcb\x4f\x5a\x85\x5a\xea\xed\x8e\xdf\x00\x00\x00\xff\xff\x91\x33\xcc\x6e\xee\x01\x00\x00") + +func assetsGlauthCssBytes() ([]byte, error) { + return bindataRead( + _assetsGlauthCss, "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, - }, +func assetsGlauthCss() (*asset, error) { + bytes, err := assetsGlauthCssBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "assets/glauth.css", size: 494, mode: os.FileMode(436), modTime: time.Unix(1524616076, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _assetsGlauthJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x54\xd1\x8a\xdb\x30\x10\x7c\xf7\x57\x6c\xdd\xc0\xc9\x34\x95\x43\x5f\x43\xfa\x76\x70\x29\xf4\x0a\x6d\x7e\x40\xb1\xd6\x89\xa8\x2c\x99\xf5\xc6\x69\x39\xfc\xef\x45\x96\x9d\xf8\x72\x77\x70\xc5\x2f\x49\xd8\x9d\x99\x8c\x35\x63\xb5\x8a\xc0\x38\x46\x6a\x95\x85\x0d\x7c\x59\xad\x56\xeb\x24\x59\x88\xf2\xe4\x0a\x36\xde\x89\x0c\x9e\x12\x80\x53\xad\x15\xe3\x77\x64\x32\x45\x23\xb2\x75\x02\x90\xe7\x71\xb8\x53\xc6\x86\x49\x97\xad\x93\x24\xc8\xb1\x32\x76\xab\x61\x03\x41\x69\xd4\xb9\x55\xe8\x55\x03\xba\x8a\x13\xd8\xc0\x42\x1e\x90\xbf\xfd\xfa\xf1\x28\x20\xcd\x35\xee\x4f\x87\xbc\x55\xd4\xa4\x4b\xb8\x98\xd1\x91\x17\x99\x8c\x55\x6d\x15\x23\x6c\xe0\x41\x39\x6d\x71\xaf\xa8\x91\x85\xaf\x6a\x63\x51\xc0\x42\xa4\x1f\x1b\x56\xdc\xd4\xca\xa1\xfd\x3c\xa2\xd3\x4c\x1e\xb9\xb2\x22\x83\xfe\x29\xa2\x54\x98\x84\xdf\x9b\x8b\xa8\xd0\xc3\xfa\xb9\xcc\xc8\x0e\x1f\x13\xfe\x7b\xad\xcc\x77\x31\xc3\x00\x52\x8b\x34\xd3\x42\xd4\x78\x61\xa2\xcb\x12\x00\x59\x86\x26\xdc\x14\xe7\xad\x03\x4c\xef\x89\x3c\x7d\x48\x27\x74\x65\xcf\xea\x6f\xf3\x52\xa0\x41\xde\x99\x0a\xfd\x89\xc5\xb3\x12\x2d\xc7\xde\x0e\x1a\xeb\xa4\xbb\xad\x5b\xec\xe6\xa5\x6b\xa1\x99\xb7\x45\x0b\xb3\x3c\x85\x4f\x63\x6d\x5f\x6b\x9b\x96\xa5\xa7\x7b\x55\x1c\xaf\xe6\x70\xdc\x01\x98\x12\x04\xca\xad\x86\xaf\x83\xc6\x75\x05\xd7\x97\x21\x20\xd6\xc3\xb8\xeb\xbf\xbb\xff\xcb\x2f\x28\xcd\x08\xaf\xcf\x4a\x1e\x8d\x46\x91\xc9\x9a\xb0\x46\xa7\x77\x7e\xd0\x4d\x33\x59\x2a\x8d\x5b\x27\xc2\x05\xf0\xae\x48\x07\xda\xec\x30\x43\x44\xaf\x25\x99\x4c\xce\x81\xf0\x60\x1a\x46\x7a\x40\x5b\x23\x89\xbb\xc0\xfb\x89\x56\xb1\x69\xf1\x6e\x12\x58\xe1\x1d\xe3\x1f\x5e\xc2\xde\xfa\xe2\x77\xfc\xcb\x90\xce\xd9\x38\xed\xcf\xb2\xf2\x15\x3a\x1e\x9d\xe4\x39\x21\x9f\xc8\x41\x1c\x8f\xe4\x4c\x96\xe4\xab\x47\x7f\x16\xc3\xd1\xbd\x85\xf2\x54\x29\x8e\xa0\x0e\x6d\x83\x4f\x53\xf4\x00\xeb\x97\xc3\xd5\xf8\x2f\x00\x00\xff\xff\x1d\x12\x43\xad\x6a\x05\x00\x00") + +func assetsGlauthJsBytes() ([]byte, error) { + return bindataRead( + _assetsGlauthJs, "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, - }, +func assetsGlauthJs() (*asset, error) { + bytes, err := assetsGlauthJsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "assets/glauth.js", size: 1386, mode: os.FileMode(436), modTime: time.Unix(1526347681, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _assetsIndexHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x57\x6d\x6f\xdb\x36\x10\xfe\x9e\x5f\x71\xd1\xbe\x4e\x62\xed\xae\x5b\x17\xc8\x06\xba\x34\x5b\x03\xb4\x6b\x90\x76\xd8\x86\xa2\x28\x68\xf1\x6c\xd1\xa1\x48\x85\x77\x72\x62\x08\xfa\xef\x03\x2d\xbf\xc9\x73\x12\xc7\xd8\xbe\xd8\x22\xf9\xdc\xcb\xf3\xf0\x8e\xa2\xd2\xd3\xb7\x1f\xcf\x3f\xff\x7d\x75\x01\x39\x17\x66\x78\x92\x86\x3f\x30\xd2\x4e\x06\x11\xda\x68\x78\x02\x90\xe6\x28\x55\x78\x00\x48\x0b\x64\x09\x59\x2e\x3d\x21\x0f\xa2\x8a\xc7\xf1\xeb\x68\x7b\x29\x67\x2e\x63\xbc\xad\xf4\x6c\x10\xfd\x15\xff\xf1\x26\x3e\x77\x45\x29\x59\x8f\x0c\x46\x90\x39\xcb\x68\x79\x10\x5d\x5e\x0c\x50\x4d\xb0\x63\x69\x65\x81\x83\x68\xa6\xf1\xae\x74\x9e\xb7\xc0\x77\x5a\x71\x3e\x50\x38\xd3\x19\xc6\x8b\xc1\xf7\xa0\xad\x66\x2d\x4d\x4c\x99\x34\x38\xe8\xed\x71\xa4\x90\x32\xaf\x4b\xd6\xce\x6e\xf9\xda\x03\x94\x15\xe7\xce\x77\x31\x2d\x88\x35\x1b\x1c\xfe\xf6\xfe\x4d\xc5\x39\x7c\x62\xc9\x15\xa5\xa2\x9d\x5c\x22\x8c\xb6\x37\xe0\xd1\x0c\x22\xe2\xb9\x41\xca\x11\x39\x82\xdc\xe3\x78\x10\x05\x25\xe8\x4c\x88\x42\xde\x67\xca\x26\x23\xe7\x98\xd8\xcb\x32\x0c\x32\x57\x88\xf5\x84\x78\x99\xf4\x93\x17\x22\x23\xda\xcc\x25\x85\xb6\x49\x46\xb4\xca\xf7\x7f\x0b\x14\x73\x8e\x05\x3e\x27\x9c\x24\x42\x26\x31\x31\x41\xb8\xa5\x51\x6b\x75\x1a\xc7\xf0\xee\xf3\x87\xf7\xaf\x80\x72\x5d\x80\xb4\x0a\xae\x91\x4a\x67\x55\x32\x25\xb8\xbc\x78\x0d\x54\x95\x61\x73\xc1\x8d\x97\x40\x34\x58\xa0\x65\x5a\x80\x0b\x54\x5a\xc2\x6d\x85\x5e\x23\x41\x1c\x0f\xd7\x6e\xbf\xe8\x31\x18\x86\xcb\x0b\xf8\xf9\x6b\x3b\x0b\x90\xb6\xfb\x0b\xe4\xb3\x8d\x06\x8e\x28\x59\xea\x10\xa8\x87\x5a\x7e\x45\xb9\x9e\x89\x97\xc9\x4f\x49\x7f\x33\x5e\x10\x9e\x52\x34\x4c\x45\xeb\xe6\x39\x5e\x7d\x4b\x4a\xf4\x92\x1f\x92\xfe\x6a\xf4\x80\xc7\xf4\xf4\x0b\x5a\xa5\xc7\x5f\x5b\x3a\xa9\x68\x7b\x29\x3c\x8e\x9c\x9a\x83\x77\x26\x14\xab\xcb\xaa\xa0\xc3\x5a\x4a\xa5\x67\x90\x19\x49\x34\x88\x42\x5d\x4a\x6d\xd1\xc3\x62\xab\x62\xca\xdd\x5d\x26\x09\xa3\xa5\x6d\x21\xb5\x5d\xd9\x2d\x37\xe1\x83\xd4\x16\xa6\x55\x31\x72\xec\x9d\x85\xb1\xf3\x20\xa1\xf4\xba\x90\x7e\x0e\x85\xf4\x37\xc8\xda\x4e\xa0\x40\x22\x39\x41\x70\x1e\x32\x69\x0c\xb0\x03\x99\x85\x86\x59\x6b\xdf\xcd\x64\xed\x31\x5a\xad\xae\x11\x5a\x85\x52\x91\x4c\xa5\xb4\x68\xa2\x95\xc5\x62\x04\x8b\xdf\x58\xe1\x58\x56\x86\xa1\xac\x8c\x89\xbd\x9e\xe4\xdc\x75\x23\x94\x9e\x6d\x26\xd2\xbc\xb7\xec\xbc\x54\xe4\xbd\xad\xf9\x72\xf8\x39\xd7\x04\xec\x9c\x01\x4d\xa0\x2d\x28\x9c\xa1\x71\x65\xd0\x0f\x62\xb0\x8e\xe1\xb6\xd2\x8c\xe0\x51\xaa\xf9\x82\x7c\xe9\x9d\xaa\x16\xcc\x4e\x53\x51\x6e\xb4\x6a\x43\xee\x61\xea\xdd\xdd\x56\x72\xdd\xdd\x30\xf1\x3d\xc5\xbd\x3e\x84\x27\x2a\xe2\x1f\xbb\x2c\xf2\xfe\x70\xa1\x43\x2a\xf2\xfe\xc3\x2a\x45\x4f\x48\xba\xa3\x45\x27\xcf\x67\xe7\x33\x92\xd9\x0d\x5a\x05\x84\x7e\x86\xfe\x91\xcc\xda\xf5\xa3\x72\xfb\x77\xa2\xed\x73\x5b\x8f\x62\x53\xc3\xa1\xb2\x4e\xb6\x1b\xad\x5b\x39\x31\x63\x51\x1a\xc9\x18\x01\xcf\x4b\x1c\x44\x8c\xf7\x2c\xee\xe3\x5c\x5a\x65\x70\x24\x3d\x6d\x10\xfb\x37\xa8\x75\x13\x7a\xab\x93\x76\x08\x58\x4a\xbb\x42\x15\xc8\x5e\x67\xd1\xb0\xf4\xee\x7e\x9e\x04\xda\xda\xd9\xb3\x54\x04\xcc\x10\xea\xba\x33\xdf\x34\xe9\xc8\xef\xa5\xbc\xe9\xf5\xfd\x9c\x8e\xa1\xf3\x70\x9e\xdf\xc6\x7e\xf1\x8e\x52\xc9\x48\x5b\xf5\xcd\xe3\x2d\xed\xa6\xbc\x07\xd2\xc9\xfe\x60\xe7\x54\x65\x19\x12\xe1\x53\x11\xd6\xb8\xe3\xc2\xa0\xf7\xce\x3f\x15\xa3\x05\x3d\x3b\x00\xa1\xf4\x59\xfe\x84\x4c\x5b\xa0\x63\x03\x1c\x20\xd5\x2e\xf2\xd8\x50\x4f\xc9\xd5\x81\x3d\x3b\x48\x66\xdc\xa3\x2c\xda\xf5\x2d\xb7\x8f\x95\x7f\x7b\x98\x1c\xd3\x00\x75\xfd\x1d\xca\x2c\x87\x36\xfa\xf2\xf4\x4a\x96\x0e\x9b\xe6\xe4\xd1\x86\xae\xeb\x4f\x59\x78\x4d\x36\xcd\x99\x10\x75\xfd\xce\x11\x87\x6b\x5e\xd3\x9c\xd5\xf5\x95\xf3\xdc\x34\x1b\x7a\x57\xda\x4e\x9a\x06\xea\xba\xbd\xdb\x35\x0d\x6c\x09\x56\xd7\x22\x64\xb1\x8c\xf7\x08\x53\x96\xfa\xa8\x63\x2b\xe5\x70\x48\x6d\x8e\x95\x15\x6d\xce\x75\x87\x25\xfb\x15\xc7\xdd\x03\x8d\xd5\x6a\xc5\x95\x50\xd7\x1f\xcb\xa6\x09\x02\x84\xff\x54\xb0\x3a\x0c\xfd\x8b\xb6\xea\xed\xef\xcf\xb1\xf8\xb4\x28\xb2\x6b\xbc\x4d\x7e\xd5\x86\xd1\x3f\x61\x1b\x4c\xae\x91\x2a\xc3\xe7\x4e\xe1\x01\xe0\x95\xff\x60\x42\x07\xe0\xcf\x8d\x46\xcb\x97\x57\x07\x40\x95\x64\xbc\x46\x23\x59\xcf\x10\xfe\xcc\xd1\xee\xda\xa4\x82\xfd\xf6\x96\x6c\xd7\x40\x77\xcb\x1e\xa8\x88\xce\xbd\x51\x4e\xe5\x7d\x32\x71\x6e\x62\x50\x96\x9a\x16\x97\xc7\x30\x27\x8c\x1e\x91\x98\x86\x9b\xee\x5c\xf4\x92\x5e\x2f\xe9\x2d\x47\x0f\xdd\x22\xf7\x79\x3f\xf4\xbe\x3f\xdd\xfd\xae\x38\xd0\x7f\xa6\xec\x94\x42\xd3\x57\x6a\x6c\xa4\xc7\x9d\xf4\x37\xb5\x9d\x4c\x49\xf4\x93\x17\xc9\x8b\xed\xb9\xff\x2e\x50\xe1\xc2\xd5\xae\x0d\xf2\x3a\x79\xb9\x1c\xc7\x77\x9a\xf3\xd8\xb8\xf0\x01\x78\x50\xb4\xee\x77\xcb\x2e\x38\x15\xed\xd6\xa6\xa2\xfd\x0c\xfe\x27\x00\x00\xff\xff\x08\x9c\x44\x70\x17\x0f\x00\x00") + +func assetsIndexHtmlBytes() ([]byte, error) { + return bindataRead( + _assetsIndexHtml, "assets/index.html", ) } +func assetsIndexHtml() (*asset, error) { + bytes, err := assetsIndexHtmlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "assets/index.html", size: 3863, mode: os.FileMode(436), modTime: time.Unix(1524616076, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + // 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() + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil } 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, +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "assets/glauth.css": assetsGlauthCss, + "assets/glauth.js": assetsGlauthJs, + "assets/index.html": assetsIndexHtml, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} + +var _bintree = &bintree{nil, map[string]*bintree{ + "assets": &bintree{nil, map[string]*bintree{ + "glauth.css": &bintree{assetsGlauthCss, map[string]*bintree{}}, + "glauth.js": &bintree{assetsGlauthJs, map[string]*bintree{}}, + "index.html": &bintree{assetsIndexHtml, map[string]*bintree{}}, + }}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } diff --git a/configbackend.go b/configbackend.go index e7722d3..f02d00a 100644 --- a/configbackend.go +++ b/configbackend.go @@ -4,19 +4,23 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "github.com/GeertJohan/yubigo" "github.com/nmcclain/ldap" + "github.com/pquerna/otp/totp" "net" + "sort" "strings" ) type configHandler struct { - cfg *config + cfg *config + yubikeyAuth *yubigo.YubiAuth } -func newConfigHandler(cfg *config) Backend { +func newConfigHandler(cfg *config, yubikeyAuth *yubigo.YubiAuth) Backend { handler := configHandler{ - cfg: cfg, - } + cfg: cfg, + yubikeyAuth: yubikeyAuth} return handler } @@ -24,12 +28,15 @@ func newConfigHandler(cfg *config) Backend { 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()) + + log.Debug(fmt.Sprintf("Bind request: bindDN: %s, BaseDN: %s, source: %s", bindDN, h.cfg.Backend.BaseDN, conn.RemoteAddr().String())) + stats_frontend.Add("bind_reqs", 1) - // parse the bindDN + // parse the bindDN - ensure that the bindDN ends with the BaseDN if !strings.HasSuffix(bindDN, baseDN) { log.Warning(fmt.Sprintf("Bind Error: BindDN %s not our BaseDN %s", bindDN, h.cfg.Backend.BaseDN)) + // log.Warning(fmt.Sprintf("Bind Error: BindDN %s not our BaseDN %s", bindDN, baseDN)) return ldap.LDAPResultInvalidCredentials, nil } parts := strings.Split(strings.TrimSuffix(bindDN, baseDN), ",") @@ -54,7 +61,7 @@ func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultC } } if !found { - log.Warning(fmt.Sprintf("Bind Error: User %s not found.", user)) + log.Warning(fmt.Sprintf("Bind Error: User %s not found.", userName)) return ldap.LDAPResultInvalidCredentials, nil } // find the group @@ -67,7 +74,7 @@ func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultC } } if !found { - log.Warning(fmt.Sprintf("Bind Error: Group %s not found.", group)) + log.Warning(fmt.Sprintf("Bind Error: Group %s not found.", groupName)) return ldap.LDAPResultInvalidCredentials, nil } // validate group membership @@ -76,6 +83,42 @@ func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultC return ldap.LDAPResultInvalidCredentials, nil } + validotp := false + + if len(user.Yubikey) == 0 && len(user.OTPSecret) == 0 { + validotp = true + } + + if len(user.Yubikey) > 0 && h.yubikeyAuth != nil { + if len(bindSimplePw) > 44 { + otp := bindSimplePw[len(bindSimplePw)-44:] + yubikeyid := otp[0:12] + bindSimplePw = bindSimplePw[:len(bindSimplePw)-44] + + if user.Yubikey == yubikeyid { + _, ok, _ := h.yubikeyAuth.Verify(otp) + + if ok { + validotp = true + } + } + } + } + + if len(user.OTPSecret) > 0 && !validotp { + if len(bindSimplePw) > 6 { + otp := bindSimplePw[len(bindSimplePw)-6:] + bindSimplePw = bindSimplePw[:len(bindSimplePw)-6] + + validotp = totp.Validate(otp, user.OTPSecret) + } + } + + if !validotp { + log.Warning(fmt.Sprintf("Bind Error: invalid token as %s from %s", bindDN, conn.RemoteAddr().String())) + return ldap.LDAPResultInvalidCredentials, nil + } + // finally, validate user's pw hash := sha256.New() hash.Write([]byte(bindSimplePw)) @@ -171,7 +214,7 @@ func (h configHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn 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)}) + attrs = append(attrs, &ldap.EntryAttribute{"memberOf", h.getGroupDNs(append(u.OtherGroups, u.PrimaryGroup))}) if len(u.SSHKeys) > 0 { attrs = append(attrs, &ldap.EntryAttribute{"sshPublicKey", u.SSHKeys}) } @@ -206,10 +249,28 @@ func (h configHandler) getGroupMembers(gid int) []string { } } } + + for _, g := range h.cfg.Groups { + if gid == g.UnixID { + for _, includegroupid := range g.IncludeGroups { + if includegroupid != gid { + includegroupmembers := h.getGroupMembers(includegroupid) + + for _, includegroupmember := range includegroupmembers { + members[includegroupmember] = true + } + } + } + } + } + m := []string{} for k, _ := range members { m = append(m, k) } + + sort.Strings(m) + return m } @@ -227,14 +288,34 @@ func (h configHandler) getGroupMemberIDs(gid int) []string { } } } + + for _, g := range h.cfg.Groups { + if gid == g.UnixID { + for _, includegroupid := range g.IncludeGroups { + if includegroupid == gid { + log.Warning(fmt.Sprintf("Group: %d - Ignoring myself as included group", includegroupid)) + } else { + includegroupmemberids := h.getGroupMemberIDs(includegroupid) + + for _, includegroupmemberid := range includegroupmemberids { + members[includegroupmemberid] = true + } + } + } + } + } + m := []string{} for k, _ := range members { m = append(m, k) } + + sort.Strings(m) + return m } -// +// Converts an array of GUIDs into an array of DNs func (h configHandler) getGroupDNs(gids []int) []string { groups := make(map[string]bool) for _, gid := range gids { @@ -243,12 +324,26 @@ func (h configHandler) getGroupDNs(gids []int) []string { dn := fmt.Sprintf("cn=%s,ou=groups,%s", g.Name, h.cfg.Backend.BaseDN) groups[dn] = true } + + for _, includegroupid := range g.IncludeGroups { + if includegroupid == gid && g.UnixID != gid { + includegroupdns := h.getGroupDNs([]int{g.UnixID}) + + for _, includegroupdn := range includegroupdns { + groups[includegroupdn] = true + } + } + } } } + g := []string{} for k, _ := range groups { g = append(g, k) } + + sort.Strings(g) + return g } diff --git a/glauth.go b/glauth.go index af33184..db74f28 100644 --- a/glauth.go +++ b/glauth.go @@ -4,6 +4,7 @@ import ( "expvar" "fmt" "github.com/BurntSushi/toml" + "github.com/GeertJohan/yubigo" "github.com/docopt/docopt-go" "github.com/nmcclain/ldap" "github.com/op/go-logging" @@ -13,7 +14,13 @@ import ( "strings" ) -var version = "1.0.1" +// Set with buildtime vars +var LastGitTag string +var BuildTime string +var GitCommit string +var GitClean string +var GitBranch string +var GitTagIsCommit string const programName = "glauth" @@ -73,6 +80,8 @@ type configUser struct { PassSHA256 string PrimaryGroup int SSHKeys []string + OTPSecret string + Yubikey string Disabled bool UnixID int Mail string @@ -82,13 +91,16 @@ type configUser struct { Homedir string } type configGroup struct { - Name string - UnixID int + Name string + UnixID int + IncludeGroups []int } type config struct { API configAPI Backend configBackend Debug bool + YubikeyClientID string + YubikeySecret string Frontend configFrontend Groups []configGroup Syslog bool @@ -101,6 +113,48 @@ type config struct { var log = logging.MustGetLogger(programName) +// 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 getVersionString() string { + + var versionstr string + + versionstr = "GLauth" + + // Notate the git context of the build + switch { + // If a release, use the tag + case GitClean == "1" && GitTagIsCommit == "1": + versionstr += " " + LastGitTag + "\n\n" + + // If this branch had a tag before, mention the branch and the tag to give a rough idea of the base version + case len(GitBranch) > 1 && len(LastGitTag) > 1: + versionstr += "\nNon-release build from branch " + GitBranch + ", based on tag " + LastGitTag + "\n\n" + + // If no previous tag specified, just mention the branch + case len(GitBranch) > 1: + versionstr += "\nNon-release build from branch " + GitBranch + "\n\n" + + // Fallback message, if all else fails + default: + versionstr += "\nNon-release build\n\n" + } + + // Include build time + if len(BuildTime) > 1 { + versionstr += "Build time: " + BuildTime + "\n" + } + + // Add commit hash + if GitClean == "1" && len(GitCommit) > 1 { + versionstr += "Commit: " + GitCommit + "\n" + } + + return versionstr + +} + func main() { stderr := initLogging() log.Debug("AP start") @@ -114,7 +168,7 @@ func main() { } // stats - stats_general.Set("version", stringer(version)) + stats_general.Set("version", stringer(LastGitTag)) // web API if cfg.API.Enabled { @@ -122,6 +176,16 @@ func main() { go RunAPI(cfg) } + yubiAuth := (*yubigo.YubiAuth)(nil) + + if len(cfg.YubikeyClientID) > 0 && len(cfg.YubikeySecret) > 0 { + yubiAuth, err = yubigo.NewYubiAuth(cfg.YubikeyClientID, cfg.YubikeySecret) + + if err != nil { + log.Fatalf("Yubikey Auth failed") + } + } + // configure the backend s := ldap.NewServer() s.EnforceLDAP = true @@ -130,7 +194,7 @@ func main() { case "ldap": handler = newLdapHandler(cfg) case "config": - handler = newConfigHandler(cfg) + handler = newConfigHandler(cfg, yubiAuth) default: log.Fatalf("Unsupported backend %s - must be 'config' or 'ldap'.", cfg.Backend.Datastore) } @@ -161,7 +225,7 @@ func doConfig() (*config, error) { cfg.Frontend.TLS = true // parse the command-line args - args, err := docopt.Parse(usage, nil, true, version, false) + args, err := docopt.Parse(usage, nil, true, getVersionString(), false) if err != nil { return &cfg, err } diff --git a/glauth_test.go b/glauth_test.go new file mode 100644 index 0000000..00d96c8 --- /dev/null +++ b/glauth_test.go @@ -0,0 +1,32 @@ +package main + +// Just the beginning of testing - more to be added + +import ( + "testing" +) + +func TestGetVersionString(t *testing.T) { + + // Setup config and check output + LastGitTag = "7" + BuildTime = "20180616_042045Z" + GitCommit = "a9837f3112fc049fd1e9faca6f56d8be1bec91bd" + GitClean = "1" + GitBranch = "dev" + GitTagIsCommit = "0" + + versionOutput := getVersionString() + if versionOutput != "7" { + t.Errorf("Finish writing this test, output was: %s", versionOutput) + } + + // TODO: write these cases + + // Cases to test: + // 1) if GitTagIsCommit=1 - check for release-based strings (this build is release) + // 2) if GitClean=1 - check for "Commit: " as well as value of commit str + // 3) if GitClean=0 - Ensure "Commit: " is NOT there, as well ensure value of commit str is not there + // 4) do additional checks for release behavior, as well as branch name + +} diff --git a/sample-simple.cfg b/sample-simple.cfg index a97572a..a03f1ef 100644 --- a/sample-simple.cfg +++ b/sample-simple.cfg @@ -5,7 +5,8 @@ # General configuration. debug = true #syslog = true - +# yubikeyclientid = "yubi-api-clientid" +# yubikeysecret = "yubi-api-secret" ################# # The frontend section controls how clients connect to the proxy. [frontend] @@ -42,13 +43,21 @@ debug = true passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood sshkeys = ["ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwVw3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4hC/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLVIfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XBYnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+txSuhw== rsa-key-20160209"] - [[users]] name = "serviceuser" unixid = 5003 primarygroup = 5502 passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret +# Test user showing 2 factor auth authentication +[[users]] + name = "otpuser" + unixid = 5004 + primarygroup = 5501 + passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret + otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk" + yubikey = "vvjrcfalhlaa" + ################# # The groups section contains a hardcoded list of valid users. [[groups]] @@ -59,6 +68,11 @@ debug = true name = "svcaccts" unixid = 5502 +[[groups]] + name = "vpn" + unixid = 5503 + includegroups = [ 5501 ] + ################# # Enable and configure the optional REST API here. [api] @@ -67,4 +81,3 @@ debug = true listen = "localhost:5555" cert = "cert.pem" key = "key.pem" - diff --git a/scripts/docker/start.sh b/scripts/docker/start.sh index 5611681..f58f6ce 100755 --- a/scripts/docker/start.sh +++ b/scripts/docker/start.sh @@ -5,5 +5,9 @@ if [ ! -f /app/config/config.cfg ] ; then cp /app/docker/default-config.cfg /app/config/config.cfg; fi + +# Output version string to logs +/app/glauth --version + # Run app /app/glauth -c /app/config/config.cfg diff --git a/scripts/travis/.gitignore b/scripts/travis/.gitignore new file mode 100644 index 0000000..c9a86b9 --- /dev/null +++ b/scripts/travis/.gitignore @@ -0,0 +1 @@ +/test-results diff --git a/scripts/travis/good-results/posixAccountList0 b/scripts/travis/good-results/posixAccountList0 new file mode 100644 index 0000000..4def4f9 --- /dev/null +++ b/scripts/travis/good-results/posixAccountList0 @@ -0,0 +1,104 @@ +dn: cn=hackers,ou=superheros,dc=glauth,dc=com +cn: hackers +uid: hackers +ou: superheros +uidNumber: 5001 +accountStatus: active +objectClass: posixAccount +loginShell: /bin/bash +homeDirectory: /home/hackers +description: hackers via LDAP +gecos: hackers via LDAP +gidNumber: 5501 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=superheros,ou=groups,dc=glauth,dc=com +memberOf: cn=vpnaccess,ou=groups,dc=glauth,dc=com + +dn: cn=johndoe,ou=superheros,dc=glauth,dc=com +cn: johndoe +uid: johndoe +givenName: John +sn: Doe +ou: superheros +uidNumber: 5002 +accountStatus: active +mail: jdoe@example.com +objectClass: posixAccount +loginShell: /bin/sh +homeDirectory: /root +description: johndoe via LDAP +gecos: johndoe via LDAP +gidNumber: 5501 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=superheros,ou=groups,dc=glauth,dc=com +memberOf: cn=vpnaccess,ou=groups,dc=glauth,dc=com +sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwV + w3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4h + C/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLV + IfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XB + YnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+ + txSuhw== rsa-key-20160209 + +dn: cn=jamesdoe,ou=superheros,dc=glauth,dc=com +cn: jamesdoe +uid: jamesdoe +givenName: James +sn: Doe +ou: superheros +uidNumber: 5003 +accountStatus: active +mail: jdoe2@example.com +objectClass: posixAccount +loginShell: /bin/sh +homeDirectory: /home/jamesdoe +description: jamesdoe via LDAP +gecos: jamesdoe via LDAP +gidNumber: 5501 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=fulltime,ou=groups,dc=glauth,dc=com +memberOf: cn=mailadmin,ou=groups,dc=glauth,dc=com +memberOf: cn=superheros,ou=groups,dc=glauth,dc=com +memberOf: cn=vpnaccess,ou=groups,dc=glauth,dc=com +sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwV + w3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4h + C/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLV + IfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XB + YnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+ + txSuhw== rsa-key-20160209 + +dn: cn=alexdoe,ou=superheros,dc=glauth,dc=com +cn: alexdoe +uid: alexdoe +givenName: Alex +sn: Doe +ou: superheros +uidNumber: 5004 +accountStatus: active +mail: adoe@example.com +objectClass: posixAccount +loginShell: /bin/sh +homeDirectory: /home/alexdoe +description: alexdoe via LDAP +gecos: alexdoe via LDAP +gidNumber: 5501 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=fulltime,ou=groups,dc=glauth,dc=com +memberOf: cn=mailadmin,ou=groups,dc=glauth,dc=com +memberOf: cn=superheros,ou=groups,dc=glauth,dc=com +memberOf: cn=vpnaccess,ou=groups,dc=glauth,dc=com + +dn: cn=serviceuser,ou=svcaccts,dc=glauth,dc=com +cn: serviceuser +uid: serviceuser +ou: svcaccts +uidNumber: 5003 +accountStatus: active +objectClass: posixAccount +loginShell: /bin/bash +homeDirectory: /home/serviceuser +description: serviceuser via LDAP +gecos: serviceuser via LDAP +gidNumber: 5502 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=svcaccts,ou=groups,dc=glauth,dc=com + diff --git a/scripts/travis/good-results/posixGroupList0 b/scripts/travis/good-results/posixGroupList0 new file mode 100644 index 0000000..3158491 --- /dev/null +++ b/scripts/travis/good-results/posixGroupList0 @@ -0,0 +1,78 @@ +dn: cn=superheros,ou=groups,dc=glauth,dc=com +cn: superheros +description: superheros via LDAP +gidNumber: 5501 +objectClass: posixGroup +uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com +uniqueMember: cn=hackers,ou=superheros,dc=glauth,dc=com +uniqueMember: cn=jamesdoe,ou=superheros,dc=glauth,dc=com +uniqueMember: cn=johndoe,ou=superheros,dc=glauth,dc=com +memberUid: alexdoe +memberUid: hackers +memberUid: jamesdoe +memberUid: johndoe + +dn: cn=svcaccts,ou=groups,dc=glauth,dc=com +cn: svcaccts +description: svcaccts via LDAP +gidNumber: 5502 +objectClass: posixGroup +uniqueMember: cn=serviceuser,ou=svcaccts,dc=glauth,dc=com +memberUid: serviceuser + +dn: cn=vpnaccess,ou=groups,dc=glauth,dc=com +cn: vpnaccess +description: vpnaccess via LDAP +gidNumber: 5503 +objectClass: posixGroup +uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com +uniqueMember: cn=hackers,ou=superheros,dc=glauth,dc=com +uniqueMember: cn=jamesdoe,ou=superheros,dc=glauth,dc=com +uniqueMember: cn=johndoe,ou=superheros,dc=glauth,dc=com +memberUid: alexdoe +memberUid: hackers +memberUid: jamesdoe +memberUid: johndoe + +dn: cn=allaccs,ou=groups,dc=glauth,dc=com +cn: allaccs +description: allaccs via LDAP +gidNumber: 5504 +objectClass: posixGroup +uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com +uniqueMember: cn=hackers,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=serviceuser,ou=svcaccts,dc=glauth,dc=com +memberUid: alexdoe +memberUid: hackers +memberUid: jamesdoe +memberUid: johndoe +memberUid: serviceuser + +dn: cn=mailadmin,ou=groups,dc=glauth,dc=com +cn: mailadmin +description: mailadmin via LDAP +gidNumber: 5505 +objectClass: posixGroup +uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com +uniqueMember: cn=jamesdoe,ou=superheros,dc=glauth,dc=com +memberUid: alexdoe +memberUid: jamesdoe + +dn: cn=webmail,ou=groups,dc=glauth,dc=com +cn: webmail +description: webmail via LDAP +gidNumber: 5506 +objectClass: posixGroup + +dn: cn=fulltime,ou=groups,dc=glauth,dc=com +cn: fulltime +description: fulltime via LDAP +gidNumber: 5507 +objectClass: posixGroup +uniqueMember: cn=alexdoe,ou=superheros,dc=glauth,dc=com +uniqueMember: cn=jamesdoe,ou=superheros,dc=glauth,dc=com +memberUid: alexdoe +memberUid: jamesdoe + diff --git a/scripts/travis/good-results/userFetchNonexistentUser0 b/scripts/travis/good-results/userFetchNonexistentUser0 new file mode 100644 index 0000000..e69de29 diff --git a/scripts/travis/good-results/userFetchNonexistentUser1 b/scripts/travis/good-results/userFetchNonexistentUser1 new file mode 100644 index 0000000..e69de29 diff --git a/scripts/travis/good-results/userFetchTest0 b/scripts/travis/good-results/userFetchTest0 new file mode 100644 index 0000000..dec044a --- /dev/null +++ b/scripts/travis/good-results/userFetchTest0 @@ -0,0 +1,16 @@ +dn: cn=hackers,ou=superheros,dc=glauth,dc=com +cn: hackers +uid: hackers +ou: superheros +uidNumber: 5001 +accountStatus: active +objectClass: posixAccount +loginShell: /bin/bash +homeDirectory: /home/hackers +description: hackers via LDAP +gecos: hackers via LDAP +gidNumber: 5501 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=superheros,ou=groups,dc=glauth,dc=com +memberOf: cn=vpnaccess,ou=groups,dc=glauth,dc=com + diff --git a/scripts/travis/good-results/userFetchTest1 b/scripts/travis/good-results/userFetchTest1 new file mode 100644 index 0000000..f3b22b1 --- /dev/null +++ b/scripts/travis/good-results/userFetchTest1 @@ -0,0 +1,25 @@ +dn: cn=johndoe,ou=superheros,dc=glauth,dc=com +cn: johndoe +uid: johndoe +givenName: John +sn: Doe +ou: superheros +uidNumber: 5002 +accountStatus: active +mail: jdoe@example.com +objectClass: posixAccount +loginShell: /bin/sh +homeDirectory: /root +description: johndoe via LDAP +gecos: johndoe via LDAP +gidNumber: 5501 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=superheros,ou=groups,dc=glauth,dc=com +memberOf: cn=vpnaccess,ou=groups,dc=glauth,dc=com +sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwV + w3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4h + C/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLV + IfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XB + YnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+ + txSuhw== rsa-key-20160209 + diff --git a/scripts/travis/good-results/userFetchTest2 b/scripts/travis/good-results/userFetchTest2 new file mode 100644 index 0000000..6f7f399 --- /dev/null +++ b/scripts/travis/good-results/userFetchTest2 @@ -0,0 +1,15 @@ +dn: cn=serviceuser,ou=svcaccts,dc=glauth,dc=com +cn: serviceuser +uid: serviceuser +ou: svcaccts +uidNumber: 5003 +accountStatus: active +objectClass: posixAccount +loginShell: /bin/bash +homeDirectory: /home/serviceuser +description: serviceuser via LDAP +gecos: serviceuser via LDAP +gidNumber: 5502 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=svcaccts,ou=groups,dc=glauth,dc=com + diff --git a/scripts/travis/good-results/userFetchTest3 b/scripts/travis/good-results/userFetchTest3 new file mode 100644 index 0000000..3eadadf --- /dev/null +++ b/scripts/travis/good-results/userFetchTest3 @@ -0,0 +1,27 @@ +dn: cn=jamesdoe,ou=superheros,dc=glauth,dc=com +cn: jamesdoe +uid: jamesdoe +givenName: James +sn: Doe +ou: superheros +uidNumber: 5003 +accountStatus: active +mail: jdoe2@example.com +objectClass: posixAccount +loginShell: /bin/sh +homeDirectory: /home/jamesdoe +description: jamesdoe via LDAP +gecos: jamesdoe via LDAP +gidNumber: 5501 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=fulltime,ou=groups,dc=glauth,dc=com +memberOf: cn=mailadmin,ou=groups,dc=glauth,dc=com +memberOf: cn=superheros,ou=groups,dc=glauth,dc=com +memberOf: cn=vpnaccess,ou=groups,dc=glauth,dc=com +sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwV + w3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4h + C/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLV + IfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XB + YnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+ + txSuhw== rsa-key-20160209 + diff --git a/scripts/travis/good-results/userFetchTest4 b/scripts/travis/good-results/userFetchTest4 new file mode 100644 index 0000000..ad243ce --- /dev/null +++ b/scripts/travis/good-results/userFetchTest4 @@ -0,0 +1,21 @@ +dn: cn=alexdoe,ou=superheros,dc=glauth,dc=com +cn: alexdoe +uid: alexdoe +givenName: Alex +sn: Doe +ou: superheros +uidNumber: 5004 +accountStatus: active +mail: adoe@example.com +objectClass: posixAccount +loginShell: /bin/sh +homeDirectory: /home/alexdoe +description: alexdoe via LDAP +gecos: alexdoe via LDAP +gidNumber: 5501 +memberOf: cn=allaccs,ou=groups,dc=glauth,dc=com +memberOf: cn=fulltime,ou=groups,dc=glauth,dc=com +memberOf: cn=mailadmin,ou=groups,dc=glauth,dc=com +memberOf: cn=superheros,ou=groups,dc=glauth,dc=com +memberOf: cn=vpnaccess,ou=groups,dc=glauth,dc=com + diff --git a/scripts/travis/integration-test.sh b/scripts/travis/integration-test.sh index b8a20bc..93f92eb 100755 --- a/scripts/travis/integration-test.sh +++ b/scripts/travis/integration-test.sh @@ -1,11 +1,192 @@ #!/bin/bash -sudo apt-get -qq update && sudo apt-get -qq install -y ldap-utils && +export CLEANUP="$1" -$TRAVIS_BUILD_DIR/glauth -c "$TRAVIS_BUILD_DIR/$1" & +## Main Methods + +# Get the git working directory base if travis build dir isn't set +if [[ "$TRAVIS_BUILD_DIR" == "" ]] ; then + export TRAVIS_BUILD_DIR="$(git rev-parse --show-toplevel)" +fi + +# This script requires that "$TRAVIS_BUILD_DIR" is set to the repo root + +# Ensure ldap utils are installed (for example - when running this outside of travis) +if [[ ! `which ldapsearch` ]]; then + sudo apt-get -qq update && sudo apt-get -qq install -y ldap-utils || exit 1; +fi + +# Display version string +echo ""; +echo "" +echo "Version string of tested binary:" +"$TRAVIS_BUILD_DIR/bin/glauth64" --version +echo "" + +# Start in background, capture PID +"$TRAVIS_BUILD_DIR/bin/glauth64" -c "$TRAVIS_BUILD_DIR/scripts/travis/test-config.cfg" &> /dev/null & glauthPid="$!" -echo "Running at $glauthPid" +echo "Running glauth at PID=$glauthPid" + +# Sleep 2 sec, to ensure it comes online successfully and stays up sleep 2; -kill $glauthPid; -echo "done." + +# Check if process is still running before continuing +ps aux | grep -v "grep" | grep "$glauthPid" &> /dev/null || FAIL="1" + +if [[ "$FAIL" = "1" ]] ; then + echo "Integration test FAILED - process did not remain running > 2 sec" + exit 255; +fi + + +FAIL="0" + +# Used for OTP testing +# Arguments: +# $1 - Full Bind DN +# $2 - Full Bind PW +# $3 - query to run +# $4 - test name +function bindTest() { + ldapsearch -LLL \ + -H ldap://localhost:3893 \ + -D "$1" \ + -w "$2" \ + -x -bdc=glauth,dc=com \ + "$3" > /dev/null + + exitCode="$?" + + if [[ "$exitCode" = "0" ]] ; then + echo " - PASS : 2FA test '$4'"; + else + echo " - FAIL : 2FA test '$4'"; + FAIL="1" + fi + + +} + +# Arguments: +# $1 - query +# $2 - name of snapshot +function snapshotTest() { + + goodResults="$TRAVIS_BUILD_DIR/scripts/travis/good-results" + testResults="$TRAVIS_BUILD_DIR/scripts/travis/test-results" + + mkdir "$testResults" &> /dev/null + + # Run tests here + ldapCmd="ldapsearch -LLL \ + -H ldap://localhost:3893 \ + -D cn=serviceuser,ou=svcaccts,dc=glauth,dc=com \ + -w mysecret \ + -x -bdc=glauth,dc=com \ + $1"; + + # Run the ldap command, pipe to file + # "$ldapCmd" &> "$testResults/$2" + + # Useful for debugging - output the command run + # echo "$ldapCmd"; + + ldapsearch -LLL \ + -H ldap://localhost:3893 \ + -D cn=serviceuser,ou=svcaccts,dc=glauth,dc=com \ + -w mysecret \ + -x -bdc=glauth,dc=com \ + $1 > "$testResults/$2" + + + # Handle the first-run case, saving the test results + if [ ! -f "$goodResults/$2" ]; then + echo " - FIRST RUN - SAVING SNAPSHOT, RUN AGAIN TO PASS : '$2'"; + + # Copy the results to the goodResults dir, for future runs. + cp "$testResults/$2" "$goodResults/$2"; + + # NOTE: fail=1 must still be set, otherwise CI runs would succeed when they shouldn't + FAIL="1" + else + + THISFAIL="0" + diff -u "$goodResults/$2" "$testResults/$2" || THISFAIL="1" + + + if [[ "$CLEANUP" = "cleanup" ]] ; then + rm -rf "$testResults" + fi + + if [[ "$THISFAIL" = "0" ]] ; then + echo " - PASS : snapshot '$2'"; + else + echo " - FAIL : snapshot '$2'"; + FAIL="1" + fi + fi + +} + + +echo ""; +echo ""; +echo "RUNNING TESTS:" +echo ""; + +################# +## TEST RUNS +################# + +## Query output tests + +# Regular single-user fetches +snapshotTest "cn=hackers" userFetchTest0 +snapshotTest "cn=johndoe" userFetchTest1 +snapshotTest "cn=serviceuser" userFetchTest2 +snapshotTest "cn=jamesdoe" userFetchTest3 +snapshotTest "cn=alexdoe" userFetchTest4 + +# Test result of fetching nonexistent users +snapshotTest "cn=fakeuser" userFetchNonexistentUser0 +snapshotTest "cn=janedoe" userFetchNonexistentUser1 + +# List all posixgroups +snapshotTest "objectClass=posixgroup" posixGroupList0 +snapshotTest "objectClass=posixaccount" posixAccountList0 + + +## 2FA Bind Test +# Fetch the OTP for this moment +otpCode="$(oathtool --totp -b -d 6 '3hnvnk4ycv44glzigd6s25j4dougs3rk')" + +pass="ThisAloneWontWork!" + +# Try to bind with it +bindTest "cn=alexdoe,ou=superheros,dc=glauth,dc=com" \ + "$pass$otpCode" \ + "cn=alexdoe" \ + "OtpAlexDoe" + + +############# +## Cleanup +############# + +echo ""; +echo ""; + +# Kill saved PID when done +# However - throw the fail flag if the process isn't there (ie, exited prematurely) +echo "Killing glauth" +kill "$glauthPid" || FAIL="1" + +if [[ "$FAIL" = "0" ]] ; then + echo "Integration test success" + exit 0; +else + echo "Integration test FAILED" + exit 255; +fi diff --git a/scripts/travis/test-config.cfg b/scripts/travis/test-config.cfg index a97572a..d91a464 100644 --- a/scripts/travis/test-config.cfg +++ b/scripts/travis/test-config.cfg @@ -42,6 +42,33 @@ debug = true passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood sshkeys = ["ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwVw3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4hC/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLVIfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XBYnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+txSuhw== rsa-key-20160209"] +# This user record tests lots of groups, including group inheritence +[[users]] + name = "jamesdoe" + givenname="James" + sn="Doe" + mail = "jdoe2@example.com" + unixid = 5003 + primarygroup = 5501 + loginShell = "/bin/sh" + otherGroups = [5505,5507] + homeDir = "/home/jamesdoe" + passsha256 = "ff522a502031e5f37054892d642c2c0f36af6c4e8f62225470d4a1a99f3c9c2a" # dogood1 + sshkeys = ["ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwVw3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4hC/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLVIfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XBYnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+txSuhw== rsa-key-20160209"] + +# 2FA test user +[[users]] + name = "alexdoe" + givenname="Alex" + sn="Doe" + mail = "adoe@example.com" + unixid = 5004 + primarygroup = 5501 + loginShell = "/bin/sh" + otherGroups = [5505,5507] + otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk" + passsha256 = "b1cae08a1fd8b0bd0855e48f74ba2f8548904dd5de72311e6234617a3f661e16" # ThisAloneWontWork! + [[users]] name = "serviceuser" @@ -59,12 +86,35 @@ debug = true name = "svcaccts" unixid = 5502 + +[[groups]] + name = "vpnaccess" + unixid = 5503 + includegroups = [ 5501 ] + +[[groups]] + name = "allaccs" + unixid = 5504 + includegroups = [ 5501, 5502 ] + +[[groups]] + name = "mailadmin" + unixid = 5505 + +[[groups]] + name = "webmail" + unixid = 5506 + + +[[groups]] + name = "fulltime" + unixid = 5507 + ################# # Enable and configure the optional REST API here. [api] - enabled = true + enabled = false tls = false # enable TLS for production!! listen = "localhost:5555" cert = "cert.pem" key = "key.pem" - From 3a513c4ee62804b6410b31dcb4840c5af7c9af4e Mon Sep 17 00:00:00 2001 From: Ben Yanke Date: Fri, 20 Jul 2018 23:38:14 -0500 Subject: [PATCH 2/3] Removing bindata - should have been previously gitignored --- bindata.go | 283 ----------------------------------------------------- 1 file changed, 283 deletions(-) delete mode 100644 bindata.go diff --git a/bindata.go b/bindata.go deleted file mode 100644 index fccfd16..0000000 --- a/bindata.go +++ /dev/null @@ -1,283 +0,0 @@ -// Code generated by go-bindata. -// sources: -// assets/glauth.css -// assets/glauth.js -// assets/index.html -// DO NOT EDIT! - -package main - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(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) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -func (fi bindataFileInfo) Name() string { - return fi.name -} -func (fi bindataFileInfo) Size() int64 { - return fi.size -} -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} -func (fi bindataFileInfo) IsDir() bool { - return false -} -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _assetsGlauthCss = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x8f\x41\x6e\xc3\x20\x10\x45\xf7\x9c\x62\x24\xaf\x63\xd9\x0e\x4e\xc1\x39\x0d\x03\x63\x9b\xd6\x01\x04\xa4\xad\x5a\xf5\xee\x95\x1d\x39\x2a\xc9\xa6\xeb\xff\xfe\x7f\x33\xac\x7e\xbd\x5e\xd0\xe7\xe8\x1d\x7c\x33\x00\xed\x17\x1f\x07\xa8\x74\x73\x94\x1d\x9e\x19\x00\x2a\xfd\x36\x45\x7f\x75\xe6\xb0\x87\xa4\xc7\x66\x6c\xcf\xec\x87\xb1\x2a\x65\x95\x53\x50\x8e\x96\xa2\x7f\xe4\x5c\xf6\xf4\x84\xd4\x17\xca\xd1\xea\x07\x54\x0a\x83\x7f\xd0\x22\x95\xd8\x4b\x3c\xad\x87\x04\x65\x8c\x75\xd3\x00\x22\x7c\xae\x74\x95\x28\xbe\x53\xfc\x2f\xce\xe6\x6e\x25\x77\xb0\x93\xa2\x41\x79\xb3\x66\x65\x17\xc8\x73\x31\xf4\x32\x0a\x2d\xcc\xe6\xb9\xc5\x66\x8b\xef\xab\x7c\x5d\x7d\xfe\x17\x60\xf4\x2e\x1f\x92\xfd\xa2\x01\xda\x5d\xbd\x4f\xd4\x3e\x14\x12\x41\x9c\x2b\x73\x6f\x7d\x90\x9d\xe6\x3c\x00\xfa\xa5\x30\xd7\x3e\xd4\x68\x9d\x29\xba\xed\x49\x35\xa2\x7f\xc4\x12\xa9\xa8\xcb\x4f\x5a\x85\x5a\xea\xed\x8e\xdf\x00\x00\x00\xff\xff\x91\x33\xcc\x6e\xee\x01\x00\x00") - -func assetsGlauthCssBytes() ([]byte, error) { - return bindataRead( - _assetsGlauthCss, - "assets/glauth.css", - ) -} - -func assetsGlauthCss() (*asset, error) { - bytes, err := assetsGlauthCssBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "assets/glauth.css", size: 494, mode: os.FileMode(436), modTime: time.Unix(1524616076, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _assetsGlauthJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xa4\x54\xd1\x8a\xdb\x30\x10\x7c\xf7\x57\x6c\xdd\xc0\xc9\x34\x95\x43\x5f\x43\xfa\x76\x70\x29\xf4\x0a\x6d\x7e\x40\xb1\xd6\x89\xa8\x2c\x99\xf5\xc6\x69\x39\xfc\xef\x45\x96\x9d\xf8\x72\x77\x70\xc5\x2f\x49\xd8\x9d\x99\x8c\x35\x63\xb5\x8a\xc0\x38\x46\x6a\x95\x85\x0d\x7c\x59\xad\x56\xeb\x24\x59\x88\xf2\xe4\x0a\x36\xde\x89\x0c\x9e\x12\x80\x53\xad\x15\xe3\x77\x64\x32\x45\x23\xb2\x75\x02\x90\xe7\x71\xb8\x53\xc6\x86\x49\x97\xad\x93\x24\xc8\xb1\x32\x76\xab\x61\x03\x41\x69\xd4\xb9\x55\xe8\x55\x03\xba\x8a\x13\xd8\xc0\x42\x1e\x90\xbf\xfd\xfa\xf1\x28\x20\xcd\x35\xee\x4f\x87\xbc\x55\xd4\xa4\x4b\xb8\x98\xd1\x91\x17\x99\x8c\x55\x6d\x15\x23\x6c\xe0\x41\x39\x6d\x71\xaf\xa8\x91\x85\xaf\x6a\x63\x51\xc0\x42\xa4\x1f\x1b\x56\xdc\xd4\xca\xa1\xfd\x3c\xa2\xd3\x4c\x1e\xb9\xb2\x22\x83\xfe\x29\xa2\x54\x98\x84\xdf\x9b\x8b\xa8\xd0\xc3\xfa\xb9\xcc\xc8\x0e\x1f\x13\xfe\x7b\xad\xcc\x77\x31\xc3\x00\x52\x8b\x34\xd3\x42\xd4\x78\x61\xa2\xcb\x12\x00\x59\x86\x26\xdc\x14\xe7\xad\x03\x4c\xef\x89\x3c\x7d\x48\x27\x74\x65\xcf\xea\x6f\xf3\x52\xa0\x41\xde\x99\x0a\xfd\x89\xc5\xb3\x12\x2d\xc7\xde\x0e\x1a\xeb\xa4\xbb\xad\x5b\xec\xe6\xa5\x6b\xa1\x99\xb7\x45\x0b\xb3\x3c\x85\x4f\x63\x6d\x5f\x6b\x9b\x96\xa5\xa7\x7b\x55\x1c\xaf\xe6\x70\xdc\x01\x98\x12\x04\xca\xad\x86\xaf\x83\xc6\x75\x05\xd7\x97\x21\x20\xd6\xc3\xb8\xeb\xbf\xbb\xff\xcb\x2f\x28\xcd\x08\xaf\xcf\x4a\x1e\x8d\x46\x91\xc9\x9a\xb0\x46\xa7\x77\x7e\xd0\x4d\x33\x59\x2a\x8d\x5b\x27\xc2\x05\xf0\xae\x48\x07\xda\xec\x30\x43\x44\xaf\x25\x99\x4c\xce\x81\xf0\x60\x1a\x46\x7a\x40\x5b\x23\x89\xbb\xc0\xfb\x89\x56\xb1\x69\xf1\x6e\x12\x58\xe1\x1d\xe3\x1f\x5e\xc2\xde\xfa\xe2\x77\xfc\xcb\x90\xce\xd9\x38\xed\xcf\xb2\xf2\x15\x3a\x1e\x9d\xe4\x39\x21\x9f\xc8\x41\x1c\x8f\xe4\x4c\x96\xe4\xab\x47\x7f\x16\xc3\xd1\xbd\x85\xf2\x54\x29\x8e\xa0\x0e\x6d\x83\x4f\x53\xf4\x00\xeb\x97\xc3\xd5\xf8\x2f\x00\x00\xff\xff\x1d\x12\x43\xad\x6a\x05\x00\x00") - -func assetsGlauthJsBytes() ([]byte, error) { - return bindataRead( - _assetsGlauthJs, - "assets/glauth.js", - ) -} - -func assetsGlauthJs() (*asset, error) { - bytes, err := assetsGlauthJsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "assets/glauth.js", size: 1386, mode: os.FileMode(436), modTime: time.Unix(1526347681, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _assetsIndexHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x57\x6d\x6f\xdb\x36\x10\xfe\x9e\x5f\x71\xd1\xbe\x4e\x62\xed\xae\x5b\x17\xc8\x06\xba\x34\x5b\x03\xb4\x6b\x90\x76\xd8\x86\xa2\x28\x68\xf1\x6c\xd1\xa1\x48\x85\x77\x72\x62\x08\xfa\xef\x03\x2d\xbf\xc9\x73\x12\xc7\xd8\xbe\xd8\x22\xf9\xdc\xcb\xf3\xf0\x8e\xa2\xd2\xd3\xb7\x1f\xcf\x3f\xff\x7d\x75\x01\x39\x17\x66\x78\x92\x86\x3f\x30\xd2\x4e\x06\x11\xda\x68\x78\x02\x90\xe6\x28\x55\x78\x00\x48\x0b\x64\x09\x59\x2e\x3d\x21\x0f\xa2\x8a\xc7\xf1\xeb\x68\x7b\x29\x67\x2e\x63\xbc\xad\xf4\x6c\x10\xfd\x15\xff\xf1\x26\x3e\x77\x45\x29\x59\x8f\x0c\x46\x90\x39\xcb\x68\x79\x10\x5d\x5e\x0c\x50\x4d\xb0\x63\x69\x65\x81\x83\x68\xa6\xf1\xae\x74\x9e\xb7\xc0\x77\x5a\x71\x3e\x50\x38\xd3\x19\xc6\x8b\xc1\xf7\xa0\xad\x66\x2d\x4d\x4c\x99\x34\x38\xe8\xed\x71\xa4\x90\x32\xaf\x4b\xd6\xce\x6e\xf9\xda\x03\x94\x15\xe7\xce\x77\x31\x2d\x88\x35\x1b\x1c\xfe\xf6\xfe\x4d\xc5\x39\x7c\x62\xc9\x15\xa5\xa2\x9d\x5c\x22\x8c\xb6\x37\xe0\xd1\x0c\x22\xe2\xb9\x41\xca\x11\x39\x82\xdc\xe3\x78\x10\x05\x25\xe8\x4c\x88\x42\xde\x67\xca\x26\x23\xe7\x98\xd8\xcb\x32\x0c\x32\x57\x88\xf5\x84\x78\x99\xf4\x93\x17\x22\x23\xda\xcc\x25\x85\xb6\x49\x46\xb4\xca\xf7\x7f\x0b\x14\x73\x8e\x05\x3e\x27\x9c\x24\x42\x26\x31\x31\x41\xb8\xa5\x51\x6b\x75\x1a\xc7\xf0\xee\xf3\x87\xf7\xaf\x80\x72\x5d\x80\xb4\x0a\xae\x91\x4a\x67\x55\x32\x25\xb8\xbc\x78\x0d\x54\x95\x61\x73\xc1\x8d\x97\x40\x34\x58\xa0\x65\x5a\x80\x0b\x54\x5a\xc2\x6d\x85\x5e\x23\x41\x1c\x0f\xd7\x6e\xbf\xe8\x31\x18\x86\xcb\x0b\xf8\xf9\x6b\x3b\x0b\x90\xb6\xfb\x0b\xe4\xb3\x8d\x06\x8e\x28\x59\xea\x10\xa8\x87\x5a\x7e\x45\xb9\x9e\x89\x97\xc9\x4f\x49\x7f\x33\x5e\x10\x9e\x52\x34\x4c\x45\xeb\xe6\x39\x5e\x7d\x4b\x4a\xf4\x92\x1f\x92\xfe\x6a\xf4\x80\xc7\xf4\xf4\x0b\x5a\xa5\xc7\x5f\x5b\x3a\xa9\x68\x7b\x29\x3c\x8e\x9c\x9a\x83\x77\x26\x14\xab\xcb\xaa\xa0\xc3\x5a\x4a\xa5\x67\x90\x19\x49\x34\x88\x42\x5d\x4a\x6d\xd1\xc3\x62\xab\x62\xca\xdd\x5d\x26\x09\xa3\xa5\x6d\x21\xb5\x5d\xd9\x2d\x37\xe1\x83\xd4\x16\xa6\x55\x31\x72\xec\x9d\x85\xb1\xf3\x20\xa1\xf4\xba\x90\x7e\x0e\x85\xf4\x37\xc8\xda\x4e\xa0\x40\x22\x39\x41\x70\x1e\x32\x69\x0c\xb0\x03\x99\x85\x86\x59\x6b\xdf\xcd\x64\xed\x31\x5a\xad\xae\x11\x5a\x85\x52\x91\x4c\xa5\xb4\x68\xa2\x95\xc5\x62\x04\x8b\xdf\x58\xe1\x58\x56\x86\xa1\xac\x8c\x89\xbd\x9e\xe4\xdc\x75\x23\x94\x9e\x6d\x26\xd2\xbc\xb7\xec\xbc\x54\xe4\xbd\xad\xf9\x72\xf8\x39\xd7\x04\xec\x9c\x01\x4d\xa0\x2d\x28\x9c\xa1\x71\x65\xd0\x0f\x62\xb0\x8e\xe1\xb6\xd2\x8c\xe0\x51\xaa\xf9\x82\x7c\xe9\x9d\xaa\x16\xcc\x4e\x53\x51\x6e\xb4\x6a\x43\xee\x61\xea\xdd\xdd\x56\x72\xdd\xdd\x30\xf1\x3d\xc5\xbd\x3e\x84\x27\x2a\xe2\x1f\xbb\x2c\xf2\xfe\x70\xa1\x43\x2a\xf2\xfe\xc3\x2a\x45\x4f\x48\xba\xa3\x45\x27\xcf\x67\xe7\x33\x92\xd9\x0d\x5a\x05\x84\x7e\x86\xfe\x91\xcc\xda\xf5\xa3\x72\xfb\x77\xa2\xed\x73\x5b\x8f\x62\x53\xc3\xa1\xb2\x4e\xb6\x1b\xad\x5b\x39\x31\x63\x51\x1a\xc9\x18\x01\xcf\x4b\x1c\x44\x8c\xf7\x2c\xee\xe3\x5c\x5a\x65\x70\x24\x3d\x6d\x10\xfb\x37\xa8\x75\x13\x7a\xab\x93\x76\x08\x58\x4a\xbb\x42\x15\xc8\x5e\x67\xd1\xb0\xf4\xee\x7e\x9e\x04\xda\xda\xd9\xb3\x54\x04\xcc\x10\xea\xba\x33\xdf\x34\xe9\xc8\xef\xa5\xbc\xe9\xf5\xfd\x9c\x8e\xa1\xf3\x70\x9e\xdf\xc6\x7e\xf1\x8e\x52\xc9\x48\x5b\xf5\xcd\xe3\x2d\xed\xa6\xbc\x07\xd2\xc9\xfe\x60\xe7\x54\x65\x19\x12\xe1\x53\x11\xd6\xb8\xe3\xc2\xa0\xf7\xce\x3f\x15\xa3\x05\x3d\x3b\x00\xa1\xf4\x59\xfe\x84\x4c\x5b\xa0\x63\x03\x1c\x20\xd5\x2e\xf2\xd8\x50\x4f\xc9\xd5\x81\x3d\x3b\x48\x66\xdc\xa3\x2c\xda\xf5\x2d\xb7\x8f\x95\x7f\x7b\x98\x1c\xd3\x00\x75\xfd\x1d\xca\x2c\x87\x36\xfa\xf2\xf4\x4a\x96\x0e\x9b\xe6\xe4\xd1\x86\xae\xeb\x4f\x59\x78\x4d\x36\xcd\x99\x10\x75\xfd\xce\x11\x87\x6b\x5e\xd3\x9c\xd5\xf5\x95\xf3\xdc\x34\x1b\x7a\x57\xda\x4e\x9a\x06\xea\xba\xbd\xdb\x35\x0d\x6c\x09\x56\xd7\x22\x64\xb1\x8c\xf7\x08\x53\x96\xfa\xa8\x63\x2b\xe5\x70\x48\x6d\x8e\x95\x15\x6d\xce\x75\x87\x25\xfb\x15\xc7\xdd\x03\x8d\xd5\x6a\xc5\x95\x50\xd7\x1f\xcb\xa6\x09\x02\x84\xff\x54\xb0\x3a\x0c\xfd\x8b\xb6\xea\xed\xef\xcf\xb1\xf8\xb4\x28\xb2\x6b\xbc\x4d\x7e\xd5\x86\xd1\x3f\x61\x1b\x4c\xae\x91\x2a\xc3\xe7\x4e\xe1\x01\xe0\x95\xff\x60\x42\x07\xe0\xcf\x8d\x46\xcb\x97\x57\x07\x40\x95\x64\xbc\x46\x23\x59\xcf\x10\xfe\xcc\xd1\xee\xda\xa4\x82\xfd\xf6\x96\x6c\xd7\x40\x77\xcb\x1e\xa8\x88\xce\xbd\x51\x4e\xe5\x7d\x32\x71\x6e\x62\x50\x96\x9a\x16\x97\xc7\x30\x27\x8c\x1e\x91\x98\x86\x9b\xee\x5c\xf4\x92\x5e\x2f\xe9\x2d\x47\x0f\xdd\x22\xf7\x79\x3f\xf4\xbe\x3f\xdd\xfd\xae\x38\xd0\x7f\xa6\xec\x94\x42\xd3\x57\x6a\x6c\xa4\xc7\x9d\xf4\x37\xb5\x9d\x4c\x49\xf4\x93\x17\xc9\x8b\xed\xb9\xff\x2e\x50\xe1\xc2\xd5\xae\x0d\xf2\x3a\x79\xb9\x1c\xc7\x77\x9a\xf3\xd8\xb8\xf0\x01\x78\x50\xb4\xee\x77\xcb\x2e\x38\x15\xed\xd6\xa6\xa2\xfd\x0c\xfe\x27\x00\x00\xff\xff\x08\x9c\x44\x70\x17\x0f\x00\x00") - -func assetsIndexHtmlBytes() ([]byte, error) { - return bindataRead( - _assetsIndexHtml, - "assets/index.html", - ) -} - -func assetsIndexHtml() (*asset, error) { - bytes, err := assetsIndexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "assets/index.html", size: 3863, mode: os.FileMode(436), modTime: time.Unix(1524616076, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// 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) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "assets/glauth.css": assetsGlauthCss, - "assets/glauth.js": assetsGlauthJs, - "assets/index.html": assetsIndexHtml, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "assets": &bintree{nil, map[string]*bintree{ - "glauth.css": &bintree{assetsGlauthCss, map[string]*bintree{}}, - "glauth.js": &bintree{assetsGlauthJs, map[string]*bintree{}}, - "index.html": &bintree{assetsIndexHtml, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} From d410b01955e90e3d9c93cded9b55d945adc6c578 Mon Sep 17 00:00:00 2001 From: Ben Yanke Date: Tue, 31 Jul 2018 16:02:52 -0500 Subject: [PATCH 3/3] Switching docker hub size badge to a working one --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 86ab744..41cb622 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Go-lang LDAP Authentication (GLAuth) is a secure, easy-to-use, LDAP server w/ co [![Last Commit](https://img.shields.io/github/last-commit/glauth/glauth.svg)](https://github.com/glauth/glauth/graphs/commit-activity) [![](https://img.shields.io/docker/build/glauth/glauth.svg)](https://hub.docker.com/r/glauth/glauth/) -[![DockerHub Image Size](https://img.shields.io/imagelayers/image-size/glauth/glauth/latest.svg)](https://hub.docker.com/r/glauth/glauth/) +[![DockerHub Image Size](https://img.shields.io/microbadger/image-size/glauth/glauth.svg)](https://hub.docker.com/r/glauth/glauth/) [![Maintainability](https://img.shields.io/codeclimate/maintainability/glauth/glauth.svg)](https://codeclimate.com/github/glauth/glauth/maintainability) [![Test Coverage](https://img.shields.io/codeclimate/coverage/glauth/glauth.svg)](https://codeclimate.com/github/glauth/glauth/test_coverage)