github.com/lologarithm/mattermost-server@v5.3.2-0.20181002060438-c82a84ed765b+incompatible/app/session.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package app 5 6 import ( 7 "fmt" 8 "net/http" 9 10 "github.com/mattermost/mattermost-server/mlog" 11 "github.com/mattermost/mattermost-server/model" 12 ) 13 14 func (a *App) CreateSession(session *model.Session) (*model.Session, *model.AppError) { 15 session.Token = "" 16 17 if result := <-a.Srv.Store.Session().Save(session); result.Err != nil { 18 return nil, result.Err 19 } else { 20 session := result.Data.(*model.Session) 21 22 a.AddSessionToCache(session) 23 24 return session, nil 25 } 26 } 27 28 func (a *App) GetSession(token string) (*model.Session, *model.AppError) { 29 metrics := a.Metrics 30 31 var session *model.Session 32 if ts, ok := a.sessionCache.Get(token); ok { 33 session = ts.(*model.Session) 34 if metrics != nil { 35 metrics.IncrementMemCacheHitCounterSession() 36 } 37 } else { 38 if metrics != nil { 39 metrics.IncrementMemCacheMissCounterSession() 40 } 41 } 42 43 if session == nil { 44 if sessionResult := <-a.Srv.Store.Session().Get(token); sessionResult.Err == nil { 45 session = sessionResult.Data.(*model.Session) 46 47 if session != nil { 48 if session.Token != token { 49 return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token, "Error": ""}, "", http.StatusUnauthorized) 50 } 51 52 if !session.IsExpired() { 53 a.AddSessionToCache(session) 54 } 55 } 56 } else if sessionResult.Err.StatusCode == http.StatusInternalServerError { 57 return nil, sessionResult.Err 58 } 59 } 60 61 if session == nil { 62 var err *model.AppError 63 session, err = a.createSessionForUserAccessToken(token) 64 if err != nil { 65 detailedError := "" 66 statusCode := http.StatusUnauthorized 67 if err.Id != "app.user_access_token.invalid_or_missing" { 68 detailedError = err.Error() 69 statusCode = err.StatusCode 70 } 71 return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, detailedError, statusCode) 72 } 73 } 74 75 if session == nil || session.IsExpired() { 76 return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, "", http.StatusUnauthorized) 77 } 78 79 license := a.License() 80 if *a.Config().ServiceSettings.SessionIdleTimeoutInMinutes > 0 && 81 license != nil && *license.Features.Compliance && 82 session != nil && !session.IsOAuth && !session.IsMobileApp() && 83 session.Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_USER_ACCESS_TOKEN { 84 85 timeout := int64(*a.Config().ServiceSettings.SessionIdleTimeoutInMinutes) * 1000 * 60 86 if model.GetMillis()-session.LastActivityAt > timeout { 87 a.RevokeSessionById(session.Id) 88 return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, "idle timeout", http.StatusUnauthorized) 89 } 90 } 91 92 return session, nil 93 } 94 95 func (a *App) GetSessions(userId string) ([]*model.Session, *model.AppError) { 96 if result := <-a.Srv.Store.Session().GetSessions(userId); result.Err != nil { 97 return nil, result.Err 98 } else { 99 return result.Data.([]*model.Session), nil 100 } 101 } 102 103 func (a *App) RevokeAllSessions(userId string) *model.AppError { 104 if result := <-a.Srv.Store.Session().GetSessions(userId); result.Err != nil { 105 return result.Err 106 } else { 107 sessions := result.Data.([]*model.Session) 108 109 for _, session := range sessions { 110 if session.IsOAuth { 111 a.RevokeAccessToken(session.Token) 112 } else { 113 if result := <-a.Srv.Store.Session().Remove(session.Id); result.Err != nil { 114 return result.Err 115 } 116 } 117 118 a.RevokeWebrtcToken(session.Id) 119 } 120 } 121 122 a.ClearSessionCacheForUser(userId) 123 124 return nil 125 } 126 127 func (a *App) ClearSessionCacheForUser(userId string) { 128 a.ClearSessionCacheForUserSkipClusterSend(userId) 129 130 if a.Cluster != nil { 131 msg := &model.ClusterMessage{ 132 Event: model.CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER, 133 SendType: model.CLUSTER_SEND_RELIABLE, 134 Data: userId, 135 } 136 a.Cluster.SendClusterMessage(msg) 137 } 138 } 139 140 func (a *App) ClearSessionCacheForUserSkipClusterSend(userId string) { 141 keys := a.sessionCache.Keys() 142 143 for _, key := range keys { 144 if ts, ok := a.sessionCache.Get(key); ok { 145 session := ts.(*model.Session) 146 if session.UserId == userId { 147 a.sessionCache.Remove(key) 148 if a.Metrics != nil { 149 a.Metrics.IncrementMemCacheInvalidationCounterSession() 150 } 151 } 152 } 153 } 154 155 a.InvalidateWebConnSessionCacheForUser(userId) 156 } 157 158 func (a *App) AddSessionToCache(session *model.Session) { 159 a.sessionCache.AddWithExpiresInSecs(session.Token, session, int64(*a.Config().ServiceSettings.SessionCacheInMinutes*60)) 160 } 161 162 func (a *App) SessionCacheLength() int { 163 return a.sessionCache.Len() 164 } 165 166 func (a *App) RevokeSessionsForDeviceId(userId string, deviceId string, currentSessionId string) *model.AppError { 167 if result := <-a.Srv.Store.Session().GetSessions(userId); result.Err != nil { 168 return result.Err 169 } else { 170 sessions := result.Data.([]*model.Session) 171 for _, session := range sessions { 172 if session.DeviceId == deviceId && session.Id != currentSessionId { 173 mlog.Debug(fmt.Sprintf("Revoking sessionId=%v for userId=%v re-login with same device Id", session.Id, userId), mlog.String("user_id", userId)) 174 if err := a.RevokeSession(session); err != nil { 175 // Soft error so we still remove the other sessions 176 mlog.Error(err.Error()) 177 } 178 } 179 } 180 } 181 182 return nil 183 } 184 185 func (a *App) GetSessionById(sessionId string) (*model.Session, *model.AppError) { 186 if result := <-a.Srv.Store.Session().Get(sessionId); result.Err != nil { 187 result.Err.StatusCode = http.StatusBadRequest 188 return nil, result.Err 189 } else { 190 return result.Data.(*model.Session), nil 191 } 192 } 193 194 func (a *App) RevokeSessionById(sessionId string) *model.AppError { 195 if result := <-a.Srv.Store.Session().Get(sessionId); result.Err != nil { 196 result.Err.StatusCode = http.StatusBadRequest 197 return result.Err 198 } else { 199 return a.RevokeSession(result.Data.(*model.Session)) 200 } 201 } 202 203 func (a *App) RevokeSession(session *model.Session) *model.AppError { 204 if session.IsOAuth { 205 if err := a.RevokeAccessToken(session.Token); err != nil { 206 return err 207 } 208 } else { 209 if result := <-a.Srv.Store.Session().Remove(session.Id); result.Err != nil { 210 return result.Err 211 } 212 } 213 214 a.RevokeWebrtcToken(session.Id) 215 a.ClearSessionCacheForUser(session.UserId) 216 217 return nil 218 } 219 220 func (a *App) AttachDeviceId(sessionId string, deviceId string, expiresAt int64) *model.AppError { 221 if result := <-a.Srv.Store.Session().UpdateDeviceId(sessionId, deviceId, expiresAt); result.Err != nil { 222 return result.Err 223 } 224 225 return nil 226 } 227 228 func (a *App) UpdateLastActivityAtIfNeeded(session model.Session) { 229 now := model.GetMillis() 230 231 a.UpdateWebConnUserActivity(session, now) 232 233 if now-session.LastActivityAt < model.SESSION_ACTIVITY_TIMEOUT { 234 return 235 } 236 237 if result := <-a.Srv.Store.Session().UpdateLastActivityAt(session.Id, now); result.Err != nil { 238 mlog.Error(fmt.Sprintf("Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v", session.UserId, session.Id, result.Err), mlog.String("user_id", session.UserId)) 239 } 240 241 session.LastActivityAt = now 242 a.AddSessionToCache(&session) 243 } 244 245 func (a *App) CreateUserAccessToken(token *model.UserAccessToken) (*model.UserAccessToken, *model.AppError) { 246 if !*a.Config().ServiceSettings.EnableUserAccessTokens { 247 return nil, model.NewAppError("CreateUserAccessToken", "app.user_access_token.disabled", nil, "", http.StatusNotImplemented) 248 } 249 250 token.Token = model.NewId() 251 252 uchan := a.Srv.Store.User().Get(token.UserId) 253 254 if result := <-a.Srv.Store.UserAccessToken().Save(token); result.Err != nil { 255 return nil, result.Err 256 } else { 257 token = result.Data.(*model.UserAccessToken) 258 } 259 260 if result := <-uchan; result.Err != nil { 261 mlog.Error(result.Err.Error()) 262 } else { 263 user := result.Data.(*model.User) 264 if err := a.SendUserAccessTokenAddedEmail(user.Email, user.Locale, a.GetSiteURL()); err != nil { 265 mlog.Error(err.Error()) 266 } 267 } 268 269 return token, nil 270 271 } 272 273 func (a *App) createSessionForUserAccessToken(tokenString string) (*model.Session, *model.AppError) { 274 if !*a.Config().ServiceSettings.EnableUserAccessTokens { 275 return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "EnableUserAccessTokens=false", http.StatusUnauthorized) 276 } 277 278 var token *model.UserAccessToken 279 if result := <-a.Srv.Store.UserAccessToken().GetByToken(tokenString); result.Err != nil { 280 return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, result.Err.Error(), http.StatusUnauthorized) 281 } else { 282 token = result.Data.(*model.UserAccessToken) 283 284 if !token.IsActive { 285 return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_token", http.StatusUnauthorized) 286 } 287 } 288 289 var user *model.User 290 if result := <-a.Srv.Store.User().Get(token.UserId); result.Err != nil { 291 return nil, result.Err 292 } else { 293 user = result.Data.(*model.User) 294 } 295 296 if user.DeleteAt != 0 { 297 return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_user_id="+user.Id, http.StatusUnauthorized) 298 } 299 300 session := &model.Session{ 301 Token: token.Token, 302 UserId: user.Id, 303 Roles: user.GetRawRoles(), 304 IsOAuth: false, 305 } 306 307 session.AddProp(model.SESSION_PROP_USER_ACCESS_TOKEN_ID, token.Id) 308 session.AddProp(model.SESSION_PROP_TYPE, model.SESSION_TYPE_USER_ACCESS_TOKEN) 309 session.SetExpireInDays(model.SESSION_USER_ACCESS_TOKEN_EXPIRY) 310 311 if result := <-a.Srv.Store.Session().Save(session); result.Err != nil { 312 return nil, result.Err 313 } else { 314 session := result.Data.(*model.Session) 315 316 a.AddSessionToCache(session) 317 318 return session, nil 319 } 320 } 321 322 func (a *App) RevokeUserAccessToken(token *model.UserAccessToken) *model.AppError { 323 var session *model.Session 324 if result := <-a.Srv.Store.Session().Get(token.Token); result.Err == nil { 325 session = result.Data.(*model.Session) 326 } 327 328 if result := <-a.Srv.Store.UserAccessToken().Delete(token.Id); result.Err != nil { 329 return result.Err 330 } 331 332 if session == nil { 333 return nil 334 } 335 336 return a.RevokeSession(session) 337 } 338 339 func (a *App) DisableUserAccessToken(token *model.UserAccessToken) *model.AppError { 340 var session *model.Session 341 if result := <-a.Srv.Store.Session().Get(token.Token); result.Err == nil { 342 session = result.Data.(*model.Session) 343 } 344 345 if result := <-a.Srv.Store.UserAccessToken().UpdateTokenDisable(token.Id); result.Err != nil { 346 return result.Err 347 } 348 349 if session == nil { 350 return nil 351 } 352 353 return a.RevokeSession(session) 354 } 355 356 func (a *App) EnableUserAccessToken(token *model.UserAccessToken) *model.AppError { 357 var session *model.Session 358 if result := <-a.Srv.Store.Session().Get(token.Token); result.Err == nil { 359 session = result.Data.(*model.Session) 360 } 361 362 if result := <-a.Srv.Store.UserAccessToken().UpdateTokenEnable(token.Id); result.Err != nil { 363 return result.Err 364 } 365 366 if session == nil { 367 return nil 368 } 369 370 return nil 371 } 372 373 func (a *App) GetUserAccessTokens(page, perPage int) ([]*model.UserAccessToken, *model.AppError) { 374 if result := <-a.Srv.Store.UserAccessToken().GetAll(page*perPage, perPage); result.Err != nil { 375 return nil, result.Err 376 } else { 377 tokens := result.Data.([]*model.UserAccessToken) 378 for _, token := range tokens { 379 token.Token = "" 380 } 381 382 return tokens, nil 383 } 384 } 385 386 func (a *App) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*model.UserAccessToken, *model.AppError) { 387 if result := <-a.Srv.Store.UserAccessToken().GetByUser(userId, page*perPage, perPage); result.Err != nil { 388 return nil, result.Err 389 } else { 390 tokens := result.Data.([]*model.UserAccessToken) 391 for _, token := range tokens { 392 token.Token = "" 393 } 394 395 return tokens, nil 396 } 397 } 398 399 func (a *App) GetUserAccessToken(tokenId string, sanitize bool) (*model.UserAccessToken, *model.AppError) { 400 if result := <-a.Srv.Store.UserAccessToken().Get(tokenId); result.Err != nil { 401 return nil, result.Err 402 } else { 403 token := result.Data.(*model.UserAccessToken) 404 if sanitize { 405 token.Token = "" 406 } 407 return token, nil 408 } 409 } 410 411 func (a *App) SearchUserAccessTokens(term string) ([]*model.UserAccessToken, *model.AppError) { 412 if result := <-a.Srv.Store.UserAccessToken().Search(term); result.Err != nil { 413 return nil, result.Err 414 } else { 415 tokens := result.Data.([]*model.UserAccessToken) 416 for _, token := range tokens { 417 token.Token = "" 418 } 419 return tokens, nil 420 } 421 }