|
@@ -0,0 +1,217 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "crypto/tls"
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "io/ioutil"
|
|
|
+ "net/http"
|
|
|
+ "net/url"
|
|
|
+ "strings"
|
|
|
+
|
|
|
+ "github.com/dgrijalva/jwt-go"
|
|
|
+ "github.com/labstack/echo"
|
|
|
+)
|
|
|
+
|
|
|
+type handler struct{}
|
|
|
+type userInfo struct {
|
|
|
+ Result struct {
|
|
|
+ Result struct {
|
|
|
+ Sshpubkeyfp []string `json:"sshpubkeyfp"`
|
|
|
+ HasKeytab bool `json:"has_keytab"`
|
|
|
+ Ipasshpubkey []string `json:"ipasshpubkey"`
|
|
|
+ Cn []string `json:"cn"`
|
|
|
+ Krbcanonicalname []string `json:"krbcanonicalname"`
|
|
|
+ Krbticketflags []string `json:"krbticketflags"`
|
|
|
+ MemberofGroup []string `json:"memberof_group"`
|
|
|
+ HasPassword bool `json:"has_password"`
|
|
|
+ Homedirectory []string `json:"homedirectory"`
|
|
|
+ Nsaccountlock bool `json:"nsaccountlock"`
|
|
|
+ UID []string `json:"uid"`
|
|
|
+ Title []string `json:"title"`
|
|
|
+ Loginshell []string `json:"loginshell"`
|
|
|
+ Uidnumber []string `json:"uidnumber"`
|
|
|
+ Preserved bool `json:"preserved"`
|
|
|
+ Krbextradata []struct {
|
|
|
+ Base64 string `json:"__base64__"`
|
|
|
+ } `json:"krbextradata"`
|
|
|
+ Mail []string `json:"mail"`
|
|
|
+ MemberofindirectHbacrule []string `json:"memberofindirect_hbacrule"`
|
|
|
+ Dn string `json:"dn"`
|
|
|
+ Displayname []string `json:"displayname"`
|
|
|
+ Mepmanagedentry []string `json:"mepmanagedentry"`
|
|
|
+ Ipauniqueid []string `json:"ipauniqueid"`
|
|
|
+ Krbloginfailedcount []string `json:"krbloginfailedcount"`
|
|
|
+ Krbpwdpolicyreference []string `json:"krbpwdpolicyreference"`
|
|
|
+ Krbprincipalname []string `json:"krbprincipalname"`
|
|
|
+ Givenname []string `json:"givenname"`
|
|
|
+ Krblastadminunlock []struct {
|
|
|
+ Datetime string `json:"__datetime__"`
|
|
|
+ } `json:"krblastadminunlock"`
|
|
|
+ Krbpasswordexpiration []struct {
|
|
|
+ Datetime string `json:"__datetime__"`
|
|
|
+ } `json:"krbpasswordexpiration"`
|
|
|
+ Krblastfailedauth []struct {
|
|
|
+ Datetime string `json:"__datetime__"`
|
|
|
+ } `json:"krblastfailedauth"`
|
|
|
+ Objectclass []string `json:"objectclass"`
|
|
|
+ Gidnumber []string `json:"gidnumber"`
|
|
|
+ Gecos []string `json:"gecos"`
|
|
|
+ Sn []string `json:"sn"`
|
|
|
+ MemberofSudorule []string `json:"memberof_sudorule"`
|
|
|
+ Krblastpwdchange []struct {
|
|
|
+ Datetime string `json:"__datetime__"`
|
|
|
+ } `json:"krblastpwdchange"`
|
|
|
+ Initials []string `json:"initials"`
|
|
|
+ } `json:"result"`
|
|
|
+ Value string `json:"value"`
|
|
|
+ Summary interface{} `json:"summary"`
|
|
|
+ } `json:"result"`
|
|
|
+ Version string `json:"version"`
|
|
|
+ Error interface{} `json:"error"`
|
|
|
+ ID int `json:"id"`
|
|
|
+ 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"
|
|
|
+ method := "POST"
|
|
|
+ params := url.Values{}
|
|
|
+ params.Add("user", username)
|
|
|
+ params.Add("password", password)
|
|
|
+ payload := strings.NewReader(params.Encode())
|
|
|
+ tr := &http.Transport{
|
|
|
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
|
+ }
|
|
|
+ client := &http.Client{Transport: tr}
|
|
|
+ req, err := http.NewRequest(method, _url, payload)
|
|
|
+ audit("Recieved Login request from: " + RealIP)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println(err)
|
|
|
+ }
|
|
|
+ req.Header.Add("Referer", "https://ipa.sf.faraborddi.dc/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()
|
|
|
+ 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)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ return c.JSON(http.StatusOK, tokens)
|
|
|
+ }
|
|
|
+
|
|
|
+ return echo.ErrUnauthorized
|
|
|
+}
|
|
|
+func getUserInfo(cockie []*http.Cookie, username string) userInfo {
|
|
|
+ url := "https://ipa.sf.faraborddi.dc/ipa/session/json"
|
|
|
+ method := "POST"
|
|
|
+ _json := fmt.Sprintf(`
|
|
|
+{
|
|
|
+ "method": "user_show",
|
|
|
+ "params": [
|
|
|
+ [
|
|
|
+ "%s"
|
|
|
+ ],
|
|
|
+ {
|
|
|
+ "all": true,
|
|
|
+ "version": "2.215"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "id": 0
|
|
|
+}
|
|
|
+`, 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", "https://ipa.sf.faraborddi.dc/ipa")
|
|
|
+ req.Header.Add("Content-Type", "application/json")
|
|
|
+ req.Header.Add("Accept", "text/plain")
|
|
|
+ req.Header.Add("Cookie", cockie[0].Raw)
|
|
|
+ res, err := client.Do(req)
|
|
|
+ defer res.Body.Close()
|
|
|
+ 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) findMAC(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+"!")
|
|
|
+}
|