/* * ==================================================================== * Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.auth; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.net.ssl.TrustManager; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.io.SVNRepository; /** * The <b>BasicAuthenticationManager</b> is a simple implementation of * <b>ISVNAuthenticationManager</b> for storing and providing credentials without * using auth providers. A basic manager simply keeps the user credentials provided. * Also this manager may store a single proxy server options context (for HHTP requests * to go through a particular proxy server). * * <p> * This manager does not use authentication providers (<b>ISVNAuthenticationProvider</b>) but only * those credentials that was supplied to its constructor. Also this manager never * caches credentials. * * <p> * This manager is not used in SVNKit internals. You may use a default * manager (how to get it read javadoc for {@link ISVNAuthenticationManager}), * this basic manager or implement your own one. * * @version 1.3 * @author TMate Software Ltd. * @since 1.2 * @see ISVNAuthenticationProvider */ public class BasicAuthenticationManager implements ISVNAuthenticationManager, ISVNProxyManagerEx, ISVNSSHHostVerifier { /** * Creates an auth manager given a user credential - a username * and password. * * @param userName a username * @param password a password * * @since 1.8.9 */ public static BasicAuthenticationManager newInstance(String userName, char[] password) { return newInstance(new SVNAuthentication[] { SVNPasswordAuthentication.newInstance(userName, password, false, null, false), SVNSSHAuthentication.newInstance(userName, password, -1, false, null, false), SVNUserNameAuthentication.newInstance(userName, false, null, false), }); } /** * Creates an auth manager given a user credential - a username and * an ssh private key. * * @param userName a username * @param keyFile a private key file * @param passphrase a password to the private key * @param portNumber a port number over which an ssh tunnel is established * * @since 1.8.9 */ public static BasicAuthenticationManager newInstance(String userName, File keyFile, char[] passphrase, int portNumber) { return newInstance(new SVNAuthentication[] { SVNSSHAuthentication.newInstance(userName, keyFile, passphrase, portNumber, false, null, false), SVNUserNameAuthentication.newInstance(userName, false, null, false), }); } /** * Creates an auth manager given user credentials to use. * * @param credentials user credentials * * @since 1.8.9 */ public static BasicAuthenticationManager newInstance(SVNAuthentication[] credentials) { return new BasicAuthenticationManager(credentials); } /** * Utility method to acknowledge successful or failed authentication attempt */ public static void acknowledgeAuthentication(boolean accepted, String kind, String realm, SVNErrorMessage errorMessage, SVNAuthentication authentication, SVNURL accessedURL, ISVNAuthenticationManager authManager) throws SVNException { if (authManager instanceof ISVNAuthenticationManagerExt) { ((ISVNAuthenticationManagerExt)authManager).acknowledgeAuthentication(accepted, kind, realm, errorMessage, authentication, accessedURL); } else { authManager.acknowledgeAuthentication(accepted, kind, realm, errorMessage, authentication); } } private List<SVNAuthentication> myPasswordAuthentications; private List<SVNAuthentication> mySSHAuthentications; private List<SVNAuthentication> myUserNameAuthentications; private List<SVNAuthentication> mySSLAuthentications; private int mySSHIndex; private int myPasswordIndex; private int myUserNameIndex; private int mySSLIndex; private String myProxyHost; private int myProxyPort; private String myProxyUserName; private char[] myProxyPassword; private boolean myIsAuthenticationForced; /** * Creates an auth manager given a user credential - a username * and password. * * @deprecated Use {@link #newInstance(String, char[])} method * * @param userName a username * @param password a password */ public BasicAuthenticationManager(String userName, String password) { this(new SVNAuthentication[] { SVNPasswordAuthentication.newInstance(userName, password != null ? password.toCharArray() : null, false, null, false), SVNSSHAuthentication.newInstance(userName, password != null ? password.toCharArray() : null, -1, false, null, false), SVNUserNameAuthentication.newInstance(userName, false, null, false), }); } /** * Creates an auth manager given a user credential - a username and * an ssh private key. * * @deprecated Use {@link #newInstance(String, File, char[], int)} method * * @param userName a username * @param keyFile a private key file * @param passphrase a password to the private key * @param portNumber a port number over which an ssh tunnel is established */ public BasicAuthenticationManager(String userName, File keyFile, String passphrase, int portNumber) { this(new SVNAuthentication[] { SVNSSHAuthentication.newInstance(userName, keyFile, passphrase != null ? passphrase.toCharArray() : null, portNumber, false, null, false), SVNUserNameAuthentication.newInstance(userName, false, null, false), }); } /** * Creates an auth manager given user credentials to use. * * @param authentications user credentials */ public BasicAuthenticationManager(SVNAuthentication[] authentications) { setAuthentications(authentications); } /** * Sets the given user credentials to this manager. * * @param authentications user credentials */ public void setAuthentications(SVNAuthentication[] authentications) { dismissSensitiveData(); myPasswordAuthentications = new ArrayList<SVNAuthentication>(); mySSHAuthentications = new ArrayList<SVNAuthentication>(); myUserNameAuthentications = new ArrayList<SVNAuthentication>(); mySSLAuthentications = new ArrayList<SVNAuthentication>(); myPasswordIndex = 0; mySSHIndex = 0; mySSLIndex = 0; myUserNameIndex = 0; for (int i = 0; authentications != null && i < authentications.length; i++) { SVNAuthentication auth = authentications[i]; if (auth instanceof SVNPasswordAuthentication) { myPasswordAuthentications.add(auth); } else if (auth instanceof SVNSSHAuthentication) { mySSHAuthentications.add(auth); } else if (auth instanceof SVNUserNameAuthentication) { myUserNameAuthentications.add(auth); } else if (auth instanceof SVNSSLAuthentication) { mySSLAuthentications.add(auth); } } } /** * Sets a proxy server context to this manager. * * @deprecated * * @param proxyHost a proxy server hostname * @param proxyPort a proxy server port * @param proxyUserName a username to supply to a proxy machine * @param proxyPassword a password to supply to a proxy machine */ public void setProxy(String proxyHost, int proxyPort, String proxyUserName, String proxyPassword) { setProxy(proxyHost, proxyPort, proxyUserName, proxyPassword != null ? proxyPassword.toCharArray() : null); } /** * Sets a proxy server context to this manager. * * @param proxyHost a proxy server hostname * @param proxyPort a proxy server port * @param proxyUserName a username to supply to a proxy machine * @param proxyPassword a password to supply to a proxy machine */ public void setProxy(String proxyHost, int proxyPort, String proxyUserName, char[] proxyPassword) { myProxyHost = proxyHost; myProxyPort = proxyPort >= 0 ? proxyPort : 3128; myProxyUserName = proxyUserName; myProxyPassword = proxyPassword; } /** * Returns the first user's authentication credentials. * * @param kind credentials kind; valid kinds are {@link ISVNAuthenticationManager#SSH}, * {@link ISVNAuthenticationManager#PASSWORD}, {@link ISVNAuthenticationManager#USERNAME}, * {@link ISVNAuthenticationManager#SSL}, {@link ISVNAuthenticationManager#USERNAME} * @param realm authentication realm * @param url repository url * @return first user's credentials * @throws SVNException exception with {@link org.tmatesoft.svn.core.SVNErrorCode#RA_NOT_AUTHORIZED} * error code - in case of invalid <code>kind</code> */ public SVNAuthentication getFirstAuthentication(String kind, String realm, SVNURL url) throws SVNException { if (ISVNAuthenticationManager.SSH.equals(kind) && mySSHAuthentications.size() > 0) { mySSHIndex = 0; return (SVNAuthentication) mySSHAuthentications.get(0); } else if (ISVNAuthenticationManager.PASSWORD.equals(kind) && myPasswordAuthentications.size() > 0) { myPasswordIndex = 0; return (SVNAuthentication) myPasswordAuthentications.get(0); } else if (ISVNAuthenticationManager.USERNAME.equals(kind) && myUserNameAuthentications.size() > 0) { myUserNameIndex = 0; return (SVNAuthentication) myUserNameAuthentications.get(0); } else if (ISVNAuthenticationManager.SSL.equals(kind) && mySSLAuthentications.size() > 0) { mySSLIndex = 0; return (SVNAuthentication) mySSLAuthentications.get(0); } if (ISVNAuthenticationManager.USERNAME.equals(kind)) { if (url.getUserInfo() != null && !"".equals(url.getUserInfo())) { return SVNUserNameAuthentication.newInstance(url.getUserInfo(), false, url, false); } // client will use default. return SVNUserNameAuthentication.newInstance(null, false, url, false); } SVNErrorManager.authenticationFailed("Authentication required for ''{0}''", realm); return null; } /** * Returns next user authentication credentials. This method is called whenever the first credentials * returned by {@link #getFirstAuthentication(String, String, SVNURL)} failed to authenticate the user. * * @param kind credentials kind; valid kinds are {@link ISVNAuthenticationManager#SSH}, * {@link ISVNAuthenticationManager#PASSWORD}, {@link ISVNAuthenticationManager#USERNAME}, * {@link ISVNAuthenticationManager#SSL}, {@link ISVNAuthenticationManager#USERNAME} * @param realm authentication realm * @param url repository url * @return next user's authentication credentials * @throws SVNException exception with {@link org.tmatesoft.svn.core.SVNErrorCode#RA_NOT_AUTHORIZED} * error code - in case of invalid <code>kind</code> */ public SVNAuthentication getNextAuthentication(String kind, String realm, SVNURL url) throws SVNException { if (ISVNAuthenticationManager.SSH.equals(kind) && mySSHIndex + 1 < mySSHAuthentications.size()) { mySSHIndex++; return (SVNAuthentication) mySSHAuthentications.get(mySSHIndex); } else if (ISVNAuthenticationManager.PASSWORD.equals(kind) && myPasswordIndex + 1 < myPasswordAuthentications.size()) { myPasswordIndex++; return (SVNAuthentication) myPasswordAuthentications.get(myPasswordIndex); } else if (ISVNAuthenticationManager.USERNAME.equals(kind) && myUserNameIndex + 1 < myUserNameAuthentications.size()) { myUserNameIndex++; return (SVNAuthentication) myUserNameAuthentications.get(myUserNameIndex); } else if (ISVNAuthenticationManager.SSL.equals(kind) && mySSLIndex + 1 < mySSLAuthentications.size()) { mySSLIndex++; return (SVNAuthentication) mySSLAuthentications.get(mySSLIndex); } SVNErrorManager.authenticationFailed("Authentication required for ''{0}''", realm); return null; } /** * Does nothing. * * @param provider */ public void setAuthenticationProvider(ISVNAuthenticationProvider provider) { } /** * Returns itself as a proxy manager. * * @param url a repository location that will be accessed * over the proxy server for which a manager is needed * @return a proxy manager * @throws SVNException */ public ISVNProxyManager getProxyManager(SVNURL url) throws SVNException { return this; } /** * Returns <span class="javakeyword">null</span>. * * @param url repository url * @return <span class="javakeyword">null</span> * @throws SVNException * @since 1.2.0 */ public TrustManager getTrustManager(SVNURL url) throws SVNException { return null; } /** * Does nothing. * * @param accepted * @param kind * @param realm * @param errorMessage * @param authentication */ public void acknowledgeAuthentication(boolean accepted, String kind, String realm, SVNErrorMessage errorMessage, SVNAuthentication authentication) { } /** * Does nothing. * * @param manager * @since 1.2.0 */ public void acknowledgeTrustManager(TrustManager manager) { } /** * Tells whether authentication should be tried despite not being challenged from the server yet. * * <p/> * By default the return value is always <span class="javakeyword">false</span> until this behavior is * changed via a call to {@link #setAuthenticationForced(boolean)}. * * @return authentication force flag */ public boolean isAuthenticationForced() { return myIsAuthenticationForced; } /** * Sets whether authentication should be forced or not. * * @param forced authentication force flag * @see #isAuthenticationForced() */ public void setAuthenticationForced(boolean forced) { myIsAuthenticationForced = forced; } /** * Returns the proxy host name. * * @return the proxy host argument value specified via the {@link #setProxy(String, int, String, String)} * method */ public String getProxyHost() { return myProxyHost; } /** * Returns the proxy port number. * @return the proxy port argument value specified via the {@link #setProxy(String, int, String, String)} * method */ public int getProxyPort() { return myProxyPort; } /** * Returns the proxy user name. * @return the proxy user name argument value specified via the {@link #setProxy(String, int, String, String)} * method */ public String getProxyUserName() { return myProxyUserName; } /** * Returns the password to authenticate against the proxy server. * * @deprecated Use {@link #getProxyPasswordValue()} * * @return the proxy password argument value specified via the {@link #setProxy(String, int, String, String)} * method */ public String getProxyPassword() { return myProxyPassword != null ? new String(myProxyPassword) : null; } /** * Returns the password to authenticate against the proxy server. * * @since 1.8.9 * * @return the proxy password argument value specified via the {@link #setProxy(String, int, String, String)} * method */ public char[] getProxyPasswordValue() { return myProxyPassword; } /** * Does nothing. * * @param accepted * @param errorMessage */ public void acknowledgeProxyContext(boolean accepted, SVNErrorMessage errorMessage) { } /** * Returns connection timeout value. * * <p/> * This implementation returns a read timeout value equal to 3600 seconds for <code>http</code> * or <code>https</code> access operations. If <code>repository</code> uses a different access protocol, * the return value will be 0. * * @param repository repository access object * @return read timeout value in milliseconds * @since 1.2.0 */ public int getReadTimeout(SVNRepository repository) { String protocol = repository.getLocation().getProtocol(); if ("http".equals(protocol) || "https".equals(protocol)) { return 3600*1000; } return 0; } /** * Returns connection timeout value. * * <p/> * This implementation returns a connection timeout value equal to 60 seconds for <code>http</code> * or <code>https</code> access operations. If <code>repository</code> uses a different access protocol, * the return value will be 0. * * @param repository repository access object * @return connection timeout value in milliseconds * @since 1.2.0 */ public int getConnectTimeout(SVNRepository repository) { String protocol = repository.getLocation().getProtocol(); if ("http".equals(protocol) || "https".equals(protocol)) { return 60*1000; } return 0; } public void verifyHostKey(String hostName, int port, String keyAlgorithm, byte[] hostKey) throws SVNException { } /** * Dismiss cached sensitive data (e.g. password) * * Calling this method clears and removes all credentials stored in this authentication manager. * * @since 1.8.9 */ public void dismissSensitiveData() { dismissSensitiveData(myPasswordAuthentications); dismissSensitiveData(mySSHAuthentications); dismissSensitiveData(myUserNameAuthentications); dismissSensitiveData(mySSLAuthentications); myPasswordIndex = 0; mySSHIndex = 0; mySSLIndex = 0; myUserNameIndex = 0; } private void dismissSensitiveData(List<SVNAuthentication> auths) { if (auths == null) { return; } for (SVNAuthentication auth : auths) { auth.dismissSensitiveData(); } auths.clear(); } }