Containerize
This commit is contained in:
parent
7ab5451a3f
commit
9a6e24aea0
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
guichet
|
guichet
|
||||||
|
guichet.static
|
||||||
config.json
|
config.json
|
||||||
|
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM scratch
|
||||||
|
|
||||||
|
ADD static /static
|
||||||
|
ADD guichet.static /guichet
|
||||||
|
ADD templates /templates
|
||||||
|
|
||||||
|
ENTRYPOINT ["/guichet"]
|
22
Makefile
22
Makefile
@ -1,5 +1,19 @@
|
|||||||
all: guichet
|
BIN=guichet
|
||||||
|
SRC=main.go ssha.go profile.go admin.go
|
||||||
|
DOCKER=lxpz/guichet_amd64
|
||||||
|
|
||||||
guichet: main.go ssha.go profile.go admin.go
|
all: $(BIN)
|
||||||
go get -v
|
|
||||||
go build -v
|
$(BIN): $(SRC)
|
||||||
|
go get -d -v
|
||||||
|
go build -v -o $(BIN)
|
||||||
|
|
||||||
|
$(BIN).static: $(SRC)
|
||||||
|
go get -d -v
|
||||||
|
CGO_ENABLED=0 GOOS=linux go build -a -v -o $(BIN).static
|
||||||
|
|
||||||
|
docker: $(BIN).static
|
||||||
|
docker build -t $(DOCKER):$(TAG) .
|
||||||
|
docker push $(DOCKER):$(TAG)
|
||||||
|
docker tag $(DOCKER):$(TAG) $(DOCKER):latest
|
||||||
|
docker push $(DOCKER):latest
|
||||||
|
@ -5,7 +5,6 @@ Exemple de config.json pour Deuxfleurs:
|
|||||||
```
|
```
|
||||||
{
|
{
|
||||||
"http_bind_addr": ":9991",
|
"http_bind_addr": ":9991",
|
||||||
"session_key": "V1BAbmn9VW/wL0EZ6Q8xwhkVq/QVwmwPOtliUlfc0iI=",
|
|
||||||
"ldap_server_addr": "ldap://bottin2.service.2.cluster.deuxfleurs.fr:389",
|
"ldap_server_addr": "ldap://bottin2.service.2.cluster.deuxfleurs.fr:389",
|
||||||
|
|
||||||
"base_dn": "dc=deuxfleurs,dc=fr",
|
"base_dn": "dc=deuxfleurs,dc=fr",
|
||||||
@ -14,7 +13,12 @@ Exemple de config.json pour Deuxfleurs:
|
|||||||
"group_base_dn": "ou=groups,dc=deuxfleurs,dc=fr",
|
"group_base_dn": "ou=groups,dc=deuxfleurs,dc=fr",
|
||||||
"group_name_attr": "cn",
|
"group_name_attr": "cn",
|
||||||
|
|
||||||
|
"admin_account": "cn=admin,dc=deuxfleurs,dc=fr",
|
||||||
"group_can_admin": "cn=admin,ou=groups,dc=deuxfleurs,dc=fr",
|
"group_can_admin": "cn=admin,ou=groups,dc=deuxfleurs,dc=fr",
|
||||||
"group_can_invite": "cn=asso_deuxfleurs,ou=groups,dc=deuxfleurs,dc=fr"
|
"group_can_invite": "cn=asso_deuxfleurs,ou=groups,dc=deuxfleurs,dc=fr"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --net host -v $PWD/config.json:/config.json -i lxpz/guichet_amd64:latest
|
||||||
|
```
|
||||||
|
42
admin.go
42
admin.go
@ -78,7 +78,7 @@ func handleAdminUsers(w http.ResponseWriter, r *http.Request) {
|
|||||||
data := &AdminUsersTplData{
|
data := &AdminUsersTplData{
|
||||||
Login: login,
|
Login: login,
|
||||||
UserNameAttr: config.UserNameAttr,
|
UserNameAttr: config.UserNameAttr,
|
||||||
UserBaseDN: config.UserBaseDN,
|
UserBaseDN: config.UserBaseDN,
|
||||||
Users: EntryList(sr.Entries),
|
Users: EntryList(sr.Entries),
|
||||||
}
|
}
|
||||||
sort.Sort(data.Users)
|
sort.Sort(data.Users)
|
||||||
@ -117,7 +117,7 @@ func handleAdminGroups(w http.ResponseWriter, r *http.Request) {
|
|||||||
data := &AdminGroupsTplData{
|
data := &AdminGroupsTplData{
|
||||||
Login: login,
|
Login: login,
|
||||||
GroupNameAttr: config.GroupNameAttr,
|
GroupNameAttr: config.GroupNameAttr,
|
||||||
GroupBaseDN: config.GroupBaseDN,
|
GroupBaseDN: config.GroupBaseDN,
|
||||||
Groups: EntryList(sr.Entries),
|
Groups: EntryList(sr.Entries),
|
||||||
}
|
}
|
||||||
sort.Sort(data.Groups)
|
sort.Sort(data.Groups)
|
||||||
@ -128,11 +128,11 @@ func handleAdminGroups(w http.ResponseWriter, r *http.Request) {
|
|||||||
type AdminLDAPTplData struct {
|
type AdminLDAPTplData struct {
|
||||||
DN string
|
DN string
|
||||||
|
|
||||||
Path []PathItem
|
Path []PathItem
|
||||||
Children []Child
|
Children []Child
|
||||||
CanAddChild bool
|
CanAddChild bool
|
||||||
Props map[string]*PropValues
|
Props map[string]*PropValues
|
||||||
CanDelete bool
|
CanDelete bool
|
||||||
|
|
||||||
HasMembers bool
|
HasMembers bool
|
||||||
Members []EntryName
|
Members []EntryName
|
||||||
@ -161,9 +161,9 @@ type PathItem struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PropValues struct {
|
type PropValues struct {
|
||||||
Name string
|
Name string
|
||||||
Values []string
|
Values []string
|
||||||
Editable bool
|
Editable bool
|
||||||
Deletable bool
|
Deletable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ func handleAdminLDAP(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
dError = err.Error()
|
dError = err.Error()
|
||||||
} else {
|
} else {
|
||||||
http.Redirect(w, r, "/admin/ldap/" + strings.Join(dn_split[1:], ","), http.StatusFound)
|
http.Redirect(w, r, "/admin/ldap/"+strings.Join(dn_split[1:], ","), http.StatusFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -344,16 +344,16 @@ func handleAdminLDAP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
deletable := true
|
deletable := true
|
||||||
for _, restricted := range []string{ "displayname", "objectclass", "structuralobjectclass" } {
|
for _, restricted := range []string{"displayname", "objectclass", "structuralobjectclass"} {
|
||||||
if strings.EqualFold(attr.Name, restricted) {
|
if strings.EqualFold(attr.Name, restricted) {
|
||||||
deletable = false
|
deletable = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
props[name_lower] = &PropValues{
|
props[name_lower] = &PropValues{
|
||||||
Name: attr.Name,
|
Name: attr.Name,
|
||||||
Values: attr.Values,
|
Values: attr.Values,
|
||||||
Editable: editable,
|
Editable: editable,
|
||||||
Deletable: deletable,
|
Deletable: deletable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,11 +468,11 @@ func handleAdminLDAP(w http.ResponseWriter, r *http.Request) {
|
|||||||
templateAdminLDAP.Execute(w, &AdminLDAPTplData{
|
templateAdminLDAP.Execute(w, &AdminLDAPTplData{
|
||||||
DN: dn,
|
DN: dn,
|
||||||
|
|
||||||
Path: path,
|
Path: path,
|
||||||
Children: children,
|
Children: children,
|
||||||
Props: props,
|
Props: props,
|
||||||
CanAddChild: dn_last_attr == "ou" || isOrganization,
|
CanAddChild: dn_last_attr == "ou" || isOrganization,
|
||||||
CanDelete: dn != config.BaseDN && len(children) == 0,
|
CanDelete: dn != config.BaseDN && len(children) == 0,
|
||||||
|
|
||||||
HasMembers: len(members) > 0 || hasMembers,
|
HasMembers: len(members) > 0 || hasMembers,
|
||||||
Members: members,
|
Members: members,
|
||||||
@ -486,14 +486,14 @@ func handleAdminLDAP(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
type CreateData struct {
|
type CreateData struct {
|
||||||
SuperDN string
|
SuperDN string
|
||||||
Path []PathItem
|
Path []PathItem
|
||||||
|
|
||||||
IdType string
|
IdType string
|
||||||
IdValue string
|
IdValue string
|
||||||
DisplayName string
|
DisplayName string
|
||||||
StructuralObjectClass string
|
StructuralObjectClass string
|
||||||
ObjectClass string
|
ObjectClass string
|
||||||
IsTemplated bool
|
IsTemplated bool
|
||||||
|
|
||||||
Error string
|
Error string
|
||||||
}
|
}
|
||||||
@ -548,7 +548,7 @@ func handleAdminCreate(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Handle data
|
// Handle data
|
||||||
data := &CreateData{
|
data := &CreateData{
|
||||||
SuperDN: super_dn,
|
SuperDN: super_dn,
|
||||||
Path: path,
|
Path: path,
|
||||||
}
|
}
|
||||||
if template == "user" {
|
if template == "user" {
|
||||||
data.IdType = config.UserNameAttr
|
data.IdType = config.UserNameAttr
|
||||||
|
76
main.go
76
main.go
@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -21,7 +20,6 @@ import (
|
|||||||
|
|
||||||
type ConfigFile struct {
|
type ConfigFile struct {
|
||||||
HttpBindAddr string `json:"http_bind_addr"`
|
HttpBindAddr string `json:"http_bind_addr"`
|
||||||
SessionKey string `json:"session_key"`
|
|
||||||
LdapServerAddr string `json:"ldap_server_addr"`
|
LdapServerAddr string `json:"ldap_server_addr"`
|
||||||
LdapTLS bool `json:"ldap_tls"`
|
LdapTLS bool `json:"ldap_tls"`
|
||||||
|
|
||||||
@ -31,7 +29,7 @@ type ConfigFile struct {
|
|||||||
GroupBaseDN string `json:"group_base_dn"`
|
GroupBaseDN string `json:"group_base_dn"`
|
||||||
GroupNameAttr string `json:"group_name_attr"`
|
GroupNameAttr string `json:"group_name_attr"`
|
||||||
|
|
||||||
AdminAccount string `json:"admin_account"`
|
AdminAccount string `json:"admin_account"`
|
||||||
GroupCanInvite string `json:"group_can_invite"`
|
GroupCanInvite string `json:"group_can_invite"`
|
||||||
GroupCanAdmin string `json:"group_can_admin"`
|
GroupCanAdmin string `json:"group_can_admin"`
|
||||||
}
|
}
|
||||||
@ -45,15 +43,8 @@ const SESSION_NAME = "guichet_session"
|
|||||||
var store sessions.Store = nil
|
var store sessions.Store = nil
|
||||||
|
|
||||||
func readConfig() ConfigFile {
|
func readConfig() ConfigFile {
|
||||||
key_bytes := make([]byte, 32)
|
|
||||||
n, err := rand.Read(key_bytes)
|
|
||||||
if err != nil || n != 32 {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config_file := ConfigFile{
|
config_file := ConfigFile{
|
||||||
HttpBindAddr: ":9991",
|
HttpBindAddr: ":9991",
|
||||||
SessionKey: base64.StdEncoding.EncodeToString(key_bytes),
|
|
||||||
LdapServerAddr: "ldap://127.0.0.1:389",
|
LdapServerAddr: "ldap://127.0.0.1:389",
|
||||||
LdapTLS: false,
|
LdapTLS: false,
|
||||||
BaseDN: "dc=example,dc=com",
|
BaseDN: "dc=example,dc=com",
|
||||||
@ -66,7 +57,7 @@ func readConfig() ConfigFile {
|
|||||||
GroupCanAdmin: "gid=admin,ou=groups,dc=example,dc=com",
|
GroupCanAdmin: "gid=admin,ou=groups,dc=example,dc=com",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = os.Stat(*configFlag)
|
_, err := os.Stat(*configFlag)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// Generate default config file
|
// Generate default config file
|
||||||
log.Printf("Generating default config file as %s", *configFlag)
|
log.Printf("Generating default config file as %s", *configFlag)
|
||||||
@ -106,7 +97,13 @@ func main() {
|
|||||||
|
|
||||||
config_file := readConfig()
|
config_file := readConfig()
|
||||||
config = &config_file
|
config = &config_file
|
||||||
store = sessions.NewFilesystemStore("", []byte(config.SessionKey))
|
|
||||||
|
session_key := make([]byte, 32)
|
||||||
|
n, err := rand.Read(session_key)
|
||||||
|
if err != nil || n != 32 {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
store = sessions.NewCookieStore(session_key)
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/", handleHome)
|
r.HandleFunc("/", handleHome)
|
||||||
@ -123,7 +120,7 @@ func main() {
|
|||||||
r.Handle("/static/{file:.*}", http.StripPrefix("/static/", staticfiles))
|
r.Handle("/static/{file:.*}", http.StripPrefix("/static/", staticfiles))
|
||||||
|
|
||||||
log.Printf("Starting HTTP server on %s", config.HttpBindAddr)
|
log.Printf("Starting HTTP server on %s", config.HttpBindAddr)
|
||||||
err := http.ListenAndServe(config.HttpBindAddr, logRequest(r))
|
err = http.ListenAndServe(config.HttpBindAddr, logRequest(r))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Cannot start http server: ", err)
|
log.Fatal("Cannot start http server: ", err)
|
||||||
}
|
}
|
||||||
@ -149,28 +146,28 @@ func logRequest(handler http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkLogin(w http.ResponseWriter, r *http.Request) *LoginStatus {
|
func checkLogin(w http.ResponseWriter, r *http.Request) *LoginStatus {
|
||||||
|
var login_info *LoginInfo
|
||||||
|
|
||||||
session, err := store.Get(r, SESSION_NAME)
|
session, err := store.Get(r, SESSION_NAME)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
username, ok := session.Values["login_username"]
|
||||||
return nil
|
password, ok2 := session.Values["login_password"]
|
||||||
|
user_dn, ok3 := session.Values["login_dn"]
|
||||||
|
|
||||||
|
if ok && ok2 && ok3 {
|
||||||
|
login_info = &LoginInfo{
|
||||||
|
DN: user_dn.(string),
|
||||||
|
Username: username.(string),
|
||||||
|
Password: password.(string),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
username, ok := session.Values["login_username"]
|
if login_info == nil {
|
||||||
password, ok2 := session.Values["login_password"]
|
|
||||||
user_dn, ok3 := session.Values["login_dn"]
|
|
||||||
|
|
||||||
var login_info *LoginInfo
|
|
||||||
if !(ok && ok2 && ok3) {
|
|
||||||
login_info = handleLogin(w, r)
|
login_info = handleLogin(w, r)
|
||||||
if login_info == nil {
|
if login_info == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
login_info = &LoginInfo{
|
|
||||||
DN: user_dn.(string),
|
|
||||||
Username: username.(string),
|
|
||||||
Password: password.(string),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l := ldapOpen(w)
|
l := ldapOpen(w)
|
||||||
@ -193,8 +190,8 @@ func checkLogin(w http.ResponseWriter, r *http.Request) *LoginStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loginStatus := &LoginStatus{
|
loginStatus := &LoginStatus{
|
||||||
Info: login_info,
|
Info: login_info,
|
||||||
conn: l,
|
conn: l,
|
||||||
}
|
}
|
||||||
|
|
||||||
requestKind := "(objectClass=organizationalPerson)"
|
requestKind := "(objectClass=organizationalPerson)"
|
||||||
@ -245,11 +242,11 @@ func ldapOpen(w http.ResponseWriter) *ldap.Conn {
|
|||||||
// Page handlers ----
|
// Page handlers ----
|
||||||
|
|
||||||
type HomePageData struct {
|
type HomePageData struct {
|
||||||
Login *LoginStatus
|
Login *LoginStatus
|
||||||
WelcomeName string
|
WelcomeName string
|
||||||
CanAdmin bool
|
CanAdmin bool
|
||||||
CanInvite bool
|
CanInvite bool
|
||||||
BaseDN string
|
BaseDN string
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHome(w http.ResponseWriter, r *http.Request) {
|
func handleHome(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -272,10 +269,10 @@ func handleHome(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data := &HomePageData{
|
data := &HomePageData{
|
||||||
Login: login,
|
Login: login,
|
||||||
CanAdmin: can_admin,
|
CanAdmin: can_admin,
|
||||||
CanInvite: can_invite,
|
CanInvite: can_invite,
|
||||||
BaseDN: config.BaseDN,
|
BaseDN: config.BaseDN,
|
||||||
WelcomeName: login.UserEntry.GetAttributeValue("givenname"),
|
WelcomeName: login.UserEntry.GetAttributeValue("givenname"),
|
||||||
}
|
}
|
||||||
if data.WelcomeName == "" {
|
if data.WelcomeName == "" {
|
||||||
@ -346,8 +343,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
|
|||||||
// Successfully logged in, save it to session
|
// Successfully logged in, save it to session
|
||||||
session, err := store.Get(r, SESSION_NAME)
|
session, err := store.Get(r, SESSION_NAME)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
session, _ = store.New(r, SESSION_NAME)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
session.Values["login_username"] = username
|
session.Values["login_username"] = username
|
||||||
|
@ -146,7 +146,7 @@
|
|||||||
<div class="col-md-3"><strong>Ajouter au groupe :</strong>
|
<div class="col-md-3"><strong>Ajouter au groupe :</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<input class="form-control" type="text" name="values" placeholder="Groupe..." />
|
<input class="form-control" type="text" name="values" placeholder="Utilisateur..." />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<input type="submit" value="Ajouter" class="form-control btn btn-success btn-sm" />
|
<input type="submit" value="Ajouter" class="form-control btn btn-success btn-sm" />
|
||||||
|
Loading…
Reference in New Issue
Block a user