github.com/vnforks/kid@v5.11.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  	result := <-a.Srv.Store.Session().Save(session)
    18  	if result.Err != nil {
    19  		return nil, result.Err
    20  	}
    21  	session = result.Data.(*model.Session)
    22  
    23  	a.AddSessionToCache(session)
    24  
    25  	return session, nil
    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.Srv.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  	if session != nil &&
    80  		*a.Config().ServiceSettings.SessionIdleTimeoutInMinutes > 0 &&
    81  		!session.IsOAuth &&
    82  		session.Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_USER_ACCESS_TOKEN {
    83  
    84  		timeout := int64(*a.Config().ServiceSettings.SessionIdleTimeoutInMinutes) * 1000 * 60
    85  		if (model.GetMillis() - session.LastActivityAt) > timeout {
    86  			a.RevokeSessionById(session.Id)
    87  			return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, "idle timeout", http.StatusUnauthorized)
    88  		}
    89  	}
    90  
    91  	return session, nil
    92  }
    93  
    94  func (a *App) GetSessions(userId string) ([]*model.Session, *model.AppError) {
    95  	result := <-a.Srv.Store.Session().GetSessions(userId)
    96  	if result.Err != nil {
    97  		return nil, result.Err
    98  	}
    99  	return result.Data.([]*model.Session), nil
   100  
   101  }
   102  
   103  func (a *App) RevokeAllSessions(userId string) *model.AppError {
   104  	result := <-a.Srv.Store.Session().GetSessions(userId)
   105  	if result.Err != nil {
   106  		return result.Err
   107  	}
   108  	sessions := result.Data.([]*model.Session)
   109  
   110  	for _, session := range sessions {
   111  		if session.IsOAuth {
   112  			a.RevokeAccessToken(session.Token)
   113  		} else {
   114  			if result := <-a.Srv.Store.Session().Remove(session.Id); result.Err != nil {
   115  				return result.Err
   116  			}
   117  		}
   118  	}
   119  
   120  	a.ClearSessionCacheForUser(userId)
   121  
   122  	return nil
   123  }
   124  
   125  func (a *App) ClearSessionCacheForUser(userId string) {
   126  	a.ClearSessionCacheForUserSkipClusterSend(userId)
   127  
   128  	if a.Cluster != nil {
   129  		msg := &model.ClusterMessage{
   130  			Event:    model.CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER,
   131  			SendType: model.CLUSTER_SEND_RELIABLE,
   132  			Data:     userId,
   133  		}
   134  		a.Cluster.SendClusterMessage(msg)
   135  	}
   136  }
   137  
   138  func (a *App) ClearSessionCacheForUserSkipClusterSend(userId string) {
   139  	keys := a.Srv.sessionCache.Keys()
   140  
   141  	for _, key := range keys {
   142  		if ts, ok := a.Srv.sessionCache.Get(key); ok {
   143  			session := ts.(*model.Session)
   144  			if session.UserId == userId {
   145  				a.Srv.sessionCache.Remove(key)
   146  				if a.Metrics != nil {
   147  					a.Metrics.IncrementMemCacheInvalidationCounterSession()
   148  				}
   149  			}
   150  		}
   151  	}
   152  
   153  	a.InvalidateWebConnSessionCacheForUser(userId)
   154  }
   155  
   156  func (a *App) AddSessionToCache(session *model.Session) {
   157  	a.Srv.sessionCache.AddWithExpiresInSecs(session.Token, session, int64(*a.Config().ServiceSettings.SessionCacheInMinutes*60))
   158  }
   159  
   160  func (a *App) SessionCacheLength() int {
   161  	return a.Srv.sessionCache.Len()
   162  }
   163  
   164  func (a *App) RevokeSessionsForDeviceId(userId string, deviceId string, currentSessionId string) *model.AppError {
   165  	result := <-a.Srv.Store.Session().GetSessions(userId)
   166  	if result.Err != nil {
   167  		return result.Err
   168  	}
   169  	sessions := result.Data.([]*model.Session)
   170  	for _, session := range sessions {
   171  		if session.DeviceId == deviceId && session.Id != currentSessionId {
   172  			mlog.Debug(fmt.Sprintf("Revoking sessionId=%v for userId=%v re-login with same device Id", session.Id, userId), mlog.String("user_id", userId))
   173  			if err := a.RevokeSession(session); err != nil {
   174  				// Soft error so we still remove the other sessions
   175  				mlog.Error(err.Error())
   176  			}
   177  		}
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  func (a *App) GetSessionById(sessionId string) (*model.Session, *model.AppError) {
   184  	result := <-a.Srv.Store.Session().Get(sessionId)
   185  	if result.Err != nil {
   186  		result.Err.StatusCode = http.StatusBadRequest
   187  		return nil, result.Err
   188  	}
   189  	return result.Data.(*model.Session), nil
   190  }
   191  
   192  func (a *App) RevokeSessionById(sessionId string) *model.AppError {
   193  	result := <-a.Srv.Store.Session().Get(sessionId)
   194  	if result.Err != nil {
   195  		result.Err.StatusCode = http.StatusBadRequest
   196  		return result.Err
   197  	}
   198  	return a.RevokeSession(result.Data.(*model.Session))
   199  
   200  }
   201  
   202  func (a *App) RevokeSession(session *model.Session) *model.AppError {
   203  	if session.IsOAuth {
   204  		if err := a.RevokeAccessToken(session.Token); err != nil {
   205  			return err
   206  		}
   207  	} else {
   208  		if result := <-a.Srv.Store.Session().Remove(session.Id); result.Err != nil {
   209  			return result.Err
   210  		}
   211  	}
   212  
   213  	a.ClearSessionCacheForUser(session.UserId)
   214  
   215  	return nil
   216  }
   217  
   218  func (a *App) AttachDeviceId(sessionId string, deviceId string, expiresAt int64) *model.AppError {
   219  	if result := <-a.Srv.Store.Session().UpdateDeviceId(sessionId, deviceId, expiresAt); result.Err != nil {
   220  		return result.Err
   221  	}
   222  
   223  	return nil
   224  }
   225  
   226  func (a *App) UpdateLastActivityAtIfNeeded(session model.Session) {
   227  	now := model.GetMillis()
   228  
   229  	a.UpdateWebConnUserActivity(session, now)
   230  
   231  	if now-session.LastActivityAt < model.SESSION_ACTIVITY_TIMEOUT {
   232  		return
   233  	}
   234  
   235  	if result := <-a.Srv.Store.Session().UpdateLastActivityAt(session.Id, now); result.Err != nil {
   236  		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))
   237  	}
   238  
   239  	session.LastActivityAt = now
   240  	a.AddSessionToCache(&session)
   241  }
   242  
   243  func (a *App) CreateUserAccessToken(token *model.UserAccessToken) (*model.UserAccessToken, *model.AppError) {
   244  	if !*a.Config().ServiceSettings.EnableUserAccessTokens {
   245  		return nil, model.NewAppError("CreateUserAccessToken", "app.user_access_token.disabled", nil, "", http.StatusNotImplemented)
   246  	}
   247  
   248  	token.Token = model.NewId()
   249  
   250  	uchan := a.Srv.Store.User().Get(token.UserId)
   251  
   252  	result := <-a.Srv.Store.UserAccessToken().Save(token)
   253  	if result.Err != nil {
   254  		return nil, result.Err
   255  	}
   256  	token = result.Data.(*model.UserAccessToken)
   257  
   258  	if result := <-uchan; result.Err != nil {
   259  		mlog.Error(result.Err.Error())
   260  	} else {
   261  		user := result.Data.(*model.User)
   262  		if err := a.SendUserAccessTokenAddedEmail(user.Email, user.Locale, a.GetSiteURL()); err != nil {
   263  			mlog.Error(err.Error())
   264  		}
   265  	}
   266  
   267  	return token, nil
   268  
   269  }
   270  
   271  func (a *App) createSessionForUserAccessToken(tokenString string) (*model.Session, *model.AppError) {
   272  	if !*a.Config().ServiceSettings.EnableUserAccessTokens {
   273  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "EnableUserAccessTokens=false", http.StatusUnauthorized)
   274  	}
   275  
   276  	var token *model.UserAccessToken
   277  	result := <-a.Srv.Store.UserAccessToken().GetByToken(tokenString)
   278  	if result.Err != nil {
   279  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, result.Err.Error(), http.StatusUnauthorized)
   280  	}
   281  	token = result.Data.(*model.UserAccessToken)
   282  
   283  	if !token.IsActive {
   284  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_token", http.StatusUnauthorized)
   285  	}
   286  
   287  	var user *model.User
   288  	result = <-a.Srv.Store.User().Get(token.UserId)
   289  	if result.Err != nil {
   290  		return nil, result.Err
   291  	}
   292  	user = result.Data.(*model.User)
   293  
   294  	if user.DeleteAt != 0 {
   295  		return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_user_id="+user.Id, http.StatusUnauthorized)
   296  	}
   297  
   298  	session := &model.Session{
   299  		Token:   token.Token,
   300  		UserId:  user.Id,
   301  		Roles:   user.GetRawRoles(),
   302  		IsOAuth: false,
   303  	}
   304  
   305  	session.AddProp(model.SESSION_PROP_USER_ACCESS_TOKEN_ID, token.Id)
   306  	session.AddProp(model.SESSION_PROP_TYPE, model.SESSION_TYPE_USER_ACCESS_TOKEN)
   307  	session.SetExpireInDays(model.SESSION_USER_ACCESS_TOKEN_EXPIRY)
   308  
   309  	result = <-a.Srv.Store.Session().Save(session)
   310  	if result.Err != nil {
   311  		return nil, result.Err
   312  	}
   313  	session = result.Data.(*model.Session)
   314  
   315  	a.AddSessionToCache(session)
   316  
   317  	return session, nil
   318  
   319  }
   320  
   321  func (a *App) RevokeUserAccessToken(token *model.UserAccessToken) *model.AppError {
   322  	var session *model.Session
   323  	if result := <-a.Srv.Store.Session().Get(token.Token); result.Err == nil {
   324  		session = result.Data.(*model.Session)
   325  	}
   326  
   327  	if result := <-a.Srv.Store.UserAccessToken().Delete(token.Id); result.Err != nil {
   328  		return result.Err
   329  	}
   330  
   331  	if session == nil {
   332  		return nil
   333  	}
   334  
   335  	return a.RevokeSession(session)
   336  }
   337  
   338  func (a *App) DisableUserAccessToken(token *model.UserAccessToken) *model.AppError {
   339  	var session *model.Session
   340  	if result := <-a.Srv.Store.Session().Get(token.Token); result.Err == nil {
   341  		session = result.Data.(*model.Session)
   342  	}
   343  
   344  	if result := <-a.Srv.Store.UserAccessToken().UpdateTokenDisable(token.Id); result.Err != nil {
   345  		return result.Err
   346  	}
   347  
   348  	if session == nil {
   349  		return nil
   350  	}
   351  
   352  	return a.RevokeSession(session)
   353  }
   354  
   355  func (a *App) EnableUserAccessToken(token *model.UserAccessToken) *model.AppError {
   356  	var session *model.Session
   357  	if result := <-a.Srv.Store.Session().Get(token.Token); result.Err == nil {
   358  		session = result.Data.(*model.Session)
   359  	}
   360  
   361  	if result := <-a.Srv.Store.UserAccessToken().UpdateTokenEnable(token.Id); result.Err != nil {
   362  		return result.Err
   363  	}
   364  
   365  	if session == nil {
   366  		return nil
   367  	}
   368  
   369  	return nil
   370  }
   371  
   372  func (a *App) GetUserAccessTokens(page, perPage int) ([]*model.UserAccessToken, *model.AppError) {
   373  	result := <-a.Srv.Store.UserAccessToken().GetAll(page*perPage, perPage)
   374  	if result.Err != nil {
   375  		return nil, result.Err
   376  	}
   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  	result := <-a.Srv.Store.UserAccessToken().GetByUser(userId, page*perPage, perPage)
   388  	if result.Err != nil {
   389  		return nil, result.Err
   390  	}
   391  	tokens := result.Data.([]*model.UserAccessToken)
   392  	for _, token := range tokens {
   393  		token.Token = ""
   394  	}
   395  
   396  	return tokens, nil
   397  
   398  }
   399  
   400  func (a *App) GetUserAccessToken(tokenId string, sanitize bool) (*model.UserAccessToken, *model.AppError) {
   401  	result := <-a.Srv.Store.UserAccessToken().Get(tokenId)
   402  	if result.Err != nil {
   403  		return nil, result.Err
   404  	}
   405  	token := result.Data.(*model.UserAccessToken)
   406  	if sanitize {
   407  		token.Token = ""
   408  	}
   409  	return token, nil
   410  
   411  }
   412  
   413  func (a *App) SearchUserAccessTokens(term string) ([]*model.UserAccessToken, *model.AppError) {
   414  	result := <-a.Srv.Store.UserAccessToken().Search(term)
   415  	if result.Err != nil {
   416  		return nil, result.Err
   417  	}
   418  	tokens := result.Data.([]*model.UserAccessToken)
   419  	for _, token := range tokens {
   420  		token.Token = ""
   421  	}
   422  	return tokens, nil
   423  
   424  }