Ticket T604600
Visible to All Users

Questions on migrating to the PermissionPolicyXXX classes from SecuritySystemXXX ones

created 7 years ago

[DevExpress Support Team: CLONED FROM T418166: How to upgrade an existing project to the Allow/Deny permission policy (migrate to PermissionPolicyUser and PermissionPolicyRole)]
Here is my scenario:
Other than some SQL contained in RDL (SSRS) reports I do not have any direct references to SecuritySystemUser, so that's not a big deal to take care of.

I have a custom class (User) derived from SecuritySystemUser

I do not wish to change Oid to string values on any references or associations to User so seems the CodeProject solution mostly deals with this.

Questions:

  1. How do I handle in a single pass changing my User class to be derived from PermissionPolicyUser wihtout requiring a 2nd build version to be deployed after conversion?

  2. What are other considerations of having a custom User class and trying to migrate in ModuleUpdater?

  3. I would also like to copy the password, so it does look like part of the CodeProject example would be of benefit for copying just the user objects, especially since I want to preserve the existing Oid values for user objects (not necessarily for roles/permissions) as there are many objects that reference this.

Making some progress.  I was able to get User and SystemSecurityUser to convert to PermissionPolicyUser and handle all the references…

However, when it gets to the CopyUser loop, no objects are returned in ObjectSpace.GetObjects<SecuritySystemUser>() even though there is still data there.  I don't get any errors and looking at SQL profiler, nothing is hitting the database.

