github.com/spline-fu/mattermost-server@v4.10.10+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  	if now-session.LastActivityAt < model.SESSION_ACTIVITY_TIMEOUT {
   231  		return
   232  	}
   233  
   234  	if result := <-a.Srv.Store.Session().UpdateLastActivityAt(session.Id, now); result.Err != nil {
   235  		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))
   236  	}
   237  
   238  	session.LastActivityAt = now
   239  	a.AddSessionToCache(&session)
   240  }
   241  
   242  func (a *App) CreateUserAccessToken(token *model.UserAccessToken) (*model.UserAccessToken, *model.AppError) {
   243  	if !*a.Config().ServiceSettings.EnableUserAccessTokens {
   244  		return nil, model.NewAppError("CreateUserAccessToken", "app.user_access_token.disabled", nil, "", http.StatusNotImplemented)
   245  	}
   246  
   247  	token.Token = model.NewId()
   248  
   249  	uchan := a.Srv.Store.User().Get(token.UserId)
   250  
   251  	if result := <-a.Srv.Store.UserAccessToken().Save(token); result.Err != nil {
   252  		return nil, result.Err
   253  	} else {
   254  		token = result.Data.(*model.UserAccessToken)
   255  	}
   256  
   257  	if result := <-uchan; result.Err != nil {
   258  		mlog.Error(result.Err.Error())
   259  	} else {
   260  		user := result.Data.(*model.User)
   261  		if err := a.SendUserAccessTokenAddedEmail(user.Email, user.Locale); err != nil {
   262  			mlog.Error(err.Error())
   263  		}
   264  	}
   265  
   266  	return token, nil
   267  
   268  }
   269  
   270  func (a *App) createSessionForUserAccessToken(tokenString string) (*model.Session, *model.AppError) {
   271  	if !*a.Config().ServiceSettings.EnableUserAccessTokens {
   272  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "EnableUserAccessTokens=false", http.StatusUnauthorized)
   273  	}
   274  
   275  	var token *model.UserAccessToken
   276  	if result := <-a.Srv.Store.UserAccessToken().GetByToken(tokenString); result.Err != nil {
   277  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, result.Err.Error(), http.StatusUnauthorized)
   278  	} else {
   279  		token = result.Data.(*model.UserAccessToken)
   280  
   281  		if !token.IsActive {
   282  			return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_token", http.StatusUnauthorized)
   283  		}
   284  	}
   285  
   286  	var user *model.User
   287  	if result := <-a.Srv.Store.User().Get(token.UserId); result.Err != nil {
   288  		return nil, result.Err
   289  	} else {
   290  		user = result.Data.(*model.User)
   291  	}
   292  
   293  	if user.DeleteAt != 0 {
   294  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_user_id="+user.Id, http.StatusUnauthorized)
   295  	}
   296  
   297  	session := &model.Session{
   298  		Token:   token.Token,
   299  		UserId:  user.Id,
   300  		Roles:   user.GetRawRoles(),
   301  		IsOAuth: false,
   302  	}
   303  
   304  	session.AddProp(model.SESSION_PROP_USER_ACCESS_TOKEN_ID, token.Id)
   305  	session.AddProp(model.SESSION_PROP_TYPE, model.SESSION_TYPE_USER_ACCESS_TOKEN)
   306  	session.SetExpireInDays(model.SESSION_USER_ACCESS_TOKEN_EXPIRY)
   307  
   308  	if result := <-a.Srv.Store.Session().Save(session); result.Err != nil {
   309  		return nil, result.Err
   310  	} else {
   311  		session := result.Data.(*model.Session)
   312  
   313  		a.AddSessionToCache(session)
   314  
   315  		return session, nil
   316  	}
   317  }
   318  
   319  func (a *App) RevokeUserAccessToken(token *model.UserAccessToken) *model.AppError {
   320  	var session *model.Session
   321  	if result := <-a.Srv.Store.Session().Get(token.Token); result.Err == nil {
   322  		session = result.Data.(*model.Session)
   323  	}
   324  
   325  	if result := <-a.Srv.Store.UserAccessToken().Delete(token.Id); result.Err != nil {
   326  		return result.Err
   327  	}
   328  
   329  	if session == nil {
   330  		return nil
   331  	}
   332  
   333  	return a.RevokeSession(session)
   334  }
   335  
   336  func (a *App) DisableUserAccessToken(token *model.UserAccessToken) *model.AppError {
   337  	var session *model.Session
   338  	if result := <-a.Srv.Store.Session().Get(token.Token); result.Err == nil {
   339  		session = result.Data.(*model.Session)
   340  	}
   341  
   342  	if result := <-a.Srv.Store.UserAccessToken().UpdateTokenDisable(token.Id); result.Err != nil {
   343  		return result.Err
   344  	}
   345  
   346  	if session == nil {
   347  		return nil
   348  	}
   349  
   350  	return a.RevokeSession(session)
   351  }
   352  
   353  func (a *App) EnableUserAccessToken(token *model.UserAccessToken) *model.AppError {
   354  	var session *model.Session
   355  	if result := <-a.Srv.Store.Session().Get(token.Token); result.Err == nil {
   356  		session = result.Data.(*model.Session)
   357  	}
   358  
   359  	if result := <-a.Srv.Store.UserAccessToken().UpdateTokenEnable(token.Id); result.Err != nil {
   360  		return result.Err
   361  	}
   362  
   363  	if session == nil {
   364  		return nil
   365  	}
   366  
   367  	return nil
   368  }
   369  
   370  func (a *App) GetUserAccessTokens(page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
   371  	if result := <-a.Srv.Store.UserAccessToken().GetAll(page*perPage, perPage); result.Err != nil {
   372  		return nil, result.Err
   373  	} else {
   374  		tokens := result.Data.([]*model.UserAccessToken)
   375  		for _, token := range tokens {
   376  			token.Token = ""
   377  		}
   378  
   379  		return tokens, nil
   380  	}
   381  }
   382  
   383  func (a *App) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
   384  	if result := <-a.Srv.Store.UserAccessToken().GetByUser(userId, page*perPage, perPage); result.Err != nil {
   385  		return nil, result.Err
   386  	} else {
   387  		tokens := result.Data.([]*model.UserAccessToken)
   388  		for _, token := range tokens {
   389  			token.Token = ""
   390  		}
   391  
   392  		return tokens, nil
   393  	}
   394  }
   395  
   396  func (a *App) GetUserAccessToken(tokenId string, sanitize bool) (*model.UserAccessToken, *model.AppError) {
   397  	if result := <-a.Srv.Store.UserAccessToken().Get(tokenId); result.Err != nil {
   398  		return nil, result.Err
   399  	} else {
   400  		token := result.Data.(*model.UserAccessToken)
   401  		if sanitize {
   402  			token.Token = ""
   403  		}
   404  		return token, nil
   405  	}
   406  }
   407  
   408  func (a *App) SearchUserAccessTokens(term string) ([]*model.UserAccessToken, *model.AppError) {
   409  	if result := <-a.Srv.Store.UserAccessToken().Search(term); result.Err != nil {
   410  		return nil, result.Err
   411  	} else {
   412  		tokens := result.Data.([]*model.UserAccessToken)
   413  		for _, token := range tokens {
   414  			token.Token = ""
   415  		}
   416  		return tokens, nil
   417  	}
   418  }