User permissions migration allows migrating all existing user-permission relations from mod-permissions
for users with authentication information in Keycloak.
Info |
---|
This migration is idempotent and can be repeated multiple times providing the same results |
...
Expand |
---|
|
Code Block |
---|
@startuml
!theme mono
!pragma useVerticalIf on
skinparam conditionStyle inside
skinparam defaultTextAlignment center
skinparam defaultFontSize 12
<style>
activityDiagram {
activity {
MaximumWidth 600
backgroundColor #f0f0f0
LineColor DimGrey
}
diamond {
HorizontalAlignment center
}
group {
LineColor LightGrey
FontSize 10
}
}
</style>
start
group PermissionMigrationService.migratePermissions {
:log that migration started;<<task>>
group UserPermissionsLoader.loadUserPermissions {
:load all users from Keycloak
//users loaded in batches, size is controlled by configuration properties//;<<task>>
:extract user ids from loaded keycloak users and store it as ""userIds""
//Folio user id is stored as ""user_id"" attribute in KeycloakUser entity//;<<input>>
:create an empty list with user permissions
as ""List<UserPermission> userPermissionsData"";
while (""userIds"" has next element) is (yes)
:get next user id from ""users"";
:load user permissions from ""mod-permissions"" by ""userId"" as ""userPermissions""
//""/users/{userId}/permissions"" endpoint is used//;<<input>>
:extract permission names from ""userPermissions"" as ""permissionNames"";<<task>>
if (""permissionNames"" is empty) then (yes)
:log that user has no permissions;<<output>>
else (no)
:remove duplicates from ""permissionNames"" and store it as ""uniquePermissionNames"";<<task>>
:sort alphabetically ""uniquePermissionNames"" as ""sortedUniquePermissionNames"";<<task>>
:concatenate ""sortedUniquePermissionNames"" using delimiter ""'|'"" as ""concatenatedPermissionString"";<<task>>
:generate ""roleName"" as sha1 hash from ""concatenatedPermissionString"";<<task>>
:create ""userPermissionsValue"" from ""userId"", ""roleName"", ""uniquePermissionNames"";<<task>>
:add ""userPermissionsValue"" to ""userPermissionsData"" list;<<output>>
end if
end while (no)
:return ""userPermissionsData"";<<output>>
}
group MigrationRoleCreator.createRoles {
:extract unique role names from ""userPermissionsData"" as ""uniqueRoleNames"";<<input>>
:create roles using ""RoleService"" batch API as ""createdRoles"";<<task>>
if (""createdRoles"" size is equal to ""uniqueRoleNames"" size) then (yes)
:return ""createdRoles"";<<output>>
else (no)
:retrieve roles by ""uniqueRoleNames""
from ""RoleService"" as ""foundRoles"";<<output>>
:return ""foundRoles"" as ""createdRoles"";<<output>>
end if
}
group validateAndGetUserPermissionsWithRoles {
:group ""createdRoles"" by ""roleName"" as ""createdRolesByName"";<<task>>
:for each value in ""userPermissionsData"" retrieve role object by ""roleName"" from ""createdRolesByName"";<<task>>
if (all roles are not found by all ""roleNames"") then (yes)
:thrown MigrationException;<<output>>
end
else (no)
:return updated ""userPermissionsData"";<<output>>
end if
}
group MigrationRoleCreator.assignUsers {
:group users by ""roleName""
as map where key = role identifier and value is a collection of user ids
//""userId"" and generated ""roleName"" are extracted from ""userPermissionsData"";
:create a user-role relation for each ""Pair(userId, roleId)"" in ""UserRoleService"";
if (errors occurred during user-role relation assignment) then (yes)
:thrown MigrationException;<<output>>
end
else (no)
:log the number of created user-role relations;<<output>>
end if
}
group RolePermissionAssignor.assignPermissions {
:define a set with visited role identifiers as ""visitedRoleIds"";<<task>>
while (""userPermissionsData"" has next value) is (yes)
:get next ""userPermissions"" from ""userPermissionsData"";<<input>>
:get role id as ""roleId"" from ""userPermissions"";<<input>>
if (""visitedRoleIds"" contains ""roleId"") then (no)
:get list of permission names as ""permissions"" from ""userPermissions"";<<input>>
:find capabilities as ""foundCapabilities"" by ""permissions"" using ""CapabilityService"";<<task>>
:extract ""capabilityPermissionNames"" from ""foundCapabilities"";<<task>>
:define ""notFoundPermissions"" as difference between ""permissions"" and ""capabilityPermissionNames"";<<input>>
if (""foundCapabilities"" collection is not empty) then (yes)
:assign ""foundCapabilities"" to a role with ""roleId"";<<task>>
end if
:find capability sets as ""foundCapabilitySets"" by ""permissions"" using ""CapabilitySetService"";<<task>>
:extract ""capabilitySetPermissionNames"" from ""foundCapabilitySets"";<<task>>
:define ""notFoundPermissionsInSets"" as difference between ""notFoundPermissions"" and ""capabilitySetPermissionNames"";<<input>>
if (""foundCapabilitySets"" collection is not empty) then (yes)
:assign ""foundCapabilitySets"" to a role with ""roleId"";<<task>>
end if
:log assigned permissions for role with ""roleId"";<<output>>
if (""notFoundPermissionsInSets"" collection is not empty) then (yes)
:[warn] log ""notFoundPermissionsInSets"" were not assigned for role with ""roleId"";<<output>>
end if
else (yes)
end if
end while
}
:log that migration finished;<<task>>
}
end
@enduml |
|