Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Using IssueService to create an issue always uses the Context's LoggedInUser, not the parameter

Joerg
Contributor
July 21, 2021

Using this method in a post-function (or an event triggered listener) to create an issue seems to always use the Context's "LoggedInUser" (JiraAuthenticationContext.getLoggedInUser()).:


IssueService.IssueResult create(@Nullable
ApplicationUser user,
IssueService.CreateValidationResult createValidationResult)


This create method's documentation https://docs.atlassian.com/software/jira/docs/api/7.6.1/index.html?com/atlassian/jira/bc/issue/IssueService.html states this for the user parameter:
"Parameters:
user - who the permission checks will be run against (can be null, indicating an anonymous user)."

But this seems to be false. No matter which ApplicationUser you hand over to the method, it always uses the Context's LoggedInUser.

The workaround is to set the context's loggedInUser to the intended user before creating the issue by using this method. 

 

I encountered this curiosity while debugging a script where an issue should be created with an automated admin user, but the transition button is pressed by a non-admin user.

So my question is: Is this intended, an Atlassian bug, or am I missing something.

 

Steps to reproduce:

1. Use the above method to create an issue via post-function.

2. Set the "user" parameter of the method to: 

ComponentAccessor.getUserManager().getUserByName($some user's username with create permissions)

3. The user who presses the transition/workflow button must NOT have the permissions to create any issues in the target project.

 

Example Code that can be run from Script Runners console (adjust variables for project ID, issuetype and adminUser obviously):

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.issue.IssueEvent
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.IssueService.CreateValidationResult
import com.atlassian.jira.bc.issue.IssueService.IssueResult
import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.issue.search.SearchResults
import com.atlassian.jira.bc.issue.search.SearchService.ParseResult
import com.atlassian.jira.web.bean.PagerFilter

import org.apache.log4j.Logger
import org.apache.log4j.Level

Logger logger = Logger.getLogger("create.example")
logger.setLevel(Level.DEBUG)

IssueManager issueManager = ComponentAccessor.getIssueManager()
UserManager userManager = ComponentAccessor.getUserManager()
CustomFieldManager customFieldManager1 = ComponentAccessor.getCustomFieldManager()
IssueService issueService = ComponentAccessor.getIssueService()

ApplicationUser appUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() //Non-Admin User
ApplicationUser adminUser = userManager.getUserByName("autoassist") //Admin User

//Setting loggedInUser to adminUser (autoassist):
ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(adminUser);


String newSummary = "Create Test"

//creating with appUser, which is not adminUser "autoassist":
MutableIssue newIssue = createIssue(appUser, newSummary, issueService, logger)
logger.debug("New Issue: " + newIssue?.getKey())

//Both return "autoassist" as the Reporter and Creator:
logger.debug("Creator: " + newIssue?.getCreator())
logger.debug("Reporter: " + newIssue?.getReporter())

 

//** METHODS:

public MutableIssue createIssue(ApplicationUser appUser, String summary, IssueService issueService, Logger logger){
//ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(appUser);
IssueInputParameters issueInputParameters1 = issueService.newIssueInputParameters(new HashMap())

issueInputParameters1.setProjectId(13609L) //set project Id
issueInputParameters1.setIssueTypeId("10100") //set issuetype
issueInputParameters1.setSummary(summary)
//issueInputParameters1.setReporterId(appUser.username)
issueInputParameters1.setSkipScreenCheck(true)
issueInputParameters1.setApplyDefaultValuesWhenParameterNotProvided(true)
//issueInputParameters1.setRetainExistingValuesWhenParameterNotProvided(true, true)

CreateValidationResult createValidationResult = issueService.validateCreate(appUser, issueInputParameters1)
boolean isValid = createValidationResult.isValid()
Map<String, String> errorCollection = createValidationResult.getErrorCollection().getErrors();
if(errorCollection){
logger.info("ERROR: Validation errors:" + errorCollection);
for (String errorKey : errorCollection.keySet()) {
logger.debug(errorKey)
logger.debug(errorCollection.get(errorKey))
}
}

if(isValid){
IssueResult issueResult = issueService.create(appUser, createValidationResult)
MutableIssue newIssue = (MutableIssue)issueResult.getIssue()
logger.debug("CreatedIssue: " + issueResult + " Issue Key: " + newIssue)
return newIssue
}
}

1 answer

1 accepted

0 votes
Answer accepted
Martin Bayer _MoroSystems_ s_r_o__
Community Champion
July 21, 2021

Hi @Joerg can you share your script? You need to call also validateCreate method. What user do you use for this?

Joerg
Contributor
July 22, 2021

Edited my post, but not sure how to make a code block that looks pretty. :D
So here once again:


Joerg
Contributor
July 22, 2021
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.issue.IssueEvent
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.IssueService.CreateValidationResult
import com.atlassian.jira.bc.issue.IssueService.IssueResult
import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.issue.search.SearchResults
import com.atlassian.jira.bc.issue.search.SearchService.ParseResult
import com.atlassian.jira.web.bean.PagerFilter

import org.apache.log4j.Logger
import org.apache.log4j.Level

Logger logger = Logger.getLogger("create.example")
logger.setLevel(Level.DEBUG)

IssueManager issueManager = ComponentAccessor.getIssueManager()
UserManager userManager = ComponentAccessor.getUserManager()
CustomFieldManager customFieldManager1 = ComponentAccessor.getCustomFieldManager()
IssueService issueService = ComponentAccessor.getIssueService()

ApplicationUser appUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() //Non-Admin User
ApplicationUser adminUser = userManager.getUserByName("autoassist") //Admin User

//Setting loggedInUser to adminUser (autoassist):
ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(adminUser);


String newSummary = "Create Test"

//creating with appUser, which is not adminUser "autoassist":
MutableIssue newIssue = createIssue(appUser, newSummary, issueService, logger)
logger.debug("New Issue: " + newIssue?.getKey())

//Both return "autoassist" as the Reporter and Creator:
logger.debug("Creator: " + newIssue?.getCreator())
logger.debug("Reporter: " + newIssue?.getReporter())




//** METHODS:

public MutableIssue createIssue(ApplicationUser appUser, String summary, IssueService issueService, Logger logger){
//ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(appUser);
IssueInputParameters issueInputParameters1 = issueService.newIssueInputParameters(new HashMap())

issueInputParameters1.setProjectId(13609L) //set project Id
issueInputParameters1.setIssueTypeId("10100") //set issuetype
issueInputParameters1.setSummary(summary)
//issueInputParameters1.setReporterId(appUser.username)
issueInputParameters1.setSkipScreenCheck(true)
issueInputParameters1.setApplyDefaultValuesWhenParameterNotProvided(true)
//issueInputParameters1.setRetainExistingValuesWhenParameterNotProvided(true, true)

CreateValidationResult createValidationResult = issueService.validateCreate(appUser, issueInputParameters1)
boolean isValid = createValidationResult.isValid()
Map<String, String> errorCollection = createValidationResult.getErrorCollection().getErrors();
if(errorCollection){
logger.info("ERROR: Validation errors:" + errorCollection);
for (String errorKey : errorCollection.keySet()) {
logger.debug(errorKey)
logger.debug(errorCollection.get(errorKey))
}
}

if(isValid){
IssueResult issueResult = issueService.create(appUser, createValidationResult)
MutableIssue newIssue = (MutableIssue)issueResult.getIssue()
logger.debug("CreatedIssue: " + issueResult + " Issue Key: " + newIssue)
return newIssue
}
}
Joerg
Contributor
July 22, 2021

And guess what this script returns:
Screenshot 2021-07-22 182720.png

Joerg
Contributor
July 22, 2021

Also logging the AppUser variable at any point always returns my personal user, and not the "autoassist" admin user.

Martin Bayer _MoroSystems_ s_r_o__
Community Champion
July 22, 2021

Hi @Joerg , it is interesting. I checked Jira source codes and it looks like setApplyDefaultValuesWhenParameterNotProvided might be the problem.

Short description:

  • if you check com.atlassian.jira.issue.fields.ReporterSystemField implementation, you can see following implementation of method populateDefaults
    • public void populateDefaults(Map<String, Object> fieldValuesHolder, Issue issue) {
      ApplicationUser remoteUser = getDefaultValue(issue);
      if (remoteUser != null)
      fieldValuesHolder.put(getId(), remoteUser.getName());
      }

      public ApplicationUser getDefaultValue(Issue issue) {
      // The default value that should be set if the user cannot modify this field is the remote user's name
      return getAuthenticationContext().getUser();
      }

       

Can you try to call the method setApplyDefaultValuesWhenParameterNotProvided with false parameter? 

Martin Bayer _MoroSystems_ s_r_o__
Community Champion
July 23, 2021

Hi @Joerg did it work for you? :)

