github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/app/session.go (about)

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