XSRF failure for GET REST requests when Update group membership on login is enabled and user or group membership is updated

XMLWordPrintable

    • Type: Bug
    • Resolution: Fixed
    • Priority: Low
    • 8.0.0, 7.2.2, 8.0.0 EAP1
    • Affects Version/s: 7.1.1
    • Component/s: REST API
    • None
    • 3
    • Severity 2 - Major
    • 1

      Issue Summary

      If Update group membership on login is enabled and there is an underlying change to the user in LDAP/Crowd (email, firstname, lastname etc) or their group membership is updated, GET requests to REST APIs will fail.

      Steps to Reproduce

      1. Hook Bamboo up to Crowd or LDAP
      2. Ensure Update group memberships when logging in: Everytime is enabled
      3. Create a user in Crowd and add it to a Bamboo group
      4. Login as that user into Bamboo
      5. Now go into Crowd and update their first or last name (or in LDAP, go from no email attribute to an empty string)
      6. Perform a GET request to $BAMBOO_BASE_URL/rest/api/latest/result/$PLAN_KEY.json

      Expected Results

      Request succeeds

      Actual Results

      Request fails with XSRF failure.

      The below exception is thrown if the user attributes were updated:

      java.lang.IllegalStateException: XSRF: A mutative operation was attempted on InternalUser within a non-mutative HTTP request: $BAMBOO_BASE_URL/rest/api/latest/result/RESULT_KEY.json :
      [[old row]]->[[new row]]
      		at com.atlassian.bamboo.utils.XsrfUtils.fail(XsrfUtils.java:27)
      		at com.atlassian.bamboo.hibernate.ReadOnlyGetMethodEnforcer.fail(ReadOnlyGetMethodEnforcer.java:125)
      		at com.atlassian.bamboo.hibernate.ReadOnlyGetMethodEnforcer.onFlushDirty(ReadOnlyGetMethodEnforcer.java:76)
      		at org.hibernate.event.internal.DefaultFlushEntityEventListener.invokeInterceptor(DefaultFlushEntityEventListener.java:355)
      		at org.hibernate.event.internal.DefaultFlushEntityEventListener.handleInterception(DefaultFlushEntityEventListener.java:332)
      		at org.hibernate.event.internal.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:283)
      		at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:154)
      		at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:235)
      		at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:94)
      		at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:44)
      		at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1415)
      		at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1501)
      		at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1537)
      		at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1505)
      		at com.atlassian.crowd.dao.membership.MembershipDAOHibernate.search(MembershipDAOHibernate.java:304)
      		at com.atlassian.crowd.directory.AbstractInternalDirectory.searchGroupRelationships(AbstractInternalDirectory.java:872)
      		at com.atlassian.crowd.directory.DbCachingRemoteDirectory.updateGroupsMembershipOnLogin(DbCachingRemoteDirectory.java:349)
      		at com.atlassian.crowd.directory.DbCachingRemoteDirectory.updateUserFromRemoteDirectory(DbCachingRemoteDirectory.java:285)
      		at com.atlassian.crowd.directory.DbCachingRemoteDirectory.authenticateAndUpdateInternalUser(DbCachingRemoteDirectory.java:253)
      		at com.atlassian.crowd.directory.DbCachingRemoteDirectory.performAuthenticationAndUpdateAttributes(DbCachingRemoteDirectory.java:192)
      		at com.atlassian.crowd.directory.DbCachingRemoteDirectory.authenticate(DbCachingRemoteDirectory.java:172)
      		at com.atlassian.crowd.manager.directory.DirectoryManagerGeneric.authenticateUser(DirectoryManagerGeneric.java:284)
      		at sun.reflect.GeneratedMethodAccessor2027.invoke(Unknown Source)
      		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      		at java.lang.reflect.Method.invoke(Method.java:498)
      		at com.sun.proxy.$Proxy170.authenticateUser(Unknown Source)
      		at com.atlassian.crowd.manager.application.ApplicationServiceGeneric.authenticateUser(ApplicationServiceGeneric.java:182)
      		at sun.reflect.GeneratedMethodAccessor2026.invoke(Unknown Source)
      		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      		at java.lang.reflect.Method.invoke(Method.java:498)
      		at com.sun.proxy.$Proxy173.authenticateUser(Unknown Source)
      		at com.atlassian.crowd.embedded.core.CrowdServiceImpl.authenticate(CrowdServiceImpl.java:70)
      		at sun.reflect.GeneratedMethodAccessor2025.invoke(Unknown Source)
      		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      		at java.lang.reflect.Method.invoke(Method.java:498)
      		at com.sun.proxy.$Proxy174.authenticate(Unknown Source)
      		at com.atlassian.crowd.embedded.atlassianuser.EmbeddedCrowdAuthenticator.authenticate(EmbeddedCrowdAuthenticator.java:24)
      		at com.atlassian.crowd.embedded.atlassianuser.EmbeddedCrowdAuthenticator$$FastClassBySpringCGLIB$$af97c51b.invoke(<generated>)
      		at com.atlassian.crowd.embedded.atlassianuser.EmbeddedCrowdAuthenticator$$EnhancerBySpringCGLIB$$cb218de2.authenticate(<generated>)
      		at bucket.user.DefaultUserAccessor.authenticate(DefaultUserAccessor.java:711)
      		at sun.reflect.GeneratedMethodAccessor2024.invoke(Unknown Source)
      		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      		at java.lang.reflect.Method.invoke(Method.java:498)
      		at com.sun.proxy.$Proxy183.authenticate(Unknown Source)
      		at com.atlassian.bamboo.user.authentication.BambooAuthenticator.authenticate(BambooAuthenticator.java:47)
      		at com.atlassian.seraph.auth.DefaultAuthenticator.login(DefaultAuthenticator.java:90)
      		at com.atlassian.bamboo.user.authentication.BambooAuthenticator.login(BambooAuthenticator.java:32)
      		at com.atlassian.seraph.auth.DefaultAuthenticator.getUserFromBasicAuthentication(DefaultAuthenticator.java:530)
      		at com.atlassian.seraph.auth.DefaultAuthenticator.getUser(DefaultAuthenticator.java:341)
      		at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:609)
      		at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
      		at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
      		at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1623)
      		at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
      		at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      		at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      		at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      		at java.lang.Thread.run(Thread.java:748)
      

      If group membership has changed:

      java.lang.IllegalStateException: XSRF: A mutative operation was attempted on InternalMembership within a non-mutative HTTP request: $BAMBOO_BASE_URL/rest/api/latest/result/RESULT_KEY.json : [null]->[new row]
      	at com.atlassian.bamboo.utils.XsrfUtils.fail(XsrfUtils.java:27)
      	at com.atlassian.bamboo.hibernate.ReadOnlyGetMethodEnforcer.fail(ReadOnlyGetMethodEnforcer.java:127)
      	at com.atlassian.bamboo.hibernate.ReadOnlyGetMethodEnforcer.failIfStateMutationNotAllowed(ReadOnlyGetMethodEnforcer.java:104)
      	at com.atlassian.bamboo.hibernate.ReadOnlyGetMethodEnforcer.onSave(ReadOnlyGetMethodEnforcer.java:88)
      	at com.atlassian.bamboo.persister.OidGenerationInterceptor.onSave(OidGenerationInterceptor.java:46)
      	at org.hibernate.event.internal.AbstractSaveEventListener.substituteValuesIfNecessary(AbstractSaveEventListener.java:419)
      	at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275)
      	at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:201)
      	at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
      	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
      	at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
      	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
      	at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
      	at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
      	at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:709)
      	at org.hibernate.internal.SessionImpl.save(SessionImpl.java:701)
      	at org.hibernate.internal.SessionImpl.save(SessionImpl.java:696)
      	at com.atlassian.crowd.util.persistence.hibernate.HibernateDao.save(HibernateDao.java:299)
      	at com.atlassian.crowd.dao.membership.MembershipDAOHibernate.addUserToGroup(MembershipDAOHibernate.java:131)
      	at com.atlassian.crowd.directory.AbstractInternalDirectory.addUserToGroup(AbstractInternalDirectory.java:816)
      	at com.atlassian.crowd.directory.DbCachingRemoteDirectory.addUserToGroupInternal(DbCachingRemoteDirectory.java:806)
      	at com.atlassian.crowd.directory.DbCachingRemoteDirectory.updateGroupsMembershipOnLogin(DbCachingRemoteDirectory.java:389)
      	at com.atlassian.crowd.directory.DbCachingRemoteDirectory.updateUserFromRemoteDirectory(DbCachingRemoteDirectory.java:288)
      	at com.atlassian.crowd.directory.DbCachingRemoteDirectory.authenticateAndUpdateInternalUser(DbCachingRemoteDirectory.java:256)
      	at com.atlassian.crowd.directory.DbCachingRemoteDirectory.authenticate(DbCachingRemoteDirectory.java:173)
      	at com.atlassian.crowd.manager.directory.DirectoryManagerGeneric.authenticateUser(DirectoryManagerGeneric.java:304)
      	at sun.reflect.GeneratedMethodAccessor2308.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      	at com.sun.proxy.$Proxy175.authenticateUser(Unknown Source)
      	at com.atlassian.crowd.manager.application.ApplicationServiceGeneric.authenticateUser(ApplicationServiceGeneric.java:177)
      	at sun.reflect.GeneratedMethodAccessor2348.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      	at com.sun.proxy.$Proxy179.authenticateUser(Unknown Source)
      	at com.atlassian.crowd.embedded.core.CrowdServiceImpl.authenticate(CrowdServiceImpl.java:70)
      	at sun.reflect.GeneratedMethodAccessor2347.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      	at com.sun.proxy.$Proxy180.authenticate(Unknown Source)
      	at com.atlassian.crowd.embedded.atlassianuser.EmbeddedCrowdAuthenticator.authenticate(EmbeddedCrowdAuthenticator.java:24)
      	at com.atlassian.crowd.embedded.atlassianuser.EmbeddedCrowdAuthenticator$$FastClassBySpringCGLIB$$af97c51b.invoke(<generated>)
      	at com.atlassian.crowd.embedded.atlassianuser.EmbeddedCrowdAuthenticator$$EnhancerBySpringCGLIB$$cb218de2.authenticate(<generated>)
      	at bucket.user.DefaultUserAccessor.authenticate(DefaultUserAccessor.java:711)
      	at sun.reflect.GeneratedMethodAccessor2346.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:498)
      	at com.sun.proxy.$Proxy189.authenticate(Unknown Source)
      	at com.atlassian.bamboo.user.authentication.BambooAuthenticator.authenticate(BambooAuthenticator.java:47)
      	at com.atlassian.seraph.auth.DefaultAuthenticator.login(DefaultAuthenticator.java:90)
      	at com.atlassian.bamboo.user.authentication.BambooAuthenticator.login(BambooAuthenticator.java:32)
      	at com.atlassian.seraph.auth.DefaultAuthenticator.getUserFromBasicAuthentication(DefaultAuthenticator.java:530)
      	at com.atlassian.seraph.auth.DefaultAuthenticator.getUser(DefaultAuthenticator.java:341)
      	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:609)
      	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
      	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
      	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1623)
      	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      	at java.lang.Thread.run(Thread.java:748)
      

      Both stacks have been heavily truncated to remove filters, springframework and catalina lines.

      Workaround

      Workaround 1

      Use Personal Access Tokens to authenticate with the API instead:

      Workaround 2

      Login as the user via the UI so that updates are performed. REST calls will now work until theres another change to the user or their group membership.

            Assignee:
            Alexey Chystoprudov
            Reporter:
            Jeremy Owen
            Votes:
            2 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: