How to remove an attachment from Jira 4.4 using Http - jira

I have been looking for a way to remove an attachment from Jira using the SOAP Api, but it seems that this is not possible natively, and I would prefer not having to implement a new plugin for Jira, as suggested in the accepted answer to this question, or recompiling the existing plugin to support this as mentioned here.
This answer to the abovementioned question seems to do exactly what I want, but alas, I can't get i to work. The response i get is an error stating that:
XSRF Security Token Missing
JIRA could not complete this action due to a missing form token.
You may have cleared your browser cookies, which could have resulted in the expiry of your current form token. A new form token has been reissued.
As I am using Asp.Net MVC C#, I have used the code from the answer, as is, with only the server url adjusted, as well as with different credentials (a Jira user) and the username/password passed through as request parameters using:
os_username=jirausername&os_password=xxxxxxx
The code I am currently using is as follows:
public void RemoveAttachment(string issueid, string attachmentid)
{
using (System.Net.WebClient client = new System.Net.WebClient())
{
//Compute jira server base url from WS url
string baseUrl = _service.Url.Substring(0, _service.Url.IndexOf("/rpc/"));
//Compute complete attachment url
string attachmenturl = baseUrl + "/secure/DeleteAttachment.jspa?id=" +
issueid + "&deleteAttachmentId=" + attachmentid;
client.Credentials = new System.Net.NetworkCredential("jirausername", "xxxxxxx");
string response = client.DownloadString(attachmenturl);
}
}

I ended up using a method that first requests the deletion confirmation form, then extracts a required token from the form, and finally posts something equivalent to the form content in order to delete the attachment. Code below.
public void RemoveAttachment(string issueid, string attachmentid)
{
//Compute jira server base url from WS url
string baseUrl = _service.Url.Substring(0, _service.Url.IndexOf("/rpc/"));
//Compute complete attachment deletion confirm url
string confirmurl = baseUrl + "/secure/DeleteAttachment!default.jspa?id=" +
issueid + "&deleteAttachmentId=" + attachmentid + "&os_username=jirauser&os_password=xxxxxx";
//Create a cookie container to maintain the xsrf security token cookie.
CookieContainer jiracontainer = new CookieContainer();
//Create a get request for the page containing the delete confirmation.
HttpWebRequest confirmrequest = (HttpWebRequest)WebRequest.Create(confirmurl);
confirmrequest.Credentials = System.Net.CredentialCache.DefaultCredentials;
confirmrequest.CookieContainer = jiracontainer;
//Get the response and the responsestream.
WebResponse confirmdeleteresponse = confirmrequest.GetResponse();
Stream ReceiveStream = confirmdeleteresponse.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader confirmreader = new StreamReader(ReceiveStream);
// Read the content.
string confirmresponse = confirmreader.ReadToEnd();
//Create a regex to extract the atl/xsrf token from a hidden field. (Might be nicer to read it from a cookie, which should also be possible).
Regex atl_token_matcher = new Regex("<input[^>]*id=\"atl_token\"[^>]*value=\"(?<token>\\S+)\"[^>]*>", RegexOptions.Singleline);
Match token_match = atl_token_matcher.Match(confirmresponse);
if (token_match.Success)
{
//If we found the token get the value.
string token = token_match.Groups["token"].Value;
//Compute attachment delete url.
string deleteurl = baseUrl + "/secure/DeleteAttachment.jspa";
//Construct form data.
string postdata = "atl_token=" + HttpContext.Current.Server.UrlEncode(token) + "&id=" + issueid + "&deleteAttachmentId=" + attachmentid + "&Delete=Delete&os_username=jirauser&os_password=xxxxxx";
//Create a post request for the deletion page.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(deleteurl);
request.KeepAlive = false;
request.CookieContainer = jiracontainer; // Remember to set the cookiecontainer.
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
//Turn our request string into a byte stream
byte[] postBytes = Encoding.ASCII.GetBytes(postdata);
//Make sure you specify the proper type.
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
Stream requestStream = request.GetRequestStream();
//Send the post.
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
//Get the response.
WebResponse deleteresponse = request.GetResponse();
// Open the responsestream using a StreamReader for easy access.
StreamReader deleteresponsereader = new StreamReader(deleteresponse.GetResponseStream());
// Read the content.
string deleteresponsecontent = deleteresponsereader.ReadToEnd();
// do whatever validation/reporting with the response...
}
else
{
//We couldn't find the atl_token. Throw an error or something...
}
}
Edit:
Same thing works for removing comments. Replace 'attachment' with 'comment' and 'deleteAttachmentId' with 'commentId' and you should be good to go.