Joerg
Contributor
July 23, 2021

Deleted comment

Joerg
Contributor
July 23, 2021

Did some test anyway:

adjusted the script. I removed the create permission in the project from the "appUser". Only the adminUser now has create permission there:

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.issue.IssueEvent
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.bc.issue.IssueService.CreateValidationResult
import com.atlassian.jira.bc.issue.IssueService.IssueResult
import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.issue.search.SearchResults
import com.atlassian.jira.bc.issue.search.SearchService.ParseResult
import com.atlassian.jira.web.bean.PagerFilter

import org.apache.log4j.Logger
import org.apache.log4j.Level

Logger logger = Logger.getLogger("create.example")
logger.setLevel(Level.DEBUG)

IssueManager issueManager = ComponentAccessor.getIssueManager()
UserManager userManager = ComponentAccessor.getUserManager()
CustomFieldManager customFieldManager1 = ComponentAccessor.getCustomFieldManager()
IssueService issueService = ComponentAccessor.getIssueService()

//ApplicationUser appUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() //Non-Admin User
ApplicationUser appUser = userManager.getUserByName($userWithoutCreatePermissionInProject) //Random User without create permissions in the project
ApplicationUser adminUser = userManager.getUserByName("autoassist") //Admin User


//Setting loggedInUser to User without create permissions in the project:
ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(appUser);
logger.debug("AppUser without Create Permission: " + appUser)

