Compare commits

...

8 Commits

Author SHA1 Message Date
Ben Yanke 28802ff87d Pulling in latest changes and fixes for 1.1.1 (#56)
* Adding a few test dockerfiles

* Continued work on docker builds

* Basic example of docker build and run works - see build.sh for now

* Continuing to work on docker build

* Removing testing from build script, since it belongs later in process

* Implementing dumb init

* Docker build fully switched to alpine

* Setting up alpine build

* Cleaning up dockerfile

* Cleaning up repo in prep for merge

* Updating permissions for clean merge

* Removing old ansible cruft, as per #12

* Removing binaries (since we now build)

* Updating sample config to use new fields now available

* Testing travis

* another travis test

* Still working on travis builds

* Fix missing amazon packages

* Merge in Travis config feature branch (#26)

* Adding version string

* Fixing and cleaning up docker build

* Adding image hashing and verification to 'make all'

* Testing build

* Running gofmt to fix build

* Testing switching travis to make

* Testing build again

* Merging in Fixes from travis-build feature branch (#33)

This includes an integration test which runs glauth and compares ldapsearch snapshot output stored in the repo compared to the snapshot output of the glauth.

Additionally, removing old versions of go, and adding windows and linuxar builds (but not tests) to the makefile, and consequently, the travis build.

While the mac, linux-arm, and windows binaries are not able to be run in travis, they are able to be at least compiled.

* Remove needless comment from integration test

* Adding 'is-process-running' check before integration tests run, to clearly note if the program crashes on run

* Switching from 1 sec to 2 sec timeout for integration test

* Adding back config file to fix build. Previous commit intended to see if build failed (and it did)

* Add support for including groups in groups (#23)

* Add support for including groups in groups
* Pulling in Makefile structure to allow easier testing and builds

* Forgot to remove spare test

* Add Version Info at Buildtime  (#39)

Adds the build info to the binary at buildtime via buildtime variables. This is shown by `./glauth --version`.

Example output for a non-release:
```
GLauth
Non-release build from branch feature/buildversion

Build time: 20180531_181011Z
Commit: 07ba631c2f
```

And example of a built release:
```
GLauth v2.3.4

Build time: 20180601_041330Z
Commit: 931d666262

```

* Fixing Broken Docker Build (#41)

Forgot to include go-bindata run in Dockerfile.

* Removing leftover TODO from merge

* Testing releases

* Testing releases

* Testing releases

* Adjusting logging

* Add new group tests to integration tests

* add cleanup to test process

* Add documentation about otherGroups, which was a previously undocumented field.

* Auto fetching bindata during build so it's not needed to be done manually

* Syntax fix

* starting framework for unit tests

* Merging in ongoing progress from Feature/travis build (#44)

Fixes a few minor issues:

#42 - now uses the makefile in the docker build, which means version info is correctly embedded at runtime - also now outputs version data at the top of the log when the container starts

Fixing a simple issue found by go vet. Need to do more work on fixing issues found in go vet.

* Forgot to run 'go fmt'

* Adding codecov for go now that a single test is written

* Testing not quite ready yet, removing from build

* Add Support For 2 Factor Authentication

Merging in feature from @ryskov (PR #24) adding 2FA support during LDAP binds. This is accomplished by concatenating the code to the end of the password. 

Also added integration tests for the TOTP method to run in CI. Could not, however, add automated tests for the yubikey, due the physical nature.

* Expose LDAPS ports in Docker container (#49)

Currently, the LDAPS ports are not exposed in the docker container.

* Adding better logging to docker start script

* Add more logging info to docker startup script

* Fix Arm32 Build (#52)

As discussed in issue #51, Arm32 builds were using 368 (intel/amd) arch accidentally, generating linux 32 bit binaries instead of arm 32 bit binaries. This commit fixes this in the Makefile, which will fix both the local builds, as well as the travis CI and release builds.

fixes #52

* Update docker hub image badge to a working one

previous one simply returned 0.

* Removing 3893 - fixes #50

* Fixing readme MD formatting

* Adding travis_retry to fix against intermittent network outages

* Add TLS options for running both with TLS and without on the same time (#27)

* Add TLS options for running both with TLS and without on the same time.

This commit expands on the settings available for using TLS. It puts TLS settings under the [frontend.tls] section and adds a new setting to [frontend] called TLSExclusive (bool).
TLSExclusive specifies whether or not to only run TLS when it is enabled, and is 'true' by default. Setting it to 'false' and having TLS enabled, causes the server to start both a LDAP and LDAPS server,
and therefore requires to seperate 'listen' options (to run on different ports) - the Frontend.Listen and the Frontend.TLS.Listen. If TLSExclusive is set to 'true' and no Frontend.TLS.Listen is specified, it will use the Frontend.Listen.

* Adding PR template and improving integration test tooling

* Updating formatting

* Add get dependencies step to makefile setup

* Add go 1.11

* Add App Password Support (#60)

App passwords can now be used to allow easier OTP use alongside applications which need to bind with a static password. Use the key `passappsha256` and specify an array of password hashes. See the readme and sample configuration file for more information.

Fixes #54

* Adding NCoC as official project code of conduct

We happily accept contributions based on the merit of the contributions.

* Properly handling paramaters in logs - fixes #64

* Adding ldapsearch for healthchecks
2018-12-25 11:25:42 -06:00
kost a02544ac8b Fix Legacy URL (#63) 2018-10-22 11:51:41 -05:00
kost 3acd492e61 uidnumber typo fix (#62) 2018-10-19 22:03:46 -05:00
Ben Yanke bd9a5e47ee Adding NCoC as official project code of conduct
We happily accept contributions based on the merit of the contributions.
2018-09-20 12:38:20 -05:00
Ben Yanke 2b4aa3b78d Update README.md 2018-08-30 11:51:52 -05:00
Ben Yanke 45a2671f46 Changing formatting 2018-08-22 09:09:17 -05:00
Ben Yanke 5e1ed70865 Add github PR template 2018-08-22 09:07:47 -05:00
Ben Yanke d410b01955 Switching docker hub size badge to a working one 2018-07-31 16:02:52 -05:00
17 changed files with 444 additions and 71 deletions
+25
View File
@@ -0,0 +1,25 @@
Thank you for making a pull request!
A few things to be aware of as you're working on your PR:
## WIP Tag
Incomplete PRs are more than welcome - it can be useful to collaborate before
implementation of an idea is complete. However, if your PR is not ready
for merge, please add [WIP] to the end of the title (work-in-progress).
## Tests
Before committing, you are encouraged to run the small but growing test
suite. This is accomplished by `make test`. Additionally, if you are adding
new functionality, consider adding tests covering your feature.
## CI
Each push to a branch connected to a PR will be run through GLAuth's
CI system. Please use these to your advantage. In particular, the Travis
integration tests rely on the LDAP queries returning with a set result,
so if your changes will change the output, Travis will likely fail.
To update, run `make fast && make updatetest && make test`. This will
delete the output snapshots provided and make new ones. You can then
inspect the changes and commit them.
Similarly, check codeclimate and try to fix what you find there if it fails.
+3
View File
@@ -4,6 +4,9 @@ glauth.cfg
# Ignore the built binary during testing
glauth
# Ignore generated certs in this folder
certs/
# Built binaries
bin
+10 -8
View File
@@ -3,8 +3,9 @@ language: go
# USE THIS alongside makefile tag detection: $TRAVIS_TAG
go:
- 1.9.x # last version
- 1.10.x # current version
- 1.9.x # older version
- 1.10.x # last version
- 1.11.x # current version
# Speed up git clones
git:
@@ -15,18 +16,19 @@ git:
# flunk the build and immediately stop. It's sorta like having
# set -e enabled in bash.
before_script:
- 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
- travis_retry sudo apt-get -qq update && sudo apt-get install -y ldap-utils oathtool # need this for integration tests
- travis_retry 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
#- travis_retry go get github.com/golang/lint/golint # Linter
#- travis_retry go get honnef.co/go/tools/cmd/megacheck # Badass static analyzer/linter
# - travis_retry go get github.com/fzipp/gocyclo # Not sure what this is
# Run bindata for assets
- make bindata
# Fetch dependencies
- go get -t -v ./...
- travis_retry go get -t -v ./...
script:
+5
View File
@@ -0,0 +1,5 @@
# Contributor Code of Conduct
This project adheres to No Code of Conduct. We are all adults. We accept anyone's contributions. Nothing else matters.
For more information please visit the [No Code of Conduct](https://github.com/domgetter/NCoC) homepage.
+5 -1
View File
@@ -45,11 +45,15 @@ COPY --from=build /app/glauth /app/glauth
COPY --from=build /app/scripts/docker/start.sh /app/docker/
COPY --from=build /app/scripts/docker/default-config.cfg /app/docker/
# Install ldapsearch for container health checks, then ensure ldapsearch is installed
RUN apk update && apk add --no-cache openldap-clients && which ldapsearch && rm -rf /var/cache/apk/*
# Install init
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64 && chmod +x /usr/local/bin/dumb-init
# Expose web and LDAP ports
EXPOSE 389 5555
EXPOSE 389 636 5555
ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
CMD ["/bin/sh", "/app/docker/start.sh"]
+7 -2
View File
@@ -37,7 +37,7 @@ fast: setup linux64 verify cleanup
binaries: linux32 linux64 linuxarm32 linuxarm64 darwin64 win32 win64
# Setup commands to always run
setup: bindata format
setup: getdeps bindata format
#####################
# Subcommands
@@ -47,7 +47,12 @@ setup: bindata format
runtest:
./scripts/travis/integration-test.sh cleanup
# Get all dependencies
getdeps:
go get -d ./...
updatetest:
./scripts/travis/integration-test.sh
bindata:
go get -u github.com/jteeuwen/go-bindata/... && ${GOPATH}/bin/go-bindata -pkg=main assets && gofmt -w bindata.go
@@ -70,7 +75,7 @@ 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
GOOS=linux GOARCH=arm 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
+19 -4
View File
@@ -1,4 +1,3 @@
# GLAuth: LDAP authentication server for developers
Go-lang LDAP Authentication (GLAuth) is a secure, easy-to-use, LDAP server w/ configurable backends.
@@ -6,7 +5,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)
@@ -40,8 +39,11 @@ This quickstart is a great way to try out GLAuth in a non-production environment
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:
@@ -92,14 +94,14 @@ In order to use S3, you must set your AWS credentials. Either:
1. set the -K and -S command-line flags **OR**
2. set the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables.
More configuration options are documented here: https://github.com/nmcclain/glauth/blob/master/sample-simple.cfg
More configuration options are documented here: https://github.com/glauth/glauth/blob/master/sample-simple.cfg
### Required Fields
* Name
* The user's username
* ou
* ID of the user's primary group
* uidbumber
* uidnumber
* The user's unix user id
* sshPublicKey
* Specify an array of public keys
@@ -137,6 +139,10 @@ More configuration options are documented here: https://github.com/nmcclain/glau
* Specify OTP secret used to validate OTP passcode
* Example: 3hnvnk4ycv44glzigd6s25j4dougs3rk
* default = blank
* passappsha256
* Specify an array of app passwords which can also succesfully bind - these bypass the OTP check. Hash the same way as password.
* Example: ["c32255dbf6fd6b64883ec8801f793bccfa2a860f2b1ae1315cd95cdac1338efa","4939efa7c87095dacb5e7e8b8cfb3a660fa1f5edcc9108f6d7ec20ea4d6b3a88"]
* default = blank
* yubikey
* Specify Yubikey ID for maching Yubikey OTP against the user
* Example: cccjgjgkhcbb
@@ -155,6 +161,11 @@ When using 2FA, append the 2FA code to the end of the password when authenticati
#### 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.
#### App Passwords
Additionally, you can specify an array of password hashes using the `passappsha256` for app passwords. These are not OTP validated, and are hashed in the same way as a password. This allows you to generate a long random string to be used in software which requires the ability to authenticate.
However, app passwords can be used without OTP as well.
#### 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/).
@@ -191,6 +202,10 @@ go get github.com/jteeuwen/go-bindata/...
make all
```
## Stargazers over time
[![Stargazers over time](https://starcharts.herokuapp.com/glauth/glauth.svg)](https://starcharts.herokuapp.com/glauth/glauth)
### Support
Support the ongoing development of GLAuth!
+33 -7
View File
@@ -105,6 +105,13 @@ func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultC
}
}
// Store the full bind password provided before possibly modifying
// in the otp check
// Generate a hash of the provided password
hashFull := sha256.New()
hashFull.Write([]byte(bindSimplePw))
// Test OTP if exists
if len(user.OTPSecret) > 0 && !validotp {
if len(bindSimplePw) > 6 {
otp := bindSimplePw[len(bindSimplePw)-6:]
@@ -114,20 +121,39 @@ func (h configHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultC
}
}
// finally, validate user's pw
// check app passwords first
for index, appPw := range user.PassAppSHA256 {
if appPw != hex.EncodeToString(hashFull.Sum(nil)) {
log.Debug(fmt.Sprintf("Attempted to bind app pw #%d - failure as %s from %s", index, bindDN, conn.RemoteAddr().String()))
} else {
stats_frontend.Add("bind_successes", 1)
log.Debug("Bind success using app pw #%d as %s from %s", index, bindDN, conn.RemoteAddr().String())
return ldap.LDAPResultSuccess, nil
}
}
// then check main password with the hash
hash := sha256.New()
hash.Write([]byte(bindSimplePw))
// Then ensure the OTP is valid before checking
if !validotp {
log.Warning(fmt.Sprintf("Bind Error: invalid token as %s from %s", bindDN, conn.RemoteAddr().String()))
log.Warning(fmt.Sprintf("Bind Error: invalid OTP 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))
// Now, check the hash
if user.PassSHA256 != hex.EncodeToString(hash.Sum(nil)) {
log.Warning(fmt.Sprintf("Bind Error: invalid credentials as %s from %s", bindDN, conn.RemoteAddr().String()))
return ldap.LDAPResultInvalidCredentials, nil
}
stats_frontend.Add("bind_successes", 1)
log.Debug("Bind success as %s from %s", bindDN, conn.RemoteAddr().String())
log.Debug(fmt.Sprintf("Bind success as %s from %s", bindDN, conn.RemoteAddr().String()))
return ldap.LDAPResultSuccess, nil
}
@@ -136,7 +162,7 @@ func (h configHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn
bindDN = strings.ToLower(bindDN)
baseDN := strings.ToLower("," + h.cfg.Backend.BaseDN)
searchBaseDN := strings.ToLower(searchReq.BaseDN)
log.Debug("Search request as %s from %s for %s", bindDN, conn.RemoteAddr().String(), searchReq.Filter)
log.Debug(fmt.Sprintf("Search request as %s from %s for %s", bindDN, conn.RemoteAddr().String(), searchReq.Filter))
stats_frontend.Add("search_reqs", 1)
// validate the user is authenticated and has appropriate access
@@ -223,7 +249,7 @@ func (h configHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn
}
}
stats_frontend.Add("search_successes", 1)
log.Debug("AP: Search OK: %s", searchReq.Filter)
log.Debug(fmt.Sprintf("AP: Search OK: %s", searchReq.Filter))
return ldap.ServerSearchResult{entries, []string{}, []ldap.Control{}, ldap.LDAPResultSuccess}, nil
}
+110 -28
View File
@@ -3,6 +3,9 @@ package main
import (
"expvar"
"fmt"
"os"
"strings"
"github.com/BurntSushi/toml"
"github.com/GeertJohan/yubigo"
"github.com/docopt/docopt-go"
@@ -10,8 +13,6 @@ import (
"github.com/op/go-logging"
"gopkg.in/amz.v1/aws"
"gopkg.in/amz.v1/s3"
"os"
"strings"
)
// Set with buildtime vars
@@ -61,11 +62,21 @@ type configBackend struct {
}
type configFrontend struct {
AllowedBaseDNs []string // For LDAP backend only
Listen string
Cert string
Key string
Listen string
TLS bool
}
type configLDAP struct {
Enabled bool
Listen string
}
type configLDAPS struct {
Enabled bool
Listen string
Cert string
Key string
}
type configAPI struct {
Cert string
Enabled bool
@@ -75,20 +86,21 @@ type configAPI struct {
TLS bool
}
type configUser struct {
Name string
OtherGroups []int
PassSHA256 string
PrimaryGroup int
SSHKeys []string
OTPSecret string
Yubikey string
Disabled bool
UnixID int
Mail string
LoginShell string
GivenName string
SN string
Homedir string
Name string
OtherGroups []int
PassSHA256 string
PassAppSHA256 []string
PrimaryGroup int
SSHKeys []string
OTPSecret string
Yubikey string
Disabled bool
UnixID int
Mail string
LoginShell string
GivenName string
SN string
Homedir string
}
type configGroup struct {
Name string
@@ -102,6 +114,8 @@ type config struct {
YubikeyClientID string
YubikeySecret string
Frontend configFrontend
LDAP configLDAP
LDAPS configLDAPS
Groups []configGroup
Syslog bool
Users []configUser
@@ -203,26 +217,45 @@ func main() {
s.SearchFunc("", handler)
s.CloseFunc("", handler)
// start the frontend server
if cfg.Frontend.TLS {
log.Notice(fmt.Sprintf("Frontend LDAPS server listening on %s", cfg.Frontend.Listen))
if err := s.ListenAndServeTLS(cfg.Frontend.Listen, cfg.Frontend.Cert, cfg.Frontend.Key); err != nil {
log.Fatalf("LDAP Server Failed: %s", err.Error())
}
} else {
log.Notice(fmt.Sprintf("Frontend LDAP server listening on %s", cfg.Frontend.Listen))
if err := s.ListenAndServe(cfg.Frontend.Listen); err != nil {
log.Fatalf("LDAP Server Failed: %s", err.Error())
if cfg.LDAP.Enabled {
// Dont block if also starting a LDAPS server afterwards
shouldBlock := !cfg.LDAPS.Enabled
if shouldBlock {
startLDAP(&cfg.LDAP, s)
} else {
go startLDAP(&cfg.LDAP, s)
}
}
if cfg.LDAPS.Enabled {
// Always block here
startLDAPS(&cfg.LDAPS, s)
}
log.Critical("AP exit")
}
func startLDAP(ldapConfig *configLDAP, server *ldap.Server) {
log.Notice(fmt.Sprintf("LDAP server listening on %s", ldapConfig.Listen))
if err := server.ListenAndServe(ldapConfig.Listen); err != nil {
log.Fatalf("LDAP Server Failed: %s", err.Error())
}
}
func startLDAPS(ldapsConfig *configLDAPS, server *ldap.Server) {
log.Notice(fmt.Sprintf("LDAPS server listening on %s", ldapsConfig.Listen))
if err := server.ListenAndServeTLS(ldapsConfig.Listen, ldapsConfig.Cert, ldapsConfig.Key); err != nil {
log.Fatalf("LDAP Server Failed: %s", err.Error())
}
}
// doConfig reads the cli flags and config file
func doConfig() (*config, error) {
cfg := config{}
// setup defaults
cfg.Frontend.TLS = true
cfg.LDAP.Enabled = false
cfg.LDAPS.Enabled = true
// parse the command-line args
args, err := docopt.Parse(usage, nil, true, getVersionString(), false)
@@ -270,6 +303,55 @@ func doConfig() (*config, error) {
logging.SetLevel(logging.DEBUG, programName)
log.Debug("Debugging enabled")
}
if len(cfg.Frontend.Listen) > 0 && (len(cfg.LDAP.Listen) > 0 || len(cfg.LDAPS.Listen) > 0) {
// Both old server-config and new - dont allow
return &cfg, fmt.Errorf("Both old and new server-config in use - please remove old format ([frontend]) and migrate to new format ([ldap], [ldaps])")
}
if len(cfg.Frontend.Listen) > 0 {
// We're going with old format - parse it into new
log.Warning("Config [frontend] is deprecated - please move to [ldap] and [ldaps] as-per documentation")
cfg.LDAP.Enabled = !cfg.Frontend.TLS
cfg.LDAPS.Enabled = cfg.Frontend.TLS
if cfg.Frontend.TLS {
cfg.LDAPS.Listen = cfg.Frontend.Listen
} else {
cfg.LDAP.Listen = cfg.Frontend.Listen
}
if len(cfg.Frontend.Cert) > 0 {
cfg.LDAPS.Cert = cfg.Frontend.Cert
}
if len(cfg.Frontend.Key) > 0 {
cfg.LDAPS.Key = cfg.Frontend.Key
}
}
if !cfg.LDAP.Enabled && !cfg.LDAPS.Enabled {
return &cfg, fmt.Errorf("No server configuration found: please provide either LDAP or LDAPS configuration")
}
if cfg.LDAPS.Enabled {
// LDAPS enabled - verify requirements (cert, key, listen)
if len(cfg.LDAPS.Cert) == 0 || len(cfg.LDAPS.Key) == 0 {
return &cfg, fmt.Errorf("LDAPS was enabled but no certificate or key were specified: please disable LDAPS or use the 'cert' and 'key' options")
}
if len(cfg.LDAPS.Listen) == 0 {
return &cfg, fmt.Errorf("No LDAPS bind address was specified: please disable LDAPS or use the 'listen' option")
}
}
if cfg.LDAP.Enabled {
// LDAP enabled - verify listen
if len(cfg.LDAP.Listen) == 0 {
return &cfg, fmt.Errorf("No LDAP bind address was specified: please disable LDAP or use the 'listen' option")
}
}
switch cfg.Backend.Datastore {
case "":
cfg.Backend.Datastore = "config"
+12 -12
View File
@@ -66,27 +66,27 @@ func newLdapHandler(cfg *config) Backend {
//
func (h ldapHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (resultCode ldap.LDAPResultCode, err error) {
log.Debug("Bind request as %s from %s", bindDN, conn.RemoteAddr().String())
log.Debug(fmt.Sprintf("Bind request as %s from %s", bindDN, conn.RemoteAddr().String()))
stats_frontend.Add("bind_reqs", 1)
s, err := h.getSession(conn)
if err != nil {
stats_frontend.Add("bind_ldapSession_errors", 1)
log.Debug("Bind ops error as %s from %s == %s", bindDN, conn.RemoteAddr().String(), err.Error())
log.Debug(fmt.Sprintf("Bind ops error as %s from %s == %s", bindDN, conn.RemoteAddr().String(), err.Error()))
return ldap.LDAPResultOperationsError, err
}
if err := s.ldap.Bind(bindDN, bindSimplePw); err != nil {
stats_frontend.Add("bind_errors", 1)
log.Debug("Bind invalid creds as %s from %s", bindDN, conn.RemoteAddr().String())
log.Debug(fmt.Sprintf("Bind invalid creds as %s from %s", bindDN, conn.RemoteAddr().String()))
return ldap.LDAPResultInvalidCredentials, nil
}
stats_frontend.Add("bind_successes", 1)
log.Debug("Bind success as %s from %s", bindDN, conn.RemoteAddr().String())
log.Debug(fmt.Sprintf("Bind success as %s from %s", bindDN, conn.RemoteAddr().String()))
return ldap.LDAPResultSuccess, nil
}
//
func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn net.Conn) (result ldap.ServerSearchResult, err error) {
log.Debug("Search request as %s from %s for %s", boundDN, conn.RemoteAddr().String(), searchReq.Filter)
log.Debug(fmt.Sprintf("Search request as %s from %s for %s", boundDN, conn.RemoteAddr().String(), searchReq.Filter))
stats_frontend.Add("search_reqs", 1)
s, err := h.getSession(conn)
if err != nil {
@@ -105,24 +105,24 @@ func (h ldapHandler) Search(boundDN string, searchReq ldap.SearchRequest, conn n
searchReq.Controls,
)
log.Debug("Search req to backend: %# v", pretty.Formatter(search))
log.Debug(fmt.Sprintf("Search req to backend: %# v", pretty.Formatter(search)))
sr, err := s.ldap.Search(search)
log.Debug("Backend Search result: %# v", pretty.Formatter(sr))
log.Debug(fmt.Sprintf("Backend Search result: %# v", pretty.Formatter(sr)))
ssr := ldap.ServerSearchResult{
Entries: sr.Entries,
Referrals: sr.Referrals,
Controls: sr.Controls,
}
log.Debug("Frontend Search result: %# v", pretty.Formatter(ssr))
log.Debug(fmt.Sprintf("Frontend Search result: %# v", pretty.Formatter(ssr)))
if err != nil {
e := err.(*ldap.Error)
log.Debug("Search Err: %# v", pretty.Formatter(err))
log.Debug(fmt.Sprintf("Search Err: %# v", pretty.Formatter(err)))
stats_frontend.Add("search_errors", 1)
ssr.ResultCode = ldap.LDAPResultCode(e.ResultCode)
return ssr, err
}
stats_frontend.Add("search_successes", 1)
log.Debug("AP: Search OK: %s -> num of entries = %d\n", search.Filter, len(ssr.Entries))
log.Debug(fmt.Sprintf("AP: Search OK: %s -> num of entries = %d\n", search.Filter, len(ssr.Entries)))
return ssr, nil
}
func (h ldapHandler) Close(boundDn string, conn net.Conn) error {
@@ -229,7 +229,7 @@ func (h ldapHandler) ping() error {
}
h.lock.Unlock()
}
log.Debug("Server health: %# v", pretty.Formatter(h.servers))
log.Debug(fmt.Sprintf("Server health: %# v", pretty.Formatter(h.servers)))
b, err := json.Marshal(h.servers)
if err != nil {
log.Error(fmt.Sprintf("Error encoding tail data: %s", err.Error()))
@@ -258,7 +258,7 @@ func (h ldapHandler) getBestServer() (ldapBackend, error) {
if bestping == forever {
return ldapBackend{}, fmt.Errorf("No healthy servers found")
}
log.Debug("Best server: %# v", pretty.Formatter(favorite))
log.Debug(fmt.Sprintf("Best server: %# v", pretty.Formatter(favorite)))
return favorite, nil
}
+29 -5
View File
@@ -5,15 +5,33 @@
# 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]
tls = false # enable TLS for production!!
# Server configuration.
#
# This is the old server-config format
# - will still work, but please use new format, shown below
#
# [frontend]
# listen = "localhost:8484"
# tls = false
# cert ="certs/server.crt"
# key = "certs/server.key"
# This ([ldap] and [ldaps]) is the new server-config format
[ldap]
enabled = true
listen = "localhost:3893"
cert = "cert.pem"
key = "key.pem"
[ldaps]
enabled = true
listen = "localhost:3894"
cert = "certs/server.crt"
key = "certs/server.key"
#################
# The backend section controls the data store.
@@ -41,7 +59,13 @@ debug = true
loginShell = "/bin/sh"
homeDir = "/root"
passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood
passappsha256 = ["6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a"]
sshkeys = ["ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEA3UKCEllO2IZXgqNygiVb+dDLJJwVw3AJwV34t2jzR+/tUNVeJ9XddKpYQektNHsFmY93lJw5QDSbeH/mAC4KPoUM47EriINKEelRbyG4hC/ko/e2JWqEclPS9LP7GtqGmscXXo4JFkqnKw4TIRD52XI9n1syYM9Y8rJ88fjC/Lpn+01AB0paLVIfppJU35t0Ho9doHAEfEvcQA6tcm7FLJUvklAxc8WUbdziczbRV40KzDroIkXAZRjX7vXXhh/p7XBYnA0GO8oTa2VY4dTQSeDAUJSUxbzevbL0ll9Gi1uYaTDQyE5gbn2NfJSqq0OYA+3eyGtIVjFYZgi+txSuhw== rsa-key-20160209"]
passappsha256 = [
"c32255dbf6fd6b64883ec8801f793bccfa2a860f2b1ae1315cd95cdac1338efa", # TestAppPw1
"c9853d5f2599e90497e9f8cc671bd2022b0fb5d1bd7cfff92f079e8f8f02b8d3", # TestAppPw2
"4939efa7c87095dacb5e7e8b8cfb3a660fa1f5edcc9108f6d7ec20ea4d6b3a88", # TestAppPw3
]
[[users]]
name = "serviceuser"
+1 -1
View File
@@ -10,7 +10,7 @@ debug = true
# The frontend section controls how clients connect to the proxy.
[frontend]
tls = false # enable TLS for production!!
listen = "localhost:3893"
listen = "localhost:389"
cert = "cert.pem"
key = "key.pem"
+16 -1
View File
@@ -2,12 +2,27 @@
# Copy config file if it doesn't exist so that the app can start
if [ ! -f /app/config/config.cfg ] ; then
cp /app/docker/default-config.cfg /app/config/config.cfg;
echo "Config file not found at /app/config/config.cfg"
echo "Copying example configuration file to run."
cp /app/docker/default-config.cfg /app/config/config.cfg || exit 1
fi
echo "";
echo "Version and build information:";
echo "";
# Output version string to logs
/app/glauth --version
echo "";
echo "Starting GLauth now.";
echo "";
# Run app
/app/glauth -c /app/config/config.cfg
echo ""
echo "GLauth has exited.""
echo "Exiting."
@@ -87,6 +87,48 @@ 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=jackdoe,ou=superheros,dc=glauth,dc=com
cn: jackdoe
uid: jackdoe
givenName: Jack
sn: Doe
ou: superheros
uidNumber: 5005
accountStatus: active
mail: jdoe3@example.com
objectClass: posixAccount
loginShell: /bin/sh
homeDirectory: /home/jackdoe
description: jackdoe via LDAP
gecos: jackdoe 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=sarahdoe,ou=superheros,dc=glauth,dc=com
cn: sarahdoe
uid: sarahdoe
givenName: Sarah
sn: Doe
ou: superheros
uidNumber: 5006
accountStatus: active
mail: sdoe@example.com
objectClass: posixAccount
loginShell: /bin/sh
homeDirectory: /home/sarahdoe
description: sarahdoe via LDAP
gecos: sarahdoe 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
@@ -5,12 +5,16 @@ gidNumber: 5501
objectClass: posixGroup
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
memberUid: alexdoe
memberUid: hackers
memberUid: jackdoe
memberUid: jamesdoe
memberUid: johndoe
memberUid: sarahdoe
dn: cn=svcaccts,ou=groups,dc=glauth,dc=com
cn: svcaccts
@@ -27,12 +31,16 @@ gidNumber: 5503
objectClass: posixGroup
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
memberUid: alexdoe
memberUid: hackers
memberUid: jackdoe
memberUid: jamesdoe
memberUid: johndoe
memberUid: sarahdoe
dn: cn=allaccs,ou=groups,dc=glauth,dc=com
cn: allaccs
@@ -41,13 +49,17 @@ gidNumber: 5504
objectClass: posixGroup
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
memberUid: alexdoe
memberUid: hackers
memberUid: jackdoe
memberUid: jamesdoe
memberUid: johndoe
memberUid: sarahdoe
memberUid: serviceuser
dn: cn=mailadmin,ou=groups,dc=glauth,dc=com
@@ -56,9 +68,13 @@ description: mailadmin via LDAP
gidNumber: 5505
objectClass: posixGroup
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
memberUid: alexdoe
memberUid: jackdoe
memberUid: jamesdoe
memberUid: sarahdoe
dn: cn=webmail,ou=groups,dc=glauth,dc=com
cn: webmail
@@ -72,7 +88,11 @@ description: fulltime via LDAP
gidNumber: 5507
objectClass: posixGroup
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
memberUid: alexdoe
memberUid: jackdoe
memberUid: jamesdoe
memberUid: sarahdoe
+67 -2
View File
@@ -4,6 +4,15 @@ export CLEANUP="$1"
## Main Methods
# Dep check
command -v oathtool ;
if [[ "$?" = "1" ]] ; then
echo "Please install oathtool or add it to \$PATH before continuing."
exit 1;
fi
# 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)"
@@ -25,6 +34,9 @@ echo ""
# Start in background, capture PID
"$TRAVIS_BUILD_DIR/bin/glauth64" -c "$TRAVIS_BUILD_DIR/scripts/travis/test-config.cfg" &> /dev/null &
# Use this instead to see glauth logs while running
# "$TRAVIS_BUILD_DIR/bin/glauth64" -c "$TRAVIS_BUILD_DIR/scripts/travis/test-config.cfg" &
glauthPid="$!"
echo "Running glauth at PID=$glauthPid"
@@ -60,9 +72,9 @@ function bindTest() {
exitCode="$?"
if [[ "$exitCode" = "0" ]] ; then
echo " - PASS : 2FA test '$4'";
echo " - PASS : Bind test '$4'";
else
echo " - FAIL : 2FA test '$4'";
echo " - FAIL : Bind test '$4'";
FAIL="1"
fi
@@ -170,6 +182,59 @@ bindTest "cn=alexdoe,ou=superheros,dc=glauth,dc=com" \
"cn=alexdoe" \
"OtpAlexDoe"
## App Password Bind Test
# Test the main pw
bindTest "cn=jackdoe,ou=superheros,dc=glauth,dc=com" \
"dogood1" \
"cn=jackdoe" \
"AppPwNoOtp0"
# App passwords on user
bindTest "cn=jackdoe,ou=superheros,dc=glauth,dc=com" \
"TestAppPw1" \
"cn=jackdoe" \
"AppPwNoOtp1"
bindTest "cn=jackdoe,ou=superheros,dc=glauth,dc=com" \
"TestAppPw2" \
"cn=jackdoe" \
"AppPwNoOtp2"
bindTest "cn=jackdoe,ou=superheros,dc=glauth,dc=com" \
"TestAppPw3" \
"cn=jackdoe" \
"AppPwNoOtp3"
####
# Test for a user who also uses OTP
####
otpCode="$(oathtool --totp -b -d 6 '3hnvnk4ycv44glzigd6s25j4dougs3rk')"
pass="dogood1"
# Test the main pw
bindTest "cn=sarahdoe,ou=superheros,dc=glauth,dc=com" \
"$pass$otpCode" \
"cn=sarahdoe" \
"AppPwOtp0"
# App passwords on user
bindTest "cn=sarahdoe,ou=superheros,dc=glauth,dc=com" \
"TestAppPw1" \
"cn=sarahdoe" \
"AppPwOtp1"
bindTest "cn=sarahdoe,ou=superheros,dc=glauth,dc=com" \
"TestAppPw2" \
"cn=sarahdoe" \
"AppPwOtp2"
bindTest "cn=sarahdoe,ou=superheros,dc=glauth,dc=com" \
"TestAppPw3" \
"cn=sarahdoe" \
"AppPwOtp3"
#############
## Cleanup
+40
View File
@@ -10,6 +10,9 @@ debug = true
# The frontend section controls how clients connect to the proxy.
[frontend]
tls = false # enable TLS for production!!
# Using a nonstandard port to ensure there are no
# conflicts if running a test alongside a prod instance
listen = "localhost:3893"
cert = "cert.pem"
key = "key.pem"
@@ -70,6 +73,43 @@ debug = true
passsha256 = "b1cae08a1fd8b0bd0855e48f74ba2f8548904dd5de72311e6234617a3f661e16" # ThisAloneWontWork!
# App PW test user without OTP
[[users]]
name = "jackdoe"
givenname="Jack"
sn="Doe"
mail = "jdoe3@example.com"
unixid = 5005
primarygroup = 5501
loginShell = "/bin/sh"
otherGroups = [5505,5507]
passsha256 = "ff522a502031e5f37054892d642c2c0f36af6c4e8f62225470d4a1a99f3c9c2a" #dogood1
passappsha256 = [
"c32255dbf6fd6b64883ec8801f793bccfa2a860f2b1ae1315cd95cdac1338efa", # TestAppPw1
"c9853d5f2599e90497e9f8cc671bd2022b0fb5d1bd7cfff92f079e8f8f02b8d3", # TestAppPw2
"4939efa7c87095dacb5e7e8b8cfb3a660fa1f5edcc9108f6d7ec20ea4d6b3a88", # TestAppPw3
]
# App PW test user with OTP
[[users]]
name = "sarahdoe"
givenname="Sarah"
sn="Doe"
mail = "sdoe@example.com"
unixid = 5006
primarygroup = 5501
loginShell = "/bin/sh"
otherGroups = [5505,5507]
otpsecret = "3hnvnk4ycv44glzigd6s25j4dougs3rk"
passsha256 = "ff522a502031e5f37054892d642c2c0f36af6c4e8f62225470d4a1a99f3c9c2a" #dogood1
passappsha256 = [
"c32255dbf6fd6b64883ec8801f793bccfa2a860f2b1ae1315cd95cdac1338efa", # TestAppPw1
"c9853d5f2599e90497e9f8cc671bd2022b0fb5d1bd7cfff92f079e8f8f02b8d3", # TestAppPw2
"4939efa7c87095dacb5e7e8b8cfb3a660fa1f5edcc9108f6d7ec20ea4d6b3a88", # TestAppPw3
]
[[users]]
name = "serviceuser"
unixid = 5003