Related

Is there any way to bulk delete all permissions of a file using the IGraphServiceClient?

As part of a user action, we are using the MS Graph Java SDK to first list all permissions of a file, then iterating over the list of permissions to delete each one individually. This seems to have some performance issues. We were wondering if there is any way to batch the calls using the IGraphServiceClient.
Relevant APIs used:
https://learn.microsoft.com/en-us/graph/api/driveitem-list-permissions?view=graph-rest-1.0&tabs=http
https://learn.microsoft.com/en-us/graph/api/permission-delete?view=graph-rest-1.0&tabs=http
You can make batch requests.
1. Create MSBatch Request Steps (examples below)
Request requestGetMe = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/").build();
List<String> arrayOfDependsOnIdsGetMe = null;
MSBatchRequestStep stepGetMe = new MSBatchRequestStep("1", requestGetMe, arrayOfDependsOnIdsGetMe);
Request requestGetMePlannerTasks = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/planner/tasks").build();
List<String> arrayOfDependsOnIdsGetMePlannerTasks = Arrays.asList("1");
MSBatchRequestStep stepMePlannerTasks = new MSBatchRequestStep("2", requestGetMePlannerTasks, arrayOfDependsOnIdsGetMePlannerTasks);
String body = "{" +
"\"displayName\": \"My Notebook\"" +
"}";
RequestBody postBody = RequestBody.create(MediaType.parse("application/json"), body);
Request requestCreateNotebook = new Request
.Builder()
.addHeader("Content-Type", "application/json")
.url("https://graph.microsoft.com/v1.0/me/onenote/notebooks")
.post(postBody)
.build();
MSBatchRequestStep stepCreateNotebook = new MSBatchRequestStep("3", requestCreateNotebook, Arrays.asList("2"));
2. Create MSBatch Request Content and get content
List<MSBatchRequestStep> steps = Arrays.asList(stepGetMe, stepMePlannerTasks, stepCreateNotebook);
MSBatchRequestContent requestContent = new MSBatchRequestContent(steps);
String content = requestContent.getBatchRequestContent();
3. Make call to $batch endpoint
OkHttpClient client = HttpClients.createDefault(auth);
Request batchRequest = new Request
.Builder()
.url("https://graph.microsoft.com/v1.0/$batch")
.post(RequestBody.create(MediaType.parse("application/json"), content))
.build();
Response batchResponse = client.newCall(batchRequest).execute();
4. Create MSBatch Response Content
MSBatchResponseContent responseContent = new MSBatchResponseContent(batchResponse);
Response responseGetMe = responseContent.getResponseById("1");
// Use the response of each request

OAuth 1.0 A Invalid Signature when requesting request token (SalesForce/JIRA Integration)

