Add the ability to switch from email to ldap and back
Этот коммит содержится в:
197
api/user.go
197
api/user.go
@@ -51,8 +51,6 @@ func InitUser(r *mux.Router) {
|
||||
sr.Handle("/login_ldap", ApiAppHandler(loginLdap)).Methods("POST")
|
||||
sr.Handle("/revoke_session", ApiUserRequired(revokeSession)).Methods("POST")
|
||||
sr.Handle("/attach_device", ApiUserRequired(attachDeviceId)).Methods("POST")
|
||||
sr.Handle("/switch_to_sso", ApiAppHandler(switchToSSO)).Methods("POST")
|
||||
sr.Handle("/switch_to_email", ApiUserRequired(switchToEmail)).Methods("POST")
|
||||
sr.Handle("/verify_email", ApiAppHandler(verifyEmail)).Methods("POST")
|
||||
sr.Handle("/resend_verification", ApiAppHandler(resendVerification)).Methods("POST")
|
||||
|
||||
@@ -67,6 +65,11 @@ func InitUser(r *mux.Router) {
|
||||
sr.Handle("/{id:[A-Za-z0-9]+}/sessions", ApiUserRequired(getSessions)).Methods("GET")
|
||||
sr.Handle("/{id:[A-Za-z0-9]+}/audits", ApiUserRequired(getAudits)).Methods("GET")
|
||||
sr.Handle("/{id:[A-Za-z0-9]+}/image", ApiUserRequired(getProfileImage)).Methods("GET")
|
||||
|
||||
sr.Handle("/claim/email_to_oauth", ApiAppHandler(emailToOAuth)).Methods("POST")
|
||||
sr.Handle("/claim/oauth_to_email", ApiUserRequired(oauthToEmail)).Methods("POST")
|
||||
sr.Handle("/claim/email_to_ldap", ApiAppHandler(emailToLdap)).Methods("POST")
|
||||
sr.Handle("/claim/ldap_to_email", ApiAppHandler(ldapToEmail)).Methods("POST")
|
||||
}
|
||||
|
||||
func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
@@ -2047,30 +2050,30 @@ func IsUsernameTaken(name string, teamId string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func switchToSSO(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
func emailToOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
password := props["password"]
|
||||
if len(password) == 0 {
|
||||
c.SetInvalidParam("switchToSSO", "password")
|
||||
c.SetInvalidParam("emailToOAuth", "password")
|
||||
return
|
||||
}
|
||||
|
||||
teamName := props["team_name"]
|
||||
if len(teamName) == 0 {
|
||||
c.SetInvalidParam("switchToSSO", "team_name")
|
||||
c.SetInvalidParam("emailToOAuth", "team_name")
|
||||
return
|
||||
}
|
||||
|
||||
service := props["service"]
|
||||
if len(service) == 0 {
|
||||
c.SetInvalidParam("switchToSSO", "service")
|
||||
c.SetInvalidParam("emailToOAuth", "service")
|
||||
return
|
||||
}
|
||||
|
||||
email := props["email"]
|
||||
if len(email) == 0 {
|
||||
c.SetInvalidParam("switchToSSO", "email")
|
||||
c.SetInvalidParam("emailToOAuth", "email")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2162,24 +2165,24 @@ func CompleteSwitchWithOAuth(c *Context, w http.ResponseWriter, r *http.Request,
|
||||
sendSignInChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), strings.Title(service)+" SSO")
|
||||
}
|
||||
|
||||
func switchToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
func oauthToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
password := props["password"]
|
||||
if len(password) == 0 {
|
||||
c.SetInvalidParam("switchToEmail", "password")
|
||||
c.SetInvalidParam("oauthToEmail", "password")
|
||||
return
|
||||
}
|
||||
|
||||
teamName := props["team_name"]
|
||||
if len(teamName) == 0 {
|
||||
c.SetInvalidParam("switchToEmail", "team_name")
|
||||
c.SetInvalidParam("oauthToEmail", "team_name")
|
||||
return
|
||||
}
|
||||
|
||||
email := props["email"]
|
||||
if len(email) == 0 {
|
||||
c.SetInvalidParam("switchToEmail", "email")
|
||||
c.SetInvalidParam("oauthToEmail", "email")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2205,7 +2208,7 @@ func switchToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if user.Id != c.Session.UserId {
|
||||
c.LogAudit("fail - user ids didn't match")
|
||||
c.Err = model.NewLocAppError("switchToEmail", "api.user.switch_to_email.context.app_error", nil, "")
|
||||
c.Err = model.NewLocAppError("oauthToEmail", "api.user.oauth_to_email.context.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusForbidden
|
||||
return
|
||||
}
|
||||
@@ -2230,6 +2233,176 @@ func switchToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(model.MapToJson(m)))
|
||||
}
|
||||
|
||||
func emailToLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
email := props["email"]
|
||||
if len(email) == 0 {
|
||||
c.SetInvalidParam("emailToLdap", "email")
|
||||
return
|
||||
}
|
||||
|
||||
emailPassword := props["email_password"]
|
||||
if len(emailPassword) == 0 {
|
||||
c.SetInvalidParam("emailToLdap", "email_password")
|
||||
return
|
||||
}
|
||||
|
||||
teamName := props["team_name"]
|
||||
if len(teamName) == 0 {
|
||||
c.SetInvalidParam("emailToLdap", "team_name")
|
||||
return
|
||||
}
|
||||
|
||||
ldapId := props["ldap_id"]
|
||||
if len(ldapId) == 0 {
|
||||
c.SetInvalidParam("emailToLdap", "ldap_id")
|
||||
return
|
||||
}
|
||||
|
||||
ldapPassword := props["ldap_password"]
|
||||
if len(ldapPassword) == 0 {
|
||||
c.SetInvalidParam("emailToLdap", "ldap_password")
|
||||
return
|
||||
}
|
||||
|
||||
c.LogAudit("attempt")
|
||||
|
||||
var team *model.Team
|
||||
if result := <-Srv.Store.Team().GetByName(teamName); result.Err != nil {
|
||||
c.LogAudit("fail - couldn't get team")
|
||||
c.Err = result.Err
|
||||
return
|
||||
} else {
|
||||
team = result.Data.(*model.Team)
|
||||
}
|
||||
|
||||
var user *model.User
|
||||
if result := <-Srv.Store.User().GetByEmail(team.Id, email); result.Err != nil {
|
||||
c.LogAudit("fail - couldn't get user")
|
||||
c.Err = result.Err
|
||||
return
|
||||
} else {
|
||||
user = result.Data.(*model.User)
|
||||
}
|
||||
|
||||
if !checkUserLoginAttempts(c, user) || !checkUserPassword(c, user, emailPassword) {
|
||||
c.LogAuditWithUserId(user.Id, "fail - invalid email password")
|
||||
return
|
||||
}
|
||||
|
||||
RevokeAllSession(c, user.Id)
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ldapInterface := einterfaces.GetLdapInterface()
|
||||
if ldapInterface == nil {
|
||||
c.Err = model.NewLocAppError("emailToLdap", "api.user.email_to_ldap.not_available.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusNotImplemented
|
||||
return
|
||||
}
|
||||
|
||||
if err := ldapInterface.DoSwitch(user.Id, ldapId, ldapPassword); err != nil {
|
||||
c.LogAuditWithUserId(user.Id, "fail - ldap switch failed")
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
sendSignInChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), "LDAP")
|
||||
|
||||
m := map[string]string{}
|
||||
m["follow_link"] = c.GetTeamURL() + "/login?extra=signin_change"
|
||||
|
||||
c.LogAudit("success")
|
||||
w.Write([]byte(model.MapToJson(m)))
|
||||
}
|
||||
|
||||
func ldapToEmail(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
email := props["email"]
|
||||
if len(email) == 0 {
|
||||
c.SetInvalidParam("ldapToEmail", "email")
|
||||
return
|
||||
}
|
||||
|
||||
emailPassword := props["email_password"]
|
||||
if len(emailPassword) == 0 {
|
||||
c.SetInvalidParam("ldapToEmail", "email_password")
|
||||
return
|
||||
}
|
||||
|
||||
teamName := props["team_name"]
|
||||
if len(teamName) == 0 {
|
||||
c.SetInvalidParam("ldapToEmail", "team_name")
|
||||
return
|
||||
}
|
||||
|
||||
ldapPassword := props["ldap_password"]
|
||||
if len(ldapPassword) == 0 {
|
||||
c.SetInvalidParam("ldapToEmail", "ldap_password")
|
||||
return
|
||||
}
|
||||
|
||||
c.LogAudit("attempt")
|
||||
|
||||
var team *model.Team
|
||||
if result := <-Srv.Store.Team().GetByName(teamName); result.Err != nil {
|
||||
c.LogAudit("fail - couldn't get team")
|
||||
c.Err = result.Err
|
||||
return
|
||||
} else {
|
||||
team = result.Data.(*model.Team)
|
||||
}
|
||||
|
||||
var user *model.User
|
||||
if result := <-Srv.Store.User().GetByEmail(team.Id, email); result.Err != nil {
|
||||
c.LogAudit("fail - couldn't get user")
|
||||
c.Err = result.Err
|
||||
return
|
||||
} else {
|
||||
user = result.Data.(*model.User)
|
||||
}
|
||||
|
||||
if user.AuthService != model.USER_AUTH_SERVICE_LDAP {
|
||||
c.Err = model.NewLocAppError("ldapToEmail", "api.user.ldap_to_email.not_ldap_account.app_error", nil, "")
|
||||
return
|
||||
}
|
||||
|
||||
ldapInterface := einterfaces.GetLdapInterface()
|
||||
if ldapInterface == nil {
|
||||
c.Err = model.NewLocAppError("ldapToEmail", "api.user.ldap_to_email.not_available.app_error", nil, "")
|
||||
c.Err.StatusCode = http.StatusNotImplemented
|
||||
return
|
||||
}
|
||||
|
||||
if err := ldapInterface.CheckPassword(user.AuthData, ldapPassword); err != nil {
|
||||
c.LogAuditWithUserId(user.Id, "fail - ldap authentication failed")
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.User().UpdatePassword(user.Id, model.HashPassword(emailPassword)); result.Err != nil {
|
||||
c.LogAudit("fail - database issue")
|
||||
c.Err = result.Err
|
||||
return
|
||||
}
|
||||
|
||||
RevokeAllSession(c, user.Id)
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sendSignInChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), c.T("api.templates.signin_change_email.body.method_email"))
|
||||
|
||||
m := map[string]string{}
|
||||
m["follow_link"] = c.GetTeamURL() + "/login?extra=signin_change"
|
||||
|
||||
c.LogAudit("success")
|
||||
w.Write([]byte(model.MapToJson(m)))
|
||||
}
|
||||
|
||||
func sendSignInChangeEmailAndForget(c *Context, email, teamDisplayName, teamURL, siteURL, method string) {
|
||||
go func() {
|
||||
|
||||
|
||||
145
api/user_test.go
145
api/user_test.go
@@ -1161,7 +1161,7 @@ func TestStatuses(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestSwitchToSSO(t *testing.T) {
|
||||
func TestEmailToOAuth(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
@@ -1172,45 +1172,45 @@ func TestSwitchToSSO(t *testing.T) {
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
m := map[string]string{}
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.EmailToOAuth(m); err == nil {
|
||||
t.Fatal("should have failed - empty data")
|
||||
}
|
||||
|
||||
m["password"] = "pwd"
|
||||
_, err := Client.SwitchToSSO(m)
|
||||
_, err := Client.EmailToOAuth(m)
|
||||
if err == nil {
|
||||
t.Fatal("should have failed - missing team_name, service, email")
|
||||
}
|
||||
|
||||
m["team_name"] = team.Name
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.EmailToOAuth(m); err == nil {
|
||||
t.Fatal("should have failed - missing service, email")
|
||||
}
|
||||
|
||||
m["service"] = "someservice"
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.EmailToOAuth(m); err == nil {
|
||||
t.Fatal("should have failed - missing email")
|
||||
}
|
||||
|
||||
m["team_name"] = "junk"
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.EmailToOAuth(m); err == nil {
|
||||
t.Fatal("should have failed - bad team name")
|
||||
}
|
||||
|
||||
m["team_name"] = team.Name
|
||||
m["email"] = "junk"
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.EmailToOAuth(m); err == nil {
|
||||
t.Fatal("should have failed - bad email")
|
||||
}
|
||||
|
||||
m["email"] = ruser.Email
|
||||
m["password"] = "junk"
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.EmailToOAuth(m); err == nil {
|
||||
t.Fatal("should have failed - bad password")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSwitchToEmail(t *testing.T) {
|
||||
func TestOAuthToEmail(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
@@ -1225,45 +1225,158 @@ func TestSwitchToEmail(t *testing.T) {
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser2.Id))
|
||||
|
||||
m := map[string]string{}
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.OAuthToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.OAuthToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - empty data")
|
||||
}
|
||||
|
||||
m["password"] = "pwd"
|
||||
_, err := Client.SwitchToSSO(m)
|
||||
_, err := Client.OAuthToEmail(m)
|
||||
if err == nil {
|
||||
t.Fatal("should have failed - missing team_name, service, email")
|
||||
}
|
||||
|
||||
m["team_name"] = team.Name
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.OAuthToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - missing email")
|
||||
}
|
||||
|
||||
m["email"] = ruser.Email
|
||||
m["team_name"] = "junk"
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.OAuthToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - bad team name")
|
||||
}
|
||||
|
||||
m["team_name"] = team.Name
|
||||
m["email"] = "junk"
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.OAuthToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - bad email")
|
||||
}
|
||||
|
||||
m["email"] = ruser2.Email
|
||||
if _, err := Client.SwitchToSSO(m); err == nil {
|
||||
if _, err := Client.OAuthToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - wrong user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLDAPToEmail(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
|
||||
m := map[string]string{}
|
||||
if _, err := Client.LDAPToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - empty data")
|
||||
}
|
||||
|
||||
m["email_password"] = "pwd"
|
||||
_, err := Client.LDAPToEmail(m)
|
||||
if err == nil {
|
||||
t.Fatal("should have failed - missing team_name, ldap_password, email")
|
||||
}
|
||||
|
||||
m["team_name"] = team.Name
|
||||
if _, err := Client.LDAPToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - missing email, ldap_password")
|
||||
}
|
||||
|
||||
m["ldap_password"] = "pwd"
|
||||
if _, err := Client.LDAPToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - missing email")
|
||||
}
|
||||
|
||||
m["email"] = ruser.Email
|
||||
m["team_name"] = "junk"
|
||||
if _, err := Client.LDAPToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - bad team name")
|
||||
}
|
||||
|
||||
m["team_name"] = team.Name
|
||||
m["email"] = "junk"
|
||||
if _, err := Client.LDAPToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - bad email")
|
||||
}
|
||||
|
||||
m["email"] = user.Email
|
||||
if _, err := Client.LDAPToEmail(m); err == nil {
|
||||
t.Fatal("should have failed - user is not an LDAP user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmailToLDAP(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
|
||||
m := map[string]string{}
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - empty data")
|
||||
}
|
||||
|
||||
m["email_password"] = "pwd"
|
||||
_, err := Client.EmailToLDAP(m)
|
||||
if err == nil {
|
||||
t.Fatal("should have failed - missing team_name, ldap_id, ldap_password, email")
|
||||
}
|
||||
|
||||
m["team_name"] = team.Name
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - missing email, ldap_password, ldap_id")
|
||||
}
|
||||
|
||||
m["ldap_id"] = "someid"
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - missing email, ldap_password")
|
||||
}
|
||||
|
||||
m["ldap_password"] = "pwd"
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - missing email")
|
||||
}
|
||||
|
||||
m["email"] = ruser.Email
|
||||
m["team_name"] = "junk"
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - bad team name")
|
||||
}
|
||||
|
||||
m["team_name"] = team.Name
|
||||
m["email"] = "junk"
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - bad email")
|
||||
}
|
||||
|
||||
m["email"] = user.Email
|
||||
m["email_password"] = "junk"
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - bad password")
|
||||
}
|
||||
|
||||
m["email_password"] = "pwd"
|
||||
if _, err := Client.EmailToLDAP(m); err == nil {
|
||||
t.Fatal("should have failed - missing ldap bits or user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeLoggedIn(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user