Implement APIv4 infrastructure (#5191)
* Implement APIv4 infrastructure * Update parameter requirement functions per feedback
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
3e2f879b77
Коммит
c01d9ad6cf
@@ -67,7 +67,7 @@ func InitRouter() {
|
||||
func InitApi() {
|
||||
BaseRoutes = &Routes{}
|
||||
BaseRoutes.Root = app.Srv.Router
|
||||
BaseRoutes.ApiRoot = app.Srv.Router.PathPrefix(model.API_URL_SUFFIX).Subrouter()
|
||||
BaseRoutes.ApiRoot = app.Srv.Router.PathPrefix(model.API_URL_SUFFIX_V3).Subrouter()
|
||||
BaseRoutes.Users = BaseRoutes.ApiRoot.PathPrefix("/users").Subrouter()
|
||||
BaseRoutes.NeedUser = BaseRoutes.Users.PathPrefix("/{user_id:[A-Za-z0-9]+}").Subrouter()
|
||||
BaseRoutes.Teams = BaseRoutes.ApiRoot.PathPrefix("/teams").Subrouter()
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/mattermost/platform/app"
|
||||
"github.com/mattermost/platform/einterfaces"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func checkPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError {
|
||||
if err := checkUserAdditionalAuthenticationCriteria(user, mfaToken); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkUserPassword(user, password); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This to be used for places we check the users password when they are already logged in
|
||||
func doubleCheckPassword(user *model.User, password string) *model.AppError {
|
||||
if err := checkUserLoginAttempts(user); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkUserPassword(user, password); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkUserPassword(user *model.User, password string) *model.AppError {
|
||||
if !model.ComparePassword(user.Password, password) {
|
||||
if result := <-app.Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, user.FailedAttempts+1); result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
|
||||
return model.NewLocAppError("checkUserPassword", "api.user.check_user_password.invalid.app_error", nil, "user_id="+user.Id)
|
||||
} else {
|
||||
if result := <-app.Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, 0); result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func checkLdapUserPasswordAndAllCriteria(ldapId *string, password string, mfaToken string) (*model.User, *model.AppError) {
|
||||
ldapInterface := einterfaces.GetLdapInterface()
|
||||
|
||||
if ldapInterface == nil || ldapId == nil {
|
||||
err := model.NewLocAppError("doLdapAuthentication", "api.user.login_ldap.not_available.app_error", nil, "")
|
||||
err.StatusCode = http.StatusNotImplemented
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var user *model.User
|
||||
if ldapUser, err := ldapInterface.DoLogin(*ldapId, password); err != nil {
|
||||
err.StatusCode = http.StatusUnauthorized
|
||||
return nil, err
|
||||
} else {
|
||||
user = ldapUser
|
||||
}
|
||||
|
||||
if err := checkUserMfa(user, mfaToken); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := checkUserNotDisabled(user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// user successfully authenticated
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func checkUserAdditionalAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError {
|
||||
if err := checkUserMfa(user, mfaToken); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkEmailVerified(user); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkUserNotDisabled(user); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkUserLoginAttempts(user); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkUserMfa(user *model.User, token string) *model.AppError {
|
||||
if !user.MfaActive || !utils.IsLicensed || !*utils.License.Features.MFA || !*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication {
|
||||
return nil
|
||||
}
|
||||
|
||||
mfaInterface := einterfaces.GetMfaInterface()
|
||||
if mfaInterface == nil {
|
||||
return model.NewLocAppError("checkUserMfa", "api.user.check_user_mfa.not_available.app_error", nil, "")
|
||||
}
|
||||
|
||||
if ok, err := mfaInterface.ValidateToken(user.MfaSecret, token); err != nil {
|
||||
return err
|
||||
} else if !ok {
|
||||
return model.NewLocAppError("checkUserMfa", "api.user.check_user_mfa.bad_code.app_error", nil, "")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkUserLoginAttempts(user *model.User) *model.AppError {
|
||||
if user.FailedAttempts >= utils.Cfg.ServiceSettings.MaximumLoginAttempts {
|
||||
return model.NewLocAppError("checkUserLoginAttempts", "api.user.check_user_login_attempts.too_many.app_error", nil, "user_id="+user.Id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkEmailVerified(user *model.User) *model.AppError {
|
||||
if !user.EmailVerified && utils.Cfg.EmailSettings.RequireEmailVerification {
|
||||
return model.NewLocAppError("Login", "api.user.login.not_verified.app_error", nil, "user_id="+user.Id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkUserNotDisabled(user *model.User) *model.AppError {
|
||||
if user.DeleteAt > 0 {
|
||||
return model.NewLocAppError("Login", "api.user.login.inactive.app_error", nil, "user_id="+user.Id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func authenticateUser(user *model.User, password, mfaToken string) (*model.User, *model.AppError) {
|
||||
ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil && utils.IsLicensed && *utils.License.Features.LDAP
|
||||
|
||||
if user.AuthService == model.USER_AUTH_SERVICE_LDAP {
|
||||
if !ldapAvailable {
|
||||
err := model.NewLocAppError("login", "api.user.login_ldap.not_available.app_error", nil, "")
|
||||
err.StatusCode = http.StatusNotImplemented
|
||||
return user, err
|
||||
} else if ldapUser, err := checkLdapUserPasswordAndAllCriteria(user.AuthData, password, mfaToken); err != nil {
|
||||
err.StatusCode = http.StatusUnauthorized
|
||||
return user, err
|
||||
} else {
|
||||
// slightly redundant to get the user again, but we need to get it from the LDAP server
|
||||
return ldapUser, nil
|
||||
}
|
||||
} else if user.AuthService != "" {
|
||||
authService := user.AuthService
|
||||
if authService == model.USER_AUTH_SERVICE_SAML || authService == model.USER_AUTH_SERVICE_LDAP {
|
||||
authService = strings.ToUpper(authService)
|
||||
}
|
||||
err := model.NewLocAppError("login", "api.user.login.use_auth_service.app_error", map[string]interface{}{"AuthService": authService}, "")
|
||||
err.StatusCode = http.StatusBadRequest
|
||||
return user, err
|
||||
} else {
|
||||
if err := checkPasswordAndAllCriteria(user, password, mfaToken); err != nil {
|
||||
err.StatusCode = http.StatusUnauthorized
|
||||
return user, err
|
||||
} else {
|
||||
return user, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,7 +239,7 @@ func TestTestCommand(t *testing.T) {
|
||||
*utils.Cfg.ServiceSettings.EnableCommands = true
|
||||
|
||||
cmd1 := &model.Command{
|
||||
URL: "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX + "/teams/command_test",
|
||||
URL: "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V3 + "/teams/command_test",
|
||||
Method: model.COMMAND_METHOD_POST,
|
||||
Trigger: "test",
|
||||
}
|
||||
@@ -259,7 +259,7 @@ func TestTestCommand(t *testing.T) {
|
||||
}
|
||||
|
||||
cmd2 := &model.Command{
|
||||
URL: "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX + "/teams/command_test",
|
||||
URL: "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V3 + "/teams/command_test",
|
||||
Method: model.COMMAND_METHOD_GET,
|
||||
Trigger: "test2",
|
||||
}
|
||||
|
||||
@@ -21,17 +21,18 @@ import (
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
Session model.Session
|
||||
RequestId string
|
||||
IpAddress string
|
||||
Path string
|
||||
Err *model.AppError
|
||||
siteURL string
|
||||
teamURLValid bool
|
||||
teamURL string
|
||||
T goi18n.TranslateFunc
|
||||
Locale string
|
||||
TeamId string
|
||||
Session model.Session
|
||||
RequestId string
|
||||
IpAddress string
|
||||
Path string
|
||||
Err *model.AppError
|
||||
siteURL string
|
||||
teamURLValid bool
|
||||
teamURL string
|
||||
T goi18n.TranslateFunc
|
||||
Locale string
|
||||
TeamId string
|
||||
isSystemAdmin bool
|
||||
}
|
||||
|
||||
func ApiAppHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
|
||||
@@ -142,7 +143,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if utils.GetSiteURL() == "" {
|
||||
protocol := GetProtocol(r)
|
||||
protocol := app.GetProtocol(r)
|
||||
c.SetSiteURL(protocol + "://" + r.Host)
|
||||
} else {
|
||||
c.SetSiteURL(utils.GetSiteURL())
|
||||
@@ -251,21 +252,13 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if h.isApi && einterfaces.GetMetricsInterface() != nil {
|
||||
einterfaces.GetMetricsInterface().IncrementHttpRequest()
|
||||
|
||||
if r.URL.Path != model.API_URL_SUFFIX+"/users/websocket" {
|
||||
if r.URL.Path != model.API_URL_SUFFIX_V3+"/users/websocket" {
|
||||
elapsed := float64(time.Since(now)) / float64(time.Second)
|
||||
einterfaces.GetMetricsInterface().ObserveHttpRequestDuration(elapsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetProtocol(r *http.Request) string {
|
||||
if r.Header.Get(model.HEADER_FORWARDED_PROTO) == "https" {
|
||||
return "https"
|
||||
} else {
|
||||
return "http"
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) LogAudit(extraInfo string) {
|
||||
audit := &model.Audit{UserId: c.Session.UserId, IpAddress: c.IpAddress, Action: c.Path, ExtraInfo: extraInfo, SessionId: c.Session.Id}
|
||||
if r := <-app.Srv.Store.Audit().Save(audit); r.Err != nil {
|
||||
@@ -347,13 +340,17 @@ func (c *Context) SystemAdminRequired() {
|
||||
c.Err = model.NewLocAppError("", "api.context.session_expired.app_error", nil, "SystemAdminRequired")
|
||||
c.Err.StatusCode = http.StatusUnauthorized
|
||||
return
|
||||
} else if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
|
||||
} else if !c.IsSystemAdmin() {
|
||||
c.Err = model.NewLocAppError("", "api.context.permissions.app_error", nil, "AdminRequired")
|
||||
c.Err.StatusCode = http.StatusForbidden
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) IsSystemAdmin() bool {
|
||||
return app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM)
|
||||
}
|
||||
|
||||
func (c *Context) RemoveSessionCookie(w http.ResponseWriter, r *http.Request) {
|
||||
cookie := &http.Cookie{
|
||||
Name: model.SESSION_COOKIE_TOKEN,
|
||||
|
||||
@@ -406,6 +406,7 @@ func TestGetPublicFile(t *testing.T) {
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
if resp, err := http.Get(link); err != nil || resp.StatusCode != http.StatusOK {
|
||||
t.Log(link)
|
||||
t.Fatal("failed to get image with public link", err)
|
||||
}
|
||||
|
||||
@@ -509,7 +510,7 @@ func TestGetPublicFileOld(t *testing.T) {
|
||||
|
||||
func generatePublicLinkOld(siteURL, teamId, channelId, userId, filename string) string {
|
||||
hash := app.GeneratePublicLinkHash(filename, *utils.Cfg.FileSettings.PublicLinkSalt)
|
||||
return fmt.Sprintf("%s%s/public/files/get/%s/%s/%s/%s?h=%s", siteURL, model.API_URL_SUFFIX, teamId, channelId, userId, filename, hash)
|
||||
return fmt.Sprintf("%s%s/public/files/get/%s/%s/%s/%s?h=%s", siteURL, model.API_URL_SUFFIX_V3, teamId, channelId, userId, filename, hash)
|
||||
}
|
||||
|
||||
func TestGetPublicLink(t *testing.T) {
|
||||
|
||||
10
api/oauth.go
10
api/oauth.go
@@ -291,7 +291,7 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
doLogin(c, w, r, user, "")
|
||||
}
|
||||
if c.Err == nil {
|
||||
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, app.GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
|
||||
}
|
||||
break
|
||||
case model.OAUTH_ACTION_LOGIN:
|
||||
@@ -304,25 +304,25 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, c.GetSiteURL()+val, http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, app.GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
|
||||
}
|
||||
break
|
||||
case model.OAUTH_ACTION_EMAIL_TO_SSO:
|
||||
CompleteSwitchWithOAuth(c, w, r, service, body, props["email"])
|
||||
if c.Err == nil {
|
||||
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host+"/login?extra=signin_change", http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, app.GetProtocol(r)+"://"+r.Host+"/login?extra=signin_change", http.StatusTemporaryRedirect)
|
||||
}
|
||||
break
|
||||
case model.OAUTH_ACTION_SSO_TO_EMAIL:
|
||||
LoginByOAuth(c, w, r, service, body)
|
||||
if c.Err == nil {
|
||||
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host+"/claim?email="+url.QueryEscape(props["email"]), http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, app.GetProtocol(r)+"://"+r.Host+"/claim?email="+url.QueryEscape(props["email"]), http.StatusTemporaryRedirect)
|
||||
}
|
||||
break
|
||||
default:
|
||||
LoginByOAuth(c, w, r, service, body)
|
||||
if c.Err == nil {
|
||||
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, app.GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
229
api/user.go
229
api/user.go
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/store"
|
||||
"github.com/mattermost/platform/utils"
|
||||
"github.com/mssola/user_agent"
|
||||
)
|
||||
|
||||
func InitUser() {
|
||||
@@ -77,12 +76,6 @@ func InitUser() {
|
||||
}
|
||||
|
||||
func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if !utils.Cfg.EmailSettings.EnableSignUpWithEmail || !utils.Cfg.TeamSettings.EnableUserCreation {
|
||||
c.Err = model.NewLocAppError("createUser", "api.user.create_user.signup_email_disabled.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusNotImplemented
|
||||
return
|
||||
}
|
||||
|
||||
user := model.UserFromJson(r.Body)
|
||||
|
||||
if user == nil {
|
||||
@@ -90,45 +83,25 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
user.EmailVerified = false
|
||||
|
||||
hash := r.URL.Query().Get("h")
|
||||
inviteId := r.URL.Query().Get("iid")
|
||||
|
||||
var ruser *model.User
|
||||
var err *model.AppError
|
||||
if len(hash) > 0 {
|
||||
data := r.URL.Query().Get("d")
|
||||
ruser, err = app.CreateUserWithHash(user, hash, data)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
ruser, err = app.CreateUserWithHash(user, hash, r.URL.Query().Get("d"))
|
||||
} else if len(inviteId) > 0 {
|
||||
ruser, err = app.CreateUserWithInviteId(user, inviteId, c.GetSiteURL())
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !app.IsFirstUserAccount() && !*utils.Cfg.TeamSettings.EnableOpenServer {
|
||||
c.Err = model.NewLocAppError("createUser", "api.user.create_user.no_open_server", nil, "email="+user.Email)
|
||||
return
|
||||
}
|
||||
ruser, err = app.CreateUserFromSignup(user, c.GetSiteURL())
|
||||
}
|
||||
|
||||
ruser, err = app.CreateUser(user)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
if err := app.SendWelcomeEmail(ruser.Id, ruser.Email, ruser.EmailVerified, ruser.Locale, c.GetSiteURL()); err != nil {
|
||||
l4g.Error(err.Error())
|
||||
}
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(ruser.ToJson()))
|
||||
|
||||
}
|
||||
|
||||
func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
@@ -141,56 +114,15 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
deviceId := props["device_id"]
|
||||
ldapOnly := props["ldap_only"] == "true"
|
||||
|
||||
if len(password) == 0 {
|
||||
c.Err = model.NewLocAppError("login", "api.user.login.blank_pwd.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
return
|
||||
}
|
||||
|
||||
var user *model.User
|
||||
var err *model.AppError
|
||||
|
||||
if len(id) != 0 {
|
||||
c.LogAuditWithUserId(id, "attempt")
|
||||
|
||||
if user, err = app.GetUser(id); err != nil {
|
||||
c.LogAuditWithUserId(id, "failure")
|
||||
c.Err = err
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
if einterfaces.GetMetricsInterface() != nil {
|
||||
einterfaces.GetMetricsInterface().IncrementLoginFail()
|
||||
}
|
||||
return
|
||||
}
|
||||
} else {
|
||||
c.LogAudit("attempt")
|
||||
|
||||
if user, err = app.GetUserForLogin(loginId, ldapOnly); err != nil {
|
||||
c.LogAudit("failure")
|
||||
c.Err = err
|
||||
if einterfaces.GetMetricsInterface() != nil {
|
||||
einterfaces.GetMetricsInterface().IncrementLoginFail()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c.LogAuditWithUserId(user.Id, "attempt")
|
||||
}
|
||||
|
||||
// and then authenticate them
|
||||
if user, err = authenticateUser(user, password, mfaToken); err != nil {
|
||||
c.LogAuditWithUserId(user.Id, "failure")
|
||||
c.LogAudit("attempt - user_id=" + id + " login_id=" + loginId)
|
||||
user, err := app.AuthenticateUserForLogin(id, loginId, password, mfaToken, deviceId, ldapOnly)
|
||||
if err != nil {
|
||||
c.LogAudit("failure - user_id=" + id + " login_id=" + loginId)
|
||||
c.Err = err
|
||||
if einterfaces.GetMetricsInterface() != nil {
|
||||
einterfaces.GetMetricsInterface().IncrementLoginFail()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c.LogAuditWithUserId(user.Id, "success")
|
||||
if einterfaces.GetMetricsInterface() != nil {
|
||||
einterfaces.GetMetricsInterface().IncrementLogin()
|
||||
}
|
||||
|
||||
doLogin(c, w, r, user, deviceId)
|
||||
if c.Err != nil {
|
||||
@@ -244,77 +176,12 @@ func LoginByOAuth(c *Context, w http.ResponseWriter, r *http.Request, service st
|
||||
|
||||
// User MUST be authenticated completely before calling Login
|
||||
func doLogin(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) {
|
||||
|
||||
session := &model.Session{UserId: user.Id, Roles: user.GetRawRoles(), DeviceId: deviceId, IsOAuth: false}
|
||||
|
||||
maxAge := *utils.Cfg.ServiceSettings.SessionLengthWebInDays * 60 * 60 * 24
|
||||
|
||||
if len(deviceId) > 0 {
|
||||
session.SetExpireInDays(*utils.Cfg.ServiceSettings.SessionLengthMobileInDays)
|
||||
maxAge = *utils.Cfg.ServiceSettings.SessionLengthMobileInDays * 60 * 60 * 24
|
||||
|
||||
// A special case where we logout of all other sessions with the same Id
|
||||
if err := app.RevokeSessionsForDeviceId(user.Id, deviceId, ""); err != nil {
|
||||
c.Err = err
|
||||
c.Err.StatusCode = http.StatusInternalServerError
|
||||
return
|
||||
}
|
||||
} else {
|
||||
session.SetExpireInDays(*utils.Cfg.ServiceSettings.SessionLengthWebInDays)
|
||||
}
|
||||
|
||||
ua := user_agent.New(r.UserAgent())
|
||||
|
||||
plat := ua.Platform()
|
||||
if plat == "" {
|
||||
plat = "unknown"
|
||||
}
|
||||
|
||||
os := ua.OS()
|
||||
if os == "" {
|
||||
os = "unknown"
|
||||
}
|
||||
|
||||
bname, bversion := ua.Browser()
|
||||
if bname == "" {
|
||||
bname = "unknown"
|
||||
}
|
||||
|
||||
if bversion == "" {
|
||||
bversion = "0.0"
|
||||
}
|
||||
|
||||
session.AddProp(model.SESSION_PROP_PLATFORM, plat)
|
||||
session.AddProp(model.SESSION_PROP_OS, os)
|
||||
session.AddProp(model.SESSION_PROP_BROWSER, fmt.Sprintf("%v/%v", bname, bversion))
|
||||
|
||||
var err *model.AppError
|
||||
if session, err = app.CreateSession(session); err != nil {
|
||||
session, err := app.DoLogin(w, r, user, deviceId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
c.Err.StatusCode = http.StatusInternalServerError
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set(model.HEADER_TOKEN, session.Token)
|
||||
|
||||
secure := false
|
||||
if GetProtocol(r) == "https" {
|
||||
secure = true
|
||||
}
|
||||
|
||||
expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAge), 0)
|
||||
sessionCookie := &http.Cookie{
|
||||
Name: model.SESSION_COOKIE_TOKEN,
|
||||
Value: session.Token,
|
||||
Path: "/",
|
||||
MaxAge: maxAge,
|
||||
Expires: expiresAt,
|
||||
HttpOnly: true,
|
||||
Secure: secure,
|
||||
}
|
||||
|
||||
http.SetCookie(w, sessionCookie)
|
||||
|
||||
c.Session = *session
|
||||
}
|
||||
|
||||
@@ -357,7 +224,7 @@ func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
maxAge := *utils.Cfg.ServiceSettings.SessionLengthMobileInDays * 60 * 60 * 24
|
||||
|
||||
secure := false
|
||||
if GetProtocol(r) == "https" {
|
||||
if app.GetProtocol(r) == "https" {
|
||||
secure = true
|
||||
}
|
||||
|
||||
@@ -502,12 +369,15 @@ func getUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if user, err = app.GetUser(id); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
} else if HandleEtag(user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress), "Get User", w, r) {
|
||||
}
|
||||
|
||||
etag := user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress)
|
||||
|
||||
if HandleEtag(etag, "Get User", w, r) {
|
||||
return
|
||||
} else {
|
||||
sanitizeProfile(c, user)
|
||||
|
||||
w.Header().Set(model.HEADER_ETAG_SERVER, user.Etag(utils.Cfg.PrivacySettings.ShowFullName, utils.Cfg.PrivacySettings.ShowEmailAddress))
|
||||
app.SanitizeProfile(user, c.IsSystemAdmin())
|
||||
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
|
||||
w.Write([]byte(user.ToJson()))
|
||||
return
|
||||
}
|
||||
@@ -829,24 +699,11 @@ func updateUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if ruser, err := app.UpdateUser(user, c.GetSiteURL()); err != nil {
|
||||
if ruser, err := app.UpdateUserAsUser(user, c.GetSiteURL(), c.IsSystemAdmin()); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
} else {
|
||||
c.LogAudit("")
|
||||
|
||||
updatedUser := ruser
|
||||
updatedUser = sanitizeProfile(c, updatedUser)
|
||||
|
||||
omitUsers := make(map[string]bool, 1)
|
||||
omitUsers[user.Id] = true
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_USER_UPDATED, "", "", "", omitUsers)
|
||||
message.Add("user", updatedUser)
|
||||
go app.Publish(message)
|
||||
|
||||
ruser.Password = ""
|
||||
ruser.AuthData = new(string)
|
||||
*ruser.AuthData = ""
|
||||
w.Write([]byte(ruser.ToJson()))
|
||||
}
|
||||
}
|
||||
@@ -875,38 +732,8 @@ func updatePassword(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var user *model.User
|
||||
var err *model.AppError
|
||||
|
||||
if user, err = app.GetUser(userId); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
c.Err = model.NewLocAppError("updatePassword", "api.user.update_password.valid_account.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
return
|
||||
}
|
||||
|
||||
if user.AuthData != nil && *user.AuthData != "" {
|
||||
c.LogAudit("failed - tried to update user password who was logged in through oauth")
|
||||
c.Err = model.NewLocAppError("updatePassword", "api.user.update_password.oauth.app_error", nil, "auth_service="+user.AuthService)
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
return
|
||||
}
|
||||
|
||||
if err := doubleCheckPassword(user, currentPassword); err != nil {
|
||||
if err.Id == "api.user.check_user_password.invalid.app_error" {
|
||||
c.Err = model.NewLocAppError("updatePassword", "api.user.update_password.incorrect.app_error", nil, "")
|
||||
} else {
|
||||
c.Err = err
|
||||
}
|
||||
c.Err.StatusCode = http.StatusForbidden
|
||||
return
|
||||
}
|
||||
|
||||
if err := app.UpdatePasswordSendEmail(user, newPassword, c.T("api.user.update_password.menu"), c.GetSiteURL()); err != nil {
|
||||
if err := app.UpdatePasswordAsUser(userId, currentPassword, newPassword, c.GetSiteURL()); err != nil {
|
||||
c.LogAudit("failed")
|
||||
c.Err = err
|
||||
return
|
||||
} else {
|
||||
@@ -1110,7 +937,7 @@ func emailToOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := checkPasswordAndAllCriteria(user, password, mfaToken); err != nil {
|
||||
if err := app.CheckPasswordAndAllCriteria(user, password, mfaToken); err != nil {
|
||||
c.LogAuditWithUserId(user.Id, "failed - bad authentication")
|
||||
c.Err = err
|
||||
return
|
||||
@@ -1238,7 +1065,7 @@ func emailToLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := checkPasswordAndAllCriteria(user, emailPassword, token); err != nil {
|
||||
if err := app.CheckPasswordAndAllCriteria(user, emailPassword, token); err != nil {
|
||||
c.LogAuditWithUserId(user.Id, "failed - bad authentication")
|
||||
c.Err = err
|
||||
return
|
||||
@@ -1332,7 +1159,7 @@ func ldapToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := checkUserMfa(user, token); err != nil {
|
||||
if err := app.CheckUserMfa(user, token); err != nil {
|
||||
c.LogAuditWithUserId(user.Id, "fail - mfa token failed")
|
||||
c.Err = err
|
||||
return
|
||||
@@ -1600,7 +1427,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.Err.StatusCode = http.StatusFound
|
||||
return
|
||||
} else {
|
||||
if err := checkUserAdditionalAuthenticationCriteria(user, ""); err != nil {
|
||||
if err := app.CheckUserAdditionalAuthenticationCriteria(user, ""); err != nil {
|
||||
c.Err = err
|
||||
c.Err.StatusCode = http.StatusFound
|
||||
return
|
||||
@@ -1635,7 +1462,7 @@ func completeSaml(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, c.GetSiteURL()+val, http.StatusFound)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusFound)
|
||||
http.Redirect(w, r, app.GetProtocol(r)+"://"+r.Host, http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -634,7 +634,7 @@ func TestGetAudits(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
|
||||
if len(result.Data.(model.Audits)) != 2 {
|
||||
if len(result.Data.(model.Audits)) != 1 {
|
||||
t.Fatal(result.Data.(model.Audits))
|
||||
}
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user