PLT-2258 Unified login screen and related APIs (#2820)
* Unified login screen and related APIs * Refactored login API call to be less convoluted * Removed LDAP login prompt from invite process * Fixed existing LDAP users being able to log in if LDAP was configured, but disabled * Gofmt * Future proofed login API * Updated login APIs based on feedback * Added additional auditing to login API * Actually removed loginById
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
e76a30bca0
Коммит
87989b8afd
@@ -200,19 +200,19 @@ func (me *TestHelper) CreatePost(client *model.Client, channel *model.Channel) *
|
||||
|
||||
func (me *TestHelper) LoginBasic() {
|
||||
utils.DisableDebugLogForTest()
|
||||
me.BasicClient.Must(me.BasicClient.LoginByEmail(me.BasicTeam.Name, me.BasicUser.Email, me.BasicUser.Password))
|
||||
me.BasicClient.Must(me.BasicClient.Login(me.BasicUser.Email, me.BasicUser.Password))
|
||||
utils.EnableDebugLogForTest()
|
||||
}
|
||||
|
||||
func (me *TestHelper) LoginBasic2() {
|
||||
utils.DisableDebugLogForTest()
|
||||
me.BasicClient.Must(me.BasicClient.LoginByEmail(me.BasicTeam.Name, me.BasicUser2.Email, me.BasicUser2.Password))
|
||||
me.BasicClient.Must(me.BasicClient.Login(me.BasicUser2.Email, me.BasicUser2.Password))
|
||||
utils.EnableDebugLogForTest()
|
||||
}
|
||||
|
||||
func (me *TestHelper) LoginSystemAdmin() {
|
||||
utils.DisableDebugLogForTest()
|
||||
me.SystemAdminClient.Must(me.SystemAdminClient.LoginByEmail(me.SystemAdminTeam.Name, me.SystemAdminUser.Email, me.SystemAdminUser.Password))
|
||||
me.SystemAdminClient.Must(me.SystemAdminClient.Login(me.SystemAdminUser.Email, me.SystemAdminUser.Password))
|
||||
utils.EnableDebugLogForTest()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"github.com/mattermost/platform/einterfaces"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func checkPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError {
|
||||
@@ -37,6 +39,32 @@ func checkUserPassword(user *model.User, password string) *model.AppError {
|
||||
}
|
||||
}
|
||||
|
||||
func checkLdapUserPasswordAndAllCriteria(ldapId, password, mfaToken string) (*model.User, *model.AppError) {
|
||||
ldapInterface := einterfaces.GetLdapInterface()
|
||||
|
||||
if ldapInterface == 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 := checkUserAdditionalAuthenticationCriteria(user, mfaToken); err != nil {
|
||||
err.StatusCode = http.StatusUnauthorized
|
||||
return user, 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
|
||||
@@ -97,3 +125,32 @@ func checkUserNotDisabled(user *model.User) *model.AppError {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func authenticateUser(user *model.User, password, mfaToken string) (*model.User, *model.AppError) {
|
||||
ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil
|
||||
|
||||
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 != "" {
|
||||
err := model.NewLocAppError("login", "api.user.login.use_auth_service.app_error", map[string]interface{}{"AuthService": user.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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ func BenchmarkJoinChannel(b *testing.B) {
|
||||
user = th.BasicClient.Must(th.BasicClient.CreateUser(user, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user, th.BasicTeam)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
th.BasicClient.LoginByEmail(th.BasicTeam.Name, user.Email, "pwd")
|
||||
th.BasicClient.Login(user.Email, "pwd")
|
||||
|
||||
// Benchmark Start
|
||||
b.ResetTimer()
|
||||
|
||||
@@ -169,7 +169,7 @@ func TestUpdateChannel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user2.Email, user2.Password)
|
||||
Client.Login(user2.Email, user2.Password)
|
||||
|
||||
if _, err := Client.UpdateChannel(upChannel1); err == nil {
|
||||
t.Fatal("Standard User should have failed to update")
|
||||
@@ -432,7 +432,7 @@ func TestJoinChannelById(t *testing.T) {
|
||||
|
||||
user3 := th.CreateUser(th.BasicClient)
|
||||
LinkUserToTeam(user3, team)
|
||||
Client.LoginByEmail(team.Name, user3.Email, "pwd")
|
||||
Client.Login(user3.Email, "pwd")
|
||||
|
||||
if _, err := Client.JoinChannel(rchannel.Id); err == nil {
|
||||
t.Fatal("shoudn't be able to join direct channel")
|
||||
@@ -462,7 +462,7 @@ func TestJoinChannelByName(t *testing.T) {
|
||||
|
||||
user3 := th.CreateUser(th.BasicClient)
|
||||
LinkUserToTeam(user3, team)
|
||||
Client.LoginByEmail(team.Name, user3.Email, "pwd")
|
||||
Client.Login(user3.Email, "pwd")
|
||||
|
||||
if _, err := Client.JoinChannelByName(rchannel.Name); err == nil {
|
||||
t.Fatal("shoudn't be able to join direct channel")
|
||||
@@ -518,7 +518,7 @@ func TestDeleteChannel(t *testing.T) {
|
||||
|
||||
Client.AddChannelMember(channelMadeByCA.Id, userTeamAdmin.Id)
|
||||
|
||||
Client.LoginByEmail(team.Name, userTeamAdmin.Email, "pwd")
|
||||
Client.Login(userTeamAdmin.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -541,7 +541,7 @@ func TestDeleteChannel(t *testing.T) {
|
||||
|
||||
userStd := th.CreateUser(th.BasicClient)
|
||||
LinkUserToTeam(userStd, team)
|
||||
Client.LoginByEmail(team.Name, userStd.Email, userStd.Password)
|
||||
Client.Login(userStd.Email, userStd.Password)
|
||||
|
||||
if _, err := Client.JoinChannel(channel1.Id); err == nil {
|
||||
t.Fatal("should have failed to join deleted channel")
|
||||
@@ -606,7 +606,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
Client2.SetTeamId(team.Id)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client2.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
Client2.Login(user2.Email, "pwd")
|
||||
Client2.Must(Client2.JoinChannel(channel1.Id))
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, -1, currentEtag); err != nil {
|
||||
@@ -775,7 +775,7 @@ func TestRemoveChannelMember(t *testing.T) {
|
||||
channel2 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
|
||||
|
||||
Client.LoginByEmail(team.Name, userStd.Email, userStd.Password)
|
||||
Client.Login(userStd.Email, userStd.Password)
|
||||
|
||||
if _, err := Client.RemoveChannelMember(channel2.Id, userStd.Id); err == nil {
|
||||
t.Fatal("Should have errored, user not channel admin")
|
||||
|
||||
@@ -164,7 +164,7 @@ func (me *LoadTestProvider) SetupCommand(c *Context, channelId string, message s
|
||||
if err := CreateBasicUser(client); err != nil {
|
||||
return &model.CommandResponse{Text: "Failed to create testing environment", ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
client.LoginByEmail(BTEST_TEAM_NAME, BTEST_USER_EMAIL, BTEST_USER_PASSWORD)
|
||||
client.Login(BTEST_USER_EMAIL, BTEST_USER_PASSWORD)
|
||||
environment, err := CreateTestEnvironmentWithTeams(
|
||||
client,
|
||||
utils.Range{numTeams, numTeams},
|
||||
|
||||
@@ -217,7 +217,7 @@ func TestGetFile(t *testing.T) {
|
||||
data := model.MapToJson(newProps)
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt))
|
||||
|
||||
Client.LoginByEmail(team2.Name, user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.SetTeamId(team2.Id)
|
||||
|
||||
if _, downErr := Client.GetFile(filenames[0]+"?d="+url.QueryEscape(data)+"&h="+url.QueryEscape(hash)+"&t="+team.Id, false); downErr != nil {
|
||||
|
||||
@@ -91,7 +91,7 @@ func TestCreatePost(t *testing.T) {
|
||||
t.Fatal("Should have been forbidden")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team2.Name, user3.Email, user3.Password)
|
||||
Client.Login(user3.Email, user3.Password)
|
||||
Client.SetTeamId(team2.Id)
|
||||
channel3 := th.CreateChannel(Client, team2)
|
||||
|
||||
@@ -512,7 +512,7 @@ func TestSearchPostsFromUser(t *testing.T) {
|
||||
t.Fatalf("wrong number of posts returned %v", len(result.Order))
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user3.Email, user3.Password)
|
||||
Client.Login(user3.Email, user3.Password)
|
||||
|
||||
// wait for the join/leave messages to be created for user3 since they're done asynchronously
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
@@ -741,7 +741,7 @@ func TestGetOutOfChannelMentions(t *testing.T) {
|
||||
user4 := th.CreateUser(Client)
|
||||
LinkUserToTeam(user4, team2)
|
||||
|
||||
Client.Must(Client.LoginByEmail(team2.Name, user4.Email, user4.Password))
|
||||
Client.Must(Client.Login(user4.Email, user4.Password))
|
||||
Client.SetTeamId(team2.Id)
|
||||
|
||||
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team2.Id}
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestCreateTeam(t *testing.T) {
|
||||
LinkUserToTeam(user, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(rteam.Data.(*model.Team).Id)
|
||||
|
||||
c1 := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
|
||||
@@ -209,7 +209,7 @@ func TestAddUserToTeamFromInvite(t *testing.T) {
|
||||
|
||||
user2 := th.CreateUser(th.BasicClient)
|
||||
Client.Must(Client.Logout())
|
||||
Client.Must(Client.LoginByEmail("", user2.Email, user2.Password))
|
||||
Client.Must(Client.Login(user2.Email, user2.Password))
|
||||
|
||||
if result, err := th.BasicClient.AddUserToTeamFromInvite("", "", rteam.InviteId); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -234,7 +234,7 @@ func TestGetAllTeams(t *testing.T) {
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if r1, err := Client.GetAllTeams(); err != nil {
|
||||
@@ -254,7 +254,7 @@ func TestGetAllTeams(t *testing.T) {
|
||||
c.IpAddress = "cmd_line"
|
||||
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if r1, err := Client.GetAllTeams(); err != nil {
|
||||
@@ -283,7 +283,7 @@ func TestGetAllTeamListings(t *testing.T) {
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if r1, err := Client.GetAllTeamListings(); err != nil {
|
||||
@@ -303,7 +303,7 @@ func TestGetAllTeamListings(t *testing.T) {
|
||||
c.IpAddress = "cmd_line"
|
||||
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if r1, err := Client.GetAllTeams(); err != nil {
|
||||
@@ -332,7 +332,7 @@ func TestTeamPermDelete(t *testing.T) {
|
||||
LinkUserToTeam(user1, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
Client.Login(user1.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
@@ -375,7 +375,7 @@ func TestInviteMembers(t *testing.T) {
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
invite := make(map[string]string)
|
||||
@@ -413,7 +413,7 @@ func TestUpdateTeamDisplayName(t *testing.T) {
|
||||
LinkUserToTeam(user2, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
vteam := &model.Team{DisplayName: team.DisplayName, Name: team.Name, Email: team.Email, Type: team.Type}
|
||||
@@ -422,7 +422,7 @@ func TestUpdateTeamDisplayName(t *testing.T) {
|
||||
t.Fatal("Should have errored, not admin")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
|
||||
vteam.DisplayName = ""
|
||||
if _, err := Client.UpdateTeam(vteam); err == nil {
|
||||
@@ -474,7 +474,7 @@ func TestGetMyTeam(t *testing.T) {
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.Login(user.Email, user.Password)
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if result, err := Client.GetMyTeam(""); err != nil {
|
||||
|
||||
254
api/user.go
254
api/user.go
@@ -45,7 +45,6 @@ func InitUser() {
|
||||
BaseRoutes.Users.Handle("/reset_password", ApiAppHandler(resetPassword)).Methods("POST")
|
||||
BaseRoutes.Users.Handle("/login", ApiAppHandler(login)).Methods("POST")
|
||||
BaseRoutes.Users.Handle("/logout", ApiAppHandler(logout)).Methods("POST")
|
||||
BaseRoutes.Users.Handle("/login_ldap", ApiAppHandler(loginLdap)).Methods("POST")
|
||||
BaseRoutes.Users.Handle("/revoke_session", ApiUserRequired(revokeSession)).Methods("POST")
|
||||
BaseRoutes.Users.Handle("/attach_device", ApiUserRequired(attachDeviceId)).Methods("POST")
|
||||
BaseRoutes.Users.Handle("/verify_email", ApiAppHandler(verifyEmail)).Methods("POST")
|
||||
@@ -333,7 +332,7 @@ func CreateOAuthUser(c *Context, w http.ResponseWriter, r *http.Request, service
|
||||
}
|
||||
}
|
||||
|
||||
Login(c, w, r, ruser, "")
|
||||
doLogin(c, w, r, ruser, "")
|
||||
if c.Err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -431,116 +430,88 @@ func SendVerifyEmailAndForget(c *Context, userId, userEmail, siteURL string) {
|
||||
func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
if len(props["password"]) == 0 {
|
||||
id := props["id"]
|
||||
loginId := props["login_id"]
|
||||
password := props["password"]
|
||||
mfaToken := props["token"]
|
||||
deviceId := props["device_id"]
|
||||
|
||||
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
|
||||
if len(props["id"]) != 0 {
|
||||
user = LoginById(c, w, r, props["id"], props["password"], props["token"], props["device_id"])
|
||||
} else if len(props["email"]) != 0 {
|
||||
user = LoginByEmail(c, w, r, props["email"], props["name"], props["password"], props["token"], props["device_id"])
|
||||
} else if len(props["username"]) != 0 {
|
||||
user = LoginByUsername(c, w, r, props["username"], props["name"], props["password"], props["token"], props["device_id"])
|
||||
var err *model.AppError
|
||||
|
||||
if len(id) != 0 {
|
||||
c.LogAuditWithUserId(id, "attempt")
|
||||
|
||||
if result := <-Srv.Store.User().Get(id); result.Err != nil {
|
||||
c.LogAuditWithUserId(user.Id, "failure")
|
||||
c.Err = result.Err
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
return
|
||||
} else {
|
||||
user = result.Data.(*model.User)
|
||||
}
|
||||
} else {
|
||||
c.Err = model.NewLocAppError("login", "api.user.login.not_provided.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
c.LogAudit("attempt")
|
||||
|
||||
if user, err = getUserForLogin(loginId); err != nil {
|
||||
c.LogAudit("failure")
|
||||
c.Err = err
|
||||
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.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
c.LogAuditWithUserId(user.Id, "success")
|
||||
|
||||
doLogin(c, w, r, user, deviceId)
|
||||
|
||||
user.Sanitize(map[string]bool{})
|
||||
|
||||
if user != nil {
|
||||
user.Sanitize(map[string]bool{})
|
||||
} else {
|
||||
user = &model.User{}
|
||||
}
|
||||
w.Write([]byte(user.ToJson()))
|
||||
}
|
||||
|
||||
func doUserPasswordAuthenticationAndLogin(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, password string, mfaToken string, deviceId string) bool {
|
||||
c.LogAuditWithUserId(user.Id, "attempt")
|
||||
if err := checkPasswordAndAllCriteria(user, password, mfaToken); err != nil {
|
||||
c.LogAuditWithUserId(user.Id, "fail")
|
||||
c.Err = err
|
||||
c.Err.StatusCode = http.StatusUnauthorized
|
||||
return false
|
||||
func getUserForLogin(loginId string) (*model.User, *model.AppError) {
|
||||
ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil
|
||||
|
||||
if result := <-Srv.Store.User().GetForLogin(
|
||||
loginId,
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithUsername,
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithEmail,
|
||||
ldapAvailable,
|
||||
); result.Err != nil {
|
||||
|
||||
if !ldapAvailable {
|
||||
// failed to find user and no LDAP server to fall back on
|
||||
result.Err.StatusCode = http.StatusBadRequest
|
||||
return nil, result.Err
|
||||
}
|
||||
|
||||
// fall back to LDAP server to see if we can find a user
|
||||
if ldapUser, ldapErr := einterfaces.GetLdapInterface().GetUser(loginId); ldapErr != nil {
|
||||
ldapErr.StatusCode = http.StatusBadRequest
|
||||
return nil, ldapErr
|
||||
} else {
|
||||
return ldapUser, nil
|
||||
}
|
||||
} else {
|
||||
Login(c, w, r, user, deviceId)
|
||||
c.LogAuditWithUserId(user.Id, "success")
|
||||
return true
|
||||
return result.Data.(*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func LoginById(c *Context, w http.ResponseWriter, r *http.Request, userId, password, mfaToken, deviceId string) *model.User {
|
||||
if result := <-Srv.Store.User().Get(userId); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
return nil
|
||||
} else {
|
||||
user := result.Data.(*model.User)
|
||||
|
||||
if len(user.AuthData) != 0 {
|
||||
c.Err = model.NewLocAppError("LoginById", "api.user.login_by_email.sign_in.app_error",
|
||||
map[string]interface{}{"AuthService": user.AuthService}, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
if doUserPasswordAuthenticationAndLogin(c, w, r, user, password, mfaToken, deviceId) {
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoginByEmail(c *Context, w http.ResponseWriter, r *http.Request, email, name, password, mfaToken, deviceId string) *model.User {
|
||||
if result := <-Srv.Store.User().GetByEmail(email); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
c.Err.StatusCode = http.StatusUnauthorized
|
||||
return nil
|
||||
} else {
|
||||
user := result.Data.(*model.User)
|
||||
|
||||
if len(user.AuthData) != 0 {
|
||||
c.Err = model.NewLocAppError("LoginByEmail", "api.user.login_by_email.sign_in.app_error",
|
||||
map[string]interface{}{"AuthService": user.AuthService}, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
if doUserPasswordAuthenticationAndLogin(c, w, r, user, password, mfaToken, deviceId) {
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoginByUsername(c *Context, w http.ResponseWriter, r *http.Request, username, name, password, mfaToken, deviceId string) *model.User {
|
||||
if result := <-Srv.Store.User().GetByUsername(username); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
c.Err.StatusCode = http.StatusUnauthorized
|
||||
return nil
|
||||
} else {
|
||||
user := result.Data.(*model.User)
|
||||
|
||||
if len(user.AuthData) != 0 {
|
||||
c.Err = model.NewLocAppError("LoginByUsername", "api.user.login_by_email.sign_in.app_error",
|
||||
map[string]interface{}{"AuthService": user.AuthService}, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
if doUserPasswordAuthenticationAndLogin(c, w, r, user, password, mfaToken, deviceId) {
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoginByOAuth(c *Context, w http.ResponseWriter, r *http.Request, service string, userData io.Reader) *model.User {
|
||||
buf := bytes.Buffer{}
|
||||
buf.ReadFrom(userData)
|
||||
@@ -570,80 +541,13 @@ func LoginByOAuth(c *Context, w http.ResponseWriter, r *http.Request, service st
|
||||
return nil
|
||||
} else {
|
||||
user = result.Data.(*model.User)
|
||||
Login(c, w, r, user, "")
|
||||
doLogin(c, w, r, user, "")
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
func loginLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if !*utils.Cfg.LdapSettings.Enable {
|
||||
c.Err = model.NewLocAppError("loginLdap", "api.user.login_ldap.disabled.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusNotImplemented
|
||||
return
|
||||
}
|
||||
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
password := props["password"]
|
||||
id := props["id"]
|
||||
mfaToken := props["token"]
|
||||
|
||||
if len(password) == 0 {
|
||||
c.Err = model.NewLocAppError("loginLdap", "api.user.login_ldap.blank_pwd.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
return
|
||||
}
|
||||
|
||||
if len(id) == 0 {
|
||||
c.Err = model.NewLocAppError("loginLdap", "api.user.login_ldap.need_id.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
return
|
||||
}
|
||||
|
||||
ldapInterface := einterfaces.GetLdapInterface()
|
||||
if ldapInterface == nil {
|
||||
c.Err = model.NewLocAppError("loginLdap", "api.user.login_ldap.not_available.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusNotImplemented
|
||||
return
|
||||
}
|
||||
|
||||
user, err := ldapInterface.DoLogin(id, password)
|
||||
if err != nil {
|
||||
if user != nil {
|
||||
c.LogAuditWithUserId(user.Id, "attempt")
|
||||
c.LogAuditWithUserId(user.Id, "fail")
|
||||
} else {
|
||||
c.LogAudit("attempt")
|
||||
c.LogAudit("fail")
|
||||
}
|
||||
c.Err = err
|
||||
c.Err.StatusCode = http.StatusUnauthorized
|
||||
return
|
||||
}
|
||||
c.LogAuditWithUserId(user.Id, "attempt")
|
||||
|
||||
if err = checkUserAdditionalAuthenticationCriteria(user, mfaToken); err != nil {
|
||||
c.LogAuditWithUserId(user.Id, "fail")
|
||||
c.Err = err
|
||||
c.Err.StatusCode = http.StatusUnauthorized
|
||||
return
|
||||
}
|
||||
|
||||
// User is authenticated at this point
|
||||
|
||||
Login(c, w, r, user, props["device_id"])
|
||||
c.LogAuditWithUserId(user.Id, "success")
|
||||
|
||||
if user != nil {
|
||||
user.Sanitize(map[string]bool{})
|
||||
} else {
|
||||
user = &model.User{}
|
||||
}
|
||||
w.Write([]byte(user.ToJson()))
|
||||
}
|
||||
|
||||
// User MUST be authenticated completely before calling Login
|
||||
func Login(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) {
|
||||
func doLogin(c *Context, w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) {
|
||||
|
||||
session := &model.Session{UserId: user.Id, Roles: user.Roles, DeviceId: deviceId, IsOAuth: false}
|
||||
|
||||
@@ -2371,28 +2275,20 @@ func checkMfa(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
method := props["method"]
|
||||
if method != model.USER_AUTH_SERVICE_EMAIL &&
|
||||
method != model.USER_AUTH_SERVICE_USERNAME &&
|
||||
method != model.USER_AUTH_SERVICE_LDAP {
|
||||
c.SetInvalidParam("checkMfa", "method")
|
||||
return
|
||||
}
|
||||
|
||||
loginId := props["login_id"]
|
||||
if len(loginId) == 0 {
|
||||
c.SetInvalidParam("checkMfa", "login_id")
|
||||
return
|
||||
}
|
||||
|
||||
var uchan store.StoreChannel
|
||||
if method == model.USER_AUTH_SERVICE_EMAIL {
|
||||
uchan = Srv.Store.User().GetByEmail(loginId)
|
||||
} else if method == model.USER_AUTH_SERVICE_USERNAME {
|
||||
uchan = Srv.Store.User().GetByUsername(loginId)
|
||||
} else if method == model.USER_AUTH_SERVICE_LDAP {
|
||||
uchan = Srv.Store.User().GetByAuth(loginId, model.USER_AUTH_SERVICE_LDAP)
|
||||
}
|
||||
// we don't need to worry about contacting the ldap server to get this user because
|
||||
// only users already in the system could have MFA enabled
|
||||
uchan := Srv.Store.User().GetForLogin(
|
||||
loginId,
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithUsername,
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithEmail,
|
||||
*utils.Cfg.LdapSettings.Enable,
|
||||
)
|
||||
|
||||
rdata := map[string]string{}
|
||||
if result := <-uchan; result.Err != nil {
|
||||
|
||||
113
api/user_test.go
113
api/user_test.go
@@ -84,6 +84,19 @@ func TestLogin(t *testing.T) {
|
||||
th := Setup()
|
||||
Client := th.CreateClient()
|
||||
|
||||
enableSignInWithEmail := *utils.Cfg.EmailSettings.EnableSignInWithEmail
|
||||
enableSignInWithUsername := *utils.Cfg.EmailSettings.EnableSignInWithUsername
|
||||
enableLdap := *utils.Cfg.LdapSettings.Enable
|
||||
defer func() {
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithEmail = enableSignInWithEmail
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithUsername = enableSignInWithUsername
|
||||
*utils.Cfg.LdapSettings.Enable = enableLdap
|
||||
}()
|
||||
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithEmail = false
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithUsername = false
|
||||
*utils.Cfg.LdapSettings.Enable = false
|
||||
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
@@ -100,7 +113,12 @@ func TestLogin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if result, err := Client.LoginByEmail(team.Name, user.Email, user.Password); err != nil {
|
||||
if _, err := Client.Login(user.Email, user.Password); err == nil {
|
||||
t.Fatal("shouldn't be able to log in by email when disabled")
|
||||
}
|
||||
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithEmail = true
|
||||
if result, err := Client.Login(user.Email, user.Password); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if result.Data.(*model.User).Email != user.Email {
|
||||
@@ -108,7 +126,12 @@ func TestLogin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if result, err := Client.LoginByUsername(team.Name, user.Username, user.Password); err != nil {
|
||||
if _, err := Client.Login(user.Username, user.Password); err == nil {
|
||||
t.Fatal("shouldn't be able to log in by username when disabled")
|
||||
}
|
||||
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithUsername = true
|
||||
if result, err := Client.Login(user.Username, user.Password); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if result.Data.(*model.User).Email != user.Email {
|
||||
@@ -116,19 +139,19 @@ func TestLogin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := Client.LoginByEmail(team.Name, user.Email, user.Password+"invalid"); err == nil {
|
||||
if _, err := Client.Login(user.Email, user.Password+"invalid"); err == nil {
|
||||
t.Fatal("Invalid Password")
|
||||
}
|
||||
|
||||
if _, err := Client.LoginByUsername(team.Name, user.Username, user.Password+"invalid"); err == nil {
|
||||
if _, err := Client.Login(user.Username, user.Password+"invalid"); err == nil {
|
||||
t.Fatal("Invalid Password")
|
||||
}
|
||||
|
||||
if _, err := Client.LoginByEmail(team.Name, "", user.Password); err == nil {
|
||||
if _, err := Client.Login("", user.Password); err == nil {
|
||||
t.Fatal("should have failed")
|
||||
}
|
||||
|
||||
if _, err := Client.LoginByUsername(team.Name, "", user.Password); err == nil {
|
||||
if _, err := Client.Login("", user.Password); err == nil {
|
||||
t.Fatal("should have failed")
|
||||
}
|
||||
|
||||
@@ -160,22 +183,35 @@ func TestLogin(t *testing.T) {
|
||||
|
||||
ruser2, _ := Client.CreateUserFromSignup(&user2, data, hash)
|
||||
|
||||
if _, err := Client.LoginByEmail(team2.Name, ruser2.Data.(*model.User).Email, user2.Password); err != nil {
|
||||
if _, err := Client.Login(ruser2.Data.(*model.User).Email, user2.Password); err != nil {
|
||||
t.Fatal("From verfied hash")
|
||||
}
|
||||
|
||||
Client.AuthToken = authToken
|
||||
|
||||
user3 := &model.User{
|
||||
Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com",
|
||||
Nickname: "Corey Hulen",
|
||||
Username: "corey" + model.NewId(),
|
||||
Password: "pwd",
|
||||
AuthService: model.USER_AUTH_SERVICE_LDAP,
|
||||
}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
if _, err := Client.Login(user3.Id, user3.Password); err == nil {
|
||||
t.Fatal("LDAP user should not be able to log in with LDAP disabled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginWithDeviceId(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
Client := th.BasicClient
|
||||
team := th.BasicTeam
|
||||
user := th.BasicUser
|
||||
Client.Must(Client.Logout())
|
||||
|
||||
deviceId := model.NewId()
|
||||
if result, err := Client.LoginByEmailWithDevice(team.Name, user.Email, user.Password, deviceId); err != nil {
|
||||
if result, err := Client.LoginWithDevice(user.Email, user.Password, deviceId); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
ruser := result.Data.(*model.User)
|
||||
@@ -184,7 +220,7 @@ func TestLoginWithDeviceId(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
sessions := ssresult.Data.([]*model.Session)
|
||||
if _, err := Client.LoginByEmailWithDevice(team.Name, user.Email, user.Password, deviceId); err != nil {
|
||||
if _, err := Client.LoginWithDevice(user.Email, user.Password, deviceId); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -198,13 +234,12 @@ func TestLoginWithDeviceId(t *testing.T) {
|
||||
func TestSessions(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
Client := th.BasicClient
|
||||
team := th.BasicTeam
|
||||
user := th.BasicUser
|
||||
Client.Must(Client.Logout())
|
||||
|
||||
deviceId := model.NewId()
|
||||
Client.LoginByEmailWithDevice(team.Name, user.Email, user.Password, deviceId)
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.LoginWithDevice(user.Email, user.Password, deviceId)
|
||||
Client.Login(user.Email, user.Password)
|
||||
|
||||
r1, err := Client.GetSessions(user.Id)
|
||||
if err != nil {
|
||||
@@ -269,7 +304,7 @@ func TestGetUser(t *testing.T) {
|
||||
LinkUserToTeam(ruser3.Data.(*model.User), rteam2.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser3.Data.(*model.User).Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.Login(user.Email, user.Password)
|
||||
|
||||
rId := ruser.Data.(*model.User).Id
|
||||
if result, err := Client.GetUser(rId, ""); err != nil {
|
||||
@@ -333,7 +368,7 @@ func TestGetUser(t *testing.T) {
|
||||
c.IpAddress = "cmd_line"
|
||||
UpdateRoles(c, ruser.Data.(*model.User), model.ROLE_SYSTEM_ADMIN)
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
|
||||
if _, err := Client.GetProfiles(rteam2.Data.(*model.Team).Id, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -374,7 +409,7 @@ func TestGetAudits(t *testing.T) {
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.Login(user.Email, user.Password)
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
@@ -427,7 +462,7 @@ func TestUserCreateImage(t *testing.T) {
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
|
||||
Client.DoApiGet("/users/"+user.Id+"/image", "", "")
|
||||
|
||||
@@ -471,7 +506,7 @@ func TestUserUploadProfileImage(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if _, upErr := Client.UploadProfileFile(body.Bytes(), writer.FormDataContentType()); upErr == nil {
|
||||
@@ -575,7 +610,7 @@ func TestUserUpdate(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
@@ -615,7 +650,7 @@ func TestUserUpdate(t *testing.T) {
|
||||
LinkUserToTeam(user2, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
user.Nickname = "Tim Timmy"
|
||||
@@ -642,7 +677,7 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
|
||||
if _, err := Client.UpdateUserPassword("123", "pwd", "newpwd"); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
@@ -673,7 +708,7 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
t.Fatal("LastPasswordUpdate should have changed")
|
||||
}
|
||||
|
||||
if _, err := Client.LoginByEmail(team.Name, user.Email, "newpwd"); err != nil {
|
||||
if _, err := Client.Login(user.Email, "newpwd"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -681,7 +716,7 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
LinkUserToTeam(user2, team)
|
||||
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "pwd")
|
||||
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "pwd", "newpwd"); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
@@ -713,7 +748,7 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
t.Fatal("Should have errored, not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if _, err := Client.UpdateUserRoles(data); err == nil {
|
||||
@@ -728,7 +763,7 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
LinkUserToTeam(user3, team2)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
Client.LoginByEmail(team2.Name, user3.Email, "pwd")
|
||||
Client.Login(user3.Email, "pwd")
|
||||
Client.SetTeamId(team2.Id)
|
||||
|
||||
data["user_id"] = user2.Id
|
||||
@@ -737,7 +772,7 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
t.Fatal("Should have errored, wrong team")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
|
||||
data["user_id"] = "junk"
|
||||
data["new_roles"] = "admin"
|
||||
@@ -771,7 +806,7 @@ func TestUserUpdateDeviceId(t *testing.T) {
|
||||
LinkUserToTeam(user, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
deviceId := model.PUSH_NOTIFY_APPLE + ":1234567890"
|
||||
|
||||
@@ -811,7 +846,7 @@ func TestUserUpdateActive(t *testing.T) {
|
||||
t.Fatal("Should have errored, not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
Client.Login(user2.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if _, err := Client.UpdateActive(user.Id, false); err == nil {
|
||||
@@ -828,14 +863,14 @@ func TestUserUpdateActive(t *testing.T) {
|
||||
LinkUserToTeam(user2, team2)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
Client.LoginByEmail(team2.Name, user3.Email, "pwd")
|
||||
Client.Login(user3.Email, "pwd")
|
||||
Client.SetTeamId(team2.Id)
|
||||
|
||||
if _, err := Client.UpdateActive(user.Id, false); err == nil {
|
||||
t.Fatal("Should have errored, not yourself")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if _, err := Client.UpdateActive("junk", false); err == nil {
|
||||
@@ -859,7 +894,7 @@ func TestUserPermDelete(t *testing.T) {
|
||||
LinkUserToTeam(user1, team)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
Client.Login(user1.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
@@ -1013,7 +1048,7 @@ func TestUserUpdateNotify(t *testing.T) {
|
||||
t.Fatal("Should have errored - not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
Client.Login(user.Email, "pwd")
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
if result, err := Client.UpdateUserNotify(data); err != nil {
|
||||
@@ -1109,7 +1144,7 @@ func TestStatuses(t *testing.T) {
|
||||
LinkUserToTeam(ruser2, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.Login(user.Email, user.Password)
|
||||
Client.SetTeamId(team.Id)
|
||||
|
||||
userIds := []string{ruser2.Id}
|
||||
@@ -1207,7 +1242,7 @@ func TestOAuthToEmail(t *testing.T) {
|
||||
t.Fatal("should have failed - not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.Login(user.Email, user.Password)
|
||||
|
||||
if _, err := Client.OAuthToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - empty data")
|
||||
@@ -1248,7 +1283,7 @@ func TestLDAPToEmail(t *testing.T) {
|
||||
LinkUserToTeam(ruser, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.Login(user.Email, user.Password)
|
||||
|
||||
m := map[string]string{}
|
||||
if _, err := Client.LDAPToEmail(m); err == nil {
|
||||
@@ -1301,7 +1336,7 @@ func TestEmailToLDAP(t *testing.T) {
|
||||
LinkUserToTeam(ruser, rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.Login(user.Email, user.Password)
|
||||
|
||||
m := map[string]string{}
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
@@ -1438,7 +1473,7 @@ func TestGenerateMfaQrCode(t *testing.T) {
|
||||
t.Fatal("should have failed - not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.Login(user.Email, user.Password)
|
||||
|
||||
if _, err := Client.GenerateMfaQrCode(); err == nil {
|
||||
t.Fatal("should have failed - not licensed")
|
||||
@@ -1476,7 +1511,7 @@ func TestUpdateMfa(t *testing.T) {
|
||||
t.Fatal("should have failed - not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
Client.Login(user.Email, user.Password)
|
||||
|
||||
if _, err := Client.UpdateMfa(true, ""); err == nil {
|
||||
t.Fatal("should have failed - no token")
|
||||
@@ -1509,7 +1544,7 @@ func TestCheckMfa(t *testing.T) {
|
||||
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
if result, err := Client.CheckMfa(model.USER_AUTH_SERVICE_EMAIL, user.Email); err != nil {
|
||||
if result, err := Client.CheckMfa(user.Email); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
resp := result.Data.(map[string]string)
|
||||
|
||||
10
i18n/en.json
10
i18n/en.json
@@ -1560,7 +1560,7 @@
|
||||
"translation": "Revoking sessionId=%v for userId=%v re-login with same device Id"
|
||||
},
|
||||
{
|
||||
"id": "api.user.login_by_email.sign_in.app_error",
|
||||
"id": "api.user.login.use_auth_service.app_error",
|
||||
"translation": "Please sign in using {{.AuthService}}"
|
||||
},
|
||||
{
|
||||
@@ -3443,6 +3443,14 @@
|
||||
"id": "store.sql_user.get_for_export.app_error",
|
||||
"translation": "We encountered an error while finding user profiles"
|
||||
},
|
||||
{
|
||||
"id": "store.sql_user.get_for_login.app_error",
|
||||
"translation": "We couldn't find an existing account matching your credentials. This team may require an invite from the team owner to join."
|
||||
},
|
||||
{
|
||||
"id": "store.sql_user.get_for_login.multiple_users",
|
||||
"translation": "We found multiple users matching your credentials and were unable to log you in. Please contact an administrator."
|
||||
},
|
||||
{
|
||||
"id": "store.sql_user.get_profiles.app_error",
|
||||
"translation": "We encountered an error while finding user profiles"
|
||||
|
||||
@@ -1560,7 +1560,7 @@
|
||||
"translation": "Revocando sessionId=%v para el userId=%v vuelve a iniciar la sesión el el mismo dispositivo"
|
||||
},
|
||||
{
|
||||
"id": "api.user.login_by_email.sign_in.app_error",
|
||||
"id": "api.user.login.use_auth_service.app_error",
|
||||
"translation": "Por favor inicia sesión usando {{.AuthService}}"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1428,7 +1428,7 @@
|
||||
"translation": "Session sessionId=%v de l'utilisateur userId=%v révoquée re-connexion avec le même identifiant"
|
||||
},
|
||||
{
|
||||
"id": "api.user.login_by_email.sign_in.app_error",
|
||||
"id": "api.user.login.use_auth_service.app_error",
|
||||
"translation": "Veuillez vous connecter en utilisant {{.AuthService}}"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1564,7 +1564,7 @@
|
||||
"translation": "userId=%vのsessionId=%vを無効化しました。同じデバイスIDでログインし直してください"
|
||||
},
|
||||
{
|
||||
"id": "api.user.login_by_email.sign_in.app_error",
|
||||
"id": "api.user.login.use_auth_service.app_error",
|
||||
"translation": "{{.AuthService}}を使ってサインインしてください"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1520,7 +1520,7 @@
|
||||
"translation": "Revogada sessionid=%v para userid=%v logue novamente com o mesmo id de dispositivo"
|
||||
},
|
||||
{
|
||||
"id": "api.user.login_by_email.sign_in.app_error",
|
||||
"id": "api.user.login.use_auth_service.app_error",
|
||||
"translation": "Por favor logue usando {{.AuthService}}"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -355,51 +355,21 @@ func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
|
||||
return c.login(m)
|
||||
}
|
||||
|
||||
func (c *Client) LoginByEmail(name string, email string, password string) (*Result, *AppError) {
|
||||
func (c *Client) Login(loginId string, password string) (*Result, *AppError) {
|
||||
m := make(map[string]string)
|
||||
m["name"] = name
|
||||
m["email"] = email
|
||||
m["login_id"] = loginId
|
||||
m["password"] = password
|
||||
return c.login(m)
|
||||
}
|
||||
|
||||
func (c *Client) LoginByUsername(name string, username string, password string) (*Result, *AppError) {
|
||||
func (c *Client) LoginWithDevice(loginId string, password string, deviceId string) (*Result, *AppError) {
|
||||
m := make(map[string]string)
|
||||
m["name"] = name
|
||||
m["username"] = username
|
||||
m["password"] = password
|
||||
return c.login(m)
|
||||
}
|
||||
|
||||
func (c *Client) LoginByEmailWithDevice(name string, email string, password string, deviceId string) (*Result, *AppError) {
|
||||
m := make(map[string]string)
|
||||
m["name"] = name
|
||||
m["email"] = email
|
||||
m["login_id"] = loginId
|
||||
m["password"] = password
|
||||
m["device_id"] = deviceId
|
||||
return c.login(m)
|
||||
}
|
||||
|
||||
func (c *Client) LoginByLdap(userid string, password string, mfatoken string) (*Result, *AppError) {
|
||||
m := make(map[string]string)
|
||||
m["id"] = userid
|
||||
m["password"] = password
|
||||
m["token"] = mfatoken
|
||||
if r, err := c.DoApiPost("/users/login_ldap", MapToJson(m)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
c.AuthToken = r.Header.Get(HEADER_TOKEN)
|
||||
c.AuthType = HEADER_BEARER
|
||||
sessionToken := getCookie(SESSION_COOKIE_TOKEN, r)
|
||||
|
||||
if c.AuthToken != sessionToken.Value {
|
||||
NewLocAppError("/users/login_ldap", "model.client.login.app_error", nil, "")
|
||||
}
|
||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) login(m map[string]string) (*Result, *AppError) {
|
||||
if r, err := c.DoApiPost("/users/login", MapToJson(m)); err != nil {
|
||||
return nil, err
|
||||
@@ -430,9 +400,8 @@ func (c *Client) Logout() (*Result, *AppError) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) CheckMfa(method, loginId string) (*Result, *AppError) {
|
||||
func (c *Client) CheckMfa(loginId string) (*Result, *AppError) {
|
||||
m := make(map[string]string)
|
||||
m["method"] = method
|
||||
m["login_id"] = loginId
|
||||
|
||||
if r, err := c.DoApiPost("/users/mfa", MapToJson(m)); err != nil {
|
||||
|
||||
@@ -716,6 +716,47 @@ func (us SqlUserStore) GetByUsername(username string) StoreChannel {
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled bool) StoreChannel {
|
||||
storeChannel := make(StoreChannel)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
params := map[string]interface{}{
|
||||
"LoginId": loginId,
|
||||
"AllowSignInWithUsername": allowSignInWithUsername,
|
||||
"AllowSignInWithEmail": allowSignInWithEmail,
|
||||
"LdapEnabled": ldapEnabled,
|
||||
}
|
||||
|
||||
users := []*model.User{}
|
||||
if _, err := us.GetReplica().Select(
|
||||
&users,
|
||||
`SELECT
|
||||
*
|
||||
FROM
|
||||
Users
|
||||
WHERE
|
||||
(:AllowSignInWithUsername AND Username = :LoginId)
|
||||
OR (:AllowSignInWithEmail AND Email = :LoginId)
|
||||
OR (:LdapEnabled AND AuthService = '`+model.USER_AUTH_SERVICE_LDAP+`' AND AuthData = :LoginId)`,
|
||||
params); err != nil {
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, err.Error())
|
||||
} else if len(users) == 1 {
|
||||
result.Data = users[0]
|
||||
} else if len(users) > 1 {
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.multiple_users", nil, "")
|
||||
} else {
|
||||
result.Err = model.NewLocAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, "")
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (us SqlUserStore) VerifyEmail(userId string) StoreChannel {
|
||||
storeChannel := make(StoreChannel)
|
||||
|
||||
|
||||
@@ -469,6 +469,82 @@ func TestUserStoreGetByUsername(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserStoreGetForLogin(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
u1 := &model.User{
|
||||
Email: model.NewId(),
|
||||
Username: model.NewId(),
|
||||
AuthService: model.USER_AUTH_SERVICE_GITLAB,
|
||||
AuthData: model.NewId(),
|
||||
}
|
||||
Must(store.User().Save(u1))
|
||||
|
||||
u2 := &model.User{
|
||||
Email: model.NewId(),
|
||||
Username: model.NewId(),
|
||||
AuthService: model.USER_AUTH_SERVICE_LDAP,
|
||||
AuthData: model.NewId(),
|
||||
}
|
||||
Must(store.User().Save(u2))
|
||||
|
||||
if result := <-store.User().GetForLogin(u1.Username, true, true, true); result.Err != nil {
|
||||
t.Fatal("Should have gotten user by username", result.Err)
|
||||
} else if result.Data.(*model.User).Id != u1.Id {
|
||||
t.Fatal("Should have gotten user1 by username")
|
||||
}
|
||||
|
||||
if result := <-store.User().GetForLogin(u1.Email, true, true, true); result.Err != nil {
|
||||
t.Fatal("Should have gotten user by email", result.Err)
|
||||
} else if result.Data.(*model.User).Id != u1.Id {
|
||||
t.Fatal("Should have gotten user1 by email")
|
||||
}
|
||||
|
||||
if result := <-store.User().GetForLogin(u2.AuthData, true, true, true); result.Err != nil {
|
||||
t.Fatal("Should have gotten user by LDAP AuthData", result.Err)
|
||||
} else if result.Data.(*model.User).Id != u2.Id {
|
||||
t.Fatal("Should have gotten user2 by LDAP AuthData")
|
||||
}
|
||||
|
||||
// prevent getting user by AuthData when they're not an LDAP user
|
||||
if result := <-store.User().GetForLogin(u1.AuthData, true, true, true); result.Err == nil {
|
||||
t.Fatal("Should not have gotten user by non-LDAP AuthData")
|
||||
}
|
||||
|
||||
// prevent getting user when different login methods are disabled
|
||||
if result := <-store.User().GetForLogin(u1.Username, false, true, true); result.Err == nil {
|
||||
t.Fatal("Should have failed to get user1 by username")
|
||||
}
|
||||
|
||||
if result := <-store.User().GetForLogin(u1.Email, true, false, true); result.Err == nil {
|
||||
t.Fatal("Should have failed to get user1 by email")
|
||||
}
|
||||
|
||||
if result := <-store.User().GetForLogin(u2.AuthData, true, true, false); result.Err == nil {
|
||||
t.Fatal("Should have failed to get user3 by LDAP AuthData")
|
||||
}
|
||||
|
||||
// test a special case where two users will have conflicting login information so we throw a special error
|
||||
u3 := &model.User{
|
||||
Email: model.NewId(),
|
||||
Username: model.NewId(),
|
||||
AuthService: model.USER_AUTH_SERVICE_LDAP,
|
||||
AuthData: model.NewId(),
|
||||
}
|
||||
Must(store.User().Save(u3))
|
||||
u4 := &model.User{
|
||||
Email: model.NewId(),
|
||||
Username: model.NewId(),
|
||||
AuthService: model.USER_AUTH_SERVICE_LDAP,
|
||||
AuthData: u3.Username,
|
||||
}
|
||||
Must(store.User().Save(u4))
|
||||
|
||||
if err := (<-store.User().GetForLogin(u3.Username, true, true, true)).Err; err == nil {
|
||||
t.Fatal("Should have failed to get users with conflicting login information")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserStoreUpdatePassword(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
|
||||
@@ -137,6 +137,7 @@ type UserStore interface {
|
||||
GetByEmail(email string) StoreChannel
|
||||
GetByAuth(authData string, authService string) StoreChannel
|
||||
GetByUsername(username string) StoreChannel
|
||||
GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled bool) StoreChannel
|
||||
VerifyEmail(userId string) StoreChannel
|
||||
GetEtagForProfiles(teamId string) StoreChannel
|
||||
GetEtagForDirectProfiles(userId string) StoreChannel
|
||||
|
||||
@@ -204,7 +204,7 @@ func TestIncomingWebhook(t *testing.T) {
|
||||
c.RequestId = model.NewId()
|
||||
c.IpAddress = "cmd_line"
|
||||
api.UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
|
||||
ApiClient.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
ApiClient.Login(user.Email, "pwd")
|
||||
ApiClient.SetTeamId(team.Id)
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
|
||||
@@ -746,7 +746,19 @@ export default class Client {
|
||||
end(this.handleResponse.bind(this, 'getMe', success, error));
|
||||
}
|
||||
|
||||
login = (email, username, password, mfaToken, success, error) => {
|
||||
login = (loginId, password, mfaToken, success, error) => {
|
||||
this.doLogin({login_id: loginId, password, token: mfaToken}, success, error);
|
||||
|
||||
this.track('api', 'api_users_login', '', 'login_id', loginId);
|
||||
}
|
||||
|
||||
loginById = (id, password, mfaToken, success, error) => {
|
||||
this.doLogin({id, password, token: mfaToken}, success, error);
|
||||
|
||||
this.track('api', 'api_users_login', '', 'id', id);
|
||||
}
|
||||
|
||||
doLogin = (outgoingData, success, error) => {
|
||||
var outer = this; // eslint-disable-line consistent-this
|
||||
|
||||
request.
|
||||
@@ -754,7 +766,7 @@ export default class Client {
|
||||
set(this.defaultHeaders).
|
||||
type('application/json').
|
||||
accept('application/json').
|
||||
send({email, password, username, token: mfaToken}).
|
||||
send(outgoingData).
|
||||
end(this.handleResponse.bind(
|
||||
this,
|
||||
'login',
|
||||
@@ -773,39 +785,6 @@ export default class Client {
|
||||
},
|
||||
error
|
||||
));
|
||||
|
||||
this.track('api', 'api_users_login', '', 'email', email);
|
||||
}
|
||||
|
||||
loginByLdap = (ldapId, password, mfaToken, success, error) => {
|
||||
var outer = this; // eslint-disable-line consistent-this
|
||||
|
||||
request.
|
||||
post(`${this.getUsersRoute()}/login_ldap`).
|
||||
set(this.defaultHeaders).
|
||||
type('application/json').
|
||||
accept('application/json').
|
||||
send({id: ldapId, password, token: mfaToken}).
|
||||
end(this.handleResponse.bind(
|
||||
this,
|
||||
'loginByLdap',
|
||||
(data, res) => {
|
||||
if (res && res.header) {
|
||||
outer.token = res.header[HEADER_TOKEN];
|
||||
|
||||
if (outer.useToken) {
|
||||
outer.defaultHeaders[HEADER_AUTH] = `${HEADER_BEARER} ${outer.token}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
success(data, res);
|
||||
}
|
||||
},
|
||||
error
|
||||
));
|
||||
|
||||
this.track('api', 'api_users_loginLdap', '', 'email', ldapId);
|
||||
}
|
||||
|
||||
logout = (success, error) => {
|
||||
@@ -819,10 +798,10 @@ export default class Client {
|
||||
this.track('api', 'api_users_logout');
|
||||
}
|
||||
|
||||
checkMfa = (method, loginId, success, error) => {
|
||||
var data = {};
|
||||
data.method = method;
|
||||
data.login_id = loginId;
|
||||
checkMfa = (loginId, success, error) => {
|
||||
const data = {
|
||||
login_id: loginId
|
||||
};
|
||||
|
||||
request.
|
||||
post(`${this.getUsersRoute()}/mfa`).
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default class LoginEmail extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
|
||||
this.state = {
|
||||
serverError: props.serverError
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({serverError: nextProps.serverError});
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
var state = {};
|
||||
|
||||
const email = this.refs.email.value.trim();
|
||||
if (!email) {
|
||||
state.serverError = Utils.localizeMessage('login_email.emailReq', 'An email is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const password = this.refs.password.value.trim();
|
||||
if (!password) {
|
||||
state.serverError = Utils.localizeMessage('login_email.pwdReq', 'A password is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.serverError = '';
|
||||
this.setState(state);
|
||||
|
||||
this.props.submit(Constants.EMAIL_SERVICE, email, password);
|
||||
}
|
||||
render() {
|
||||
let serverError;
|
||||
let errorClass = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <label className='control-label'>{this.state.serverError}</label>;
|
||||
errorClass = ' has-error';
|
||||
}
|
||||
|
||||
let priorEmail = UserStore.getLastEmail();
|
||||
let focusEmail = false;
|
||||
let focusPassword = false;
|
||||
if (priorEmail === '') {
|
||||
focusEmail = true;
|
||||
} else {
|
||||
focusPassword = true;
|
||||
}
|
||||
|
||||
const emailParam = Utils.getUrlParameter('email');
|
||||
if (emailParam) {
|
||||
priorEmail = decodeURIComponent(emailParam);
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
<div className={'form-group' + errorClass}>
|
||||
{serverError}
|
||||
</div>
|
||||
<div className={'form-group' + errorClass}>
|
||||
<input
|
||||
autoFocus={focusEmail}
|
||||
type='email'
|
||||
className='form-control'
|
||||
name='email'
|
||||
defaultValue={priorEmail}
|
||||
ref='email'
|
||||
placeholder={Utils.localizeMessage('login_email.email', 'Email')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
<div className={'form-group' + errorClass}>
|
||||
<input
|
||||
autoFocus={focusPassword}
|
||||
type='password'
|
||||
className='form-control'
|
||||
name='password'
|
||||
ref='password'
|
||||
placeholder={Utils.localizeMessage('login_email.pwd', 'Password')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='login_email.signin'
|
||||
defaultMessage='Sign in'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
LoginEmail.defaultProps = {
|
||||
};
|
||||
|
||||
LoginEmail.propTypes = {
|
||||
submit: React.PropTypes.func.isRequired,
|
||||
serverError: React.PropTypes.string
|
||||
};
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default class LoginLdap extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
|
||||
this.state = {
|
||||
serverError: props.serverError
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({serverError: nextProps.serverError});
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const state = {};
|
||||
|
||||
const id = this.refs.id.value.trim();
|
||||
if (!id) {
|
||||
state.serverError = Utils.localizeMessage('login_ldap.idlReq', 'An LDAP ID is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const password = this.refs.password.value.trim();
|
||||
if (!password) {
|
||||
state.serverError = Utils.localizeMessage('login_ldap.pwdReq', 'An LDAP password is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.serverError = '';
|
||||
this.setState(state);
|
||||
|
||||
this.props.submit(Constants.LDAP_SERVICE, id, password);
|
||||
}
|
||||
render() {
|
||||
let serverError;
|
||||
let errorClass = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <label className='control-label'>{this.state.serverError}</label>;
|
||||
errorClass = ' has-error';
|
||||
}
|
||||
|
||||
let loginPlaceholder;
|
||||
if (global.window.mm_config.LdapLoginFieldName) {
|
||||
loginPlaceholder = global.window.mm_config.LdapLoginFieldName;
|
||||
} else {
|
||||
loginPlaceholder = Utils.localizeMessage('login_ldap.username', 'LDAP Username');
|
||||
}
|
||||
|
||||
let passwordPlaceholder;
|
||||
if (global.window.mm_config.LdapPasswordFieldName) {
|
||||
passwordPlaceholder = global.window.mm_config.LdapPasswordFieldName;
|
||||
} else {
|
||||
passwordPlaceholder = Utils.localizeMessage('login_ldap.pwd', 'LDAP Password');
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
<div className={'form-group' + errorClass}>
|
||||
{serverError}
|
||||
</div>
|
||||
<div className={'form-group' + errorClass}>
|
||||
<input
|
||||
autoFocus={true}
|
||||
className='form-control'
|
||||
ref='id'
|
||||
placeholder={loginPlaceholder}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
<div className={'form-group' + errorClass}>
|
||||
<input
|
||||
type='password'
|
||||
className='form-control'
|
||||
ref='password'
|
||||
placeholder={passwordPlaceholder}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='login_ldap.signin'
|
||||
defaultMessage='Sign in'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
LoginLdap.defaultProps = {
|
||||
};
|
||||
|
||||
LoginLdap.propTypes = {
|
||||
serverError: React.PropTypes.string,
|
||||
submit: React.PropTypes.func.isRequired
|
||||
};
|
||||
@@ -31,7 +31,7 @@ export default class LoginMfa extends React.Component {
|
||||
state.serverError = '';
|
||||
this.setState(state);
|
||||
|
||||
this.props.submit(this.props.method, this.props.loginId, this.props.password, token);
|
||||
this.props.submit(this.props.loginId, this.props.password, token);
|
||||
}
|
||||
render() {
|
||||
let serverError;
|
||||
@@ -85,7 +85,6 @@ LoginMfa.defaultProps = {
|
||||
};
|
||||
|
||||
LoginMfa.propTypes = {
|
||||
method: React.PropTypes.string.isRequired,
|
||||
loginId: React.PropTypes.string.isRequired,
|
||||
password: React.PropTypes.string.isRequired,
|
||||
submit: React.PropTypes.func.isRequired
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default class LoginUsername extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
|
||||
this.state = {
|
||||
serverError: props.serverError
|
||||
};
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({serverError: nextProps.serverError});
|
||||
}
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const state = {};
|
||||
|
||||
const username = this.refs.username.value.trim();
|
||||
if (!username) {
|
||||
state.serverError = Utils.localizeMessage('login_username.usernameReq', 'A username is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const password = this.refs.password.value.trim();
|
||||
if (!password) {
|
||||
state.serverError = Utils.localizeMessage('login_username.pwdReq', 'A password is required');
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.serverError = '';
|
||||
this.setState(state);
|
||||
|
||||
this.props.submit(Constants.USERNAME_SERVICE, username, password);
|
||||
}
|
||||
render() {
|
||||
let serverError;
|
||||
let errorClass = '';
|
||||
if (this.state.serverError) {
|
||||
serverError = <label className='control-label'>{this.state.serverError}</label>;
|
||||
errorClass = ' has-error';
|
||||
}
|
||||
|
||||
let priorUsername = UserStore.getLastUsername();
|
||||
let focusUsername = false;
|
||||
let focusPassword = false;
|
||||
if (priorUsername === '') {
|
||||
focusUsername = true;
|
||||
} else {
|
||||
focusPassword = true;
|
||||
}
|
||||
|
||||
const emailParam = Utils.getUrlParameter('email');
|
||||
if (emailParam) {
|
||||
priorUsername = decodeURIComponent(emailParam);
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
<div className={'form-group' + errorClass}>
|
||||
{serverError}
|
||||
</div>
|
||||
<div className={'form-group' + errorClass}>
|
||||
<input
|
||||
autoFocus={focusUsername}
|
||||
type='username'
|
||||
className='form-control'
|
||||
name='username'
|
||||
defaultValue={priorUsername}
|
||||
ref='username'
|
||||
placeholder={Utils.localizeMessage('login_username.username', 'Username')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
<div className={'form-group' + errorClass}>
|
||||
<input
|
||||
autoFocus={focusPassword}
|
||||
type='password'
|
||||
className='form-control'
|
||||
name='password'
|
||||
ref='password'
|
||||
placeholder={Utils.localizeMessage('login_username.pwd', 'Password')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='login_username.signin'
|
||||
defaultMessage='Sign in'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
LoginUsername.defaultProps = {
|
||||
};
|
||||
|
||||
LoginUsername.propTypes = {
|
||||
serverError: React.PropTypes.string,
|
||||
submit: React.PropTypes.func.isRequired
|
||||
};
|
||||
@@ -1,13 +1,11 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import LoginEmail from './components/login_email.jsx';
|
||||
import LoginUsername from './components/login_username.jsx';
|
||||
import LoginLdap from './components/login_ldap.jsx';
|
||||
import LoginMfa from './components/login_mfa.jsx';
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import FormError from 'components/form_error.jsx';
|
||||
|
||||
import * as GlobalActions from '../../action_creators/global_actions.jsx';
|
||||
import * as GlobalActions from 'action_creators/global_actions.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
import Client from 'utils/web_client.jsx';
|
||||
@@ -30,10 +28,16 @@ export default class Login extends React.Component {
|
||||
this.submit = this.submit.bind(this);
|
||||
this.finishSignin = this.finishSignin.bind(this);
|
||||
|
||||
const state = {};
|
||||
state.showMfa = false;
|
||||
this.state = state;
|
||||
this.handleLoginIdChange = this.handleLoginIdChange.bind(this);
|
||||
this.handlePasswordChange = this.handlePasswordChange.bind(this);
|
||||
|
||||
this.state = {
|
||||
loginId: '', // the browser will set a default for this
|
||||
password: '',
|
||||
showMfa: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
document.title = global.window.mm_config.SiteName;
|
||||
|
||||
@@ -41,31 +45,97 @@ export default class Login extends React.Component {
|
||||
browserHistory.push('/select_team');
|
||||
}
|
||||
}
|
||||
preSubmit(method, loginId, password) {
|
||||
if (global.window.mm_config.EnableMultifactorAuthentication !== 'true') {
|
||||
this.submit(method, loginId, password, '');
|
||||
|
||||
preSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const loginId = this.state.loginId.trim();
|
||||
if (!loginId) {
|
||||
const ldapEnabled = global.window.mm_config.EnableLdap === 'true';
|
||||
const usernameSigninEnabled = global.window.mm_config.EnableSignInWithUsername === 'true';
|
||||
const emailSigninEnabled = global.window.mm_config.EnableSignInWithEmail === 'true';
|
||||
|
||||
this.setState({
|
||||
serverError: (
|
||||
<FormattedMessage
|
||||
id='login.loginIdRequired'
|
||||
defaultMessage='A {type} is required'
|
||||
values={{
|
||||
type: this.createLoginPlaceholder(emailSigninEnabled, usernameSigninEnabled, ldapEnabled)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Client.checkMfa(method, loginId,
|
||||
const password = this.state.password.trim();
|
||||
if (!password) {
|
||||
this.setState({
|
||||
serverError: (
|
||||
<FormattedMessage
|
||||
id='login.passwordRequired'
|
||||
defaultMessage='A password is required'
|
||||
/>
|
||||
)
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (global.window.mm_config.EnableMultifactorAuthentication !== 'true') {
|
||||
this.submit(loginId, password, '');
|
||||
return;
|
||||
}
|
||||
|
||||
Client.checkMfa(
|
||||
loginId,
|
||||
(data) => {
|
||||
if (data.mfa_required === 'true') {
|
||||
this.setState({showMfa: true, method, loginId, password});
|
||||
this.setState({showMfa: true});
|
||||
} else {
|
||||
this.submit(method, loginId, password, '');
|
||||
this.submit(loginId, password, '');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (method === Constants.EMAIL_SERVICE) {
|
||||
this.setState({serverEmailError: err.message});
|
||||
} else if (method === Constants.USERNAME_SERVICE) {
|
||||
this.setState({serverUsernameError: err.message});
|
||||
} else if (method === Constants.LDAP_SERVICE) {
|
||||
this.setState({serverLdapError: err.message});
|
||||
this.setState({serverError: err.message});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
submit(loginId, password, token) {
|
||||
this.setState({showMfa: false, serverError: null});
|
||||
|
||||
Client.webLogin(
|
||||
loginId,
|
||||
password,
|
||||
token,
|
||||
() => {
|
||||
this.finishSignin();
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
browserHistory.push('/should_verify_email?&email=' + encodeURIComponent(loginId));
|
||||
return;
|
||||
} else if (err.id === 'store.sql_user.get_for_login.app_error' ||
|
||||
err.id === 'ent.ldap.do_login.user_not_registered.app_error' ||
|
||||
err.id === 'ent.ldap.do_login.user_filtered.app_error') {
|
||||
this.setState({
|
||||
serverError: (
|
||||
<FormattedMessage
|
||||
id='login.userNotFound'
|
||||
defaultMessage="We couldn't find an existing account matching your login credentials."
|
||||
/>
|
||||
)
|
||||
});
|
||||
} else {
|
||||
this.setState({serverError: err.message});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
finishSignin() {
|
||||
GlobalActions.emitInitialLoad(
|
||||
() => {
|
||||
@@ -74,72 +144,18 @@ export default class Login extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
submit(method, loginId, password, token) {
|
||||
this.setState({showMfa: false, serverEmailError: null, serverUsernameError: null, serverLdapError: null});
|
||||
|
||||
if (method === Constants.EMAIL_SERVICE) {
|
||||
Client.webLogin(
|
||||
loginId,
|
||||
null,
|
||||
password,
|
||||
token,
|
||||
() => {
|
||||
UserStore.setLastEmail(loginId);
|
||||
this.finishSignin();
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
browserHistory.push('/should_verify_email?&email=' + encodeURIComponent(loginId));
|
||||
return;
|
||||
}
|
||||
this.setState({serverEmailError: err.message});
|
||||
}
|
||||
);
|
||||
} else if (method === Constants.USERNAME_SERVICE) {
|
||||
Client.webLogin(
|
||||
null,
|
||||
loginId,
|
||||
password,
|
||||
token,
|
||||
() => {
|
||||
UserStore.setLastUsername(loginId);
|
||||
|
||||
const redirect = Utils.getUrlParameter('redirect');
|
||||
if (redirect) {
|
||||
browserHistory.push(decodeURIComponent(redirect));
|
||||
} else {
|
||||
this.finishSignin();
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (err.id === 'api.user.login.not_verified.app_error') {
|
||||
this.setState({serverUsernameError: Utils.localizeMessage('login_username.verifyEmailError', 'Please verify your email address. Check your inbox for an email.')});
|
||||
} else if (err.id === 'store.sql_user.get_by_username.app_error') {
|
||||
this.setState({serverUsernameError: Utils.localizeMessage('login_username.userNotFoundError', 'We couldn\'t find an existing account matching your username for this team.')});
|
||||
} else {
|
||||
this.setState({serverUsernameError: err.message});
|
||||
}
|
||||
}
|
||||
);
|
||||
} else if (method === Constants.LDAP_SERVICE) {
|
||||
Client.loginByLdap(
|
||||
loginId,
|
||||
password,
|
||||
token,
|
||||
() => {
|
||||
const redirect = Utils.getUrlParameter('redirect');
|
||||
if (redirect) {
|
||||
browserHistory.push(decodeURIComponent(redirect));
|
||||
} else {
|
||||
this.finishSignin();
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
this.setState({serverLdapError: err.message});
|
||||
}
|
||||
);
|
||||
}
|
||||
handleLoginIdChange(e) {
|
||||
this.setState({
|
||||
loginId: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
handlePasswordChange(e) {
|
||||
this.setState({
|
||||
password: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
createCustomLogin() {
|
||||
if (global.window.mm_license.IsLicensed === 'true' &&
|
||||
global.window.mm_license.CustomBrand === 'true' &&
|
||||
@@ -158,6 +174,36 @@ export default class Login extends React.Component {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
createLoginPlaceholder(emailSigninEnabled, usernameSigninEnabled, ldapEnabled) {
|
||||
const loginPlaceholders = [];
|
||||
if (emailSigninEnabled) {
|
||||
loginPlaceholders.push(Utils.localizeMessage('login.email', 'Email'));
|
||||
}
|
||||
|
||||
if (usernameSigninEnabled) {
|
||||
loginPlaceholders.push(Utils.localizeMessage('login.username', 'Username'));
|
||||
}
|
||||
|
||||
if (ldapEnabled) {
|
||||
if (global.window.mm_config.LdapLoginFieldName) {
|
||||
loginPlaceholders.push(global.window.mm_config.LdapLoginFieldName);
|
||||
} else {
|
||||
loginPlaceholders.push(Utils.localizeMessage('login.ldap_username', 'LDAP Username'));
|
||||
}
|
||||
}
|
||||
|
||||
if (loginPlaceholders.length >= 2) {
|
||||
return loginPlaceholders.slice(0, loginPlaceholders.length - 1).join(', ') +
|
||||
Utils.localizeMessage('login.placeholderOr', ' or ') +
|
||||
loginPlaceholders[loginPlaceholders.length - 1];
|
||||
} else if (loginPlaceholders.length === 1) {
|
||||
return loginPlaceholders[0];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
createLoginOptions() {
|
||||
const extraParam = Utils.getUrlParameter('extra');
|
||||
let extraBox = '';
|
||||
@@ -248,76 +294,52 @@ export default class Login extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let emailLogin;
|
||||
if (emailSigninEnabled) {
|
||||
emailLogin = (
|
||||
<LoginEmail
|
||||
serverError={this.state.serverEmailError}
|
||||
submit={this.preSubmit}
|
||||
/>
|
||||
);
|
||||
let login = null;
|
||||
if (emailSigninEnabled || usernameSigninEnabled || ldapEnabled) {
|
||||
let errorClass = '';
|
||||
if (this.state.serverError) {
|
||||
errorClass = ' has-error';
|
||||
}
|
||||
|
||||
if (oauthLogins.length > 0) {
|
||||
emailLogin = (
|
||||
<div>
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
login = (
|
||||
<form onSubmit={this.preSubmit}>
|
||||
<div className='signup__email-container'>
|
||||
<FormError error={this.state.serverError}/>
|
||||
<div className={'form-group' + errorClass}>
|
||||
<input
|
||||
className='form-control'
|
||||
name='loginId'
|
||||
value={this.state.loginId}
|
||||
onChange={this.handleLoginIdChange}
|
||||
placeholder={this.createLoginPlaceholder(emailSigninEnabled, usernameSigninEnabled, ldapEnabled)}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
{emailLogin}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let usernameLogin;
|
||||
if (usernameSigninEnabled) {
|
||||
usernameLogin = (
|
||||
<LoginUsername
|
||||
serverError={this.state.serverUsernameError}
|
||||
submit={this.preSubmit}
|
||||
/>
|
||||
);
|
||||
|
||||
if (emailSigninEnabled || oauthLogins.length > 0) {
|
||||
usernameLogin = (
|
||||
<div>
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
<div className={'form-group' + errorClass}>
|
||||
<input
|
||||
type='password'
|
||||
className='form-control'
|
||||
name='password'
|
||||
value={this.state.password}
|
||||
onChange={this.handlePasswordChange}
|
||||
placeholder={Utils.localizeMessage('login.password', 'Password')}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
{usernameLogin}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let ldapLogin;
|
||||
if (ldapEnabled) {
|
||||
ldapLogin = (
|
||||
<LoginLdap
|
||||
serverError={this.state.serverLdapError}
|
||||
submit={this.preSubmit}
|
||||
/>
|
||||
);
|
||||
|
||||
if (emailSigninEnabled || usernameSigninEnabled || oauthLogins.length > 0) {
|
||||
ldapLogin = (
|
||||
<div>
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='login.or'
|
||||
defaultMessage='or'
|
||||
/>
|
||||
<div className='form-group'>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='login.signIn'
|
||||
defaultMessage='Sign in'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
{ldapLogin}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
const userSignUp = (
|
||||
@@ -358,14 +380,13 @@ export default class Login extends React.Component {
|
||||
<div>
|
||||
{extraBox}
|
||||
{oauthLogins}
|
||||
{emailLogin}
|
||||
{usernameLogin}
|
||||
{ldapLogin}
|
||||
{login}
|
||||
{userSignUp}
|
||||
{forgotPassword}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let content;
|
||||
let customContent;
|
||||
@@ -373,7 +394,6 @@ export default class Login extends React.Component {
|
||||
if (this.state.showMfa) {
|
||||
content = (
|
||||
<LoginMfa
|
||||
method={this.state.method}
|
||||
loginId={this.state.loginId}
|
||||
password={this.state.password}
|
||||
submit={this.submit}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import LoadingScreen from 'components/loading_screen.jsx';
|
||||
import LoginLdap from 'components/login/components/login_ldap.jsx';
|
||||
import * as GlobalActions from 'action_creators/global_actions.jsx';
|
||||
|
||||
import BrowserStore from 'stores/browser_store.jsx';
|
||||
@@ -25,7 +24,6 @@ class SignupUserComplete extends React.Component {
|
||||
super(props);
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.handleLdapSignup = this.handleLdapSignup.bind(this);
|
||||
|
||||
this.state = {
|
||||
data: '',
|
||||
@@ -150,26 +148,6 @@ class SignupUserComplete extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
handleLdapSignup(method, loginId, password, token) {
|
||||
Client.loginByLdap(loginId, password, token,
|
||||
() => {
|
||||
const redirect = Utils.getUrlParameter('redirect');
|
||||
if (redirect) {
|
||||
browserHistory.push(decodeURIComponent(redirect));
|
||||
} else {
|
||||
GlobalActions.emitInitialLoad(
|
||||
() => {
|
||||
browserHistory.push('/select_team');
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
this.setState({serverError: err.message});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -268,15 +246,13 @@ class SignupUserComplete extends React.Component {
|
||||
this.state.data,
|
||||
this.state.hash,
|
||||
this.state.inviteId,
|
||||
() => {
|
||||
(data) => {
|
||||
Client.track('signup', 'signup_user_02_complete');
|
||||
Client.login(
|
||||
user.email,
|
||||
null,
|
||||
Client.loginById(
|
||||
data.id,
|
||||
user.password,
|
||||
'',
|
||||
() => {
|
||||
UserStore.setLastEmail(user.email);
|
||||
if (this.state.hash > 0) {
|
||||
BrowserStore.setGlobalItem(this.state.hash, JSON.stringify({usedBefore: true}));
|
||||
}
|
||||
@@ -455,21 +431,6 @@ class SignupUserComplete extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let ldapSignup;
|
||||
if (global.window.mm_config.EnableLdap === 'true' && global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.LDAP) {
|
||||
ldapSignup = (
|
||||
<div className='inner__content'>
|
||||
<h5><strong>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.withLdap'
|
||||
defaultMessage='With your LDAP credentials'
|
||||
/>
|
||||
</strong></h5>
|
||||
<LoginLdap submit={this.handleLdapSignup}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let emailSignup;
|
||||
if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
|
||||
emailSignup = (
|
||||
@@ -533,7 +494,7 @@ class SignupUserComplete extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (signupMessage.length > 0 && (emailSignup || ldapSignup)) {
|
||||
if (signupMessage.length > 0 && emailSignup) {
|
||||
signupMessage = (
|
||||
<div>
|
||||
{signupMessage}
|
||||
@@ -547,21 +508,7 @@ class SignupUserComplete extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
if (ldapSignup && emailSignup) {
|
||||
ldapSignup = (
|
||||
<div>
|
||||
{ldapSignup}
|
||||
<div className='or__container'>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.or'
|
||||
defaultMessage='or'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (signupMessage.length === 0 && !emailSignup && !ldapSignup) {
|
||||
if (signupMessage.length === 0 && !emailSignup) {
|
||||
emailSignup = (
|
||||
<div>
|
||||
<FormattedMessage
|
||||
@@ -586,7 +533,6 @@ class SignupUserComplete extends React.Component {
|
||||
|
||||
if (this.state.noOpenServerError) {
|
||||
signupMessage = null;
|
||||
ldapSignup = null;
|
||||
emailSignup = null;
|
||||
terms = null;
|
||||
}
|
||||
@@ -620,7 +566,6 @@ class SignupUserComplete extends React.Component {
|
||||
/>
|
||||
</h4>
|
||||
{signupMessage}
|
||||
{ldapSignup}
|
||||
{emailSignup}
|
||||
{serverError}
|
||||
{terms}
|
||||
|
||||
@@ -953,41 +953,29 @@
|
||||
"login.changed": " Sign-in method changed successfully",
|
||||
"login.create": "Create one now",
|
||||
"login.createTeam": "Create a new team",
|
||||
"login.email": "Email",
|
||||
"login.find": "Find your other teams",
|
||||
"login.forgot": "I forgot my password",
|
||||
"login.loginIdRequired": "A {type} is required",
|
||||
"login.gitlab": "with GitLab",
|
||||
"login.google": "with Google Apps",
|
||||
"login.ldapUsername": "LDAP Username",
|
||||
"login.noAccount": "Don't have an account? ",
|
||||
"login.on": "on {siteName}",
|
||||
"login.or": "or",
|
||||
"login.password": "Password",
|
||||
"login.passwordChanged": " Password updated successfully",
|
||||
"login.passwordRequired": "A password is required",
|
||||
"login.session_expired": " Your session has expired. Please login again.",
|
||||
"login.signIn": "Sign in",
|
||||
"login.signTo": "Sign in to:",
|
||||
"login.username": "Username",
|
||||
"login.userNotFound": "We couldn't find an existing account matching your login credentials.",
|
||||
"login.verified": " Email Verified",
|
||||
"login_email.badTeam": "Bad team name",
|
||||
"login_email.email": "Email",
|
||||
"login_email.emailReq": "An email is required",
|
||||
"login_email.pwd": "Password",
|
||||
"login_email.pwdReq": "A password is required",
|
||||
"login_email.signin": "Sign in",
|
||||
"login_ldap.badTeam": "Bad team name",
|
||||
"login_ldap.idlReq": "An LDAP ID is required",
|
||||
"login_ldap.pwd": "LDAP Password",
|
||||
"login_ldap.pwdReq": "An LDAP password is required",
|
||||
"login_ldap.signin": "Sign in",
|
||||
"login_ldap.username": "LDAP Username",
|
||||
"login_mfa.enterToken": "To complete the sign in process, please enter a token from your smartphone's authenticator",
|
||||
"login_mfa.submit": "Submit",
|
||||
"login_mfa.token": "MFA Token",
|
||||
"login_mfa.tokenReq": "Please enter an MFA token",
|
||||
"login_username.badTeam": "Bad team name",
|
||||
"login_username.pwd": "Password",
|
||||
"login_username.pwdReq": "A password is required",
|
||||
"login_username.signin": "Sign in",
|
||||
"login_username.userNotFoundError": "We couldn't find an existing account matching your username for this team.",
|
||||
"login_username.username": "Username",
|
||||
"login_username.usernameReq": "A username is required",
|
||||
"login_username.verifyEmailError": "Please verify your email address. Check your inbox for an email.",
|
||||
"member_item.makeAdmin": "Make Admin",
|
||||
"member_item.member": "Member",
|
||||
"member_list.noUsersAdd": "No users to add.",
|
||||
|
||||
@@ -953,41 +953,27 @@
|
||||
"login.changed": " Cambiado el método de inicio de sesión satisfactoriamente",
|
||||
"login.create": "Crea una ahora",
|
||||
"login.createTeam": "Crear un nuevo equipo",
|
||||
"login.email": "Correo electrónico",
|
||||
"login.find": "Encuentra tus otros equipos",
|
||||
"login.forgot": "Olvide mi contraseña",
|
||||
"login.gitlab": "con GitLab",
|
||||
"login.google": "con Google Apps",
|
||||
"login.ldapUsername": "Usuario LDAP",
|
||||
"login.noAccount": "¿No tienes una cuenta? ",
|
||||
"login.on": "en {siteName}",
|
||||
"login.or": "o",
|
||||
"login.password": "Contraseña",
|
||||
"login.passwordChanged": " La contraseña ha sido actualizada",
|
||||
"login.passwordRequired": "La contraseña es obligatoria",
|
||||
"login.session_expired": " Tu sesión ha expirado. Por favor inicia sesión nuevamente.",
|
||||
"login.signIn": "Entrar",
|
||||
"login.signTo": "Ingresar a:",
|
||||
"login.username": "Nombre de usuario",
|
||||
"login.verified": " Correo electrónico Verificado",
|
||||
"login_email.badTeam": "Nombre de Equipo inválido",
|
||||
"login_email.email": "Correo electrónico",
|
||||
"login_email.emailReq": "El correo electrónico es obligatorio",
|
||||
"login_email.pwd": "Contraseña",
|
||||
"login_email.pwdReq": "La contraseña es obligatoria",
|
||||
"login_email.signin": "Entrar",
|
||||
"login_ldap.badTeam": "Nombre de Equipo inválido",
|
||||
"login_ldap.idlReq": "El ID de LDAP es obligatorio",
|
||||
"login_ldap.pwd": "Contraseña LDAP",
|
||||
"login_ldap.pwdReq": "La contraseña LDAP es obligatoria",
|
||||
"login_ldap.signin": "Entrar",
|
||||
"login_ldap.username": "Usuario LDAP",
|
||||
"login_mfa.enterToken": "Para completar el proceso de inicio de sesión, por favor ingresa el token provisto por el autenticador de tu teléfono inteligente",
|
||||
"login_mfa.submit": "Enviar",
|
||||
"login_mfa.token": "Token AMF",
|
||||
"login_mfa.tokenReq": "Por favor ingresa un token AMF",
|
||||
"login_username.badTeam": "Mal nombre de equipo",
|
||||
"login_username.pwd": "Contraseña",
|
||||
"login_username.pwdReq": "La contraseña es obligatoria",
|
||||
"login_username.signin": "Ingresar",
|
||||
"login_username.userNotFoundError": "No encontramos una cuenta existente que coincida con tu nombre de usuario en este equipo.",
|
||||
"login_username.username": "Nombre de usuario",
|
||||
"login_username.usernameReq": "El nombre de usuario es obligatorio",
|
||||
"login_username.verifyEmailError": "Por favor válida tu dirección de correo electrónico. Te hemos enviado un correo, revisa tu bandeja de entrada.",
|
||||
"member_item.makeAdmin": "Convertir en Admin de Equipo",
|
||||
"member_item.member": "Miembro",
|
||||
"member_list.noUsersAdd": "No hay usuarios que agregar.",
|
||||
|
||||
@@ -818,36 +818,22 @@
|
||||
"login.changed": "Méthode de connexion changée",
|
||||
"login.create": "Créer maintenant",
|
||||
"login.createTeam": "Créer une nouvelle équipe",
|
||||
"login.email": "Adresse électronique",
|
||||
"login.find": "Trouver vos autres équipes",
|
||||
"login.forgot": "Mot de passe perdu",
|
||||
"login.gitlab": "avec GitLab",
|
||||
"login.google": "avec Google Apps",
|
||||
"login.ldapUsername": "Utilisateur LDAP",
|
||||
"login.noAccount": "Pas de compte utilisateur ?",
|
||||
"login.on": "sur {siteName}",
|
||||
"login.or": "ou",
|
||||
"login.password": "Mot de passe",
|
||||
"login.passwordRequired": "Le mot de passe est obligatoire",
|
||||
"login.session_expired": "Votre session a expiré. Merci de vous reconnecter.",
|
||||
"login.signIn": "Connexion",
|
||||
"login.signTo": "Se connecter à :",
|
||||
"login.username": "Nom d'utilisateur",
|
||||
"login.verified": "Adresse électronique vérifiée",
|
||||
"login_email.badTeam": "Erreur dans le nom de l'équipe",
|
||||
"login_email.email": "Adresse électronique",
|
||||
"login_email.emailReq": "Une adresse électronique est obligatoire",
|
||||
"login_email.pwd": "Mot de passe",
|
||||
"login_email.pwdReq": "Le mot de passe est obligatoire",
|
||||
"login_email.signin": "Connexion",
|
||||
"login_ldap.badTeam": "Erreur dans le nom de l'équipe",
|
||||
"login_ldap.idlReq": "Un identifiant LDAP est obligatoire",
|
||||
"login_ldap.pwd": "Mot de passe LDAP",
|
||||
"login_ldap.pwdReq": "Un mot de passe LDAP est obligatoire",
|
||||
"login_ldap.signin": "Connexion",
|
||||
"login_ldap.username": "Utilisateur LDAP",
|
||||
"login_username.badTeam": "Erreur dans le nom de l'équipe",
|
||||
"login_username.pwd": "Mot de passe",
|
||||
"login_username.pwdReq": "Mot de passe obligatoire",
|
||||
"login_username.signin": "Connexion",
|
||||
"login_username.userNotFoundError": "Impossible de trouver un compte utilisateur à ce nom dans cette équipe.",
|
||||
"login_username.username": "Nom d'utilisateur",
|
||||
"login_username.usernameReq": "Le nom d'utilisateur est obligatoire",
|
||||
"login_username.verifyEmailError": "Vérifiez votre adresse électronique. Cherchez le courriel dans votre boîte de réception.",
|
||||
"member_item.makeAdmin": "Passer Administrateur",
|
||||
"member_item.member": "Membre",
|
||||
"member_list.noUsersAdd": "Aucun utilisateur à ajouter.",
|
||||
|
||||
@@ -915,40 +915,26 @@
|
||||
"login.changed": "サインイン方法が変更されました",
|
||||
"login.create": "ただいま作成しています",
|
||||
"login.createTeam": "新しいチームを作成する",
|
||||
"login.email": "電子メールアドレス",
|
||||
"login.find": "参加している他のチームを探す",
|
||||
"login.forgot": "パスワードを忘れました",
|
||||
"login.gitlab": "GitLabでログインする",
|
||||
"login.google": "Google Appsでログインする",
|
||||
"login.ldapUsername": "LDAPユーザー名",
|
||||
"login.noAccount": "アカウントを持っていますか? ",
|
||||
"login.on": "{siteName}にて",
|
||||
"login.or": "または",
|
||||
"login.password": "パスワード",
|
||||
"login.passwordRequired": "パスワードは必須です",
|
||||
"login.session_expired": " あなたのセッションは有効期限が切れました。再度ログインしてください。",
|
||||
"login.signIn": "利用登録",
|
||||
"login.signTo": "利用登録先: ",
|
||||
"login.username": "LDAPユーザー名",
|
||||
"login.verified": " 電子メールアドレスが確認されました",
|
||||
"login_email.badTeam": "無効なチーム名です",
|
||||
"login_email.email": "電子メールアドレス",
|
||||
"login_email.emailReq": "電子メールアドレスは必須です",
|
||||
"login_email.pwd": "パスワード",
|
||||
"login_email.pwdReq": "パスワードは必須です",
|
||||
"login_email.signin": "利用登録",
|
||||
"login_ldap.badTeam": "無効なチーム名です",
|
||||
"login_ldap.idlReq": "LDAP IDは必須です",
|
||||
"login_ldap.pwd": "LDAPパスワード",
|
||||
"login_ldap.pwdReq": "LDAPパスワードは必須です",
|
||||
"login_ldap.signin": "利用登録",
|
||||
"login_ldap.username": "LDAPユーザー名",
|
||||
"login_mfa.enterToken": "利用登録を完了するには、スマートフォンのauthenticatorからのトークンを入力してください。",
|
||||
"login_mfa.submit": "送信する",
|
||||
"login_mfa.token": "MFAトークン",
|
||||
"login_mfa.tokenReq": "MFAトークンを入力してください",
|
||||
"login_username.badTeam": "無効なチーム名です",
|
||||
"login_username.pwd": "パスワード",
|
||||
"login_username.pwdReq": "パスワードは必須です",
|
||||
"login_username.signin": "利用登録",
|
||||
"login_username.userNotFoundError": "このチームにはあなたのユーザー名に合致するアカウントはありません。",
|
||||
"login_username.username": "ユーザー名",
|
||||
"login_username.usernameReq": "ユーザー名は必須です",
|
||||
"login_username.verifyEmailError": "電子メールアドレスを確認します。電子メールの受信ボックスを見てみてください。",
|
||||
"member_item.makeAdmin": "管理者にする",
|
||||
"member_item.member": "メンバー",
|
||||
"member_list.noUsersAdd": "ユーザーは追加されません。",
|
||||
|
||||
@@ -911,40 +911,26 @@
|
||||
"login.changed": " Método de login alterada com sucesso",
|
||||
"login.create": "Crie um agora",
|
||||
"login.createTeam": "Criar uma nova equipe",
|
||||
"login.email": "E-mail",
|
||||
"login.find": "Encontre suas outras equipes",
|
||||
"login.forgot": "Eu esqueci a minha senha",
|
||||
"login.gitlab": "com GitLab",
|
||||
"login.google": "com Google Apps",
|
||||
"login.ldapUsername": "Usuário LDAP",
|
||||
"login.noAccount": "Não tem uma conta? ",
|
||||
"login.on": "no {siteName}",
|
||||
"login.or": "ou",
|
||||
"login.password": "Senha",
|
||||
"login.passwordRequired": "É necessário uma senha",
|
||||
"login.session_expired": " Sua sessão expirou. Por favor faça login novamente.",
|
||||
"login.signIn": "Login",
|
||||
"login.signTo": "Login em:",
|
||||
"login.username": "Usuário",
|
||||
"login.verified": " Email Verificado",
|
||||
"login_email.badTeam": "Nome ruim de equipe",
|
||||
"login_email.email": "E-mail",
|
||||
"login_email.emailReq": "Um email é necessário",
|
||||
"login_email.pwd": "Senha",
|
||||
"login_email.pwdReq": "É necessário uma senha",
|
||||
"login_email.signin": "Login",
|
||||
"login_ldap.badTeam": "Nome de equipe ruim",
|
||||
"login_ldap.idlReq": "Um ID LDAP é necessário",
|
||||
"login_ldap.pwd": "Senha LDAP",
|
||||
"login_ldap.pwdReq": "É necessário uma senha do LDAP",
|
||||
"login_ldap.signin": "Login",
|
||||
"login_ldap.username": "Usuário LDAP",
|
||||
"login_mfa.enterToken": "Para completar o login em processo, por favor entre um token do seu autenticador no smartphone",
|
||||
"login_mfa.submit": "Enviar",
|
||||
"login_mfa.token": "Token MFA",
|
||||
"login_mfa.tokenReq": "Por favor entre um token MFA",
|
||||
"login_username.badTeam": "Nome de equipe ruim",
|
||||
"login_username.pwd": "Senha",
|
||||
"login_username.pwdReq": "É necessário uma senha",
|
||||
"login_username.signin": "Login",
|
||||
"login_username.userNotFoundError": "Não foi possível encontrar uma conta existente que corresponda ao seu usuário para esta equipe.",
|
||||
"login_username.username": "Usuário",
|
||||
"login_username.usernameReq": "Um nome de usuário é necessário",
|
||||
"login_username.verifyEmailError": "Por favor verifique seu endereço de email. Verifique por um email na sua caixa de entrada.",
|
||||
"member_item.makeAdmin": "Tornar Admin",
|
||||
"member_item.member": "Membro",
|
||||
"member_list.noUsersAdd": "Nenhum usuário para adicionar.",
|
||||
|
||||
@@ -6,7 +6,6 @@ import EventEmitter from 'events';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
import BrowserStore from './browser_store.jsx';
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
const CHANGE_EVENT_SESSIONS = 'change_sessions';
|
||||
@@ -97,22 +96,6 @@ class UserStoreClass extends EventEmitter {
|
||||
return null;
|
||||
}
|
||||
|
||||
getLastEmail() {
|
||||
return BrowserStore.getGlobalItem('last_email', '');
|
||||
}
|
||||
|
||||
setLastEmail(email) {
|
||||
BrowserStore.setGlobalItem('last_email', email);
|
||||
}
|
||||
|
||||
getLastUsername() {
|
||||
return BrowserStore.getGlobalItem('last_username', '');
|
||||
}
|
||||
|
||||
setLastUsername(username) {
|
||||
BrowserStore.setGlobalItem('last_username', username);
|
||||
}
|
||||
|
||||
hasProfile(userId) {
|
||||
return this.getProfiles()[userId] != null;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,33 @@ describe('Client.User', function() {
|
||||
function() {
|
||||
client.login(
|
||||
user.email,
|
||||
user.password,
|
||||
null,
|
||||
function(data) {
|
||||
assert.equal(data.id.length > 0, true);
|
||||
assert.equal(data.email, user.email);
|
||||
done();
|
||||
},
|
||||
function(err) {
|
||||
done(new Error(err.message));
|
||||
}
|
||||
);
|
||||
},
|
||||
function(err) {
|
||||
done(new Error(err.message));
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('loginById', function(done) {
|
||||
var client = TestHelper.createClient();
|
||||
var user = TestHelper.fakeUser();
|
||||
client.createUser(
|
||||
user,
|
||||
function(newUser) {
|
||||
assert.equal(user.email, newUser.email);
|
||||
client.loginById(
|
||||
newUser.id,
|
||||
user.password,
|
||||
null,
|
||||
function(data) {
|
||||
@@ -86,40 +112,13 @@ describe('Client.User', function() {
|
||||
});
|
||||
|
||||
it('loginByUsername', function(done) {
|
||||
var client = TestHelper.createClient();
|
||||
var user = TestHelper.fakeUser();
|
||||
client.createUser(
|
||||
user,
|
||||
function() {
|
||||
client.login(
|
||||
null,
|
||||
user.username,
|
||||
user.password,
|
||||
null,
|
||||
function(data) {
|
||||
assert.equal(data.id.length > 0, true);
|
||||
assert.equal(data.email, user.email);
|
||||
done();
|
||||
},
|
||||
function(err) {
|
||||
done(new Error(err.message));
|
||||
}
|
||||
);
|
||||
},
|
||||
function(err) {
|
||||
done(new Error(err.message));
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('loginByLdap', function(done) {
|
||||
var client = TestHelper.createClient();
|
||||
client.enableLogErrorsToConsole(false); // Disabling since this unit test causes an error
|
||||
var user = TestHelper.fakeUser();
|
||||
client.createUser(
|
||||
user,
|
||||
function() {
|
||||
client.loginByLdap(
|
||||
client.login(
|
||||
user.username,
|
||||
user.password,
|
||||
null,
|
||||
@@ -127,7 +126,8 @@ describe('Client.User', function() {
|
||||
done(new Error());
|
||||
},
|
||||
function(err) {
|
||||
assert.equal(err.id, 'api.user.login_ldap.disabled.app_error');
|
||||
// should error out because logging in by username is disabled by default
|
||||
assert.equal(err.id, 'store.sql_user.get_for_login.app_error');
|
||||
done();
|
||||
}
|
||||
);
|
||||
@@ -372,7 +372,6 @@ describe('Client.User', function() {
|
||||
it('checkMfa', function(done) {
|
||||
TestHelper.initBasic(() => {
|
||||
TestHelper.basicClient().checkMfa(
|
||||
'email',
|
||||
TestHelper.generateId(),
|
||||
function(data) {
|
||||
assert.equal(data.mfa_required, 'false');
|
||||
|
||||
@@ -128,7 +128,6 @@ class TestHelperClass {
|
||||
outer.basicClient().setTeamId(outer.basict.id);
|
||||
outer.basicClient().login(
|
||||
rteamSignup.user.email,
|
||||
null,
|
||||
password,
|
||||
null,
|
||||
function() {
|
||||
|
||||
@@ -39,14 +39,13 @@ class WebClientClass extends Client {
|
||||
|
||||
// not sure why but super.login doesn't work if using an () => arrow functions.
|
||||
// I think this might be a webpack issue.
|
||||
webLogin(email, username, password, token, success, error) {
|
||||
webLogin(loginId, password, token, success, error) {
|
||||
this.login(
|
||||
email,
|
||||
username,
|
||||
loginId,
|
||||
password,
|
||||
token,
|
||||
(data) => {
|
||||
this.track('api', 'api_users_login_success', '', 'email', data.email);
|
||||
this.track('api', 'api_users_login_success', '', 'login_id', loginId);
|
||||
BrowserStore.signalLogin();
|
||||
|
||||
if (success) {
|
||||
@@ -54,7 +53,7 @@ class WebClientClass extends Client {
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
this.track('api', 'api_users_login_fail', name, 'email', email);
|
||||
this.track('api', 'api_users_login_fail', name, 'login_id', loginId);
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user