[MM-25645] api4/user: add migrate_auth endpoints (#14966)

* api4/user: add migrate_auth endpoints

* api4/user: reflect review comments

* add translations

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Ibrahim Serdar Acikgoz
2020-08-31 14:56:36 +03:00
коммит произвёл GitHub
родитель f12ca27bac
Коммит c30fea5f2d
5 изменённых файлов: 164 добавлений и 0 удалений

Просмотреть файл

@@ -85,6 +85,9 @@ func (api *API) InitUser() {
api.BaseRoutes.Users.Handle("/tokens/enable", api.ApiSessionRequired(enableUserAccessToken)).Methods("POST")
api.BaseRoutes.User.Handle("/typing", api.ApiSessionRequiredDisableWhenBusy(publishUserTyping)).Methods("POST")
api.BaseRoutes.Users.Handle("/migrate_auth/ldap", api.ApiSessionRequired(migrateAuthToLDAP)).Methods("POST")
api.BaseRoutes.Users.Handle("/migrate_auth/saml", api.ApiSessionRequired(migrateAuthToSaml)).Methods("POST")
}
func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -2555,3 +2558,101 @@ func convertUserToBot(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write(bot.ToJson())
}
func migrateAuthToLDAP(c *Context, w http.ResponseWriter, r *http.Request) {
props := model.StringInterfaceFromJson(r.Body)
from, ok := props["from"].(string)
if !ok {
c.SetInvalidParam("from")
return
}
if len(from) == 0 || (from != "email" && from != "gitlab" && from != "saml" && from != "google" && from != "office365") {
c.SetInvalidParam("from")
return
}
force, ok := props["force"].(bool)
if !ok {
c.SetInvalidParam("force")
return
}
matchField, ok := props["match_field"].(string)
if !ok {
c.SetInvalidParam("match_field")
return
}
auditRec := c.MakeAuditRecord("migrateAuthToLdap", audit.Fail)
defer c.LogAuditRec(auditRec)
auditRec.AddMeta("from", from)
auditRec.AddMeta("match_field", matchField)
auditRec.AddMeta("force", force)
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
return
}
if migrate := c.App.AccountMigration(); migrate != nil {
if err := migrate.MigrateToLdap(from, matchField, force, false); err != nil {
c.Err = model.NewAppError("api.migrateAuthToLdap", "api.migrate_to_saml.error", nil, err.Error(), http.StatusInternalServerError)
return
}
} else {
c.Err = model.NewAppError("api.migrateAuthToLdap", "api.admin.ldap.not_available.app_error", nil, "", http.StatusNotImplemented)
return
}
auditRec.Success()
ReturnStatusOK(w)
}
func migrateAuthToSaml(c *Context, w http.ResponseWriter, r *http.Request) {
props := model.StringInterfaceFromJson(r.Body)
from, ok := props["from"].(string)
if !ok {
c.SetInvalidParam("from")
return
}
if len(from) == 0 || (from != "email" && from != "gitlab" && from != "ldap" && from != "google" && from != "office365") {
c.SetInvalidParam("from")
return
}
auto, ok := props["auto"].(bool)
if !ok {
c.SetInvalidParam("auto")
return
}
matches, ok := props["matches"].(map[string]interface{})
if !ok {
c.SetInvalidParam("matches")
return
}
usersMap := model.MapFromJson(strings.NewReader(model.StringInterfaceToJson(matches)))
auditRec := c.MakeAuditRecord("migrateAuthToSaml", audit.Fail)
defer c.LogAuditRec(auditRec)
auditRec.AddMeta("from", from)
auditRec.AddMeta("matches", matches)
auditRec.AddMeta("auto", auto)
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
return
}
if migrate := c.App.AccountMigration(); migrate != nil {
if err := migrate.MigrateToSaml(from, usersMap, auto, false); err != nil {
c.Err = model.NewAppError("api.migrateAuthToSaml", "api.migrate_to_saml.error", nil, err.Error(), http.StatusInternalServerError)
return
}
} else {
c.Err = model.NewAppError("api.migrateAuthToSaml", "api.admin.saml.not_available.app_error", nil, "", http.StatusNotImplemented)
return
}
auditRec.Success()
ReturnStatusOK(w)
}