I've been trying my darndest to avoid asking a question. I'm recieving an invalid signature error when trying to request a request token from JIRA from within Salesforce. The response I'm getting is:
08:15:24:201 USER_DEBUG [30]|DEBUG|
oauth_problem=signature_invalid
&oauth_signature=RaOPaBPznmS7aDUuJN1pOclcyHWP4uRYYx4j%2F%2BdtKB1SD4l1JcCCys3P3RAa8P7377MwLsIMBtkHfL62jaXr5LV30RndjVUSlCsVl3h47CvinHgDtTMwWGukQJXhOmSsLPvccCqD7qsRmiQnnjSJCwd9YKJEi2cxNcwMqhnceqAwJdzn3RD%2FBBeNpf3G97wqWhJx%2FtyEhQGk35OTu00fhtw%2BIX025STN3iiGNbyANlmoImAGWqAJeqJOPUVva7TR2OAInysL9%2BHmYkQTOcb7a9sn5rRWUqE4Jua6EoVyPgzJnSgZ4pFEIMzU0eTWQqhSFdQwOdnoq5EQU8W%2BPJM8uA%3D%3D
&oauth_signature_base_string=POST%26https%253A%252F%252F.atlassian.net%252Fplugins%252Fservlet%252Foauth%252Frequest-token%26oauth_consumer_key%253D3MVG9KI2HHAq33RwCPH5bNzAHbOgfiicjJ6HjvVfNhGU8aWXGl6ps.vsEzobCPqRXuDcmeV2Baw%25253D%25253D%2526oauth_nonce%253D-6826921263934288296%2526oauth_signature_method%253DRSA-SHA1%2526oauth_timestamp%253D1492182924
&oauth_signature_method=RSA-SHA1
The code I'm using to try to generate the signature is:
// GitHub OAuth Playground: https://github.com/jesperfj/sfdc-oauth-playground/blob/master/OAuth/src/classes/OAuth.cls
// OAuth Bible: http://oauthbible.com/
// Static Values
String consumerKey = '3MVG9KI2HHAq33RwCPH5bNzAHbOgfiicjJ6HjvVfNhGU8aWXGl6ps.vsEzobCPqRXuDcmeV2Baw==';
String endpoint = 'https://<AtlassianSiteName>.atlassian.net/plugins/servlet/oauth/request-token';
// Params
String callbackParam = '&oauth_callback=' + EncodingUtil.urlEncode('https://localhost/', 'UTF-8');
String consumerKeyParam = '&oauth_consumer_key=' + EncodingUtil.urlEncode(consumerKey, 'UTF-8');
String signatureMethodParam = '&oauth_signature_method=RSA-SHA1';
String timestampParam = '&oauth_timestamp=' + String.valueOf(DateTime.now().getTime()/1000);
String nonceParam = '&oauth_nonce=' + String.valueOf(crypto.getRandomLong());
String versionParam = '&oauth_version=1.0';
String paramString = consumerKeyParam + nonceParam + signatureMethodParam + timestampParam + versionParam + callbackParam;
// Get baseString
String baseString = 'POST&' + encodingUtil.urlEncode(endpoint, 'UTF-8') + paramString;
system.debug(baseString);
blob sig = crypto.signWithCertificate('RSA-SHA1', blob.ValueOf(baseString), 'SelfSignedCert_26Oct2015_184625');
String signature = EncodingUtil.urlEncode(EncodingUtil.base64encode(sig), 'UTF-8');
httpRequest req = new httprequest();
http http = new http();
req.setEndPoint(endpoint);
req.setMethod('GET');
req.setBody(paramString +
'&oauth_signature=' + signature);
httpresponse res = http.send(req);
system.debug(res.getBody());
Note: Yes I understand that I probably shouldn't be sharing some of this information but these are my personal test orgs that contain nothing important and I'm not providing the SSL used. You'll notice some comments at the top of my code containing a few urls to my favorite resources that have gotten me this far. These are not the only resources I've used, just the most useful ones.

JIRA rest api to fetch the activity stream

I am trying to get activity stream of my jira instance using the below api and it is not working , can anybody point me in the right direction ?
You should check this page out: https://developer.atlassian.com/docs/atlassian-platform-common-components/activity-streams/consuming-an-activity-streams-feed
The Atom feed of the activity stream works well only if you also log in in your feed reader.
Here is an example of consuming the activity stream through the Jira API using Basic Authentication. This is in C#, but the basic pattern can be applied anywhere:
string myJiraUsername = "username";
string myJiraPassword = "password"; //or API token
string authenticationHeaderValue = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(myJiraUsername + ":" + myJiraPassword));
System.Net.Http.HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authenticationHeaderValue);
Task<HttpResponseMessage> task = client.GetAsync("https://mycompany.atlassian.net/activity");
task.Wait();
HttpResponseMessage response = task.Result;
string resultOfApiCall = "";
if (response.IsSuccessStatusCode)
{
resultOfApiCall = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("This was returned by your API request:\n" + resultOfApiCall);
}

How can I either fetch a CSRF token or send POST data through webbrowser

