Uploaded image for project: 'Crowd Data Center'
  1. Crowd Data Center
  2. CWD-3147

If a user exists in two directories in an application, and is added to a group in one directory that it was already in the other, clients get duplicate key errors

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Obsolete
    • Icon: Medium Medium
    • 2.8
    • 2.6.1, 2.7.2
    • None
    • None

      Symptoms

      In a client application, directory synchronisation fails with a duplicate key error, when adding a group membership. This will appear in the client log.

      Sample Confluence log:

      2013-02-20 15:49:36,071 ERROR [scheduler_Worker-4] [atlassian.crowd.directory.DbCachingDirectoryPoller] pollChanges Error occurred while refreshing the cache for directory [ 98307 ].
      org.springframework.dao.DataIntegrityViolationException: Hibernate operation: could not insert: [com.atlassian.crowd.embedded.hibernate2.HibernateMembership#295109]; SQL []; ERROR: duplicate key value violates unique constraint "cwd_unique_user_membership"
        Detail: Key (parent_id, child_user_id)=(163847, 229382) already exists.; nested exception is org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "cwd_unique_user_membership"
        Detail: Key (parent_id, child_user_id)=(163847, 229382) already exists.
      	at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:100)
      	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
      	at org.springframework.orm.hibernate.HibernateTransactionManager.convertJdbcAccessException(HibernateTransactionManager.java:619)
      	at org.springframework.orm.hibernate.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:605)
      	at org.springframework.orm.hibernate.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:518)
      	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:732)
      	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:701)
      	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321)
      	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116)
      	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
      	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
      	at com.atlassian.crowd.directory.$Proxy1476.addUserToGroup(Unknown Source)
      	at com.atlassian.crowd.directory.DirectoryCacheImplUsingChangeOperations.addUserToGroup(DirectoryCacheImplUsingChangeOperations.java:187)
      	at com.atlassian.crowd.directory.ldap.cache.EventTokenChangedCacheRefresher.synchroniseChanges(EventTokenChangedCacheRefresher.java:115)
      	at com.atlassian.crowd.directory.DbCachingRemoteDirectory.synchroniseCache(DbCachingRemoteDirectory.java:610)
      	at com.atlassian.crowd.manager.directory.DirectorySynchroniserImpl.synchronise(DirectorySynchroniserImpl.java:63)
      	at com.atlassian.crowd.directory.DbCachingDirectoryPoller.pollChanges(DbCachingDirectoryPoller.java:50)
      	at com.atlassian.crowd.manager.directory.monitor.poller.DirectoryPollerJobBean.executeInternal(DirectoryPollerJobBean.java:29)
      	at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
      	at org.quartz.core.JobRunShell.run(JobRunShell.java:199)
      	at com.atlassian.confluence.schedule.quartz.ConfluenceQuartzThreadPool$1.run(ConfluenceQuartzThreadPool.java:20)
      	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)
      Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "cwd_unique_user_membership"
        Detail: Key (parent_id, child_user_id)=(163847, 229382) already exists.
      	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
      	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
      	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
      	at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:500)
      	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:388)
      	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:334)
      	at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
      	at net.sf.hibernate.impl.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:22)
      	at net.sf.hibernate.persister.EntityPersister.insert(EntityPersister.java:462)
      	at net.sf.hibernate.persister.EntityPersister.insert(EntityPersister.java:436)
      	at net.sf.hibernate.impl.ScheduledInsertion.execute(ScheduledInsertion.java:37)
      	at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2464)
      	at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2450)
      	at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2407)
      	at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2276)
      	at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
      	at org.springframework.orm.hibernate.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:510)
      	... 17 more
      

      Sample JIRA log:

      2013-02-20 15:49:35,363 QuartzWorker-0 ERROR ServiceRunner     [atlassian.crowd.directory.DbCachingDirectoryPoller] Error occurred while refreshing the cache for directory [ 10001 ].
      com.atlassian.jira.crowd.embedded.ofbiz.db.DataAccessException: org.ofbiz.core.entity.GenericEntityException: while inserting: [GenericEntity:Membership][id,10067][membershipType,GROUP_USER][lowerParentName,jira-users][parentId,10013][childId,10014][childName,dmason][lowerChildName,dmason][directoryId,10001][parentName,jira-users] (SQL Exception while executing the following:INSERT INTO public.cwd_membership (ID, parent_id, child_id, membership_type, group_type, parent_name, lower_parent_name, child_name, lower_child_name, directory_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) (ERROR: duplicate key value violates unique constraint "uk_mem_parent_child_type"
        Detail: Key (parent_id, child_id, membership_type)=(10013, 10014, GROUP_USER) already exists.))
      	at com.atlassian.jira.crowd.embedded.ofbiz.db.OfBizHelper.createValue(OfBizHelper.java:167)
      	at com.atlassian.jira.crowd.embedded.ofbiz.OfBizInternalMembershipDao.createMembership(OfBizInternalMembershipDao.java:101)
      	at com.atlassian.jira.crowd.embedded.ofbiz.OfBizInternalMembershipDao.addUserToGroup(OfBizInternalMembershipDao.java:94)
      	at com.atlassian.jira.crowd.embedded.ofbiz.OfBizDelegatingMembershipDao.addUserToGroup(OfBizDelegatingMembershipDao.java:78)
      	at com.atlassian.crowd.directory.AbstractInternalDirectory.addUserToGroup(AbstractInternalDirectory.java:695)
      	at com.atlassian.crowd.directory.DbCachingRemoteChangeOperations.addUserToGroup(DbCachingRemoteChangeOperations.java:1151)
      	at com.atlassian.crowd.directory.DirectoryCacheImplUsingChangeOperations.addUserToGroup(DirectoryCacheImplUsingChangeOperations.java:187)
      	at com.atlassian.crowd.directory.ldap.cache.EventTokenChangedCacheRefresher.synchroniseChanges(EventTokenChangedCacheRefresher.java:115)
      	at com.atlassian.crowd.directory.DbCachingRemoteDirectory.synchroniseCache(DbCachingRemoteDirectory.java:609)
      	at com.atlassian.crowd.manager.directory.DirectorySynchroniserImpl.synchronise(DirectorySynchroniserImpl.java:63)
      	at com.atlassian.crowd.directory.DbCachingDirectoryPoller.pollChanges(DbCachingDirectoryPoller.java:50)
      	at com.atlassian.crowd.manager.directory.monitor.poller.DirectoryPollerJob.execute(DirectoryPollerJob.java:34)
      	at org.quartz.core.JobRunShell.run(JobRunShell.java:195)
      	at com.atlassian.multitenant.quartz.MultiTenantThreadPool$MultiTenantRunnable.run(MultiTenantThreadPool.java:72)
      	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:520)
      Caused by: org.ofbiz.core.entity.GenericEntityException: while inserting: [GenericEntity:Membership][id,10067][membershipType,GROUP_USER][lowerParentName,jira-users][parentId,10013][childId,10014][childName,dmason][lowerChildName,dmason][directoryId,10001][parentName,jira-users] (SQL Exception while executing the following:INSERT INTO public.cwd_membership (ID, parent_id, child_id, membership_type, group_type, parent_name, lower_parent_name, child_name, lower_child_name, directory_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) (ERROR: duplicate key value violates unique constraint "uk_mem_parent_child_type"
        Detail: Key (parent_id, child_id, membership_type)=(10013, 10014, GROUP_USER) already exists.))
      	at org.ofbiz.core.entity.GenericDAO.singleInsert(GenericDAO.java:136)
      	at org.ofbiz.core.entity.GenericDAO.insert(GenericDAO.java:101)
      	at org.ofbiz.core.entity.GenericHelperDAO.create(GenericHelperDAO.java:64)
      	at org.ofbiz.core.entity.GenericDelegator.create(GenericDelegator.java:487)
      	at org.ofbiz.core.entity.GenericValue.create(GenericValue.java:98)
      	at com.atlassian.jira.crowd.embedded.ofbiz.db.OfBizHelper.createValue(OfBizHelper.java:162)
      	... 14 more
      

      This also happens when using JIRA as a user directory server for other applications.

      Cause

      The application in Crowd has multiple directories, and a user name exists in both directories. When a user is a member of a group in one directory, then added to the same named group in the other directory, then when clients synchronise again, they try to add the user to that group. Since that user is already a member of the group, it's a duplicate key error.

      Steps to Reproduce

      1. Create two internal directories in crowd
      2. Create a user in each of them, with the same name
      3. Create a group in both directories
      4. Add the user to a group in one of the directories
      5. Add an application that includes both directories
      6. Connect a client to that application in the Crowd server
      7. Ensure it synchronises at least once
      8. Add the user to the same group in the directory where it didn't already have that membership
      9. Synchronise the client again

      Workaround

      Two ways to prevent it from occurring:

      1. Ensure that there are no overlaps in usernames between directories, or ensure that groups are not added when the membership already exists in one directory (process change). This may be hard to manage if one of the directories is an LDAP synchronised directory, or synchronised from another Crowd server out of the control of the administrator.
      2. Create two applications, each with only one of the directories in them. Then set up two user directories in the client instead. This does not work, if JIRA is the Crowd server, as JIRA simply uses all directories whenever a client connects in.

      If it does occur in the client, you can clear the remote directory cache to stop it from happening until the next time a user is added to a group this way:

      1. Disable the directory
      2. Enable the directory
      3. Force a full synchronisation

              Unassigned Unassigned
              dmason David Mason (Inactive)
              Votes:
              21 Vote for this issue
              Watchers:
              42 Start watching this issue

                Created:
                Updated:
                Resolved: