Possible Admin Scope Bug for Issue Edit REST API

306 views
Skip to first unread message

Paul Clark

unread,
Jul 26, 2016, 12:42:05 AM7/26/16
to Atlassian Connect Dev
Hi

I'm trying to update an issue for a custom field that isn't in any screen using the URL: rest/api/2/issue/10100?overrideScreenSecurity=true

but I am getting the error: "Only Connect add-on users with admin scope permission are allowed to override screen security."

even though my atlassian-connect.json has: "scopes": ["READ", "WRITE", "PROJECT_ADMIN", "ADMIN"]

Is this a bug or am I missing something?

Thanks
Paul

Krzysztof Kercz

unread,
Jul 26, 2016, 2:47:32 AM7/26/16
to Atlassian Connect Dev
Hi Paul,

how are you sending the request? Is it done from your add-on's server, or from the front-end? The latter wouldn't work, since such a request would be done on behalf of a user, not your add-on. If it's the former, though, then it should be fine... 

You might also double check that your Connect add-on user has the administer permission granted in permission schemes (it should happen automatically, though).

Best regards
Krzysztof

Paul Clark

unread,
Jul 26, 2016, 3:40:49 AM7/26/16
to Atlassian Connect Dev
Hi Krzysztof

Yes I was doing it from the front end.  That explains it, I'll change it to occur on the server.

Thanks
Paul

Paul Clark

unread,
Jul 26, 2016, 6:01:29 AM7/26/16
to Atlassian Connect Dev
Hi Krzysztof

I have moved the code to Java now.  I create a JWT token using the add on key and shared secret and do the put operation to /rest/api/2/issue/10100?overrideScreenSecurity=true sending {"update":{"customfield_10105":[{"set":"2016-7-1"}]}}

Now I get the message: Encountered a "401 - Unauthorized" error while loading this page

The content-type and accept is application/json

Thanks
Paul


On Tuesday, July 26, 2016 at 6:47:32 PM UTC+12, Krzysztof Kercz wrote:

Krzysztof Kercz

unread,
Jul 26, 2016, 6:56:30 AM7/26/16
to Atlassian Connect Dev
Hi Paul,

That must mean your add-on is not authenticated correctly, i.e. that JIRA does not recognize the request as performed by your add-on, but rather by an anonymous user. Most likely it's not a problem with this particular endpoint. Please, refer to the documentation on using JWT:



Best regards
Krzysztof

Paul Clark

unread,
Jul 26, 2016, 10:38:08 PM7/26/16
to Atlassian Connect Dev
Hi

I have looked through the documentation you provided, tried a few things but have still not been able to get it working.  If have coded a standalone example (which I can email) from the second link you provided and it doesn't work (same problem).  I have included the code (minus secret) below (I can also email a zip file of the project).

This returns a web page with a 401 error.

Thanks
Paul

public class TestJwt {

    public static void main(String[] args) throws MalformedURLException, ProtocolException, UnsupportedEncodingException, NoSuchAlgorithmException, IOException {
        new TestJwt().sendPut(createUriWithJwt(), "{\"update\":{\"customfield_10116\":[{\"set\":\"2016-7-1\"}]}}", "PUT");
   
}

    private static final String USER_AGENT = "Mozilla/5.0";

   
public static String createUriWithJwt()
           
throws UnsupportedEncodingException, NoSuchAlgorithmException {
       
long issuedAt = System.currentTimeMillis() / 1000L;
       
long expiresAt = issuedAt + 180L;
       
String key = "com.redmoon.customfields.jira"; //the key from the add-on descriptor
       
String sharedSecret = "*******************************************************************************";    //the sharedsecret key received
                                       
//during the add-on installation handshake
       
String method = "PUT";
       
String baseUrl = "https://redmoondev.atlassian.net/";
       
String contextPath = "/";
       
String apiPath = "/rest/api/2/issue/TEST-1";

       
JwtJsonBuilder jwtBuilder = new JsonSmartJwtJsonBuilder()
               
.issuedAt(issuedAt)
               
.expirationTime(expiresAt)
               
.issuer(key);

       
CanonicalHttpUriRequest canonical = new CanonicalHttpUriRequest(method, apiPath, contextPath, new HashMap());
       
JwtClaimsBuilder.appendHttpRequestClaims(jwtBuilder, canonical);

       
JwtWriterFactory jwtWriterFactory = new NimbusJwtWriterFactory();
       
String jwtbuilt = jwtBuilder.build();
       
String jwtToken = jwtWriterFactory.macSigningWriter(SigningAlgorithm.HS256, sharedSecret).jsonToJwt(jwtbuilt);

       
String apiUrl = baseUrl + apiPath + "?jwt=" + jwtToken+"&overrideScreenSecurity=true";
       
return apiUrl;
   
}

   
public String sendPut(String url, String data, String sendType) throws MalformedURLException, IOException, ProtocolException {
        boolean success = false;
        URL obj
= new URL(url);
       
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
        con
.setConnectTimeout(120000);

        //add request header
        con
.setRequestMethod(sendType);
        con
.setRequestProperty("User-Agent", USER_AGENT);
        con
.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
        con
.setRequestProperty("Content-Type", "application/json");

        // Send post request
        con
.setDoOutput(true);
        OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream());
        wr
.write(data);
        wr
.flush();
        wr
.close();
        con
.connect();

       
int responseCode = con.getResponseCode();
        success
= responseCode >= 200 && responseCode <= 204;

       
BufferedReader in;
       
if(success){
           
in = new BufferedReader(new InputStreamReader(con.getInputStream()));
        } else {
            in = new BufferedReader(new InputStreamReader(con.getErrorStream()));
       
}
       
String inputLine;
        StringBuffer response = new StringBuffer();

        while ((inputLine = in.readLine()) != null) {
            response
.append(inputLine);
        }
        in.close();
        System.out.println("URL: "+url);
        System.out.println("Success: "+success);
        System.out.println("Response: "+response.toString());
        String responseMessage = response.toString();
        return responseMessage;
   
}
}

Seb Ruiz

unread,
Jul 27, 2016, 9:08:55 PM7/27/16
to atlassian-...@googlegroups.com
Paul,

You are adding the overrideScreenSecurity=true query param after constructing the JWT token. This won't work as the JWT token needs all the query params to calculate the signature.

Seb

--
You received this message because you are subscribed to the Google Groups "Atlassian Connect Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to atlassian-connec...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Seb Ruiz
Atlassian

Paul Clark

unread,
Jul 27, 2016, 10:19:26 PM7/27/16
to Atlassian Connect Dev
Hi Seb

If I change the apiPath to be: String apiPath = "/rest/api/2/issue/TEST-1?overrideScreenSecurity=true";

and the apiUrl to: String apiUrl = baseUrl + apiPath + "&jwt=" + jwtToken;

then I still get the 401.  

I tried removing the "overrideScreenSecurity=true" completely and I then get the message "Field 'customfield_10116' cannot be set. It is not on the appropriate screen, or unknown.".  So the authorisation problem only seems to be when using "overrideScreenSecurity=true".  

I do have the scopes "scopes": ["READ", "WRITE", "PROJECT_ADMIN", "ADMIN"] and the REST api says to use the admin scope.  Can some please check to see if the scope for this REST api is correct?

Thanks
Paul

To unsubscribe from this group and stop receiving emails from it, send an email to atlassian-connect-dev+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Seb Ruiz
Atlassian

Krzysztof Kercz

unread,
Jul 28, 2016, 3:06:44 AM7/28/16
to Atlassian Connect Dev
Hi Paul,

I think you might be using your JwtBuilder wrong in regard to query paramters. I've found an example that puts paramters into the map that is used to construct CanonicalHttpUriRequest. Currently you are passing an empty HashMap there. Try it like this (and, of course, also restore your "apiUrl" to the previous form):

Map<String, String[]> parameters = new HashMap<>();
paramters.put("overrideScreenSecurity", new String[] {true});

CanonicalHttpUriRequest canonical = new CanonicalHttpUriRequest(method, apiPath, contextPath, parameters);



Hope that helps
Krzysztof

Paul Clark

unread,
Jul 28, 2016, 5:41:46 AM7/28/16
to Atlassian Connect Dev
Hi Krzysztof

Thanks very much for that, it now works.  I used the empty HashMap because that was what the example used and I didn't know what it was for.  Is it possible (to help out others who may have the same problem) to get the example updated to use a parameter HashMap so they will know what it is for.  i.e.

        Map<String, String[]> parameters = new HashMap();
        // parameters.put("overrideScreenSecurity", new String[] {"true"});
        
        CanonicalHttpUriRequest canonical = new CanonicalHttpUriRequest(method, apiPath, contextPath, parameters);

Thanks again for your help (and Seb)

Now I can finish my changes :)

Paul

Paul Clark

unread,
Jul 28, 2016, 4:15:22 PM7/28/16
to Atlassian Connect Dev
In case anyone is interested in the final version of my test code the createUriWithJwt is now:

    public static String createUriWithJwt()
           
throws UnsupportedEncodingException, NoSuchAlgorithmException {
       
long issuedAt = System.currentTimeMillis() / 1000L;
       
long expiresAt = issuedAt + 180L;
       
String key = "com.redmoon.customfields.jira"; //the key from the add-on descriptor

       
String sharedSecret = "**************************************************************************************";    //the sharedsecret key received

                                       
//during the add-on installation handshake
       
String method = "PUT";
       
String baseUrl = "https://redmoondev.atlassian.net/";
       
String contextPath = "/";
       
String apiPath = "/rest/api/2/issue/TEST-1";


       
JwtJsonBuilder jwtBuilder = new JsonSmartJwtJsonBuilder()
               
.issuedAt(issuedAt)
               
.expirationTime(expiresAt)
               
.issuer(key);



       
Map<String, String[]> parameters = new HashMap();

        parameters
.put("overrideScreenSecurity", new String[] {"true"});

       
       
CanonicalHttpUriRequest canonical = new CanonicalHttpUriRequest(method, apiPath, contextPath, parameters);
Reply all
Reply to author
Forward
0 new messages