import org.eclipse.jgit.http.server.resolver.RepositoryResolver;
import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.http.test.util.AccessEvent;
+import org.eclipse.jgit.http.test.util.AppServer;
import org.eclipse.jgit.http.test.util.HttpTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.transport.FetchConnection;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
public class HttpClientTests extends HttpTestCase {
private TestRepository<FileRepository> remoteRepository;
}
}
+ public void testListRemote_Dumb_Auth() throws Exception {
+ Repository dst = createBareRepository();
+ Transport t = Transport.open(dst, dumbAuthBasicURI);
+ t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
+ AppServer.username, AppServer.password));
+ try {
+ t.openFetch();
+ } finally {
+ t.close();
+ }
+ t = Transport.open(dst, dumbAuthBasicURI);
+ t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
+ AppServer.username, ""));
+ try {
+ t.openFetch();
+ fail("connection opened even info/refs needs auth basic and we provide wrong password");
+ } catch (TransportException err) {
+ String exp = dumbAuthBasicURI + ": "
+ + JGitText.get().notAuthorized;
+ assertEquals(exp, err.getMessage());
+ } finally {
+ t.close();
+ }
+ }
+
public void testListRemote_Smart_UploadPackNeedsAuth() throws Exception {
Repository dst = createBareRepository();
Transport t = Transport.open(dst, smartAuthBasicURI);
countingObjects=Counting objects
createBranchFailedUnknownReason=Create branch failed for unknown reason
createBranchUnexpectedResult=Create branch returned unexpected result {0}
-creatingDeltasIsNotImplemented=creating deltas is not implemented
+credentialPassword=Password
+credentialUsername=Username
daemonAlreadyRunning=Daemon already running
deleteBranchUnexpectedResult=Delete branch returned unexpected result {0}
deletingNotSupported=Deleting {0} not supported.
/***/ public String countingObjects;
/***/ public String createBranchFailedUnknownReason;
/***/ public String createBranchUnexpectedResult;
- /***/ public String creatingDeltasIsNotImplemented;
+ /***/ public String credentialPassword;
+ /***/ public String credentialUsername;
/***/ public String daemonAlreadyRunning;
/***/ public String deleteBranchUnexpectedResult;
/***/ public String deletingNotSupported;
--- /dev/null
+/*
+ * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>,
+ * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.errors;
+
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.URIish;
+
+/**
+ * An exception thrown when a {@link CredentialItem} is requested from a
+ * {@link CredentialsProvider} which is not supported by this provider.
+ */
+public class UnsupportedCredentialItem extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs an UnsupportedCredentialItem with the specified detail message
+ * prefixed with provided URI.
+ *
+ * @param uri
+ * URI used for transport
+ * @param s
+ * message
+ */
+ public UnsupportedCredentialItem(final URIish uri, final String s) {
+ super(uri.setPass(null) + ": " + s);
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.util.Arrays;
+
+import org.eclipse.jgit.JGitText;
+
+/**
+ * A credential requested from a {@link CredentialsProvider}.
+ *
+ * Most users should work with the specialized subclasses:
+ * <ul>
+ * <li>{@link Username} for usernames</li>
+ * <li>{@link Password} for passwords</li>
+ * <li>{@link StringType} for other general string information</li>
+ * <li>{@link CharArrayType} for other general secret information</li>
+ * </ul>
+ *
+ * This class is not thread-safe. Applications should construct their own
+ * instance for each use, as the value is held within the CredentialItem object.
+ */
+public abstract class CredentialItem {
+ private final String promptText;
+
+ private final boolean valueSecure;
+
+ /**
+ * Initialize a prompt.
+ *
+ * @param promptText
+ * prompt to display to the user alongside of the input field.
+ * Should be sufficient text to indicate what to supply for this
+ * item.
+ * @param maskValue
+ * true if the value should be masked from displaying during
+ * input. This should be true for passwords and other secrets,
+ * false for names and other public data.
+ */
+ public CredentialItem(String promptText, boolean maskValue) {
+ this.promptText = promptText;
+ this.valueSecure = maskValue;
+ }
+
+ /** @return prompt to display to the user. */
+ public String getPromptText() {
+ return promptText;
+ }
+
+ /** @return true if the value should be masked when entered. */
+ public boolean isValueSecure() {
+ return valueSecure;
+ }
+
+ /** Clear the stored value, destroying it as much as possible. */
+ public abstract void clear();
+
+ /**
+ * An item whose value is stored as a string.
+ *
+ * When working with secret data, consider {@link CharArrayType} instead, as
+ * the internal members of the array can be cleared, reducing the chances
+ * that the password is left in memory after authentication is completed.
+ */
+ public static class StringType extends CredentialItem {
+ private String value;
+
+ /**
+ * Initialize a prompt for a single string.
+ *
+ * @param promptText
+ * prompt to display to the user alongside of the input
+ * field. Should be sufficient text to indicate what to
+ * supply for this item.
+ * @param maskValue
+ * true if the value should be masked from displaying during
+ * input. This should be true for passwords and other
+ * secrets, false for names and other public data.
+ */
+ public StringType(String promptText, boolean maskValue) {
+ super(promptText, maskValue);
+ }
+
+ @Override
+ public void clear() {
+ value = null;
+ }
+
+ /** @return the current value */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ *
+ * @param newValue
+ */
+ public void setValue(String newValue) {
+ value = newValue;
+ }
+ }
+
+ /** An item whose value is stored as a char[] and is therefore clearable. */
+ public static class CharArrayType extends CredentialItem {
+ private char[] value;
+
+ /**
+ * Initialize a prompt for a secure value stored in a character array.
+ *
+ * @param promptText
+ * prompt to display to the user alongside of the input
+ * field. Should be sufficient text to indicate what to
+ * supply for this item.
+ * @param maskValue
+ * true if the value should be masked from displaying during
+ * input. This should be true for passwords and other
+ * secrets, false for names and other public data.
+ */
+ public CharArrayType(String promptText, boolean maskValue) {
+ super(promptText, maskValue);
+ }
+
+ /** Destroys the current value, clearing the internal array. */
+ @Override
+ public void clear() {
+ if (value != null) {
+ Arrays.fill(value, (char) 0);
+ value = null;
+ }
+ }
+
+ /**
+ * Get the current value.
+ *
+ * The returned array will be cleared out when {@link #clear()} is
+ * called. Callers that need the array elements to survive should delay
+ * invoking {@code clear()} until the value is no longer necessary.
+ *
+ * @return the current value array. The actual internal array is
+ * returned, reducing the number of copies present in memory.
+ */
+ public char[] getValue() {
+ return value;
+ }
+
+ /**
+ * Set the new value, clearing the old value array.
+ *
+ * @param newValue
+ * if not null, the array is copied.
+ */
+ public void setValue(char[] newValue) {
+ clear();
+
+ if (newValue != null) {
+ value = new char[newValue.length];
+ System.arraycopy(newValue, 0, value, 0, newValue.length);
+ }
+ }
+
+ /**
+ * Set the new value, clearing the old value array.
+ *
+ * @param newValue
+ * the new internal array. The array is <b>NOT</b> copied.
+ */
+ public void setValueNoCopy(char[] newValue) {
+ clear();
+ value = newValue;
+ }
+ }
+
+ /** Prompt for a username, which is not masked on input. */
+ public static class Username extends StringType {
+ /** Initialize a new username item, with a default username prompt. */
+ public Username() {
+ super(JGitText.get().credentialUsername, false);
+ }
+ }
+
+ /** Prompt for a password, which is masked on input. */
+ public static class Password extends CharArrayType {
+ /** Initialize a new password item, with a default password prompt. */
+ public Password() {
+ super(JGitText.get().credentialPassword, true);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>,
+ * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.util.List;
+
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+
+/**
+ * Provide credentials for use in connecting to Git repositories.
+ *
+ * Implementors are strongly encouraged to support at least the minimal
+ * {@link CredentialItem.Username} and {@link CredentialItem.Password} items.
+ * More sophisticated implementors may implement additional types, such as
+ * {@link CredentialItem.StringType}.
+ *
+ * CredentialItems are usually presented in bulk, allowing implementors to
+ * combine them into a single UI widget and streamline the authentication
+ * process for an end-user.
+ *
+ * @see UsernamePasswordCredentialsProvider
+ */
+public abstract class CredentialsProvider {
+ /**
+ * Check if the provider can supply the necessary {@link CredentialItem}s.
+ *
+ * @param items
+ * the items the application requires to complete authentication.
+ * @return {@code true} if this {@link CredentialsProvider} supports all of
+ * the items supplied.
+ */
+ public abstract boolean supports(CredentialItem... items);
+
+ /**
+ * Ask for the credential items to be populated.
+ *
+ * @param uri
+ * the URI of the remote resource that needs authentication.
+ * @param items
+ * the items the application requires to complete authentication.
+ * @return {@code true} if the request was successful and values were
+ * supplied; {@code false} if the user canceled the request and did
+ * not supply all requested values.
+ * @throws UnsupportedCredentialItem
+ * if one of the items supplied is not supported.
+ */
+ public abstract boolean get(URIish uri, CredentialItem... items)
+ throws UnsupportedCredentialItem;
+
+ /**
+ * Ask for the credential items to be populated.
+ *
+ * @param uri
+ * the URI of the remote resource that needs authentication.
+ * @param items
+ * the items the application requires to complete authentication.
+ * @return {@code true} if the request was successful and values were
+ * supplied; {@code false} if the user canceled the request and did
+ * not supply all requested values.
+ * @throws UnsupportedCredentialItem
+ * if one of the items supplied is not supported.
+ */
+ public boolean get(URIish uri, List<CredentialItem> items)
+ throws UnsupportedCredentialItem {
+ return get(uri, items.toArray(new CredentialItem[items.size()]));
+ }
+}
*
* @param uri
* the URI used to create the connection.
+ * @param credentialsProvider
+ * the credentials provider, or null. If provided,
+ * {@link URIish#getPass() credentials in the URI} are ignored.
+ *
+ * @return true if the authentication method is able to provide
+ * authorization for the given URI
*/
- void authorize(URIish uri) {
- authorize(uri.getUser(), uri.getPass());
+ boolean authorize(URIish uri, CredentialsProvider credentialsProvider) {
+ String username;
+ String password;
+
+ if (credentialsProvider != null) {
+ CredentialItem.Username u = new CredentialItem.Username();
+ CredentialItem.Password p = new CredentialItem.Password();
+
+ if (credentialsProvider.supports(u, p)
+ && credentialsProvider.get(uri, u, p)) {
+ username = u.getValue();
+ password = new String(p.getValue());
+ p.clear();
+ } else
+ return false;
+ } else {
+ username = uri.getUser();
+ password = uri.getPass();
+ }
+ if (username != null) {
+ authorize(username, password);
+ return true;
+ }
+ return false;
}
/**
/** Pack configuration used by this transport to make pack file. */
private PackConfig packConfig;
+ /** Assists with authentication the connection. */
+ private CredentialsProvider credentialsProvider;
+
/**
* Create a new transport instance.
*
packConfig = pc;
}
+ /**
+ * A credentials provider to assist with authentication connections..
+ *
+ * @param credentialsProvider
+ * the credentials provider, or null if there is none
+ */
+ public void setCredentialsProvider(CredentialsProvider credentialsProvider) {
+ this.credentialsProvider = credentialsProvider;
+ }
+
+ /**
+ * The configured credentials provider.
+ *
+ * @return the credentials provider, or null if no credentials provider is
+ * associated with this transport.
+ */
+ public CredentialsProvider getCredentialsProvider() {
+ return credentialsProvider;
+ }
+
/**
* Fetch objects and refs from the remote repository to the local one.
* <p>
if (authMethod == HttpAuthMethod.NONE)
throw new TransportException(uri, MessageFormat.format(
JGitText.get().authenticationNotSupported, uri));
- if (1 < authAttempts || uri.getUser() == null)
+ if (1 < authAttempts
+ || !authMethod.authorize(uri,
+ getCredentialsProvider())) {
throw new TransportException(uri,
JGitText.get().notAuthorized);
- authMethod.authorize(uri);
+ }
authAttempts++;
continue;
--- /dev/null
+/*
+ * Copyright (C) 2010, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.util.Arrays;
+
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+
+/**
+ * Simple {@link CredentialsProvider} that always uses the same information.
+ */
+public class UsernamePasswordCredentialsProvider extends CredentialsProvider {
+ private String username;
+
+ private char[] password;
+
+ /**
+ * Initialize the provider with a single username and password.
+ *
+ * @param username
+ * @param password
+ */
+ public UsernamePasswordCredentialsProvider(String username, String password) {
+ this(username, password.toCharArray());
+ }
+
+ /**
+ * Initialize the provider with a single username and password.
+ *
+ * @param username
+ * @param password
+ */
+ public UsernamePasswordCredentialsProvider(String username, char[] password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ @Override
+ public boolean supports(CredentialItem... items) {
+ for (CredentialItem i : items) {
+ if (i instanceof CredentialItem.Username)
+ continue;
+
+ else if (i instanceof CredentialItem.Password)
+ continue;
+
+ else
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean get(URIish uri, CredentialItem... items)
+ throws UnsupportedCredentialItem {
+ for (CredentialItem i : items) {
+ if (i instanceof CredentialItem.Username)
+ ((CredentialItem.Username) i).setValue(username);
+
+ else if (i instanceof CredentialItem.Password)
+ ((CredentialItem.Password) i).setValue(password);
+
+ else
+ throw new UnsupportedCredentialItem(uri, i.getPromptText());
+ }
+ return true;
+ }
+
+ /** Destroy the saved username and password.. */
+ public void clear() {
+ username = null;
+
+ if (password != null) {
+ Arrays.fill(password, (char) 0);
+ password = null;
+ }
+ }
+}