diff options
Diffstat (limited to 'api4')
-rw-r--r-- | api4/user.go | 34 | ||||
-rw-r--r-- | api4/user_test.go | 87 |
2 files changed, 101 insertions, 20 deletions
diff --git a/api4/user.go b/api4/user.go index 2292544c4..2b79b19f1 100644 --- a/api4/user.go +++ b/api4/user.go @@ -22,6 +22,7 @@ func (api *API) InitUser() { api.BaseRoutes.Users.Handle("/usernames", api.ApiSessionRequired(getUsersByNames)).Methods("POST") api.BaseRoutes.Users.Handle("/search", api.ApiSessionRequired(searchUsers)).Methods("POST") api.BaseRoutes.Users.Handle("/autocomplete", api.ApiSessionRequired(autocompleteUsers)).Methods("GET") + api.BaseRoutes.Users.Handle("/stats", api.ApiSessionRequired(getTotalUsersStats)).Methods("GET") api.BaseRoutes.User.Handle("", api.ApiSessionRequired(getUser)).Methods("GET") api.BaseRoutes.User.Handle("/image", api.ApiSessionRequiredTrustRequester(getProfileImage)).Methods("GET") @@ -278,6 +279,20 @@ func setProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { ReturnStatusOK(w) } +func getTotalUsersStats(c *Context, w http.ResponseWriter, r *http.Request) { + if c.Err != nil { + return + } + + if stats, err := c.App.GetTotalUsersStats(); err != nil { + c.Err = err + return + } else { + w.Write([]byte(stats.ToJson())) + return + } +} + func getUsers(c *Context, w http.ResponseWriter, r *http.Request) { inTeamId := r.URL.Query().Get("in_team") notInTeamId := r.URL.Query().Get("not_in_team") @@ -968,8 +983,27 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) { deviceId := props["device_id"] ldapOnly := props["ldap_only"] == "true" + if *c.App.Config().ExperimentalSettings.ClientSideCertEnable { + if license := c.App.License(); license == nil || !*license.Features.SAML { + c.Err = model.NewAppError("ClientSideCertNotAllowed", "Attempt to use the experimental feature ClientSideCertEnable without a valid enterprise license", nil, "", http.StatusBadRequest) + return + } else { + certPem, certSubject, certEmail := c.App.CheckForClienSideCert(r) + mlog.Debug("Client Cert", mlog.String("cert_subject", certSubject), mlog.String("cert_email", certEmail)) + + if len(certPem) == 0 || len(certEmail) == 0 { + c.Err = model.NewAppError("ClientSideCertMissing", "Attempted to sign in using the experimental feature ClientSideCert without providing a valid certificate", nil, "", http.StatusBadRequest) + return + } else if *c.App.Config().ExperimentalSettings.ClientSideCertCheck == model.CLIENT_SIDE_CERT_CHECK_PRIMARY_AUTH { + loginId = certEmail + password = "certificate" + } + } + } + c.LogAuditWithUserId(id, "attempt - login_id="+loginId) user, err := c.App.AuthenticateUserForLogin(id, loginId, password, mfaToken, ldapOnly) + if err != nil { c.LogAuditWithUserId(id, "failure - login_id="+loginId) c.Err = err diff --git a/api4/user_test.go b/api4/user_test.go index 1044e6162..96aa55d5f 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -909,6 +909,21 @@ func TestGetUsersByUsernames(t *testing.T) { CheckUnauthorizedStatus(t, resp) } +func TestGetTotalUsersStat(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer th.TearDown() + Client := th.Client + + total := <-th.App.Srv.Store.User().GetTotalUsersCount() + + rstats, resp := Client.GetTotalUsersStats("") + CheckNoError(t, resp) + + if rstats.TotalUsersCount != total.Data.(int64) { + t.Fatal("wrong count") + } +} + func TestUpdateUser(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -1837,30 +1852,23 @@ func TestUpdateUserPassword(t *testing.T) { /*func TestResetPassword(t *testing.T) { th := Setup().InitBasic() Client := th.Client - Client.Logout() - user := th.BasicUser - // Delete all the messages before check the reset password utils.DeleteMailBox(user.Email) - success, resp := Client.SendPasswordResetEmail(user.Email) CheckNoError(t, resp) if !success { t.Fatal("should have succeeded") } - _, resp = Client.SendPasswordResetEmail("") CheckBadRequestStatus(t, resp) - // Should not leak whether the email is attached to an account or not success, resp = Client.SendPasswordResetEmail("notreal@example.com") CheckNoError(t, resp) if !success { t.Fatal("should have succeeded") } - // Check if the email was send to the right email address and the recovery key match var resultsMailbox utils.JSONMessageHeaderInbucket err := utils.RetryInbucket(5, func() error { @@ -1872,7 +1880,6 @@ func TestUpdateUserPassword(t *testing.T) { t.Log(err) t.Log("No email was received, maybe due load on the server. Disabling this verification") } - var recoveryTokenString string if err == nil && len(resultsMailbox) > 0 { if !strings.ContainsAny(resultsMailbox[0].To[0], user.Email) { @@ -1889,7 +1896,6 @@ func TestUpdateUserPassword(t *testing.T) { } } } - var recoveryToken *model.Token if result := <-th.App.Srv.Store.Token().GetByToken(recoveryTokenString); result.Err != nil { t.Log(recoveryTokenString) @@ -1897,44 +1903,33 @@ func TestUpdateUserPassword(t *testing.T) { } else { recoveryToken = result.Data.(*model.Token) } - _, resp = Client.ResetPassword(recoveryToken.Token, "") CheckBadRequestStatus(t, resp) - _, resp = Client.ResetPassword(recoveryToken.Token, "newp") CheckBadRequestStatus(t, resp) - _, resp = Client.ResetPassword("", "newpwd") CheckBadRequestStatus(t, resp) - _, resp = Client.ResetPassword("junk", "newpwd") CheckBadRequestStatus(t, resp) - code := "" for i := 0; i < model.TOKEN_SIZE; i++ { code += "a" } - _, resp = Client.ResetPassword(code, "newpwd") CheckBadRequestStatus(t, resp) - success, resp = Client.ResetPassword(recoveryToken.Token, "newpwd") CheckNoError(t, resp) if !success { t.Fatal("should have succeeded") } - Client.Login(user.Email, "newpwd") Client.Logout() - _, resp = Client.ResetPassword(recoveryToken.Token, "newpwd") CheckBadRequestStatus(t, resp) - authData := model.NewId() if result := <-app.Srv.Store.User().UpdateAuthData(user.Id, "random", &authData, "", true); result.Err != nil { t.Fatal(result.Err) } - _, resp = Client.SendPasswordResetEmail(user.Email) CheckBadRequestStatus(t, resp) }*/ @@ -2240,6 +2235,58 @@ func TestSetProfileImage(t *testing.T) { t.Fatal(err) } } +func TestCBALogin(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + Client := th.Client + Client.Logout() + + th.App.SetLicense(model.NewTestLicense("saml")) + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ExperimentalSettings.ClientSideCertEnable = true + *cfg.ExperimentalSettings.ClientSideCertCheck = model.CLIENT_SIDE_CERT_CHECK_PRIMARY_AUTH + }) + + user, resp := Client.Login(th.BasicUser.Email, th.BasicUser.Password) + if resp.Error.StatusCode != 400 && user == nil { + t.Fatal("Should have failed because it's missing the cert header") + } + + Client.HttpHeader["X-SSL-Client-Cert"] = "valid_cert_fake" + user, resp = Client.Login(th.BasicUser.Email, th.BasicUser.Password) + if resp.Error.StatusCode != 400 && user == nil { + t.Fatal("Should have failed because it's missing the cert subject") + } + + Client.HttpHeader["X-SSL-Client-Cert-Subject-DN"] = "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=mis_match" + th.BasicUser.Email + user, resp = Client.Login(th.BasicUser.Email, "") + if resp.Error.StatusCode != 400 && user == nil { + t.Fatal("Should have failed because the emails mismatch") + } + + Client.HttpHeader["X-SSL-Client-Cert-Subject-DN"] = "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=" + th.BasicUser.Email + user, resp = Client.Login(th.BasicUser.Email, "") + if !(user != nil && user.Email == th.BasicUser.Email) { + t.Fatal("Should have been able to login") + } + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ExperimentalSettings.ClientSideCertEnable = true + *cfg.ExperimentalSettings.ClientSideCertCheck = model.CLIENT_SIDE_CERT_CHECK_SECONDARY_AUTH + }) + + Client.HttpHeader["X-SSL-Client-Cert-Subject-DN"] = "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=" + th.BasicUser.Email + user, resp = Client.Login(th.BasicUser.Email, "") + if resp.Error.StatusCode != 400 && user == nil { + t.Fatal("Should have failed because password is required") + } + + Client.HttpHeader["X-SSL-Client-Cert-Subject-DN"] = "C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=" + th.BasicUser.Email + user, resp = Client.Login(th.BasicUser.Email, th.BasicUser.Password) + if !(user != nil && user.Email == th.BasicUser.Email) { + t.Fatal("Should have been able to login") + } +} func TestSwitchAccount(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() |