Refactor switching login type code into app layer and add v4 endpoint (#6000)
* Refactor switching login type code into app layer and add v4 endpoint * Fix unit test
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
7b77bcf87e
Коммит
dfc6db7374
172
app/oauth.go
172
app/oauth.go
@@ -4,11 +4,20 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
b64 "encoding/base64"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
)
|
||||
|
||||
func RevokeAccessToken(token string) *model.AppError {
|
||||
|
||||
session, _ := GetSession(token)
|
||||
schan := Srv.Store.Session().Remove(token)
|
||||
|
||||
@@ -32,3 +41,164 @@ func RevokeAccessToken(token string) *model.AppError {
|
||||
|
||||
return 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)
|
||||
}
|
||||
|
||||
clientId := sso.Id
|
||||
endpoint := sso.AuthEndpoint
|
||||
scope := sso.Scope
|
||||
|
||||
props["hash"] = model.HashPassword(clientId)
|
||||
state := b64.StdEncoding.EncodeToString([]byte(model.MapToJson(props)))
|
||||
|
||||
redirectUri := utils.GetSiteURL() + "/signup/" + service + "/complete"
|
||||
|
||||
authUrl := endpoint + "?response_type=code&client_id=" + clientId + "&redirect_uri=" + url.QueryEscape(redirectUri) + "&state=" + url.QueryEscape(state)
|
||||
|
||||
if len(scope) > 0 {
|
||||
authUrl += "&scope=" + utils.UrlEncode(scope)
|
||||
}
|
||||
|
||||
if len(loginHint) > 0 {
|
||||
authUrl += "&login_hint=" + utils.UrlEncode(loginHint)
|
||||
}
|
||||
|
||||
return authUrl, nil
|
||||
}
|
||||
|
||||
func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser, string, map[string]string, *model.AppError) {
|
||||
sso := utils.Cfg.GetSSOService(service)
|
||||
if sso == nil || !sso.Enable {
|
||||
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.unsupported.app_error", nil, "service="+service)
|
||||
}
|
||||
|
||||
stateStr := ""
|
||||
if b, err := b64.StdEncoding.DecodeString(state); err != nil {
|
||||
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, err.Error())
|
||||
} else {
|
||||
stateStr = string(b)
|
||||
}
|
||||
|
||||
stateProps := model.MapFromJson(strings.NewReader(stateStr))
|
||||
|
||||
if !model.ComparePassword(stateProps["hash"], sso.Id) {
|
||||
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "")
|
||||
}
|
||||
|
||||
teamId := stateProps["team_id"]
|
||||
|
||||
p := url.Values{}
|
||||
p.Set("client_id", sso.Id)
|
||||
p.Set("client_secret", sso.Secret)
|
||||
p.Set("code", code)
|
||||
p.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
|
||||
p.Set("redirect_uri", redirectUri)
|
||||
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections},
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
req, _ := http.NewRequest("POST", sso.TokenEndpoint, strings.NewReader(p.Encode()))
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
var ar *model.AccessResponse
|
||||
var respBody []byte
|
||||
if resp, err := client.Do(req); err != nil {
|
||||
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, err.Error())
|
||||
} else {
|
||||
ar = model.AccessResponseFromJson(resp.Body)
|
||||
defer func() {
|
||||
ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
}()
|
||||
if ar == nil {
|
||||
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.bad_response.app_error", nil, "")
|
||||
}
|
||||
}
|
||||
|
||||
if strings.ToLower(ar.TokenType) != model.ACCESS_TOKEN_TYPE {
|
||||
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.bad_token.app_error", nil, "token_type="+ar.TokenType+", response_body="+string(respBody))
|
||||
}
|
||||
|
||||
if len(ar.AccessToken) == 0 {
|
||||
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.missing.app_error", nil, "")
|
||||
}
|
||||
|
||||
p = url.Values{}
|
||||
p.Set("access_token", ar.AccessToken)
|
||||
req, _ = http.NewRequest("GET", sso.UserApiEndpoint, strings.NewReader(""))
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+ar.AccessToken)
|
||||
|
||||
if resp, err := client.Do(req); err != nil {
|
||||
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.service.app_error",
|
||||
map[string]interface{}{"Service": service}, err.Error())
|
||||
} else {
|
||||
return resp.Body, teamId, stateProps, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func SwitchEmailToOAuth(email, password, code, service string) (string, *model.AppError) {
|
||||
var user *model.User
|
||||
var err *model.AppError
|
||||
if user, err = GetUserByEmail(email); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := CheckPasswordAndAllCriteria(user, password, code); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
stateProps := map[string]string{}
|
||||
stateProps["action"] = model.OAUTH_ACTION_EMAIL_TO_SSO
|
||||
stateProps["email"] = email
|
||||
|
||||
if service == model.USER_AUTH_SERVICE_SAML {
|
||||
return utils.GetSiteURL() + "/login/sso/saml?action=" + model.OAUTH_ACTION_EMAIL_TO_SSO + "&email=" + email, nil
|
||||
} else {
|
||||
if authUrl, err := GetAuthorizationCode(service, stateProps, ""); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
return authUrl, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SwitchOAuthToEmail(email, password, requesterId string) (string, *model.AppError) {
|
||||
var user *model.User
|
||||
var err *model.AppError
|
||||
if user, err = GetUserByEmail(email); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if user.Id != requesterId {
|
||||
return "", model.NewAppError("SwitchOAuthToEmail", "api.user.oauth_to_email.context.app_error", nil, "", http.StatusForbidden)
|
||||
}
|
||||
|
||||
if err := UpdatePassword(user, password); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
T := utils.GetUserTranslations(user.Locale)
|
||||
|
||||
go func() {
|
||||
if err := SendSignInChangeEmail(user.Email, T("api.templates.signin_change_email.body.method_email"), user.Locale, utils.GetSiteURL()); err != nil {
|
||||
l4g.Error(err.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
if err := RevokeAllSessions(requesterId); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "/login?extra=signin_change", nil
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user