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"
|
"bytes"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -14,21 +13,13 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/ldap.v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var loginSalt string
|
var loginSalt string
|
||||||
|
|
||||||
type loginChecker struct {
|
type loginChecker struct {
|
||||||
students []Student
|
students []Student
|
||||||
noAuth bool
|
authMethod AuthMethod
|
||||||
ldapAddr string
|
|
||||||
ldapPort int
|
|
||||||
ldapIsTLS bool
|
|
||||||
ldapBase string
|
|
||||||
ldapBindUsername string
|
|
||||||
ldapBindPassword string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type loginUpload struct {
|
type loginUpload struct {
|
||||||
|
@ -36,64 +27,6 @@ type loginUpload struct {
|
||||||
Password string
|
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) {
|
func (l loginChecker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
if addr := r.Header.Get("X-Forwarded-For"); addr != "" {
|
if addr := r.Header.Get("X-Forwarded-For"); addr != "" {
|
||||||
|
@ -139,16 +72,14 @@ func (l loginChecker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ! l.noAuth {
|
if ok, err := l.authMethod.checkAuth(lu.Username, lu.Password); err != nil {
|
||||||
if ok, err := l.ldapAuth(lu.Username, lu.Password); err != nil {
|
log.Println("Unable to perform authentication for", lu.Username, ":", err, "at", r.RemoteAddr)
|
||||||
log.Println("Unable to perform authentication for", lu.Username, ":", err, "at", r.RemoteAddr)
|
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
return
|
||||||
return
|
} else if !ok {
|
||||||
} else if !ok {
|
log.Println("Login failed:", lu.Username, "at", r.RemoteAddr)
|
||||||
log.Println("Login failed:", lu.Username, "at", r.RemoteAddr)
|
http.Error(w, "Invalid password", http.StatusUnauthorized)
|
||||||
http.Error(w, "Invalid password", http.StatusUnauthorized)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find corresponding MAC
|
// Find corresponding MAC
|
||||||
|
|
|
@ -17,21 +17,20 @@ var tftpDir string
|
||||||
func main() {
|
func main() {
|
||||||
var studentsFile string
|
var studentsFile string
|
||||||
|
|
||||||
var lc loginChecker
|
|
||||||
|
|
||||||
var bind = flag.String("bind", ":8081", "Bind port/socket")
|
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(&studentsFile, "students", "./students.csv", "Path to a CSV file containing students list")
|
||||||
flag.StringVar(&ARPTable, "arp", ARPTable, "Path to ARP table")
|
flag.StringVar(&ARPTable, "arp", ARPTable, "Path to ARP table")
|
||||||
flag.StringVar(&tftpDir, "tftpdir", "/var/tftp/", "Path to TFTPd directory")
|
flag.StringVar(&tftpDir, "tftpdir", "/var/tftp/", "Path to TFTPd directory")
|
||||||
flag.StringVar(&loginSalt, "loginsalt", "adelina", "secret used in login HMAC")
|
flag.StringVar(&loginSalt, "loginsalt", "adelina", "secret used in login HMAC")
|
||||||
|
|
||||||
flag.BoolVar(&lc.noAuth, "noauth", false, "don't perform password check")
|
var auth = flag.String("auth", "none", "Auth method: none, ldap")
|
||||||
flag.StringVar(&lc.ldapAddr, "ldaphost", "auth.cri.epita.fr", "LDAP host")
|
|
||||||
flag.IntVar(&lc.ldapPort, "ldapport", 636, "LDAP port")
|
var ldapAddr = flag.String("ldaphost", "auth.cri.epita.fr", "LDAP host")
|
||||||
flag.BoolVar(&lc.ldapIsTLS, "ldaptls", false, "Is LDAP connection LDAPS?")
|
var ldapPort = flag.Int("ldapport", 636, "LDAP port")
|
||||||
flag.StringVar(&lc.ldapBase, "ldapbase", "dc=epita,dc=net", "LDAP base")
|
var ldaptls = flag.Bool("ldaptls", false, "Is LDAP connection LDAPS?")
|
||||||
flag.StringVar(&lc.ldapBindUsername, "ldapbindusername", "", "LDAP user to use in order to perform bind (optional if search can be made anonymously)")
|
var ldapbase = flag.String("ldapbase", "dc=epita,dc=net", "LDAP base")
|
||||||
flag.StringVar(&lc.ldapBindPassword, "ldapbindpassword", "", "Password for the bind user")
|
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()
|
flag.Parse()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
@ -42,6 +41,23 @@ func main() {
|
||||||
log.Fatal(err)
|
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)
|
lc.students, err = readStudentsList(studentsFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|
|
@ -153,9 +153,9 @@ services:
|
||||||
- /var/lib/adlin/pxelinux.cfg:/srv/tftp/pxelinux.cfg
|
- /var/lib/adlin/pxelinux.cfg:/srv/tftp/pxelinux.cfg
|
||||||
|
|
||||||
- name: login-validator
|
- name: login-validator
|
||||||
image: nemunaire/adlin-login-validator:a5fee7db6c578a6d698983be8e74e7ce7420791e
|
image: nemunaire/adlin-login-validator:87f1cf05e8037b934d293a48704bd3f8ee678d41
|
||||||
# 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", "-auth=ldap", "-ldaphost=auth.cri.epita.net", "-ldapport=636", "-ldaptls", "-ldapbase=dc=epita,dc=net"]
|
||||||
command: ["/bin/login-validator", "-bind=:8081", "-noauth"]
|
command: ["/bin/login-validator", "-bind=:8081", "-auth=none"]
|
||||||
net: /run/netns/login
|
net: /run/netns/login
|
||||||
binds:
|
binds:
|
||||||
- /etc/resolv.conf:/etc/resolv.conf:ro
|
- /etc/resolv.conf:/etc/resolv.conf:ro
|
||||||
|
|
Reference in New Issue
Block a user