From 36825935ed7028d7adff368d2a8c76781876131a Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 9 Apr 2014 20:28:41 +0400 Subject: [PATCH] Disable Basic Authentication in JIRA connector once JSESSIONID cookie was received to maintain session --- .../tasks/impl/BaseRepositoryImpl.java | 3 + .../intellij/tasks/jira/JiraRepository.java | 61 +++++++++++-------- .../intellij/tasks/jira/rest/JiraRestApi.java | 2 +- .../integration/JiraIntegrationTest.java | 11 ++++ 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepositoryImpl.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepositoryImpl.java index f80c6124261e..5a0aa95bdec7 100644 --- a/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepositoryImpl.java +++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/impl/BaseRepositoryImpl.java @@ -76,6 +76,9 @@ public abstract class BaseRepositoryImpl extends BaseRepository { client.getParams().setCredentialCharset("UTF-8"); client.getParams().setAuthenticationPreemptive(true); client.getState().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(getUsername(), getPassword())); + } else { + client.getState().clearCredentials(); + client.getParams().setAuthenticationPreemptive(false); } } diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java index 82b0051961d7..a04e6b008ede 100644 --- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java @@ -18,10 +18,7 @@ import com.intellij.tasks.jira.rest.JiraRestApi; import com.intellij.tasks.jira.soap.JiraSoapApi; import com.intellij.util.ArrayUtil; import com.intellij.util.xmlb.annotations.Tag; -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.methods.GetMethod; import org.jetbrains.annotations.NotNull; @@ -54,10 +51,13 @@ public class JiraRepository extends BaseRepositoryImpl { */ @SuppressWarnings({"UnusedDeclaration"}) public JiraRepository() { + myUseHttpAuthentication = true; } public JiraRepository(JiraRepositoryType type) { super(type); + // Use Basic authentication at the beginning of new session and disable then if needed + myUseHttpAuthentication = true; } private JiraRepository(JiraRepository other) { @@ -131,7 +131,7 @@ public class JiraRepository extends BaseRepositoryImpl { @NotNull public JiraRemoteApi discoverApiVersion() throws Exception { if (LEGACY_API_ONLY) { - LOG.warn("Intentionally using only legacy JIRA API"); + LOG.info("Intentionally using only legacy JIRA API"); return new JiraSoapApi(this); } @@ -166,22 +166,32 @@ public class JiraRepository extends BaseRepositoryImpl { } } - // Used primarily for XML_RPC API @NotNull public String executeMethod(@NotNull HttpMethod method) throws Exception { - return executeMethod(getHttpClient(), method); - } - - @NotNull - public String executeMethod(@NotNull HttpClient client, @NotNull HttpMethod method) throws Exception { LOG.debug("URI: " + method.getURI()); - int statusCode; - String entityContent; - statusCode = client.executeMethod(method); + + HttpClient client = getHttpClient(); + // Fix for https://jetbrains.zendesk.com/agent/#/tickets/24566 + // See https://confluence.atlassian.com/display/ONDEMANDKB/Getting+randomly+logged+out+of+OnDemand for details + boolean cookieAuthenticated = false; + for (Cookie cookie : client.getState().getCookies()) { + if (cookie.getName().equals("JSESSIONID") && !cookie.isExpired()) { + cookieAuthenticated = true; + break; + } + } + // disable subsequent basic authorization attempts if user already was authenticated + boolean enableBasicAuthentication = !(isRestApiSupported() && cookieAuthenticated); + if (enableBasicAuthentication != isUseHttpAuthentication()) { + LOG.info("Basic authentication for subsequent requests was " + (enableBasicAuthentication ? "enabled" : "disabled")); + } + setUseHttpAuthentication(enableBasicAuthentication); + + int statusCode = client.executeMethod(method); LOG.debug("Status code: " + statusCode); // may be null if 204 No Content received final InputStream stream = method.getResponseBodyAsStream(); - entityContent = stream == null ? "" : StreamUtil.readText(stream, CharsetToolkit.UTF8); + String entityContent = stream == null ? "" : StreamUtil.readText(stream, CharsetToolkit.UTF8); TaskUtil.prettyFormatJsonToLog(LOG, entityContent); // besides SC_OK, can also be SC_NO_CONTENT in issue transition requests // see: JiraRestApi#setTaskStatus @@ -221,14 +231,6 @@ public class JiraRepository extends BaseRepositoryImpl { return super.getHttpClient(); } - /** - * Always use Basic HTTP authentication for JIRA REST interface - */ - @Override - public boolean isUseHttpAuthentication() { - return true; - } - @Override protected void configureHttpClient(HttpClient client) { super.configureHttpClient(client); @@ -238,17 +240,22 @@ public class JiraRepository extends BaseRepositoryImpl { @Override protected int getFeatures() { int features = super.getFeatures(); - if (myApiVersion == null || myApiVersion.getType() == JiraRemoteApi.ApiType.SOAP) { - return features & ~NATIVE_SEARCH & ~STATE_UPDATING & ~TIME_MANAGEMENT; - } else { + if (isRestApiSupported()) { return features | TIME_MANAGEMENT | STATE_UPDATING; } + else { + return features & ~NATIVE_SEARCH & ~STATE_UPDATING & ~TIME_MANAGEMENT; + } } - public boolean isJqlSupported() { + private boolean isRestApiSupported() { return myApiVersion != null && myApiVersion.getType() != JiraRemoteApi.ApiType.SOAP; } + public boolean isJqlSupported() { + return isRestApiSupported(); + } + public String getSearchQuery() { return mySearchQuery; } diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java index a56b1cf1091a..ad43cf48496a 100644 --- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java @@ -30,7 +30,7 @@ public abstract class JiraRestApi extends JiraRemoteApi { private static final Logger LOG = Logger.getInstance(JiraRestApi.class); public static JiraRestApi fromJiraVersion(@NotNull JiraVersion jiraVersion, @NotNull JiraRepository repository) { - LOG.debug("JIRA version is " + jiraVersion); + LOG.info("JIRA version is " + jiraVersion); if (jiraVersion.getMajorNumber() == 4 && jiraVersion.getMinorNumber() >= 2) { return new JiraRestApi20Alpha1(repository); } diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/JiraIntegrationTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/JiraIntegrationTest.java index 317750ff9bab..8bbdf687c3e9 100644 --- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/JiraIntegrationTest.java +++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/JiraIntegrationTest.java @@ -28,6 +28,8 @@ import com.intellij.tasks.impl.TaskUtil; import com.intellij.tasks.jira.JiraRepository; import com.intellij.tasks.jira.JiraRepositoryType; import com.intellij.tasks.jira.JiraVersion; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.GetMethod; import org.jetbrains.annotations.NonNls; @@ -101,6 +103,15 @@ public class JiraIntegrationTest extends TaskManagerTestCase { } } + public void testBasicAuthenticationDisabling() throws Exception { + assertTrue("Basic authentication should be enabled at first", myRepository.isUseHttpAuthentication()); + myRepository.findTask("PRJONE-1"); + assertFalse("Basic authentication should be disabled once JSESSIONID cookie was received", myRepository.isUseHttpAuthentication()); + HttpClient client = myRepository.getHttpClient(); + assertFalse(client.getParams().isAuthenticationPreemptive()); + assertNull(client.getState().getCredentials(AuthScope.ANY)); + } + public void testSetTaskState() throws Exception { changeStateAndCheck(JIRA_4_TEST_SERVER_URL, "PRJONE-8"); changeStateAndCheck(JIRA_5_TEST_SERVER_URL, "UT-8");