* implement openid connect

* update error strings

* handle OpenIdSetting.Secret as FAKE SETTING

* add openid to telemetry

* update config defaults, add telemetry

* fix bug with Office365

* Retrieve Office365 AuthData from IdToken

* fix linter

* add feature flag, reset defaults for config

* fix build error

* fix unit tests

* add authentication permission to Feature
Flags

* turn off feature flag

* set default button color

* set default button color only on openid

* fix for merging FeatureFlags in config

* remove feature flag

* revert config changes

* remove debug statements

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Scott Bishel
2020-12-08 19:58:37 -07:00
коммит произвёл GitHub
родитель 2a71fc5ee2
Коммит f548ecbee1
22 изменённых файлов: 258 добавлений и 138 удалений

Просмотреть файл

@@ -376,7 +376,7 @@ type AppIface interface {
AttachDeviceId(sessionId string, deviceId string, expiresAt int64) *model.AppError
AttachSessionCookies(w http.ResponseWriter, r *http.Request)
AuthenticateUserForLogin(id, loginId, password, mfaToken, cwsToken string, ldapOnly bool) (user *model.User, err *model.AppError)
AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service, code, state, redirectUri string) (io.ReadCloser, string, map[string]string, *model.AppError)
AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service, code, state, redirectUri string) (io.ReadCloser, string, map[string]string, *model.User, *model.AppError)
AutocompleteChannels(teamId string, term string) (*model.ChannelList, *model.AppError)
AutocompleteChannelsForSearch(teamId string, userId string, term string) (*model.ChannelList, *model.AppError)
AutocompleteUsersInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError)
@@ -412,8 +412,8 @@ type AppIface interface {
Cluster() einterfaces.ClusterInterface
CompareAndDeletePluginKey(pluginId string, key string, oldValue []byte) (bool, *model.AppError)
CompareAndSetPluginKey(pluginId string, key string, oldValue, newValue []byte) (bool, *model.AppError)
CompleteOAuth(service string, body io.ReadCloser, teamId string, props map[string]string) (*model.User, *model.AppError)
CompleteSwitchWithOAuth(service string, userData io.Reader, email string) (*model.User, *model.AppError)
CompleteOAuth(service string, body io.ReadCloser, teamId string, props map[string]string, tokenUser *model.User) (*model.User, *model.AppError)
CompleteSwitchWithOAuth(service string, userData io.Reader, email string, tokenUser *model.User) (*model.User, *model.AppError)
Compliance() einterfaces.ComplianceInterface
Config() *model.Config
Context() context.Context
@@ -429,7 +429,7 @@ type AppIface interface {
CreateJob(job *model.Job) (*model.Job, *model.AppError)
CreateOAuthApp(app *model.OAuthApp) (*model.OAuthApp, *model.AppError)
CreateOAuthStateToken(extra string) (*model.Token, *model.AppError)
CreateOAuthUser(service string, userData io.Reader, teamId string) (*model.User, *model.AppError)
CreateOAuthUser(service string, userData io.Reader, teamId string, tokenUser *model.User) (*model.User, *model.AppError)
CreateOutgoingWebhook(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.AppError)
CreatePasswordRecoveryToken(userId, email string) (*model.Token, *model.AppError)
CreatePost(post *model.Post, channel *model.Channel, triggerWebhooks, setOnline bool) (savedPost *model.Post, err *model.AppError)
@@ -778,7 +778,7 @@ type AppIface interface {
ListPluginKeys(pluginId string, page, perPage int) ([]string, *model.AppError)
ListTeamCommands(teamId string) ([]*model.Command, *model.AppError)
Log() *mlog.Logger
LoginByOAuth(service string, userData io.Reader, teamId string) (*model.User, *model.AppError)
LoginByOAuth(service string, userData io.Reader, teamId string, tokenUser *model.User) (*model.User, *model.AppError)
MakePermissionError(permissions []*model.Permission) *model.AppError
MarkChannelsAsViewed(channelIds []string, userId string, currentSessionId string) (map[string]int64, *model.AppError)
MaxPostSize() int
@@ -982,7 +982,7 @@ type AppIface interface {
UpdateLastActivityAtIfNeeded(session model.Session)
UpdateMfa(activate bool, userId, token string) *model.AppError
UpdateMobileAppBadge(userId string)
UpdateOAuthUserAttrs(userData io.Reader, user *model.User, provider einterfaces.OauthProvider, service string) *model.AppError
UpdateOAuthUserAttrs(userData io.Reader, user *model.User, provider einterfaces.OauthProvider, service string, tokenUser *model.User) *model.AppError
UpdateOauthApp(oldApp, updatedApp *model.OAuthApp) (*model.OAuthApp, *model.AppError)
UpdateOutgoingWebhook(oldHook, updatedHook *model.OutgoingWebhook) (*model.OutgoingWebhook, *model.AppError)
UpdatePassword(user *model.User, newPassword string) *model.AppError

Просмотреть файл

@@ -26,6 +26,7 @@ import (
const (
OAUTH_COOKIE_MAX_AGE_SECONDS = 30 * 60 // 30 minutes
COOKIE_OAUTH = "MMOAUTH"
OPENID_SCOPE = "openid"
)
func (a *App) CreateOAuthApp(app *model.OAuthApp) (*model.OAuthApp, *model.AppError) {
@@ -544,52 +545,69 @@ func (a *App) RevokeAccessToken(token string) *model.AppError {
return nil
}
func (a *App) CompleteOAuth(service string, body io.ReadCloser, teamId string, props map[string]string) (*model.User, *model.AppError) {
func (a *App) CompleteOAuth(service string, body io.ReadCloser, teamId string, props map[string]string, tokenUser *model.User) (*model.User, *model.AppError) {
defer body.Close()
action := props["action"]
switch action {
case model.OAUTH_ACTION_SIGNUP:
return a.CreateOAuthUser(service, body, teamId)
return a.CreateOAuthUser(service, body, teamId, tokenUser)
case model.OAUTH_ACTION_LOGIN:
return a.LoginByOAuth(service, body, teamId)
return a.LoginByOAuth(service, body, teamId, tokenUser)
case model.OAUTH_ACTION_EMAIL_TO_SSO:
return a.CompleteSwitchWithOAuth(service, body, props["email"])
return a.CompleteSwitchWithOAuth(service, body, props["email"], tokenUser)
case model.OAUTH_ACTION_SSO_TO_EMAIL:
return a.LoginByOAuth(service, body, teamId)
return a.LoginByOAuth(service, body, teamId, tokenUser)
default:
return a.LoginByOAuth(service, body, teamId)
return a.LoginByOAuth(service, body, teamId, tokenUser)
}
}
func (a *App) LoginByOAuth(service string, userData io.Reader, teamId string) (*model.User, *model.AppError) {
provider := einterfaces.GetOauthProvider(service)
func (a *App) getSSOProvider(service string) (einterfaces.OauthProvider, *model.AppError) {
sso := a.Config().GetSSOService(service)
if sso == nil || !*sso.Enable {
return nil, model.NewAppError("getSSOProvider", "api.user.authorize_oauth_user.unsupported.app_error", nil, "service="+service, http.StatusNotImplemented)
}
providerType := service
if strings.Contains(*sso.Scope, OPENID_SCOPE) {
providerType = model.SERVICE_OPENID
}
provider := einterfaces.GetOauthProvider(providerType)
if provider == nil {
return nil, model.NewAppError("LoginByOAuth", "api.user.login_by_oauth.not_available.app_error",
return nil, model.NewAppError("getSSOProvider", "api.user.login_by_oauth.not_available.app_error",
map[string]interface{}{"Service": strings.Title(service)}, "", http.StatusNotImplemented)
}
return provider, nil
}
func (a *App) LoginByOAuth(service string, userData io.Reader, teamId string, tokenUser *model.User) (*model.User, *model.AppError) {
provider, e := a.getSSOProvider(service)
if e != nil {
return nil, e
}
buf := bytes.Buffer{}
if _, err := buf.ReadFrom(userData); err != nil {
return nil, model.NewAppError("LoginByOAuth", "api.user.login_by_oauth.parse.app_error",
return nil, model.NewAppError("LoginByOAuth2", "api.user.login_by_oauth.parse.app_error",
map[string]interface{}{"Service": service}, "", http.StatusBadRequest)
}
authUser, err1 := provider.GetUserFromJson(bytes.NewReader(buf.Bytes()))
authUser, err1 := provider.GetUserFromJson(bytes.NewReader(buf.Bytes()), tokenUser)
if err1 != nil {
return nil, model.NewAppError("LoginByOAuth", "api.user.login_by_oauth.parse.app_error",
map[string]interface{}{"Service": service}, err1.Error(), http.StatusBadRequest)
}
if *authUser.AuthData == "" {
return nil, model.NewAppError("LoginByOAuth", "api.user.login_by_oauth.parse.app_error",
return nil, model.NewAppError("LoginByOAuth3", "api.user.login_by_oauth.parse.app_error",
map[string]interface{}{"Service": service}, "", http.StatusBadRequest)
}
user, err := a.GetUserByAuth(model.NewString(*authUser.AuthData), service)
if err != nil {
if err.Id == MISSING_AUTH_ACCOUNT_ERROR {
user, err = a.CreateOAuthUser(service, bytes.NewReader(buf.Bytes()), teamId)
user, err = a.CreateOAuthUser(service, bytes.NewReader(buf.Bytes()), teamId, tokenUser)
} else {
return nil, err
}
@@ -601,7 +619,7 @@ func (a *App) LoginByOAuth(service string, userData io.Reader, teamId string) (*
return nil, model.NewAppError("loginByOAuth", "api.user.login_by_oauth.bot_login_forbidden.app_error", nil, "", http.StatusForbidden)
}
if err = a.UpdateOAuthUserAttrs(bytes.NewReader(buf.Bytes()), user, provider, service); err != nil {
if err = a.UpdateOAuthUserAttrs(bytes.NewReader(buf.Bytes()), user, provider, service, tokenUser); err != nil {
return nil, err
}
if len(teamId) > 0 {
@@ -616,18 +634,17 @@ func (a *App) LoginByOAuth(service string, userData io.Reader, teamId string) (*
return user, nil
}
func (a *App) CompleteSwitchWithOAuth(service string, userData io.Reader, email string) (*model.User, *model.AppError) {
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)
func (a *App) CompleteSwitchWithOAuth(service string, userData io.Reader, email string, tokenUser *model.User) (*model.User, *model.AppError) {
provider, e := a.getSSOProvider(service)
if e != nil {
return nil, e
}
if email == "" {
return nil, model.NewAppError("CompleteSwitchWithOAuth", "api.user.complete_switch_with_oauth.blank_email.app_error", nil, "", http.StatusBadRequest)
}
ssoUser, err1 := provider.GetUserFromJson(userData)
ssoUser, err1 := provider.GetUserFromJson(userData, tokenUser)
if err1 != nil {
return nil, model.NewAppError("CompleteSwitchWithOAuth", "api.user.complete_switch_with_oauth.parse.app_error",
map[string]interface{}{"Service": service}, err1.Error(), http.StatusBadRequest)
@@ -696,9 +713,14 @@ func (a *App) GetOAuthStateToken(token string) (*model.Token, *model.AppError) {
}
func (a *App) GetAuthorizationCode(w http.ResponseWriter, r *http.Request, service string, props map[string]string, loginHint string) (string, *model.AppError) {
sso := a.Config().GetSSOService(service)
if sso == nil || !*sso.Enable {
return "", model.NewAppError("GetAuthorizationCode", "api.user.get_authorization_code.unsupported.app_error", nil, "service="+service, http.StatusNotImplemented)
provider, e := a.getSSOProvider(service)
if e != nil {
return "", e
}
sso, e2 := provider.GetSSOSettings(a.Config(), service)
if e2 != nil {
return "", model.NewAppError("GetAuthorizationCode.GetSSOSettings", "api.user.get_authorization_code.endpoint.app_error", nil, e.Error(), http.StatusNotImplemented)
}
secure := false
@@ -755,40 +777,44 @@ func (a *App) GetAuthorizationCode(w http.ResponseWriter, r *http.Request, servi
return authUrl, nil
}
func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service, code, state, redirectUri string) (io.ReadCloser, string, map[string]string, *model.AppError) {
sso := a.Config().GetSSOService(service)
if sso == nil || !*sso.Enable {
return nil, "", nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.unsupported.app_error", nil, "service="+service, http.StatusNotImplemented)
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) {
provider, e := a.getSSOProvider(service)
if e != nil {
return nil, "", nil, nil, e
}
sso, e2 := provider.GetSSOSettings(a.Config(), service)
if e2 != nil {
return nil, "", nil, nil, model.NewAppError("GetAuthorizationCode.GetSSOSettings", "api.user.get_authorization_code.endpoint.app_error", nil, e.Error(), http.StatusNotImplemented)
}
b, strErr := b64.StdEncoding.DecodeString(state)
if strErr != nil {
return nil, "", nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, strErr.Error(), http.StatusBadRequest)
return nil, "", nil, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, strErr.Error(), http.StatusBadRequest)
}
stateStr := string(b)
stateProps := model.MapFromJson(strings.NewReader(stateStr))
expectedToken, appErr := a.GetOAuthStateToken(stateProps["token"])
if appErr != nil {
return nil, "", stateProps, appErr
return nil, "", stateProps, nil, appErr
}
stateEmail := stateProps["email"]
stateAction := stateProps["action"]
if stateAction == model.OAUTH_ACTION_EMAIL_TO_SSO && stateEmail == "" {
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "", http.StatusBadRequest)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "", http.StatusBadRequest)
}
cookie, cookieErr := r.Cookie(COOKIE_OAUTH)
if cookieErr != nil {
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "", http.StatusBadRequest)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "", http.StatusBadRequest)
}
expectedTokenExtra := generateOAuthStateTokenExtra(stateEmail, stateAction, cookie.Value)
if expectedTokenExtra != expectedToken.Extra {
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "", http.StatusBadRequest)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "", http.StatusBadRequest)
}
appErr = a.DeleteToken(expectedToken)
@@ -819,7 +845,7 @@ func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service
req, requestErr := http.NewRequest("POST", *sso.TokenEndpoint, strings.NewReader(p.Encode()))
if requestErr != nil {
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, requestErr.Error(), http.StatusInternalServerError)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, requestErr.Error(), http.StatusInternalServerError)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
@@ -827,31 +853,39 @@ func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service
resp, err := a.HTTPService().MakeClient(true).Do(req)
if err != nil {
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, err.Error(), http.StatusInternalServerError)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, err.Error(), http.StatusInternalServerError)
}
defer resp.Body.Close()
var buf bytes.Buffer
tee := io.TeeReader(resp.Body, &buf)
ar := model.AccessResponseFromJson(tee)
if ar == nil || resp.StatusCode != http.StatusOK {
return nil, "", stateProps, 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)
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)
}
if strings.ToLower(ar.TokenType) != model.ACCESS_TOKEN_TYPE {
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.bad_token.app_error", nil, "token_type="+ar.TokenType+", response_body="+buf.String(), http.StatusInternalServerError)
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)
}
if len(ar.AccessToken) == 0 {
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.missing.app_error", nil, "response_body="+buf.String(), http.StatusInternalServerError)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.missing.app_error", nil, "response_body="+buf.String(), http.StatusInternalServerError)
}
p = url.Values{}
p.Set("access_token", ar.AccessToken)
var userFromToken *model.User
if ar.IdToken != "" {
userFromToken, err = provider.GetUserFromIdToken(ar.IdToken)
if err != nil {
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, e.Error(), http.StatusInternalServerError)
}
}
req, requestErr = http.NewRequest("GET", *sso.UserApiEndpoint, strings.NewReader(""))
if requestErr != nil {
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.service.app_error", map[string]interface{}{"Service": service}, requestErr.Error(), http.StatusInternalServerError)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.service.app_error", map[string]interface{}{"Service": service}, requestErr.Error(), http.StatusInternalServerError)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
@@ -860,7 +894,7 @@ func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service
resp, err = a.HTTPService().MakeClient(true).Do(req)
if err != nil {
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.service.app_error", map[string]interface{}{"Service": service}, err.Error(), http.StatusInternalServerError)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.service.app_error", map[string]interface{}{"Service": service}, err.Error(), http.StatusInternalServerError)
} else if resp.StatusCode != http.StatusOK {
defer resp.Body.Close()
@@ -868,18 +902,18 @@ func (a *App) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service
bodyBytes, _ := ioutil.ReadAll(resp.Body)
bodyString := string(bodyBytes)
mlog.Error("Error getting OAuth user", mlog.String("body_string", bodyString))
mlog.Error("Error getting OAuth user", mlog.Int("response", resp.StatusCode), mlog.String("body_string", bodyString))
if service == model.SERVICE_GITLAB && resp.StatusCode == http.StatusForbidden && strings.Contains(bodyString, "Terms of Service") {
// Return a nicer error when the user hasn't accepted GitLab's terms of service
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "oauth.gitlab.tos.error", nil, "", http.StatusBadRequest)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "oauth.gitlab.tos.error", nil, "", http.StatusBadRequest)
}
return nil, "", stateProps, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.response.app_error", nil, "response_body="+bodyString, http.StatusInternalServerError)
return nil, "", stateProps, nil, model.NewAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.response.app_error", nil, "response_body="+bodyString, http.StatusInternalServerError)
}
// Note that resp.Body is not closed here, so it must be closed by the caller
return resp.Body, teamId, stateProps, nil
return resp.Body, teamId, stateProps, userFromToken, nil
}
func (a *App) SwitchEmailToOAuth(w http.ResponseWriter, r *http.Request, email, password, code, service string) (string, *model.AppError) {

Просмотреть файл

@@ -191,7 +191,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
th := setup(t, false, true, true, "")
defer th.TearDown()
_, _, _, err := th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", "", "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", "", "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.unsupported.app_error", err.Id)
})
@@ -202,7 +202,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
state := "!"
_, _, _, err := th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.invalid_state.app_error", err.Id)
})
@@ -215,7 +215,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
"token": model.NewId(),
})))
_, _, _, err := th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.oauth.invalid_state_token.app_error", err.Id)
assert.NotEqual(t, "", err.DetailedError)
@@ -230,7 +230,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
state := makeState(token)
_, _, _, err := th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.oauth.invalid_state_token.app_error", err.Id)
assert.Equal(t, "", err.DetailedError)
@@ -253,7 +253,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
"token": token.Token,
})))
_, _, _, err = th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err = th.App.AuthorizeOAuthUser(nil, nil, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.invalid_state.app_error", err.Id)
})
@@ -266,7 +266,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, "")
state := makeState(makeToken(th, cookie))
_, _, _, err := th.App.AuthorizeOAuthUser(nil, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(nil, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.invalid_state.app_error", err.Id)
})
@@ -283,7 +283,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, cookie)
state := makeState(token)
_, _, _, err = th.App.AuthorizeOAuthUser(nil, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err = th.App.AuthorizeOAuthUser(nil, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.invalid_state.app_error", err.Id)
})
@@ -296,7 +296,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, cookie)
state := makeState(makeToken(th, cookie))
_, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.token_failed.app_error", err.Id)
})
@@ -314,7 +314,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, cookie)
state := makeState(makeToken(th, cookie))
_, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.bad_response.app_error", err.Id)
assert.Contains(t, err.DetailedError, "status_code=418")
@@ -333,7 +333,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, cookie)
state := makeState(makeToken(th, cookie))
_, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.bad_response.app_error", err.Id)
assert.Contains(t, err.DetailedError, "response_body=invalid")
@@ -355,7 +355,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, cookie)
state := makeState(makeToken(th, cookie))
_, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.bad_token.app_error", err.Id)
})
@@ -376,7 +376,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, cookie)
state := makeState(makeToken(th, cookie))
_, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.missing.app_error", err.Id)
})
@@ -397,7 +397,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, cookie)
state := makeState(makeToken(th, cookie))
_, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.service.app_error", err.Id)
})
@@ -425,7 +425,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, cookie)
state := makeState(makeToken(th, cookie))
_, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.authorize_oauth_user.response.app_error", err.Id)
})
@@ -454,7 +454,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
request := makeRequest(t, cookie)
state := makeState(makeToken(th, cookie))
_, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
_, _, _, _, err := th.App.AuthorizeOAuthUser(&httptest.ResponseRecorder{}, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, err)
assert.Equal(t, "oauth.gitlab.tos.error", err.Id)
})
@@ -504,7 +504,7 @@ func TestAuthorizeOAuthUser(t *testing.T) {
state := base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps)))
recorder := httptest.ResponseRecorder{}
body, receivedTeamId, receivedStateProps, err := th.App.AuthorizeOAuthUser(&recorder, request, model.SERVICE_GITLAB, "", state, "")
body, receivedTeamId, receivedStateProps, _, err := th.App.AuthorizeOAuthUser(&recorder, request, model.SERVICE_GITLAB, "", state, "")
require.NotNil(t, body)
bodyBytes, bodyErr := ioutil.ReadAll(body)
@@ -533,7 +533,8 @@ func TestGetAuthorizationCode(t *testing.T) {
_, err := th.App.GetAuthorizationCode(nil, nil, model.SERVICE_GITLAB, map[string]string{}, "")
require.NotNil(t, err)
assert.Equal(t, "api.user.get_authorization_code.unsupported.app_error", err.Id)
assert.Equal(t, "api.user.authorize_oauth_user.unsupported.app_error", err.Id)
})
t.Run("enabled and properly configured", func(t *testing.T) {

Просмотреть файл

@@ -687,7 +687,7 @@ func (a *OpenTracingAppLayer) AuthenticateUserForLogin(id string, loginId string
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service string, code string, state string, redirectUri string) (io.ReadCloser, string, map[string]string, *model.AppError) {
func (a *OpenTracingAppLayer) AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service string, code string, state string, redirectUri string) (io.ReadCloser, string, map[string]string, *model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AuthorizeOAuthUser")
@@ -699,14 +699,14 @@ func (a *OpenTracingAppLayer) AuthorizeOAuthUser(w http.ResponseWriter, r *http.
}()
defer span.Finish()
resultVar0, resultVar1, resultVar2, resultVar3 := a.app.AuthorizeOAuthUser(w, r, service, code, state, redirectUri)
resultVar0, resultVar1, resultVar2, resultVar3, resultVar4 := a.app.AuthorizeOAuthUser(w, r, service, code, state, redirectUri)
if resultVar3 != nil {
span.LogFields(spanlog.Error(resultVar3))
if resultVar4 != nil {
span.LogFields(spanlog.Error(resultVar4))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1, resultVar2, resultVar3
return resultVar0, resultVar1, resultVar2, resultVar3, resultVar4
}
func (a *OpenTracingAppLayer) AutocompleteChannels(teamId string, term string) (*model.ChannelList, *model.AppError) {
@@ -1427,7 +1427,7 @@ func (a *OpenTracingAppLayer) CompareAndSetPluginKey(pluginId string, key string
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) CompleteOAuth(service string, body io.ReadCloser, teamId string, props map[string]string) (*model.User, *model.AppError) {
func (a *OpenTracingAppLayer) CompleteOAuth(service string, body io.ReadCloser, teamId string, props map[string]string, tokenUser *model.User) (*model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CompleteOAuth")
@@ -1439,7 +1439,7 @@ func (a *OpenTracingAppLayer) CompleteOAuth(service string, body io.ReadCloser,
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.CompleteOAuth(service, body, teamId, props)
resultVar0, resultVar1 := a.app.CompleteOAuth(service, body, teamId, props, tokenUser)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
@@ -1449,7 +1449,7 @@ func (a *OpenTracingAppLayer) CompleteOAuth(service string, body io.ReadCloser,
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) CompleteSwitchWithOAuth(service string, userData io.Reader, email string) (*model.User, *model.AppError) {
func (a *OpenTracingAppLayer) CompleteSwitchWithOAuth(service string, userData io.Reader, email string, tokenUser *model.User) (*model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CompleteSwitchWithOAuth")
@@ -1461,7 +1461,7 @@ func (a *OpenTracingAppLayer) CompleteSwitchWithOAuth(service string, userData i
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.CompleteSwitchWithOAuth(service, userData, email)
resultVar0, resultVar1 := a.app.CompleteSwitchWithOAuth(service, userData, email, tokenUser)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
@@ -1932,7 +1932,7 @@ func (a *OpenTracingAppLayer) CreateOAuthStateToken(extra string) (*model.Token,
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) CreateOAuthUser(service string, userData io.Reader, teamId string) (*model.User, *model.AppError) {
func (a *OpenTracingAppLayer) CreateOAuthUser(service string, userData io.Reader, teamId string, tokenUser *model.User) (*model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateOAuthUser")
@@ -1944,7 +1944,7 @@ func (a *OpenTracingAppLayer) CreateOAuthUser(service string, userData io.Reader
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.CreateOAuthUser(service, userData, teamId)
resultVar0, resultVar1 := a.app.CreateOAuthUser(service, userData, teamId, tokenUser)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
@@ -10392,7 +10392,7 @@ func (a *OpenTracingAppLayer) LogAuditRecWithLevel(rec *audit.Record, level mlog
a.app.LogAuditRecWithLevel(rec, level, err)
}
func (a *OpenTracingAppLayer) LoginByOAuth(service string, userData io.Reader, teamId string) (*model.User, *model.AppError) {
func (a *OpenTracingAppLayer) LoginByOAuth(service string, userData io.Reader, teamId string, tokenUser *model.User) (*model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.LoginByOAuth")
@@ -10404,7 +10404,7 @@ func (a *OpenTracingAppLayer) LoginByOAuth(service string, userData io.Reader, t
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.LoginByOAuth(service, userData, teamId)
resultVar0, resultVar1 := a.app.LoginByOAuth(service, userData, teamId, tokenUser)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
@@ -14864,7 +14864,7 @@ func (a *OpenTracingAppLayer) UpdateMobileAppBadge(userId string) {
a.app.UpdateMobileAppBadge(userId)
}
func (a *OpenTracingAppLayer) UpdateOAuthUserAttrs(userData io.Reader, user *model.User, provider einterfaces.OauthProvider, service string) *model.AppError {
func (a *OpenTracingAppLayer) UpdateOAuthUserAttrs(userData io.Reader, user *model.User, provider einterfaces.OauthProvider, service string, tokenUser *model.User) *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateOAuthUserAttrs")
@@ -14876,7 +14876,7 @@ func (a *OpenTracingAppLayer) UpdateOAuthUserAttrs(userData io.Reader, user *mod
}()
defer span.Finish()
resultVar0 := a.app.UpdateOAuthUserAttrs(userData, user, provider, service)
resultVar0 := a.app.UpdateOAuthUserAttrs(userData, user, provider, service, tokenUser)
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))

Просмотреть файл

@@ -335,19 +335,22 @@ func (a *App) createUser(user *model.User) (*model.User, *model.AppError) {
return ruser, nil
}
func (a *App) CreateOAuthUser(service string, userData io.Reader, teamId string) (*model.User, *model.AppError) {
func (a *App) CreateOAuthUser(service string, userData io.Reader, teamId string, tokenUser *model.User) (*model.User, *model.AppError) {
if !*a.Config().TeamSettings.EnableUserCreation {
return nil, model.NewAppError("CreateOAuthUser", "api.user.create_user.disabled.app_error", nil, "", http.StatusNotImplemented)
}
provider := einterfaces.GetOauthProvider(service)
if provider == nil {
return nil, model.NewAppError("CreateOAuthUser", "api.user.create_oauth_user.not_available.app_error", map[string]interface{}{"Service": strings.Title(service)}, "", http.StatusNotImplemented)
provider, e := a.getSSOProvider(service)
if e != nil {
return nil, e
}
user, err1 := provider.GetUserFromJson(userData)
user, err1 := provider.GetUserFromJson(userData, tokenUser)
if err1 != nil {
return nil, model.NewAppError("CreateOAuthUser", "api.user.create_oauth_user.create.app_error", map[string]interface{}{"Service": service}, err1.Error(), http.StatusInternalServerError)
}
if user.AuthService == "" {
user.AuthService = service
}
suchan := make(chan store.StoreResult, 1)
euchan := make(chan store.StoreResult, 1)
@@ -1990,8 +1993,8 @@ func (a *App) AutocompleteUsersInTeam(teamId string, term string, options *model
return autocomplete, nil
}
func (a *App) UpdateOAuthUserAttrs(userData io.Reader, user *model.User, provider einterfaces.OauthProvider, service string) *model.AppError {
oauthUser, err1 := provider.GetUserFromJson(userData)
func (a *App) UpdateOAuthUserAttrs(userData io.Reader, user *model.User, provider einterfaces.OauthProvider, service string, tokenUser *model.User) *model.AppError {
oauthUser, err1 := provider.GetUserFromJson(userData, tokenUser)
if err1 != nil {
return model.NewAppError("UpdateOAuthUserAttrs", "api.user.update_oauth_user_attrs.get_user.app_error", map[string]interface{}{"Service": service}, err1.Error(), http.StatusBadRequest)
}

Просмотреть файл

@@ -76,10 +76,14 @@ func TestCreateOAuthUser(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.GitLabSettings.Enable = true
})
glUser := oauthgitlab.GitLabUser{Id: 42, Username: "o" + model.NewId(), Email: model.NewId() + "@simulator.amazonses.com", Name: "Joram Wilander"}
json := glUser.ToJson()
user, err := th.App.CreateOAuthUser(model.USER_AUTH_SERVICE_GITLAB, strings.NewReader(json), th.BasicTeam.Id)
user, err := th.App.CreateOAuthUser(model.USER_AUTH_SERVICE_GITLAB, strings.NewReader(json), th.BasicTeam.Id, nil)
require.Nil(t, err)
require.Equal(t, glUser.Username, user.Username, "usernames didn't match")
@@ -88,7 +92,7 @@ func TestCreateOAuthUser(t *testing.T) {
*th.App.Config().TeamSettings.EnableUserCreation = false
_, err = th.App.CreateOAuthUser(model.USER_AUTH_SERVICE_GITLAB, strings.NewReader(json), th.BasicTeam.Id)
_, err = th.App.CreateOAuthUser(model.USER_AUTH_SERVICE_GITLAB, strings.NewReader(json), th.BasicTeam.Id, nil)
require.NotNil(t, err, "should have failed - user creation disabled")
}
@@ -269,6 +273,9 @@ func TestUpdateOAuthUserAttrs(t *testing.T) {
id := model.NewId()
id2 := model.NewId()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.GitLabSettings.Enable = true
})
gitlabProvider := einterfaces.GetOauthProvider("gitlab")
username := "user" + id
@@ -289,7 +296,7 @@ func TestUpdateOAuthUserAttrs(t *testing.T) {
data := bytes.NewReader(gitlabUser)
user = getUserFromDB(th.App, user.Id, t)
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab")
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab", nil)
user = getUserFromDB(th.App, user.Id, t)
require.Equal(t, gitlabUserObj.Username, user.Username, "user's username is not updated")
@@ -302,7 +309,7 @@ func TestUpdateOAuthUserAttrs(t *testing.T) {
data := bytes.NewReader(gitlabUser)
user = getUserFromDB(th.App, user.Id, t)
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab")
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab", nil)
user = getUserFromDB(th.App, user.Id, t)
require.NotEqual(t, gitlabUserObj.Username, user.Username, "user's username is updated though there already exists another user with the same username")
@@ -316,7 +323,7 @@ func TestUpdateOAuthUserAttrs(t *testing.T) {
data := bytes.NewReader(gitlabUser)
user = getUserFromDB(th.App, user.Id, t)
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab")
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab", nil)
user = getUserFromDB(th.App, user.Id, t)
require.Equal(t, gitlabUserObj.Email, user.Email, "user's email is not updated")
@@ -331,7 +338,7 @@ func TestUpdateOAuthUserAttrs(t *testing.T) {
data := bytes.NewReader(gitlabUser)
user = getUserFromDB(th.App, user.Id, t)
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab")
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab", nil)
user = getUserFromDB(th.App, user.Id, t)
require.NotEqual(t, gitlabUserObj.Email, user.Email, "user's email is updated though there already exists another user with the same email")
@@ -344,7 +351,7 @@ func TestUpdateOAuthUserAttrs(t *testing.T) {
data := bytes.NewReader(gitlabUser)
user = getUserFromDB(th.App, user.Id, t)
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab")
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab", nil)
user = getUserFromDB(th.App, user.Id, t)
require.Equal(t, "Updated", user.FirstName, "user's first name is not updated")
@@ -356,7 +363,7 @@ func TestUpdateOAuthUserAttrs(t *testing.T) {
data := bytes.NewReader(gitlabUser)
user = getUserFromDB(th.App, user.Id, t)
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab")
th.App.UpdateOAuthUserAttrs(data, user, gitlabProvider, "gitlab", nil)
user = getUserFromDB(th.App, user.Id, t)
require.Equal(t, "Lastname", user.LastName, "user's last name is not updated")
@@ -532,7 +539,7 @@ func createGitlabUser(t *testing.T, a *App, id int64, username string, email str
var user *model.User
var err *model.AppError
user, err = a.CreateOAuthUser("gitlab", bytes.NewReader(gitlabUser), "")
user, err = a.CreateOAuthUser("gitlab", bytes.NewReader(gitlabUser), "", nil)
require.Nil(t, err, "unable to create the user", err)
return user, gitlabUserObj