/******************************************************************************* * Copyright (c) 2006, 2010 Steffen Pingel and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Steffen Pingel - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.trac.core.client; import java.io.IOException; import java.net.HttpURLConnection; import java.net.Proxy; import java.net.URL; import java.util.HashMap; import org.apache.commons.httpclient.Cookie; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.methods.PostMethod; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.mylyn.commons.core.CoreUtil; import org.eclipse.mylyn.commons.net.AbstractWebLocation; import org.eclipse.mylyn.commons.net.AuthenticationCredentials; import org.eclipse.mylyn.commons.net.WebUtil; import org.eclipse.mylyn.internal.trac.core.model.TracComponent; import org.eclipse.mylyn.internal.trac.core.model.TracMilestone; import org.eclipse.mylyn.internal.trac.core.model.TracPriority; import org.eclipse.mylyn.internal.trac.core.model.TracSeverity; import org.eclipse.mylyn.internal.trac.core.model.TracTicketField; import org.eclipse.mylyn.internal.trac.core.model.TracTicketResolution; import org.eclipse.mylyn.internal.trac.core.model.TracTicketStatus; import org.eclipse.mylyn.internal.trac.core.model.TracTicketType; import org.eclipse.mylyn.internal.trac.core.model.TracVersion; /** * @author Steffen Pingel */ public abstract class AbstractTracClient implements ITracClient { /** * Artificial status code to indicate that SSL cert authentication failed. */ public static final int SC_CERT_AUTH_FAILED = 499; protected static final boolean DEBUG_AUTH = Boolean.valueOf(Platform.getDebugOption("org.eclipse.mylyn.trac.core/debug/authentication")); //$NON-NLS-1$ protected static final String USER_AGENT = "TracConnector"; //$NON-NLS-1$ private static final String LOGIN_COOKIE_NAME = "trac_auth"; //$NON-NLS-1$ protected final String repositoryUrl; protected final Version version; protected final AbstractWebLocation location; protected TracClientData data; public AbstractTracClient(URL repositoryUrl, Version version, String username, String password, Proxy proxy) { this.repositoryUrl = repositoryUrl.toString(); this.version = version; this.location = null; this.data = new TracClientData(); } public AbstractTracClient(AbstractWebLocation location, Version version) { this.location = location; this.version = version; this.repositoryUrl = location.getUrl(); this.data = new TracClientData(); } protected HttpClient createHttpClient() { HttpClient httpClient = new HttpClient(); httpClient.setHttpConnectionManager(WebUtil.getConnectionManager()); httpClient.getParams().setCookiePolicy(CookiePolicy.RFC_2109); WebUtil.configureHttpClient(httpClient, USER_AGENT); return httpClient; } public Version getAccessMode() { return version; } protected boolean credentialsValid(AuthenticationCredentials credentials) { return credentials != null && credentials.getUserName().length() > 0; } protected void authenticateAccountManager(HttpClient httpClient, HostConfiguration hostConfiguration, AuthenticationCredentials credentials, IProgressMonitor monitor) throws IOException, TracLoginException { String formToken = getFormToken(httpClient); authenticateAccountManagerInternal(httpClient, hostConfiguration, credentials, monitor, formToken); // form token is based on a cookie which may have changed due to the login post // re-try with new token to ensure we are logging in with the right token, otherwise user won't be logged in String newFormToken = getFormToken(httpClient); if (formToken.length() == 0 && !formToken.equals(newFormToken)) { authenticateAccountManagerInternal(httpClient, hostConfiguration, credentials, monitor, newFormToken); } } public void authenticateAccountManagerInternal(HttpClient httpClient, HostConfiguration hostConfiguration, AuthenticationCredentials credentials, IProgressMonitor monitor, String formToken) throws IOException, TracLoginException { PostMethod post = new PostMethod(WebUtil.getRequestPath(repositoryUrl + LOGIN_URL)); post.setFollowRedirects(false); NameValuePair[] data = { new NameValuePair("referer", ""), //$NON-NLS-1$ //$NON-NLS-2$ new NameValuePair("user", credentials.getUserName()), //$NON-NLS-1$ new NameValuePair("password", credentials.getPassword()), new NameValuePair("__FORM_TOKEN", formToken) }; //$NON-NLS-1$ //$NON-NLS-2$ post.setRequestBody(data); try { if (DEBUG_AUTH) { System.err.println(location.getUrl() + ": Attempting form-based account manager authentication"); //$NON-NLS-1$ } int code = WebUtil.execute(httpClient, hostConfiguration, post, monitor); if (DEBUG_AUTH) { System.err.println(location.getUrl() + ": Received account manager response (" + code + ")"); //$NON-NLS-1$ //$NON-NLS-2$ } // code should be a redirect in case of success if (code == HttpURLConnection.HTTP_OK) { throw new TracLoginException(); } } finally { WebUtil.releaseConnection(post, monitor); } } private String getFormToken(HttpClient httpClient) { Cookie[] cookies = httpClient.getState().getCookies(); for (Cookie cookie : cookies) { if ("trac_form_token".equals(cookie.getName())) { //$NON-NLS-1$ return cookie.getValue(); } } return ""; //$NON-NLS-1$ } /** * Check if authentication cookie has been set. * * @throws TracLoginException * thrown if the cookie has not been set */ protected void validateAuthenticationState(HttpClient httpClient) throws TracLoginException { Cookie[] cookies = httpClient.getState().getCookies(); for (Cookie cookie : cookies) { if (LOGIN_COOKIE_NAME.equals(cookie.getName())) { return; } } if (CoreUtil.TEST_MODE) { System.err.println(" Authentication failed: " + httpClient.getState()); //$NON-NLS-1$ } throw new TracLoginException(); } public TracComponent[] getComponents() { return (data.components != null) ? data.components.toArray(new TracComponent[0]) : null; } public TracMilestone[] getMilestones() { return (data.milestones != null) ? data.milestones.toArray(new TracMilestone[0]) : null; } public TracPriority[] getPriorities() { return (data.priorities != null) ? data.priorities.toArray(new TracPriority[0]) : null; } public TracSeverity[] getSeverities() { return (data.severities != null) ? data.severities.toArray(new TracSeverity[0]) : null; } public TracTicketField[] getTicketFields() { return (data.ticketFields != null) ? data.ticketFields.toArray(new TracTicketField[0]) : null; } public TracTicketField getTicketFieldByName(String name) { if (data.ticketFields != null) { synchronized (this) { // lazily fill fieldByName map if (data.ticketFieldByName == null) { data.ticketFieldByName = new HashMap<String, TracTicketField>(); for (TracTicketField field : data.ticketFields) { data.ticketFieldByName.put(field.getName(), field); } } return data.ticketFieldByName.get(name); } } return null; } public TracTicketResolution[] getTicketResolutions() { return (data.ticketResolutions != null) ? data.ticketResolutions.toArray(new TracTicketResolution[0]) : null; } public TracTicketStatus[] getTicketStatus() { return (data.ticketStatus != null) ? data.ticketStatus.toArray(new TracTicketStatus[0]) : null; } public TracTicketType[] getTicketTypes() { return (data.ticketTypes != null) ? data.ticketTypes.toArray(new TracTicketType[0]) : null; } public TracVersion[] getVersions() { return (data.versions != null) ? data.versions.toArray(new TracVersion[0]) : null; } public boolean hasAttributes() { return (data.lastUpdate != 0); } public void updateAttributes(IProgressMonitor monitor, boolean force) throws TracException { if (!hasAttributes() || force) { updateAttributes(monitor); data.lastUpdate = System.currentTimeMillis(); } } public abstract void updateAttributes(IProgressMonitor monitor) throws TracException; public void setData(TracClientData data) { this.data = data; } public String[] getDefaultTicketResolutions() { return new String[] { "fixed", "invalid", "wontfix", "duplicate", "worksforme" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ } public String[] getDefaultTicketActions(String status) { if ("new".equals(status)) { //$NON-NLS-1$ return new String[] { "leave", "resolve", "reassign", "accept" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } else if ("assigned".equals(status)) { //$NON-NLS-1$ return new String[] { "leave", "resolve", "reassign" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else if ("reopened".equals(status)) { //$NON-NLS-1$ return new String[] { "leave", "resolve", "reassign" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else if ("closed".equals(status)) { //$NON-NLS-1$ return new String[] { "leave", "reopen" }; //$NON-NLS-1$ //$NON-NLS-2$ } return null; } public String getUrl() { return repositoryUrl; } }