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  }