3 Commits
v0.4 ... v0.5.1

Author SHA1 Message Date
yo
c4e980834d Add TLS/https options 2022-11-11 13:01:33 +01:00
yo
5e363df9b0 Use builtin status codes, change HTTPS option 2022-11-11 13:00:57 +01:00
yo
bdda2de936 https support 2022-10-09 09:16:23 +02:00
2 changed files with 56 additions and 19 deletions

View File

@ -1,5 +1,12 @@
LISTEN="0.0.0.0:8081" LISTEN="0.0.0.0:8081"
LDAP_HOST="ldap://ldap.example.org" LDAP_HOST="ldap://ldap.example.org"
LDAP_BASE_DN="dc=example,dc=org" LDAP_BASE_DN="dc=example,dc=org"
# Credentials used for every op in ldap, so this account needs write access if you want to update ldap
LDAP_USER="cn=ldapuser,dc=example,dc=org" LDAP_USER="cn=ldapuser,dc=example,dc=org"
LDAP_PASS='here_lies_the_password' LDAP_PASS='here_lies_the_password'
# Https support
HTTPS=false
SSL_CERTIFICATE=/etc/ssl/certs/server.pem
SSL_PRIVATE_KEY=/etc/ssl/private/server.key

68
main.go
View File

@ -10,6 +10,7 @@ import (
"flag" "flag"
"time" "time"
"strings" "strings"
"net/http"
"encoding/json" "encoding/json"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -19,7 +20,7 @@ import (
) )
var ( var (
gVersion = "0.4" gVersion = "0.5.1"
) )
func marshalResultToText(res *ldap.SearchResult, delimiter string, showValueName, showDN bool) string { func marshalResultToText(res *ldap.SearchResult, delimiter string, showValueName, showDN bool) string {
@ -54,9 +55,9 @@ func sendResponse(c *gin.Context, res *ldap.SearchResult, format string) {
// 404 Not found // 404 Not found
if len(res.Entries) == 0 { if len(res.Entries) == 0 {
if strings.EqualFold(format, "json") { if strings.EqualFold(format, "json") {
c.JSON(404, gin.H{"error": "No result"}) c.JSON(http.StatusNotFound, gin.H{"error": "No result"})
} else { } else {
c.String(404, "No result") c.String(http.StatusNotFound, "No result")
} }
return return
} }
@ -69,27 +70,27 @@ func sendResponse(c *gin.Context, res *ldap.SearchResult, format string) {
log.Errorf("Error marshalling result to json: %v", err) log.Errorf("Error marshalling result to json: %v", err)
} }
log.Debugf("%v\n", string(jsonRes)) log.Debugf("%v\n", string(jsonRes))
c.String(200, string(jsonRes)) c.String(http.StatusOK, string(jsonRes))
} else if strings.EqualFold(format, "text") { } else if strings.EqualFold(format, "text") {
txtRes := marshalResultToText(res, "=", false, true) txtRes := marshalResultToText(res, "=", false, true)
log.Debugf("%v\n", string(txtRes)) log.Debugf("%v\n", string(txtRes))
c.String(200, string(txtRes)) c.String(http.StatusOK, string(txtRes))
} else if strings.EqualFold(format, "ldif") { } else if strings.EqualFold(format, "ldif") {
txtRes := marshalResultToText(res, ": ", false, true) txtRes := marshalResultToText(res, ": ", false, true)
log.Debugf("%v\n", string(txtRes)) log.Debugf("%v\n", string(txtRes))
c.String(200, string(txtRes)) c.String(http.StatusOK, string(txtRes))
} else if strings.EqualFold(format, "textvalue") { } else if strings.EqualFold(format, "textvalue") {
txtRes := marshalResultToText(res, "", true, true) txtRes := marshalResultToText(res, "", true, true)
log.Debugf("%v\n", string(txtRes)) log.Debugf("%v\n", string(txtRes))
c.String(200, string(txtRes)) c.String(http.StatusOK, string(txtRes))
} else if strings.EqualFold(format, "textvalue-nodn") { } else if strings.EqualFold(format, "textvalue-nodn") {
txtRes := marshalResultToText(res, "", true, false) txtRes := marshalResultToText(res, "", true, false)
log.Debugf("%v\n", string(txtRes)) log.Debugf("%v\n", string(txtRes))
c.String(200, string(txtRes)) c.String(http.StatusOK, string(txtRes))
} }
} }
@ -149,7 +150,7 @@ func basicAuth(c *gin.Context) {
if hasAuth && user == "admin" && password == "admin" { if hasAuth && user == "admin" && password == "admin" {
log.Infof("[%s]: User %s successfully authenticated", c.Request.RemoteAddr, user) log.Infof("[%s]: User %s successfully authenticated", c.Request.RemoteAddr, user)
} else { } else {
c.AbortWithStatus(401) c.AbortWithStatus(http.StatusUnauthorized)
c.Writer.Header().Set("WWW-Authenticate", "Basic realm=Restricted") c.Writer.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
return return
} }
@ -158,7 +159,7 @@ func basicAuth(c *gin.Context) {
func initRouter(r *gin.Engine, myldap *MyLdap) { func initRouter(r *gin.Engine, myldap *MyLdap) {
r.GET("/ping", func(c *gin.Context) { r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{ c.JSON(http.StatusOK, gin.H{
"message": "pong", "message": "pong",
}) })
}) })
@ -178,7 +179,7 @@ func initRouter(r *gin.Engine, myldap *MyLdap) {
// If OU does not exist, we'll get err='LDAP Result Code 32 "No Such Object"' // If OU does not exist, we'll get err='LDAP Result Code 32 "No Such Object"'
if err != nil { if err != nil {
log.Errorf("Error searching %s in %s : %v", cn, ou, err) log.Errorf("Error searching %s in %s : %v", cn, ou, err)
c.AbortWithError(500, err) c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
sendResponse(c, res, format) sendResponse(c, res, format)
@ -195,7 +196,7 @@ func initRouter(r *gin.Engine, myldap *MyLdap) {
modified, err := checkIfModifiedSince(c, myldap, ou, cn, class, "ALL") modified, err := checkIfModifiedSince(c, myldap, ou, cn, class, "ALL")
if err != nil { if err != nil {
c.AbortWithError(500, err) c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
@ -203,12 +204,12 @@ func initRouter(r *gin.Engine, myldap *MyLdap) {
res, err := doLdapSearch(myldap, ou, cn, class, "ALL") res, err := doLdapSearch(myldap, ou, cn, class, "ALL")
if err != nil { if err != nil {
log.Errorf("Error searching %s in %s : %v", cn, ou, err) log.Errorf("Error searching %s in %s : %v", cn, ou, err)
c.AbortWithError(500, err) c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
sendResponse(c, res, format) sendResponse(c, res, format)
} else { } else {
c.String(304, "") c.String(http.StatusNotModified, "")
} }
return return
}) })
@ -225,7 +226,7 @@ func initRouter(r *gin.Engine, myldap *MyLdap) {
res, err := doLdapSearch(myldap, ou, cn, class, attr) res, err := doLdapSearch(myldap, ou, cn, class, attr)
if err != nil { if err != nil {
log.Errorf("Error searching %s in %s : %v", cn, ou, err) log.Errorf("Error searching %s in %s : %v", cn, ou, err)
c.AbortWithError(500, err) c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
sendResponse(c, res, format) sendResponse(c, res, format)
@ -243,7 +244,7 @@ func initRouter(r *gin.Engine, myldap *MyLdap) {
modified, err := checkIfModifiedSince(c, myldap, ou, cn, class, attr) modified, err := checkIfModifiedSince(c, myldap, ou, cn, class, attr)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
@ -251,12 +252,12 @@ func initRouter(r *gin.Engine, myldap *MyLdap) {
res, err := doLdapSearch(myldap, ou, cn, class, attr) res, err := doLdapSearch(myldap, ou, cn, class, attr)
if err != nil { if err != nil {
log.Errorf("Error searching %s in %s : %v", cn, ou, err) log.Errorf("Error searching %s in %s : %v", cn, ou, err)
c.AbortWithError(500, err) c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
sendResponse(c, res, format) sendResponse(c, res, format)
} else { } else {
c.String(304, "") c.String(http.StatusNotModified, "")
} }
return return
}) })
@ -269,6 +270,9 @@ func main() {
var ldapUser string var ldapUser string
var ldapPass string var ldapPass string
var ldapBaseDN string var ldapBaseDN string
var tlsPrivKey string
var tlsCert string
var doTls bool
var debug bool var debug bool
flag.StringVar(&confFile, "config", "", "Path to the config file (optional)") flag.StringVar(&confFile, "config", "", "Path to the config file (optional)")
@ -277,6 +281,9 @@ func main() {
flag.StringVar(&ldapUser, "ldap-user", "", "ldap username") flag.StringVar(&ldapUser, "ldap-user", "", "ldap username")
flag.StringVar(&ldapPass, "ldap-pass", "", "ldap password") flag.StringVar(&ldapPass, "ldap-pass", "", "ldap password")
flag.StringVar(&ldapBaseDN, "ldap-base-dn", "", "ldap base DN") flag.StringVar(&ldapBaseDN, "ldap-base-dn", "", "ldap base DN")
flag.BoolVar(&doTls, "https", false, "Serve over TLS")
flag.StringVar(&tlsPrivKey, "ssl-private-key", "", "SSL Private key")
flag.StringVar(&tlsCert, "ssl-certificate", "", "SSL certificate (PEM format)")
flag.BoolVar(&debug, "debug", false, "Set log level to debug") flag.BoolVar(&debug, "debug", false, "Set log level to debug")
flag.Parse() flag.Parse()
@ -328,6 +335,25 @@ func main() {
log.Fatal("No ldap-base-dn defined!") log.Fatal("No ldap-base-dn defined!")
} }
} }
if false == doTls {
doTls = viper.GetBool("HTTPS")
}
if doTls && len(tlsCert) == 0 {
l := viper.GetString("SSL_CERTIFICATE")
if len(l) > 0 {
tlsCert = l
} else {
log.Fatal("SSL certificate must be set to use https!")
}
}
if doTls && len(tlsPrivKey) == 0 {
l := viper.GetString("SSL_PRIVATE_KEY")
if len(l) > 0 {
tlsPrivKey = l
} else {
log.Fatal("SSL private key must be set to use https!")
}
}
log.Println("Starting Go Ldap API v.", gVersion) log.Println("Starting Go Ldap API v.", gVersion)
if debug { if debug {
@ -340,7 +366,11 @@ func main() {
initRouter(r, &ldap) initRouter(r, &ldap)
r.Run(listen) if doTls {
r.RunTLS(listen, tlsCert, tlsPrivKey)
} else {
r.Run(listen)
}
} }