github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/access_control.go (about) 1 /* 2 * Copyright 2020 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. 3 */ 4 5 package govcd 6 7 import ( 8 "bytes" 9 "encoding/xml" 10 "fmt" 11 "net/http" 12 "net/url" 13 "strings" 14 15 "github.com/vmware/go-vcloud-director/v2/types/v56" 16 ) 17 18 // orgInfoCache is a cache to save org information, avoid repeated calls to compute the same result. 19 // The keys to this map are the requesting objects IDs. 20 var orgInfoCache = make(map[string]*TenantContext) 21 22 // GetAccessControl retrieves the access control information for the requested entity 23 func (client Client) GetAccessControl(href, entityType, entityName string, headerValues map[string]string) (*types.ControlAccessParams, error) { 24 25 href += "/controlAccess" 26 var controlAccess types.ControlAccessParams 27 28 acUrl, err := url.ParseRequestURI(href) 29 if err != nil { 30 return nil, fmt.Errorf("[client.GetAccessControl] error parsing HREF %s: %s", href, err) 31 } 32 var additionalHeader = make(http.Header) 33 34 if len(headerValues) > 0 { 35 for k, v := range headerValues { 36 additionalHeader.Add(k, v) 37 } 38 } 39 req := client.newRequest( 40 nil, // params 41 nil, // notEncodedParams 42 http.MethodGet, // method 43 *acUrl, // reqUrl 44 nil, // body 45 client.APIVersion, // apiVersion 46 additionalHeader, // additionalHeader 47 ) 48 49 resp, err := checkResp(client.Http.Do(req)) 50 if err != nil { 51 return nil, fmt.Errorf("[client.GetAccessControl] error checking response to request %s: %s", href, err) 52 } 53 if resp == nil { 54 return nil, fmt.Errorf("[client.GetAccessControl] nil response received") 55 } 56 if err = decodeBody(types.BodyTypeXML, resp, &controlAccess); err != nil { 57 return nil, fmt.Errorf("[client.GetAccessControl] error decoding response: %s", err) 58 } 59 60 return &controlAccess, nil 61 } 62 63 // SetAccessControl changes the access control information for this entity 64 // There are two ways of setting the access: 65 // with accessControl.IsSharedToEveryone = true we give access to everyone 66 // with accessControl.IsSharedToEveryone = false, accessControl.AccessSettings defines which subjects can access the vApp 67 // For each setting we must provide: 68 // * The subject (HREF and Type are mandatory) 69 // * The access level (one of ReadOnly, Change, FullControl) 70 func (client *Client) SetAccessControl(accessControl *types.ControlAccessParams, href, entityType, entityName string, headerValues map[string]string) error { 71 return client.setAccessControlWithHttpMethod(http.MethodPost, accessControl, href, entityType, entityName, headerValues) 72 } 73 74 // setAccessControlWithMethod is the same as Client.SetAccessControl but allowing passing a different HTTP method. 75 // This method has been created since VDC accessControl endpoint works with PUT and SetAccessControl method worked 76 // exclusively with POST. This private method gives the flexibility to use both POST and PUT passing it as httpMethod parameter. 77 func (client *Client) setAccessControlWithHttpMethod(httpMethod string, accessControl *types.ControlAccessParams, href, entityType, entityName string, headerValues map[string]string) error { 78 href += "/action/controlAccess" 79 // Make sure that subjects in the setting list are used only once 80 if accessControl.AccessSettings != nil && len(accessControl.AccessSettings.AccessSetting) > 0 { 81 if accessControl.IsSharedToEveryone { 82 return fmt.Errorf("[client.SetAccessControl] can't set IsSharedToEveryone and AccessSettings at the same time for %s %s (%s)", entityType, entityName, href) 83 } 84 var used = make(map[string]bool) 85 for _, setting := range accessControl.AccessSettings.AccessSetting { 86 _, seen := used[setting.Subject.HREF] 87 if seen { 88 return fmt.Errorf("[client.SetAccessControl] subject %s (%s) used more than once", setting.Subject.Name, setting.Subject.HREF) 89 } 90 used[setting.Subject.HREF] = true 91 if setting.Subject.Type == "" { 92 return fmt.Errorf("[client.SetAccessControl] subject %s (%s) has no type defined", setting.Subject.Name, setting.Subject.HREF) 93 } 94 } 95 } 96 97 accessControl.Xmlns = types.XMLNamespaceVCloud 98 queryUrl, err := url.ParseRequestURI(href) 99 if err != nil { 100 return fmt.Errorf("[client.SetAccessControl] error parsing HREF %s: %s", href, err) 101 } 102 103 var header = make(http.Header) 104 if len(headerValues) > 0 { 105 for k, v := range headerValues { 106 header.Add(k, v) 107 } 108 } 109 110 marshaledXml, err := xml.MarshalIndent(accessControl, " ", " ") 111 if err != nil { 112 return fmt.Errorf("[client.SetAccessControl] error marshalling xml data: %s", err) 113 } 114 body := bytes.NewBufferString(xml.Header + string(marshaledXml)) 115 116 req := client.newRequest( 117 nil, // params 118 nil, // notEncodedParams 119 httpMethod, // method 120 *queryUrl, // reqUrl 121 body, // body 122 client.APIVersion, // apiVersion 123 header, // additionalHeader 124 ) 125 126 resp, err := checkResp(client.Http.Do(req)) 127 128 if err != nil { 129 return fmt.Errorf("[client.SetAccessControl] error checking response to HREF %s: %s", href, err) 130 } 131 if resp == nil { 132 return fmt.Errorf("[client.SetAccessControl] nil response received") 133 } 134 _, err = checkResp(resp, err) 135 return err 136 } 137 138 // GetAccessControl retrieves the access control information for this vApp 139 func (vapp VApp) GetAccessControl(useTenantContext bool) (*types.ControlAccessParams, error) { 140 141 if vapp.VApp.HREF == "" { 142 return nil, fmt.Errorf("vApp HREF is empty") 143 } 144 // if useTenantContext is false, we use an empty header (= default behavior) 145 // if it is true, we use a header populated with tenant context values 146 accessControlHeader, err := vapp.getAccessControlHeader(useTenantContext) 147 if err != nil { 148 return nil, err 149 } 150 return vapp.client.GetAccessControl(vapp.VApp.HREF, "vApp", vapp.VApp.Name, accessControlHeader) 151 } 152 153 // SetAccessControl changes the access control information for this vApp 154 func (vapp VApp) SetAccessControl(accessControl *types.ControlAccessParams, useTenantContext bool) error { 155 156 if vapp.VApp.HREF == "" { 157 return fmt.Errorf("vApp HREF is empty") 158 } 159 160 // if useTenantContext is false, we use an empty header (= default behavior) 161 // if it is true, we use a header populated with tenant context values 162 accessControlHeader, err := vapp.getAccessControlHeader(useTenantContext) 163 if err != nil { 164 return err 165 } 166 return vapp.client.SetAccessControl(accessControl, vapp.VApp.HREF, "vApp", vapp.VApp.Name, accessControlHeader) 167 168 } 169 170 // RemoveAccessControl is a shortcut to SetAccessControl with all access disabled 171 func (vapp VApp) RemoveAccessControl(useTenantContext bool) error { 172 return vapp.SetAccessControl(&types.ControlAccessParams{IsSharedToEveryone: false}, useTenantContext) 173 } 174 175 // IsShared shows whether a vApp is shared or not, regardless of the number of subjects sharing it 176 func (vapp VApp) IsShared(useTenantContext bool) (bool, error) { 177 settings, err := vapp.GetAccessControl(useTenantContext) 178 if err != nil { 179 return false, err 180 } 181 if settings.IsSharedToEveryone { 182 return true, nil 183 } 184 return settings.AccessSettings != nil, nil 185 } 186 187 // GetAccessControl retrieves the access control information for this catalog 188 func (adminCatalog AdminCatalog) GetAccessControl(useTenantContext bool) (*types.ControlAccessParams, error) { 189 190 if adminCatalog.AdminCatalog.HREF == "" { 191 return nil, fmt.Errorf("catalog HREF is empty") 192 } 193 href := strings.Replace(adminCatalog.AdminCatalog.HREF, "/admin/", "/", 1) 194 195 // if useTenantContext is false, we use an empty header (= default behavior) 196 // if it is true, we use a header populated with tenant context values 197 accessControlHeader, err := adminCatalog.getAccessControlHeader(useTenantContext) 198 if err != nil { 199 return nil, err 200 } 201 return adminCatalog.client.GetAccessControl(href, "catalog", adminCatalog.AdminCatalog.Name, accessControlHeader) 202 } 203 204 // SetAccessControl changes the access control information for this catalog 205 func (adminCatalog AdminCatalog) SetAccessControl(accessControl *types.ControlAccessParams, useTenantContext bool) error { 206 207 if adminCatalog.AdminCatalog.HREF == "" { 208 return fmt.Errorf("catalog HREF is empty") 209 } 210 href := strings.Replace(adminCatalog.AdminCatalog.HREF, "/admin/", "/", 1) 211 212 // if useTenantContext is false, we use an empty header (= default behavior) 213 // if it is true, we use a header populated with tenant context values 214 accessControlHeader, err := adminCatalog.getAccessControlHeader(useTenantContext) 215 if err != nil { 216 return err 217 } 218 return adminCatalog.client.SetAccessControl(accessControl, href, "catalog", adminCatalog.AdminCatalog.Name, accessControlHeader) 219 } 220 221 // RemoveAccessControl is a shortcut to SetAccessControl with all access disabled 222 func (adminCatalog AdminCatalog) RemoveAccessControl(useTenantContext bool) error { 223 return adminCatalog.SetAccessControl(&types.ControlAccessParams{IsSharedToEveryone: false}, useTenantContext) 224 } 225 226 // IsShared shows whether a catalog is shared or not, regardless of the number of subjects sharing it 227 func (adminCatalog AdminCatalog) IsShared(useTenantContext bool) (bool, error) { 228 settings, err := adminCatalog.GetAccessControl(useTenantContext) 229 if err != nil { 230 return false, err 231 } 232 if settings.IsSharedToEveryone { 233 return true, nil 234 } 235 return settings.AccessSettings != nil, nil 236 } 237 238 // GetVappAccessControl is a convenience method to retrieve access control for a vApp 239 // from a VDC. 240 // The input variable vappIdentifier can be either the vApp name or its ID 241 func (vdc *Vdc) GetVappAccessControl(vappIdentifier string, useTenantContext bool) (*types.ControlAccessParams, error) { 242 vapp, err := vdc.GetVAppByNameOrId(vappIdentifier, true) 243 if err != nil { 244 return nil, fmt.Errorf("error retrieving vApp %s: %s", vappIdentifier, err) 245 } 246 return vapp.GetAccessControl(useTenantContext) 247 } 248 249 // GetCatalogAccessControl is a convenience method to retrieve access control for a catalog 250 // from an organization. 251 // The input variable catalogIdentifier can be either the catalog name or its ID 252 func (org *AdminOrg) GetCatalogAccessControl(catalogIdentifier string, useTenantContext bool) (*types.ControlAccessParams, error) { 253 catalog, err := org.GetAdminCatalogByNameOrId(catalogIdentifier, true) 254 if err != nil { 255 return nil, fmt.Errorf("error retrieving catalog %s: %s", catalogIdentifier, err) 256 } 257 return catalog.GetAccessControl(useTenantContext) 258 } 259 260 // GetCatalogAccessControl is a convenience method to retrieve access control for a catalog 261 // from an organization. 262 // The input variable catalogIdentifier can be either the catalog name or its ID 263 func (org *Org) GetCatalogAccessControl(catalogIdentifier string, useTenantContext bool) (*types.ControlAccessParams, error) { 264 catalog, err := org.GetCatalogByNameOrId(catalogIdentifier, true) 265 if err != nil { 266 return nil, fmt.Errorf("error retrieving catalog %s: %s", catalogIdentifier, err) 267 } 268 return catalog.GetAccessControl(useTenantContext) 269 } 270 271 // GetAccessControl retrieves the access control information for this catalog 272 func (catalog Catalog) GetAccessControl(useTenantContext bool) (*types.ControlAccessParams, error) { 273 274 if catalog.Catalog.HREF == "" { 275 return nil, fmt.Errorf("catalog HREF is empty") 276 } 277 href := strings.Replace(catalog.Catalog.HREF, "/admin/", "/", 1) 278 accessControlHeader, err := catalog.getAccessControlHeader(useTenantContext) 279 if err != nil { 280 return nil, err 281 } 282 return catalog.client.GetAccessControl(href, "catalog", catalog.Catalog.Name, accessControlHeader) 283 } 284 285 // SetAccessControl changes the access control information for this catalog 286 func (catalog Catalog) SetAccessControl(accessControl *types.ControlAccessParams, useTenantContext bool) error { 287 288 if catalog.Catalog.HREF == "" { 289 return fmt.Errorf("catalog HREF is empty") 290 } 291 292 href := strings.Replace(catalog.Catalog.HREF, "/admin/", "/", 1) 293 294 // if useTenantContext is false, we use an empty header (= default behavior) 295 // if it is true, we use a header populated with tenant context values 296 accessControlHeader, err := catalog.getAccessControlHeader(useTenantContext) 297 if err != nil { 298 return err 299 } 300 return catalog.client.SetAccessControl(accessControl, href, "catalog", catalog.Catalog.Name, accessControlHeader) 301 } 302 303 // RemoveAccessControl is a shortcut to SetAccessControl with all access disabled 304 func (catalog Catalog) RemoveAccessControl(useTenantContext bool) error { 305 return catalog.SetAccessControl(&types.ControlAccessParams{IsSharedToEveryone: false}, useTenantContext) 306 } 307 308 // IsShared shows whether a catalog is shared or not, regardless of the number of subjects sharing it 309 func (catalog Catalog) IsShared(useTenantContext bool) (bool, error) { 310 settings, err := catalog.GetAccessControl(useTenantContext) 311 if err != nil { 312 return false, err 313 } 314 if settings.IsSharedToEveryone { 315 return true, nil 316 } 317 return settings.AccessSettings != nil, nil 318 } 319 320 // getAccessControlHeader builds the data needed to set the header when tenant context is required. 321 // If useTenantContext is false, it returns an empty map. 322 // Otherwise, it finds the Org ID and name (going up in the hierarchy through the VDC) 323 // and creates the header data 324 func (vapp *VApp) getAccessControlHeader(useTenantContext bool) (map[string]string, error) { 325 if !useTenantContext { 326 return map[string]string{}, nil 327 } 328 orgInfo, err := vapp.getOrgInfo() 329 if err != nil { 330 return nil, err 331 } 332 return map[string]string{types.HeaderTenantContext: orgInfo.OrgId, types.HeaderAuthContext: orgInfo.OrgName}, nil 333 } 334 335 // getAccessControlHeader builds the data needed to set the header when tenant context is required. 336 // If useTenantContext is false, it returns an empty map. 337 // Otherwise, it finds the Org ID and name and creates the header data 338 func (catalog *Catalog) getAccessControlHeader(useTenantContext bool) (map[string]string, error) { 339 if !useTenantContext { 340 return map[string]string{}, nil 341 } 342 orgInfo, err := catalog.getOrgInfo() 343 if err != nil { 344 return nil, err 345 } 346 return map[string]string{types.HeaderTenantContext: orgInfo.OrgId, types.HeaderAuthContext: orgInfo.OrgName}, nil 347 } 348 349 // getAccessControlHeader builds the data needed to set the header when tenant context is required. 350 // If useTenantContext is false, it returns an empty map. 351 // Otherwise, it finds the Org ID and name and creates the header data 352 func (adminCatalog *AdminCatalog) getAccessControlHeader(useTenantContext bool) (map[string]string, error) { 353 if !useTenantContext { 354 return map[string]string{}, nil 355 } 356 orgInfo, err := adminCatalog.getOrgInfo() 357 358 if err != nil { 359 return nil, err 360 } 361 return map[string]string{types.HeaderTenantContext: orgInfo.OrgId, types.HeaderAuthContext: orgInfo.OrgName}, nil 362 } 363 364 // GetControlAccess read and returns the control access parameters from a VDC 365 func (vdc *Vdc) GetControlAccess(useTenantContext bool) (*types.ControlAccessParams, error) { 366 err := checkSanityVdcControlAccess(vdc) 367 if err != nil { 368 return nil, err 369 } 370 371 var tenantContextHeaders map[string]string 372 373 if useTenantContext { 374 tenantContext, err := vdc.getTenantContext() 375 if err != nil { 376 return nil, fmt.Errorf("error getting the tenant context - %s", err) 377 } 378 379 tenantContextHeaders = getTenantContextHeader(tenantContext) 380 } 381 382 controlAccessParams, err := vdc.client.GetAccessControl(vdc.Vdc.HREF, "vdc", vdc.Vdc.Name, tenantContextHeaders) 383 if err != nil { 384 return nil, fmt.Errorf("there was an error when retrieving VDC control access params - %s", err) 385 } 386 387 return controlAccessParams, nil 388 } 389 390 // SetControlAccess sets VDC control access parameters for everybody or individual users/groups. 391 // This method either sets control for everybody, passing isSharedToEveryOne true, and everyoneAccessLevel (currently only ReadOnly is supported for VDC) and nil for accessSettings, 392 // or can set access control for specific users/groups, passing isSharedToEveryOne false, everyoneAccessLevel "" and accessSettings filled as desired. 393 // The method will fail if tries to configure access control for everybody and passes individual users/groups to configure. 394 // It returns the control access parameters that are read from the API (using Vdc.GetControlAccess). 395 func (vdc *Vdc) SetControlAccess(isSharedToEveryOne bool, everyoneAccessLevel string, accessSettings []*types.AccessSetting, useTenantContext bool) (*types.ControlAccessParams, error) { 396 err := checkSanityVdcControlAccess(vdc) 397 if err != nil { 398 return nil, err 399 } 400 401 if (isSharedToEveryOne && accessSettings != nil) && len(accessSettings) > 0 { 402 return nil, fmt.Errorf("either configure access for everybody or individual users, not both at the same time") 403 } 404 405 var tenantContextHeaders map[string]string 406 var accessControl = &types.ControlAccessParams{ 407 Xmlns: types.XMLNamespaceVCloud, 408 } 409 410 if isSharedToEveryOne { // Do configuration for everyone 411 if everyoneAccessLevel == "" { 412 return nil, fmt.Errorf("everyoneAccessLevel needs to be set if isSharedToEveryOne is true") 413 } 414 415 accessControl.IsSharedToEveryone = true 416 accessControl.EveryoneAccessLevel = &everyoneAccessLevel 417 418 } else { // Do configuration for individual users/groups 419 if len(accessSettings) > 0 { 420 accessControl.AccessSettings = &types.AccessSettingList{ 421 AccessSetting: accessSettings, 422 } 423 } 424 } 425 426 if useTenantContext { 427 tenantContext, err := vdc.getTenantContext() 428 if err != nil { 429 return nil, fmt.Errorf("error getting the tenant context - %s", err) 430 } 431 432 tenantContextHeaders = getTenantContextHeader(tenantContext) 433 } 434 435 err = vdc.client.setAccessControlWithHttpMethod(http.MethodPut, accessControl, vdc.Vdc.HREF, "vdc", vdc.Vdc.Name, tenantContextHeaders) 436 if err != nil { 437 return nil, fmt.Errorf("there was an error when setting VDC control access params - %s", err) 438 } 439 440 return vdc.GetControlAccess(useTenantContext) 441 } 442 443 // DeleteControlAccess makes stop sharing VDC with anyone 444 func (vdc *Vdc) DeleteControlAccess(useTenantContext bool) (*types.ControlAccessParams, error) { 445 return vdc.SetControlAccess(false, "", nil, useTenantContext) 446 } 447 448 // checkSanityVdcControlAccess is a function that check some Vdc attributes and returns error if any is missing. It is useful for 449 // checking sanity of Vdc struct before running controlAccess methods. 450 func checkSanityVdcControlAccess(vdc *Vdc) error { 451 if vdc.client == nil { 452 return fmt.Errorf("client has not been set up on Vdc struct. Please initialize it before using this method") 453 } 454 if vdc.Vdc == nil || vdc.Vdc.Name == "" { 455 return fmt.Errorf("types.Vdc struct has not been set up on Vdc struct or Vdc.Vdc.Name is missing. Please initialize it before using this method ") 456 } 457 return nil 458 } 459 460 func publishCatalog(client *Client, catalogUrl string, tenantContext *TenantContext, publishCatalog types.PublishCatalogParams) error { 461 catalogUrl = catalogUrl + "/action/publish" 462 463 publishCatalog.Xmlns = types.XMLNamespaceVCloud 464 465 if tenantContext != nil { 466 client.SetCustomHeader(getTenantContextHeader(tenantContext)) 467 } 468 469 err := client.ExecuteRequestWithoutResponse(catalogUrl, http.MethodPost, 470 types.PublishCatalog, "error setting catalog publishing state: %s", publishCatalog) 471 472 if tenantContext != nil { 473 client.RemoveProvidedCustomHeaders(getTenantContextHeader(tenantContext)) 474 } 475 476 return err 477 } 478 479 // IsSharedReadOnly returns the state of the catalog read-only sharing to all organizations 480 func (cat *Catalog) IsSharedReadOnly() (bool, error) { 481 accessControl, err := cat.GetAccessControl(true) 482 if err != nil { 483 return false, err 484 } 485 if accessControl.AccessSettings != nil || accessControl.IsSharedToEveryone { 486 return false, nil 487 } 488 err = cat.Refresh() 489 if err != nil { 490 return false, err 491 } 492 return cat.Catalog.IsPublished, nil 493 } 494 495 // IsSharedReadOnly returns the state of the catalog read-only sharing to all organizations 496 func (cat *AdminCatalog) IsSharedReadOnly() (bool, error) { 497 accessControl, err := cat.GetAccessControl(true) 498 if err != nil { 499 return false, err 500 } 501 if accessControl.AccessSettings != nil || accessControl.IsSharedToEveryone { 502 return false, nil 503 } 504 err = cat.Refresh() 505 if err != nil { 506 return false, err 507 } 508 return cat.AdminCatalog.IsPublished, nil 509 } 510 511 // publish publishes a catalog read-only access control to all organizations. 512 // This operation is usually the second step for a read-only sharing to all Orgs 513 func (cat *Catalog) publish(isPublished bool) error { 514 if cat.Catalog == nil { 515 return fmt.Errorf("cannot publish catalog, Object is empty") 516 } 517 518 catalogUrl := cat.Catalog.HREF 519 if catalogUrl == "nil" || catalogUrl == "" { 520 return fmt.Errorf("cannot publish catalog, HREF is empty") 521 } 522 523 tenantContext, err := cat.getTenantContext() 524 if err != nil { 525 return fmt.Errorf("cannot publish catalog, tenant context error: %s", err) 526 } 527 528 publishParameters := types.PublishCatalogParams{ 529 IsPublished: &isPublished, 530 } 531 err = publishCatalog(cat.client, catalogUrl, tenantContext, publishParameters) 532 if err != nil { 533 return err 534 } 535 536 return cat.Refresh() 537 } 538 539 // publish publishes a catalog read-only access control to all organizations. 540 // This operation is usually the second step for a read-only sharing to all Orgs 541 func (cat *AdminCatalog) publish(isPublished bool) error { 542 if cat.AdminCatalog == nil { 543 return fmt.Errorf("cannot publish catalog, Object is empty") 544 } 545 546 catalogUrl := cat.AdminCatalog.HREF 547 if catalogUrl == "nil" || catalogUrl == "" { 548 return fmt.Errorf("cannot publish catalog, HREF is empty") 549 } 550 551 tenantContext, err := cat.getTenantContext() 552 if err != nil { 553 return fmt.Errorf("cannot publish catalog, tenant context error: %s", err) 554 } 555 556 publishParameters := types.PublishCatalogParams{ 557 IsPublished: &isPublished, 558 } 559 err = publishCatalog(cat.client, catalogUrl, tenantContext, publishParameters) 560 if err != nil { 561 return err 562 } 563 564 err = cat.Refresh() 565 if err != nil { 566 return err 567 } 568 569 return err 570 } 571 572 // SetReadOnlyAccessControl will create or rescind the read-only catalog sharing to all organizations 573 func (cat *Catalog) SetReadOnlyAccessControl(isPublished bool) error { 574 if cat.Catalog == nil { 575 return fmt.Errorf("cannot set access control, Object is empty") 576 } 577 err := cat.SetAccessControl(&types.ControlAccessParams{ 578 IsSharedToEveryone: false, 579 EveryoneAccessLevel: addrOf(types.ControlAccessReadOnly), 580 }, true) 581 if err != nil { 582 return fmt.Errorf("error resetting access control record for catalog %s: %s", cat.Catalog.Name, err) 583 } 584 return cat.publish(isPublished) 585 } 586 587 // SetReadOnlyAccessControl will create or rescind the read-only AdminCatalog sharing to all organizations 588 func (cat *AdminCatalog) SetReadOnlyAccessControl(isPublished bool) error { 589 if cat.AdminCatalog == nil { 590 return fmt.Errorf("cannot set access control, Object is empty") 591 } 592 err := cat.SetAccessControl(&types.ControlAccessParams{ 593 IsSharedToEveryone: false, 594 EveryoneAccessLevel: addrOf(types.ControlAccessReadOnly), 595 }, true) 596 if err != nil { 597 return err 598 } 599 return cat.publish(isPublished) 600 }