瀏覽代碼

updated LDAP component

AY's Macbook Pro 3 年之前
父節點
當前提交
ecd5e0808a
共有 4 個文件被更改,包括 339 次插入4 次删除
  1. 25 1
      ldap.go
  2. 21 0
      mod/auth/ldap/common.go
  3. 132 3
      mod/auth/ldap/ldap.go
  4. 161 0
      web/SystemAO/advance/ldap.html

+ 25 - 1
ldap.go

@@ -1,10 +1,34 @@
 package main
 
 import (
+	"net/http"
+
 	ldap "imuslab.com/arozos/mod/auth/ldap"
+	prout "imuslab.com/arozos/mod/prouter"
 )
 
 func ldapInit() {
+	//ldap
 	ldapHandler := ldap.NewLdapHandler(authAgent, registerHandler, sysdb)
-	ldapHandler.SyncInformation()
+
+	//add a entry to the system settings
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Setting",
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			errorHandlePermissionDenied(w, r)
+		},
+	})
+	registerSetting(settingModule{
+		Name:         "LDAP<sup>BETA</sup>",
+		Desc:         "Allows external account access to system",
+		IconPath:     "SystemAO/advance/img/small_icon.png",
+		Group:        "Security",
+		StartDir:     "SystemAO/advance/ldap.html",
+		RequireAdmin: true,
+	})
+
+	adminRouter.HandleFunc("/system/auth/ldap/config/read", ldapHandler.ReadConfig)
+	adminRouter.HandleFunc("/system/auth/ldap/config/write", ldapHandler.WriteConfig)
 }

+ 21 - 0
mod/auth/ldap/common.go

@@ -0,0 +1,21 @@
+package ldap
+
+import db "imuslab.com/arozos/mod/database"
+
+func readSingleConfig(key string, coredb *db.Database) string {
+	var value string
+	err := coredb.Read("oauth", key, &value)
+	if err != nil {
+		value = ""
+	}
+	return value
+}
+
+func (ldap *ldapHandler) readSingleConfig(key string) string {
+	var value string
+	err := ldap.coredb.Read("oauth", key, &value)
+	if err != nil {
+		value = ""
+	}
+	return value
+}

+ 132 - 3
mod/auth/ldap/ldap.go

@@ -1,43 +1,172 @@
 package ldap
 
 import (
+	"encoding/json"
 	"log"
+	"net/http"
+	"strconv"
 
 	auth "imuslab.com/arozos/mod/auth"
 	"imuslab.com/arozos/mod/auth/ldap/ldapreader"
 	reg "imuslab.com/arozos/mod/auth/register"
+	"imuslab.com/arozos/mod/common"
 	db "imuslab.com/arozos/mod/database"
 )
 
 type ldapHandler struct {
 	ag         *auth.AuthAgent
 	ldapreader *ldapreader.LdapReader
+	reg        *reg.RegisterHandler
+	coredb     *db.Database
 }
 
+type Config struct {
+	Enabled      bool   `json:"enabled"`
+	AutoRedirect bool   `json:"auto_redirect"`
+	BindUsername string `json:"bind_username"`
+	BindPassword string `json:"bind_password"`
+	FQDN         string `json:"fqdn"`
+	BaseDN       string `json:"base_dn"`
+}
+
+/*
 const (
 	BindUsername = "uid=root,cn=users,dc=dsm"
 	BindPassword = "12345678"
 	FQDN         = "192.168.1.147"
 	BaseDN       = "cn=users,dc=dsm"
 )
+*/
+
+/*
+TODO: not sure why enabled will keep enable
 
-//NewOauthHandler xxx
+*/
+
+//NewLdapHandler xxx
 func NewLdapHandler(authAgent *auth.AuthAgent, register *reg.RegisterHandler, coreDb *db.Database) *ldapHandler {
-	log.Println("Starting LDAP server...")
+	//ldap handler init
+	log.Println("Starting LDAP client...")
 	err := coreDb.NewTable("ldap")
 	if err != nil {
-		log.Println("Failed to create oauth database. Terminating.")
+		log.Println("Failed to create LDAP database. Terminating.")
 		panic(err)
 	}
 
+	//key value to be used for LDAP authentication
+	BindUsername := readSingleConfig("BindUsername", coreDb)
+	BindPassword := readSingleConfig("BindPassword", coreDb)
+	FQDN := readSingleConfig("FQDN", coreDb)
+	BaseDN := readSingleConfig("BaseDN", coreDb)
+
 	LDAPHandler := ldapHandler{
 		ag:         authAgent,
 		ldapreader: ldapreader.NewLDAPReader(BindUsername, BindPassword, FQDN, BaseDN),
+		reg:        register,
+		coredb:     coreDb,
 	}
 
 	return &LDAPHandler
 }
 
