private static void BatchUpMembershipThatExceedsSizeLimit(TeamFoundationIdentity membershipGroup, int batchSizeLimit, IIdentityManagementService ims, List<TeamFoundationIdentity> membershipGroups, Dictionary<IdentityDescriptor, TeamFoundationIdentity> allIdentities) { var batchNum = 0; var remainder = membershipGroup.Members.Length; var descriptors = new IdentityDescriptor[batchSizeLimit]; while (remainder > 0) { var startAt = batchNum*batchSizeLimit; var length = batchSizeLimit; if (length > remainder) { length = remainder; descriptors = new IdentityDescriptor[length]; } Array.Copy(membershipGroup.Members, startAt, descriptors, 0, length); var memberIdentities = ims.ReadIdentities(descriptors, MembershipQuery.Direct, ReadIdentityOptions.None); AddCollectionUsersAndGroupsToLists(memberIdentities, membershipGroups, allIdentities); remainder -= length; } }
private void FetchIdentities(IdentityDescriptor[] descriptors) { TeamFoundationIdentity[] identities; // If total membership exceeds batch size limit for Read, break it up int batchSizeLimit = 100000; if (descriptors.Length > batchSizeLimit) { int batchNum = 0; int remainder = descriptors.Length; var batchDescriptors = new IdentityDescriptor[batchSizeLimit]; while (remainder > 0) { int startAt = batchNum * batchSizeLimit; int length = batchSizeLimit; if (length > remainder) { length = remainder; batchDescriptors = new IdentityDescriptor[length]; } Array.Copy(descriptors, startAt, batchDescriptors, 0, length); identities = tfsContext.IdentityManagementService.ReadIdentities(batchDescriptors, MembershipQuery.Direct, ReadIdentityOptions.None); SortIdentities(identities); remainder -= length; } } else { identities = tfsContext.IdentityManagementService.ReadIdentities(descriptors, MembershipQuery.Direct, ReadIdentityOptions.None); SortIdentities(identities); } }
public PolicyViolationEvent(Type policyType, object originalEvent, IdentityDescriptor identity, string message) { PolicyType = policyType; OriginalEvent = originalEvent; Identity = identity; Message = message; }
private static void BatchUpMembershipThatExceedsSizeLimit(TeamFoundationIdentity membershipGroup, int batchSizeLimit, IIdentityManagementService ims, List <TeamFoundationIdentity> membershipGroups, Dictionary <IdentityDescriptor, TeamFoundationIdentity> allIdentities) { var batchNum = 0; var remainder = membershipGroup.Members.Length; var descriptors = new IdentityDescriptor[batchSizeLimit]; while (remainder > 0) { var startAt = batchNum * batchSizeLimit; var length = batchSizeLimit; if (length > remainder) { length = remainder; descriptors = new IdentityDescriptor[length]; } Array.Copy(membershipGroup.Members, startAt, descriptors, 0, length); var memberIdentities = ims.ReadIdentities(descriptors, MembershipQuery.Direct, ReadIdentityOptions.None); AddCollectionUsersAndGroupsToLists(memberIdentities, membershipGroups, allIdentities); remainder -= length; } }
static void AddUserToAccount(string username) { //Reference taken from https://blogs.msdn.microsoft.com/buckh/2014/10/07/how-to-add-licensed-users-to-vs-online-via-the-api/ try { string _personalAccessToken = ConfigurationSettings.AppSettings["appsetting.pat"].ToString(); var creds = new VssBasicCredential("", _personalAccessToken); string _vstsaccountname = ConfigurationSettings.AppSettings["appsetting.vstsacountname"].ToString(); var vssConnection = new VssConnection(new Uri("https://" + _vstsaccountname + ".vssps.visualstudio.com"), creds); string aadtenantid = ConfigurationSettings.AppSettings["appsetting.aadtenantid"].ToString(); var licensingClient = vssConnection.GetClient <LicensingHttpClient>(); var identityClient = vssConnection.GetClient <IdentityHttpClient>(); var collectionScope = identityClient.GetScopeAsync(_vstsaccountname).Result; var licensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, GroupWellKnownSidConstants.LicensedUsersGroupSid); var identifier = String.Concat(SidIdentityHelper.GetDomainSid(collectionScope.Id), SidIdentityHelper.WellKnownSidType, licensedUsersGroupDescriptor.Identifier.Substring(SidIdentityHelper.WellKnownSidPrefix.Length)); var collectionLicensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, identifier); var upnIdentity = string.Format("upn:{0}\\{1}", aadtenantid, username); var newUserDesciptor = new IdentityDescriptor(IdentityConstants.BindPendingIdentityType, upnIdentity); bool result = identityClient.AddMemberToGroupAsync(collectionLicensedUsersGroupDescriptor, newUserDesciptor).Result; var userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, username).Result.FirstOrDefault(); var entitlement = licensingClient.AssignEntitlementAsync(userIdentity.Id, AccountLicense.Auto).Result; } catch (Exception e) { Console.WriteLine(e.Message); if (e.InnerException != null) { Console.WriteLine(e.InnerException.Message); } } }
/// <summary> /// Constructs an AccessCheckException. /// </summary> /// <param name="descriptor">The identity descriptor which was checked.</param> /// <param name="identityDisplayName">The display name of the identity which was checked.</param> /// <param name="token">The token which was checked.</param> /// <param name="requestedPermissions">The requested permissions, which were not satisifed by the check.</param> /// <param name="namespaceId">The security namespace which was checked.</param> /// <param name="message">A descriptive message for the exception.</param> public AccessCheckException( IdentityDescriptor descriptor, String identityDisplayName, String token, int requestedPermissions, Guid namespaceId, String message) : this(descriptor, token, requestedPermissions, namespaceId, message) { this.IdentityDisplayName = identityDisplayName; }
public void WorkItemRepositoryBuilt(Uri uri, IdentityDescriptor toImpersonate) { if (toImpersonate != null) { this.logger.Log(LogLevel.Verbose, "Built a new Work Item Repository for {0} as {1}", uri, toImpersonate); } else { this.logger.Log(LogLevel.Diagnostic, "Built a new Work Item Repository for {0}", uri); } }
/// <summary> /// Retrieve the target identity for a given source descriptor /// </summary> /// <param name="sourceIdentityDescriptor">Source identity Descriptor</param> /// <returns>Target Identity</returns> private TeamFoundationIdentity GetTargetIdentity(IdentityDescriptor sourceIdentityDescriptor) { var sourceIdentity = sourceIdentityManagementService.ReadIdentity( sourceIdentityDescriptor, MembershipQuery.Direct, ReadIdentityOptions.ExtendedProperties); string sourceIdentityMail = sourceIdentity.GetProperty("Mail") as string; // Try refresh the Identity if we are missing the Mail property if (string.IsNullOrEmpty(sourceIdentityMail)) { sourceIdentity = sourceIdentityManagementService.ReadIdentity( sourceIdentityDescriptor, MembershipQuery.Direct, ReadIdentityOptions.ExtendedProperties); sourceIdentityMail = sourceIdentity.GetProperty("Mail") as string; } if (!string.IsNullOrEmpty(sourceIdentityMail)) { // translate source assignedto name to target identity var targetIdentity = targetIdentityManagementService.ReadIdentity( IdentitySearchFactor.MailAddress, sourceIdentityMail, MembershipQuery.Direct, ReadIdentityOptions.None); if (targetIdentity == null) { targetIdentity = targetIdentityManagementService.ReadIdentity( IdentitySearchFactor.AccountName, sourceIdentityMail, MembershipQuery.Direct, ReadIdentityOptions.None); } if (targetIdentity == null) { Trace.Write($"Cannot find tester with e-mail [{sourceIdentityMail}] in target system. Cannot assign.", "TestPlansAndSuites"); return(null); } return(targetIdentity); } else { Trace.Write($"No e-mail address known in source system for [{sourceIdentity.DisplayName}]. Cannot translate to target.", "TestPlansAndSuites"); return(null); } }
internal static IdentityDescriptorWrapper GetInstance() { IdentityDescriptor real = default(IdentityDescriptor); RealInstanceFactory(ref real); var instance = (IdentityDescriptorWrapper)IdentityDescriptorWrapper.GetWrapper(real); InstanceFactory(ref instance); if (instance == null) { Assert.Inconclusive("Could not Create Test Instance"); } return(instance); }
/// <summary> /// /// </summary> /// <param name="groupID"></param> /// <param name="userID"></param> /// <returns></returns> private bool RemoveMemberFromGroup(IdentityDescriptor groupID, IdentityDescriptor userID) { try { if (groupID != null && userID != null && idMgmtSvc.IsMember(groupID, userID)) { idMgmtSvc.RemoveMemberFromApplicationGroup(groupID, userID); } } catch (Exception ex) { FileHelper.Log(ex.Message); return(false); } return(true); }
private IEnumerable <PermissionAssignment> GetResourcePermissions( IdentityDescriptor identity, IReadOnlyList <Resource> resources, string namespaceName) { try { var @namespace = _facade.GetNamespace(namespaceName); var tfsIdentity = _facade.GetIdentity(identity); var permissions = GetResourcePermissions(resources, @namespace, tfsIdentity); return(permissions); } catch (Exception e) { Log.Warning($"{e.Message}"); return(Enumerable.Empty <PermissionAssignment>()); } }
/// <summary> /// Constructs an AccessCheckException. /// </summary> /// <param name="descriptor">The identity descriptor which was checked.</param> /// <param name="token">The token which was checked.</param> /// <param name="requestedPermissions">The requested permissions, which were not satisifed by the check.</param> /// <param name="namespaceId">The security namespace which was checked.</param> /// <param name="message">A descriptive message for the exception.</param> public AccessCheckException( IdentityDescriptor descriptor, String token, int requestedPermissions, Guid namespaceId, String message) : base(message) { ArgumentUtility.CheckForNull(descriptor, nameof(descriptor)); ArgumentUtility.CheckForNull(token, nameof(token)); ArgumentUtility.CheckForNull(message, nameof(message)); this.Descriptor = descriptor; this.Token = token; this.RequestedPermissions = requestedPermissions; this.NamespaceId = namespaceId; }
public TeamFoundationIdentity[] GetUsers() { var ims = TfsTeamProjectCollection.GetService <IIdentityManagementService>(); // Get expanded membership of the Valid Users group, which is all identities in this host var group = ims.ReadIdentity(GroupWellKnownDescriptors.EveryoneGroup, MembershipQuery.Expanded, ReadIdentityOptions.None); var resultIdentities = new HashSet <TeamFoundationIdentity>();; // If total membership exceeds batch size limit for Read, break it up int batchSizeLimit = 100000; var descriptors = group.Members; if (descriptors.Length > batchSizeLimit) { TeamFoundationIdentity[] identities; int batchNum = 0; int remainder = descriptors.Length; IdentityDescriptor[] batchDescriptors = new IdentityDescriptor[batchSizeLimit]; while (remainder > 0) { int startAt = batchNum * batchSizeLimit; int length = batchSizeLimit; if (length > remainder) { length = remainder; batchDescriptors = new IdentityDescriptor[length]; } Array.Copy(descriptors, startAt, batchDescriptors, 0, length); identities = ims.ReadIdentities(batchDescriptors, MembershipQuery.Direct, ReadIdentityOptions.None); resultIdentities.UnionWith(identities); remainder -= length; } } else { resultIdentities.UnionWith(ims.ReadIdentities(descriptors, MembershipQuery.Direct, ReadIdentityOptions.None)); } var validWebUsers = resultIdentities.Where(identity => identity.Descriptor.Identifier.EndsWith("@live.com", StringComparison.InvariantCultureIgnoreCase) && identity.IsActive == true && identity.IsContainer == false).ToArray(); var validLocalUsers = resultIdentities.Where(identity => identity.Descriptor.IdentityType == "System.Security.Principal.WindowsIdentity" && identity.IsActive == true && identity.IsContainer == false).ToArray(); var users = validWebUsers.Concat(validLocalUsers).Where(identity => System.Globalization.CultureInfo.InvariantCulture.CompareInfo.IndexOf(identity.DisplayName, "build", System.Globalization.CompareOptions.IgnoreCase) < 0); return(users .ToArray()); }
public TeamFoundationIdentity GetIdentity(IdentityDescriptor identity) { var tfsIdentity = _identityService.ReadIdentity(identity, MembershipQuery.Direct, ReadIdentityOptions.None); if (tfsIdentity != null) { return(tfsIdentity); } var adIdentity = _identityService.ReadIdentity(identity, MembershipQuery.Direct, ReadIdentityOptions.IncludeReadFromSource); if (adIdentity != null) { return(adIdentity); } throw new Exception($"Identity not found: {identity}"); }
public async static Task CheckIdentity(WorkItemClientConnection client, string project) { IdentityHttpClient targetIdentityClient = null; var currentUserIdentity = client.Connection.AuthorizedIdentity; IdentityDescriptor adminId = null; Logger.LogInformation($"Checking administrative permissions for {client.Connection.AuthorizedIdentity.DisplayName} in {project}"); try { targetIdentityClient = client.Connection.GetClient <IdentityHttpClient>(); var targetIdentity = (await targetIdentityClient.ReadIdentitiesAsync(IdentitySearchFilter.General, "Project Collection Administrators", queryMembership: QueryMembership.Expanded)).FirstOrDefault(); if (targetIdentity != null) { //Check if the current user account running the tool is a member of project collection administrators #region HackRegion adminId = targetIdentity.Members.Where(a => string.Equals(a.Identifier, currentUserIdentity.Descriptor.Identifier, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); //We can replace the above code with the following two statements when they work //var me = targetIdentityClient.GetIdentitySelfAsync().Result; //var isMember = targetIdentityClient.IsMember(targetIdentity.Descriptor, currentUserIdentity.Descriptor).Result; #endregion } } catch (Exception e) when(e.InnerException is VssUnauthorizedException) { throw new ValidationException(client.Connection.Uri.ToString(), (VssUnauthorizedException)e.InnerException); } catch (Exception e) { throw new ValidationException("An unexpected error occurred while checking administrative permissions", e); } if (adminId != null) { Logger.LogSuccess(LogDestination.All, $"Verified {client.Connection.AuthorizedIdentity.DisplayName} is a Project Collection Administrator in {project}"); } else { throw new ValidationException($"{currentUserIdentity.Descriptor.Identifier} is not a Project Collection Administrator in {project}. Please follow https://www.visualstudio.com/en-us/docs/setup-admin/add-administrator-tfs on how to add the account to the project collection administrators"); } }
internal static void FetchIdentities(IdentityDescriptor[] descriptors, List <TeamFoundationIdentity> globalGroups, Dictionary <IdentityDescriptor, TeamFoundationIdentity> globalIdentities) { Int64 startTicks = Log.APPLICATION("Enter", Common.LOG_CATEGORY); TeamFoundationIdentity[] identities; // If total membership exceeds batch size limit for Read, break it up int batchSizeLimit = 100000; if (descriptors.Length > batchSizeLimit) { int batchNum = 0; int remainder = descriptors.Length; IdentityDescriptor[] batchDescriptors = new IdentityDescriptor[batchSizeLimit]; while (remainder > 0) { int startAt = batchNum * batchSizeLimit; int length = batchSizeLimit; if (length > remainder) { length = remainder; batchDescriptors = new IdentityDescriptor[length]; } Array.Copy(descriptors, startAt, batchDescriptors, 0, length); identities = AzureDevOpsExplorer.Presentation.Views.Server.IdentityManagementService.ReadIdentities(batchDescriptors, MembershipQuery.Direct, ReadIdentityOptions.None); SortIdentities(identities, globalGroups, globalIdentities); remainder -= length; } } else { identities = AzureDevOpsExplorer.Presentation.Views.Server.IdentityManagementService.ReadIdentities(descriptors, MembershipQuery.Direct, ReadIdentityOptions.None); SortIdentities(identities, globalGroups, globalIdentities); } Log.APPLICATION("Exit", Common.LOG_CATEGORY, startTicks); }
/// <summary> /// Checks if a group exists and returns the descriptor. /// If the group does not exist, it is created (if the createIfNew flag is set to true). /// </summary> /// <param name="scope">Scope Id to limit the search area - default (empty string) is collection level.</param> /// <param name="groupName">Name of the group. Also used as group description for create.</param> /// <param name="createIfNew">Set to true for create. Default is false.</param> /// <returns>The IdentityDescriptor of the group. Returns null in case of any errors.</returns> private IdentityDescriptor CheckIfGroupExists(string scope, string groupName, bool createIfNew) { TeamFoundationIdentity tfi = null; try { // Find the group using Account Name tfi = idMgmtSvc.ReadIdentity(IdentitySearchFactor.AccountName, groupName, MembershipQuery.Direct, ReadIdentityOptions.None); if (tfi == null && createIfNew) { FileHelper.Log("Creating new group..." + groupName); // SCOPE: If a Team Project is found, add the group in that TP. // If not, add the group at collection level. // string scopeId = (teamProjectIdentity == null) ? string.Empty : teamProjectIdentity.Descriptor.Identifier; //string scopeId = tpCollection.Uri.ToString() + "/" + scope; IdentityDescriptor idDesc = idMgmtSvc.CreateApplicationGroup(scope, groupName, groupName); FileHelper.Log("Group creation successful..." + groupName); return(idDesc); } else { FileHelper.Log("Group identity found..." + groupName); return(tfi.Descriptor); } } catch (Exception ex) { FileHelper.Log(ex.Message); FileHelper.Log(ex.StackTrace); } return(null); }
static void Main(string[] args) { string project = "http://xxx.xxx.xxx.xxx:8080/tfs"; TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri(project)); var tps = tpc.GetService <VersionControlServer>(); var ttt = tps.GetTeamProject("ProjectName"); ISecurityService securityService = tpc.GetService <ISecurityService>(); System.Collections.ObjectModel.ReadOnlyCollection <SecurityNamespace> securityNamespaces = securityService.GetSecurityNamespaces(); IGroupSecurityService gss = tpc.GetService <IGroupSecurityService>(); Identity SIDS = gss.ReadIdentity(SearchFactor.AccountName, "GroupName", QueryMembership.Expanded);//GourName format: [ProjectName]\\GourpName IdentityDescriptor id = new IdentityDescriptor("Microsoft.TeamFoundation.Identity", SIDS.Sid); List <SecurityNamespace> securityList = securityNamespaces.ToList <SecurityNamespace>(); string securityToken; foreach (SecurityNamespace sn in securityList) { if (sn.Description.DisplayName == "Project") { securityToken = "$PROJECT:" + ttt.ArtifactUri.AbsoluteUri; sn.SetPermissions(securityToken, id, 115, 0, true); } } }
public bool RemoveTeamAdministrator(string team, string user, out string message) { message = string.Empty; bool ret = true; TeamFoundationTeam t = this.teamService.ReadTeam(this.projectInfo.Uri, team, null); TeamFoundationIdentity i = this.identityManagementService.ReadIdentity(IdentitySearchFactor.AccountName, user, MembershipQuery.Direct, ReadIdentityOptions.None); if (t == null) { message = "Team [" + team + "] not found"; ret = false; } if (i == null) { message = "User [" + user + "] not found"; ret = false; } if (ret) { this.identityManagementService.AddMemberToApplicationGroup(t.Identity.Descriptor, i.Descriptor); message = "User removed "; IdentityDescriptor descriptor = i.Descriptor; string token = GetTeamAdminstratorsToken(t); ISecurityService securityService = this.teamProjectCollection.GetService <ISecurityService>(); SecurityNamespace securityNamespace = securityService.GetSecurityNamespace(FrameworkSecurity.IdentitiesNamespaceId); securityNamespace.RemovePermissions(token, descriptor, 15); } return(ret); }
private static void ApplySecurityNamespacePermissions(string token, IdentityDescriptor identity, SecurityNamespace securityNamespace, IEnumerable <PermissionChange> permissions) { if (permissions.Where(p => p.Action != PermissionChangeAction.None).Any()) { var allows = permissions.Where(p => p.Action == PermissionChangeAction.Allow).Aggregate(0, (sum, p) => sum += p.Permission.PermissionBit); var denies = permissions.Where(p => p.Action == PermissionChangeAction.Deny).Aggregate(0, (sum, p) => sum += p.Permission.PermissionBit); var inherits = permissions.Where(p => p.Action == PermissionChangeAction.Inherit).Aggregate(0, (sum, p) => sum += p.Permission.PermissionBit); if (allows > 0 || denies > 0 || inherits > 0) { if (securityNamespace == null) { throw new InvalidOperationException("Permissions are being modified but the security namespace is not available in the current Team Project Collection."); } if (inherits > 0) { securityNamespace.RemovePermissions(token, identity, inherits); } if (allows > 0 || denies > 0) { securityNamespace.SetPermissions(token, identity, allows, denies, true); } } } }
/// <summary> /// Adds the specified user to the TFS security group /// </summary> /// <param name="groupID">The TFS Security Group identifier</param> /// <param name="userName">The User name</param> /// <returns>true, if successful.</returns> private bool AddMemberToGroup(IdentityDescriptor groupId, string userName) { try { TeamFoundationIdentity tfiUser = idMgmtSvc.ReadIdentity(IdentitySearchFactor.AccountName, userName, MembershipQuery.Direct, ReadIdentityOptions.IncludeReadFromSource); if (idMgmtSvc.IsMember(groupId, tfiUser.Descriptor)) { FileHelper.Log("User {0} already part of group {1}", userName, groupId.Identifier); } else { idMgmtSvc.AddMemberToApplicationGroup(groupId, tfiUser.Descriptor); FileHelper.Log("User {0} added to group {1}", userName, groupId.Identifier); } } catch (Exception ex) { FileHelper.Log(ex.Message); return(false); } return(true); }
private static void ApplyGroupMemberChanges(ApplicationTask task, SecurityGroupChange securityGroup, IdentityDescriptor groupDescriptor, IIdentityManagementService ims, IList <TeamFoundationIdentity> existingMembers) { var existingMemberAccountNames = existingMembers.Select(m => GetAccountName(m)); // Remove requested members. if (securityGroup.RemoveAllUsers) { foreach (var member in existingMembers) { ims.RemoveMemberFromApplicationGroup(groupDescriptor, member.Descriptor); } } else { if (!string.IsNullOrEmpty(securityGroup.UsersToRemove)) { foreach (var userToRemove in securityGroup.UsersToRemove.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(u => u.Trim())) { if (existingMemberAccountNames.Any(m => string.Equals(m, userToRemove, StringComparison.OrdinalIgnoreCase))) { PerformUserAction(task, ims, userToRemove, identityToRemove => ims.RemoveMemberFromApplicationGroup(groupDescriptor, identityToRemove.Descriptor)); } } } } // Add requested members. if (!string.IsNullOrEmpty(securityGroup.UsersToAdd)) { foreach (var userToAdd in securityGroup.UsersToAdd.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(u => u.Trim())) { if (!existingMemberAccountNames.Any(m => string.Equals(m, userToAdd, StringComparison.OrdinalIgnoreCase))) { PerformUserAction(task, ims, userToAdd, identityToAdd => ims.AddMemberToApplicationGroup(groupDescriptor, identityToAdd.Descriptor)); } } } }
public void AddMemberToTeam(string teamName, IdentityDescriptor descriptor) { var groupSid = GetGroupIdentityForTeamName(teamName); groupSecurityService.AddMemberToApplicationGroup(groupSid.Sid, descriptor.Identifier); }
private TeamFoundationIdentity[] allTfsUsers(TfsConnection tfs) { try { IIdentityManagementService ims = tfs.GetService<IIdentityManagementService>(); TeamFoundationIdentity[] projectGroups = ims.ListApplicationGroups(tfsProject.Project, ReadIdentityOptions.None); Dictionary<IdentityDescriptor, object> descSet = new Dictionary<IdentityDescriptor, object>(IdentityDescriptorComparer.Instance); foreach (TeamFoundationIdentity projectGroup in projectGroups) { descSet[projectGroup.Descriptor] = projectGroup.Descriptor; } projectGroups = ims.ReadIdentities(descSet.Keys.ToArray(), MembershipQuery.Expanded, ReadIdentityOptions.None); foreach (TeamFoundationIdentity projectGroup in projectGroups) { foreach (IdentityDescriptor mem in projectGroup.Members) { descSet[mem] = mem; } } TeamFoundationIdentity[] identities = new TeamFoundationIdentity[0]; int batchSizeLimit = 100000; var descriptors = descSet.Keys.ToArray(); if (descriptors.Length > batchSizeLimit) { int batchNum = 0; int remainder = descriptors.Length; IdentityDescriptor[] batchDescriptors = new IdentityDescriptor[batchSizeLimit]; while (remainder > 0) { int startAt = batchNum * batchSizeLimit; int length = batchSizeLimit; if (length > remainder) { length = remainder; batchDescriptors = new IdentityDescriptor[length]; } Array.Copy(descriptors, startAt, batchDescriptors, 0, length); identities = ims.ReadIdentities(batchDescriptors, MembershipQuery.Direct, ReadIdentityOptions.None); remainder -= length; } } else { identities = ims.ReadIdentities(descriptors, MembershipQuery.Direct, ReadIdentityOptions.None); } return identities.Where(_ => !_.IsContainer && _.Descriptor.IdentityType != "Microsoft.TeamFoundation.UnauthenticatedIdentity").ToArray(); } catch { /* Do nothing */ } return (tfs != null? new TeamFoundationIdentity[] { tfs.AuthorizedIdentity } : new TeamFoundationIdentity[0]); }
private static void AddUserToAccount(string VssAccountName, string VssUserToAddMailAddress, License VssLicense) { try { // The first call is to see if the user already exists in the account. // Since this is the first call to the service, this will trigger the sign-in window to pop up. Console.WriteLine("Sign in as the admin of account {0}. You will see a sign-in window on the desktop.", VssAccountName); var userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, VssUserToAddMailAddress).Result.FirstOrDefault(); if (userIdentity == null) { var username = VssUserToAddMailAddress.Substring(0, VssUserToAddMailAddress.IndexOf("@")); userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.MailAddress, VssUserToAddMailAddress).Result.FirstOrDefault(); } // If the identity is null, this is a user that has not yet been added to the account. // We'll need to add the user as a "bind pending" - meaning that the email address of the identity is // recorded so that the user can log into the account, but the rest of the details of the identity // won't be filled in until first login. if (userIdentity == null) { Console.WriteLine("Creating a new identity and adding it to the collection's licensed users group."); // We are adding the user to a collection, and at the moment only one collection is supported per // account in VSO. var collectionScope = identityClient.GetScopeAsync(VssAccountName).Result; // First get the descriptor for the licensed users group, which is a well known (built in) group. var licensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, GroupWellKnownSidConstants.LicensedUsersGroupSid); // Now convert that into the licensed users group descriptor into a collection scope identifier. var identifier = String.Concat(SidIdentityHelper.GetDomainSid(collectionScope.Id), SidIdentityHelper.WellKnownSidType, licensedUsersGroupDescriptor.Identifier.Substring(SidIdentityHelper.WellKnownSidPrefix.Length)); // Here we take the string representation and create the strongly-type descriptor var collectionLicensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, identifier); // Get the domain from the user that runs this code. This domain will then be used to construct // the bind-pending identity. The domain is either going to be "Windows Live ID" or the Azure // Active Directory (AAD) unique identifier, depending on whether the account is connected to // an AAD tenant. Then we'll format this as a UPN string. var currUserIdentity = vssConnection.AuthorizedIdentity.Descriptor; var directory = "Windows Live ID"; // default to an MSA (fka Live ID) if (currUserIdentity.Identifier.Contains('\\')) { // The identifier is domain\userEmailAddress, which is used by AAD-backed accounts. // We'll extract the domain from the admin user. directory = currUserIdentity.Identifier.Split(new char[] { '\\' })[0]; } var upnIdentity = string.Format("upn:{0}\\{1}", directory, VssUserToAddMailAddress); // Next we'll create the identity descriptor for a new "bind pending" user identity. var newUserDesciptor = new IdentityDescriptor(IdentityConstants.BindPendingIdentityType, upnIdentity); // We are ready to actually create the "bind pending" identity entry. First we have to add the // identity to the collection's licensed users group. Then we'll retrieve the Identity object // for this newly-added user. Without being added to the licensed users group, the identity // can't exist in the account. bool result = identityClient.AddMemberToGroupAsync(collectionLicensedUsersGroupDescriptor, newUserDesciptor).Result; userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, VssUserToAddMailAddress).Result.FirstOrDefault(); } Console.WriteLine("Assigning license to user."); var entitlement = licensingClient.AssignEntitlementAsync(userIdentity.Id, VssLicense).Result; Console.WriteLine("Success!"); } catch (Exception e) { using (StreamWriter sw = File.AppendText("fubarAccounts.txt")) { sw.WriteLine("{0}, failed, {1}", VssUserToAddMailAddress, e.InnerException.Message); } Console.WriteLine("\r\nSomething went wrong..."); Console.WriteLine(e.Message); if (e.InnerException != null) { Console.WriteLine(e.InnerException.Message); } } }
/// <summary> /// This is the one where all the magic starts. Main() so to speak. I will load the settings, connect to TFS and apply the aggregation rules. /// </summary> public EventNotificationStatus ProcessEvent( TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { var runtime = RuntimeContext.GetContext( GetServerSettingsFullPath, new RequestContextWrapper(requestContext), new ServerEventLogger(LogLevel.Normal)); if (runtime.HasErrors) { statusCode = 99; statusMessage = string.Join(". ", runtime.Errors); properties = null; return(EventNotificationStatus.ActionPermitted); } // HACK: remove cast for ProcessEventException var logger = (ServerEventLogger)runtime.Logger; var result = new ProcessingResult(); try { // Check if we have a workitem changed event before proceeding if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent) { var uri = this.GetCollectionUriFromContext(requestContext); IdentityDescriptor toImpersonate = null; if (runtime.Settings.AutoImpersonate) { toImpersonate = this.GetIdentityToImpersonate(requestContext, notificationEventArgs as WorkItemChangedEvent); } using (EventProcessor eventProcessor = new EventProcessor(uri.AbsoluteUri, toImpersonate, runtime)) { var context = runtime.RequestContext; var notification = new NotificationWrapper( notificationType, notificationEventArgs as WorkItemChangedEvent); logger.StartingProcessing(context, notification); result = eventProcessor.ProcessEvent(context, notification); logger.ProcessingCompleted(result); } } } catch (Exception e) { logger.ProcessEventException(e); // notify failure result.StatusCode = -1; result.StatusMessage = "Unexpected error: " + e.Message; result.NotificationStatus = EventNotificationStatus.ActionPermitted; } statusCode = result.StatusCode; statusMessage = result.StatusMessage; properties = result.ExceptionProperties; return(result.NotificationStatus); }
private async static Task <Guid> AddMemberToAccount(Project project, TraceWriter log) { string username = ConfigurationManager.AppSettings.Get("VSTSUserName"); string pattoken = ConfigurationManager.AppSettings.Get("VSTSPat"); string accountName = ConfigurationManager.AppSettings.Get("VSTSAccountName"); if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(pattoken) || string.IsNullOrWhiteSpace(accountName)) { log.Error("AppSettings missing for VSTSUserName, VSTSPat or VSTSAccountName"); return(Guid.Empty); } try { VssBasicCredential credentials = new VssBasicCredential(username, pattoken); VssConnection connection = new VssConnection(new Uri($"https://{accountName}.vssps.visualstudio.com/"), credentials); var identityClient = connection.GetClient <IdentityHttpClient>(); var licensingClient = connection.GetClient <LicensingHttpClient>(); var userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, project.Owner).Result.FirstOrDefault(); // If the identity is null, this is a user that has not yet been added to the account. // We'll need to add the user as a "bind pending" - meaning that the email address of the identity is // recorded so that the user can log into the account, but the rest of the details of the identity // won't be filled in until first login. if (userIdentity != null) { log.Info($"User:{project.Owner} already exists in VSTS account with name: {accountName}"); return(userIdentity.Id); } log.Info("Creating a new identity and adding it to the collection's licensed users group."); var collectionScope = identityClient.GetScopeAsync(accountName).Result; // First get the descriptor for the licensed users group, which is a well known (built in) group. var licensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, GroupWellKnownSidConstants.LicensedUsersGroupSid); // Now convert that into the licensed users group descriptor into a collection scope identifier. var identifier = string.Concat(SidIdentityHelper.GetDomainSid(collectionScope.Id), SidIdentityHelper.WellKnownSidType, licensedUsersGroupDescriptor.Identifier.Substring(SidIdentityHelper.WellKnownSidPrefix.Length)); // Here we take the string representation and create the strongly-type descriptor var collectionLicensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, identifier); // Get the domain from the user that runs this code. This domain will then be used to construct // the bind-pending identity. The domain is either going to be "Windows Live ID" or the Azure // Active Directory (AAD) unique identifier, depending on whether the account is connected to // an AAD tenant. Then we'll format this as a UPN string. var currUserIdentity = connection.AuthorizedIdentity.Descriptor; if (!currUserIdentity.Identifier.Contains('\\')) { log.Error("Could not find directory for user"); return(Guid.Empty); } // The identifier is domain\userEmailAddress, which is used by AAD-backed accounts. // We'll extract the domain from the admin user. var directory = currUserIdentity.Identifier.Split(new char[] { '\\' })[0]; var upnIdentity = string.Format("upn:{0}\\{1}", directory, project.Owner); // Next we'll create the identity descriptor for a new "bind pending" user identity. var newUserDesciptor = new IdentityDescriptor(IdentityConstants.BindPendingIdentityType, upnIdentity); // We are ready to actually create the "bind pending" identity entry. First we have to add the // identity to the collection's licensed users group. Then we'll retrieve the Identity object // for this newly-added user. Without being added to the licensed users group, the identity // can't exist in the account. bool result = identityClient.AddMemberToGroupAsync(collectionLicensedUsersGroupDescriptor, newUserDesciptor).Result; userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, project.Owner).Result.FirstOrDefault(); log.Info("Assigning license to user."); Microsoft.VisualStudio.Services.Licensing.License licence = GetLicense(); var entitlement = licensingClient.AssignEntitlementAsync(userIdentity.Id, licence, false).Result; log.Info($"Added {project.Owner} as a user with license:{licence.ToString()} to account with name:{accountName}"); return(userIdentity.Id); } catch (Exception e) { log.Error(e.Message); return(Guid.Empty); } }
static partial void RealInstanceFactory(ref IdentityDescriptor real, string callerName) { real = (IdentityDescriptor)FormatterServices.GetUninitializedObject(typeof(IdentityDescriptor)); }
public ConnectionInfo(Uri uri, IdentityDescriptor toImpersonate) { this.ProjectCollectionUri = uri; this.Impersonate = toImpersonate; }
private TeamFoundationIdentity[] allTfsUsers(TfsConnection tfs) { try { IIdentityManagementService ims = tfs.GetService <IIdentityManagementService>(); TeamFoundationIdentity[] projectGroups = ims.ListApplicationGroups(tfsProject.Project, ReadIdentityOptions.None); Dictionary <IdentityDescriptor, object> descSet = new Dictionary <IdentityDescriptor, object>(IdentityDescriptorComparer.Instance); foreach (TeamFoundationIdentity projectGroup in projectGroups) { descSet[projectGroup.Descriptor] = projectGroup.Descriptor; } projectGroups = ims.ReadIdentities(descSet.Keys.ToArray(), MembershipQuery.Expanded, ReadIdentityOptions.None); foreach (TeamFoundationIdentity projectGroup in projectGroups) { foreach (IdentityDescriptor mem in projectGroup.Members) { descSet[mem] = mem; } } TeamFoundationIdentity[] identities = new TeamFoundationIdentity[0]; int batchSizeLimit = 100000; var descriptors = descSet.Keys.ToArray(); if (descriptors.Length > batchSizeLimit) { int batchNum = 0; int remainder = descriptors.Length; IdentityDescriptor[] batchDescriptors = new IdentityDescriptor[batchSizeLimit]; while (remainder > 0) { int startAt = batchNum * batchSizeLimit; int length = batchSizeLimit; if (length > remainder) { length = remainder; batchDescriptors = new IdentityDescriptor[length]; } Array.Copy(descriptors, startAt, batchDescriptors, 0, length); identities = ims.ReadIdentities(batchDescriptors, MembershipQuery.Direct, ReadIdentityOptions.None); remainder -= length; } } else { identities = ims.ReadIdentities(descriptors, MembershipQuery.Direct, ReadIdentityOptions.None); } return(identities.Where(_ => !_.IsContainer && _.Descriptor.IdentityType != "Microsoft.TeamFoundation.UnauthenticatedIdentity").ToArray()); } catch { /* Do nothing */ } return(tfs != null? new TeamFoundationIdentity[] { tfs.AuthorizedIdentity } : new TeamFoundationIdentity[0]); }
/// <summary> /// Adds a domain user to a TFS Security group, at a collection level. If the group does not exist, it will be created. /// The method will assume the context of the executing user. /// i.e.: To add a domain user, execute in the context of a domain user. /// Usage Scenarios: /// 1. Use this method to add a given user to multiple groups /// 2. Use this method to add multiple users to multiple groups /// </summary> /// <param name="user2Groups">A list of user to groups mapping</param> /// <returns></returns> public ReturnCode AddUsersToGroups(List <User2GroupsMap> user2Groups) { if (tpCollection == null) { FileHelper.Log("Collection not initialized."); return(ReturnCode.Failure); } int errorCount = 0; int iteration = 0; try { if (user2Groups == null || user2Groups.Capacity <= 0) { FileHelper.Log("Users 2 Groups mapping is not available."); return(ReturnCode.Failure); } // For each User to Groups mapping foreach (User2GroupsMap u2gmap in user2Groups) { string userName = u2gmap.UserName; // For each team project listed // Note that the tool assumes that if there are more than one team project specified, // the user wants to add all groups listed to all team projects foreach (string teamProjName in u2gmap.TeamProjectNames) { ProjectInfo objTeamProj = GetProject(teamProjName); iteration++; if (objTeamProj != null) { FileHelper.Log("Team Project: {0} found", objTeamProj.Name); // For each group name specified foreach (string grpName in u2gmap.GroupNames) { iteration++; string searchableGroupName = string.Format(GROUP_NAME_FORMAT, teamProjName, grpName); #if TFS10 bool success = CheckIfGroupExists_TFS10(objTeamProj.Uri, searchableGroupName, grpName, true); if (success) { iteration++; if (!AddMemberToGroup_TFS10(objTeamProj.Name, searchableGroupName, userName)) { FileHelper.Log("Failed to add user {0} to group {1}", userName, grpName); errorCount++; } } else { errorCount++; } #else IdentityDescriptor groupId = CheckIfGroupExists(objTeamProj.Uri, searchableGroupName, true); if (groupId != null) { if (AddMemberToGroup(groupId, userName)) { FileHelper.Log("User {0} added to group {1}", userName, searchableGroupName); } else { FileHelper.Log("Failed to add user {0} to group {1}", userName, searchableGroupName); errorCount++; } } else { errorCount++; } #endif } } else { errorCount++; } } } } catch (Exception ex) { FileHelper.Log(ex.Message); return(ReturnCode.Failure); } return(GetReturnCode(iteration, errorCount)); }
static partial void RealInstanceFactory(ref IdentityDescriptor real, [CallerMemberName] string callerName = "");
/// <summary> /// Remove a particular user from all groups at a collection level /// </summary> /// <param name="tfiPCValidUsers">The identity of ProjectCollectionValidUsers group</param> /// <param name="userIdentity">The identity of the user to be removed</param> /// <returns>True, if successful</returns> private bool RemoveUserFromAllGroupsInCollection(TeamFoundationIdentity tfiPCValidUsers, IdentityDescriptor userIdentity) { foreach (IdentityDescriptor groupDesc in tfiPCValidUsers.Members) { if (idMgmtSvc.IsMember(groupDesc, userIdentity)) { try { idMgmtSvc.RemoveMemberFromApplicationGroup(groupDesc, userIdentity); } catch (Exception ex) { FileHelper.Log(ex.Message); FileHelper.Log(ex.StackTrace); } } } return(true); }