C#
// UpdateDatabaseBeforeUpdateSchema public override void UpdateDatabaseBeforeUpdateSchema() { base.UpdateDatabaseBeforeUpdateSchema(); if (CurrentDBVersion < new Version("1.0.6450.23803") && CurrentDBVersion > new Version("0.0.0.0")) { ExecuteNonQueryCommand("ALTER TABLE AuditDataItemPersistent ALTER COLUMN OldValue Nvarchar(MAX)", true); ExecuteNonQueryCommand("ALTER TABLE AuditDataItemPersistent ALTER COLUMN NewValue Nvarchar(MAX)", true); } if (CurrentDBVersion < new Version("1.0.6612.31390") && CurrentDBVersion > new Version("0.0.0.0")) { // drop constraint so new PermissionPolicyUser table can be created ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[User] DROP CONSTRAINT [FK_User_Oid]", false); // SELECT * INTO temp_User FROM [User] ExecuteNonQueryCommand(@"SELECT * INTO temp_User FROM [User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[Class] NOCHECK CONSTRAINT [FK_Class_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[Client] NOCHECK CONSTRAINT [FK_Client_Staff]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[ClientCase] NOCHECK CONSTRAINT [FK_ClientCase_Counselor]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[ClientViewAudit] NOCHECK CONSTRAINT [FK_ClientViewAudit_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[FollowUp] NOCHECK CONSTRAINT [FK_FollowUp_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[FollowUp] NOCHECK CONSTRAINT [FK_FollowUp_CompletedBy]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[LoginAudit] NOCHECK CONSTRAINT [FK_LoginAudit_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[UsersXLocations] NOCHECK CONSTRAINT [FK_UsersXLocations_Users]", false); // DELETE from [User] ExecuteNonQueryCommand(@"DELETE FROM [User]", false); } }
C#
public override void UpdateDatabaseAfterUpdateSchema() { base.UpdateDatabaseAfterUpdateSchema(); if (CurrentDBVersion < new Version("1.0.6612.31390") && CurrentDBVersion > new Version("0.0.0.0")) { // convert SecuritySystem to PermissionPolicy ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[User] NOCHECK CONSTRAINT [FK_User_Oid]", false); ExecuteNonQueryCommand(@"INSERT INTO PermissionPolicyUser (Oid, UserName, StoredPassword, ChangePasswordOnFirstLogon, IsActive, ObjectType, OptimisticLockField) SELECT Oid, UserName, StoredPassword, ChangePasswordOnFirstLogon, IsActive, ObjectType, OptimisticLockField FROM SecuritySystemUser", false); ExecuteNonQueryCommand(@"INSERT INTO [User] SELECT * from temp_User", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[User] CHECK CONSTRAINT [FK_User_Oid]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[Class] CHECK CONSTRAINT [FK_Class_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[Client] CHECK CONSTRAINT [FK_Client_Staff]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[ClientCase] CHECK CONSTRAINT [FK_ClientCase_Counselor]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[ClientViewAudit] CHECK CONSTRAINT [FK_ClientViewAudit_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[FollowUp] CHECK CONSTRAINT [FK_FollowUp_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[FollowUp] CHECK CONSTRAINT [FK_FollowUp_CompletedBy]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[LoginAudit] CHECK CONSTRAINT [FK_LoginAudit_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[UsersXLocations] CHECK CONSTRAINT [FK_UsersXLocations_Users]", false); ExecuteNonQueryCommand(@"DROP TABLE temp_User", false); // HERE IS THE PROBLEM: NOTHING FOUND IN .GetObjects() for the old types foreach (SecuritySystemUser securitySystemUser in ObjectSpace.GetObjects<SecuritySystemUser>()) { CopyUser(securitySystemUser); } foreach (SecuritySystemRole securitySystemRole in ObjectSpace.GetObjects<SecuritySystemRole>()) { CopyRole(securitySystemRole, null); } ObjectSpace.CommitChanges(); } }

I even added this to my module constructor (although I don't believe it's needed)

C#
AdditionalExportedTypes.AddRange(new Type[] { typeof(SecuritySystemUser), typeof(SecuritySystemRole) });

So I can log in and I see that it's using the new PermissionPolicyUser object, but I have no roles or permissions

Comments (1)
DevExpress Support Team 7 years ago

    Hello Randy,

    The How to upgrade an existing project to the Allow/Deny permission policy (migrate to PermissionPolicyUser and PermissionPolicyRole) article contains only common instructions and recommendations for the migration to the PermissionPolicy classes:
    "The main purpose of the following instructions is to simplify the migration as we cannot guarantee that all existing permissions will be converted correctly, because the old classes use different permission mechanisms. Only common scenarios are covered, others may not work, and you would need to manually check if all permissions are converted correctly and update them further yourself in case of any problems."

    Also the migration is the complicated process and you can have some issues in unexpected places. Do not forget to make the database backup and thoroughly check the data and permissions settings after the migration.
    The most reliable way is to create new PermissionPolicy permissions according to old SecuritySystem permission settings manually and follow the steps in the If you do not need to transfer existing permissions to the new permissions policy  part of the migration article:
    "invoke the Application Designer for the YourSolutionName.Wxx/WxxApplication.xx file and set the UserType and RoleType properties of the SecurityStrategyComplexcomponent to the PermissionPolicyUser and PermissionPolicyRole  values respectively. After that, update your code that creates predefined users, roles and the required permissions as per the Using the Security System help article."

    >> no objects are returned in ObjectSpace.GetObjects<SecuritySystemUser>()
    Probably the data could be lost while you used direct SQL queries. It is difficult to define the precise cause of this behavior. Try to switch your application back to the SecuritySystem classes, run it and check whether all works fine and the database contains this data.

    Answers approved by DevExpress Support

    created 7 years ago (modified 7 years ago)

    OK, so I was close.  And yes, doing all of this in dev/localdb and have restored many times :)  I really needed to get this to work since our client has over 200 users and several roles and type permissions defined.

    Basically, I had to let SecuritySystemUser create a type reference in XPObjectType (it never existed since I had a derived User class)

    Everything appears to be working now.

    Here is the modified version of my code in UpdateDatabaseAfterSchema:

    C#
    public override void UpdateDatabaseAfterUpdateSchema() { base.UpdateDatabaseAfterUpdateSchema(); if (CurrentDBVersion < new Version("1.0.6612.31390") && CurrentDBVersion > new Version("0.0.0.0")) { // convert SecuritySystem to PermissionPolicy ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[User] NOCHECK CONSTRAINT [FK_User_Oid]", false); ExecuteNonQueryCommand(@"INSERT INTO PermissionPolicyUser (Oid, UserName, StoredPassword, ChangePasswordOnFirstLogon, IsActive, ObjectType, OptimisticLockField) SELECT Oid, UserName, StoredPassword, ChangePasswordOnFirstLogon, IsActive, ObjectType, OptimisticLockField FROM SecuritySystemUser", false); ExecuteNonQueryCommand(@"INSERT INTO [User] SELECT * from temp_User", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[User] CHECK CONSTRAINT [FK_User_Oid]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[Class] CHECK CONSTRAINT [FK_Class_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[Client] CHECK CONSTRAINT [FK_Client_Staff]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[ClientCase] CHECK CONSTRAINT [FK_ClientCase_Counselor]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[ClientViewAudit] CHECK CONSTRAINT [FK_ClientViewAudit_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[FollowUp] CHECK CONSTRAINT [FK_FollowUp_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[FollowUp] CHECK CONSTRAINT [FK_FollowUp_CompletedBy]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[LoginAudit] CHECK CONSTRAINT [FK_LoginAudit_User]", false); ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[UsersXLocations] CHECK CONSTRAINT [FK_UsersXLocations_Users]", false); ExecuteNonQueryCommand(@"DROP TABLE temp_User", false); // update SecuritySystemUser with new ObjectType // this will cause a new XPObjectType to be created (since this is no longer the parent class of User) int iXPOid = 0; XPCollection<SecuritySystemUser> ssUsers = new XPCollection<SecuritySystemUser>(prodcheck.Session); while (1 == 1) { ObjectSpace.ReloadCollection(ssUsers); if (ssUsers != null) { // force an object to read from db in order to Create the type in XPObjectType int iCount = ssUsers.Count; if (iCount > 0) break; } // now get new ObjectType var xOid = ExecuteScalarCommand("SELECT OID FROM XPObjectType WHERE TypeName = 'DevExpress.ExpressApp.Security.Strategy.SecuritySystemUser'", false); // and update SecuritySystemUser with this if (xOid != null) { iXPOid = Convert.ToInt32(xOid); ExecuteNonQueryCommand(string.Format("UPDATE SecuritySystemUser SET ObjectType = {0}", iXPOid), false); } } foreach (SecuritySystemUser securitySystemUser in ssUsers) { CopyUser(securitySystemUser); } foreach (SecuritySystemRole securitySystemRole in ObjectSpace.GetObjects<SecuritySystemRole>()) { CopyRole(securitySystemRole, null); } ObjectSpace.CommitChanges(); ssUsers.Dispose(); // Clean up unused type reference ExecuteNonQueryCommand(@"ALTER TABLE [dbo].[SecuritySystemUser] NOCHECK CONSTRAINT [FK_SecuritySystemUser_ObjectType]", false); ExecuteNonQueryCommand(string.Format("DELETE FROM XPObjectType WHERE OID = {0}", iXPOid), false); } }
      Comments (1)
      DevExpress Support Team 7 years ago

        Hello Randy,

        Thank you for sharing your solution. I converted your comment to the answer and closed this ticket. Please do not hesitate to contact us again in the future.

        Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

        Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.