PLT-6226 fixing race in IsAuth (#7296)

* Fixing race in isAuth function

* PLT-6226 fixing race in IsAuth

* Moving int64 to top so it's aligned

* Adding comment and fixing asymmetric call
This commit is contained in:
Corey Hulen
2017-09-05 07:58:47 -07:00
committed by GitHub
parent 7843dc3cfa
commit d6383643cb
4 changed files with 71 additions and 31 deletions
+62 -28
View File
@@ -5,6 +5,7 @@ package app
import (
"fmt"
"sync/atomic"
"time"
"github.com/mattermost/platform/einterfaces"
@@ -28,11 +29,11 @@ const (
)
type WebConn struct {
sessionExpiresAt int64 // This should stay at the top for 64-bit alignment of 64-bit words accessed atomically
WebSocket *websocket.Conn
Send chan model.WebSocketMessage
SessionToken string
SessionExpiresAt int64
Session *model.Session
sessionToken atomic.Value
session atomic.Value
UserId string
T goi18n.TranslateFunc
Locale string
@@ -49,15 +50,47 @@ func NewWebConn(ws *websocket.Conn, session model.Session, t goi18n.TranslateFun
}()
}
return &WebConn{
Send: make(chan model.WebSocketMessage, SEND_QUEUE_SIZE),
WebSocket: ws,
UserId: session.UserId,
SessionToken: session.Token,
SessionExpiresAt: session.ExpiresAt,
T: t,
Locale: locale,
wc := &WebConn{
Send: make(chan model.WebSocketMessage, SEND_QUEUE_SIZE),
WebSocket: ws,
UserId: session.UserId,
T: t,
Locale: locale,
}
wc.SetSession(&session)
wc.SetSessionToken(session.Token)
wc.SetSessionExpiresAt(session.ExpiresAt)
return wc
}
func (c *WebConn) GetSessionExpiresAt() int64 {
return atomic.LoadInt64(&c.sessionExpiresAt)
}
func (c *WebConn) SetSessionExpiresAt(v int64) {
atomic.StoreInt64(&c.sessionExpiresAt, v)
}
func (c *WebConn) GetSessionToken() string {
return c.sessionToken.Load().(string)
}
func (c *WebConn) SetSessionToken(v string) {
c.sessionToken.Store(v)
}
func (c *WebConn) GetSession() *model.Session {
return c.session.Load().(*model.Session)
}
func (c *WebConn) SetSession(v *model.Session) {
if v != nil {
v = v.DeepCopy()
}
c.session.Store(v)
}
func (c *WebConn) ReadPump() {
@@ -175,7 +208,7 @@ func (c *WebConn) WritePump() {
}
case <-authTicker.C:
if c.SessionToken == "" {
if c.GetSessionToken() == "" {
l4g.Debug(fmt.Sprintf("websocket.authTicker: did not authenticate ip=%v", c.WebSocket.RemoteAddr()))
return
}
@@ -187,29 +220,28 @@ func (c *WebConn) WritePump() {
func (webCon *WebConn) InvalidateCache() {
webCon.AllChannelMembers = nil
webCon.LastAllChannelMembersTime = 0
webCon.SessionExpiresAt = 0
webCon.Session = nil
webCon.SetSession(nil)
webCon.SetSessionExpiresAt(0)
}
func (webCon *WebConn) IsAuthenticated() bool {
// Check the expiry to see if we need to check for a new session
if webCon.SessionExpiresAt < model.GetMillis() {
if webCon.SessionToken == "" {
if webCon.GetSessionExpiresAt() < model.GetMillis() {
if webCon.GetSessionToken() == "" {
return false
}
session, err := GetSession(webCon.SessionToken)
session, err := GetSession(webCon.GetSessionToken())
if err != nil {
l4g.Error(utils.T("api.websocket.invalid_session.error"), err.Error())
webCon.SessionToken = ""
webCon.SessionExpiresAt = 0
webCon.Session = nil
webCon.SetSessionToken("")
webCon.SetSession(nil)
webCon.SetSessionExpiresAt(0)
return false
}
webCon.SessionToken = session.Token
webCon.SessionExpiresAt = session.ExpiresAt
webCon.Session = session
webCon.SetSession(session)
webCon.SetSessionExpiresAt(session.ExpiresAt)
}
return true
@@ -278,18 +310,20 @@ func (webCon *WebConn) ShouldSendEvent(msg *model.WebSocketEvent) bool {
func (webCon *WebConn) IsMemberOfTeam(teamId string) bool {
if webCon.Session == nil {
session, err := GetSession(webCon.SessionToken)
currentSession := webCon.GetSession()
if currentSession == nil || len(currentSession.Token) == 0 {
session, err := GetSession(webCon.GetSessionToken())
if err != nil {
l4g.Error(utils.T("api.websocket.invalid_session.error"), err.Error())
return false
} else {
webCon.Session = session
webCon.SetSession(session)
currentSession = session
}
}
member := webCon.Session.GetTeamByTeamId(teamId)
member := currentSession.GetTeamByTeamId(teamId)
if member != nil {
return true
+3 -2
View File
@@ -43,7 +43,7 @@ func (wr *WebSocketRouter) ServeWebSocket(conn *WebConn, r *model.WebSocketReque
}
if r.Action == model.WEBSOCKET_AUTHENTICATION_CHALLENGE {
if conn.SessionToken != "" {
if conn.GetSessionToken() != "" {
return
}
@@ -63,7 +63,8 @@ func (wr *WebSocketRouter) ServeWebSocket(conn *WebConn, r *model.WebSocketReque
UpdateLastActivityAtIfNeeded(*session)
}()
conn.SessionToken = session.Token
conn.SetSession(session)
conn.SetSessionToken(session.Token)
conn.UserId = session.UserId
HubRegister(conn)
+5
View File
@@ -37,6 +37,11 @@ type Session struct {
TeamMembers []*TeamMember `json:"team_members" db:"-"`
}
func (me *Session) DeepCopy() *Session {
copy := *me
return &copy
}
func (me *Session) ToJson() string {
b, err := json.Marshal(me)
if err != nil {
+1 -1
View File
@@ -23,7 +23,7 @@ type webSocketHandler struct {
func (wh webSocketHandler) ServeWebSocket(conn *app.WebConn, r *model.WebSocketRequest) {
l4g.Debug("/api/v3/users/websocket:%s", r.Action)
session, sessionErr := app.GetSession(conn.SessionToken)
session, sessionErr := app.GetSession(conn.GetSessionToken())
if sessionErr != nil {
l4g.Error(utils.T("api.web_socket_handler.log.error"), "/api/v3/users/websocket", r.Action, r.Seq, conn.UserId, sessionErr.SystemMessage(utils.T), sessionErr.Error())
sessionErr.DetailedError = ""