github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/api4/ldap.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package api4
     5  
     6  import (
     7  	"encoding/json"
     8  	"mime/multipart"
     9  	"net/http"
    10  
    11  	"github.com/masterhung0112/hk_server/v5/audit"
    12  	"github.com/masterhung0112/hk_server/v5/model"
    13  )
    14  
    15  type mixedUnlinkedGroup struct {
    16  	Id           *string `json:"mattermost_group_id"`
    17  	DisplayName  string  `json:"name"`
    18  	RemoteId     string  `json:"primary_key"`
    19  	HasSyncables *bool   `json:"has_syncables"`
    20  }
    21  
    22  func (api *API) InitLdap() {
    23  	api.BaseRoutes.LDAP.Handle("/sync", api.ApiSessionRequired(syncLdap)).Methods("POST")
    24  	api.BaseRoutes.LDAP.Handle("/test", api.ApiSessionRequired(testLdap)).Methods("POST")
    25  	api.BaseRoutes.LDAP.Handle("/migrateid", api.ApiSessionRequired(migrateIdLdap)).Methods("POST")
    26  
    27  	// GET /api/v4/ldap/groups?page=0&per_page=1000
    28  	api.BaseRoutes.LDAP.Handle("/groups", api.ApiSessionRequired(getLdapGroups)).Methods("GET")
    29  
    30  	// POST /api/v4/ldap/groups/:remote_id/link
    31  	api.BaseRoutes.LDAP.Handle(`/groups/{remote_id}/link`, api.ApiSessionRequired(linkLdapGroup)).Methods("POST")
    32  
    33  	// DELETE /api/v4/ldap/groups/:remote_id/link
    34  	api.BaseRoutes.LDAP.Handle(`/groups/{remote_id}/link`, api.ApiSessionRequired(unlinkLdapGroup)).Methods("DELETE")
    35  
    36  	api.BaseRoutes.LDAP.Handle("/certificate/public", api.ApiSessionRequired(addLdapPublicCertificate)).Methods("POST")
    37  	api.BaseRoutes.LDAP.Handle("/certificate/private", api.ApiSessionRequired(addLdapPrivateCertificate)).Methods("POST")
    38  
    39  	api.BaseRoutes.LDAP.Handle("/certificate/public", api.ApiSessionRequired(removeLdapPublicCertificate)).Methods("DELETE")
    40  	api.BaseRoutes.LDAP.Handle("/certificate/private", api.ApiSessionRequired(removeLdapPrivateCertificate)).Methods("DELETE")
    41  
    42  }
    43  
    44  func syncLdap(c *Context, w http.ResponseWriter, r *http.Request) {
    45  	if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.LDAP {
    46  		c.Err = model.NewAppError("Api4.syncLdap", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented)
    47  		return
    48  	}
    49  
    50  	type LdapSyncOptions struct {
    51  		IncludeRemovedMembers bool `json:"include_removed_members"`
    52  	}
    53  	var opts LdapSyncOptions
    54  	json.NewDecoder(r.Body).Decode(&opts)
    55  
    56  	auditRec := c.MakeAuditRecord("syncLdap", audit.Fail)
    57  	defer c.LogAuditRec(auditRec)
    58  
    59  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_CREATE_LDAP_SYNC_JOB) {
    60  		c.SetPermissionError(model.PERMISSION_CREATE_LDAP_SYNC_JOB)
    61  		return
    62  	}
    63  
    64  	c.App.SyncLdap(opts.IncludeRemovedMembers)
    65  
    66  	auditRec.Success()
    67  	ReturnStatusOK(w)
    68  }
    69  
    70  func testLdap(c *Context, w http.ResponseWriter, r *http.Request) {
    71  	if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.LDAP {
    72  		c.Err = model.NewAppError("Api4.testLdap", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented)
    73  		return
    74  	}
    75  
    76  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_TEST_LDAP) {
    77  		c.SetPermissionError(model.PERMISSION_TEST_LDAP)
    78  		return
    79  	}
    80  
    81  	if err := c.App.TestLdap(); err != nil {
    82  		c.Err = err
    83  		return
    84  	}
    85  
    86  	ReturnStatusOK(w)
    87  }
    88  
    89  func getLdapGroups(c *Context, w http.ResponseWriter, r *http.Request) {
    90  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS) {
    91  		c.SetPermissionError(model.PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS)
    92  		return
    93  	}
    94  
    95  	if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.LDAPGroups {
    96  		c.Err = model.NewAppError("Api4.getLdapGroups", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented)
    97  		return
    98  	}
    99  
   100  	opts := model.LdapGroupSearchOpts{
   101  		Q: c.Params.Q,
   102  	}
   103  	if c.Params.IsLinked != nil {
   104  		opts.IsLinked = c.Params.IsLinked
   105  	}
   106  	if c.Params.IsConfigured != nil {
   107  		opts.IsConfigured = c.Params.IsConfigured
   108  	}
   109  
   110  	groups, total, err := c.App.GetAllLdapGroupsPage(c.Params.Page, c.Params.PerPage, opts)
   111  	if err != nil {
   112  		c.Err = err
   113  		return
   114  	}
   115  
   116  	mugs := []*mixedUnlinkedGroup{}
   117  	for _, group := range groups {
   118  		mug := &mixedUnlinkedGroup{
   119  			DisplayName: group.DisplayName,
   120  			RemoteId:    group.RemoteId,
   121  		}
   122  		if len(group.Id) == 26 {
   123  			mug.Id = &group.Id
   124  			mug.HasSyncables = &group.HasSyncables
   125  		}
   126  		mugs = append(mugs, mug)
   127  	}
   128  
   129  	b, marshalErr := json.Marshal(struct {
   130  		Count  int                   `json:"count"`
   131  		Groups []*mixedUnlinkedGroup `json:"groups"`
   132  	}{Count: total, Groups: mugs})
   133  	if marshalErr != nil {
   134  		c.Err = model.NewAppError("Api4.getLdapGroups", "api.marshal_error", nil, marshalErr.Error(), http.StatusInternalServerError)
   135  		return
   136  	}
   137  
   138  	w.Write(b)
   139  }
   140  
   141  func linkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) {
   142  	c.RequireRemoteId()
   143  	if c.Err != nil {
   144  		return
   145  	}
   146  
   147  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS) {
   148  		c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS)
   149  		return
   150  	}
   151  
   152  	auditRec := c.MakeAuditRecord("linkLdapGroup", audit.Fail)
   153  	defer c.LogAuditRec(auditRec)
   154  	auditRec.AddMeta("remote_id", c.Params.RemoteId)
   155  
   156  	if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.LDAPGroups {
   157  		c.Err = model.NewAppError("Api4.linkLdapGroup", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented)
   158  		return
   159  	}
   160  
   161  	ldapGroup, err := c.App.GetLdapGroup(c.Params.RemoteId)
   162  	if err != nil {
   163  		c.Err = err
   164  		return
   165  	}
   166  	auditRec.AddMeta("ldap_group", ldapGroup)
   167  
   168  	if ldapGroup == nil {
   169  		c.Err = model.NewAppError("Api4.linkLdapGroup", "api.ldap_group.not_found", nil, "", http.StatusNotFound)
   170  		return
   171  	}
   172  
   173  	group, err := c.App.GetGroupByRemoteID(ldapGroup.RemoteId, model.GroupSourceLdap)
   174  	if err != nil && err.Id != "app.group.no_rows" {
   175  		c.Err = err
   176  		return
   177  	}
   178  	if group != nil {
   179  		auditRec.AddMeta("group", group)
   180  	}
   181  
   182  	var status int
   183  	var newOrUpdatedGroup *model.Group
   184  
   185  	// Truncate display name if necessary
   186  	var displayName string
   187  	if len(ldapGroup.DisplayName) > model.GroupDisplayNameMaxLength {
   188  		displayName = ldapGroup.DisplayName[:model.GroupDisplayNameMaxLength]
   189  	} else {
   190  		displayName = ldapGroup.DisplayName
   191  	}
   192  
   193  	// Group has been previously linked
   194  	if group != nil {
   195  		if group.DeleteAt == 0 {
   196  			newOrUpdatedGroup = group
   197  		} else {
   198  			group.DeleteAt = 0
   199  			group.DisplayName = displayName
   200  			group.RemoteId = ldapGroup.RemoteId
   201  			newOrUpdatedGroup, err = c.App.UpdateGroup(group)
   202  			if err != nil {
   203  				c.Err = err
   204  				return
   205  			}
   206  		}
   207  		status = http.StatusOK
   208  	} else {
   209  		// Group has never been linked
   210  		//
   211  		// For group mentions implementation, the Name column will no longer be set by default.
   212  		// Instead it will be set and saved in the web app when Group Mentions is enabled.
   213  		newGroup := &model.Group{
   214  			DisplayName: displayName,
   215  			RemoteId:    ldapGroup.RemoteId,
   216  			Source:      model.GroupSourceLdap,
   217  		}
   218  		newOrUpdatedGroup, err = c.App.CreateGroup(newGroup)
   219  		if err != nil {
   220  			c.Err = err
   221  			return
   222  		}
   223  		status = http.StatusCreated
   224  	}
   225  
   226  	b, marshalErr := json.Marshal(newOrUpdatedGroup)
   227  	if marshalErr != nil {
   228  		c.Err = model.NewAppError("Api4.linkLdapGroup", "api.marshal_error", nil, marshalErr.Error(), http.StatusInternalServerError)
   229  		return
   230  	}
   231  
   232  	auditRec.Success()
   233  
   234  	w.WriteHeader(status)
   235  	w.Write(b)
   236  }
   237  
   238  func unlinkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) {
   239  	c.RequireRemoteId()
   240  	if c.Err != nil {
   241  		return
   242  	}
   243  
   244  	auditRec := c.MakeAuditRecord("unlinkLdapGroup", audit.Fail)
   245  	defer c.LogAuditRec(auditRec)
   246  	auditRec.AddMeta("remote_id", c.Params.RemoteId)
   247  
   248  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS) {
   249  		c.SetPermissionError(model.PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS)
   250  		return
   251  	}
   252  
   253  	if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.LDAPGroups {
   254  		c.Err = model.NewAppError("Api4.unlinkLdapGroup", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented)
   255  		return
   256  	}
   257  
   258  	group, err := c.App.GetGroupByRemoteID(c.Params.RemoteId, model.GroupSourceLdap)
   259  	if err != nil {
   260  		c.Err = err
   261  		return
   262  	}
   263  	auditRec.AddMeta("group", group)
   264  
   265  	if group.DeleteAt == 0 {
   266  		_, err = c.App.DeleteGroup(group.Id)
   267  		if err != nil {
   268  			c.Err = err
   269  			return
   270  		}
   271  	}
   272  
   273  	auditRec.Success()
   274  	ReturnStatusOK(w)
   275  }
   276  
   277  func migrateIdLdap(c *Context, w http.ResponseWriter, r *http.Request) {
   278  	props := model.StringInterfaceFromJson(r.Body)
   279  	toAttribute, ok := props["toAttribute"].(string)
   280  	if !ok || toAttribute == "" {
   281  		c.SetInvalidParam("toAttribute")
   282  		return
   283  	}
   284  
   285  	auditRec := c.MakeAuditRecord("idMigrateLdap", audit.Fail)
   286  	defer c.LogAuditRec(auditRec)
   287  
   288  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_MANAGE_SYSTEM) {
   289  		c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
   290  		return
   291  	}
   292  
   293  	if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.LDAP {
   294  		c.Err = model.NewAppError("Api4.idMigrateLdap", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented)
   295  		return
   296  	}
   297  
   298  	if err := c.App.MigrateIdLDAP(toAttribute); err != nil {
   299  		c.Err = err
   300  		return
   301  	}
   302  
   303  	auditRec.Success()
   304  	ReturnStatusOK(w)
   305  }
   306  
   307  func parseLdapCertificateRequest(r *http.Request, maxFileSize int64) (*multipart.FileHeader, *model.AppError) {
   308  	err := r.ParseMultipartForm(maxFileSize)
   309  	if err != nil {
   310  		return nil, model.NewAppError("addLdapCertificate", "api.admin.add_certificate.parseform.app_error", nil, err.Error(), http.StatusBadRequest)
   311  	}
   312  
   313  	m := r.MultipartForm
   314  
   315  	fileArray, ok := m.File["certificate"]
   316  	if !ok {
   317  		return nil, model.NewAppError("addLdapCertificate", "api.admin.add_certificate.no_file.app_error", nil, "", http.StatusBadRequest)
   318  	}
   319  
   320  	if len(fileArray) <= 0 {
   321  		return nil, model.NewAppError("addLdapCertificate", "api.admin.add_certificate.array.app_error", nil, "", http.StatusBadRequest)
   322  	}
   323  
   324  	return fileArray[0], nil
   325  }
   326  
   327  func addLdapPublicCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
   328  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_ADD_LDAP_PUBLIC_CERT) {
   329  		c.SetPermissionError(model.PERMISSION_ADD_LDAP_PUBLIC_CERT)
   330  		return
   331  	}
   332  
   333  	fileData, err := parseLdapCertificateRequest(r, *c.App.Config().FileSettings.MaxFileSize)
   334  	if err != nil {
   335  		c.Err = err
   336  		return
   337  	}
   338  
   339  	auditRec := c.MakeAuditRecord("addLdapPublicCertificate", audit.Fail)
   340  	defer c.LogAuditRec(auditRec)
   341  	auditRec.AddMeta("filename", fileData.Filename)
   342  
   343  	if err := c.App.AddLdapPublicCertificate(fileData); err != nil {
   344  		c.Err = err
   345  		return
   346  	}
   347  	auditRec.Success()
   348  	ReturnStatusOK(w)
   349  }
   350  
   351  func addLdapPrivateCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
   352  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_ADD_LDAP_PRIVATE_CERT) {
   353  		c.SetPermissionError(model.PERMISSION_ADD_LDAP_PRIVATE_CERT)
   354  		return
   355  	}
   356  
   357  	fileData, err := parseLdapCertificateRequest(r, *c.App.Config().FileSettings.MaxFileSize)
   358  	if err != nil {
   359  		c.Err = err
   360  		return
   361  	}
   362  
   363  	auditRec := c.MakeAuditRecord("addLdapPrivateCertificate", audit.Fail)
   364  	defer c.LogAuditRec(auditRec)
   365  	auditRec.AddMeta("filename", fileData.Filename)
   366  
   367  	if err := c.App.AddLdapPrivateCertificate(fileData); err != nil {
   368  		c.Err = err
   369  		return
   370  	}
   371  	auditRec.Success()
   372  	ReturnStatusOK(w)
   373  }
   374  
   375  func removeLdapPublicCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
   376  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_REMOVE_LDAP_PUBLIC_CERT) {
   377  		c.SetPermissionError(model.PERMISSION_REMOVE_LDAP_PUBLIC_CERT)
   378  		return
   379  	}
   380  
   381  	auditRec := c.MakeAuditRecord("removeLdapPublicCertificate", audit.Fail)
   382  	defer c.LogAuditRec(auditRec)
   383  
   384  	if err := c.App.RemoveLdapPublicCertificate(); err != nil {
   385  		c.Err = err
   386  		return
   387  	}
   388  
   389  	auditRec.Success()
   390  	ReturnStatusOK(w)
   391  }
   392  
   393  func removeLdapPrivateCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
   394  	if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PERMISSION_REMOVE_LDAP_PRIVATE_CERT) {
   395  		c.SetPermissionError(model.PERMISSION_REMOVE_LDAP_PRIVATE_CERT)
   396  		return
   397  	}
   398  
   399  	auditRec := c.MakeAuditRecord("removeLdapPrivateCertificate", audit.Fail)
   400  	defer c.LogAuditRec(auditRec)
   401  
   402  	if err := c.App.RemoveLdapPrivateCertificate(); err != nil {
   403  		c.Err = err
   404  		return
   405  	}
   406  
   407  	auditRec.Success()
   408  	ReturnStatusOK(w)
   409  }