Refactor OAuth 2.0 code into app layer (#6037)
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
03502cf73b
Коммит
8b8aa2ca3c
477
app/oauth.go
477
app/oauth.go
@@ -4,8 +4,10 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
b64 "encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -13,10 +15,371 @@ import (
|
||||
"strings"
|
||||
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/einterfaces"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/store"
|
||||
"github.com/mattermost/platform/utils"
|
||||
)
|
||||
|
||||
func CreateOAuthApp(app *model.OAuthApp) (*model.OAuthApp, *model.AppError) {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return nil, model.NewAppError("CreateOAuthApp", "api.oauth.register_oauth_app.turn_off.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
secret := model.NewId()
|
||||
app.ClientSecret = secret
|
||||
|
||||
if result := <-Srv.Store.OAuth().SaveApp(app); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(*model.OAuthApp), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetOAuthApp(appId string) (*model.OAuthApp, *model.AppError) {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return nil, model.NewAppError("GetOAuthApp", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.OAuth().GetApp(appId); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(*model.OAuthApp), nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteOAuthApp(appId string) *model.AppError {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return model.NewAppError("DeleteOAuthApp", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if err := (<-Srv.Store.OAuth().DeleteApp(appId)).Err; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetOAuthApps(page, perPage int) ([]*model.OAuthApp, *model.AppError) {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return nil, model.NewAppError("GetOAuthApps", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.OAuth().GetApps(page*perPage, perPage); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.([]*model.OAuthApp), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetOAuthAppsByCreator(userId string, page, perPage int) ([]*model.OAuthApp, *model.AppError) {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return nil, model.NewAppError("GetOAuthAppsByUser", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.OAuth().GetAppByUser(userId, page*perPage, perPage); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.([]*model.OAuthApp), nil
|
||||
}
|
||||
}
|
||||
|
||||
func AllowOAuthAppAccessToUser(userId, responseType, clientId, redirectUri, scope, state string) (string, *model.AppError) {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return "", model.NewAppError("AllowOAuthAppAccessToUser", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if len(scope) == 0 {
|
||||
scope = model.DEFAULT_SCOPE
|
||||
}
|
||||
|
||||
var oauthApp *model.OAuthApp
|
||||
if result := <-Srv.Store.OAuth().GetApp(clientId); result.Err != nil {
|
||||
return "", result.Err
|
||||
} else {
|
||||
oauthApp = result.Data.(*model.OAuthApp)
|
||||
}
|
||||
|
||||
if !oauthApp.IsValidRedirectURL(redirectUri) {
|
||||
return "", model.NewAppError("AllowOAuthAppAccessToUser", "api.oauth.allow_oauth.redirect_callback.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if responseType != model.AUTHCODE_RESPONSE_TYPE {
|
||||
return redirectUri + "?error=unsupported_response_type&state=" + state, nil
|
||||
}
|
||||
|
||||
authData := &model.AuthData{UserId: userId, ClientId: clientId, CreateAt: model.GetMillis(), RedirectUri: redirectUri, State: state, Scope: scope}
|
||||
authData.Code = model.HashPassword(fmt.Sprintf("%v:%v:%v:%v", clientId, redirectUri, authData.CreateAt, userId))
|
||||
|
||||
// this saves the OAuth2 app as authorized
|
||||
authorizedApp := model.Preference{
|
||||
UserId: userId,
|
||||
Category: model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP,
|
||||
Name: clientId,
|
||||
Value: scope,
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.Preference().Save(&model.Preferences{authorizedApp}); result.Err != nil {
|
||||
return redirectUri + "?error=server_error&state=" + state, nil
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.OAuth().SaveAuthData(authData); result.Err != nil {
|
||||
return redirectUri + "?error=server_error&state=" + state, nil
|
||||
}
|
||||
|
||||
return redirectUri + "?code=" + url.QueryEscape(authData.Code) + "&state=" + url.QueryEscape(authData.State), nil
|
||||
}
|
||||
|
||||
func GetOAuthAccessToken(clientId, grantType, redirectUri, code, secret, refreshToken string) (*model.AccessResponse, *model.AppError) {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
var oauthApp *model.OAuthApp
|
||||
if result := <-Srv.Store.OAuth().GetApp(clientId); result.Err != nil {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.credentials.app_error", nil, "", http.StatusNotFound)
|
||||
} else {
|
||||
oauthApp = result.Data.(*model.OAuthApp)
|
||||
}
|
||||
|
||||
if oauthApp.ClientSecret != secret {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.credentials.app_error", nil, "", http.StatusForbidden)
|
||||
}
|
||||
|
||||
var user *model.User
|
||||
var accessData *model.AccessData
|
||||
var accessRsp *model.AccessResponse
|
||||
if grantType == model.ACCESS_TOKEN_GRANT_TYPE {
|
||||
|
||||
var authData *model.AuthData
|
||||
if result := <-Srv.Store.OAuth().GetAuthData(code); result.Err != nil {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.expired_code.app_error", nil, "", http.StatusInternalServerError)
|
||||
} else {
|
||||
authData = result.Data.(*model.AuthData)
|
||||
}
|
||||
|
||||
if authData.IsExpired() {
|
||||
<-Srv.Store.OAuth().RemoveAuthData(authData.Code)
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.expired_code.app_error", nil, "", http.StatusForbidden)
|
||||
}
|
||||
|
||||
if authData.RedirectUri != redirectUri {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.redirect_uri.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if !model.ComparePassword(code, fmt.Sprintf("%v:%v:%v:%v", clientId, redirectUri, authData.CreateAt, authData.UserId)) {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.expired_code.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.User().Get(authData.UserId); result.Err != nil {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_user.app_error", nil, "", http.StatusNotFound)
|
||||
} else {
|
||||
user = result.Data.(*model.User)
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.OAuth().GetPreviousAccessData(user.Id, clientId); result.Err != nil {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal.app_error", nil, "", http.StatusInternalServerError)
|
||||
} else if result.Data != nil {
|
||||
accessData := result.Data.(*model.AccessData)
|
||||
if accessData.IsExpired() {
|
||||
if access, err := newSessionUpdateToken(oauthApp.Name, accessData, user); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
accessRsp = access
|
||||
}
|
||||
} else {
|
||||
//return the same token and no need to create a new session
|
||||
accessRsp = &model.AccessResponse{
|
||||
AccessToken: accessData.Token,
|
||||
TokenType: model.ACCESS_TOKEN_TYPE,
|
||||
ExpiresIn: int32((accessData.ExpiresAt - model.GetMillis()) / 1000),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// create a new session and return new access token
|
||||
var session *model.Session
|
||||
if result, err := newSession(oauthApp.Name, user); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
session = result
|
||||
}
|
||||
|
||||
accessData = &model.AccessData{ClientId: clientId, UserId: user.Id, Token: session.Token, RefreshToken: model.NewId(), RedirectUri: redirectUri, ExpiresAt: session.ExpiresAt, Scope: authData.Scope}
|
||||
|
||||
if result := <-Srv.Store.OAuth().SaveAccessData(accessData); result.Err != nil {
|
||||
l4g.Error(result.Err)
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_saving.app_error", nil, "", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
accessRsp = &model.AccessResponse{
|
||||
AccessToken: session.Token,
|
||||
TokenType: model.ACCESS_TOKEN_TYPE,
|
||||
RefreshToken: accessData.RefreshToken,
|
||||
ExpiresIn: int32(*utils.Cfg.ServiceSettings.SessionLengthSSOInDays * 60 * 60 * 24),
|
||||
}
|
||||
}
|
||||
|
||||
<-Srv.Store.OAuth().RemoveAuthData(authData.Code)
|
||||
} else {
|
||||
// when grantType is refresh_token
|
||||
if result := <-Srv.Store.OAuth().GetAccessDataByRefreshToken(refreshToken); result.Err != nil {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.refresh_token.app_error", nil, "", http.StatusNotFound)
|
||||
} else {
|
||||
accessData = result.Data.(*model.AccessData)
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.User().Get(accessData.UserId); result.Err != nil {
|
||||
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_user.app_error", nil, "", http.StatusNotFound)
|
||||
} else {
|
||||
user = result.Data.(*model.User)
|
||||
}
|
||||
|
||||
if access, err := newSessionUpdateToken(oauthApp.Name, accessData, user); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
accessRsp = access
|
||||
}
|
||||
}
|
||||
|
||||
return accessRsp, nil
|
||||
}
|
||||
|
||||
func newSession(appName string, user *model.User) (*model.Session, *model.AppError) {
|
||||
// set new token an session
|
||||
session := &model.Session{UserId: user.Id, Roles: user.Roles, IsOAuth: true}
|
||||
session.SetExpireInDays(*utils.Cfg.ServiceSettings.SessionLengthSSOInDays)
|
||||
session.AddProp(model.SESSION_PROP_PLATFORM, appName)
|
||||
session.AddProp(model.SESSION_PROP_OS, "OAuth2")
|
||||
session.AddProp(model.SESSION_PROP_BROWSER, "OAuth2")
|
||||
|
||||
if result := <-Srv.Store.Session().Save(session); result.Err != nil {
|
||||
return nil, model.NewAppError("newSession", "api.oauth.get_access_token.internal_session.app_error", nil, "", http.StatusInternalServerError)
|
||||
} else {
|
||||
session = result.Data.(*model.Session)
|
||||
AddSessionToCache(session)
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func newSessionUpdateToken(appName string, accessData *model.AccessData, user *model.User) (*model.AccessResponse, *model.AppError) {
|
||||
var session *model.Session
|
||||
<-Srv.Store.Session().Remove(accessData.Token) //remove the previous session
|
||||
|
||||
if result, err := newSession(appName, user); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
session = result
|
||||
}
|
||||
|
||||
accessData.Token = session.Token
|
||||
accessData.ExpiresAt = session.ExpiresAt
|
||||
if result := <-Srv.Store.OAuth().UpdateAccessData(accessData); result.Err != nil {
|
||||
l4g.Error(result.Err)
|
||||
return nil, model.NewAppError("newSessionUpdateToken", "web.get_access_token.internal_saving.app_error", nil, "", http.StatusInternalServerError)
|
||||
}
|
||||
accessRsp := &model.AccessResponse{
|
||||
AccessToken: session.Token,
|
||||
TokenType: model.ACCESS_TOKEN_TYPE,
|
||||
ExpiresIn: int32(*utils.Cfg.ServiceSettings.SessionLengthSSOInDays * 60 * 60 * 24),
|
||||
}
|
||||
|
||||
return accessRsp, nil
|
||||
}
|
||||
|
||||
func GetOAuthLoginEndpoint(service, teamId, redirectTo, loginHint string) (string, *model.AppError) {
|
||||
stateProps := map[string]string{}
|
||||
stateProps["action"] = model.OAUTH_ACTION_LOGIN
|
||||
if len(teamId) != 0 {
|
||||
stateProps["team_id"] = teamId
|
||||
}
|
||||
|
||||
if len(redirectTo) != 0 {
|
||||
stateProps["redirect_to"] = redirectTo
|
||||
}
|
||||
|
||||
if authUrl, err := GetAuthorizationCode(service, stateProps, loginHint); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return authUrl, nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetOAuthSignupEndpoint(service, teamId string) (string, *model.AppError) {
|
||||
stateProps := map[string]string{}
|
||||
stateProps["action"] = model.OAUTH_ACTION_SIGNUP
|
||||
if len(teamId) != 0 {
|
||||
stateProps["team_id"] = teamId
|
||||
}
|
||||
|
||||
if authUrl, err := GetAuthorizationCode(service, stateProps, ""); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return authUrl, nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetAuthorizedAppsForUser(userId string, page, perPage int) ([]*model.OAuthApp, *model.AppError) {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return nil, model.NewAppError("GetAuthorizedAppsForUser", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.OAuth().GetAuthorizedApps(userId, page*perPage, perPage); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
apps := result.Data.([]*model.OAuthApp)
|
||||
for k, a := range apps {
|
||||
a.Sanitize()
|
||||
apps[k] = a
|
||||
}
|
||||
|
||||
return apps, nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeauthorizeOAuthAppForUser(userId, appId string) *model.AppError {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return model.NewAppError("DeauthorizeOAuthAppForUser", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// revoke app sessions
|
||||
if result := <-Srv.Store.OAuth().GetAccessDataByUserForApp(userId, appId); result.Err != nil {
|
||||
return result.Err
|
||||
} else {
|
||||
accessData := result.Data.([]*model.AccessData)
|
||||
|
||||
for _, a := range accessData {
|
||||
if err := RevokeAccessToken(a.Token); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rad := <-Srv.Store.OAuth().RemoveAccessData(a.Token); rad.Err != nil {
|
||||
return rad.Err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deauthorize the app
|
||||
if err := (<-Srv.Store.Preference().Delete(userId, model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP, appId)).Err; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func RegenerateOAuthAppSecret(app *model.OAuthApp) (*model.OAuthApp, *model.AppError) {
|
||||
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {
|
||||
return nil, model.NewAppError("RegenerateOAuthAppSecret", "api.oauth.allow_oauth.turn_off.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
app.ClientSecret = model.NewId()
|
||||
if update := <-Srv.Store.OAuth().UpdateApp(app); update.Err != nil {
|
||||
return nil, update.Err
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func RevokeAccessToken(token string) *model.AppError {
|
||||
session, _ := GetSession(token)
|
||||
schan := Srv.Store.Session().Remove(token)
|
||||
@@ -42,10 +405,122 @@ func RevokeAccessToken(token string) *model.AppError {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CompleteOAuth(service string, body io.ReadCloser, teamId string, props map[string]string) (*model.User, *model.AppError) {
|
||||
defer func() {
|
||||
ioutil.ReadAll(body)
|
||||
body.Close()
|
||||
}()
|
||||
|
||||
action := props["action"]
|
||||
|
||||
switch action {
|
||||
case model.OAUTH_ACTION_SIGNUP:
|
||||
return CreateOAuthUser(service, body, teamId)
|
||||
case model.OAUTH_ACTION_LOGIN:
|
||||
return LoginByOAuth(service, body, teamId)
|
||||
case model.OAUTH_ACTION_EMAIL_TO_SSO:
|
||||
return CompleteSwitchWithOAuth(service, body, props["email"])
|
||||
case model.OAUTH_ACTION_SSO_TO_EMAIL:
|
||||
return LoginByOAuth(service, body, teamId)
|
||||
default:
|
||||
return LoginByOAuth(service, body, teamId)
|
||||
}
|
||||
}
|
||||
|
||||
func LoginByOAuth(service string, userData io.Reader, teamId string) (*model.User, *model.AppError) {
|
||||
buf := bytes.Buffer{}
|
||||
buf.ReadFrom(userData)
|
||||
|
||||
authData := ""
|
||||
provider := einterfaces.GetOauthProvider(service)
|
||||
if provider == nil {
|
||||
return nil, model.NewAppError("LoginByOAuth", "api.user.login_by_oauth.not_available.app_error",
|
||||
map[string]interface{}{"Service": strings.Title(service)}, "", http.StatusNotImplemented)
|
||||
} else {
|
||||
authData = provider.GetAuthDataFromJson(bytes.NewReader(buf.Bytes()))
|
||||
}
|
||||
|
||||
if len(authData) == 0 {
|
||||
return nil, model.NewAppError("LoginByOAuth", "api.user.login_by_oauth.parse.app_error",
|
||||
map[string]interface{}{"Service": service}, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
user, err := GetUserByAuth(&authData, service)
|
||||
if err != nil {
|
||||
if err.Id == store.MISSING_AUTH_ACCOUNT_ERROR {
|
||||
return CreateOAuthUser(service, bytes.NewReader(buf.Bytes()), teamId)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = UpdateOAuthUserAttrs(bytes.NewReader(buf.Bytes()), user, provider, service); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(teamId) > 0 {
|
||||
err = AddUserToTeamByTeamId(teamId, user)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func CompleteSwitchWithOAuth(service string, userData io.ReadCloser, email string) (*model.User, *model.AppError) {
|
||||
authData := ""
|
||||
ssoEmail := ""
|
||||
provider := einterfaces.GetOauthProvider(service)
|
||||
if provider == nil {
|
||||
return nil, model.NewAppError("CompleteSwitchWithOAuth", "api.user.complete_switch_with_oauth.unavailable.app_error",
|
||||
map[string]interface{}{"Service": strings.Title(service)}, "", http.StatusNotImplemented)
|
||||
} else {
|
||||
ssoUser := provider.GetUserFromJson(userData)
|
||||
ssoEmail = ssoUser.Email
|
||||
|
||||
if ssoUser.AuthData != nil {
|
||||
authData = *ssoUser.AuthData
|
||||
}
|
||||
}
|
||||
|
||||
if len(authData) == 0 {
|
||||
return nil, model.NewAppError("CompleteSwitchWithOAuth", "api.user.complete_switch_with_oauth.parse.app_error",
|
||||
map[string]interface{}{"Service": service}, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if len(email) == 0 {
|
||||
return nil, model.NewAppError("CompleteSwitchWithOAuth", "api.user.complete_switch_with_oauth.blank_email.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
var user *model.User
|
||||
if result := <-Srv.Store.User().GetByEmail(email); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
user = result.Data.(*model.User)
|
||||
}
|
||||
|
||||
if err := RevokeAllSessions(user.Id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.User().UpdateAuthData(user.Id, service, &authData, ssoEmail, true); result.Err != nil {
|
||||
return nil, result.Err
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := SendSignInChangeEmail(user.Email, strings.Title(service)+" SSO", user.Locale, utils.GetSiteURL()); err != nil {
|
||||
l4g.Error(err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func GetAuthorizationCode(service string, props map[string]string, loginHint string) (string, *model.AppError) {
|
||||
sso := utils.Cfg.GetSSOService(service)
|
||||
if sso != nil && !sso.Enable {
|
||||
return "", model.NewLocAppError("GetAuthorizationCode", "api.user.get_authorization_code.unsupported.app_error", nil, "service="+service)
|
||||
return "", model.NewAppError("GetAuthorizationCode", "api.user.get_authorization_code.unsupported.app_error", nil, "service="+service, http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
clientId := sso.Id
|
||||
|
||||
31
app/team.go
31
app/team.go
@@ -6,6 +6,7 @@ package app
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -747,3 +748,33 @@ func GetTeamStats(teamId string) (*model.TeamStats, *model.AppError) {
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func GetTeamIdFromQuery(query url.Values) (string, *model.AppError) {
|
||||
hash := query.Get("h")
|
||||
inviteId := query.Get("id")
|
||||
|
||||
if len(hash) > 0 {
|
||||
data := query.Get("d")
|
||||
props := model.MapFromJson(strings.NewReader(data))
|
||||
|
||||
if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
|
||||
return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.invalid_link.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
t, err := strconv.ParseInt(props["time"], 10, 64)
|
||||
if err != nil || model.GetMillis()-t > 1000*60*60*48 { // 48 hours
|
||||
return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.expired_link.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
return props["id"], nil
|
||||
} else if len(inviteId) > 0 {
|
||||
if result := <-Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil {
|
||||
// soft fail, so we still create user but don't auto-join team
|
||||
l4g.Error("%v", result.Err)
|
||||
} else {
|
||||
return result.Data.(*model.Team).Id, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user