github.com/levb/mattermost-server@v5.3.1+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  }