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