Issue
Users with the 'delegated_developer' role but not the 'admin' role can face a blank screen when logging in due to an incorrect permission set configuration.
How it works
A new role is created for each permission set that is granted to a delegated developer for each application scope. There should be a maximum of 13 (as of today) distinct permission sets per application if there are duplicates the login will fail to complete.
These permission sets are saved to the 'sys_scope_permission_set_role_assignment' table. Permission sets consist of 2 reference fields:
- sys_development_permission_set - predefined development permissions
- sys_user_role - A role is created and assigned specifically for this scope and permission set in this format: sn_dd_<APPLICATION SCOPE>_<PERMISSION SET NAME>_rc_01
If a duplicate permission set is created for the same scope then the delegated_developer (without Admin role) will face a blank screen when logging in.
This is because the duplicate keys cause the immutable map object used to check permissions to fail and throw the below stack trace:
2019-05-10 01:12:22 (658) AMB_SEND-thread-5 63A3798E3719B7409D8C1A7943990EFE txid=ef4b354a3759 SEVERE *** ERROR *** Multiple entries with same key: =<APPLICATION SCOPE HERE> and =<APPLICATION SCOPE HERE>
java.lang.IllegalArgumentException: Multiple entries with same key: =<APPLICATION SCOPE HERE> and =<APPLICATION SCOPE HERE>
at com.google.common.collect.ImmutableMap.checkNoConflict(ImmutableMap.java:136)
at com.google.common.collect.RegularImmutableMap.checkNoConflictInKeyBucket(RegularImmutableMap.java:98)
at com.google.common.collect.RegularImmutableMap.fromEntryArray(RegularImmutableMap.java:84)
at com.google.common.collect.ImmutableMap$Builder.build(ImmutableMap.java:295)
at com.glide.sys.security.delegateddev.ScopePermissionSetRoleAssignment.loadRoleNamesFromDb(ScopePermissionSetRoleAssignment.java:154)
at com.glide.sys.cache.TypeSafeCacheManager.get(TypeSafeCacheManager.java:85)
at com.glide.sys.security.delegateddev.ScopePermissionSetRoleAssignment.scopesForRoleNames(ScopePermissionSetRoleAssignment.java:97)
at com.glide.sys.security.delegateddev.scoperoleescalation.EscalatableRoles.getEscalatableRolesForEnvironment(EscalatableRoles.java:22)
at com.glide.sys.security.delegateddev.scoperoleescalation.ScopeRoleEscalationAccessHandler.hasRightsTo(ScopeRoleEscalationAccessHandler.java:28)
at com.glide.sys.security.CompositeAccessHandler.hasRightsTo(CompositeAccessHandler.java:52)
at com.glide.sys.security.ContextualSecurityManager.eval(ContextualSecurityManager.java:703)
at com.glide.sys.security.ContextualSecurityManager.hasRightsToImpl(ContextualSecurityManager.java:624)
at com.glide.sys.security.ContextualSecurityManager.hasRightsTo(ContextualSecurityManager.java:590)
at com.glide.sys.security.ContextualSecurityManager.hasRightsTo(ContextualSecurityManager.java:572)
at com.glide.processors.AProcessor.isACLAuthorized(AProcessor.java:645)
at com.glide.processors.AProcessor.isProcessorACLAuthorized(AProcessor.java:636)
at com.glide.processors.AProcessor.processTransaction(AProcessor.java:206)
at com.glide.processors.ProcessorRegistry.process0(ProcessorRegistry.java:178)
at com.glide.processors.ProcessorRegistry.process(ProcessorRegistry.java:167)
at com.glide.ui.GlideServletTransaction.process(GlideServletTransaction.java:31)
at com.glide.sys.Transaction.run(Transaction.java:2091)
at com.glide.amb.server.AMBTransaction.run(AMBTransaction.java:25)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Example
This is an example of a 'broken' permission set:
This situation was achieved by manually deleting the role from the 'sys_user_role' table without cleaning up the corresponding permission set from 'sys_scope_permission_set_role_assignment'.