Optimise permissions checking for a space

XMLWordPrintable

    • 0
    • 4

      Background

      At the moment, if a space has permissions for 10 different groups, and Confluence needs to check is user has an access to the space, it call this method 10 times:

      crowdService.isUserMemberOfGroup(userName, groupName) 

      If there are a plenty of groups, each call would take some time, and users will notice the slowness of the system.

      Possible solutions

      Solution 1. We need a method in Crowd like:

      crowdService.isUserMemberOfAnyGroup(userName, groupNameList) 

      It would improve performance, but it requires to change Crowd API. 

      Solution 2. Retrieve all user groups only once

      Another way (without modifying Crowd) is to retrieve all user’s groups first (Crowd allows to do this). And then check check user's groups against space groups without calling Crowd again.

      The only problem could be if a user is a part of thousands of groups, but, fortunately, the result will be cached and used for any other space.

      Here is the relevant stack-trace:

         java.lang.Thread.State: RUNNABLE
      	at org.hibernate.event.internal.ProxyVisitor.processEntity(ProxyVisitor.java:32)
      	at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:107)
      	at org.hibernate.event.internal.WrapVisitor.processValue(WrapVisitor.java:108)
      	at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:59)
      	at org.hibernate.event.internal.DefaultFlushEntityEventListener.wrapCollections(DefaultFlushEntityEventListener.java:203)
      	at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:140)
      	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216)
      	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85)
      	at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:44)
      	at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1389)
      	at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1474)
      	at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1441)
      	at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1410)
      	at com.atlassian.crowd.embedded.hibernate2.HibernateSearch.doInHibernate(HibernateSearch.java:112)
      	at com.atlassian.crowd.embedded.hibernate2.HibernateSearch.doInHibernate(HibernateSearch.java:81)
      	at org.springframework.orm.hibernate5.HibernateTemplate.doExecute(HibernateTemplate.java:385)
      	at org.springframework.orm.hibernate5.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:351)
      	at com.atlassian.crowd.embedded.hibernate2.HibernateMembershipDao.search(HibernateMembershipDao.java:151)
      	at com.atlassian.confluence.user.crowd.CachedCrowdMembershipDao.lambda$childGroupSearch$2(CachedCrowdMembershipDao.java:154)
      	at com.atlassian.confluence.user.crowd.CachedCrowdMembershipDao$$Lambda$1496/0x000000080218d840.get(Unknown Source)
      	at com.atlassian.confluence.user.crowd.DefaultGroupMembershipCache.lambda$getGroupsForGroup$0(DefaultGroupMembershipCache.java:69)
      	at com.atlassian.confluence.user.crowd.DefaultGroupMembershipCache$$Lambda$1498/0x000000080218ec40.get(Unknown Source)
      	at com.atlassian.confluence.cache.CacheOperations.lambda$get$0(CacheOperations.java:172)
      	at com.atlassian.confluence.cache.CacheOperations$$Lambda$1441/0x0000000802017040.apply(Unknown Source)
      	at java.util.HashMap.computeIfAbsent(java.base@11.0.7/Unknown Source)
      	at com.atlassian.confluence.cache.CacheOperations.get(CacheOperations.java:172)
      	at com.atlassian.confluence.cache.DeferredOperationsCache.getOrLoad(DeferredOperationsCache.java:93)
      	at com.atlassian.confluence.cache.DeferredOperationsCache.get(DeferredOperationsCache.java:57)
      	at com.atlassian.confluence.cache.TransactionalCacheFactory$TransactionalCache.get(TransactionalCacheFactory.java:343)
      	at com.atlassian.confluence.impl.cache.tx.TransactionAwareCache$1.get(TransactionAwareCache.java:43)
      	at com.atlassian.confluence.user.crowd.DefaultGroupMembershipCache.getGroupsForGroup(DefaultGroupMembershipCache.java:67)
      	at com.atlassian.confluence.user.crowd.CachedCrowdMembershipDao.childGroupSearch(CachedCrowdMembershipDao.java:153)
      	at com.atlassian.confluence.user.crowd.CachedCrowdMembershipDao.search(CachedCrowdMembershipDao.java:139)
      	at jdk.internal.reflect.GeneratedMethodAccessor454.invoke(Unknown Source)
      	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.7/Unknown Source)
      	at java.lang.reflect.Method.invoke(java.base@11.0.7/Unknown Source)
      	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
      	at com.atlassian.spring.interceptors.SpringProfilingInterceptor.invoke(SpringProfilingInterceptor.java:16)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
      	at org.springframework.transaction.interceptor.TransactionInterceptor$$Lambda$672/0x0000000800bcf840.proceedWithInvocation(Unknown Source)
      	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
      	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
      	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
      	at com.sun.proxy.$Proxy249.search(Unknown Source)
      	at com.atlassian.crowd.directory.AbstractInternalDirectory.searchGroupRelationships(AbstractInternalDirectory.java:854)
      	at com.atlassian.crowd.directory.AbstractForwardingDirectory.searchGroupRelationships(AbstractForwardingDirectory.java:234)
      	at com.atlassian.crowd.manager.directory.RemoteDirectorySearcher.searchDirectGroupRelationships(RemoteDirectorySearcher.java:71)
      	at com.atlassian.crowd.manager.directory.RemoteDirectorySearcher.isUserIndirectGroupMember(RemoteDirectorySearcher.java:111)
      	at com.atlassian.crowd.manager.directory.RemoteDirectorySearcher.isUserNestedGroupMember(RemoteDirectorySearcher.java:106)
      	at com.atlassian.crowd.manager.directory.RemoteDirectorySearcher.isUserIndirectGroupMember(RemoteDirectorySearcher.java:118)
      	at com.atlassian.crowd.manager.directory.RemoteDirectorySearcher.isUserNestedGroupMember(RemoteDirectorySearcher.java:106)
      	at com.atlassian.crowd.manager.directory.RemoteDirectorySearcher.isUserIndirectGroupMember(RemoteDirectorySearcher.java:118)
      	at com.atlassian.crowd.manager.directory.RemoteDirectorySearcher.isUserNestedGroupMember(RemoteDirectorySearcher.java:106)
      	at com.atlassian.crowd.manager.directory.RemoteDirectorySearcher.isUserNestedGroupMember(RemoteDirectorySearcher.java:91)
      	at com.atlassian.crowd.manager.directory.DirectoryManagerGeneric.isUserNestedGroupMember(DirectoryManagerGeneric.java:739)
      	at com.atlassian.crowd.manager.application.ApplicationServiceGeneric$6.fallibleCheckForEntity(ApplicationServiceGeneric.java:1208)
      	at com.atlassian.crowd.manager.application.ApplicationServiceGeneric$DirectoryPredicate.apply(ApplicationServiceGeneric.java:1173)
      	at com.atlassian.crowd.manager.application.ApplicationServiceGeneric$DirectoryPredicate.apply(ApplicationServiceGeneric.java:1169)
      	at com.google.common.collect.Iterators.indexOf(Iterators.java:764)
      	at com.google.common.collect.Iterators.any(Iterators.java:663)
      	at com.google.common.collect.Iterables.any(Iterables.java:608)
      	at com.atlassian.crowd.manager.application.ApplicationServiceGeneric.isUserNestedGroupMember(ApplicationServiceGeneric.java:1686)
      	at com.atlassian.crowd.embedded.core.CrowdServiceImpl.isUserMemberOfGroup(CrowdServiceImpl.java:230)
      	at jdk.internal.reflect.GeneratedMethodAccessor853.invoke(Unknown Source)
      	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.7/Unknown Source)
      	at java.lang.reflect.Method.invoke(java.base@11.0.7/Unknown Source)
      	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
      	at com.atlassian.spring.interceptors.SpringProfilingInterceptor.invoke(SpringProfilingInterceptor.java:16)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
      	at org.springframework.transaction.interceptor.TransactionInterceptor$$Lambda$672/0x0000000800bcf840.proceedWithInvocation(Unknown Source)
      	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
      	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
      	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
      	at com.sun.proxy.$Proxy104.isUserMemberOfGroup(Unknown Source)
      	at com.atlassian.confluence.security.AbstractSpacePermissionManager.hasPermissionViaGroups(AbstractSpacePermissionManager.java:387)
      	at com.atlassian.confluence.security.AbstractSpacePermissionManager.hasPermissionNoExemptions(AbstractSpacePermissionManager.java:177)
      	at com.atlassian.confluence.security.CachingSpacePermissionManager.hasPermissionNoExemptions(CachingSpacePermissionManager.java:252)
      	at com.atlassian.confluence.impl.security.recovery.RecoveryAwareCachingSpacePermissionManager.hasPermissionNoExemptions(RecoveryAwareCachingSpacePermissionManager.java:91)
      	at jdk.internal.reflect.GeneratedMethodAccessor1378.invoke(Unknown Source)
      	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.7/Unknown Source)
      	at java.lang.reflect.Method.invoke(java.base@11.0.7/Unknown Source)
      	at com.atlassian.confluence.impl.security.SpacePermissionManagerFactory.lambda$new$0(SpacePermissionManagerFactory.java:68)
      	at com.atlassian.confluence.impl.security.SpacePermissionManagerFactory$$Lambda$457/0x0000000800964c40.invoke(Unknown Source)
      	at com.sun.proxy.$Proxy108.hasPermissionNoExemptions(Unknown Source)
      	at com.atlassian.confluence.security.delegate.AbstractPermissionsDelegate.hasSpaceLevelPermission(AbstractPermissionsDelegate.java:17)
      	at com.atlassian.confluence.security.delegate.PagePermissionsDelegate.canEdit(PagePermissionsDelegate.java:30)
      	at com.atlassian.confluence.security.delegate.PagePermissionsDelegate.canEdit(PagePermissionsDelegate.java:13)
      	at com.atlassian.confluence.security.delegate.TargetToLatestVersionDecorator.canEdit(TargetToLatestVersionDecorator.java:34)
      	at com.atlassian.confluence.security.delegate.SharedAccessInterceptor$$Lambda$2664/0x0000000802fe9040.test(Unknown Source)
      	at com.atlassian.confluence.security.delegate.SharedAccessInterceptor.checkAccess(SharedAccessInterceptor.java:87)
      	at com.atlassian.confluence.security.delegate.SharedAccessInterceptor.canEdit(SharedAccessInterceptor.java:35)
      	at com.atlassian.confluence.security.Permission$2.checkAgainst(Permission.java:29)
      	at com.atlassian.confluence.security.DefaultPermissionManager.hasPermissionNoExemptions(DefaultPermissionManager.java:100)
      	at jdk.internal.reflect.GeneratedMethodAccessor1377.invoke(Unknown Source)
      	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.7/Unknown Source)
      	at java.lang.reflect.Method.invoke(java.base@11.0.7/Unknown Source)
      	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
      	at com.atlassian.spring.interceptors.SpringProfilingInterceptor.invoke(SpringProfilingInterceptor.java:16)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
      	at org.springframework.transaction.interceptor.TransactionInterceptor$$Lambda$672/0x0000000800bcf840.proceedWithInvocation(Unknown Source)
      	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295)
      	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
      	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
      	at com.sun.proxy.$Proxy115.hasPermissionNoExemptions(Unknown Source)
      	at com.atlassian.confluence.plugin.descriptor.web.conditions.PagePermissionCondition.shouldDisplay(PagePermissionCondition.java:19)
      	at com.atlassian.confluence.plugin.descriptor.web.conditions.BaseConfluenceCondition.shouldDisplay(BaseConfluenceCondition.java:33)
      	at com.atlassian.plugin.web.conditions.AndCompositeCondition.shouldDisplay(AndCompositeCondition.java:22)
      	at com.atlassian.plugin.web.DefaultWebInterfaceManager.filterFragmentsByCondition(DefaultWebInterfaceManager.java:160)
      	at com.atlassian.plugin.web.DefaultWebInterfaceManager.getDisplayableItems(DefaultWebInterfaceManager.java:113)
      	at com.atlassian.confluence.plugin.descriptor.web.ConfluenceWebInterfaceManager.getDisplayableItems(ConfluenceWebInterfaceManager.java:78)

            Assignee:
            Unassigned
            Reporter:
            George Lipatov
            Votes:
            10 Vote for this issue
            Watchers:
            9 Start watching this issue

              Created:
              Updated: