Browse Source

Add DNS Record

Sasan Torabkheslat 4 years ago
parent
commit
0e74876fbb
4 changed files with 429 additions and 69 deletions
  1. BIN
      ZiTel-Sysbo-WS
  2. 344 60
      handler.go
  3. 77 3
      main.go
  4. 8 6
      token.go

BIN
ZiTel-Sysbo-WS


+ 344 - 60
handler.go

@@ -1,16 +1,17 @@
 package main
 
 import (
+	"crypto/sha256"
 	"crypto/tls"
 	"encoding/json"
 	"fmt"
+	"github.com/dgrijalva/jwt-go"
+	"github.com/labstack/echo"
 	"io/ioutil"
 	"net/http"
 	"net/url"
 	"strings"
-
-	"github.com/dgrijalva/jwt-go"
-	"github.com/labstack/echo"
+	"time"
 )
 
 type handler struct{}
@@ -73,12 +74,10 @@ type userInfo struct {
 	Principal string      `json:"principal"`
 }
 
-// Most of the code is taken from the echo guide
-// https://echo.labstack.com/cookbook/jwt
 func (h *handler) login(c echo.Context) error {
 	username := c.FormValue("username")
 	password := c.FormValue("password")
-	_url := "https://ipa.sf.faraborddi.dc/ipa/session/login_password"
+	_url := URL + "/ipa/session/login_password"
 	method := "POST"
 	params := url.Values{}
 	params.Add("user", username)
@@ -93,17 +92,18 @@ func (h *handler) login(c echo.Context) error {
 	if err != nil {
 		fmt.Println(err)
 	}
-	req.Header.Add("Referer", "https://ipa.sf.faraborddi.dc/ipa")
+	req.Header.Add("Referer", URL+"/ipa")
 	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
 	req.Header.Add("Accept", "text/plain")
 	res, err := client.Do(req)
 	cockie := res.Cookies()
+	token := cockie[0].Raw
 	defer res.Body.Close()
 	//fmt.Println(res.StatusCode)
 	if res.StatusCode == 200 {
 		user := getUserInfo(cockie, username)
-		//fmt.Println(user.Result.Value)
-		tokens, err := generateTokenPair(user)
+		//fmt.Println(user.Result)
+		tokens, err := generateTokenPair(user, token)
 		if err != nil {
 			return err
 		}
@@ -114,7 +114,7 @@ func (h *handler) login(c echo.Context) error {
 	return echo.ErrUnauthorized
 }
 func getUserInfo(cockie []*http.Cookie, username string) userInfo {
-	url := "https://ipa.sf.faraborddi.dc/ipa/session/json"
+	url := URL + "/ipa/session/json"
 	method := "POST"
 	_json := fmt.Sprintf(`
 {
@@ -142,7 +142,7 @@ func getUserInfo(cockie []*http.Cookie, username string) userInfo {
 	if err != nil {
 		fmt.Println(err)
 	}
-	req.Header.Add("Referer", "https://ipa.sf.faraborddi.dc/ipa")
+	req.Header.Add("Referer", URL+"/ipa")
 	req.Header.Add("Content-Type", "application/json")
 	req.Header.Add("Accept", "text/plain")
 	req.Header.Add("Cookie", cockie[0].Raw)
@@ -151,60 +151,344 @@ func getUserInfo(cockie []*http.Cookie, username string) userInfo {
 	body, err := ioutil.ReadAll(res.Body)
 	user := userInfo{}
 	json.Unmarshal(body, &user)
-	//fmt.Println(user.Result.Value)
-	//fmt.Println(user.Result.Result.MemberofGroup)
 	return user
 }
-
-// This is the api to refresh tokens
-// Most of the code is taken from the jwt-go package's sample codes
-// https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac
-//func (h *handler) token(c echo.Context) error {
-//	type tokenReqBody struct {
-//		RefreshToken string `json:"refresh_token"`
-//	}
-//	tokenReq := tokenReqBody{}
-//	c.Bind(&tokenReq)
-//
-//	// Parse takes the token string and a function for looking up the key.
-//	// The latter is especially useful if you use multiple keys for your application.
-//	// The standard is to use 'kid' in the head of the token to identify
-//	// which key to use, but the parsed token (head and claims) is provided
-//	// to the callback, providing flexibility.
-//	token, err := jwt.Parse(tokenReq.RefreshToken, func(token *jwt.Token) (interface{}, error) {
-//		// Don't forget to validate the alg is what you expect:
-//		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
-//			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
-//		}
-//
-//		// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
-//		return []byte("secret"), nil
-//	})
-//
-//	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
-//		// Get the user record from database or
-//		// run through your business logic to verify if the user can log in
-//		if int(claims["sub"].(float64)) == 1 {
-//
-//			newTokenPair, err := generateTokenPair()
-//			if err != nil {
-//				return err
-//			}
-//
-//			return c.JSON(http.StatusOK, newTokenPair)
-//		}
-//
-//		return echo.ErrUnauthorized
-//	}
-//
-//	return err
-//}
-
-// Most of the code is taken from the echo guide
-// https://echo.labstack.com/cookbook/jwt
 func (h *handler) private(c echo.Context) error {
 	user := c.Get("user").(*jwt.Token)
 	claims := user.Claims.(jwt.MapClaims)
 	name := claims["name"].(string)
 	return c.String(http.StatusOK, "Welcome "+name+"!")
 }
+func (h *handler) addUser(c echo.Context) error {
+	type apiErr struct {
+		Result interface{} `json:"result"`
+		Error  struct {
+			Code    int    `json:"code"`
+			Message string `json:"message"`
+			Data    struct {
+			} `json:"data"`
+			Name string `json:"name"`
+		} `json:"error"`
+		ID        int    `json:"id"`
+		Principal string `json:"principal"`
+		Version   string `json:"version"`
+	}
+	type addUser struct {
+		Result struct {
+			Result struct {
+				Displayname           []string `json:"displayname"`
+				UID                   []string `json:"uid"`
+				Uidnumber             []string `json:"uidnumber"`
+				Objectclass           []string `json:"objectclass"`
+				Sn                    []string `json:"sn"`
+				Telephonenumber       []string `json:"telephonenumber"`
+				Cn                    []string `json:"cn"`
+				Krbpasswordexpiration []struct {
+					Datetime string `json:"__datetime__"`
+				} `json:"krbpasswordexpiration"`
+				Mobile           []string `json:"mobile"`
+				Krbprincipalname []string `json:"krbprincipalname"`
+				Ipauniqueid      []string `json:"ipauniqueid"`
+				Givenname        []string `json:"givenname"`
+				Gidnumber        []string `json:"gidnumber"`
+				Krbcanonicalname []string `json:"krbcanonicalname"`
+				Mail             []string `json:"mail"`
+				Initials         []string `json:"initials"`
+				Homedirectory    []string `json:"homedirectory"`
+				Loginshell       []string `json:"loginshell"`
+				Gecos            []string `json:"gecos"`
+				Randompassword   string   `json:"randompassword"`
+				HasPassword      bool     `json:"has_password"`
+				HasKeytab        bool     `json:"has_keytab"`
+				MemberofGroup    []string `json:"memberof_group"`
+				Dn               string   `json:"dn"`
+			} `json:"result"`
+			Value   string `json:"value"`
+			Summary string `json:"summary"`
+		} `json:"result"`
+		Error     string `json:"error"`
+		ID        int    `json:"id"`
+		Principal string `json:"principal"`
+		Version   string `json:"version"`
+	}
+	user := c.Get("user").(*jwt.Token)
+	claims := user.Claims.(jwt.MapClaims)
+	token := claims["IPAToken"].(string)
+	b, err := json.Marshal(claims)
+	if err != nil {
+		fmt.Println("err:", err)
+	}
+	username := c.FormValue("Username")
+	sha256 := sha256.Sum256([]byte(username))
+	var hashChannel = make(chan []byte, 1)
+	hashChannel <- sha256[:]
+	ciphertext := encrypt(<-hashChannel, string(b))
+	//fmt.Println(b)
+	//fmt.Println(ciphertext)
+	sn := c.FormValue("Lname")
+	cn := c.FormValue("FullName")
+	givenname := c.FormValue("Fname")
+	displayname := c.FormValue("displayname")
+	krbpasswordexpiration := c.FormValue("krbpasswordexpiration")
+	mail := c.FormValue("mail")
+	telephonenumber := c.FormValue("telephonenumber")
+	mobile := c.FormValue("mobile")
+	_url := URL + "/ipa/session/json"
+	method := "POST"
+	_json := fmt.Sprintf(`
+{
+    "id": 0,
+    "method": "user_add/1",
+    "params": [
+        [
+            "%s"
+        ],
+        {
+            "givenname": "%s",
+            "sn": "%s",
+            "cn":"%s",
+            "displayname":"%s",
+            "loginshell":"/usr/sbin/nologin",
+            "krbpasswordexpiration":"%s",
+            "mail":"%s",
+            "random":"true",
+            "gidnumber":"599200001",
+            "telephonenumber":"%s",
+            "mobile":"%s",
+            "version": "2.235"
+        }
+    ]
+}
+`, username, givenname, sn, cn, displayname, krbpasswordexpiration, mail, telephonenumber, mobile)
+	__json := fmt.Sprintf(`
+{
+    "id": 0,
+    "method": "group_add_member/1",
+    "params": [
+        [
+            "svcaccounts"
+        ],
+        {
+            "user": [
+                "%s"
+            ],
+            "version": "2.235"
+        }
+    ]
+}
+`, username)
+	payload := strings.NewReader(_json)
+	_payload := strings.NewReader(__json)
+	tr := &http.Transport{
+		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+	}
+	client := &http.Client{Transport: tr}
+	req, err := http.NewRequest(method, _url, payload)
+	if err != nil {
+		fmt.Println(err)
+	}
+	req.Header.Add("Referer", URL+"/ipa")
+	req.Header.Add("Content-Type", "application/json")
+	req.Header.Add("Accept", "text/plain")
+	req.Header.Add("Cookie", token)
+	res, err := client.Do(req)
+	_req, _ := http.NewRequest(method, _url, _payload)
+	_req.Header.Add("Referer", URL+"/ipa")
+	_req.Header.Add("Content-Type", "application/json")
+	_req.Header.Add("Accept", "text/plain")
+	_req.Header.Add("Cookie", token)
+	client.Do(_req)
+	defer res.Body.Close()
+	body, err := ioutil.ReadAll(res.Body)
+	result := addUser{}
+	_err := json.Unmarshal(body, &result)
+	if _err != nil {
+		_apiErr := apiErr{}
+		__err := json.Unmarshal(body, &_apiErr)
+		if __err != nil {
+			return c.String(http.StatusBadRequest, "Error of error!!")
+		}
+		res2B, _ := json.Marshal(_apiErr)
+		return c.String(http.StatusBadRequest, "Failed with error \n"+string(res2B))
+	}
+	sendMail("Welcome to ZiCloud\r\n Your temporary link is :\r\n https://zicloud.com/reset/"+url.QueryEscape(ciphertext), "Welcome to ZiCloud", mail)
+	return c.String(http.StatusOK, "Done, Pass:"+string(ciphertext))
+}
+func (h *handler) disableUser(c echo.Context) error {
+	user := c.Get("user").(*jwt.Token)
+	claims := user.Claims.(jwt.MapClaims)
+	token := claims["IPAToken"].(string)
+	username := c.FormValue("Username")
+	url := URL + "/ipa/session/json"
+	method := "POST"
+	_json := fmt.Sprintf(`
+{
+    "id": 0,
+    "method": "user_disable/1",
+    "params": [
+        [
+            "%s"
+        ],
+        {
+            "version": "2.235"
+        }
+    ]
+}
+`, username)
+	payload := strings.NewReader(_json)
+	tr := &http.Transport{
+		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+	}
+	client := &http.Client{Transport: tr}
+	req, err := http.NewRequest(method, url, payload)
+	if err != nil {
+		fmt.Println(err)
+	}
+	req.Header.Add("Referer", URL+"/ipa")
+	req.Header.Add("Content-Type", "application/json")
+	req.Header.Add("Accept", "text/plain")
+	req.Header.Add("Cookie", token)
+	res, err := client.Do(req)
+	if err != nil {
+		return c.String(http.StatusBadRequest, "Error"+err.Error())
+	}
+	defer res.Body.Close()
+	return c.String(http.StatusOK, "Done")
+}
+func (h *handler) resetUser(c echo.Context) error {
+	type keyJson struct {
+		IPAToken string   `json:"IPAToken"`
+		Admin    bool     `json:"admin"`
+		Exp      int      `json:"exp"`
+		Memberof []string `json:"memberof"`
+		Name     []string `json:"name"`
+		Sub      int      `json:"sub"`
+	}
+	t := time.Now() //%Y%m%d%H%M%SZ
+	t = t.Add(time.Hour * 24 * 60)
+	username := c.FormValue("Username")
+	password := c.FormValue("Password")
+	key := c.FormValue("key")
+	key, _ = url.QueryUnescape(key)
+	sha256 := sha256.Sum256([]byte(username))
+	var hashChannel = make(chan []byte, 1)
+	hashChannel <- sha256[:]
+	plainkey := decrypt(<-hashChannel, key)
+	_plainkey := keyJson{}
+	json.Unmarshal([]byte(plainkey), &_plainkey)
+	token := _plainkey.IPAToken
+	_url := URL + "/ipa/session/json"
+	method := "POST"
+	_json := fmt.Sprintf(`
+{
+    "id": 0,
+    "method": "user_mod/1",
+    "params": [
+        [
+            "%s"
+        ],
+        {
+			"userpassword":"%s",
+            "version": "2.235"
+        }
+    ]
+}
+`, username, password)
+	payload := strings.NewReader(_json)
+	tr := &http.Transport{
+		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+	}
+	client := &http.Client{Transport: tr}
+	req, err := http.NewRequest(method, _url, payload)
+	if err != nil {
+		fmt.Println(err)
+	}
+	req.Header.Add("Referer", URL+"/ipa")
+	req.Header.Add("Content-Type", "application/json")
+	req.Header.Add("Accept", "text/plain")
+	req.Header.Add("Cookie", token)
+	res, err := client.Do(req)
+	_json = fmt.Sprintf(`
+{
+    "id": 0,
+    "method": "user_mod/1",
+    "params": [
+        [
+            "%s"
+        ],
+        {
+            "krbpasswordexpiration":"%s",
+            "version": "2.235"
+        }
+    ]
+}
+`, username, t.Format("2006-01-02")+"Z")
+	payload = strings.NewReader(_json)
+	req, err = http.NewRequest(method, _url, payload)
+	if err != nil {
+		fmt.Println(err)
+	}
+	req.Header.Add("Referer", URL+"/ipa")
+	req.Header.Add("Content-Type", "application/json")
+	req.Header.Add("Accept", "text/plain")
+	req.Header.Add("Cookie", token)
+	err = nil
+	res, err = client.Do(req)
+	//fmt.Println(payload)
+	if err != nil {
+		return c.String(http.StatusBadRequest, "Error"+err.Error())
+	}
+	defer res.Body.Close()
+	return c.String(http.StatusOK, "Done")
+}
+func (h *handler) dnsrecordadd(c echo.Context) error {
+	user := c.Get("user").(*jwt.Token)
+	claims := user.Claims.(jwt.MapClaims)
+	token := claims["IPAToken"].(string)
+	recordName := c.FormValue("recordName")
+	record := c.FormValue("record")
+	url := URL + "/ipa/session/json"
+	method := "POST"
+	_json := fmt.Sprintf(`
+{
+    "id": 0,
+    "method": "dnsrecord_add/1",
+    "params": [
+        [
+            "ZI-TEL.COM",
+            {
+                "__dns_name__": "%s"
+            }
+        ],
+        {
+            "a_part_ip_address": "%s",
+            "raw": true,
+            "version": "2.235"
+        }
+    ]
+}
+`, recordName, record)
+	payload := strings.NewReader(_json)
+	tr := &http.Transport{
+		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+	}
+	client := &http.Client{Transport: tr}
+	req, err := http.NewRequest(method, url, payload)
+	if err != nil {
+		fmt.Println(err)
+	}
+	req.Header.Add("Referer", URL+"/ipa")
+	req.Header.Add("Content-Type", "application/json")
+	req.Header.Add("Accept", "text/plain")
+	req.Header.Add("Cookie", token)
+	res, err := client.Do(req)
+	if err != nil {
+		return c.String(http.StatusBadRequest, "Error"+err.Error())
+	}
+	//body, err := ioutil.ReadAll(res.Body)
+	//_res:=result{}
+	//json.Unmarshal(body, &_res)
+	//fmt.Println(_res)
+	defer res.Body.Close()
+	return c.String(http.StatusOK, "Done")
+}

+ 77 - 3
main.go

@@ -1,16 +1,24 @@
 package main
 
 import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/rand"
+	"encoding/base64"
 	"fmt"
 	"github.com/labstack/echo"
+	"io"
 	"log"
 	"log/syslog"
 	"net/http"
+	"net/smtp"
 	"os"
+	"time"
 )
 
 var _appversion string = "0.1"
-var _appname string = "ZiTel-Sysbo-WS"
+var _appname string = "ZiCloud-API"
+var URL string = "https://ipa-cl.zi-tel.com"
 
 func audit(txt string) {
 
@@ -25,6 +33,24 @@ func audit(txt string) {
 
 var RealIP string
 
+var secretKey = []byte("P*%!5+u!$y+cgM+P8bybzgnXpsd2Lv2z") // 32 bytes
+func sendMail(str string, subject string, recipient string) {
+	auth := smtp.PlainAuth("", "zicloud@zi-tel.com", "5Sd?^AQx@r2OGRvS?i|DO0", "mail.zi-tel.com")
+	to := []string{recipient}
+	buff := make([]byte, 8)
+	rand.Read(buff)
+	random_str := base64.StdEncoding.EncodeToString(buff)
+	msg := []byte("To:" + recipient + "\r\n" +
+		"Date: " + time.Now().String() + "\r\n" +
+		"Message-Id: <" + random_str + "@ZiCloud.com>" + "\r\n" +
+		"subject: " + subject + "\r\n" +
+		"From: ZiCloud <" + "zicloud@zi-tel.com" + ">\r\n" +
+		str)
+	err := smtp.SendMail("mail.zi-tel.com:25", auth, "zicloud@zi-tel.com", to, msg)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
 func extractIP(next echo.HandlerFunc) echo.HandlerFunc {
 	return func(c echo.Context) error {
 		RealIP = c.RealIP()
@@ -51,8 +77,56 @@ func main() {
 	echoHandler.GET("/private", h.private, isLoggedIn)
 
 	echoHandler.GET("/admin", h.private, isLoggedIn, isAdmin)
-
-	//echoHandler.POST("/token", h.token)
+	echoHandler.POST("/addUser", h.addUser, isLoggedIn, isAdmin)
+	echoHandler.POST("/disableUser", h.disableUser, isLoggedIn, isAdmin)
+	echoHandler.POST("/resetUser", h.resetUser)
+	echoHandler.POST("/dnsrecordadd", h.dnsrecordadd, isLoggedIn, isAdmin)
 
 	echoHandler.Logger.Fatal(echoHandler.Start(os.Args[1] + ":" + os.Args[2]))
 }
+func encrypt(key []byte, text string) string {
+	// key := []byte(keyText)
+	plaintext := []byte(text)
+
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		panic(err)
+	}
+
+	// The IV needs to be unique, but not secure. Therefore it's common to
+	// include it at the beginning of the ciphertext.
+	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
+	iv := ciphertext[:aes.BlockSize]
+	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
+		panic(err)
+	}
+
+	stream := cipher.NewCFBEncrypter(block, iv)
+	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
+
+	// convert to base64
+	return base64.URLEncoding.EncodeToString(ciphertext)
+}
+func decrypt(key []byte, cryptoText string) string {
+	ciphertext, _ := base64.URLEncoding.DecodeString(cryptoText)
+
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		panic(err)
+	}
+
+	// The IV needs to be unique, but not secure. Therefore it's common to
+	// include it at the beginning of the ciphertext.
+	if len(ciphertext) < aes.BlockSize {
+		panic("ciphertext too short")
+	}
+	iv := ciphertext[:aes.BlockSize]
+	ciphertext = ciphertext[aes.BlockSize:]
+
+	stream := cipher.NewCFBDecrypter(block, iv)
+
+	// XORKeyStream can work in-place if the two arguments are the same.
+	stream.XORKeyStream(ciphertext, ciphertext)
+
+	return fmt.Sprintf("%s", ciphertext)
+}

+ 8 - 6
token.go

@@ -6,7 +6,7 @@ import (
 	"github.com/dgrijalva/jwt-go"
 )
 
-func generateTokenPair(user userInfo) (map[string]string, error) {
+func generateTokenPair(user userInfo, cockieStr string) (map[string]string, error) {
 	// Create token
 	token := jwt.New(jwt.SigningMethodHS256)
 
@@ -16,12 +16,14 @@ func generateTokenPair(user userInfo) (map[string]string, error) {
 	claims := token.Claims.(jwt.MapClaims)
 	claims["admin"] = false
 	for _, v := range user.Result.Result.MemberofGroup {
-		if v == "admins" {
+		if v == "usermodifier" || v == "admins" {
 			claims["admin"] = true
 		}
 	}
 	claims["sub"] = 1
-	claims["name"] = user.Result.Value
+	claims["name"] = user.Result.Result.Displayname
+	claims["IPAToken"] = cockieStr
+	claims["memberof"] = user.Result.Result.MemberofGroup
 	claims["exp"] = time.Now().Add(time.Minute * 15).Unix()
 
 	// Generate encoded token and send it as response.
@@ -36,13 +38,13 @@ func generateTokenPair(user userInfo) (map[string]string, error) {
 	rtClaims["sub"] = 1
 	rtClaims["exp"] = time.Now().Add(time.Hour * 24).Unix()
 
-	rt, err := refreshToken.SignedString([]byte("secret"))
+	//rt, err := refreshToken.SignedString([]byte("secret"))
 	if err != nil {
 		return nil, err
 	}
 
 	return map[string]string{
-		"access_token":  t,
-		"refresh_token": rt,
+		"access_token": t,
+		//"refresh_token": rt,
 	}, nil
 }