github.com/vmware/govmomi@v0.51.0/ssoadmin/simulator/simulator.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package simulator 6 7 import ( 8 "encoding/base64" 9 "encoding/pem" 10 "log" 11 "net/url" 12 "os" 13 "strings" 14 15 "github.com/vmware/govmomi/simulator" 16 "github.com/vmware/govmomi/ssoadmin" 17 "github.com/vmware/govmomi/ssoadmin/methods" 18 "github.com/vmware/govmomi/ssoadmin/types" 19 "github.com/vmware/govmomi/vim25" 20 "github.com/vmware/govmomi/vim25/soap" 21 vim "github.com/vmware/govmomi/vim25/types" 22 ) 23 24 func init() { 25 simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) { 26 if r.IsVPX() { 27 s.RegisterSDK(New(r, s.Listen), ssoadmin.SystemPath) 28 } 29 }) 30 } 31 32 var content = types.AdminServiceContent{ 33 SessionManager: vim.ManagedObjectReference{Type: "SsoSessionManager", Value: "ssoSessionManager"}, 34 ConfigurationManagementService: vim.ManagedObjectReference{Type: "SsoAdminConfigurationManagementService", Value: "configurationManagementService"}, 35 SmtpManagementService: vim.ManagedObjectReference{Type: "SsoAdminSmtpManagementService", Value: "smtpManagementService"}, 36 PrincipalDiscoveryService: vim.ManagedObjectReference{Type: "SsoAdminPrincipalDiscoveryService", Value: "principalDiscoveryService"}, 37 PrincipalManagementService: vim.ManagedObjectReference{Type: "SsoAdminPrincipalManagementService", Value: "principalManagementService"}, 38 RoleManagementService: vim.ManagedObjectReference{Type: "SsoAdminRoleManagementService", Value: "roleManagementService"}, 39 PasswordPolicyService: vim.ManagedObjectReference{Type: "SsoAdminPasswordPolicyService", Value: "passwordPolicyService"}, 40 LockoutPolicyService: vim.ManagedObjectReference{Type: "SsoAdminLockoutPolicyService", Value: "lockoutPolicyService"}, 41 DomainManagementService: vim.ManagedObjectReference{Type: "SsoAdminDomainManagementService", Value: "domainManagementService"}, 42 IdentitySourceManagementService: vim.ManagedObjectReference{Type: "SsoAdminIdentitySourceManagementService", Value: "identitySourceManagementService"}, 43 SystemManagementService: vim.ManagedObjectReference{Type: "SsoAdminSystemManagementService", Value: "systemManagementService"}, 44 DeploymentInformationService: vim.ManagedObjectReference{Type: "SsoAdminDeploymentInformationService", Value: "deploymentInformationService"}, 45 ReplicationService: vim.ManagedObjectReference{Type: "SsoAdminReplicationService", Value: "replicationService"}, 46 } 47 48 var groupcheckContent = types.GroupcheckServiceContent{ 49 SessionManager: vim.ManagedObjectReference{Type: "SsoSessionManager", Value: "ssoSessionManager"}, 50 GroupCheckService: vim.ManagedObjectReference{Type: "SsoGroupcheckGroupCheckService", Value: "groupCheckService"}, 51 } 52 53 var groupcheckServiceInstance = vim.ManagedObjectReference{ 54 Type: "SsoGroupcheckServiceInstance", Value: "ServiceInstance", 55 } 56 57 var IdentitySources = types.IdentitySources{ 58 System: types.IdentitySource{ 59 Name: "vsphere.local", 60 Domains: []types.Domain{{Name: "vsphere.local", Alias: "vmwarem"}}, 61 }, 62 LocalOS: &types.IdentitySource{ 63 Name: "localos", 64 Domains: []types.Domain{{Name: "localos", Alias: ""}}, 65 }, 66 NativeAD: nil, 67 LDAPS: []types.LdapIdentitySource{ 68 { 69 IdentitySource: types.IdentitySource{ 70 Name: "example.com", 71 Domains: []types.Domain{{Name: "example.com", Alias: "examplex"}}, 72 }, 73 Type: "ActiveDirectory", 74 Details: types.LdapIdentitySourceDetails{ 75 FriendlyName: "foo", 76 UserBaseDn: "ou=People,dc=example,dc=org", 77 GroupBaseDn: "ou=People,dc=example,dc=org", 78 PrimaryURL: "ldap://10.168.194.120:389", 79 FailoverURL: "", 80 }, 81 AuthenticationDetails: types.AuthenticationDetails{ 82 AuthenticationType: "PASSWORD", 83 Username: "cn=admin,dc=example,dc=org", 84 }, 85 }, 86 }, 87 } 88 89 type ServiceInstance struct { 90 vim.ManagedObjectReference 91 } 92 93 type GroupcheckServiceInstance struct { 94 vim.ManagedObjectReference 95 } 96 97 type GroupcheckService struct { 98 vim.ManagedObjectReference 99 100 m *PrincipalManagementService 101 } 102 103 type SessionManager struct { 104 vim.ManagedObjectReference 105 } 106 107 type ConfigurationManagementService struct { 108 vim.ManagedObjectReference 109 } 110 111 type IdentitySourceManagementService struct { 112 vim.ManagedObjectReference 113 } 114 115 type PrincipalManagementService struct { 116 vim.ManagedObjectReference 117 118 dir map[types.PrincipalId]principal 119 } 120 121 type PrincipalDiscoveryService struct { 122 vim.ManagedObjectReference 123 124 m *PrincipalManagementService 125 } 126 127 type principal struct { 128 group *types.AdminGroup 129 members map[types.PrincipalId]principal 130 solution *types.AdminSolutionUser 131 person *types.AdminPersonUser 132 password string 133 } 134 135 func New(vc *simulator.Registry, u *url.URL) *simulator.Registry { 136 r := simulator.NewRegistry() 137 r.Namespace = ssoadmin.Namespace 138 r.Path = ssoadmin.Path 139 140 settings := vc.OptionManager().Setting 141 for i := range settings { 142 setting := settings[i].GetOptionValue() 143 if setting.Key == "config.vpxd.sso.admin.uri" { 144 endpoint, _ := url.Parse(setting.Value.(string)) 145 r.Path = endpoint.Path 146 } 147 } 148 149 r.Put(&ServiceInstance{ 150 ManagedObjectReference: ssoadmin.ServiceInstance, 151 }) 152 153 r.Put(&GroupcheckServiceInstance{ 154 ManagedObjectReference: groupcheckServiceInstance, 155 }) 156 157 r.Put(&SessionManager{ 158 ManagedObjectReference: content.SessionManager, 159 }) 160 161 r.Put(&ConfigurationManagementService{ 162 ManagedObjectReference: content.ConfigurationManagementService, 163 }) 164 165 r.Put(&IdentitySourceManagementService{ 166 ManagedObjectReference: content.IdentitySourceManagementService, 167 }) 168 169 m := &PrincipalManagementService{ 170 ManagedObjectReference: content.PrincipalManagementService, 171 dir: make(map[types.PrincipalId]principal), 172 } 173 r.Put(m) 174 m.createDefaultUser(u.User) 175 vc.SessionManager().ValidLogin = m.validLogin 176 177 r.Put(&PrincipalDiscoveryService{ 178 ManagedObjectReference: content.PrincipalDiscoveryService, 179 m: m, 180 }) 181 182 r.Put(&GroupcheckService{ 183 ManagedObjectReference: groupcheckContent.GroupCheckService, 184 m: m, 185 }) 186 187 return r 188 } 189 190 func (s *ServiceInstance) SsoAdminServiceInstance(ctx *simulator.Context, _ *types.SsoAdminServiceInstance) soap.HasFault { 191 return &methods.SsoAdminServiceInstanceBody{ 192 Res: &types.SsoAdminServiceInstanceResponse{ 193 Returnval: content, 194 }, 195 } 196 } 197 198 func (s *GroupcheckServiceInstance) SsoGroupcheckServiceInstance(ctx *simulator.Context, _ *types.SsoGroupcheckServiceInstance) soap.HasFault { 199 return &methods.SsoGroupcheckServiceInstanceBody{ 200 Res: &types.SsoGroupcheckServiceInstanceResponse{ 201 Returnval: groupcheckContent, 202 }, 203 } 204 } 205 206 func (s *GroupcheckService) FindAllParentGroups(ctx *simulator.Context, req *types.FindAllParentGroups) soap.HasFault { 207 body := new(methods.FindAllParentGroupsBody) 208 209 p, ok := s.m.dir[req.UserId] 210 if !ok || p.person == nil { 211 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 212 return body 213 } 214 215 body.Res = new(types.FindAllParentGroupsResponse) 216 217 for gid, p := range s.m.dir { 218 if p.group == nil { 219 continue 220 } 221 222 for id, m := range p.members { 223 if m.person == nil { 224 continue 225 } 226 if id == req.UserId { 227 body.Res.Returnval = append(body.Res.Returnval, gid) 228 } 229 } 230 } 231 232 return body 233 } 234 235 func (s *SessionManager) Login(ctx *simulator.Context, req *types.Login) soap.HasFault { 236 body := new(methods.LoginBody) 237 238 // TODO: check for Assertion>Subject>NameID as simulator.SessionManager.LoginByToken does 239 body.Res = new(types.LoginResponse) 240 241 return body 242 } 243 244 func (s *SessionManager) Logout(ctx *simulator.Context, req *types.Logout) soap.HasFault { 245 return &methods.LogoutBody{ 246 Res: new(types.LogoutResponse), 247 } 248 } 249 250 func (*ConfigurationManagementService) GetTrustedCertificates(ctx *simulator.Context, _ *types.GetTrustedCertificates) soap.HasFault { 251 m := ctx.For(vim25.Path).Map.SessionManager() 252 253 var res []string 254 255 // TODO: consider adding a vcsim -tlscacerts flag 256 cacerts := os.Getenv("VCSIM_CACERTS") 257 if cacerts != "" { 258 pemCerts, err := os.ReadFile(cacerts) 259 if err != nil { 260 log.Fatal(err) 261 } 262 for len(pemCerts) > 0 { 263 var block *pem.Block 264 block, pemCerts = pem.Decode(pemCerts) 265 if block == nil { 266 break 267 } 268 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 269 continue 270 } 271 res = append(res, base64.StdEncoding.EncodeToString(block.Bytes)) 272 } 273 } else if m.TLS != nil { 274 res = append(res, m.TLSCert()) 275 } 276 277 return &methods.GetTrustedCertificatesBody{ 278 Res: &types.GetTrustedCertificatesResponse{ 279 Returnval: res, 280 }, 281 } 282 } 283 284 func (s *IdentitySourceManagementService) Get(ctx *simulator.Context, _ *types.Get) soap.HasFault { 285 sources := IdentitySources 286 sources.All = nil 287 sources.All = append(sources.All, sources.System) 288 289 if sources.LocalOS != nil { 290 sources.All = append(sources.All, *sources.LocalOS) 291 } 292 293 if sources.NativeAD != nil { 294 sources.All = append(sources.All, *sources.NativeAD) 295 } 296 297 for _, ldap := range sources.LDAPS { 298 sources.All = append(sources.All, ldap.IdentitySource) 299 } 300 301 return &methods.GetBody{ 302 Res: &types.GetResponse{ 303 Returnval: sources, 304 }, 305 } 306 } 307 308 func (s *PrincipalDiscoveryService) FindUser(ctx *simulator.Context, req *types.FindUser) soap.HasFault { 309 body := &methods.FindUserBody{ 310 Res: new(types.FindUserResponse), 311 } 312 313 p, ok := s.m.dir[req.UserId] 314 if !ok { 315 return body 316 } 317 318 var user *types.AdminUser 319 320 switch { 321 case p.person != nil: 322 user = &types.AdminUser{ 323 Kind: "person", 324 Id: p.person.Id, 325 Description: p.person.Details.Description, 326 } 327 case p.solution != nil: 328 user = &types.AdminUser{ 329 Kind: "solution", 330 Id: p.solution.Id, 331 Description: p.solution.Details.Description, 332 } 333 334 } 335 336 body.Res.Returnval = user 337 338 return body 339 } 340 341 func (s *PrincipalDiscoveryService) FindPersonUser(ctx *simulator.Context, req *types.FindPersonUser) soap.HasFault { 342 body := &methods.FindPersonUserBody{ 343 Res: new(types.FindPersonUserResponse), 344 } 345 346 p, ok := s.m.dir[req.UserId] 347 if ok { 348 body.Res.Returnval = p.person 349 } 350 351 return body 352 } 353 354 func (s *PrincipalDiscoveryService) FindPersonUsers(ctx *simulator.Context, req *types.FindPersonUsers) soap.HasFault { 355 body := &methods.FindPersonUsersBody{ 356 Res: &types.FindPersonUsersResponse{}, 357 } 358 359 for _, p := range s.m.dir { 360 if p.person == nil { 361 continue 362 } 363 364 if domain := req.Criteria.Domain; domain != "" { 365 if p.person.Id.Domain != domain { 366 continue 367 } 368 } 369 370 if search := req.Criteria.SearchString; search != "" { 371 if !strings.Contains(p.person.Id.Name, search) { 372 continue 373 } 374 } 375 376 body.Res.Returnval = append(body.Res.Returnval, *p.person) 377 } 378 379 return body 380 } 381 382 func (s *PrincipalManagementService) createDefaultUser(u *url.Userinfo) { 383 user := &types.AdminPersonUser{ 384 Id: types.PrincipalId{ 385 Name: u.Username(), 386 Domain: IdentitySources.System.Name, 387 }, 388 } 389 390 pass, _ := u.Password() 391 s.dir[user.Id] = principal{ 392 person: user, 393 password: pass, 394 } 395 } 396 397 func (s *PrincipalManagementService) validLogin(login *vim.Login) bool { 398 id := parseID(login.UserName) 399 400 if p, ok := s.dir[id]; ok && p.person != nil { 401 return p.password == login.Password 402 } 403 404 return false 405 } 406 407 func (s *PrincipalDiscoveryService) FindSolutionUser(ctx *simulator.Context, req *types.FindSolutionUser) soap.HasFault { 408 body := &methods.FindSolutionUserBody{ 409 Res: new(types.FindSolutionUserResponse), 410 } 411 412 id := parseID(req.UserName) 413 p, ok := s.m.dir[id] 414 if ok { 415 body.Res.Returnval = p.solution 416 } 417 418 return body 419 } 420 421 func (s *PrincipalDiscoveryService) FindSolutionUsers(ctx *simulator.Context, req *types.FindSolutionUsers) soap.HasFault { 422 body := &methods.FindSolutionUsersBody{ 423 Res: new(types.FindSolutionUsersResponse), 424 } 425 426 for _, p := range s.m.dir { 427 if p.solution == nil { 428 continue 429 } 430 431 if search := req.SearchString; search != "" { 432 if !strings.Contains(p.solution.Id.Name, search) { 433 continue 434 } 435 } 436 437 body.Res.Returnval = append(body.Res.Returnval, *p.solution) 438 } 439 440 return body 441 } 442 443 func (s *PrincipalManagementService) CreateLocalPersonUser(ctx *simulator.Context, req *types.CreateLocalPersonUser) soap.HasFault { 444 body := new(methods.CreateLocalPersonUserBody) 445 446 user := &types.AdminPersonUser{ 447 Id: types.PrincipalId{ 448 Name: req.UserName, 449 Domain: IdentitySources.System.Name, 450 }, 451 Details: req.UserDetails, 452 } 453 454 if _, ok := s.dir[user.Id]; ok { 455 body.Fault_ = simulator.Fault("", new(vim.DuplicateName)) 456 return body 457 } 458 459 s.dir[user.Id] = principal{ 460 person: user, 461 password: req.Password, 462 } 463 464 body.Res = new(types.CreateLocalPersonUserResponse) 465 466 return body 467 } 468 469 func (s *PrincipalManagementService) UpdateLocalPersonUserDetails(ctx *simulator.Context, req *types.UpdateLocalPersonUserDetails) soap.HasFault { 470 body := &methods.UpdateLocalPersonUserDetailsBody{ 471 Res: new(types.UpdateLocalPersonUserDetailsResponse), 472 } 473 474 id := parseID(req.UserName) 475 p, ok := s.dir[id] 476 if !ok || p.person == nil { 477 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 478 return body 479 } 480 481 p.person.Details = req.UserDetails 482 483 return body 484 } 485 486 func (s *PrincipalManagementService) ResetLocalPersonUserPassword(ctx *simulator.Context, req *types.ResetLocalPersonUserPassword) soap.HasFault { 487 body := &methods.ResetLocalPersonUserPasswordBody{ 488 Res: new(types.ResetLocalPersonUserPasswordResponse), 489 } 490 491 id := parseID(req.UserName) 492 p, ok := s.dir[id] 493 if !ok || p.person == nil { 494 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 495 return body 496 } 497 498 p.password = req.NewPassword 499 500 return body 501 } 502 503 func (s *PrincipalManagementService) CreateLocalSolutionUser(ctx *simulator.Context, req *types.CreateLocalSolutionUser) soap.HasFault { 504 body := new(methods.CreateLocalSolutionUserBody) 505 506 user := &types.AdminSolutionUser{ 507 Id: types.PrincipalId{ 508 Name: req.UserName, 509 Domain: IdentitySources.System.Name, 510 }, 511 Details: req.UserDetails, 512 } 513 514 if _, ok := s.dir[user.Id]; ok { 515 body.Fault_ = simulator.Fault("", new(vim.DuplicateName)) 516 return body 517 } 518 519 s.dir[user.Id] = principal{ 520 solution: user, 521 } 522 523 body.Res = new(types.CreateLocalSolutionUserResponse) 524 525 return body 526 } 527 528 func (s *PrincipalManagementService) UpdateLocalSolutionUserDetails(ctx *simulator.Context, req *types.UpdateLocalSolutionUserDetails) soap.HasFault { 529 body := &methods.UpdateLocalSolutionUserDetailsBody{ 530 Res: new(types.UpdateLocalSolutionUserDetailsResponse), 531 } 532 533 id := parseID(req.UserName) 534 p, ok := s.dir[id] 535 if !ok || p.solution == nil { 536 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 537 return body 538 } 539 540 p.solution.Details = req.UserDetails 541 542 return body 543 } 544 545 func (s *PrincipalManagementService) DeleteLocalPrincipal(ctx *simulator.Context, req *types.DeleteLocalPrincipal) soap.HasFault { 546 body := new(methods.DeleteLocalPrincipalBody) 547 548 id := parseID(req.PrincipalName) 549 550 if _, ok := s.dir[id]; ok { 551 delete(s.dir, id) 552 for _, p := range s.dir { 553 if p.group != nil { 554 delete(p.members, id) 555 } 556 } 557 body.Res = new(types.DeleteLocalPrincipalResponse) 558 } else { 559 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 560 } 561 562 return body 563 } 564 565 func parseID(name string) types.PrincipalId { 566 p := strings.SplitN(name, "@", 2) 567 id := types.PrincipalId{Name: p[0]} 568 if len(p) == 2 { 569 id.Domain = p[1] 570 } else { 571 id.Domain = IdentitySources.System.Name 572 } 573 return id 574 } 575 576 func (s *PrincipalDiscoveryService) FindGroup(ctx *simulator.Context, req *types.FindGroup) soap.HasFault { 577 body := &methods.FindGroupBody{ 578 Res: new(types.FindGroupResponse), 579 } 580 581 p, ok := s.m.dir[req.GroupId] 582 if !ok { 583 return body 584 } 585 586 body.Res.Returnval = p.group 587 588 return body 589 } 590 591 func (s *PrincipalDiscoveryService) FindGroups(ctx *simulator.Context, req *types.FindGroups) soap.HasFault { 592 body := &methods.FindGroupsBody{ 593 Res: &types.FindGroupsResponse{}, 594 } 595 596 for _, p := range s.m.dir { 597 if p.group == nil { 598 continue 599 } 600 601 if domain := req.Criteria.Domain; domain != "" { 602 if p.group.Id.Domain != domain { 603 continue 604 } 605 } 606 607 if search := req.Criteria.SearchString; search != "" { 608 if !strings.Contains(p.group.Id.Name, search) { 609 continue 610 } 611 } 612 613 body.Res.Returnval = append(body.Res.Returnval, *p.group) 614 } 615 616 return body 617 } 618 619 func (s *PrincipalDiscoveryService) FindGroupsInGroup(ctx *simulator.Context, req *types.FindGroupsInGroup) soap.HasFault { 620 body := &methods.FindGroupsInGroupBody{ 621 Res: &types.FindGroupsInGroupResponse{}, 622 } 623 624 for _, p := range s.m.dir { 625 if p.group == nil { 626 continue 627 } 628 629 for id := range p.members { 630 if search := req.SearchString; search != "" { 631 if !strings.Contains(id.Name, search) { 632 continue 633 } 634 } 635 636 body.Res.Returnval = append(body.Res.Returnval, *p.group) 637 } 638 } 639 640 return body 641 } 642 643 func (s *PrincipalManagementService) CreateLocalGroup(ctx *simulator.Context, req *types.CreateLocalGroup) soap.HasFault { 644 body := new(methods.CreateLocalGroupBody) 645 646 group := &types.AdminGroup{ 647 Id: types.PrincipalId{ 648 Name: req.GroupName, 649 Domain: IdentitySources.System.Name, 650 }, 651 Details: req.GroupDetails, 652 } 653 654 if _, ok := s.dir[group.Id]; ok { 655 body.Fault_ = simulator.Fault("", new(vim.DuplicateName)) 656 return body 657 } 658 659 s.dir[group.Id] = principal{ 660 group: group, 661 members: make(map[types.PrincipalId]principal), 662 } 663 664 body.Res = new(types.CreateLocalGroupResponse) 665 666 return body 667 } 668 669 func (s *PrincipalManagementService) UpdateLocalGroupDetails(ctx *simulator.Context, req *types.UpdateLocalGroupDetails) soap.HasFault { 670 body := &methods.UpdateLocalGroupDetailsBody{ 671 Res: new(types.UpdateLocalGroupDetailsResponse), 672 } 673 674 id := parseID(req.GroupName) 675 p, ok := s.dir[id] 676 if !ok || p.group == nil { 677 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 678 return body 679 } 680 681 p.group.Details = req.GroupDetails 682 683 return body 684 } 685 686 func (s *PrincipalManagementService) AddUsersToLocalGroup(ctx *simulator.Context, req *types.AddUsersToLocalGroup) soap.HasFault { 687 body := &methods.AddUsersToLocalGroupBody{ 688 Res: new(types.AddUsersToLocalGroupResponse), 689 } 690 691 id := parseID(req.GroupName) 692 g, ok := s.dir[id] 693 if !ok || g.group == nil { 694 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 695 return body 696 } 697 698 res := new(types.AddUsersToLocalGroupResponse) 699 700 for _, id := range req.UserIds { 701 p, ok := s.dir[id] 702 if !ok || p.person == nil { 703 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 704 return body 705 } 706 707 added := false 708 if _, ok := g.members[id]; !ok { 709 g.members[id] = p 710 } else { 711 added = true 712 } 713 714 res.Returnval = append(res.Returnval, added) 715 } 716 717 body.Res = res 718 719 return body 720 } 721 722 func (s *PrincipalManagementService) AddGroupsToLocalGroup(ctx *simulator.Context, req *types.AddGroupsToLocalGroup) soap.HasFault { 723 body := &methods.AddGroupsToLocalGroupBody{ 724 Res: new(types.AddGroupsToLocalGroupResponse), 725 } 726 727 id := parseID(req.GroupName) 728 g, ok := s.dir[id] 729 if !ok || g.group == nil { 730 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 731 return body 732 } 733 734 res := new(types.AddGroupsToLocalGroupResponse) 735 736 for _, id := range req.GroupIds { 737 p, ok := s.dir[id] 738 if !ok || p.group == nil { 739 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 740 return body 741 } 742 743 added := false 744 if _, ok := g.members[id]; !ok { 745 g.members[id] = p 746 } else { 747 added = true 748 } 749 750 res.Returnval = append(res.Returnval, added) 751 } 752 753 body.Res = res 754 755 return body 756 } 757 758 func (s *PrincipalManagementService) RemovePrincipalsFromLocalGroup(ctx *simulator.Context, req *types.RemovePrincipalsFromLocalGroup) soap.HasFault { 759 body := &methods.RemovePrincipalsFromLocalGroupBody{ 760 Res: new(types.RemovePrincipalsFromLocalGroupResponse), 761 } 762 763 id := parseID(req.GroupName) 764 g, ok := s.dir[id] 765 if !ok || g.group == nil { 766 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 767 return body 768 } 769 770 res := new(types.RemovePrincipalsFromLocalGroupResponse) 771 772 for _, id := range req.PrincipalsIds { 773 _, ok := s.dir[id] 774 if !ok { 775 body.Fault_ = simulator.Fault("", new(vim.NotFound)) 776 return body 777 } 778 779 removed := false 780 if _, ok := g.members[id]; ok { 781 delete(g.members, id) 782 removed = true 783 } 784 785 res.Returnval = append(res.Returnval, removed) 786 } 787 788 body.Res = res 789 790 return body 791 }