autologin.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package auth
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io/ioutil"
  6. "log"
  7. "net/http"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/gorilla/sessions"
  12. uuid "github.com/satori/go.uuid"
  13. "imuslab.com/arozos/mod/utils"
  14. )
  15. //Autologin token. This token will not expire until admin removal
  16. type AutoLoginToken struct {
  17. Owner string
  18. Token string
  19. }
  20. func (a *AuthAgent) NewAutologinToken(username string) string {
  21. //Generate a new token
  22. newTokenUUID := uuid.NewV4().String() + "-" + strconv.Itoa(int(time.Now().Unix()))
  23. a.autoLoginTokens = append(a.autoLoginTokens, &AutoLoginToken{
  24. Owner: username,
  25. Token: newTokenUUID,
  26. })
  27. //Save the token to sysdb
  28. a.Database.Write("auth", "altoken/"+newTokenUUID, username)
  29. //Return the new token
  30. return newTokenUUID
  31. }
  32. func (a *AuthAgent) RemoveAutologinToken(token string) {
  33. newTokenArray := []*AutoLoginToken{}
  34. for _, alt := range a.autoLoginTokens {
  35. if alt.Token != token {
  36. newTokenArray = append(newTokenArray, alt)
  37. } else {
  38. //Delete this from the database
  39. a.Database.Delete("auth", "altoken/"+alt.Token)
  40. }
  41. }
  42. a.autoLoginTokens = newTokenArray
  43. }
  44. func (a *AuthAgent) RemoveAutologinTokenByUsername(username string) {
  45. newTokenArray := []*AutoLoginToken{}
  46. for _, alt := range a.autoLoginTokens {
  47. if alt.Owner != username {
  48. newTokenArray = append(newTokenArray, alt)
  49. } else {
  50. //Delete this from the database
  51. a.Database.Delete("auth", "altoken/"+alt.Token)
  52. }
  53. }
  54. a.autoLoginTokens = newTokenArray
  55. }
  56. func (a *AuthAgent) LoadAutologinTokenFromDB() error {
  57. entries, err := a.Database.ListTable("auth")
  58. if err != nil {
  59. return err
  60. }
  61. for _, keypairs := range entries {
  62. if strings.Contains(string(keypairs[0]), "altoken/") {
  63. key := string(keypairs[0])
  64. owner := ""
  65. json.Unmarshal(keypairs[1], &owner)
  66. token := strings.Split(key, "/")[1]
  67. a.autoLoginTokens = append(a.autoLoginTokens, &AutoLoginToken{
  68. Owner: owner,
  69. Token: token,
  70. })
  71. }
  72. }
  73. return nil
  74. }
  75. func (a *AuthAgent) GetUsernameFromToken(token string) (string, error) {
  76. for _, alt := range a.autoLoginTokens {
  77. if alt.Token == token {
  78. return alt.Owner, nil
  79. }
  80. }
  81. return "", errors.New("Invalid Token")
  82. }
  83. func (a *AuthAgent) GetTokensFromUsername(username string) []*AutoLoginToken {
  84. results := []*AutoLoginToken{}
  85. for _, alt := range a.autoLoginTokens {
  86. if alt.Owner == username {
  87. results = append(results, alt)
  88. }
  89. }
  90. return results
  91. }
  92. func (a *AuthAgent) HandleAutologinTokenLogin(w http.ResponseWriter, r *http.Request) {
  93. //Get the authentication token from the request
  94. if a.AllowAutoLogin == false {
  95. w.WriteHeader(http.StatusForbidden)
  96. w.Write([]byte("403 - Forbidden"))
  97. log.Println("Someone is requesting autologin while this function is turned off.")
  98. return
  99. }
  100. session, _ := a.SessionStore.Get(r, a.SessionName)
  101. token, err := utils.Mv(r, "token", false)
  102. if err != nil {
  103. //Username not defined
  104. sendErrorResponse(w, "Token not defined or empty.")
  105. return
  106. }
  107. //Try to get the username from token
  108. username, err := a.GetUsernameFromToken(token)
  109. if err != nil {
  110. //This token is not valid
  111. w.WriteHeader(http.StatusUnauthorized)
  112. //Try to get the autologin error page.
  113. errtemplate, err := ioutil.ReadFile("./system/errors/invalidToken.html")
  114. if err != nil {
  115. w.Write([]byte("401 - Unauthorized (Token not valid)"))
  116. } else {
  117. w.Write(errtemplate)
  118. }
  119. return
  120. }
  121. //Check if the current client has already logged in another account
  122. currentlyLoggedUsername, err := a.GetUserName(w, r)
  123. if err == nil && currentlyLoggedUsername != username {
  124. //The current client already logged in with another user account!
  125. w.WriteHeader(http.StatusAccepted)
  126. errtemplate, err := ioutil.ReadFile("./system/errors/alreadyLoggedin.html")
  127. if err != nil {
  128. w.Write([]byte("202 - Accepted (Already logged in as another user)"))
  129. } else {
  130. w.Write(errtemplate)
  131. }
  132. return
  133. }
  134. //Ok. Allow this client to login
  135. session.Values["authenticated"] = true
  136. session.Values["username"] = username
  137. session.Values["rememberMe"] = false
  138. log.Println(username + " logged in via auto-login token")
  139. //Check if remember me is clicked. If yes, set the maxage to 1 week.
  140. session.Options = &sessions.Options{
  141. MaxAge: 3600 * 1, //1 hour
  142. Path: "/",
  143. }
  144. session.Save(r, w)
  145. redirectTarget, _ := utils.Mv(r, "redirect", false)
  146. if redirectTarget != "" {
  147. //Redirect to target website
  148. http.Redirect(w, r, redirectTarget, http.StatusTemporaryRedirect)
  149. } else {
  150. //Redirect this client to its interface module
  151. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  152. }
  153. }
  154. //Check if the given autologin token is valid. Autologin token is different from session token (aka token)
  155. func (a *AuthAgent) ValidateAutoLoginToken(token string) (bool, string) {
  156. //Try to get the username from token
  157. username, err := a.GetUsernameFromToken(token)
  158. if err != nil {
  159. //This token is not valid
  160. return false, ""
  161. }
  162. //Token is valid
  163. return true, username
  164. }