handler.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "net/url"
  8. "strings"
  9. "github.com/dgrijalva/jwt-go"
  10. "github.com/labstack/echo"
  11. )
  12. type handler struct{}
  13. type userInfo struct {
  14. Result struct {
  15. Result struct {
  16. Sshpubkeyfp []string `json:"sshpubkeyfp"`
  17. HasKeytab bool `json:"has_keytab"`
  18. Ipasshpubkey []string `json:"ipasshpubkey"`
  19. Cn []string `json:"cn"`
  20. Krbcanonicalname []string `json:"krbcanonicalname"`
  21. Krbticketflags []string `json:"krbticketflags"`
  22. MemberofGroup []string `json:"memberof_group"`
  23. HasPassword bool `json:"has_password"`
  24. Homedirectory []string `json:"homedirectory"`
  25. Nsaccountlock bool `json:"nsaccountlock"`
  26. UID []string `json:"uid"`
  27. Title []string `json:"title"`
  28. Loginshell []string `json:"loginshell"`
  29. Uidnumber []string `json:"uidnumber"`
  30. Preserved bool `json:"preserved"`
  31. Krbextradata []struct {
  32. Base64 string `json:"__base64__"`
  33. } `json:"krbextradata"`
  34. Mail []string `json:"mail"`
  35. MemberofindirectHbacrule []string `json:"memberofindirect_hbacrule"`
  36. Dn string `json:"dn"`
  37. Displayname []string `json:"displayname"`
  38. Mepmanagedentry []string `json:"mepmanagedentry"`
  39. Ipauniqueid []string `json:"ipauniqueid"`
  40. Krbloginfailedcount []string `json:"krbloginfailedcount"`
  41. Krbpwdpolicyreference []string `json:"krbpwdpolicyreference"`
  42. Krbprincipalname []string `json:"krbprincipalname"`
  43. Givenname []string `json:"givenname"`
  44. Krblastadminunlock []struct {
  45. Datetime string `json:"__datetime__"`
  46. } `json:"krblastadminunlock"`
  47. Krbpasswordexpiration []struct {
  48. Datetime string `json:"__datetime__"`
  49. } `json:"krbpasswordexpiration"`
  50. Krblastfailedauth []struct {
  51. Datetime string `json:"__datetime__"`
  52. } `json:"krblastfailedauth"`
  53. Objectclass []string `json:"objectclass"`
  54. Gidnumber []string `json:"gidnumber"`
  55. Gecos []string `json:"gecos"`
  56. Sn []string `json:"sn"`
  57. MemberofSudorule []string `json:"memberof_sudorule"`
  58. Krblastpwdchange []struct {
  59. Datetime string `json:"__datetime__"`
  60. } `json:"krblastpwdchange"`
  61. Initials []string `json:"initials"`
  62. } `json:"result"`
  63. Value string `json:"value"`
  64. Summary interface{} `json:"summary"`
  65. } `json:"result"`
  66. Version string `json:"version"`
  67. Error interface{} `json:"error"`
  68. ID int `json:"id"`
  69. Principal string `json:"principal"`
  70. }
  71. // Most of the code is taken from the echo guide
  72. // https://echo.labstack.com/cookbook/jwt
  73. func (h *handler) login(c echo.Context) error {
  74. username := c.FormValue("username")
  75. password := c.FormValue("password")
  76. _url := "https://ipa.sf.faraborddi.dc/ipa/session/login_password"
  77. method := "POST"
  78. params := url.Values{}
  79. params.Add("user", username)
  80. params.Add("password", password)
  81. payload := strings.NewReader(params.Encode())
  82. client := &http.Client{}
  83. req, err := http.NewRequest(method, _url, payload)
  84. audit("Recieved Login request from:" + RealIP)
  85. if err != nil {
  86. fmt.Println(err)
  87. }
  88. req.Header.Add("Referer", "https://ipa.sf.faraborddi.dc/ipa")
  89. req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
  90. req.Header.Add("Accept", "text/plain")
  91. res, err := client.Do(req)
  92. cockie := res.Cookies()
  93. defer res.Body.Close()
  94. fmt.Println(res.StatusCode)
  95. if res.StatusCode == 200 {
  96. user := getUserInfo(cockie, username)
  97. fmt.Println(user.Result.Value)
  98. tokens, err := generateTokenPair()
  99. if err != nil {
  100. return err
  101. }
  102. return c.JSON(http.StatusOK, tokens)
  103. }
  104. return echo.ErrUnauthorized
  105. }
  106. func getUserInfo(cockie []*http.Cookie, username string) userInfo {
  107. url := "https://ipa.sf.faraborddi.dc/ipa/session/json"
  108. method := "POST"
  109. _json := fmt.Sprintf(`
  110. {
  111. "method": "user_show",
  112. "params": [
  113. [
  114. "%s"
  115. ],
  116. {
  117. "all": true,
  118. "version": "2.215"
  119. }
  120. ],
  121. "id": 0
  122. }
  123. `, username)
  124. payload := strings.NewReader(_json)
  125. client := &http.Client{}
  126. req, err := http.NewRequest(method, url, payload)
  127. if err != nil {
  128. fmt.Println(err)
  129. }
  130. req.Header.Add("Referer", "https://ipa.sf.faraborddi.dc/ipa")
  131. req.Header.Add("Content-Type", "application/json")
  132. req.Header.Add("Accept", "text/plain")
  133. req.Header.Add("Cookie", cockie[0].Raw)
  134. res, err := client.Do(req)
  135. defer res.Body.Close()
  136. body, err := ioutil.ReadAll(res.Body)
  137. user := userInfo{}
  138. json.Unmarshal(body, &user)
  139. //fmt.Println(user.Result.Value)
  140. return user
  141. }
  142. // This is the api to refresh tokens
  143. // Most of the code is taken from the jwt-go package's sample codes
  144. // https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse--Hmac
  145. func (h *handler) token(c echo.Context) error {
  146. type tokenReqBody struct {
  147. RefreshToken string `json:"refresh_token"`
  148. }
  149. tokenReq := tokenReqBody{}
  150. c.Bind(&tokenReq)
  151. // Parse takes the token string and a function for looking up the key.
  152. // The latter is especially useful if you use multiple keys for your application.
  153. // The standard is to use 'kid' in the head of the token to identify
  154. // which key to use, but the parsed token (head and claims) is provided
  155. // to the callback, providing flexibility.
  156. token, err := jwt.Parse(tokenReq.RefreshToken, func(token *jwt.Token) (interface{}, error) {
  157. // Don't forget to validate the alg is what you expect:
  158. if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
  159. return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
  160. }
  161. // hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
  162. return []byte("secret"), nil
  163. })
  164. if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
  165. // Get the user record from database or
  166. // run through your business logic to verify if the user can log in
  167. if int(claims["sub"].(float64)) == 1 {
  168. newTokenPair, err := generateTokenPair()
  169. if err != nil {
  170. return err
  171. }
  172. return c.JSON(http.StatusOK, newTokenPair)
  173. }
  174. return echo.ErrUnauthorized
  175. }
  176. return err
  177. }
  178. // Most of the code is taken from the echo guide
  179. // https://echo.labstack.com/cookbook/jwt
  180. func (h *handler) private(c echo.Context) error {
  181. user := c.Get("user").(*jwt.Token)
  182. claims := user.Claims.(jwt.MapClaims)
  183. name := claims["name"].(string)
  184. return c.String(http.StatusOK, "Welcome "+name+"!")
  185. }