String newSummary = "Create Test"

//creating with adminUser "autoassist":
MutableIssue newIssue = createIssue(adminUser, newSummary, issueService, logger)

logger.debug("New Issue: " + newIssue?.getKey())

//Both return "autoassist" as the Reporter and Creator:
logger.debug("Creator: " + newIssue?.getCreator())
logger.debug("Reporter: " + newIssue?.getReporter())




//** METHODS:

public MutableIssue createIssue(ApplicationUser appUser, String summary, IssueService issueService, Logger logger){
//ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(appUser);
IssueInputParameters issueInputParameters1 = issueService.newIssueInputParameters(new HashMap())

issueInputParameters1.setProjectId(13609L) //set project Id
issueInputParameters1.setIssueTypeId("10100") //set issuetype
issueInputParameters1.setSummary(summary)
issueInputParameters1.setReporterId(appUser.username)
// There seems to be no method to set creator: issueInputParameters1.setCreatorId(appUser.username) ?
issueInputParameters1.setSkipScreenCheck(true)
issueInputParameters1.setApplyDefaultValuesWhenParameterNotProvided(false)
//issueInputParameters1.setRetainExistingValuesWhenParameterNotProvided(true, true)

CreateValidationResult createValidationResult = issueService.validateCreate(appUser, issueInputParameters1)
boolean isValid = createValidationResult.isValid()
Map<String, String> errorCollection = createValidationResult.getErrorCollection().getErrors();
if(errorCollection){
logger.info("ERROR: Validation errors:" + errorCollection);
for (String errorKey : errorCollection.keySet()) {
logger.debug(errorKey)
logger.debug(errorCollection.get(errorKey))
}
}

if(isValid){
IssueResult issueResult = issueService.create(appUser, createValidationResult)
MutableIssue newIssue = (MutableIssue)issueResult.getIssue()
logger.debug("CreatedIssue: " + issueResult + " Issue Key: " + newIssue)
return newIssue
}
}
Joerg
Contributor
July 23, 2021

This is in the logs now:

Screenshot 2021-07-23 180227.png

Joerg
Contributor
July 23, 2021

Only if I set the loggedInUser to the adminUser it works, although I use the adminUser in the create method anyway.

Martin Bayer _MoroSystems_ s_r_o__
Community Champion
July 29, 2021

Hi @Joerg sorry for late response, I played with it few evenings and it's working now for me

  1. I removed all the logging functionality so it should be clear now
  2. it looks like the "user" value set as parameter of validateCreate and create methods is not taken into account because store() method in IssueImpl always uses logged in user. If there is no logged in user, reporter is used to be creator:
    1. 2021-07-29_22-37.png
  3. If I use following code
    1. I'm logged in as service user
    2. I used martin.bayer@external.com user to be used as parameter
    3. I used a.leng@external.com as app user who should be used as reporter
    4. permissions for the project is set:
      1. 2021-07-29_22-41.png
    5. code is:
      1. import com.atlassian.jira.component.ComponentAccessor
        import com.atlassian.jira.event.issue.IssueEvent
        import com.atlassian.jira.issue.Issue
        import com.atlassian.jira.issue.IssueManager
        import com.atlassian.jira.issue.CustomFieldManager
        import com.atlassian.jira.issue.fields.CustomField
        import com.atlassian.jira.bc.issue.IssueService
        import com.atlassian.jira.bc.issue.IssueService.CreateValidationResult
        import com.atlassian.jira.bc.issue.IssueService.IssueResult
        import com.atlassian.jira.issue.IssueInputParameters
        import com.atlassian.jira.issue.MutableIssue
        import com.atlassian.jira.user.util.UserManager
        import com.atlassian.jira.user.ApplicationUser
        import com.atlassian.jira.event.type.EventDispatchOption
        import com.atlassian.jira.bc.issue.search.SearchService
        import com.atlassian.jira.issue.search.SearchResults
        import com.atlassian.jira.bc.issue.search.SearchService.ParseResult
        import com.atlassian.jira.web.bean.PagerFilter

        import org.apache.log4j.Logger
        import org.apache.log4j.Level

        IssueManager issueManager = ComponentAccessor.getIssueManager()
        UserManager userManager = ComponentAccessor.getUserManager()
        CustomFieldManager customFieldManager1 = ComponentAccessor.getCustomFieldManager()
        IssueService issueService = ComponentAccessor.getIssueService()

        ApplicationUser appUser = userManager.getUserByName("a.leng@external.com") //Random User without create permissions in the project
        ApplicationUser adminUser = userManager.getUserByName("martin.bayer@external.com") //Admin User


        String newSummary = "Create Test"

        //creating with adminUser "autoassist":
        MutableIssue newIssue = createIssue(adminUser, appUser, newSummary, issueService, log)

        log.error("New Issue: " + newIssue?.getKey())

        //Both return "autoassist" as the Reporter and Creator:
        log.error("Creator: " + newIssue?.getCreator())
        log.error("Reporter: " + newIssue?.getReporter())





        //** METHODS:

        public MutableIssue createIssue(ApplicationUser adminUser, ApplicationUser appUser, String summary, IssueService issueService, Logger logger){
        //ComponentAccessor.getJiraAuthenticationContext().setLoggedInUser(appUser);
        IssueInputParameters issueInputParameters1 = issueService.newIssueInputParameters(new HashMap())

        issueInputParameters1.setProjectId(10248L) //set project Id
        issueInputParameters1.setIssueTypeId("10122") //set issuetype
        issueInputParameters1.setSummary(summary)
        issueInputParameters1.setReporterId(appUser.username)
        issueInputParameters1.setSkipScreenCheck(true)
        issueInputParameters1.setApplyDefaultValuesWhenParameterNotProvided(false)

        CreateValidationResult createValidationResult = issueService.validateCreate(adminUser, issueInputParameters1)
        boolean isValid = createValidationResult.isValid() && !createValidationResult.hasWarnings()
        Map<String, String> errorCollection = createValidationResult.getErrorCollection().getErrors();
        log.error "1:" + createValidationResult.isValid();
        log.error "2:" + createValidationResult.getWarningCollection().hasAnyWarnings();
        log.error "3:" + createValidationResult.hasWarnings();
        log.error createValidationResult.getErrorCollection().getErrors();
        def warningCollection = createValidationResult.getWarningCollection();
        if(errorCollection || warningCollection){
        logger.error("ERROR: Validation errors:" + errorCollection);
        logger.error("Warning: Validation errors:" + warningCollection.getWarnings());
        for (String errorKey : errorCollection.keySet()) {
        logger.error(errorKey)
        logger.error(errorCollection.get(errorKey))
        }
        }else{
        logger.error("No error collection")
        }

        if(isValid){
        IssueResult issueResult = issueService.create(adminUser, createValidationResult)
        MutableIssue newIssue = (MutableIssue)issueResult.getIssue()
        logger.error("CreatedIssue: " + issueResult + " Issue Key: " + newIssue)
        return newIssue
        }else{
        logger.error("Invalid request")
        }
        }

         

    6. and it creates issue with these attributes:
      1. 2021-07-29_22-44.png

I hope it will help... a little :)

Joerg
Contributor
July 30, 2021

Hey.

So basically you are confirming that the permissions are run against the loggedInUser then (unless there is none, then reporte is used)?

I wonder what is the point of the parameter in the validate and create methods of IssueService then? Is the user in parameter used to check permissions, but when it comes to storing the issue, there is an additional permission check for the creator (normally LoggedInUser), which has to have the create permission as well?

If so, then I wonder if this is a bug or oversight by Atlassian, because it is definitely confusing.
I guess my workaround would be (if the currently loggedInUser has no permissions, and I need to create the issue with another user) to:

  1. save the current LoggedInUser in a variable
  2. then set the adminUser as LoggedInUser
  3. validate + create the issue with this now logged in adminUser in the method parameter
  4. set the reporter to the desired non-admin user
  5. then revert the loggedInUser to the one saved in the variable in 1, so that any code coming after it isn't messed up or loses the info on the true/original currently logged in user.
Martin Bayer _MoroSystems_ s_r_o__
Community Champion
July 31, 2021

Hi @Joerg , yeah, it will work, it's used quite often even in other cases :)

Suggest an answer

Log in or Sign up to answer