It's all about the answers!

Ask a question

How Do I Modify a Work Item via Get/Post Without OSLC API?


Nate Decker (37812858) | asked Oct 15 '14, 10:30 a.m.

I would like to programmatically modify a work item in a way that is currently unsupported by the OSLC API. It has been suggested that one way of doing this would be to examine the http message traffic using the browser's debugging capabilities and then mimic that traffic to make a change to the work item as if I am a user interacting with a web browser.

I've looked at the web traffic and found the relevant command. However, if I try to send the command again, I get a "Save Conflict" error. The message is:

"Failed saving work item <id> because it did not have the most recent state. Refresh, make additional changes, then save again."

I'm wondering if updating the work item requires a two-part action. I note that when examining the network traffic, the POST messages are always preceded by a "hasWorkItemChanged?" GET request. The response to that request is a Boolean true or false. I'm wondering if it also provides some kind of cookie or header that is used in the subsequent POST. I know there is documentation for the OSLC API that stipulates that you need to set the IfMatch header to make sure you aren't stomping on someone else's changes, but I'm not seeing that header in the web traffic that I've been sniffing. There is a long character token called "LtpaToken2" which might include some kind of information about the state of the work item which may be getting validated, but I can't tell where this token is coming from so I can't mine it.

Has anyone tried to do something like this before? Any help would be appreciated.

4 answers



permanent link
Dominic Tulley (38114) | answered Oct 17 '14, 6:32 a.m.
Hi Nate,
what you're trying to do sounds like hard work (and is certainly unsupported).  Should you manage to get it to work it may well stop working after upgrading to a new version of the product.
If you are trying to make a valid change to a work item and it's just that the OSLC API doesn't support working with that aspect of the data then there are other supported mechanisms you might look at.

If you go to the RTC download pages on jazz.net you will see "Plain Java Client Libraries" and "Plain Java Client Libraries documentation" zip files available for download.  There's also the RTC SDK available for download there - it offers a different set of capabilities to the plain java client I believe (I'm not an expert although I have done a little work with them).

Comments
Nate Decker commented Oct 17 '14, 8:12 a.m.

While my preferred API is the OSLC interface, I've also used others including the Java API (both client and server-side). However, we've found that in our implementation the Java-based client applications won't authenticate via smart card while the OSLC-based applications will. This has effectively ruled out the Java-based applications for most of our automation solutions.


permanent link
Nate Decker (37812858) | answered Apr 20 '16, 10:15 a.m.
edited Apr 20 '16, 10:32 a.m.

I am revisiting this issue because I am still looking for a better solution than what I developed the last time I tackled this problem. Previously I had implemented a Java Client program that would create the timesheets, but this program would only authenticate on one of our networks (where we used username/password authentication instead of Smart Card).

In recent tests, I believe I have discovered the correct way to get a "False" response to the query "hasWorkItemChanged". The query to check if the work item has changed includes an ItemID (presumably the GUID of the work item), targetLinkItemIds (still unsure what these do), targetLinkTypes (which seems to be hardcoded to com.ibm.team.workitem.linktype.parentworkitem), and a stateId.

The stateId parameters seems to be the important one. It is a GUID that changes every time the work item is modified so this evidently is unrelated to the workflow states.

If you query the work item using the dynaCache, the server will respond with the work item's current stateId. You can then use that stateId in a subsequent "hasWorkItemChanged" query. The dynaCache query looks like this:

https://<server>:<port>/ccm/service/com.ibm.team.workitem.common.internal.rest.IWorkItemRestService/dynaCacheWorkItemStateId?id=<identifier>


Comments
Donald Nong commented Apr 21 '16, 12:53 a.m.

That's right. The state ID is necessary for dealing with multiple-user scenario and only the up-to-date copy of the work item can be updated.


permanent link
Nate Decker (37812858) | answered Apr 21 '16, 8:23 a.m.

I feel like I am on the cusp of success here, but I've hit a roadblock that may prove to be impassable. I was able to "Edit and Resend" the POST request in the Firefox debugger using the latest stateId and I could successfully add timesheet entries. However, it appears that Firefox is automatically including an LtpaToken2 hash in a cookie in that request. The LtpaToken seems to come from the server when you first authenticate and it appears to be necessary in order for the POST to be successful (removing it from the cookie causes the save to fail).

In my code, I have to set the "User-Agent" request header to "CustomInterface" (I think other values like "API" would probably work too) in order to authenticate. If I don't do this, I get a security message from the server saying something like I have tried to access a webpage directly, but must log in first. Unfortunately, when I have the User-Agent cookie set, the server doesn't issue me an LtpaToken when I authenticate. There is a "Set-Cookie" header in the response from the server, but the LtpaToken is ostensibly missing.

So I seem to be at an impasse. I can't save the timesheet without the LtpaToken and I can't get the token unless I authenticate without the User-Agent header, but I can't authenticate without that header.

Has anyone had success with something like this?


Comments
sam detweiler commented Apr 21 '16, 9:06 a.m.

Lie.. say you are Firefox.. the random user-agent string doesn't match anything the server knows about


Nate Decker commented Apr 21 '16, 9:13 a.m.

That's essentially what I am trying to do, but that's what I meant when I said I cannot authenticate if the User-Agent isn't set to my custom string. If I pretend to be Firefox, the server gives me the response,

"You have followed a direct link to log in to a Jazz server. This page has been presented to ensure that a malicious website cannot use cleverly crafted content to circumvent security. Please log in if you would like to access the server."

It's as if the server gives me permission to do API stuff as long as it knows that I am NOT a browser, but if I tell it that I AM a browser, then it takes issue with my authentication scheme for some reason. Clearly legitimate browsers are able to authenticate somehow so I must just need to change my authentication handshake somehow. I'm not sure what needs to be changed though.

Previously, my code would try to hit a page and then it would get a response from the server "net.jazz.web.app.authrequired". Now though, I get this new message instead of the authorization required message.


permanent link
sam detweiler (12.4k6180201) | answered Apr 21 '16, 9:22 a.m.
my understanding it is a two part process.

make a request which sends back the sessionid cookie
use the sessionid cookie on the authenticate request and all subsequent requests

my batch file

rem get the cookie
curl -k -c %cookies% "%host%/jts/authenticated/identity" >nul
use the cookie to logon
curl -k -L -b %COOKIES% -c %COOKIES% -d j_username=%USER% -d j_password=%PASSWORD% %host%/jts/authenticated/j_security_check >nul

Comments
Nate Decker commented Apr 21 '16, 10:34 a.m.

I notice in your example code that you aren't setting headers anywhere. I'm not familiar with the "curl" command. Is that abstracting the header stuff from you so you don't have to worry about it?

In my case, I had a method that authenticated successfully (as long as my User-Agent header was set). It's similar to what you describe as far as handshaking goes. As soon as I don't use that User-Agent header though, I get the aforementioned rejection from the server. The first request returns the Authentication Required response as expected, but then subsequently hitting that URL that you've cited "%host%/jts/authenticated/j_security_check" triggers the "You have followed a direct link to log in to a Jazz server."

I don't know how I'm supposed to log into the Jazz server if not by "following a direct link".

I'm starting to feel like dropping the User-Agent header is a dead end. Perhaps I should back up and see if I can get the server to accept my POST with my working login session. I just don't see how it's going to work without that LptaToken though...


sam detweiler commented Apr 21 '16, 10:38 a.m.

Sounds like you have lost the session cookie on the second request.

on curl, I would have to look at the doc to see what headers it sets by default.
but you can set additional headers.
curl --help for all that goo..

Your answer


Register or to post your answer.