IDEA-69549: IntelliJ Tasks Sends Plain Text User Credentials In JIRA Request URL

This commit is contained in:
Dmitry Avdeev
2011-05-19 12:51:50 +04:00
parent 34deaca95a
commit 8cc552cc57
2 changed files with 40 additions and 109 deletions
@@ -2,7 +2,6 @@ package com.intellij.tasks.jira;
import com.atlassian.theplugin.jira.api.JIRAIssueBean;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.tasks.Task;
import com.intellij.tasks.TaskRepository;
import com.intellij.tasks.TaskState;
@@ -11,13 +10,9 @@ import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.annotations.Tag;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.xmlrpc.XmlRpcClient;
import org.apache.xmlrpc.XmlRpcClientException;
import org.apache.xmlrpc.XmlRpcTransport;
import org.apache.xmlrpc.XmlRpcTransportFactory;
import org.apache.commons.httpclient.methods.PostMethod;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
@@ -25,20 +20,17 @@ import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import java.util.List;
/**
* @author Dmitry Avdeev
*/
@Tag("JIRA")
public class JiraRepository extends BaseRepositoryImpl implements XmlRpcTransportFactory {
public class JiraRepository extends BaseRepositoryImpl {
private final static Logger LOG = Logger.getInstance("#com.intellij.tasks.jira.JiraRepository");
private String myServerVersion;
private static final String JIRA1 = "jira1.";
private static final String XMLRPC_PATH = "/rpc/xmlrpc";
private boolean myJira4 = true;
/**
* for serialization
@@ -58,13 +50,7 @@ public class JiraRepository extends BaseRepositoryImpl implements XmlRpcTranspor
public Task[] getIssues(String request, int max, long since) throws Exception {
StringBuilder url = new StringBuilder(getUrl());
String version = getServerVersion();
if (version == null || StringUtil.compareVersionNumbers(myServerVersion, "3.7") < 0) {
url.append("/secure/IssueNavigator.jspa?view=rss&decorator=none&");
}
else {
url.append("/sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml?");
}
url.append("/sr/jira.issueviews:searchrequest-xml/temp/SearchRequest.xml?");
url.append("tempMax=").append(max);
url.append("&assignee=").append(encodeUrl(getUsername()));
// url.append("&resolution=-1");
@@ -72,17 +58,16 @@ public class JiraRepository extends BaseRepositoryImpl implements XmlRpcTranspor
url.append("&sorter/field=").append("updated");
url.append("&sorter/order=").append("DESC");
url.append("&pager/start=").append(0);
appendAuthentication(url, false);
return processRSS(url.toString());
}
@Override
public void setTaskState(Task task, TaskState state) throws Exception {
updateIssue(task.getId(), "status", state.name());
}
private Task[] processRSS(String url) throws IOException, JDOMException {
login();
HttpClient client = getHttpClient();
GetMethod method = new GetMethod(url);
configureHttpMethod(method);
@@ -115,78 +100,49 @@ public class JiraRepository extends BaseRepositoryImpl implements XmlRpcTranspor
return Task.EMPTY_ARRAY;
}
@SuppressWarnings({"UseOfObsoleteCollectionType"})
private void updateIssue(String issueKey, String field, String value) throws Exception {
Hashtable<Object, Object> hashtable = new Hashtable<Object, Object>();
// Hashtable<Object, Object> hashtable = new Hashtable<Object, Object>();
hashtable.put(field, "3");
doXmlRpcRequest("updateIssue", issueKey, hashtable);
}
@SuppressWarnings({"UseOfObsoleteCollectionType"})
private Object doXmlRpcRequest(String command, Object... params) throws Exception {
URL url = new URL(getUrl() + XMLRPC_PATH);
XmlRpcClient rpcClient = new XmlRpcClient(url, this);
Vector<Object> loginParams = new Vector<Object>(2);
loginParams.add(getUsername());
loginParams.add(getPassword());
String loginToken = (String)rpcClient.execute(JIRA1 + "login", loginParams);
if (loginToken == null) {
throw new Exception("Cannot connect to " + getUrl());
}
Vector<Object> tokens = new Vector<Object>();
tokens.add(loginToken);
ContainerUtil.addAll(tokens, params);
try {
return rpcClient.execute(JIRA1 + command, tokens);
}
finally {
rpcClient.execute(JIRA1 + "logout", new Vector<Object>(Arrays.asList(loginToken)));
private void login() throws IOException {
PostMethod postMethod = getLoginMethod();
HttpClient client = getHttpClient();
client.executeMethod(postMethod);
if (!checkLoginResult(postMethod)) {
// try 3.x protocol
login();
}
}
private String getServerVersion() throws Exception {
if (myServerVersion == null) {
try {
Map map = (Map)doXmlRpcRequest("getServerInfo");
myServerVersion = (String)map.get("version");
}
catch (Exception e) {
myServerVersion = "3.8";
LOG.warn(e);
if (e.getMessage().contains("Authentication")) {
throw e;
}
}
private boolean checkLoginResult(PostMethod postMethod) throws IOException {
int statusCode = postMethod.getStatusCode();
if (statusCode == HttpStatus.SC_NOT_FOUND && myJira4) {
myJira4 = false;
return false;
}
return myServerVersion;
if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_MOVED_TEMPORARILY) {
throw new IOException("Can't login: " + statusCode + " (" + HttpStatus.getStatusText(statusCode) + ")");
}
return true;
}
private PostMethod getLoginMethod() {
String url = getUrl() + (myJira4 ? "/rest/gadget/1.0/login" : "/secure/Dashboard.jspa");
PostMethod postMethod = new PostMethod(url);
postMethod.addParameter("os_username", getUsername());
postMethod.addParameter("os_password", getPassword());
postMethod.addParameter("os_destination", "/success");
configureHttpMethod(postMethod);
return postMethod;
}
@Override
public CancellableConnection createCancellableConnection() {
final HttpClient client = getHttpClient();
GetMethod method = new GetMethod(getUrl() + XMLRPC_PATH);
configureHttpMethod(method);
return new HttpTestConnection(method) {
PostMethod method = getLoginMethod();
return new HttpTestConnection<PostMethod>(method) {
@Override
public void doTest(HttpMethod method) throws Exception {
try {
client.executeMethod(method);
Element root = new SAXBuilder(false).build(method.getResponseBodyAsStream()).getRootElement();
if (!root.getName().equals("methodResponse")) {
throw new Exception(root.getName());
}
}
catch (Exception e) {
LOG.warn(e);
throw new Exception("JIRA RPC plugin not responded");
public void doTest(PostMethod method) throws Exception {
getHttpClient().executeMethod(method);
if (!checkLoginResult(method)) {
myMethod = getLoginMethod();
getHttpClient().executeMethod(myMethod);
}
}
};
@@ -202,7 +158,6 @@ public class JiraRepository extends BaseRepositoryImpl implements XmlRpcTranspor
StringBuilder url = new StringBuilder(getUrl());
url.append("/si/jira.issueviews:issue-xml/");
url.append(id).append('/').append(id).append(".xml");
appendAuthentication(url, true);
Task[] tasks = processRSS(url.toString());
return tasks.length == 0 ? null : tasks[0];
@@ -212,28 +167,4 @@ public class JiraRepository extends BaseRepositoryImpl implements XmlRpcTranspor
return null;
}
}
private void appendAuthentication(StringBuilder builder, boolean firstParam) {
builder.append(firstParam ? '?' : '&');
if (!isUseHttpAuthentication()) {
builder.append("os_username=").append(encodeUrl(getUsername()));
builder.append("&os_password=").append(encodeUrl(getPassword()));
}
else {
builder.append("os_authType=basic");
}
}
public XmlRpcTransport createTransport() throws XmlRpcClientException {
return new HttpClientTransport(getUrl() + XMLRPC_PATH, getHttpClient()) {
@Override
protected void configureMethod(HttpMethod method) {
configureHttpMethod(method);
}
};
}
public void setProperty(String propertyName, Object value) {
}
}
@@ -101,7 +101,7 @@ public abstract class BaseRepositoryImpl extends BaseRepository {
public abstract class HttpTestConnection<T extends HttpMethod> extends CancellableConnection {
private T myMethod;
protected T myMethod;
public HttpTestConnection(T method) {
myMethod = method;