Eclipse or SUNrise...

Eclipse or SUNrise...
...JAVA for sure

Monday, March 28, 2011

Integrating with Rational Team Concert

In this post I'll show you an example of automation of tasks with Rational Team Concert using Java. Couple of days ago I was asked to "somehow" automate a process of generating and publishing a bunch of reports to RTC. The process contained couple of steps - first a cron job which fired a PL/SQL procedure which generated a proper report, then it had to be processed, zipped and uploaded to an existing RTC custom item called report (similar to a task).

So lets focus on the interesting part - integration with RTC. Because RTC gives an JAZZ API I decided to upload the files using a simple, JAVA SE application. Unfortunately as I found out on the JAZZ official pages there was very little information about the API. Yes, there were couple of examples, but no real documentation or at least a proper Javadoc... I found some helpful info on the Internet but again, it still is not a rich source of documentation for this.

Oh, and to gain access to this so called documentation you have to register on JAZZ pages. Although you won't find a complete and proper documentation there, you will have an access to a few handy examples and a forum. At the end of this article, you can see a list of useful links.

To run the application, you'll need the client libraries to be able to connect to the RTC. I downloaded a JazzPlainJavaClient-2.0 package. It is more then 20MB of jars, but you don't require all of them to create your application. You can download it here. Look for 'Plain Java Client Libraries'. There is a lot more to download, but if you plan to develop something small don't really bother with anything else.

Now when you have your copy of libraries wire them to your project and you can run my code.

The following code is just a main body, which initialize the libraries and executes the real logic of the program - the run() function passing it all the attributes. You will find a very similar code on the examples on jazz pages.


public static void main(String[] args) {

boolean result;
TeamPlatform.startup();
try {
result = run(args);
} catch (TeamRepositoryException x) {
x.printStackTrace();
result = false;
} finally {
TeamPlatform.shutdown();
}

if (!result)
System.exit(1);

}


The run() function simply parse the arguments - there should be 6 of them and one of them should be integer. Of course you can improve the parsing, my is just as good as it have to be. Then, if they are are ok, the program authenticates provided user in the RTC repository (so be sure you gave a proper user with a valid password).

Then it looks for a project area to connect to (it will be needed to upload the attachment, note also that your user must have access there). If the program will find it, it searches for a given item (for which it will upload the report).

Now the interesting part - using WorkItemWorkingCopy object to get the item data - the one that we really want is the the item reference, which we pass later to upload the attachment (itemCopy.getReferences()). Generally we can use it also to update the task itself - for example to add additional comment or change the priority.

Now we invoke the addAttachment() function passing it the stream to a file that we want to upload, its name visible in RTC, RTC item reference to which we will attach the file, the client binding that we will use to persist the attachment and finally the RTC project area.


