diff options
author | =Corey Hulen <corey@hulen.com> | 2015-10-20 04:37:51 -0700 |
---|---|---|
committer | =Corey Hulen <corey@hulen.com> | 2015-10-20 04:37:51 -0700 |
commit | fa3a0df2b63d3f1bbbad44bf20afa48fed42aa06 (patch) | |
tree | 7ed37f554aae729a6fad579bc1a82e988de45971 | |
parent | 36658c13a4c7ebdfff22b8570e0db52bfa4de000 (diff) | |
download | chat-fa3a0df2b63d3f1bbbad44bf20afa48fed42aa06.tar.gz chat-fa3a0df2b63d3f1bbbad44bf20afa48fed42aa06.tar.bz2 chat-fa3a0df2b63d3f1bbbad44bf20afa48fed42aa06.zip |
Adding multi-session cookie
-rw-r--r-- | api/context.go | 56 | ||||
-rw-r--r-- | api/user.go | 17 | ||||
-rw-r--r-- | manualtesting/manual_testing.go | 2 | ||||
-rw-r--r-- | model/client.go | 25 | ||||
-rw-r--r-- | model/session.go | 3 | ||||
-rw-r--r-- | web/react/utils/client.jsx | 16 | ||||
-rw-r--r-- | web/templates/head.html | 17 | ||||
-rw-r--r-- | web/web.go | 36 |
8 files changed, 78 insertions, 94 deletions
diff --git a/api/context.go b/api/context.go index 67eed674a..e5ef8b312 100644 --- a/api/context.go +++ b/api/context.go @@ -30,12 +30,12 @@ type Context struct { } type Page struct { - TemplateName string - Props map[string]string - ClientCfg map[string]string - User *model.User - Team *model.Team - Session *model.Session + TemplateName string + Props map[string]string + ClientCfg map[string]string + User *model.User + Team *model.Team + SessionTokenHash string } func ApiAppHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler { @@ -99,8 +99,29 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Attempt to parse the token from the cookie if len(token) == 0 { - if cookie, err := r.Cookie(model.SESSION_TOKEN); err == nil { - token = cookie.Value + if cookie, err := r.Cookie(model.SESSION_COOKIE_TOKEN); err == nil { + multiToken := cookie.Value + + fmt.Println(">>>>>>>> multiToken: " + multiToken) + + if len(multiToken) > 0 { + tokens := strings.Split(multiToken, " ") + + // If there is only 1 token in the cookie then just use it like normal + if len(tokens) == 1 { + token = multiToken + } else { + // If it is a multi-session token then find the correct session + sessionTokenHash := r.Header.Get(model.HEADER_MM_SESSION_TOKEN_HASH) + fmt.Println(">>>>>>>> sessionHash: " + sessionTokenHash + " url=" + r.URL.Path) + for _, t := range tokens { + if sessionTokenHash == model.HashPassword(t) { + token = token + break + } + } + } + } } } @@ -179,6 +200,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Write([]byte(c.Err.ToJson())) } else { if c.Err.StatusCode == http.StatusUnauthorized { + fmt.Println("!!!!!!!!!!!!!!!! url=" + r.URL.Path) http.Redirect(w, r, c.GetTeamURL()+"/?redirect="+url.QueryEscape(r.URL.Path), http.StatusTemporaryRedirect) } else { RenderWebError(c.Err, w, r) @@ -310,25 +332,13 @@ func (c *Context) IsTeamAdmin() bool { func (c *Context) RemoveSessionCookie(w http.ResponseWriter, r *http.Request) { - sessionCache.Remove(c.Session.Token) - - cookie := &http.Cookie{ - Name: model.SESSION_TOKEN, - Value: "", - Path: "/", - MaxAge: -1, - HttpOnly: true, - } - - http.SetCookie(w, cookie) - multiToken := "" - if oldMultiCookie, err := r.Cookie(model.MULTI_SESSION_TOKEN); err == nil { + if oldMultiCookie, err := r.Cookie(model.SESSION_COOKIE_TOKEN); err == nil { multiToken = oldMultiCookie.Value } multiCookie := &http.Cookie{ - Name: model.MULTI_SESSION_TOKEN, + Name: model.SESSION_COOKIE_TOKEN, Value: strings.TrimSpace(strings.Replace(multiToken, c.Session.Token, "", -1)), Path: "/", MaxAge: model.SESSION_TIME_WEB_IN_SECS, @@ -500,7 +510,7 @@ func GetSession(token string) *model.Session { func FindMultiSessionForTeamId(r *http.Request, teamId string) *model.Session { - if multiCookie, err := r.Cookie(model.MULTI_SESSION_TOKEN); err == nil { + if multiCookie, err := r.Cookie(model.SESSION_COOKIE_TOKEN); err == nil { multiToken := multiCookie.Value if len(multiToken) > 0 { diff --git a/api/user.go b/api/user.go index ac33e81a1..1216dd30d 100644 --- a/api/user.go +++ b/api/user.go @@ -428,21 +428,14 @@ func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, } w.Header().Set(model.HEADER_TOKEN, session.Token) - sessionCookie := &http.Cookie{ - Name: model.SESSION_TOKEN, - Value: session.Token, - Path: "/", - MaxAge: maxAge, - HttpOnly: true, - } - - http.SetCookie(w, sessionCookie) multiToken := "" - if originalMultiSessionCookie, err := r.Cookie(model.MULTI_SESSION_TOKEN); err == nil { + if originalMultiSessionCookie, err := r.Cookie(model.SESSION_COOKIE_TOKEN); err == nil { multiToken = originalMultiSessionCookie.Value } + fmt.Println("original: " + multiToken) + // Attempt to clean all the old tokens or duplicate tokens if len(multiToken) > 0 { tokens := strings.Split(multiToken, " ") @@ -463,8 +456,10 @@ func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, multiToken = strings.TrimSpace(session.Token + " " + multiToken) + fmt.Println("new: " + multiToken) + multiSessionCookie := &http.Cookie{ - Name: model.MULTI_SESSION_TOKEN, + Name: model.SESSION_COOKIE_TOKEN, Value: multiToken, Path: "/", MaxAge: maxAge, diff --git a/manualtesting/manual_testing.go b/manualtesting/manual_testing.go index 3fbdd5fd7..3c2289626 100644 --- a/manualtesting/manual_testing.go +++ b/manualtesting/manual_testing.go @@ -111,7 +111,7 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) { // Respond with an auth token this can be overriden by a specific test as required sessionCookie := &http.Cookie{ - Name: model.SESSION_TOKEN, + Name: model.SESSION_COOKIE_TOKEN, Value: client.AuthToken, Path: "/", MaxAge: model.SESSION_TIME_WEB_IN_SECS, diff --git a/model/client.go b/model/client.go index 9183dcacb..79480d667 100644 --- a/model/client.go +++ b/model/client.go @@ -16,17 +16,18 @@ import ( ) const ( - HEADER_REQUEST_ID = "X-Request-ID" - HEADER_VERSION_ID = "X-Version-ID" - HEADER_ETAG_SERVER = "ETag" - HEADER_ETAG_CLIENT = "If-None-Match" - HEADER_FORWARDED = "X-Forwarded-For" - HEADER_REAL_IP = "X-Real-IP" - HEADER_FORWARDED_PROTO = "X-Forwarded-Proto" - HEADER_TOKEN = "token" - HEADER_BEARER = "BEARER" - HEADER_AUTH = "Authorization" - API_URL_SUFFIX = "/api/v1" + HEADER_REQUEST_ID = "X-Request-ID" + HEADER_VERSION_ID = "X-Version-ID" + HEADER_ETAG_SERVER = "ETag" + HEADER_ETAG_CLIENT = "If-None-Match" + HEADER_FORWARDED = "X-Forwarded-For" + HEADER_REAL_IP = "X-Real-IP" + HEADER_FORWARDED_PROTO = "X-Forwarded-Proto" + HEADER_TOKEN = "token" + HEADER_BEARER = "BEARER" + HEADER_AUTH = "Authorization" + HEADER_MM_SESSION_TOKEN_HASH = "X-MM-TokenHash" + API_URL_SUFFIX = "/api/v1" ) type Result struct { @@ -293,7 +294,7 @@ func (c *Client) login(m map[string]string) (*Result, *AppError) { } else { c.AuthToken = r.Header.Get(HEADER_TOKEN) c.AuthType = HEADER_BEARER - sessionToken := getCookie(SESSION_TOKEN, r) + sessionToken := getCookie(SESSION_COOKIE_TOKEN, r) if c.AuthToken != sessionToken.Value { NewAppError("/users/login", "Authentication tokens didn't match", "") diff --git a/model/session.go b/model/session.go index e2c1d4c55..5fe74a161 100644 --- a/model/session.go +++ b/model/session.go @@ -9,8 +9,7 @@ import ( ) const ( - SESSION_TOKEN = "MMSID" - MULTI_SESSION_TOKEN = "MMSIDMU" + SESSION_COOKIE_TOKEN = "MMTOKEN" SESSION_TIME_WEB_IN_DAYS = 30 SESSION_TIME_WEB_IN_SECS = 60 * 60 * 24 * SESSION_TIME_WEB_IN_DAYS SESSION_TIME_MOBILE_IN_DAYS = 30 diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index ee1f9ad27..fab0640fb 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -48,14 +48,14 @@ function handleError(methodName, xhr, status, err) { track('api', 'api_weberror', methodName, 'message', msg); - if (xhr.status === 401) { - if (window.location.href.indexOf('/channels') === 0) { - window.location.pathname = '/login?redirect=' + encodeURIComponent(window.location.pathname + window.location.search); - } else { - var teamURL = window.location.href.split('/channels')[0]; - window.location.href = teamURL + '/login?redirect=' + encodeURIComponent(window.location.pathname + window.location.search); - } - } + // if (xhr.status === 401) { + // if (window.location.href.indexOf('/channels') === 0) { + // window.location.pathname = '/login?redirect=' + encodeURIComponent(window.location.pathname + window.location.search); + // } else { + // var teamURL = window.location.href.split('/channels')[0]; + // window.location.href = teamURL + '/login?redirect=' + encodeURIComponent(window.location.pathname + window.location.search); + // } + // } return e; } diff --git a/web/templates/head.html b/web/templates/head.html index 31a3c97f2..731bcd691 100644 --- a/web/templates/head.html +++ b/web/templates/head.html @@ -18,13 +18,6 @@ <link rel="manifest" href="/static/config/manifest.json"> <!-- Android add to homescreen --> - <script> - window.mm_config = {{ .ClientCfg }}; - window.mm_team = {{ .Team }}; - window.mm_user = {{ .User }}; - window.mm_session = {{ .Session }}; - </script> - <!-- CSS Should always go first --> <link rel="stylesheet" href="/static/css/bootstrap-3.3.5.min.css"> <link rel="stylesheet" href="/static/css/jasny-bootstrap.min.css"> @@ -47,6 +40,16 @@ <style id="antiClickjack">body{display:none !important;}</style> <script> + window.mm_config = {{ .ClientCfg }}; + window.mm_team = {{ .Team }}; + window.mm_user = {{ .User }}; + window.mm_session_token_hash = {{ .SessionTokenHash }}; + $.ajaxSetup({ + headers: { 'X-MM-TokenHash': mm_session_token_hash } + }); + </script> + + <script> window.onerror = function(msg, url, line, column, stack) { var l = {}; l.level = 'ERROR'; diff --git a/web/web.go b/web/web.go index 701e36e95..56db99733 100644 --- a/web/web.go +++ b/web/web.go @@ -15,11 +15,7 @@ import ( "gopkg.in/fsnotify.v1" "html/template" "net/http" -<<<<<<< HEAD "net/url" - "regexp" -======= ->>>>>>> master "strconv" "strings" ) @@ -48,8 +44,8 @@ func (me *HtmlTemplatePage) Render(c *api.Context, w http.ResponseWriter) { me.User.Sanitize(map[string]bool{}) } - if me.Session != nil { - me.Session.Sanitize() + if len(c.Session.Token) > 0 { + me.SessionTokenHash = model.HashPassword(c.Session.Token) } if err := Templates.ExecuteTemplate(w, me.TemplateName, me); err != nil { @@ -95,9 +91,9 @@ func InitWeb() { mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/login", api.AppHandler(login)).Methods("GET") mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/logout", api.AppHandler(logout)).Methods("GET") mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/reset_password", api.AppHandler(resetPassword)).Methods("GET") - mainrouter.Handle("/{team}/login/{service}", api.AppHandler(loginWithOAuth)).Methods("GET") // Bug in gorilla.mux prevents us from using regex here. - mainrouter.Handle("/{team}/channels/{channelname}", api.UserRequired(getChannel)).Methods("GET") // Bug in gorilla.mux prevents us from using regex here. - mainrouter.Handle("/{team}/signup/{service}", api.AppHandler(signupWithOAuth)).Methods("GET") // Bug in gorilla.mux prevents us from using regex here. + mainrouter.Handle("/{team}/login/{service}", api.AppHandler(loginWithOAuth)).Methods("GET") // Bug in gorilla.mux prevents us from using regex here. + mainrouter.Handle("/{team}/channels/{channelname}", api.AppHandler(getChannel)).Methods("GET") // Bug in gorilla.mux prevents us from using regex here. + mainrouter.Handle("/{team}/signup/{service}", api.AppHandler(signupWithOAuth)).Methods("GET") // Bug in gorilla.mux prevents us from using regex here. watchAndParseTemplates() } @@ -205,7 +201,6 @@ func root(c *api.Context, w http.ResponseWriter, r *http.Request) { page := NewHtmlTemplatePage("home", "Home") page.Team = team page.User = user - page.Session = &c.Session page.Render(c, w) } } @@ -236,26 +231,10 @@ func login(c *api.Context, w http.ResponseWriter, r *http.Request) { team = tResult.Data.(*model.Team) } - // If we are already logged into this team then go to town-square - if len(c.Session.UserId) != 0 && c.Session.TeamId == team.Id { - http.Redirect(w, r, c.GetSiteURL()+"/"+team.Name+"/channels/town-square", http.StatusTemporaryRedirect) - return - } - // We still might be able to switch to this team because we've logged in before session := api.FindMultiSessionForTeamId(r, team.Id) if session != nil { w.Header().Set(model.HEADER_TOKEN, session.Token) - sessionCookie := &http.Cookie{ - Name: model.SESSION_TOKEN, - Value: session.Token, - Path: "/", - MaxAge: model.SESSION_TIME_WEB_IN_SECS, - HttpOnly: true, - } - - http.SetCookie(w, sessionCookie) - http.Redirect(w, r, c.GetSiteURL()+"/"+team.Name+"/channels/town-square", http.StatusTemporaryRedirect) return } @@ -375,6 +354,7 @@ func getChannel(c *api.Context, w http.ResponseWriter, r *http.Request) { session := api.FindMultiSessionForTeamId(r, team.Id) if session == nil { // redirect to login + fmt.Println(">>>>>>>>>>forwarding") http.Redirect(w, r, c.GetSiteURL()+"/"+team.Name+"/?redirect="+url.QueryEscape(r.URL.Path), http.StatusTemporaryRedirect) } else { c.Session = *session @@ -449,7 +429,6 @@ func getChannel(c *api.Context, w http.ResponseWriter, r *http.Request) { page.Props["UserId"] = c.Session.UserId page.Team = team page.User = user - page.Session = &c.Session page.Render(c, w) } @@ -678,7 +657,6 @@ func signupCompleteOAuth(c *api.Context, w http.ResponseWriter, r *http.Request) page := NewHtmlTemplatePage("home", "Home") page.Team = team page.User = ruser - page.Session = &c.Session page.Render(c, w) } } @@ -745,7 +723,6 @@ func loginCompleteOAuth(c *api.Context, w http.ResponseWriter, r *http.Request) page := NewHtmlTemplatePage("home", "Home") page.Team = team page.User = user - page.Session = &c.Session page.Render(c, w) root(c, w, r) @@ -786,7 +763,6 @@ func adminConsole(c *api.Context, w http.ResponseWriter, r *http.Request) { page := NewHtmlTemplatePage("admin_console", "Admin Console") page.User = user page.Team = team - page.Session = &c.Session page.Props["ActiveTab"] = activeTab page.Props["TeamId"] = teamId page.Render(c, w) |