diff options
author | Joram Wilander <jwawilander@gmail.com> | 2017-04-10 08:19:49 -0400 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2017-04-10 08:19:49 -0400 |
commit | dfc6db737411bd4ad68a803be5182f06055a1769 (patch) | |
tree | 375d93b8d1d8b1384988dc708c9f337e0ea2366c /api | |
parent | 7b77bcf87e85330a1f7f0b2a2dcbf71326bf2fba (diff) | |
download | chat-dfc6db737411bd4ad68a803be5182f06055a1769.tar.gz chat-dfc6db737411bd4ad68a803be5182f06055a1769.tar.bz2 chat-dfc6db737411bd4ad68a803be5182f06055a1769.zip |
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
Diffstat (limited to 'api')
-rw-r--r-- | api/oauth.go | 114 | ||||
-rw-r--r-- | api/user.go | 168 |
2 files changed, 16 insertions, 266 deletions
diff --git a/api/oauth.go b/api/oauth.go index 4a71500c4..059cac29b 100644 --- a/api/oauth.go +++ b/api/oauth.go @@ -4,8 +4,6 @@ package api import ( - "crypto/tls" - b64 "encoding/base64" "fmt" "io" "io/ioutil" @@ -273,7 +271,7 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) { uri := c.GetSiteURLHeader() + "/signup/" + service + "/complete" - if body, teamId, props, err := AuthorizeOAuthUser(service, code, state, uri); err != nil { + if body, teamId, props, err := app.AuthorizeOAuthUser(service, code, state, uri); err != nil { c.Err = err return } else { @@ -620,7 +618,7 @@ func loginWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) { stateProps["redirect_to"] = redirectTo } - if authUrl, err := GetAuthorizationCode(c, service, stateProps, loginHint); err != nil { + if authUrl, err := app.GetAuthorizationCode(service, stateProps, loginHint); err != nil { c.Err = err return } else { @@ -680,7 +678,7 @@ func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) { stateProps["team_id"] = teamId } - if authUrl, err := GetAuthorizationCode(c, service, stateProps, ""); err != nil { + if authUrl, err := app.GetAuthorizationCode(service, stateProps, ""); err != nil { c.Err = err return } else { @@ -688,112 +686,6 @@ func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) { } } -func GetAuthorizationCode(c *Context, 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 := c.GetSiteURLHeader() + "/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 CompleteSwitchWithOAuth(c *Context, w http.ResponseWriter, r *http.Request, service string, userData io.ReadCloser, email string) { authData := "" ssoEmail := "" diff --git a/api/user.go b/api/user.go index 7f422b355..99f751ee0 100644 --- a/api/user.go +++ b/api/user.go @@ -914,41 +914,14 @@ func emailToOAuth(c *Context, w http.ResponseWriter, r *http.Request) { return } - c.LogAudit("attempt") - - var user *model.User - var err *model.AppError - if user, err = app.GetUserByEmail(email); err != nil { - c.LogAudit("fail - couldn't get user") - c.Err = err - return - } - - if err := app.CheckPasswordAndAllCriteria(user, password, mfaToken); err != nil { - c.LogAuditWithUserId(user.Id, "failed - bad authentication") + link, err := app.SwitchEmailToOAuth(email, password, mfaToken, service) + if err != nil { c.Err = err return } - stateProps := map[string]string{} - stateProps["action"] = model.OAUTH_ACTION_EMAIL_TO_SSO - stateProps["email"] = email - - m := map[string]string{} - if service == model.USER_AUTH_SERVICE_SAML { - m["follow_link"] = c.GetSiteURLHeader() + "/login/sso/saml?action=" + model.OAUTH_ACTION_EMAIL_TO_SSO + "&email=" + email - } else { - if authUrl, err := GetAuthorizationCode(c, service, stateProps, ""); err != nil { - c.LogAuditWithUserId(user.Id, "fail - oauth issue") - c.Err = err - return - } else { - m["follow_link"] = authUrl - } - } - - c.LogAuditWithUserId(user.Id, "success") - w.Write([]byte(model.MapToJson(m))) + c.LogAudit("success for email=" + email) + w.Write([]byte(model.MapToJson(map[string]string{"follow_link": link}))) } func oauthToEmail(c *Context, w http.ResponseWriter, r *http.Request) { @@ -966,51 +939,19 @@ func oauthToEmail(c *Context, w http.ResponseWriter, r *http.Request) { return } - c.LogAudit("attempt") - - var user *model.User - var err *model.AppError - if user, err = app.GetUserByEmail(email); err != nil { - c.LogAudit("fail - couldn't get user") - c.Err = err - return - } - - if user.Id != c.Session.UserId { - c.LogAudit("fail - user ids didn't match") - c.Err = model.NewLocAppError("oauthToEmail", "api.user.oauth_to_email.context.app_error", nil, "") - c.Err.StatusCode = http.StatusForbidden - return - } - - if err := app.UpdatePassword(user, password); err != nil { - c.LogAudit("fail - database issue") - c.Err = err - return - } - - go func() { - if err := app.SendSignInChangeEmail(user.Email, c.T("api.templates.signin_change_email.body.method_email"), user.Locale, utils.GetSiteURL()); err != nil { - l4g.Error(err.Error()) - } - }() - - if err := app.RevokeAllSessions(c.Session.UserId); err != nil { + link, err := app.SwitchOAuthToEmail(email, password, c.Session.UserId) + if err != nil { c.Err = err return } - c.LogAuditWithUserId(c.Session.UserId, "Revoked all sessions for user") c.RemoveSessionCookie(w, r) if c.Err != nil { return } - m := map[string]string{} - m["follow_link"] = "/login?extra=signin_change" - c.LogAudit("success") - w.Write([]byte(model.MapToJson(m))) + w.Write([]byte(model.MapToJson(map[string]string{"follow_link": link}))) } func emailToLdap(c *Context, w http.ResponseWriter, r *http.Request) { @@ -1044,55 +985,19 @@ func emailToLdap(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("attempt") - var user *model.User - var err *model.AppError - if user, err = app.GetUserByEmail(email); err != nil { - c.LogAudit("fail - couldn't get user") - c.Err = err - return - } - - if err := app.CheckPasswordAndAllCriteria(user, emailPassword, token); err != nil { - c.LogAuditWithUserId(user.Id, "failed - bad authentication") - c.Err = err - return - } - - if err := app.RevokeAllSessions(user.Id); err != nil { + link, err := app.SwitchEmailToLdap(email, emailPassword, token, ldapId, ldapPassword) + if err != nil { c.Err = err return } - c.LogAuditWithUserId(user.Id, "Revoked all sessions for user") c.RemoveSessionCookie(w, r) if c.Err != nil { return } - ldapInterface := einterfaces.GetLdapInterface() - if ldapInterface == nil { - c.Err = model.NewLocAppError("emailToLdap", "api.user.email_to_ldap.not_available.app_error", nil, "") - c.Err.StatusCode = http.StatusNotImplemented - return - } - - if err := ldapInterface.SwitchToLdap(user.Id, ldapId, ldapPassword); err != nil { - c.LogAuditWithUserId(user.Id, "fail - ldap switch failed") - c.Err = err - return - } - - go func() { - if err := app.SendSignInChangeEmail(user.Email, "AD/LDAP", user.Locale, utils.GetSiteURL()); err != nil { - l4g.Error(err.Error()) - } - }() - - m := map[string]string{} - m["follow_link"] = "/login?extra=signin_change" - c.LogAudit("success") - w.Write([]byte(model.MapToJson(m))) + w.Write([]byte(model.MapToJson(map[string]string{"follow_link": link}))) } func ldapToEmail(c *Context, w http.ResponseWriter, r *http.Request) { @@ -1120,66 +1025,19 @@ func ldapToEmail(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAudit("attempt") - var user *model.User - var err *model.AppError - if user, err = app.GetUserByEmail(email); err != nil { - c.LogAudit("fail - couldn't get user") - c.Err = err - return - } - - if user.AuthService != model.USER_AUTH_SERVICE_LDAP { - c.Err = model.NewLocAppError("ldapToEmail", "api.user.ldap_to_email.not_ldap_account.app_error", nil, "") - return - } - - ldapInterface := einterfaces.GetLdapInterface() - if ldapInterface == nil || user.AuthData == nil { - c.Err = model.NewLocAppError("ldapToEmail", "api.user.ldap_to_email.not_available.app_error", nil, "") - c.Err.StatusCode = http.StatusNotImplemented - return - } - - if err := ldapInterface.CheckPassword(*user.AuthData, ldapPassword); err != nil { - c.LogAuditWithUserId(user.Id, "fail - ldap authentication failed") - c.Err = err - return - } - - if err := app.CheckUserMfa(user, token); err != nil { - c.LogAuditWithUserId(user.Id, "fail - mfa token failed") - c.Err = err - return - } - - if err := app.UpdatePassword(user, emailPassword); err != nil { - c.LogAudit("fail - database issue") - c.Err = err - return - } - - if err := app.RevokeAllSessions(user.Id); err != nil { + link, err := app.SwitchLdapToEmail(ldapPassword, token, email, emailPassword) + if err != nil { c.Err = err return } - c.LogAuditWithUserId(user.Id, "Revoked all sessions for user") c.RemoveSessionCookie(w, r) if c.Err != nil { return } - go func() { - if err := app.SendSignInChangeEmail(user.Email, c.T("api.templates.signin_change_email.body.method_email"), user.Locale, utils.GetSiteURL()); err != nil { - l4g.Error(err.Error()) - } - }() - - m := map[string]string{} - m["follow_link"] = "/login?extra=signin_change" - c.LogAudit("success") - w.Write([]byte(model.MapToJson(m))) + w.Write([]byte(model.MapToJson(map[string]string{"follow_link": link}))) } func verifyEmail(c *Context, w http.ResponseWriter, r *http.Request) { |