So what I'm trying to do is to login to a website, and then make a POST request. I've tried just making a webbrowser, and simply logging in there, then submitting the POST data with a button. I'm not sure if it isn't working this way because it's not being sent through webbrowser1 or because I'm not submitting the POST data correctly. Here was the code to submit the POST data.
HttpWebRequest req = (HttpWebRequest)
WebRequest.Create("url");
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
string postData = "postdata";
req.ContentLength = postData.Length;
StreamWriter stOut = new
StreamWriter(req.GetRequestStream(),
System.Text.Encoding.ASCII);
stOut.Write(postData);
stOut.Close();
I also tried just logging in with one button, then with another button, submitting this POST data, but the problem is that it needs the CSRF token inside the POST request. Here is what I had so far.
string formUrl = "loginurl";
string formParams = string.Format("username={0}&password={1}&csrfmiddlewaretoken={2}", "user", "pass", "token");
string cookieHeader;
WebRequest req = WebRequest.Create(formUrl);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(formParams);
req.ContentLength = bytes.Length;
using (Stream os = req.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
WebResponse resp = req.GetResponse();
cookieHeader = resp.Headers["Set-cookie"];
What would be the best way of doing this? Thank you!
You can try binding to the "ajax:before" event in jquery to transparently add in a parameter for the CSRF token before sending off. How you would add the CSRF token in is dependent on what web framework you're using.

How to multipart post form data to LinkedIn using OAuth 1 and DotNetOpenAuth?

I'm using the DotNetOpenAuth framework which has been great to get up to speed with consuming data.
I'm using it to talk to LinkedIn and am having trouble figuring out the correct approach to posting/sharing information to the site. Here is the reference I am using - http://developer.linkedin.com/documents/share-api
When I execute the below code I always get the below error responses;
Error occurred while sending a direct message or getting the response.
The remote server returned an error: (400) Bad Request.
I am using Oauth v1.0a.
Here is my code;
try
{
HttpDeliveryMethods resourceHttpMethod = HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest;
string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><share><comment>83% of employers will use social media to hire: 78% LinkedIn, 55% Facebook, 45% Twitter [SF Biz Times] http://bit.ly/cCpeOD</comment>";
xml += "<content><title>Survey: Social networks top hiring tool - San Francisco Business Times</title>";
xml += "<submitted-url>http://sanfrancisco.bizjournals.com/sanfrancisco/stories/2010/06/28/daily34.html</submitted-url>";
xml += "<submitted-image-url>http://images.bizjournals.com/travel/cityscapes/thumbs/sm_sanfrancisco.jpg</submitted-image-url>";
xml += "</content><visibility><code>anyone</code></visibility></share>";
var multiparts = new List<MultipartPostPart>();
MultipartPostPart part = MultipartPostPart.CreateFormPart("body", xml);
part.PartHeaders[HttpRequestHeader.ContentType] = "application/xml";
multiparts.Add(part);
var resourceEndpoint = new MessageReceivingEndpoint("http://api.linkedin.com/v1/people/~/shares", resourceHttpMethod);
HttpWebRequest request = consumer.PrepareAuthorizedRequest(resourceEndpoint, accessToken, multiparts);
request.ServicePoint.Expect100Continue = false;
IncomingWebResponse response = consumer.Channel.WebRequestHandler.GetResponse(request);
this.resultsBox.Text = response.GetResponseReader().ReadToEnd();
}
catch (Exception ex)
{
}
Thanks
Forgot to write back on this, talking to someone from a vintage google newsgroup I got the direction I needed but wanted to verify the solution before posting.
The big thing I was screwing up on was adding the multipart data prior to sending the request data as opposed to constructing the request myself and writing the new content to the stream.
I'm new to using OAuth and REST so I don't know all the ins and outs, suffice to say I've validated this code against both the LinkedIn and Twitter REST APIs.
Here is the new CODE;
try
{
Encoding encoder = Encoding.ASCII;
HttpDeliveryMethods resourceHttpMethod = HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest;
byte[] bytes = encoder.GetBytes(xd.OuterXml.ToString());
var resourceEndpoint = new MessageReceivingEndpoint(ResourceURL, resourceHttpMethod);
HttpWebRequest request = _consumer.PrepareAuthorizedRequest(resourceEndpoint, _manager.AccessToken);
request.ServicePoint.Expect100Continue = false;
request.Method = "POST";
request.ContentLength = bytes.Length;
request.ContentType = "application/xml";
using (System.IO.Stream requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
}
IncomingWebResponse response = _consumer.Channel.WebRequestHandler.GetResponse(request);
ret = true;
}
catch (Exception ex)
{
_Logger.Error(OpenLogger.FormatException(ex));
}

Resources