private static boolean run(String[] args) throws TeamRepositoryException {

if (args.length != 6) {
System.out
.println("Usage: UpdateWorkItem ");
return false;
}

int rtcDocumentId = -1; // 6666

if (args[0] != null && args[0].length() > 0) {

try {
rtcDocumentId = Integer.valueOf(args[0]);
} catch (NumberFormatException nfe) {
System.out.println("The workitem id have to be a valid number");
return false;
}
}

SimpleDateFormat dateFormat = new SimpleDateFormat("M/dd/yyyy hh:mm");
System.out.println("Starting program at " + dateFormat.format(new Date(System.currentTimeMillis())));

final String repositoryURI = args[1];
final String userId = args[2];
final String password = args[3];
final String projectAreaName = args[4];
final String fileName = args[5];

// loging in to the RTC
ITeamRepository teamRepository = TeamPlatform.getTeamRepositoryService().getTeamRepository(repositoryURI);
teamRepository.registerLoginHandler(new LoginHandler(userId, password));
teamRepository.login(null);

URI uri = URI.create(projectAreaName.replaceAll(" ", "%20"));
IProcessClientService processClient = (IProcessClientService) teamRepository
.getClientLibrary(IProcessClientService.class);
IProjectArea projectArea = (IProjectArea) processClient.findProcessArea(uri, null, null);
if (projectArea == null) {
System.out.println("Project area not found, check if you gave the right name");
return false;
}

System.out.println("Querying workitems with id " + rtcDocumentId);

IWorkItemClient workItemClient = (IWorkItemClient) teamRepository.getClientLibrary(IWorkItemClient.class);
IWorkItemWorkingCopyManager copyManager = workItemClient.getWorkItemWorkingCopyManager();
IWorkItemHandle handle = workItemClient.findWorkItemById(rtcDocumentId, IWorkItem.FULL_PROFILE, null);
try {
copyManager.connect(handle, IWorkItem.FULL_PROFILE, null);
WorkItemWorkingCopy itemCopy = copyManager.getWorkingCopy(handle);
IWorkItem item = itemCopy.getWorkItem();

System.out.println("Found work item: " + item.getHTMLSummary());
System.out.println("Adding new attachment...");

InputStream fileInputStream = null;
try {
if (fileName != null)
fileInputStream = new FileInputStream(fileName);

InputStream inputStream = fileInputStream != null ? fileInputStream : System.in;

addAttachment(inputStream, fileName, itemCopy.getReferences(), workItemClient, projectArea);

} catch (FileNotFoundException e) {
System.out.println("###\n Error accured, file " + fileName + " not found\n###");
return false;
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
System.out.println("Couldn't close the fileInputStream, probably you can skip this error :-) ");
}
}
}

System.out.println("Commiting the new attachment to RTC workitem..");
itemCopy.save(null);
System.out.println("Attachement added succesfully!");

} finally {
copyManager.disconnect(handle);
}

System.out.println("Disconnecting from RTC...");
teamRepository.logout();
System.out.println("Disconnected! Finishing the program. Thanks for using!");

return true;
}


Finally the addAttachment function - it simply creates a new attachment and saves it. Notice that I used a text "UTF-8" as the coding for this file. Unfortunately, I haven't found much about this interface and with other parameter values it didn't worked - so I left it with UTF-8, maybe it isn't the best option, but it works pretty well. Again, more documentation would be nice...


private static void addAttachment(InputStream inputStream, String fileName, IWorkItemReferences workItemReferences,
IWorkItemClient workItemClient, IProjectArea projectArea) throws TeamRepositoryException {
try {

IAttachment newAttachment = workItemClient.createAttachment(projectArea, fileName, "", "text", "UTF-8",
inputStream, null);

newAttachment = (IAttachment) newAttachment.getWorkingCopy();
newAttachment = workItemClient.saveAttachment(newAttachment, null);
IItemReference reference = WorkItemLinkTypes.createAttachmentReference(newAttachment);
workItemReferences.add(WorkItemEndPoints.ATTACHMENT, reference);

} catch (Exception e) {
System.out.println("Exception while adding attachement: " + e.getMessage());
throw new TeamRepositoryException(e);
}
}


Now the last thing to do is to run the program - remember to pass it a proper set of arguments and link it with the client libraries. You can use the following command to run it:


java -Djava.ext.dirs="/usr/lib/JazzPlainJavaClient-2.0:/usr/jre1.6.0_24/lib/ext" -jar UpdateWorkItem.jar 6666 https://10.10.10.10:9443/jazz account@account.com password "MyProject" "/home/xxx/report_2011_03_20.zip" >> sendReportToRTC.log


And that's just enough to start playing with RTC. I just regret that they won't supply more documentation...

Here couple of handy links that I used:

https://jazz.net/wiki/bin/view/Main/QueryDevGuide
https://jazz.net/wiki/bin/view/Main/ProgrammaticWorkItemCreation
https://jazz.net/wiki/bin/view/Main/WorkItemExampleSource

Tuesday, March 8, 2011

Hacking WebSphere Application Server console

