/// <summary> /// Remove an existing user /// </summary> /// <param name="userEmail"></param> /// <returns></returns> public bool RemoveUser(string userEmail) { string cannonicalKey = CannonicalKey(userEmail); //See if the user is already in our list ProvisioningUser existingUser = null; if (!_allUsersSet.TryGetValue(cannonicalKey, out existingUser)) { return(false); } //======================================================================= //We need to remove the old user //======================================================================= bool wasRemoved; //Remove wasRemoved = _allUsersSet.Remove(cannonicalKey); IwsDiagnostics.Assert(wasRemoved, "814-200: Internal error, item not found"); //Remove wasRemoved = GetManagerForRole(existingUser.UserRole).RemoveUser(cannonicalKey); IwsDiagnostics.Assert(wasRemoved, "814-200: Internal error, item not found"); return(wasRemoved); }
/// <summary> /// Parse all the users from the xml document /// </summary> /// <param name="xDoc"></param> /// <returns></returns> public static List <ProvisioningUser> ParseUsers(XmlDocument xDoc, string xPath, string overrideSourceGroup = null) { var xmlUsersToProvision = xDoc.SelectNodes(xPath); var listOut = new List <ProvisioningUser>(); foreach (XmlNode xNode in xmlUsersToProvision) { var thisUser = new ProvisioningUser(xNode, overrideSourceGroup); listOut.Add(thisUser); } return(listOut); }
/// <summary> /// Add a user to the set /// </summary> /// <param name="user"></param> internal void AddUser(ProvisioningUser user) { string cannonicalKey = CannonicalKey(user.UserName); if (_usersSet.ContainsKey(cannonicalKey)) { //User is already there. Don't need to do anything } else { _usersSet.Add(cannonicalKey, user); } }
/// <summary> /// Handle the provisioning for a single user /// </summary> /// <param name="userToProvision"></param> /// <param name="siteSignIn"></param> /// <param name="workingListUnexaminedUsers"></param> private void Execute_ProvisionUsers_SingleUser( ProvisioningUser userToProvision, TableauServerSignIn siteSignIn, WorkingListSiteUsers workingListUnexaminedUsers) { //See if a user with this name already exists var foundExistingUser = workingListUnexaminedUsers.FindUser(userToProvision.UserName); ProvisionUserInstructions.MissingUserAction missingUserAction; ProvisionUserInstructions.UnexpectedUserAction unexpectedUserAction; //Get the instructions based on the desired Auth model for the user we are provisioning switch (userToProvision.UserAuthenticationParsed) { case SiteUserAuth.Default: missingUserAction = _provisionInstructions.ActionForMissingDefaultAuthUsers; unexpectedUserAction = _provisionInstructions.ActionForUnexpectedDefaultAuthUsers; break; case SiteUserAuth.SAML: missingUserAction = _provisionInstructions.ActionForMissingSamlUsers; unexpectedUserAction = _provisionInstructions.ActionForUnexpectedSamlUsers; break; default: IwsDiagnostics.Assert(false, "814-1204: Unknown auth type"); throw new Exception("814-1204: Unknown auth type"); } //CASE 1: The user does NOT exist. So add them if (foundExistingUser == null) { Execute_ProvisionUsers_SingleUser_AddUser(siteSignIn, userToProvision, missingUserAction); return; } //CASE 2: The user EXISTS but is not the right role or auth; update them if ( (string.Compare(foundExistingUser.SiteRole, userToProvision.UserRole, true) != 0) || (string.Compare(foundExistingUser.SiteAuthentication, userToProvision.UserAuthentication, true) != 0) ) { Execute_ProvisionUsers_SingleUser_ModifyUser(siteSignIn, userToProvision, foundExistingUser); return; } //CASE 3: The user exists and does NOT need to be modified _statusLogs.AddStatus("No action: User exists and has expected role and authentication. User: " + userToProvision.UserName); }
/// <summary> /// The ADD-User path for provisioning a user /// </summary> /// <param name="siteSignIn"></param> /// <param name="userToProvision"></param> /// <param name="missingUserAction"></param> private SiteUser Execute_ProvisionUsers_SingleUser_AddUser( TableauServerSignIn siteSignIn, ProvisioningUser userToProvision, ProvisionUserInstructions.MissingUserAction missingUserAction, WorkingListSiteUsers workingList_allKnownUsers) { switch (missingUserAction) { //Add the user case ProvisionUserInstructions.MissingUserAction.Add: //Setup to create a new user var createUser = new SendCreateUser( siteSignIn.ServerUrls, siteSignIn, userToProvision.UserName, userToProvision.UserRole, userToProvision.UserAuthenticationParsed); var userCreated = createUser.ExecuteRequest(); //------------------------------------------------------------------------------- //Record the action in an output file //------------------------------------------------------------------------------- CSVRecord_UserModified(userToProvision.UserName, userToProvision.UserRole, userToProvision.UserAuthentication, "added", ""); workingList_allKnownUsers.AddUser(userCreated); return(userCreated); //Don't add the user, just record the finding case ProvisionUserInstructions.MissingUserAction.Report: CSVRecord_UserModified(userToProvision.UserName, userToProvision.UserRole, userToProvision.UserAuthentication, "SIMULATED added", ""); return(null); default: IwsDiagnostics.Assert(false, "814-1210: Unknown missing user provisioning action"); throw new Exception("814-1210: Unknown missing user provisioning action"); } }
/// <summary> /// Download the ist of users/roles /// </summary> /// <param name="siteSignIn"></param> private void GenerateUsersRolesList_FromTableauSite(TableauServerSignIn siteSignIn) { var downloadUsers = new DownloadUsersList(siteSignIn); bool downloadSuccess = downloadUsers.ExecuteRequest(); if (!downloadSuccess) { throw new Exception("1012-358: Fatal error attempting to download users"); } var userRolesManager = this.SetManagerForRoles; foreach (var thisUser in downloadUsers.Users) { var thisProvisioningUser = new ProvisioningUser( thisUser.Name, thisUser.SiteRole, thisUser.SiteAuthentication, "Tableau Online site list", false); userRolesManager.AddUser(thisProvisioningUser); } }
/// <summary> /// Called if a Group comes up more than once in provisioning (e.g. multiple wildcard matches) /// If so, then we consider promoting the group to the higer of the two roles /// </summary> /// <param name="suggestedMode"></param> /// <param name="suggestedSiteRole"></param> public bool ConsiderGrantLicenseRoleUpgrade(ProvisioningGroup.GrantLicenseMode suggestedMode, string suggestedSiteRole) { string currentRole = _grantLicenseRole; var currentMode = _grantLicenseInstructions; //------------------------------------------------------------------------- //See if the suggested state is once that we need to act on. //------------------------------------------------------------------------- switch (suggestedMode) { case ProvisioningGroup.GrantLicenseMode.Ignore: return(false); //Do nothing case ProvisioningGroup.GrantLicenseMode.None: return(false); //Do nothing case ProvisioningGroup.GrantLicenseMode.OnLogin: break; //Advance onward.... default: //Degenerate case IwsDiagnostics.Assert(false, "1021-106: Unknown grant license mode, " + suggestedMode.ToString()); throw new Exception("1021-106: Unknown grant license mode, " + suggestedMode.ToString()); } //------------------------------------------------------------------------- //Based on the current state, take the approprate action //------------------------------------------------------------------------- switch (currentMode) { case ProvisioningGroup.GrantLicenseMode.Ignore: //Apply the new mode _grantLicenseInstructions = suggestedMode; _grantLicenseRole = suggestedSiteRole; return(true); case ProvisioningGroup.GrantLicenseMode.None: //Apply the new mode _grantLicenseInstructions = suggestedMode; _grantLicenseRole = suggestedSiteRole; return(true); case ProvisioningGroup.GrantLicenseMode.OnLogin: //Apply the new mode if it ranks higher if (ProvisioningUser.CalculateRoleRank(currentRole) >= ProvisioningUser.CalculateRoleRank(suggestedSiteRole)) { //The current role ranks above/same as the suggested role. Do nothing return(false); } else { //Apply the new mode _grantLicenseInstructions = suggestedMode; _grantLicenseRole = suggestedSiteRole; return(true); } default: //Degenerate case IwsDiagnostics.Assert(false, "1021-113: Unknown grant license mode, " + currentMode.ToString()); throw new Exception("1021-113: Unknown grant license mode, " + currentMode.ToString()); } }
/// <summary> /// Constructor /// </summary> /// <param name="userToAdd"></param> public void AddUser(ProvisioningUser userToAdd) { string cannonicalKey = CannonicalKey(userToAdd.UserName); //==================================================================================== //See if the user is already in our list //==================================================================================== ProvisioningUser existingUser = null; if (!_allUsersSet.TryGetValue(cannonicalKey, out existingUser)) { //The user is new to us, add them. GetManagerForRole(userToAdd.UserRole).AddUser(userToAdd); _allUsersSet.Add(cannonicalKey, userToAdd); return; } //======================================================================================== //If the user has the same rank as the existing user, there is nothing we need to do //======================================================================================== if (userToAdd.RoleRank == existingUser.RoleRank) { return; } //======================================================================================== //If the user being added is a Administrator + Creator, the it outranks other roles //======================================================================================== if (userToAdd.RoleRank == ProvisioningUser.RoleRank_SiteAdministratorCreator) { //The user being added is a Creator + Administrator. This trumps other role. goto replace_existing_user; } //======================================================================================== //Two special cases: // 1.The user was previously added as a CREATOR, and is being added as an EXPLORER-ADMIN // 2. The user was previously added as an EXPLORER-ADMIN, and is being added as a CREATOR // //In both of these cases, we want to combine the "CREATOR" and "ADMIN" roles, so that the user does not get a diminished rol //======================================================================================== if (ProvisioningUser.IsCombinedUserRoleCreatorAdministrator(existingUser.RoleRank, userToAdd.RoleRank)) { userToAdd = new ProvisioningUser( userToAdd.UserName, //Keep the name ProvisioningUser.RoleText_SiteAdministratorCreator, //Upgrade the role to Creator + Administrator userToAdd.UserAuthentication, "*multiple groups (" + existingUser.SourceGroup + "+" + userToAdd.SourceGroup + ")*"); //Note that this is because of multiple groups goto replace_existing_user; } //If the existing user has a role rank equal or greater than the new entry, there is nothing we need to do if (existingUser.RoleRank >= userToAdd.RoleRank) { return; } replace_existing_user: //======================================================================= //The new instance of this user has a higher rank than the old instance. //We need to remove the old user, and add the new user //======================================================================= bool wasRemoved; //Remove wasRemoved = _allUsersSet.Remove(cannonicalKey); IwsDiagnostics.Assert(wasRemoved, "813-641: Internal error, item not found"); //Remove wasRemoved = GetManagerForRole(existingUser.UserRole).RemoveUser(cannonicalKey); IwsDiagnostics.Assert(wasRemoved, "813-642: Internal error, item not found"); //Add _allUsersSet.Add(cannonicalKey, userToAdd); GetManagerForRole(userToAdd.UserRole).AddUser(userToAdd); }
/// <summary> /// Adds a user, and replaces any matching existing user /// </summary> /// <param name="user"></param> /// <returns></returns> public void AddAndForceReplaceUser(ProvisioningUser user) { RemoveUser(user.UserName); AddUser(user); }
/// <summary> /// The MODIDFY-Existing user path for user provisioning /// </summary> /// <param name="siteSignIn"></param> /// <param name="userToProvision"></param> /// <param name="missingUserAction"></param> private void Execute_ProvisionUsers_SingleUser_ModifyUser(TableauServerSignIn siteSignIn, ProvisioningUser userToProvision, SiteUser existingUser) { ProvisionUserInstructions.ExistingUserAction existingUserAction; switch (existingUser.SiteAuthenticationParsed) { case SiteUserAuth.Default: existingUserAction = _provisionInstructions.ActionForExistingDefaultAuthUsers; break; case SiteUserAuth.SAML: existingUserAction = _provisionInstructions.ActionForExistingSamlUsers; break; case SiteUserAuth.OpenID: existingUserAction = _provisionInstructions.ActionForExistingOpenIdUsers; break; default: IwsDiagnostics.Assert(false, "814-1234: Unknown user auth type"); throw new Exception("814-1234: Unknown user auth type"); } switch (existingUserAction) { //Modify the existing user case ProvisionUserInstructions.ExistingUserAction.Modify: _statusLogs.AddStatus("Update user: User exists but role or auth differs. Update: " + userToProvision.UserName); var updateUser = new SendUpdateUser( siteSignIn, existingUser.Id, userToProvision.UserRole, userToProvision.UserAuthenticationParsed != existingUser.SiteAuthenticationParsed, //We only want to update the user role if it is NOT what we expect it to be userToProvision.UserAuthenticationParsed); var userUpdated = updateUser.ExecuteRequest(); if (userUpdated != null) { //------------------------------------------------------------------------------- //Record the action in an output file //------------------------------------------------------------------------------- CSVRecord_UserModified( userToProvision.UserName, userToProvision.UserRole, userToProvision.UserAuthentication, "existing/modified", existingUser.SiteRole + "->" + userUpdated.SiteRole + ", " + existingUser.SiteAuthentication + "->" + userUpdated.SiteAuthentication); return; } else { //Error case, the user was not updated CSVRecord_ErrorUpdatingUser(userToProvision.UserName, userToProvision.UserRole, userToProvision.UserAuthentication, "Error updating user (913-212)"); return; } //Don't modify, but report case ProvisionUserInstructions.ExistingUserAction.Report: CSVRecord_UserModified( userToProvision.UserName, userToProvision.UserRole, userToProvision.UserAuthentication, "SIMULATED existing/modified", existingUser.SiteRole + "->" + userToProvision.UserRole + ", " + existingUser.SiteAuthentication + "->" + userToProvision.UserAuthentication); return; default: IwsDiagnostics.Assert(false, "814-1237: Internal error. Unknown modify user action"); throw new Exception("814-1237: Internal error. Unknown modify user action"); } }
/// <summary> /// Handle the provisioning for a single user /// </summary> /// <param name="userToProvision"></param> /// <param name="siteSignIn"></param> /// <param name="workingListUnexaminedUsers"></param> private void Execute_ProvisionUsers_SingleUser( ProvisioningUser userToProvision, TableauServerSignIn siteSignIn, WorkingListSiteUsers workingListUnexaminedUsers, WorkingListSiteUsers workingList_allKnownUsers) { //See if a user with this name already exists var foundExistingUser = workingListUnexaminedUsers.FindUserByName(userToProvision.UserName); ProvisionUserInstructions.MissingUserAction missingUserAction; ProvisionUserInstructions.UnexpectedUserAction unexpectedUserAction; //Get the instructions based on the desired Auth model for the user we are provisioning switch (userToProvision.UserAuthenticationParsed) { case SiteUserAuth.Default: missingUserAction = _provisionInstructions.ActionForMissingDefaultAuthUsers; unexpectedUserAction = _provisionInstructions.ActionForUnexpectedDefaultAuthUsers; break; case SiteUserAuth.SAML: missingUserAction = _provisionInstructions.ActionForMissingSamlUsers; unexpectedUserAction = _provisionInstructions.ActionForUnexpectedSamlUsers; break; case SiteUserAuth.OpenID: missingUserAction = _provisionInstructions.ActionForMissingOpenIdUsers; unexpectedUserAction = _provisionInstructions.ActionForUnexpectedOpenIdUsers; break; default: var unknownAuthType = userToProvision.UserAuthentication; if (unknownAuthType == null) { unknownAuthType = ""; } IwsDiagnostics.Assert(false, "814-1204: Unknown auth type, " + unknownAuthType); throw new Exception("814-1204: Unknown auth type, " + unknownAuthType); } //=============================================================================================== //CASE 1: The user does NOT exist. So add them //=============================================================================================== if (foundExistingUser == null) { Execute_ProvisionUsers_SingleUser_AddUser(siteSignIn, userToProvision, missingUserAction, workingList_allKnownUsers); return; } //=============================================================================================== //CASE 2a: The user EXISTS but is not the right AUTH; update them //=============================================================================================== if (string.Compare(foundExistingUser.SiteAuthentication, userToProvision.UserAuthentication, true) != 0) { //Update the user Execute_ProvisionUsers_SingleUser_ModifyUser(siteSignIn, userToProvision, foundExistingUser); return; } //=============================================================================================== //CASE 2b: The user EXISTS but is not the right ROLE; update them //=============================================================================================== else if (string.Compare(foundExistingUser.SiteRole, userToProvision.UserRole, true) != 0) { //================================================================================================================================================================== //CASE 2b: Special case (to support Grant License on Sign In: If the user provisioning insturctions ALLOW //NOTE: If the authentication schemes do not match, then move foward with modifying the user -- this is a more fundamental change, and we should honor it explicitly //================================================================================================================================================================== if (userToProvision.AllowPromotedRole) { var existingUserRoleRank = ProvisioningUser.CalculateRoleRank(foundExistingUser.SiteRole); if (existingUserRoleRank > userToProvision.RoleRank) { _statusLogs.AddStatus("No action: Provisioning rule for this user allow keeping existing higher ranked role. User: "******", " + foundExistingUser.SiteRole); return; } } //CASE 2c: Update the user because the provisioning Role differs from the existing user's Role Execute_ProvisionUsers_SingleUser_ModifyUser(siteSignIn, userToProvision, foundExistingUser); return; } //=============================================================================================== //CASE 3: The user exists and does NOT need to be modified //=============================================================================================== _statusLogs.AddStatus("No action: User exists and has expected role and authentication. User: " + userToProvision.UserName); }
/// <summary> /// The MODIDFY-Existing user path for user provisioning /// </summary> /// <param name="siteSignIn"></param> /// <param name="userToProvision"></param> /// <param name="missingUserAction"></param> private void Execute_ProvisionUsers_SingleUser_ModifyUser(TableauServerSignIn siteSignIn, ProvisioningUser userToProvision, SiteUser existingUser) { ProvisionUserInstructions.ExistingUserAction existingUserAction; switch (existingUser.SiteAuthenticationParsed) { case SiteUserAuth.Default: existingUserAction = _provisionInstructions.ActionForExistingDefaultAuthUsers; break; case SiteUserAuth.SAML: existingUserAction = _provisionInstructions.ActionForExistingSamlUsers; break; default: IwsDiagnostics.Assert(false, "814-1234: Unknown user auth type"); throw new Exception("814-1234: Unknown user auth type"); } switch (existingUserAction) { //Modify the existing user case ProvisionUserInstructions.ExistingUserAction.Modify: _statusLogs.AddStatus("Update user: User exists but role or auth differs. Update: " + userToProvision.UserName); var updateUser = new SendUpdateUser( siteSignIn.ServerUrls, siteSignIn, existingUser.Id, userToProvision.UserRole, userToProvision.UserAuthenticationParsed); var userUpdated = updateUser.ExecuteRequest(); //------------------------------------------------------------------------------- //Record the action in an output file //------------------------------------------------------------------------------- CSVRecord_UserModified( userToProvision.UserName, userToProvision.UserRole, userToProvision.UserAuthentication, "existing/modified", existingUser.SiteRole + "->" + userUpdated.SiteRole + ", " + existingUser.SiteAuthentication + "->" + userUpdated.SiteAuthentication); return; //Don't modify, but report case ProvisionUserInstructions.ExistingUserAction.Report: //------------------------------------------------------------------------------- //Record the action in an output file //------------------------------------------------------------------------------- /* CSVRecord_Warning( * userToProvision.UserName, * userToProvision.UserRole, * userToProvision.UserAuthentication, * "Modify user: Per provisioning instructions, existing user left unaltered. " + existingUser.SiteRole + "->" + userToProvision.UserRole + ", " + existingUser.SiteAuthentication + "->" + userToProvision.UserAuthentication); */ CSVRecord_UserModified( userToProvision.UserName, userToProvision.UserRole, userToProvision.UserAuthentication, "SIMULATED existing/modified", existingUser.SiteRole + "->" + userToProvision.UserRole + ", " + existingUser.SiteAuthentication + "->" + userToProvision.UserAuthentication); return; default: IwsDiagnostics.Assert(false, "814-1237: Internal error. Unknown modify user action"); throw new Exception("814-1237: Internal error. Unknown modify user action"); } }