github.com/adacta-ru/mattermost-server/v6@v6.0.0/app/oauth.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  	"bytes"
     8  	b64 "encoding/base64"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"net/http"
    14  	"net/url"
    15  	"strconv"
    16  	"strings"
    17  	"time"
    18  
    19  	"github.com/adacta-ru/mattermost-server/v6/einterfaces"
    20  	"github.com/adacta-ru/mattermost-server/v6/mlog"
    21  	"github.com/adacta-ru/mattermost-server/v6/model"
    22  	"github.com/adacta-ru/mattermost-server/v6/store"
    23  	"github.com/adacta-ru/mattermost-server/v6/utils"
    24  )
    25  
    26  const (
    27  	OAUTH_COOKIE_MAX_AGE_SECONDS = 30 * 60 // 30 minutes
    28  	COOKIE_OAUTH                 = "MMOAUTH"
    29  	OPENID_SCOPE                 = "openid"
    30  )
    31  
    32  func (a *App) CreateOAuthApp(app *model.OAuthApp) (*model.OAuthApp, *model.AppError) {
    33  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
    34  		return nil, model.NewAppError("CreateOAuthApp", "api.oauth.register_oauth_app.turn_off.app_error", nil, "", http.StatusNotImplemented)
    35  	}
    36  
    37  	app.ClientSecret = model.NewId()
    38  
    39  	oauthApp, err := a.Srv().Store.OAuth().SaveApp(app)
    40  	if err != nil {
    41  		var appErr *model.AppError
    42  		var invErr *store.ErrInvalidInput
    43  		switch {
    44  		case errors.As(err, &appErr):
    45  			return nil, appErr
    46  		case errors.As(err, &invErr):
    47  			return nil, model.NewAppError("CreateOAuthApp", "app.oauth.save_app.existing.app_error", nil, invErr.Error(), http.StatusBadRequest)
    48  		default:
    49  			return nil, model.NewAppError("CreateOAuthApp", "app.oauth.save_app.save.app_error", nil, err.Error(), http.StatusInternalServerError)
    50  		}
    51  	}
    52  
    53  	return oauthApp, nil
    54  }
    55  
    56  func (a *App) GetOAuthApp(appId string) (*model.OAuthApp, *model.AppError) {
    57  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
    58  		return nil, model.NewAppError("GetOAuthApp", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
    59  	}
    60  
    61  	oauthApp, err := a.Srv().Store.OAuth().GetApp(appId)
    62  	if err != nil {
    63  		var nfErr *store.ErrNotFound
    64  		switch {
    65  		case errors.As(err, &nfErr):
    66  			return nil, model.NewAppError("GetOAuthApp", "app.oauth.get_app.find.app_error", nil, nfErr.Error(), http.StatusNotFound)
    67  		default:
    68  			return nil, model.NewAppError("GetOAuthApp", "app.oauth.get_app.finding.app_error", nil, err.Error(), http.StatusInternalServerError)
    69  		}
    70  	}
    71  
    72  	return oauthApp, nil
    73  }
    74  
    75  func (a *App) UpdateOauthApp(oldApp, updatedApp *model.OAuthApp) (*model.OAuthApp, *model.AppError) {
    76  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
    77  		return nil, model.NewAppError("UpdateOauthApp", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
    78  	}
    79  
    80  	updatedApp.Id = oldApp.Id
    81  	updatedApp.CreatorId = oldApp.CreatorId
    82  	updatedApp.CreateAt = oldApp.CreateAt
    83  	updatedApp.ClientSecret = oldApp.ClientSecret
    84  
    85  	oauthApp, err := a.Srv().Store.OAuth().UpdateApp(updatedApp)
    86  	if err != nil {
    87  		var appErr *model.AppError
    88  		var invErr *store.ErrInvalidInput
    89  		switch {
    90  		case errors.As(err, &appErr):
    91  			return nil, appErr
    92  		case errors.As(err, &invErr):
    93  			return nil, model.NewAppError("UpdateOauthApp", "app.oauth.update_app.find.app_error", nil, invErr.Error(), http.StatusBadRequest)
    94  		default:
    95  			return nil, model.NewAppError("UpdateOauthApp", "app.oauth.update_app.updating.app_error", nil, err.Error(), http.StatusInternalServerError)
    96  		}
    97  	}
    98  
    99  	return oauthApp, nil
   100  }
   101  
   102  func (a *App) DeleteOAuthApp(appId string) *model.AppError {
   103  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
   104  		return model.NewAppError("DeleteOAuthApp", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
   105  	}
   106  
   107  	if err := a.Srv().Store.OAuth().DeleteApp(appId); err != nil {
   108  		return model.NewAppError("DeleteOAuthApp", "app.oauth.delete_app.app_error", nil, err.Error(), http.StatusInternalServerError)
   109  	}
   110  
   111  	if err := a.Srv().InvalidateAllCaches(); err != nil {
   112  		mlog.Error("error in invalidating cache", mlog.Err(err))
   113  	}
   114  
   115  	return nil
   116  }
   117  
   118  func (a *App) GetOAuthApps(page, perPage int) ([]*model.OAuthApp, *model.AppError) {
   119  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
   120  		return nil, model.NewAppError("GetOAuthApps", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
   121  	}
   122  
   123  	oauthApps, err := a.Srv().Store.OAuth().GetApps(page*perPage, perPage)
   124  	if err != nil {
   125  		return nil, model.NewAppError("GetOAuthApps", "app.oauth.get_apps.find.app_error", nil, err.Error(), http.StatusInternalServerError)
   126  	}
   127  
   128  	return oauthApps, nil
   129  }
   130  
   131  func (a *App) GetOAuthAppsByCreator(userId string, page, perPage int) ([]*model.OAuthApp, *model.AppError) {
   132  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
   133  		return nil, model.NewAppError("GetOAuthAppsByUser", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
   134  	}
   135  
   136  	oauthApps, err := a.Srv().Store.OAuth().GetAppByUser(userId, page*perPage, perPage)
   137  	if err != nil {
   138  		return nil, model.NewAppError("GetOAuthAppsByCreator", "app.oauth.get_app_by_user.find.app_error", nil, err.Error(), http.StatusInternalServerError)
   139  	}
   140  
   141  	return oauthApps, nil
   142  }
   143  
   144  func (a *App) GetOAuthImplicitRedirect(userId string, authRequest *model.AuthorizeRequest) (string, *model.AppError) {
   145  	session, err := a.GetOAuthAccessTokenForImplicitFlow(userId, authRequest)
   146  	if err != nil {
   147  		return "", err
   148  	}
   149  
   150  	values := &url.Values{}
   151  	values.Add("access_token", session.Token)
   152  	values.Add("token_type", "bearer")
   153  	values.Add("expires_in", strconv.FormatInt((session.ExpiresAt-model.GetMillis())/1000, 10))
   154  	values.Add("scope", authRequest.Scope)
   155  	values.Add("state", authRequest.State)
   156  
   157  	return fmt.Sprintf("%s#%s", authRequest.RedirectUri, values.Encode()), nil
   158  }
   159  
   160  func (a *App) GetOAuthCodeRedirect(userId string, authRequest *model.AuthorizeRequest) (string, *model.AppError) {
   161  	authData := &model.AuthData{UserId: userId, ClientId: authRequest.ClientId, CreateAt: model.GetMillis(), RedirectUri: authRequest.RedirectUri, State: authRequest.State, Scope: authRequest.Scope}
   162  	authData.Code = model.NewId() + model.NewId()
   163  
   164  	if _, err := a.Srv().Store.OAuth().SaveAuthData(authData); err != nil {
   165  		return authRequest.RedirectUri + "?error=server_error&state=" + authRequest.State, nil
   166  	}
   167  
   168  	return authRequest.RedirectUri + "?code=" + url.QueryEscape(authData.Code) + "&state=" + url.QueryEscape(authData.State), nil
   169  }
   170  
   171  func (a *App) AllowOAuthAppAccessToUser(userId string, authRequest *model.AuthorizeRequest) (string, *model.AppError) {
   172  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
   173  		return "", model.NewAppError("AllowOAuthAppAccessToUser", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
   174  	}
   175  
   176  	if len(authRequest.Scope) == 0 {
   177  		authRequest.Scope = model.DEFAULT_SCOPE
   178  	}
   179  
   180  	oauthApp, nErr := a.Srv().Store.OAuth().GetApp(authRequest.ClientId)
   181  	if nErr != nil {
   182  		var nfErr *store.ErrNotFound
   183  		switch {
   184  		case errors.As(nErr, &nfErr):
   185  			return "", model.NewAppError("AllowOAuthAppAccessToUser", "app.oauth.get_app.find.app_error", nil, nfErr.Error(), http.StatusNotFound)
   186  		default:
   187  			return "", model.NewAppError("AllowOAuthAppAccessToUser", "app.oauth.get_app.finding.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   188  		}
   189  	}
   190  
   191  	if !oauthApp.IsValidRedirectURL(authRequest.RedirectUri) {
   192  		return "", model.NewAppError("AllowOAuthAppAccessToUser", "api.oauth.allow_oauth.redirect_callback.app_error", nil, "", http.StatusBadRequest)
   193  	}
   194  
   195  	var redirectURI string
   196  	var err *model.AppError
   197  	switch authRequest.ResponseType {
   198  	case model.AUTHCODE_RESPONSE_TYPE:
   199  		redirectURI, err = a.GetOAuthCodeRedirect(userId, authRequest)
   200  	case model.IMPLICIT_RESPONSE_TYPE:
   201  		redirectURI, err = a.GetOAuthImplicitRedirect(userId, authRequest)
   202  	default:
   203  		return authRequest.RedirectUri + "?error=unsupported_response_type&state=" + authRequest.State, nil
   204  	}
   205  
   206  	if err != nil {
   207  		mlog.Error("error getting oauth redirect uri", mlog.Err(err))
   208  		return authRequest.RedirectUri + "?error=server_error&state=" + authRequest.State, nil
   209  	}
   210  
   211  	// This saves the OAuth2 app as authorized
   212  	authorizedApp := model.Preference{
   213  		UserId:   userId,
   214  		Category: model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP,
   215  		Name:     authRequest.ClientId,
   216  		Value:    authRequest.Scope,
   217  	}
   218  
   219  	if nErr := a.Srv().Store.Preference().Save(&model.Preferences{authorizedApp}); nErr != nil {
   220  		mlog.Error("error saving store preference", mlog.Err(nErr))
   221  		return authRequest.RedirectUri + "?error=server_error&state=" + authRequest.State, nil
   222  	}
   223  
   224  	return redirectURI, nil
   225  }
   226  
   227  func (a *App) GetOAuthAccessTokenForImplicitFlow(userId string, authRequest *model.AuthorizeRequest) (*model.Session, *model.AppError) {
   228  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
   229  		return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.disabled.app_error", nil, "", http.StatusNotImplemented)
   230  	}
   231  
   232  	oauthApp, err := a.GetOAuthApp(authRequest.ClientId)
   233  	if err != nil {
   234  		return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.credentials.app_error", nil, "", http.StatusNotFound)
   235  	}
   236  
   237  	user, err := a.GetUser(userId)
   238  	if err != nil {
   239  		return nil, err
   240  	}
   241  
   242  	session, err := a.newSession(oauthApp.Name, user)
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  
   247  	accessData := &model.AccessData{ClientId: authRequest.ClientId, UserId: user.Id, Token: session.Token, RefreshToken: "", RedirectUri: authRequest.RedirectUri, ExpiresAt: session.ExpiresAt, Scope: authRequest.Scope}
   248  
   249  	if _, err := a.Srv().Store.OAuth().SaveAccessData(accessData); err != nil {
   250  		mlog.Error("error saving oauth access data in implicit flow", mlog.Err(err))
   251  		return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_saving.app_error", nil, "", http.StatusInternalServerError)
   252  	}
   253  
   254  	return session, nil
   255  }
   256  
   257  func (a *App) GetOAuthAccessTokenForCodeFlow(clientId, grantType, redirectUri, code, secret, refreshToken string) (*model.AccessResponse, *model.AppError) {
   258  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
   259  		return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.disabled.app_error", nil, "", http.StatusNotImplemented)
   260  	}
   261  
   262  	oauthApp, nErr := a.Srv().Store.OAuth().GetApp(clientId)
   263  	if nErr != nil {
   264  		return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.credentials.app_error", nil, "", http.StatusNotFound)
   265  	}
   266  
   267  	if oauthApp.ClientSecret != secret {
   268  		return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.credentials.app_error", nil, "", http.StatusForbidden)
   269  	}
   270  
   271  	var accessData *model.AccessData
   272  	var accessRsp *model.AccessResponse
   273  	var user *model.User
   274  	if grantType == model.ACCESS_TOKEN_GRANT_TYPE {
   275  		var authData *model.AuthData
   276  		authData, nErr = a.Srv().Store.OAuth().GetAuthData(code)
   277  		if nErr != nil {
   278  			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.expired_code.app_error", nil, "", http.StatusBadRequest)
   279  		}
   280  
   281  		if authData.IsExpired() {
   282  			if nErr = a.Srv().Store.OAuth().RemoveAuthData(authData.Code); nErr != nil {
   283  				mlog.Warn("unable to remove auth data", mlog.Err(nErr))
   284  			}
   285  			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.expired_code.app_error", nil, "", http.StatusForbidden)
   286  		}
   287  
   288  		if authData.RedirectUri != redirectUri {
   289  			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.redirect_uri.app_error", nil, "", http.StatusBadRequest)
   290  		}
   291  
   292  		user, nErr = a.Srv().Store.User().Get(authData.UserId)
   293  		if nErr != nil {
   294  			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_user.app_error", nil, "", http.StatusNotFound)
   295  		}
   296  
   297  		accessData, nErr = a.Srv().Store.OAuth().GetPreviousAccessData(user.Id, clientId)
   298  		if nErr != nil {
   299  			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal.app_error", nil, "", http.StatusBadRequest)
   300  		}
   301  
   302  		if accessData != nil {
   303  			if accessData.IsExpired() {
   304  				var access *model.AccessResponse
   305  				access, err := a.newSessionUpdateToken(oauthApp.Name, accessData, user)
   306  				if err != nil {
   307  					return nil, err
   308  				}
   309  				accessRsp = access
   310  			} else {
   311  				// Return the same token and no need to create a new session
   312  				accessRsp = &model.AccessResponse{
   313  					AccessToken:  accessData.Token,
   314  					TokenType:    model.ACCESS_TOKEN_TYPE,
   315  					RefreshToken: accessData.RefreshToken,
   316  					ExpiresIn:    int32((accessData.ExpiresAt - model.GetMillis()) / 1000),
   317  				}
   318  			}
   319  		} else {
   320  			var session *model.Session
   321  			// Create a new session and return new access token
   322  			session, err := a.newSession(oauthApp.Name, user)
   323  			if err != nil {
   324  				return nil, err
   325  			}
   326  
   327  			accessData = &model.AccessData{ClientId: clientId, UserId: user.Id, Token: session.Token, RefreshToken: model.NewId(), RedirectUri: redirectUri, ExpiresAt: session.ExpiresAt, Scope: authData.Scope}
   328  
   329  			if _, nErr = a.Srv().Store.OAuth().SaveAccessData(accessData); nErr != nil {
   330  				mlog.Error("error saving oauth access data in token for code flow", mlog.Err(nErr))
   331  				return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_saving.app_error", nil, "", http.StatusInternalServerError)
   332  			}
   333  
   334  			accessRsp = &model.AccessResponse{
   335  				AccessToken:  session.Token,
   336  				TokenType:    model.ACCESS_TOKEN_TYPE,
   337  				RefreshToken: accessData.RefreshToken,
   338  				ExpiresIn:    int32(*a.Config().ServiceSettings.SessionLengthSSOInDays * 60 * 60 * 24),
   339  			}
   340  		}
   341  
   342  		if nErr = a.Srv().Store.OAuth().RemoveAuthData(authData.Code); nErr != nil {
   343  			mlog.Warn("unable to remove auth data", mlog.Err(nErr))
   344  		}
   345  	} else {
   346  		// When grantType is refresh_token
   347  		accessData, nErr = a.Srv().Store.OAuth().GetAccessDataByRefreshToken(refreshToken)
   348  		if nErr != nil {
   349  			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.refresh_token.app_error", nil, "", http.StatusNotFound)
   350  		}
   351  
   352  		user, nErr := a.Srv().Store.User().Get(accessData.UserId)
   353  		if nErr != nil {
   354  			return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_user.app_error", nil, "", http.StatusNotFound)
   355  		}
   356  
   357  		access, err := a.newSessionUpdateToken(oauthApp.Name, accessData, user)
   358  		if err != nil {
   359  			return nil, err
   360  		}
   361  		accessRsp = access
   362  	}
   363  
   364  	return accessRsp, nil
   365  }
   366  
   367  func (a *App) newSession(appName string, user *model.User) (*model.Session, *model.AppError) {
   368  	// Set new token an session
   369  	session := &model.Session{UserId: user.Id, Roles: user.Roles, IsOAuth: true}
   370  	session.GenerateCSRF()
   371  	a.SetSessionExpireInDays(session, *a.Config().ServiceSettings.SessionLengthSSOInDays)
   372  	session.AddProp(model.SESSION_PROP_PLATFORM, appName)
   373  	session.AddProp(model.SESSION_PROP_OS, "OAuth2")
   374  	session.AddProp(model.SESSION_PROP_BROWSER, "OAuth2")
   375  
   376  	session, err := a.Srv().Store.Session().Save(session)
   377  	if err != nil {
   378  		return nil, model.NewAppError("newSession", "api.oauth.get_access_token.internal_session.app_error", nil, "", http.StatusInternalServerError)
   379  	}
   380  
   381  	a.AddSessionToCache(session)
   382  
   383  	return session, nil
   384  }
   385  
   386  func (a *App) newSessionUpdateToken(appName string, accessData *model.AccessData, user *model.User) (*model.AccessResponse, *model.AppError) {
   387  	// Remove the previous session
   388  	if err := a.Srv().Store.Session().Remove(accessData.Token); err != nil {
   389  		mlog.Error("error removing access data token from session", mlog.Err(err))
   390  	}
   391  
   392  	session, err := a.newSession(appName, user)
   393  	if err != nil {
   394  		return nil, err
   395  	}
   396  
   397  	accessData.Token = session.Token
   398  	accessData.RefreshToken = model.NewId()
   399  	accessData.ExpiresAt = session.ExpiresAt
   400  
   401  	if _, err := a.Srv().Store.OAuth().UpdateAccessData(accessData); err != nil {
   402  		mlog.Error("error updating oauth access data", mlog.Err(err))
   403  		return nil, model.NewAppError("newSessionUpdateToken", "web.get_access_token.internal_saving.app_error", nil, "", http.StatusInternalServerError)
   404  	}
   405  	accessRsp := &model.AccessResponse{
   406  		AccessToken:  session.Token,
   407  		RefreshToken: accessData.RefreshToken,
   408  		TokenType:    model.ACCESS_TOKEN_TYPE,
   409  		ExpiresIn:    int32(*a.Config().ServiceSettings.SessionLengthSSOInDays * 60 * 60 * 24),
   410  	}
   411  
   412  	return accessRsp, nil
   413  }
   414  
   415  func (a *App) GetOAuthLoginEndpoint(w http.ResponseWriter, r *http.Request, service, teamId, action, redirectTo, loginHint string, isMobile bool) (string, *model.AppError) {
   416  	stateProps := map[string]string{}
   417  	stateProps["action"] = action
   418  	if teamId != "" {
   419  		stateProps["team_id"] = teamId
   420  	}
   421  
   422  	if redirectTo != "" {
   423  		stateProps["redirect_to"] = redirectTo
   424  	}
   425  
   426  	stateProps[model.USER_AUTH_SERVICE_IS_MOBILE] = strconv.FormatBool(isMobile)
   427  
   428  	authUrl, err := a.GetAuthorizationCode(w, r, service, stateProps, loginHint)
   429  	if err != nil {
   430  		return "", err
   431  	}
   432  
   433  	return authUrl, nil
   434  }
   435  
   436  func (a *App) GetOAuthSignupEndpoint(w http.ResponseWriter, r *http.Request, service, teamId string) (string, *model.AppError) {
   437  	stateProps := map[string]string{}
   438  	stateProps["action"] = model.OAUTH_ACTION_SIGNUP
   439  	if teamId != "" {
   440  		stateProps["team_id"] = teamId
   441  	}
   442  
   443  	authUrl, err := a.GetAuthorizationCode(w, r, service, stateProps, "")
   444  	if err != nil {
   445  		return "", err
   446  	}
   447  
   448  	return authUrl, nil
   449  }
   450  
   451  func (a *App) GetAuthorizedAppsForUser(userId string, page, perPage int) ([]*model.OAuthApp, *model.AppError) {
   452  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
   453  		return nil, model.NewAppError("GetAuthorizedAppsForUser", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
   454  	}
   455  
   456  	apps, err := a.Srv().Store.OAuth().GetAuthorizedApps(userId, page*perPage, perPage)
   457  	if err != nil {
   458  		return nil, model.NewAppError("GetAuthorizedAppsForUser", "app.oauth.get_apps.find.app_error", nil, err.Error(), http.StatusInternalServerError)
   459  	}
   460  
   461  	for k, a := range apps {
   462  		a.Sanitize()
   463  		apps[k] = a
   464  	}
   465  
   466  	return apps, nil
   467  }
   468  
   469  func (a *App) DeauthorizeOAuthAppForUser(userId, appId string) *model.AppError {
   470  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
   471  		return model.NewAppError("DeauthorizeOAuthAppForUser", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
   472  	}
   473  
   474  	// Revoke app sessions
   475  	accessData, err := a.Srv().Store.OAuth().GetAccessDataByUserForApp(userId, appId)
   476  	if err != nil {
   477  		return model.NewAppError("DeauthorizeOAuthAppForUser", "app.oauth.get_access_data_by_user_for_app.app_error", nil, err.Error(), http.StatusInternalServerError)
   478  	}
   479  
   480  	for _, ad := range accessData {
   481  		if err := a.RevokeAccessToken(ad.Token); err != nil {
   482  			return err
   483  		}
   484  
   485  		if err := a.Srv().Store.OAuth().RemoveAccessData(ad.Token); err != nil {
   486  			return model.NewAppError("DeauthorizeOAuthAppForUser", "app.oauth.remove_access_data.app_error", nil, err.Error(), http.StatusInternalServerError)
   487  		}
   488  	}
   489  
   490  	// Deauthorize the app
   491  	if err := a.Srv().Store.Preference().Delete(userId, model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP, appId); err != nil {
   492  		return model.NewAppError("DeauthorizeOAuthAppForUser", "app.preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError)
   493  	}
   494  
   495  	return nil
   496  }
   497  
   498  func (a *App) RegenerateOAuthAppSecret(app *model.OAuthApp) (*model.OAuthApp, *model.AppError) {
   499  	if !*a.Config().ServiceSettings.EnableOAuthServiceProvider {
   500  		return nil, model.NewAppError("RegenerateOAuthAppSecret", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
   501  	}
   502  
   503  	app.ClientSecret = model.NewId()
   504  	if _, err := a.Srv().Store.OAuth().UpdateApp(app); err != nil {
   505  		var appErr *model.AppError
   506  		var invErr *store.ErrInvalidInput
   507  		switch {
   508  		case errors.As(err, &appErr):
   509  			return nil, appErr
   510  		case errors.As(err, &invErr):
   511  			return nil, model.NewAppError("RegenerateOAuthAppSecret", "app.oauth.update_app.find.app_error", nil, invErr.Error(), http.StatusBadRequest)
   512  		default:
   513  			return nil, model.NewAppError("RegenerateOAuthAppSecret", "app.oauth.update_app.updating.app_error", nil, err.Error(), http.StatusInternalServerError)
   514  		}
   515  	}
   516  
   517  	return app, nil
   518  }
   519  
   520  func (a *App) RevokeAccessToken(token string) *model.AppError {
   521  	session, _ := a.GetSession(token)
   522  
   523  	schan := make(chan error, 1)
   524  	go func() {
   525  		schan <- a.Srv().Store.Session().Remove(token)
   526  		close(schan)
   527  	}()
   528  
   529  	if _, err := a.Srv().Store.OAuth().GetAccessData(token); err != nil {
   530  		return model.NewAppError("RevokeAccessToken", "api.oauth.revoke_access_token.get.app_error", nil, "", http.StatusBadRequest)
   531  	}
   532  
   533  	if err := a.Srv().Store.OAuth().RemoveAccessData(token); err != nil {
   534  		return model.NewAppError("RevokeAccessToken", "api.oauth.revoke_access_token.del_token.app_error", nil, "", http.StatusInternalServerError)
   535  	}
   536  
   537  	if err := <-schan; err != nil {
   538  		return model.NewAppError("RevokeAccessToken", "api.oauth.revoke_access_token.del_session.app_error", nil, "", http.StatusInternalServerError)
   539  	}
   540  
   541  	if session != nil {
   542  		a.ClearSessionCacheForUser(session.UserId)
   543  	}
   544  
   545  	return nil
   546  }
   547  
   548  func (a *App) CompleteOAuth(service string, body io.ReadCloser, teamId string, props map[string]string, tokenUser *model.User) (*model.User, *model.AppError) {
   549  	defer body.Close()
   550  
   551  	action := props["action"]
   552  
   553  	switch action {
   554  	case model.OAUTH_ACTION_SIGNUP:
   555  		return a.CreateOAuthUser(service, body, teamId, tokenUser)
   556  	case model.OAUTH_ACTION_LOGIN:
   557  		return a.LoginByOAuth(service, body, teamId, tokenUser)
   558  	case model.OAUTH_ACTION_EMAIL_TO_SSO:
   559  		return a.CompleteSwitchWithOAuth(service, body, props["email"], tokenUser)
   560  	case model.OAUTH_ACTION_SSO_TO_EMAIL:
   561  		return a.LoginByOAuth(service, body, teamId, tokenUser)
   562  	default:
   563  		return a.LoginByOAuth(service, body, teamId, tokenUser)
   564  	}
   565  }
   566  
   567  func (a *App) getSSOProvider(service string) (einterfaces.OauthProvider, *model.AppError) {
   568  	sso := a.Config().GetSSOService(service)
   569  	if sso == nil || !*sso.Enable {
   570  		return nil, model.NewAppError("getSSOProvider", "api.user.authorize_oauth_user.unsupported.app_error", nil, "service="+service, http.StatusNotImplemented)
   571  	}
   572  	providerType := service
   573  	if strings.Contains(*sso.Scope, OPENID_SCOPE) {
   574  		providerType = model.SERVICE_OPENID
   575  	}
   576  	provider := einterfaces.GetOauthProvider(providerType)
   577  	if provider == nil {
   578  		return nil, model.NewAppError("getSSOProvider", "api.user.login_by_oauth.not_available.app_error",
   579  			map[string]interface{}{"Service": strings.Title(service)}, "", http.StatusNotImplemented)
   580  	}
   581  	return provider, nil
   582  }
   583  
   584  func (a *App) LoginByOAuth(service string, userData io.Reader, teamId string, tokenUser *model.User) (*model.User, *model.AppError) {
   585  	provider, e := a.getSSOProvider(service)
   586  	if e != nil {
   587  		return nil, e
   588  	}
   589  
   590  	buf := bytes.Buffer{}
   591  	if _, err := buf.ReadFrom(userData); err != nil {
   592  		return nil, model.NewAppError("LoginByOAuth2", "api.user.login_by_oauth.parse.app_error",
   593  			map[string]interface{}{"Service": service}, "", http.StatusBadRequest)
   594  	}
   595  
   596  	authUser, err1 := provider.GetUserFromJson(bytes.NewReader(buf.Bytes()), tokenUser)
   597  	if err1 != nil {
   598  		return nil, model.NewAppError("LoginByOAuth", "api.user.login_by_oauth.parse.app_error",
   599  			map[string]interface{}{"Service": service}, err1.Error(), http.StatusBadRequest)
   600  	}
   601  
   602  	if *authUser.AuthData == "" {
   603  		return nil, model.NewAppError("LoginByOAuth3", "api.user.login_by_oauth.parse.app_error",
   604  			map[string]interface{}{"Service": service}, "", http.StatusBadRequest)
   605  	}
   606  
   607  	user, err := a.GetUserByAuth(model.NewString(*authUser.AuthData), service)
   608  	if err != nil {
   609  		if err.Id == MISSING_AUTH_ACCOUNT_ERROR {
   610  			user, err = a.CreateOAuthUser(service, bytes.NewReader(buf.Bytes()), teamId, tokenUser)
   611  		} else {
   612  			return nil, err
   613  		}
   614  	} else {
   615  		// OAuth doesn't run through CheckUserPreflightAuthenticationCriteria, so prevent bot login
   616  		// here manually. Technically, the auth data above will fail to match a bot in the first
   617  		// place, but explicit is always better.
   618  		if user.IsBot {
   619  			return nil, model.NewAppError("loginByOAuth", "api.user.login_by_oauth.bot_login_forbidden.app_error", nil, "", http.StatusForbidden)
   620  		}
   621  
   622  		if err = a.UpdateOAuthUserAttrs(bytes.NewReader(buf.Bytes()), user, provider, service, tokenUser); err != nil {
   623  			return nil, err
   624  		}
   625  		if len(teamId) > 0 {
   626  			err = a.AddUserToTeamByTeamId(teamId, user)
   627  		}
   628  	}
   629  
   630  	if err != nil {
   631  		return nil, err
   632  	}
   633  
   634  	return user, nil
   635  }
   636  
   637  func (a *App) CompleteSwitchWithOAuth(service string, userData io.Reader, email string, tokenUser *model.User) (*model.User, *model.AppError) {
   638  	provider, e := a.getSSOProvider(service)
   639  	if e != nil {
   640  		return nil, e
   641  	}
   642  
   643  	if email == "" {
   644  		return nil, model.NewAppError("CompleteSwitchWithOAuth", "api.user.complete_switch_with_oauth.blank_email.app_error", nil, "", http.StatusBadRequest)
   645  	}
   646  
   647  	ssoUser, err1 := provider.GetUserFromJson(userData, tokenUser)
   648  	if err1 != nil {
   649  		return nil, model.NewAppError("CompleteSwitchWithOAuth", "api.user.complete_switch_with_oauth.parse.app_error",
   650  			map[string]interface{}{"Service": service}, err1.Error(), http.StatusBadRequest)
   651  	}
   652  
   653  	if *ssoUser.AuthData == "" {
   654  		return nil, model.NewAppError("CompleteSwitchWithOAuth", "api.user.complete_switch_with_oauth.parse.app_error",
   655  			map[string]interface{}{"Service": service}, "", http.StatusBadRequest)
   656  	}
   657  
   658  	user, nErr := a.Srv().Store.User().GetByEmail(email)
   659  	if nErr != nil {
   660  		return nil, model.NewAppError("CompleteSwitchWithOAuth", MISSING_ACCOUNT_ERROR, nil, nErr.Error(), http.StatusInternalServerError)
   661  	}
   662  
   663  	if err := a.RevokeAllSessions(user.Id); err != nil {
   664  		return nil, err
   665  	}
   666  
   667  	if _, nErr := a.Srv().Store.User().UpdateAuthData(user.Id, service, ssoUser.AuthData, ssoUser.Email, true); nErr != nil {
   668  		var invErr *store.ErrInvalidInput
   669  		switch {
   670  		case errors.As(nErr, &invErr):
   671  			return nil, model.NewAppError("importUser", "app.user.update_auth_data.email_exists.app_error", nil, invErr.Error(), http.StatusBadRequest)
   672  		default:
   673  			return nil, model.NewAppError("importUser", "app.user.update_auth_data.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   674  		}
   675  	}
   676  
   677  	a.Srv().Go(func() {
   678  		if err := a.Srv().EmailService.SendSignInChangeEmail(user.Email, strings.Title(service)+" SSO", user.Locale, a.GetSiteURL()); err != nil {
   679  			mlog.Error("error sending signin change email", mlog.Err(err))
   680  		}
   681  	})
   682  
   683  	return user, nil
   684  }
   685  
   686  func (a *App) CreateOAuthStateToken(extra string) (*model.Token, *model.AppError) {
   687  	token := model.NewToken(model.TOKEN_TYPE_OAUTH, extra)
   688  
   689  	if err := a.Srv().Store.Token().Save(token); err != nil {
   690  		var appErr *model.AppError
   691  		switch {
   692  		case errors.As(err, &appErr):
   693  			return nil, appErr
   694  		default:
   695  			return nil, model.NewAppError("CreateOAuthStateToken", "app.recover.save.app_error", nil, err.Error(), http.StatusInternalServerError)
   696  		}
   697  	}
   698  
   699  	return token, nil
   700  }
   701  
   702  func (a *App) GetOAuthStateToken(token string) (*model.Token, *model.AppError) {
   703  	mToken, err := a.Srv().Store.Token().GetByToken(token)
   704  	if err != nil {
   705  		return nil, model.NewAppError("GetOAuthStateToken", "api.oauth.invalid_state_token.app_error", nil, err.Error(), http.StatusBadRequest)
   706  	}
   707  
   708  	if mToken.Type != model.TOKEN_TYPE_OAUTH {
   709  		return nil, model.NewAppError("GetOAuthStateToken", "api.oauth.invalid_state_token.app_error", nil, "", http.StatusBadRequest)
   710  	}
   711  
   712  	return mToken, nil
   713  }
   714  
   715  func (a *App) GetAuthorizationCode(w http.ResponseWriter, r *http.Request, service string, props map[string]string, loginHint string) (string, *model.AppError) {
   716  	provider, e := a.getSSOProvider(service)
   717  	if e != nil {
   718  		return "", e
   719  	}
   720  
   721  	sso, e2 := provider.GetSSOSettings(a.Config(), service)
   722  	if e2 != nil {
   723  		return "", model.NewAppError("GetAuthorizationCode.GetSSOSettings", "api.user.get_authorization_code.endpoint.app_error", nil, e.Error(), http.StatusNotImplemented)
   724  	}
   725  
   726  	secure := false
   727  	if GetProtocol(r) == "https" {
   728  		secure = true
   729  	}
   730  
   731  	cookieValue := model.NewId()
   732  	subpath, _ := utils.GetSubpathFromConfig(a.Config())
   733  
   734  	expiresAt := time.Unix(model.GetMillis()/1000+int64(OAUTH_COOKIE_MAX_AGE_SECONDS), 0)
   735  	oauthCookie := &http.Cookie{
   736  		Name:     COOKIE_OAUTH,
   737  		Value:    cookieValue,
   738  		Path:     subpath,
   739  		MaxAge:   OAUTH_COOKIE_MAX_AGE_SECONDS,
   740  		Expires:  expiresAt,
   741  		HttpOnly: true,
   742  		Secure:   secure,
   743  	}
   744  
   745  	http.SetCookie(w, oauthCookie)
   746  
   747  	clientId := *sso.Id
   748  	endpoint := *sso.AuthEndpoint
   749  	scope := *sso.Scope
   750  
   751  	tokenExtra := generateOAuthStateTokenExtra(props["email"], props["action"], cookieValue)
   752  	stateToken, err := a.CreateOAuthStateToken(tokenExtra)
   753  	if err != nil {
   754  		return "", err
   755  	}
   756  
   757  	props["token"] = stateToken.Token
   758  	state := b64.StdEncoding.EncodeToString([]byte(model.MapToJson(props)))
   759  
   760  	siteUrl := a.GetSiteURL()
   761  	if strings.TrimSpace(siteUrl) == "" {
   762  		siteUrl = GetProtocol(r) + "://" + r.Host
   763  	}
   764  
   765  	redirectUri := siteUrl + "/signup/" + service + "/complete"
   766  
   767  	authUrl := endpoint + "?response_type=code&client_id=" + clientId + "&redirect_uri=" + url.QueryEscape(redirectUri) + "&state=" + url.QueryEscape(state)
   768  
   769  	if len(scope) > 0 {
   770  		authUrl += "&scope=" + utils.UrlEncode(scope)
   771  	}
   772  
   773  	if len(loginHint) > 0 {
   774  		authUrl += "&login_hint=" + utils.UrlEncode(loginHint)
   775  	}
   776  
   777  	return authUrl, nil
   778  }
   779  
   780  func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service, code, state, redirectUri string) (io.ReadCloser, string, map[string]string, *model.User, *model.AppError) {
   781  	provider, e := a.getSSOProvider(service)
   782  	if e != nil {
   783  		return nil, "", nil, nil, e
   784  	}
   785  
   786  	sso, e2 := provider.GetSSOSettings(a.Config(), service)
   787  	if e2 != nil {
   788  		return nil, "", nil, nil, model.NewAppError("GetAuthorizationCode.GetSSOSettings", "api.user.get_authorization_code.endpoint.app_error", nil, e.Error(), http.StatusNotImplemented)
   789  	}
   790  
   791  	b, strErr := b64.StdEncoding.DecodeString(state)
   792  	if strErr != nil {
   793  		return nil, "", nil, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, strErr.Error(), http.StatusBadRequest)
   794  	}
   795  
   796  	stateStr := string(b)
   797  	stateProps := model.MapFromJson(strings.NewReader(stateStr))
   798  
   799  	expectedToken, appErr := a.GetOAuthStateToken(stateProps["token"])
   800  	if appErr != nil {
   801  		return nil, "", stateProps, nil, appErr
   802  	}
   803  
   804  	stateEmail := stateProps["email"]
   805  	stateAction := stateProps["action"]
   806  	if stateAction == model.OAUTH_ACTION_EMAIL_TO_SSO && stateEmail == "" {
   807  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "", http.StatusBadRequest)
   808  	}
   809  
   810  	cookie, cookieErr := r.Cookie(COOKIE_OAUTH)
   811  	if cookieErr != nil {
   812  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "", http.StatusBadRequest)
   813  	}
   814  
   815  	expectedTokenExtra := generateOAuthStateTokenExtra(stateEmail, stateAction, cookie.Value)
   816  	if expectedTokenExtra != expectedToken.Extra {
   817  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "", http.StatusBadRequest)
   818  	}
   819  
   820  	appErr = a.DeleteToken(expectedToken)
   821  	if appErr != nil {
   822  		mlog.Error("error deleting token", mlog.Err(appErr))
   823  	}
   824  
   825  	subpath, _ := utils.GetSubpathFromConfig(a.Config())
   826  
   827  	httpCookie := &http.Cookie{
   828  		Name:     COOKIE_OAUTH,
   829  		Value:    "",
   830  		Path:     subpath,
   831  		MaxAge:   -1,
   832  		HttpOnly: true,
   833  	}
   834  
   835  	http.SetCookie(w, httpCookie)
   836  
   837  	teamId := stateProps["team_id"]
   838  
   839  	p := url.Values{}
   840  	p.Set("client_id", *sso.Id)
   841  	p.Set("client_secret", *sso.Secret)
   842  	p.Set("code", code)
   843  	p.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
   844  	p.Set("redirect_uri", redirectUri)
   845  
   846  	req, requestErr := http.NewRequest("POST", *sso.TokenEndpoint, strings.NewReader(p.Encode()))
   847  	if requestErr != nil {
   848  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, requestErr.Error(), http.StatusInternalServerError)
   849  	}
   850  
   851  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   852  	req.Header.Set("Accept", "application/json")
   853  
   854  	resp, err := a.HTTPService().MakeClient(true).Do(req)
   855  	if err != nil {
   856  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, err.Error(), http.StatusInternalServerError)
   857  	}
   858  	defer resp.Body.Close()
   859  
   860  	var buf bytes.Buffer
   861  	tee := io.TeeReader(resp.Body, &buf)
   862  	ar := model.AccessResponseFromJson(tee)
   863  	if ar == nil || resp.StatusCode != http.StatusOK {
   864  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.bad_response.app_error", nil, fmt.Sprintf("response_body=%s, status_code=%d", buf.String(), resp.StatusCode), http.StatusInternalServerError)
   865  	}
   866  
   867  	if strings.ToLower(ar.TokenType) != model.ACCESS_TOKEN_TYPE {
   868  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.bad_token.app_error", nil, "token_type="+ar.TokenType+", response_body="+buf.String(), http.StatusInternalServerError)
   869  	}
   870  
   871  	if len(ar.AccessToken) == 0 {
   872  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.missing.app_error", nil, "response_body="+buf.String(), http.StatusInternalServerError)
   873  	}
   874  
   875  	p = url.Values{}
   876  	p.Set("access_token", ar.AccessToken)
   877  
   878  	var userFromToken *model.User
   879  	if ar.IdToken != "" {
   880  		userFromToken, err = provider.GetUserFromIdToken(ar.IdToken)
   881  		if err != nil {
   882  			return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, e.Error(), http.StatusInternalServerError)
   883  		}
   884  	}
   885  
   886  	req, requestErr = http.NewRequest("GET", *sso.UserApiEndpoint, strings.NewReader(""))
   887  	if requestErr != nil {
   888  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.service.app_error", map[string]interface{}{"Service": service}, requestErr.Error(), http.StatusInternalServerError)
   889  	}
   890  
   891  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   892  	req.Header.Set("Accept", "application/json")
   893  	req.Header.Set("Authorization", "Bearer "+ar.AccessToken)
   894  
   895  	resp, err = a.HTTPService().MakeClient(true).Do(req)
   896  	if err != nil {
   897  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.service.app_error", map[string]interface{}{"Service": service}, err.Error(), http.StatusInternalServerError)
   898  	} else if resp.StatusCode != http.StatusOK {
   899  		defer resp.Body.Close()
   900  
   901  		// Ignore the error below because the resulting string will just be the empty string if bodyBytes is nil
   902  		bodyBytes, _ := ioutil.ReadAll(resp.Body)
   903  		bodyString := string(bodyBytes)
   904  
   905  		mlog.Error("Error getting OAuth user", mlog.Int("response", resp.StatusCode), mlog.String("body_string", bodyString))
   906  
   907  		if service == model.SERVICE_GITLAB && resp.StatusCode == http.StatusForbidden && strings.Contains(bodyString, "Terms of Service") {
   908  			// Return a nicer error when the user hasn't accepted GitLab's terms of service
   909  			return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "oauth.gitlab.tos.error", nil, "", http.StatusBadRequest)
   910  		}
   911  
   912  		return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.response.app_error", nil, "response_body="+bodyString, http.StatusInternalServerError)
   913  	}
   914  
   915  	// Note that resp.Body is not closed here, so it must be closed by the caller
   916  	return resp.Body, teamId, stateProps, userFromToken, nil
   917  }
   918  
   919  func (a *App) SwitchEmailToOAuth(w http.ResponseWriter, r *http.Request, email, password, code, service string) (string, *model.AppError) {
   920  	if a.Srv().License() != nil && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer {
   921  		return "", model.NewAppError("emailToOAuth", "api.user.email_to_oauth.not_available.app_error", nil, "", http.StatusForbidden)
   922  	}
   923  
   924  	user, err := a.GetUserByEmail(email)
   925  	if err != nil {
   926  		return "", err
   927  	}
   928  
   929  	if err = a.CheckPasswordAndAllCriteria(user, password, code); err != nil {
   930  		return "", err
   931  	}
   932  
   933  	stateProps := map[string]string{}
   934  	stateProps["action"] = model.OAUTH_ACTION_EMAIL_TO_SSO
   935  	stateProps["email"] = email
   936  
   937  	if service == model.USER_AUTH_SERVICE_SAML {
   938  		return a.GetSiteURL() + "/login/sso/saml?action=" + model.OAUTH_ACTION_EMAIL_TO_SSO + "&email=" + utils.UrlEncode(email), nil
   939  	}
   940  
   941  	authUrl, err := a.GetAuthorizationCode(w, r, service, stateProps, "")
   942  	if err != nil {
   943  		return "", err
   944  	}
   945  
   946  	return authUrl, nil
   947  }
   948  
   949  func (a *App) SwitchOAuthToEmail(email, password, requesterId string) (string, *model.AppError) {
   950  	if a.Srv().License() != nil && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer {
   951  		return "", model.NewAppError("oauthToEmail", "api.user.oauth_to_email.not_available.app_error", nil, "", http.StatusForbidden)
   952  	}
   953  
   954  	user, err := a.GetUserByEmail(email)
   955  	if err != nil {
   956  		return "", err
   957  	}
   958  
   959  	if user.Id != requesterId {
   960  		return "", model.NewAppError("SwitchOAuthToEmail", "api.user.oauth_to_email.context.app_error", nil, "", http.StatusForbidden)
   961  	}
   962  
   963  	if err := a.UpdatePassword(user, password); err != nil {
   964  		return "", err
   965  	}
   966  
   967  	T := utils.GetUserTranslations(user.Locale)
   968  
   969  	a.Srv().Go(func() {
   970  		if err := a.Srv().EmailService.SendSignInChangeEmail(user.Email, T("api.templates.signin_change_email.body.method_email"), user.Locale, a.GetSiteURL()); err != nil {
   971  			mlog.Error("error sending signin change email", mlog.Err(err))
   972  		}
   973  	})
   974  
   975  	if err := a.RevokeAllSessions(requesterId); err != nil {
   976  		return "", err
   977  	}
   978  
   979  	return "/login?extra=signin_change", nil
   980  }
   981  
   982  func generateOAuthStateTokenExtra(email, action, cookie string) string {
   983  	return email + ":" + action + ":" + cookie
   984  }