/*
* ====================================================================
* 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.internal.io.svn;
import java.io.IOException;
import java.util.List;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.auth.SVNAuthentication;
import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.util.SVNLogType;
/**
* @version 1.3
* @author TMate Software Ltd.
*/
public class SVNPlainAuthenticator extends SVNAuthenticator {
public SVNPlainAuthenticator(SVNConnection connection) throws SVNException {
super(connection);
}
public SVNAuthentication authenticate(List mechs, String realm, SVNRepositoryImpl repos) throws SVNException {
SVNErrorMessage failureReason = null;
if (mechs == null || mechs.size() == 0) {
return null;
}
ISVNAuthenticationManager authManager = repos.getAuthenticationManager();
if (authManager != null && authManager.isAuthenticationForced() && mechs.contains("ANONYMOUS") && mechs.contains("CRAM-MD5")) {
mechs.remove("ANONYMOUS");
}
SVNURL location = repos.getLocation();
SVNPasswordAuthentication auth = null;
if (repos.getExternalUserName() != null && mechs.contains("EXTERNAL")) {
getConnection().write("(w(s))", new Object[]{"EXTERNAL", ""});
failureReason = readAuthResponse();
} else if (mechs.contains("ANONYMOUS")) {
getConnection().write("(w(s))", new Object[]{"ANONYMOUS", ""});
failureReason = readAuthResponse();
} else if (mechs.contains("CRAM-MD5")) {
while (true) {
CramMD5 authenticator = new CramMD5();
if (location != null) {
realm = "<" + location.getProtocol() + "://"
+ location.getHost() + ":"
+ location.getPort() + "> " + realm;
}
try {
if (auth == null && authManager != null) {
auth = (SVNPasswordAuthentication) authManager.getFirstAuthentication(ISVNAuthenticationManager.PASSWORD, realm, location);
} else if (authManager != null) {
BasicAuthenticationManager.acknowledgeAuthentication(false, ISVNAuthenticationManager.PASSWORD, realm, failureReason, auth, location, authManager);
auth = (SVNPasswordAuthentication) authManager.getNextAuthentication(ISVNAuthenticationManager.PASSWORD, realm, location);
}
} catch (SVNException e) {
if (e.getErrorMessage().getErrorCode() == SVNErrorCode.CANCELLED) {
throw e;
} else if (getLastError() != null) {
SVNErrorManager.error(getLastError(), SVNLogType.NETWORK);
}
throw e;
}
if (auth == null) {
failureReason = SVNErrorMessage.create(SVNErrorCode.CANCELLED, "Authentication cancelled");
setLastError(failureReason);
break;
}
if (auth.getUserName() == null || auth.getPasswordValue() == null) {
failureReason = SVNErrorMessage.create(SVNErrorCode.RA_NOT_AUTHORIZED, "Can''t get password. Authentication is required for ''{0}''", realm);
break;
}
getConnection().write("(w())", new Object[]{"CRAM-MD5"});
while (true) {
authenticator.setUserCredentials(auth);
List items = getConnection().readTuple("w(?s)", true);
String status = SVNReader.getString(items, 0);
if (SVNAuthenticator.SUCCESS.equals(status)) {
BasicAuthenticationManager.acknowledgeAuthentication(true, ISVNAuthenticationManager.PASSWORD, realm, null, auth, location, authManager);
return auth;
} else if (SVNAuthenticator.FAILURE.equals(status)) {
failureReason = SVNErrorMessage.create(SVNErrorCode.RA_NOT_AUTHORIZED, "Authentication error from server: {0}", SVNReader.getString(items, 1));
String message = SVNReader.getString(items, 1);
if (message != null) {
setLastError(SVNErrorMessage.create(SVNErrorCode.RA_NOT_AUTHORIZED, message));
}
break;
} else if (SVNAuthenticator.STEP.equals(status)) {
try {
byte[] response = authenticator.buildChallengeResponse(SVNReader.getBytes(items, 1));
getConnectionOutputStream().write(response);
getConnectionOutputStream().flush();
} catch (IOException e) {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_SVN_IO_ERROR, e.getMessage()), e, SVNLogType.NETWORK);
}
}
}
}
} else {
SVNErrorManager.error(SVNErrorMessage.create(SVNErrorCode.RA_NOT_AUTHORIZED, "Cannot negotiate authentication mechanism"), SVNLogType.NETWORK);
}
if (failureReason != null) {
if (getLastError() != null) {
SVNErrorManager.error(getLastError(), SVNLogType.NETWORK);
}
SVNErrorManager.error(failureReason, SVNLogType.NETWORK);
}
return auth;
}
protected SVNErrorMessage readAuthResponse() throws SVNException {
List items = getConnection().readTuple("w(?s)", true);
if (SVNAuthenticator.SUCCESS.equals(SVNReader.getString(items, 0))) {
return null;
} else if (SVNAuthenticator.FAILURE.equals(SVNReader.getString(items, 0))) {
return SVNErrorMessage.create(SVNErrorCode.RA_NOT_AUTHORIZED, "Authentication error from server: {0}", SVNReader.getString(items, 1));
}
return SVNErrorMessage.create(SVNErrorCode.RA_NOT_AUTHORIZED, "Unexpected server response to authentication");
}
}