aboutsummaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2020-02-09 15:44:18 +0100
committerAlex Auvolat <alex@adnab.me>2020-02-09 15:44:18 +0100
commite72034c430eb8e78a87d4b1d312e4a9c11f3df14 (patch)
tree6aa953d3969757ab2de76b525f0840abf0b23e99 /main.go
parent8f5ab6cab3d21029d08e66c5ce99159bdd8a4c7f (diff)
downloadguichet-e72034c430eb8e78a87d4b1d312e4a9c11f3df14.tar.gz
guichet-e72034c430eb8e78a87d4b1d312e4a9c11f3df14.zip
Implement login
Diffstat (limited to 'main.go')
-rw-r--r--main.go136
1 files changed, 129 insertions, 7 deletions
diff --git a/main.go b/main.go
index 84eb402..ee01c6e 100644
--- a/main.go
+++ b/main.go
@@ -2,6 +2,7 @@ package main
import (
"os"
+ "strings"
"flag"
"fmt"
"log"
@@ -10,19 +11,29 @@ import (
"encoding/json"
"encoding/base64"
"crypto/rand"
+ "crypto/tls"
+ "html/template"
"github.com/gorilla/sessions"
+ "github.com/go-ldap/ldap/v3"
)
type ConfigFile struct {
HttpBindAddr string `json:"http_bind_addr"`
SessionKey string `json:"session_key"`
LdapServerAddr string `json:"ldap_server_addr"`
+ LdapTLS bool `json:"ldap_tls"`
+ UserFormat string `json:"user_format"`
}
var configFlag = flag.String("config", "./config.json", "Configuration file path")
-func readConfig() ConfigFile {
+var config *ConfigFile
+
+const SESSION_NAME = "guichet_session"
+var store *sessions.CookieStore = nil
+
+func readConfig() ConfigFile{
key_bytes := make([]byte, 32)
n, err := rand.Read(key_bytes)
if err!= nil || n != 32 {
@@ -32,7 +43,9 @@ func readConfig() ConfigFile {
config_file := ConfigFile{
HttpBindAddr: ":9991",
SessionKey: base64.StdEncoding.EncodeToString(key_bytes),
- LdapServerAddr: "127.0.0.1:389",
+ LdapServerAddr: "ldap://127.0.0.1:389",
+ LdapTLS: false,
+ UserFormat: "cn=%s,ou=users,dc=example,dc=com",
}
_, err = os.Stat(*configFlag)
@@ -70,24 +83,133 @@ func readConfig() ConfigFile {
return config_file
}
-var store *sessions.CookieStore = nil
-
func main() {
flag.Parse()
- config := readConfig()
+ config_file := readConfig()
+ config = &config_file
store = sessions.NewCookieStore([]byte(config.SessionKey))
http.HandleFunc("/", handleHome)
- err := http.ListenAndServe(config.HttpBindAddr, nil)
+ staticfiles := http.FileServer(http.Dir("static"))
+ http.Handle("/static/", http.StripPrefix("/static/", staticfiles))
+
+ err := http.ListenAndServe(config.HttpBindAddr, logRequest(http.DefaultServeMux))
if err != nil {
log.Fatal("Cannot start http server: ", err)
}
}
+type LoginInfo struct {
+ Username string
+ DN string
+ Password string
+ }
+
+func logRequest(handler http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL)
+ handler.ServeHTTP(w, r)
+ })
+}
+
+func checkLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
+ session, err := store.Get(r, SESSION_NAME)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return nil
+ }
+
+ login_info, has_login_info := session.Values["login_info"]
+ if !has_login_info {
+ return handleLogin(w, r)
+ }
+
+ return login_info.(*LoginInfo)
+}
+
+func ldapOpen(w http.ResponseWriter) *ldap.Conn {
+ l, err := ldap.DialURL(config.LdapServerAddr)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return nil
+ }
+
+ if config.LdapTLS {
+ err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return nil
+ }
+ }
+
+ return l
+}
+
+// Templates ----
+
+type LoginFormData struct {
+ Username string
+ ErrorMessage string
+}
+
+var (
+ templateLogin = template.Must(template.ParseFiles("templates/layout.html", "templates/login.html"))
+)
+
// Page handlers ----
func handleHome(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, "Hello, world!")
+ login := checkLogin(w, r)
+ if login == nil {
+ return
+ }
+
+ fmt.Fprintf(w, "Welcome, %s!", login.Username)
+}
+
+func handleLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
+ if r.Method == "GET" {
+ templateLogin.Execute(w, LoginFormData{})
+ return nil
+ } else if r.Method == "POST" {
+ r.ParseForm()
+
+ username := strings.Join(r.Form["username"], "")
+ user_dn := strings.ReplaceAll(config.UserFormat, "%s", username)
+
+ login_info := &LoginInfo{
+ DN: user_dn,
+ Username: username,
+ Password: strings.Join(r.Form["password"], ""),
+ }
+
+ l := ldapOpen(w)
+ if l == nil {
+ return nil
+ }
+
+ err := l.Bind(user_dn, login_info.Password)
+ if err != nil {
+ templateLogin.Execute(w, LoginFormData{
+ Username: username,
+ ErrorMessage: err.Error(),
+ })
+ return nil
+ }
+
+ // Successfully logged in, save it to session
+ session, err := store.Get(r, SESSION_NAME)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return nil
+ }
+
+ session.Values["login_info"] = login_info
+ return login_info
+ } else {
+ http.Error(w, "Unsupported method", http.StatusBadRequest)
+ return nil
+ }
}