Просмотреть файл

@@ -35,6 +35,9 @@ func (api *API) InitUserLocal() {
api.BaseRoutes.Users.Handle("/tokens/revoke", api.ApiLocal(revokeUserAccessToken)).Methods("POST")
api.BaseRoutes.User.Handle("/tokens", api.ApiLocal(getUserAccessTokensForUser)).Methods("GET")
api.BaseRoutes.User.Handle("/tokens", api.ApiLocal(createUserAccessToken)).Methods("POST")
api.BaseRoutes.Users.Handle("/migrate_auth/ldap", api.ApiLocal(migrateAuthToLDAP)).Methods("POST")
api.BaseRoutes.Users.Handle("/migrate_auth/saml", api.ApiLocal(migrateAuthToSaml)).Methods("POST")
}
func localGetUsers(c *Context, w http.ResponseWriter, r *http.Request) {

Просмотреть файл

@@ -5182,3 +5182,29 @@ func TestConvertUserToBot(t *testing.T) {
require.NotNil(t, bot)
})
}
func TestMigrateAuthToLDAP(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
_, err := th.Client.MigrateAuthToLdap("email", "a", false)
CheckForbiddenStatus(t, err)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
_, err = client.MigrateAuthToLdap("email", "a", false)
CheckNotImplementedStatus(t, err)
})
}
func TestMigrateAuthToSAML(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
_, err := th.Client.MigrateAuthToSaml("email", map[string]string{"1": "a"}, true)
CheckForbiddenStatus(t, err)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
_, err = client.MigrateAuthToSaml("email", map[string]string{"1": "a"}, true)
CheckNotImplementedStatus(t, err)
})
}

Просмотреть файл

@@ -75,6 +75,10 @@
"id": "api.admin.get_brand_image.storage.app_error",
"translation": "Image storage is not configured."
},
{
"id": "api.admin.ldap.not_available.app_error",
"translation": "LDAP is not available."
},
{
"id": "api.admin.remove_certificate.delete.app_error",
"translation": "An error occurred while deleting the certificate."
@@ -1548,6 +1552,10 @@
"id": "api.marshal_error",
"translation": "marshal error"
},
{
"id": "api.migrate_to_saml.error",
"translation": "Unable to migrate SAML."
},
{
"id": "api.oauth.allow_oauth.redirect_callback.app_error",
"translation": "invalid_request: Supplied redirect_uri did not match registered callback_url."

Просмотреть файл

@@ -4053,6 +4053,32 @@ func (c *Client4) GetGroupsByUserId(userId string) ([]*Group, *Response) {
return GroupsFromJson(r.Body), BuildResponse(r)
}
func (c *Client4) MigrateAuthToLdap(fromAuthService string, matchField string, force bool) (bool, *Response) {
r, err := c.DoApiPost(c.GetUsersRoute()+"/migrate_auth/ldap", StringInterfaceToJson(map[string]interface{}{
"from": fromAuthService,
"force": force,
"match_field": matchField,
}))
if err != nil {
return false, BuildErrorResponse(r, err)
}
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
func (c *Client4) MigrateAuthToSaml(fromAuthService string, usersMap map[string]string, auto bool) (bool, *Response) {
r, err := c.DoApiPost(c.GetUsersRoute()+"/migrate_auth/saml", StringInterfaceToJson(map[string]interface{}{
"from": fromAuthService,
"auto": auto,
"matches": usersMap,
}))
if err != nil {
return false, BuildErrorResponse(r, err)
}
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
// Audits Section
// GetAudits returns a list of audits for the whole system.