+func (ldap *ldapHandler) ReadConfig(w http.ResponseWriter, r *http.Request) {
+	//basic components
+	enabled, err := strconv.ParseBool(ldap.readSingleConfig("enabled"))
+	if err != nil {
+		common.SendTextResponse(w, "Invalid config value [key=enabled].")
+		return
+	}
+	autoredirect, err := strconv.ParseBool(ldap.readSingleConfig("autoredirect"))
+	if err != nil {
+		common.SendTextResponse(w, "Invalid config value [key=autoredirect].")
+		return
+	}
+	//get the LDAP config from db
+	BindUsername := ldap.readSingleConfig("BindUsername")
+	BindPassword := ldap.readSingleConfig("BindPassword")
+	FQDN := ldap.readSingleConfig("FQDN")
+	BaseDN := ldap.readSingleConfig("BaseDN")
+
+	//marshall it and return
+	config, err := json.Marshal(Config{
+		Enabled:      enabled,
+		AutoRedirect: autoredirect,
+		BindUsername: BindUsername,
+		BindPassword: BindPassword,
+		FQDN:         FQDN,
+		BaseDN:       BaseDN,
+	})
+	if err != nil {
+		empty, err := json.Marshal(Config{})
+		if err != nil {
+			common.SendErrorResponse(w, "Error while marshalling config")
+		}
+		common.SendJSONResponse(w, string(empty))
+	}
+	common.SendJSONResponse(w, string(config))
+}
+
+func (ldap *ldapHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
+	enabled, err := common.Mv(r, "enabled", true)
+	if err != nil {
+		common.SendErrorResponse(w, "enabled field can't be empty")
+		return
+	}
+	autoredirect, err := common.Mv(r, "autoredirect", true)
+	if err != nil {
+		common.SendErrorResponse(w, "enabled field can't be empty")
+		return
+	}
+
+	//allow empty fields if enabled is false
+	showError := true
+	if enabled != "true" {
+		showError = false
+	}
+
+	//four fields to store the LDAP authentication information
+	BindUsername, err := common.Mv(r, "bind_username", true)
+	if err != nil {
+		if showError {
+			common.SendErrorResponse(w, "bind_username field can't be empty")
+			return
+		}
+	}
+	BindPassword, err := common.Mv(r, "bind_password", true)
+	if err != nil {
+		if showError {
+			common.SendErrorResponse(w, "bind_password field can't be empty")
+			return
+		}
+	}
+	FQDN, err := common.Mv(r, "fqdn", true)
+	if err != nil {
+		if showError {
+			common.SendErrorResponse(w, "fqdn field can't be empty")
+			return
+		}
+	}
+	BaseDN, err := common.Mv(r, "base_dn", true)
+	if err != nil {
+		if showError {
+			common.SendErrorResponse(w, "base_dn field can't be empty")
+			return
+		}
+	}
+
+	ldap.coredb.Write("ldap", "enabled", enabled)
+	ldap.coredb.Write("ldap", "autoredirect", autoredirect)
+	ldap.coredb.Write("ldap", "BindUsername", BindUsername)
+	ldap.coredb.Write("ldap", "BindPassword", BindPassword)
+	ldap.coredb.Write("ldap", "FQDN", FQDN)
+	ldap.coredb.Write("ldap", "BaseDN", BaseDN)
+
+	//update the new authencation infromation
+	ldap.ldapreader = ldapreader.NewLDAPReader(BindUsername, BindPassword, FQDN, BaseDN)
+
+	common.SendOK(w)
+}
+
 func (handler *ldapHandler) SyncInformation() {
 	result, _ := handler.ldapreader.GetAllUser()
 	for _, v := range result {

+ 161 - 0
web/SystemAO/advance/ldap.html

@@ -0,0 +1,161 @@
+<html>
+
+<head>
+    <title>LDAP Login</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no">
+    <link rel="stylesheet" href="../../script/semantic/semantic.css">
+    <script type="application/javascript" src="../../script/jquery.min.js"></script>
+    <script type="application/javascript" src="../../script/clipboard.min.js"></script>
+    <script type="application/javascript" src="../../script/semantic/semantic.js"></script>
+    <style>
+        /* Tooltip container */
+        
+        .tooltip {
+            position: relative;
+            display: inline-block;
+            border-bottom: 1px dotted black;
+            /* If you want dots under the hoverable text */
+        }
+        /* Tooltip text */
+        
+        .tooltip .tooltiptext {
+            visibility: hidden;
+            width: 120px;
+            background-color: #555;
+            color: #fff;
+            text-align: center;
+            padding: 5px 0;
+            border-radius: 6px;
+            /* Position the tooltip text */
+            position: absolute;
+            z-index: 1;
+            bottom: 125%;
+            left: 50%;
+            margin-left: -60px;
+            /* Fade in tooltip */
+            opacity: 0;
+            transition: opacity 0.3s;
+        }
+        /* Tooltip arrow */
+        
+        .tooltip .tooltiptext::after {
+            content: "";
+            position: absolute;
+            top: 100%;
+            left: 50%;
+            margin-left: -5px;
+            border-width: 5px;
+            border-style: solid;
+            border-color: #555 transparent transparent transparent;
+        }
+    </style>
+</head>
+
+<body>
+    <div class="ui container">
+        <div class="ui basic segment">
+            <div class="ui header">
+                <i class="key icon"></i>
+                <div class="content">
+                    LDAP Access
+                    <div class="sub header">Allow external account to access ArozOS with LDAP</div>
+                </div>
+            </div>
+        </div>
+        <div class="ui divider"></div>
+        <div class="ui green inverted segment" style="display:none;" id="updateSet">
+            <h5 class="ui header">
+                <i class="checkmark icon"></i>
+                <div class="content">
+                    Settings Updated
+                </div>
+            </h5>
+        </div>
+        <div class="ui form">
+            <div class="field">
+                <div class="ui toggle checkbox">
+                    <input type="checkbox" id="enable" name="public">
+                    <label>Enable LDAP</label>
+                </div>
+            </div>
+            <div class="field">
+                <div class="ui toggle checkbox">
+                    <input type="checkbox" id="autoredirect" name="autoredirect">
+                    <label>Auto redirect</label>
+                </div>
+            </div>
+            <div class="field">
+                <label>Bind Username</label>
+                <div class="ui fluid input">
+                    <input type="text" id="bind_username" placeholder="root">
+                </div>
+            </div>
+            <div class="field">
+                <label>Bind Password</label>
+                <div class="ui fluid input">
+                    <input type="text" id="bind_password" placeholder="p@ssw0rd">
+                </div>
+            </div>
+            <div class="field">
+                <label>FQDN</label>
+                <div class="ui fluid input">
+                    <input type="text" id="fqdn" placeholder="10.0.0.1">
+                </div>
+            </div>
+            <div class="field">
+                <label>Base DN</label>
+                <div class="ui fluid input">
+                    <input type="text" id="base_dn" placeholder="cn=users,dc=ldap">
+                </div>
+            </div>
+            <button id="ntb" onclick="update();" class="ui green button" type="submit">Update</button>
+            <button id="test_btn" onclick="test();" class="ui button" type="submit">Test Connection</button>
+        </div>
+        <div class="ui divider"></div>
+        <br><br>
+    </div>
+
+
+    <script>
+        $(document).ready(function() {
+            read();
+        });
+
+        function read() {
+            $.getJSON("../../system/auth/ldap/config/read", function(data) {
+                if (data.enabled) {
+                    $("#enable").parent().checkbox("check")
+                }
+                if (data.autoredirect) {
+                    $("#autoredirect").parent().checkbox("check")
+                }
+                $("#bind_username").val(data.bind_username);
+                $("#bind_password").val(data.bind_password);
+                $("#fqdn").val(data.fqdn);
+                $("#base_dn").val(data.bind_dn);
+            });
+        }
+
+        function update() {
+            $.post("../../system/auth/ldap/config/write", {
+                    enabled: $("#enable").parent().checkbox("is checked"),
+                    autoredirect: $("#autoredirect").parent().checkbox("is checked"),
+                    bind_username: $("#bind_username").val(),
+                    bind_password: $("#bind_password").val(),
+                    fqdn: $("#fqdn").val(),
+                    bind_dn: $("#base_dn").val(),
+                })
+                .done(function(data) {
+                    if (data.error != undefined) {
+                        alert(data.error);
+                    } else {
+                        //OK!
+                        $("#updateSet").stop().finish().slideDown("fast").delay(3000).slideUp('fast');
+                    }
+                });
+        }
+    </script>
+</body>
+
+</html>