private static Microsoft.VisualStudio.Services.Licensing.License GetLicense() { Microsoft.VisualStudio.Services.Licensing.License license = AccountLicense.Stakeholder; string licenseType = ConfigurationManager.AppSettings.Get("License"); switch (licenseType) { case "Basic": license = AccountLicense.Express; break; case "Professional": license = AccountLicense.Professional; break; case "Advanced": license = AccountLicense.Advanced; break; case "Msdn": // When the user logs in, the system will determine the actual MSDN benefits for the user. license = MsdnLicense.Eligible; break; case "Stakeholder": license = AccountLicense.Stakeholder; break; } return(license); }
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); } }