Better tools for initial setup
This commit is contained in:
parent
61a76f624d
commit
e2e8a443ae
5 changed files with 73 additions and 22 deletions
41
admin.go
41
admin.go
|
@ -18,7 +18,7 @@ func checkAdminLogin(w http.ResponseWriter, r *http.Request) *LoginStatus {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
can_admin := false
|
can_admin := (login.Info.DN == config.AdminAccount)
|
||||||
for _, group := range login.UserEntry.GetAttributeValues("memberof") {
|
for _, group := range login.UserEntry.GetAttributeValues("memberof") {
|
||||||
if config.GroupCanAdmin != "" && group == config.GroupCanAdmin {
|
if config.GroupCanAdmin != "" && group == config.GroupCanAdmin {
|
||||||
can_admin = true
|
can_admin = true
|
||||||
|
@ -320,7 +320,7 @@ func handleAdminLDAP(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sr.Entries) != 1 {
|
if len(sr.Entries) != 1 {
|
||||||
http.Error(w, fmt.Sprintf("%d objects found", len(sr.Entries)), http.StatusInternalServerError)
|
http.Error(w, fmt.Sprintf("Object not found: %s", dn), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,6 +509,25 @@ func handleAdminCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
template := mux.Vars(r)["template"]
|
template := mux.Vars(r)["template"]
|
||||||
super_dn := mux.Vars(r)["super_dn"]
|
super_dn := mux.Vars(r)["super_dn"]
|
||||||
|
|
||||||
|
// Check that base DN exists
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
super_dn,
|
||||||
|
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
|
fmt.Sprintf("(objectclass=*)"),
|
||||||
|
[]string{},
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := login.conn.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sr.Entries) != 1 {
|
||||||
|
http.Error(w, fmt.Sprintf("Parent object %s does not exist", super_dn), http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Build path
|
// Build path
|
||||||
path := []PathItem{
|
path := []PathItem{
|
||||||
PathItem{
|
PathItem{
|
||||||
|
@ -541,6 +560,11 @@ func handleAdminCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
data.StructuralObjectClass = "groupOfNames"
|
data.StructuralObjectClass = "groupOfNames"
|
||||||
data.ObjectClass = "groupOfNames\ntop"
|
data.ObjectClass = "groupOfNames\ntop"
|
||||||
data.IsTemplated = true
|
data.IsTemplated = true
|
||||||
|
} else if template == "ou" {
|
||||||
|
data.IdType = "ou"
|
||||||
|
data.StructuralObjectClass = "organizationalUnit"
|
||||||
|
data.ObjectClass = "organizationalUnit\ntop"
|
||||||
|
data.IsTemplated = true
|
||||||
} else {
|
} else {
|
||||||
data.IdType = "cn"
|
data.IdType = "cn"
|
||||||
data.ObjectClass = "top"
|
data.ObjectClass = "top"
|
||||||
|
@ -549,12 +573,12 @@ func handleAdminCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method == "POST" {
|
if r.Method == "POST" {
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
if !data.IsTemplated {
|
if !data.IsTemplated {
|
||||||
data.IdType = strings.Join(r.Form["idtype"], "")
|
data.IdType = strings.TrimSpace(strings.Join(r.Form["idtype"], ""))
|
||||||
data.StructuralObjectClass = strings.Join(r.Form["soc"], "")
|
data.StructuralObjectClass = strings.TrimSpace(strings.Join(r.Form["soc"], ""))
|
||||||
data.ObjectClass = strings.Join(r.Form["oc"], "")
|
data.ObjectClass = strings.Join(r.Form["oc"], "")
|
||||||
}
|
}
|
||||||
data.IdValue = strings.Join(r.Form["idvalue"], "")
|
data.IdValue = strings.TrimSpace(strings.Join(r.Form["idvalue"], ""))
|
||||||
data.DisplayName = strings.Join(r.Form["displayname"], "")
|
data.DisplayName = strings.TrimSpace(strings.Join(r.Form["displayname"], ""))
|
||||||
|
|
||||||
object_class := []string{}
|
object_class := []string{}
|
||||||
for _, oc := range strings.Split(data.ObjectClass, "\n") {
|
for _, oc := range strings.Split(data.ObjectClass, "\n") {
|
||||||
|
@ -578,7 +602,10 @@ func handleAdminCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
req.Attribute("objectClass", object_class)
|
req.Attribute("objectClass", object_class)
|
||||||
req.Attribute("structuralObjectClass",
|
req.Attribute("structuralObjectClass",
|
||||||
[]string{data.StructuralObjectClass})
|
[]string{data.StructuralObjectClass})
|
||||||
req.Attribute("displayname", []string{data.DisplayName})
|
if data.DisplayName != "" {
|
||||||
|
req.Attribute("displayname", []string{data.DisplayName})
|
||||||
|
}
|
||||||
|
|
||||||
err := login.conn.Add(req)
|
err := login.conn.Add(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
data.Error = err.Error()
|
data.Error = err.Error()
|
||||||
|
|
43
main.go
43
main.go
|
@ -31,6 +31,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"`
|
||||||
GroupCanInvite string `json:"group_can_invite"`
|
GroupCanInvite string `json:"group_can_invite"`
|
||||||
GroupCanAdmin string `json:"group_can_admin"`
|
GroupCanAdmin string `json:"group_can_admin"`
|
||||||
}
|
}
|
||||||
|
@ -60,6 +61,7 @@ func readConfig() ConfigFile {
|
||||||
UserNameAttr: "uid",
|
UserNameAttr: "uid",
|
||||||
GroupBaseDN: "ou=groups,dc=example,dc=com",
|
GroupBaseDN: "ou=groups,dc=example,dc=com",
|
||||||
GroupNameAttr: "gid",
|
GroupNameAttr: "gid",
|
||||||
|
AdminAccount: "uid=admin,dc=example,dc=com",
|
||||||
GroupCanInvite: "",
|
GroupCanInvite: "",
|
||||||
GroupCanAdmin: "gid=admin,ou=groups,dc=example,dc=com",
|
GroupCanAdmin: "gid=admin,ou=groups,dc=example,dc=com",
|
||||||
}
|
}
|
||||||
|
@ -120,6 +122,7 @@ func main() {
|
||||||
staticfiles := http.FileServer(http.Dir("static"))
|
staticfiles := http.FileServer(http.Dir("static"))
|
||||||
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)
|
||||||
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)
|
||||||
|
@ -189,10 +192,19 @@ func checkLogin(w http.ResponseWriter, r *http.Request) *LoginStatus {
|
||||||
return checkLogin(w, r)
|
return checkLogin(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loginStatus := &LoginStatus{
|
||||||
|
Info: login_info,
|
||||||
|
conn: l,
|
||||||
|
}
|
||||||
|
|
||||||
|
requestKind := "(objectClass=organizationalPerson)"
|
||||||
|
if login_info.DN == config.AdminAccount {
|
||||||
|
requestKind = "(objectclass=*)"
|
||||||
|
}
|
||||||
searchRequest := ldap.NewSearchRequest(
|
searchRequest := ldap.NewSearchRequest(
|
||||||
login_info.DN,
|
login_info.DN,
|
||||||
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
|
ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
|
||||||
fmt.Sprintf("(&(objectClass=organizationalPerson))"),
|
requestKind,
|
||||||
[]string{"dn", "displayname", "givenname", "sn", "mail", "memberof"},
|
[]string{"dn", "displayname", "givenname", "sn", "mail", "memberof"},
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
|
@ -203,15 +215,13 @@ func checkLogin(w http.ResponseWriter, r *http.Request) *LoginStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sr.Entries) != 1 {
|
if len(sr.Entries) != 1 {
|
||||||
http.Error(w, fmt.Sprintf("Multiple entries: %#v", sr.Entries), http.StatusInternalServerError)
|
http.Error(w, fmt.Sprintf("Unable to find entry for %s", login_info.DN), http.StatusInternalServerError)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &LoginStatus{
|
loginStatus.UserEntry = sr.Entries[0]
|
||||||
Info: login_info,
|
|
||||||
conn: l,
|
return loginStatus
|
||||||
UserEntry: sr.Entries[0],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ldapOpen(w http.ResponseWriter) *ldap.Conn {
|
func ldapOpen(w http.ResponseWriter) *ldap.Conn {
|
||||||
|
@ -236,6 +246,7 @@ func ldapOpen(w http.ResponseWriter) *ldap.Conn {
|
||||||
|
|
||||||
type HomePageData struct {
|
type HomePageData struct {
|
||||||
Login *LoginStatus
|
Login *LoginStatus
|
||||||
|
WelcomeName string
|
||||||
CanAdmin bool
|
CanAdmin bool
|
||||||
CanInvite bool
|
CanInvite bool
|
||||||
BaseDN string
|
BaseDN string
|
||||||
|
@ -249,7 +260,7 @@ func handleHome(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
can_admin := false
|
can_admin := (login.Info.DN == config.AdminAccount)
|
||||||
can_invite := false
|
can_invite := false
|
||||||
for _, group := range login.UserEntry.GetAttributeValues("memberof") {
|
for _, group := range login.UserEntry.GetAttributeValues("memberof") {
|
||||||
if config.GroupCanInvite != "" && group == config.GroupCanInvite {
|
if config.GroupCanInvite != "" && group == config.GroupCanInvite {
|
||||||
|
@ -260,12 +271,21 @@ func handleHome(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
templateHome.Execute(w, &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"),
|
||||||
|
}
|
||||||
|
if data.WelcomeName == "" {
|
||||||
|
data.WelcomeName = login.UserEntry.GetAttributeValue("displayname")
|
||||||
|
}
|
||||||
|
if data.WelcomeName == "" {
|
||||||
|
data.WelcomeName = login.Info.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
templateHome.Execute(w, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleLogout(w http.ResponseWriter, r *http.Request) {
|
func handleLogout(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -305,6 +325,9 @@ func handleLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
|
||||||
username := strings.Join(r.Form["username"], "")
|
username := strings.Join(r.Form["username"], "")
|
||||||
password := strings.Join(r.Form["password"], "")
|
password := strings.Join(r.Form["password"], "")
|
||||||
user_dn := fmt.Sprintf("%s=%s,%s", config.UserNameAttr, username, config.UserBaseDN)
|
user_dn := fmt.Sprintf("%s=%s,%s", config.UserNameAttr, username, config.UserBaseDN)
|
||||||
|
if username == config.AdminAccount {
|
||||||
|
user_dn = username
|
||||||
|
}
|
||||||
|
|
||||||
l := ldapOpen(w)
|
l := ldapOpen(w)
|
||||||
if l == nil {
|
if l == nil {
|
||||||
|
|
|
@ -35,10 +35,10 @@ func handleProfile(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method == "POST" {
|
if r.Method == "POST" {
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
|
|
||||||
data.Mail = strings.Join(r.Form["mail"], "")
|
data.Mail = strings.TrimSpace(strings.Join(r.Form["mail"], ""))
|
||||||
data.DisplayName = strings.Join(r.Form["display_name"], "")
|
data.DisplayName = strings.TrimSpace(strings.Join(r.Form["display_name"], ""))
|
||||||
data.GivenName = strings.Join(r.Form["given_name"], "")
|
data.GivenName = strings.TrimSpace(strings.Join(r.Form["given_name"], ""))
|
||||||
data.Surname = strings.Join(r.Form["surname"], "")
|
data.Surname = strings.TrimSpace(strings.Join(r.Form["surname"], ""))
|
||||||
|
|
||||||
modify_request := ldap.NewModifyRequest(login.Info.DN, nil)
|
modify_request := ldap.NewModifyRequest(login.Info.DN, nil)
|
||||||
modify_request.Replace("mail", []string{data.Mail})
|
modify_request.Replace("mail", []string{data.Mail})
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<a class="btn btn-sm btn-success" href="/admin/create/user/{{.DN}}">+utilisateur</a>
|
<a class="btn btn-sm btn-success" href="/admin/create/user/{{.DN}}">+utilisateur</a>
|
||||||
<a class="ml-4 btn btn-sm btn-success" href="/admin/create/group/{{.DN}}">+groupe</a>
|
<a class="ml-4 btn btn-sm btn-success" href="/admin/create/group/{{.DN}}">+groupe</a>
|
||||||
|
<a class="ml-4 btn btn-sm btn-success" href="/admin/create/ou/{{.DN}}">+ou</a>
|
||||||
<a class="ml-4 btn btn-sm btn-success" href="/admin/create/generic/{{.DN}}">+objet</a>
|
<a class="ml-4 btn btn-sm btn-success" href="/admin/create/generic/{{.DN}}">+objet</a>
|
||||||
</div>
|
</div>
|
||||||
<hr class="mt-4" />
|
<hr class="mt-4" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
Bienvenue, <strong>{{ .Login.UserEntry.GetAttributeValue "givenname" }}</strong> !
|
Bienvenue, <strong>{{ .WelcomeName }}</strong> !
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<a class="ml-auto btn btn-sm btn-dark" href="/logout">Se déconnecter</a>
|
<a class="ml-auto btn btn-sm btn-dark" href="/logout">Se déconnecter</a>
|
||||||
|
|
Loading…
Reference in a new issue