17 KiB
SaaS-Change-UPN-Script-Runbook_686074283
Introduction
There are many scenarios where customers may need to update UPNs, such as domain migrations or company mergers. This runbook will guide the Operations team to migrate customers' UPNs using a defined mapping table.
Preparation
- Tenant admin should not be included
- User migration mapping file (CSV), including old UPN, old Email, new UPN, below is the template:
- Sample CSV format:
oldUpn newUpn oldEmail newEmail xiao1 xiao1_New xiao1_New@microfocus.com xiao1_New@opentext.com xiao2 xiao2_New xiao2_New@ microfocus.com xiao2_New@opentext.com userTKit05 userTKit055 userTKit055@ microfocus.com userTKit055@opentext.com
- Sample CSV format:
- Make sure no duplicate users in mapping file
- Make sure the migrated users should not exist in SMAX
Check PAT accounts
Go into IdM's database.
- Get the uuid for target tenant.
select uuid,name from <idm_schema>.organizations where name =<tenant_id>
2. List PAT users by uuid
select au.name, au.organization, at2.uuid from <idm_schema>.api_token at2, <idm_schema>.abstract_user au where at2.user_id=au.uuid and au.organization=<uuid>;
3.Inform the above users that they need to use a new UPN to obtain token after migrate if they use the UPN to get the PAT token before.
The admin user may use an api call(api/scim/organizations//users/<user_id>/access-tokens) to get other ordinary user's token. The <user_id> may be uuid or UPN, if it's UPN, it needs to be switched to a new one.
Find out the user set that user's OT UPN are already existed in SMAX
BO
Go to BO's DB
a. Create a temp mapping table
create table <bo_user_schema>.mf_ot_user_mapping
(
old_upn varchar(512) not null
constraint unique_old_upn
unique,
new_upn varchar(512) not null
constraint unique_new_upn
unique,
old_email varchar(512) not null,
new_email varchar(512) not null
);
b. Copy csv data
\copy <bo_user_schema>.mf_ot_user_mapping(old_upn,new_upn,old_email,new_email) FROM '<csv_path>' DELIMITER ',' CSV HEADER;
c. Find out users
select distinct des.* from <bo_user_schema>.user_entity nu inner join
(select mp.* from <bo_user_schema>.mf_ot_user_mapping mp inner join <bo_user_schema>.user_entity u on lower(mp.old_upn) = lower(u.name) and lower(mp.old_upn) !=lower(mp.new_upn) and u.is_deleted=false where u.idm_organization='<tenant_id>') des
on lower(nu.name)=lower(des.new_upn) and nu.is_deleted=false and nu.idm_organization='<tenant_id>';
Collect the results
d. drop the temp table
drop table <bo_user_schema>.mf_ot_user_mapping
IdM
Go to IdM's DB
a. Create a temp mapping table
create table <idm_schema>.mf_ot_user_mapping
(
old_upn varchar(512) not null
constraint unique_old_upn
unique,
new_upn varchar(512) not null
constraint unique_new_upn
unique,
old_email varchar(512) not null,
new_email varchar(512) not null
);
b. Copy csv data
\copy <idm_schema>.mf_ot_user_mapping(old_upn,new_upn,old_email,new_email) FROM '<csv_path>' DELIMITER ',' CSV HEADER;
c. Find out users
select distinct des.* from <idm_schema>.abstract_user nu inner join
(select mp.* from <idm_schema>.mf_ot_user_mapping mp inner join <idm_schema>.abstract_user u on lower(mp.old_upn)=lower(u.name) and lower(mp.old_upn) !=lower(mp.new_upn) where u.organization=(select uuid from <idm_schema>.organizations where name='<tenant_id>')) as des
on lower(nu.name)=lower(des.new_upn) and nu.organization=(select uuid from <idm_schema>.organizations where name='<tenant_id>');
Collect the resluts
d. drop the temp table
drop table <idm_schema>.mf_ot_user_mapping
EMS
Since we need to select Person's upn from entities_<tenant_id>, we need to get Tenant version from RMS's DB first.
Go to RMS's DB
- Get tenant version
select body -> 'tenant' ->> 'version' from <rms_schema>."TenantData_857561481" where body -> 'tenant' ->> 'tenantId' = '<tenant_id>';
Go to EMS's DB
a. Create a temp mapping table
create table <ems_schema>.mf_ot_user_mapping
(
old_upn varchar(512) not null
constraint unique_old_upn
unique,
new_upn varchar(512) not null
constraint unique_new_upn
unique,
old_email varchar(512) not null,
new_email varchar(512) not null
);
b. Copy csv data
\copy <ems_schema>.mf_ot_user_mapping(old_upn,new_upn,old_email,new_email) FROM '<csv_path>' DELIMITER ',' CSV HEADER;
c. Find out users for tenant
- Get physical_type_name(Replace <tenant_version> with the tenant version that get from RMS)
select physical_type_name from <ems_schema>.entityDescriptor_mapping where entity_type = 'Person' AND tenant_id = '<tenant_version>' AND logical_type_name = 'Upn';
- Get entity_type_id(Replace <tenant_version> with the tenant version that get from RMS)
select id from "entity_descriptor" where tenant_id = '<tenant_version>' and name = 'Person';
Find out users(Replace <physical_type_name>,<entity_type_id> with the physical_type_name, entity_type_id that get from above)
select distinct des.* from <ems_schema>.entities_<tenant_id> nu inner join
(select mp.* from <ems_schema>.mf_ot_user_mapping mp inner join <ems_schema>.entities_<tenant_id> u on lower(mp.old_upn) = lower(u.<physical_type_name>) and lower(mp.old_upn) !=lower(mp.new_upn) and u.is_deleted=false and u.entity_type_id=<entity_type_id> ) des
on lower(nu.<physical_type_name>)=lower(des.new_upn) and nu.is_deleted=false and nu.entity_type_id=<entity_type_id>;
Collect the results.
d. drop the temp table
drop table <ems_schema>.mf_ot_user_mapping
RMS
Go to RMS's DB
a. Create a temp mapping table
create table <rms_schema>.mf_ot_user_mapping
(
old_upn varchar(512) not null
constraint unique_old_upn
unique,
new_upn varchar(512) not null
constraint unique_new_upn
unique,
old_email varchar(512) not null,
new_email varchar(512) not null
);
b. Copy csv data
\copy <rms_schema>.mf_ot_user_mapping(old_upn,new_upn,old_email,new_email) FROM '<csv_path>' DELIMITER ',' CSV HEADER;
c. Find out users for tenant
select distinct des.* from <rms_schema>."AuthorizationPrincipalResourceJSON_<tenant_id>" nu inner join
(select mp.* from <rms_schema>.mf_ot_user_mapping mp inner join <rms_schema>."AuthorizationPrincipalResourceJSON_<tenant_id>" u on lower(mp.old_upn) = lower(u.body ->> 'UserId') and lower(mp.old_upn) !=lower(mp.new_upn)) des
on lower(nu.body ->> 'UserId')=lower(des.new_upn);
Collect the results.
d. drop the temp table
drop table <rms_schema>.mf_ot_user_mapping
In summary, we need to get the union of all the records from BO, IdM, EMS and RMS, Then cut this part of the data from the csv file.
1.Actions in Suite
- Disable User sync in the account
Login to Suite Administration:
ACCOUNTS>General>User auto-sync
- Change the tenant to Inactive
Login to Suite Administration:
TENANTS>General>Inactive
- Stop the external integration in the tenant
- Do NOT do any write action(Create/Update/Delete) on Users
- Delete the SAML authentication config in IdM
Login to Suite Administration:
TENANTS>IdM settings>Authentication
2.Backup Databases:
Ensure backups of the following databases are taken before initiating changes:
- Suite Administration service database:
bo_useruser_entity
create table <schema>.user_entity_v0 as select * from <schema>.user_entity;
- IDM service database:
idmabstract_user-abstract_user_metadata-abstract_user_profile
create table <schema>.abstract_user_v0 as select * from <schema>.abstract_user;
create table <schema>.abstract_user_metadata_v0 as select * from <schema>.abstract_user_metadata;
create table <schema>.abstract_user_profile_v0 as select * from <schema>.abstract_user_profile;
- XServices databases:
xservices_ems- entities_<Target_tenant_Id>
eg:entities_140038523
- entities_<Target_tenant_Id>
create table <schema>.entities_<tenant_id>_v0 as select * from <schema>.entities_<tenant_id>;
-
xservices_rms- AuthorizationPrincipalResourceJSON_<Target_tenant_Id>eg:AuthorizationPrincipalResourceJSON_140038523
create table <schema>."AuthorizationPrincipalResourceJSON_<tenant_id>_v0" as select * FROM <schema>."AuthorizationPrincipalResourceJSON_<tenant_id>";
Please note the single and double quotes
Note: Please replace the value in <> according to the actual environment
3.Prepare user Data
Provide a CSV file containing the new UPNs and corresponding old UPNs and new Emails.
Sample CSV format:
| oldUpn | newUpn | oldEmail | newEmail |
|---|---|---|---|
| xiao1 | xiao1_New | xiao1_New@microfocus.com | xiao1_New@opentext.com |
| xiao2 | xiao2_New | xiao2_New@ microfocus.com | xiao2_New@opentext.com |
| userTKit05 | userTKit055 | userTKit055@ microfocus.com | userTKit055@opentext.com |
We can choose a small data set to test firstly, validate these users. If everything goes fine, we can do with the rest files.
Run Script
Notes:
- This script needs to provide the old and new upn, as well as the email, the file format should be.csv.
- In addition, you need to specify the column number of the column corresponding to the new/old UPN and old/new Email of the corresponding file and the row number starting from the line.
- You must have the "root" privilege to execute the script.
- Script package should include two files: changeUserUpn.sh and change, and put these two files in the same level directory.
- The account for updating UPN should be of 3in1 type, which means that the account id and tenant id should be the same.
- In IdM, this script is only update for SAML users, which means that if you are using non-SAML integrated authentication, this script is not suitable
- Before the script runs, you need to back up the database
- Before the script runs, you need to turn off the user sync of the account, and you need to set the tenant to " Inactive ", and stop the external integration on the tenant
Follow these steps:
- Upload the scripts file and User data csv file to the bastion/master node of the suite
- Log in to the bastion/master node as a root user, copy the scripts and data file to the toolkit pod, grant executable permissions to scripts and file.
- Go into the toolkit pod and run the following command in the directory where the script is located:
sh changeUserUpn.sh -a <account_id>Where <account_id> is the ID of the account which you want to change these users under the account. For example,sh changeUserUpn.sh -a 123456789 - Follow the prompts step by step to continue executing the script
**The script will be executed after you put the correct line number in mapping file.**And you can see following messages after the script is successful executed:
Validation
Firstly, You can check whether the user's upn and email are updated correctly in IdM/BO and SAW. If it's OK, you need to
- configure OT's SAML in IdM
- Active Tenant and turn on User auto-sync in BO.
Then you can do some regular validation such as:
- The user account's UPN doesn't change before/after migration To verify after SAML login the user can match to the original user account and role/permission settings aren’t changed
- The user account's UPN has been changed after migration To verify after SAML login the user can match to the original user account and role/permission settings aren’t changed To verify after SAML login the user information can be updated to new IDP information, such as email can be updated to OT email
- The user account never login SMAX tenant To verify the new SAML user account can be created properly with new UPN in both BO and Tenant
Rollback
If you need to rollback, just rollback the database that has been backed up.
Primary rollback:
You can re-run the change UPN script and specify the old UPN and new UPN with reversed column numbers.
Secondary rollback:
- Suite Administration service database:
bo_user
create table <schema>.user_entity_v1 as select * from <schema>.user_entity;
update <schema>.user_entity as S set name = B.name, email = B.email
from <schema>.user_entity_v0 as B
where S.id = B.id
and S.account_id = '<tenant_id>';
IDM:
- IDM service database:
idm
create table <schema>.abstract_user_v1 as select * from <schema>.abstract_user;
create table <schema>.abstract_user_metadata_v1 as select * from <schema>.abstract_user_metadata;
create table <schema>.abstract_user_profile_v1 as select * from <schema>.abstract_user_profile;
update <schema>.abstract_user as au set name=bak.name, display_name=bak.display_name, name_lower=bak.name_lower from <schema>.abstract_user_v0 bak where au.uuid=bak.uuid and au.organization='<tenant_uuid>';
update <schema>.abstract_user_metadata as am set field_value=bak.field_value, field_value_lower=bak.field_value_lower from <schema>.abstract_user au, abstract_user_metadata_v0 bak where am.field_key='username' and am.uuid=bak.uuid and bak.uuid=au.uuid and au.organization='<tenant_uuid>';
update <schema>.abstract_user_metadata as am set field_value=bak.field_value, field_value_lower=bak.field_value_lower from <schema>.abstract_user au, abstract_user_metadata_v0 bak where am.field_key='email' and am.uuid=bak.uuid and bak.uuid=au.uuid and au.organization='<tenant_uuid>';
update <schema>.abstract_user_profile as ap set user_name=bak.user_name, email=bak.email from <schema>.abstract_user au, abstract_user_profile_v0 bak where ap.uuid=bak.uuid and ap.user_id=au.uuid and au.organization='<tenant_uuid>';
- XServices databases:
xservices_ems
create table <schema>.entities_<tenant_id>_v1 as select * from <schema>.entities_<tenant_id>;
-- get entity type id:
SELECT DISTINCT id, name FROM <schema>.entity_descriptor WHERE name in ('Person');
-- get tenant_version such as v27.
-- get UPN field name: (such as schar1)
select physical_type_name from <schema>.entityDescriptor_mapping where entity_type = 'Person' AND tenant_id = '<tenant_version>' AND logical_type_name = 'Upn';
-- get email field name: (such as schar2)
select physical_type_name from <schema>.entityDescriptor_mapping where entity_type = 'Person' AND tenant_id = '<tenant_version>' AND logical_type_name = 'Email';
update <schema>.entities_<tenant_id> as S set <UPN_field_name> = B.<UPN_field_name>, <email_field_name> = B.<email_field_name>
from <schema>.entities_<tenant_id>_v0 as B
where S.entity_id = B.entity_id
and S.entity_type_id = '<entity_type_id>';
-
xservices_rms
alter table <schema>."AuthorizationPrincipalResourceJSON_<tenant_id>" rename to "AuthorizationPrincipalResourceJSON_<tenant_id>_v1";
create table <schema>."AuthorizationPrincipalResourceJSON_<tenant_id>" as select * FROM <schema>."AuthorizationPrincipalResourceJSON_<tenant_id>_v0";
Troubleshooting
Empty mapping file
If you see this msg that means the.csv file is empty.
Try to read the file that mappings of user UPN and Email.
time="2024-03-11 16:21:54" level=error msg="The user mappings file is empty."
The user mappings file is empty.
Empty parameter
time="2024-03-11 17:50:02" level=error msg="Required param is EMPTY,OriginName:test1,NewName:,OriginEmail:test1,NewEmail:test1"
Required param is EMPTY,OriginName:test1,NewName:,OriginEmail:test1,NewEmail:test1
If you see this msg that means the NewName is empty.
Duplicated user
If you get this error, go to the Preparation and follow actions to find out the duplicated users.
More information will be added during next testing.
Script Files
change
changeUserUpn.sh