I guess everyone had a situation where he or she forgot his or her password and had to renew it or ask someone to do it for him. This comes more complex where you as an administrator of your server forgets the password or maybe you have to work with a server that you don't know credentials for.

When it comes for WAS, there is a way to change the administrative user account password even if you can't get in the console in the first place! You can do it if you have access to the operating system where the WAS resides and have at least permissions for the user which runs the WAS (so it needn't be a root).

When you log in as that user go to the WAS install directory, then to the profile config subdirectory and find the cells subdirectory. Let's assume we installed WAS here:

/ibm/WebSphere/AppServer/profiles/WPSprofile01/config/cells/XXX_Cell/


In there you will find a nice
security.xml
file. Edit it. The first lines are:


<?xml version="1.0" encoding="UTF-8"?>
<security:Security xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:or
b.securityprotocol="http://www.ibm.com/websphere/appserver/schemas/5.0/orb.secur
ityprotocol.xmi" xmlns:security="http://www.ibm.com/websphere/appserver/schemas/
5.0/security.xmi" xmi:id="Security_1" useLocalSecurityServer="true" useDomainQua
lifiedUserNames="false" enabled="true" cacheTimeout="598200" issuePermissionWarn
ing="true" activeProtocol="BOTH" enforceJava2Security="false" enforceFineGrained
JCASecurity="false" appEnabled="true" dynamicallyUpdateSSLConfig="true" activeAu
thMechanism="LTPA_1" activeUserRegistry="WIMUserRegistry_1" defaultSSLSettings="
SSLConfig_1">


Now, notice the attribute enabled="true". This property says that administrative security is enabled for the console. So if you change the value to false - you disable it.

Easy? Not really - in order to use the new settings the server has to be restarted and WAS will require a password for that to make it happen. So unless you don't have a valid password you will not be able to log in. Fortunately you can deal with it by using kill command for the WAS process. Just find the process using ps and grepping the WAS profile name.

Now, start the server and log in using the standard url without https (the standard URL is http://washost:9060/ibm/console), just click ok button, you don't have to specify the user and you will see the console.

So you hacked it! Now let's change the password and enable the security. We won't do it with a file, just go to the security tab. Now it depends of your security realm settings of how you can change the password. I'll write more about security and managing users on WAS in another post - basically you can do pretty much in here.

In the end don't forget to switch the security on and restart the server again. This scenario is easy for a standalone server, it gets more complicated with clustered, network managed environments but it also works with them. It just requires additional node synchronizing and a correct order of your operations to be effective.

Friday, March 4, 2011

JDK security alert for CVE-2010-4476

Lately IBM have announced a fix for its JDK virtual machine bug which might lead to a DoS (Denial of Service) attack. It is an important security issue. You can read about it here. WAS versions 6, 6.1 and 7.0 are affected so the bug stayed in Java up from version 1.4... quite some time, nice :-).

This is a result from a similar info from Sun... oh, Oralce that is. And you can read it here. IBM JDK is modified Oracle's one.

But what made me wonder was the reason that cosed that behavior. I quote:

This Security Alert addresses security issue CVE-2010-4476 (Java Runtime Environment hangs when converting "2.2250738585072012e-308" to a binary floating-point number), which is a vulnerability in the Java Runtime Environment component of the Oracle Java SE and Java for Business products. This vulnerability allows unauthenticated network attacks ( i.e. it may be exploited over a network without the need for a username and password). Successful attack of this vulnerability can result in unauthorized ability to cause a hang or frequently repeatable crash (complete Denial of Service) of the Java Runtime Environment. Java based application and web servers are especially at risk from this vulnerability.


Digging in the problem, that means that an instruction like this:

Double thisWillHurt = Double.parseDouble("2.2250738585072012e-308")


Will crash the app server... nice. I'm just curious how do they come up with this particular COMPLEX in fact number. I wonder if there is any other magical number...

Anyway, I advise to install the new fixpack (if possible) on your environments, or at least only an APAR for this:

WAS v7.0
WAS v6.1
WAS v6.0