login-validator: refactor auth methods
This commit is contained in:
parent
1d2199aaef
commit
8d4ab002d8
11
pkg/login-validator/cmd/auth.go
Normal file
11
pkg/login-validator/cmd/auth.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
type AuthMethod interface {
|
||||
checkAuth(username, password string) (bool, error)
|
||||
}
|
||||
|
||||
type NoAuth struct {}
|
||||
|
||||
func (NoAuth) checkAuth(username, password string) (res bool, err error) {
|
||||
return true, nil
|
||||
}
|
77
pkg/login-validator/cmd/auth_ldap.go
Normal file
77
pkg/login-validator/cmd/auth_ldap.go
Normal file
@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
type LDAPAuth struct {
|
||||
Addr string
|
||||
Port int
|
||||
IsTLS bool
|
||||
Base string
|
||||
BindUsername string
|
||||
BindPassword string
|
||||
}
|
||||
|
||||
func (l LDAPAuth) checkAuth(username, password string) (res bool, err error) {
|
||||
tlsCnf := tls.Config{InsecureSkipVerify: true}
|
||||
|
||||
var c *ldap.Conn
|
||||
|
||||
if l.IsTLS {
|
||||
c, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", l.Addr, l.Port), &tlsCnf)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
c, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", l.Addr, l.Port))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Reconnect with TLS
|
||||
err = c.StartTLS(&tlsCnf)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if l.BindUsername != "" {
|
||||
err = c.Bind(l.BindUsername, l.BindPassword)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
// Search for the given username
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
l.Base,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(objectClass=person)(uid=%s))", username),
|
||||
[]string{"dn"},
|
||||
nil,
|
||||
)
|
||||
|
||||
sr, err := c.Search(searchRequest)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(sr.Entries) != 1 {
|
||||
return false, errors.New("User does not exist or too many entries returned")
|
||||
}
|
||||
|
||||
userdn := sr.Entries[0].DN
|
||||
|
||||
err = c.Bind(userdn, password)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha512"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@ -14,21 +13,13 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
var loginSalt string
|
||||
|
||||
type loginChecker struct {
|
||||
students []Student
|
||||
noAuth bool
|
||||
ldapAddr string
|
||||
ldapPort int
|
||||
ldapIsTLS bool
|
||||
ldapBase string
|
||||
ldapBindUsername string
|
||||
ldapBindPassword string
|
||||
students []Student
|
||||
authMethod AuthMethod
|
||||
}
|
||||
|
||||
type loginUpload struct {
|
||||
@ -36,64 +27,6 @@ type loginUpload struct {
|
||||
Password string
|
||||
}
|
||||
|
||||
func (l loginChecker) ldapAuth(username, password string) (res bool, err error) {
|
||||
tlsCnf := tls.Config{InsecureSkipVerify: true}
|
||||
|
||||
var c *ldap.Conn
|
||||
|
||||
if l.ldapIsTLS {
|
||||
c, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", l.ldapAddr, l.ldapPort), &tlsCnf)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
c, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", l.ldapAddr, l.ldapPort))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Reconnect with TLS
|
||||
err = c.StartTLS(&tlsCnf)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if l.ldapBindUsername != "" {
|
||||
err = c.Bind(l.ldapBindUsername, l.ldapBindPassword)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
// Search for the given username
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
l.ldapBase,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(objectClass=person)(uid=%s))", username),
|
||||
[]string{"dn"},
|
||||
nil,
|
||||
)
|
||||
|
||||
sr, err := c.Search(searchRequest)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(sr.Entries) != 1 {
|
||||
return false, errors.New("User does not exist or too many entries returned")
|
||||
}
|
||||
|
||||
userdn := sr.Entries[0].DN
|
||||
|
||||
err = c.Bind(userdn, password)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (l loginChecker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if addr := r.Header.Get("X-Forwarded-For"); addr != "" {
|
||||
@ -139,16 +72,14 @@ func (l loginChecker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if ! l.noAuth {
|
||||
if ok, err := l.ldapAuth(lu.Username, lu.Password); err != nil {
|
||||
log.Println("Unable to perform authentication for", lu.Username, ":", err, "at", r.RemoteAddr)
|
||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
} else if !ok {
|
||||
log.Println("Login failed:", lu.Username, "at", r.RemoteAddr)
|
||||
http.Error(w, "Invalid password", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
if ok, err := l.authMethod.checkAuth(lu.Username, lu.Password); err != nil {
|
||||
log.Println("Unable to perform authentication for", lu.Username, ":", err, "at", r.RemoteAddr)
|
||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
} else if !ok {
|
||||
log.Println("Login failed:", lu.Username, "at", r.RemoteAddr)
|
||||
http.Error(w, "Invalid password", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Find corresponding MAC
|
||||
|
@ -17,21 +17,20 @@ var tftpDir string
|
||||
func main() {
|
||||
var studentsFile string
|
||||
|
||||
var lc loginChecker
|
||||
|
||||
var bind = flag.String("bind", ":8081", "Bind port/socket")
|
||||
flag.StringVar(&studentsFile, "students", "./students.csv", "Path to a CSV file containing students list")
|
||||
flag.StringVar(&ARPTable, "arp", ARPTable, "Path to ARP table")
|
||||
flag.StringVar(&tftpDir, "tftpdir", "/var/tftp/", "Path to TFTPd directory")
|
||||
flag.StringVar(&loginSalt, "loginsalt", "adelina", "secret used in login HMAC")
|
||||
|
||||
flag.BoolVar(&lc.noAuth, "noauth", false, "don't perform password check")
|
||||
flag.StringVar(&lc.ldapAddr, "ldaphost", "auth.cri.epita.fr", "LDAP host")
|
||||
flag.IntVar(&lc.ldapPort, "ldapport", 636, "LDAP port")
|
||||
flag.BoolVar(&lc.ldapIsTLS, "ldaptls", false, "Is LDAP connection LDAPS?")
|
||||
flag.StringVar(&lc.ldapBase, "ldapbase", "dc=epita,dc=net", "LDAP base")
|
||||
flag.StringVar(&lc.ldapBindUsername, "ldapbindusername", "", "LDAP user to use in order to perform bind (optional if search can be made anonymously)")
|
||||
flag.StringVar(&lc.ldapBindPassword, "ldapbindpassword", "", "Password for the bind user")
|
||||
var auth = flag.String("auth", "none", "Auth method: none, ldap")
|
||||
|
||||
var ldapAddr = flag.String("ldaphost", "auth.cri.epita.fr", "LDAP host")
|
||||
var ldapPort = flag.Int("ldapport", 636, "LDAP port")
|
||||
var ldaptls = flag.Bool("ldaptls", false, "Is LDAP connection LDAPS?")
|
||||
var ldapbase = flag.String("ldapbase", "dc=epita,dc=net", "LDAP base")
|
||||
var ldapbindusername = flag.String("ldapbindusername", "", "LDAP user to use in order to perform bind (optional if search can be made anonymously)")
|
||||
var ldapbindpassword = flag.String("ldapbindpassword", "", "Password for the bind user")
|
||||
flag.Parse()
|
||||
|
||||
var err error
|
||||
@ -42,6 +41,23 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var lc loginChecker
|
||||
|
||||
if auth != nil && *auth == "ldap" {
|
||||
log.Printf("Auth method: LDAP(%s@%s:%d?%s)", *ldapbindusername, *ldapAddr, *ldapPort, *ldapbase)
|
||||
lc.authMethod = LDAPAuth{
|
||||
Addr: *ldapAddr,
|
||||
Port: *ldapPort,
|
||||
IsTLS: *ldaptls,
|
||||
Base: *ldapbase,
|
||||
BindUsername: *ldapbindusername,
|
||||
BindPassword: *ldapbindpassword,
|
||||
}
|
||||
} else {
|
||||
log.Println("No auth method selected: all access will be granted")
|
||||
lc.authMethod = NoAuth{}
|
||||
}
|
||||
|
||||
lc.students, err = readStudentsList(studentsFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -153,9 +153,9 @@ services:
|
||||
- /var/lib/adlin/pxelinux.cfg:/srv/tftp/pxelinux.cfg
|
||||
|
||||
- name: login-validator
|
||||
image: nemunaire/adlin-login-validator:a5fee7db6c578a6d698983be8e74e7ce7420791e
|
||||
# command: ["/bin/login-validator", "-bind=:8081", "-ldaphost=auth.cri.epita.net", "-ldapport=636", "-ldaptls", "-ldapbase=dc=epita,dc=net"]
|
||||
command: ["/bin/login-validator", "-bind=:8081", "-noauth"]
|
||||
image: nemunaire/adlin-login-validator:87f1cf05e8037b934d293a48704bd3f8ee678d41
|
||||
# command: ["/bin/login-validator", "-bind=:8081", "-auth=ldap", "-ldaphost=auth.cri.epita.net", "-ldapport=636", "-ldaptls", "-ldapbase=dc=epita,dc=net"]
|
||||
command: ["/bin/login-validator", "-bind=:8081", "-auth=none"]
|
||||
net: /run/netns/login
|
||||
binds:
|
||||
- /etc/resolv.conf:/etc/resolv.conf:ro
|
||||
|
Reference in New Issue
Block a user