hudson.scm.UserProvidedCredential Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of subversion Show documentation
Show all versions of subversion Show documentation
Integrates Hudson with Subversion SCM
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Fulvio Cavarretta,
* Jean-Baptiste Quenot, Luca Domenico Milanesio, Renaud Bruyeron, Stephen Connolly,
* Tom Huybrechts, Yahoo! Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.scm;
import hudson.model.AbstractProject;
import hudson.model.Hudson;
import hudson.model.TaskListener;
import hudson.scm.SubversionSCM.DescriptorImpl.Credential;
import hudson.scm.SubversionSCM.DescriptorImpl.PasswordCredential;
import hudson.scm.SubversionSCM.DescriptorImpl.SshPublicKeyCredential;
import hudson.scm.SubversionSCM.DescriptorImpl.SslClientCertificateCredential;
import hudson.security.csrf.CrumbIssuer;
import hudson.util.IOException2;
import hudson.util.MultipartFormDataParser;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.logging.Logger;
import org.apache.commons.fileupload.FileItem;
import org.kohsuke.putty.PuTTYKey;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.StaplerRequest;
import org.tmatesoft.svn.core.SVNCancelException;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.auth.SVNAuthentication;
import org.tmatesoft.svn.core.auth.SVNUserNameAuthentication;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
/**
* Represents the SVN authentication credential given by the user via the <enterCredential> form fragment.
* This is just a value object.
*
* @author Kohsuke Kawaguchi
*/
public class UserProvidedCredential implements Closeable {
private final String username;
private final String password;
private final File keyFile;
private final Boolean overrideGlobal;
public Boolean getOverrideGlobal() {
return overrideGlobal;
}
/**
* If non-null, this credential is submitted primarily to be used with this project.
* This actually doesn't prevent Hudson from trying it with other projects.
*/
public final AbstractProject inContextOf;
/**
* @deprecated as of 1.18
* Use {@link #UserProvidedCredential(String, String, File, AbstractProject)}
*/
public UserProvidedCredential(String username, String password, File keyFile) {
this(username, password, keyFile, null);
}
public UserProvidedCredential(String username, String password, File keyFile, AbstractProject inContextOf) {
this(username, password, keyFile, Boolean.TRUE, inContextOf);
}
public UserProvidedCredential(String username, String password, File keyFile, Boolean overrideGlobal,
AbstractProject inContextOf) {
this.username = username;
this.password = password;
this.keyFile = keyFile;
this.inContextOf = inContextOf;
this.overrideGlobal = overrideGlobal;
}
/**
* Parses the credential information from a form submission.
*/
public static UserProvidedCredential fromForm(StaplerRequest req, MultipartFormDataParser parser)
throws IOException {
CrumbIssuer crumbIssuer = Hudson.getInstance().getCrumbIssuer();
if (crumbIssuer != null && !crumbIssuer.validateCrumb(req, parser)) {
throw HttpResponses.error(SC_FORBIDDEN, new IOException("No crumb found"));
}
String kind = parser.get("kind");
int idx = Arrays.asList("", "password", "publickey", "certificate").indexOf(kind);
String username = parser.get("username" + idx);
String password = parser.get("password" + idx);
Boolean overrideGlobal = Boolean.valueOf(parser.get("_.overrideGlobal"));
// SVNKit wants a key in a file
final File keyFile;
final FileItem item;
if (idx <= 1) {
keyFile = null;
item = null;
} else {
item = parser.getFileItem(kind.equals("publickey") ? "privateKey" : "certificate");
keyFile = File.createTempFile("hudson", "key");
if (item != null) {
try {
item.write(keyFile);
} catch (Exception e) {
throw new IOException2(e);
}
if (PuTTYKey.isPuTTYKeyFile(keyFile)) {
// TODO: we need a passphrase support
LOGGER.info("Converting " + keyFile + " from PuTTY format to OpenSSH format");
new PuTTYKey(keyFile, null).toOpenSSH(keyFile);
}
}
}
return new UserProvidedCredential(username, password, keyFile, overrideGlobal,
req.findAncestorObject(AbstractProject.class)) {
@Override
public void close() throws IOException {
if (keyFile != null)
keyFile.delete();
if (item != null)
item.delete();
}
};
}
public void close() throws IOException {
}
/**
* {@link ISVNAuthenticationManager} that uses the user provided credential.
*/
public class AuthenticationManagerImpl extends DefaultSVNAuthenticationManager {
private Credential cred;
private String realm;
public String getRealm() {
return realm;
}
public Credential getCredential() {
return cred;
}
private final PrintWriter logWriter;
/**
* Set to true if SVNKit asked for a {@link SVNAuthentication}.
* False indicates that the server didn't attempt to authenticate the client.
*/
boolean authenticationAttempted;
/**
* Set to true if SVNKit acknowledged us whether the credential has worked or not.
* I'm not sure when this won't happen, but presumably under some error conditions.
*/
boolean authenticationAcknowledged;
/**
* Constructor for AuthenticationManager implementation.
* Uses $Hudson.Home config directory for storing credentials.
*
* @param logWriter PrintWriter.
* @see hudson.scm.SubversionSCM#getSubversionConfigDir().
*/
public AuthenticationManagerImpl(PrintWriter logWriter) {
this(SubversionSCM.getSubversionConfigDir(), logWriter);
}
public AuthenticationManagerImpl(File subversionConfigDir, PrintWriter logWriter) {
super(subversionConfigDir, true, username, password, keyFile, password);
this.logWriter = logWriter;
}
public AuthenticationManagerImpl(Writer w) {
this(new PrintWriter(w));
}
public AuthenticationManagerImpl(TaskListener listener) {
this(new PrintWriter(listener.getLogger(), true));
}
@Override
public SVNAuthentication getFirstAuthentication(String kind, String realm, SVNURL url) throws SVNException {
this.realm = realm;
authenticationAttempted = true;
if (kind.equals(ISVNAuthenticationManager.USERNAME))
// when using svn+ssh, svnkit first asks for ISVNAuthenticationManager.SSH
// authentication to connect via SSH, then calls this method one more time
// to get the user name. Perhaps svn takes user name on its own, separate
// from OS user name? In any case, we need to return the same user name.
// I don't set the cred field here, so that the 1st credential for ssh
// won't get clobbered.
{
return new SVNUserNameAuthentication(username, false, null, false);
}
if (kind.equals(ISVNAuthenticationManager.PASSWORD)) {
logWriter.println("Passing user name " + username + " and password you entered");
cred = new PasswordCredential(username, password);
}
if (kind.equals(ISVNAuthenticationManager.SSH)) {
if (keyFile == null) {
logWriter.println("Passing user name " + username + " and password you entered to SSH");
cred = new PasswordCredential(username, password);
} else {
logWriter.println("Attempting a public key authentication with username " + username);
cred = new SshPublicKeyCredential(username, password, keyFile);
}
}
if (kind.equals(ISVNAuthenticationManager.SSL)) {
logWriter.println("Attempting an SSL client certificate authentcation");
try {
cred = new SslClientCertificateCredential(keyFile, password);
} catch (IOException e) {
e.printStackTrace(logWriter);
return null;
}
}
if (cred == null) {
logWriter.println("Unknown authentication method: " + kind);
return null;
}
return cred.createSVNAuthentication(kind);
}
/**
* Getting here means the authentication tried in {@link #getFirstAuthentication(String, String, SVNURL)}
* didn't work.
*/
@Override
public SVNAuthentication getNextAuthentication(String kind, String realm, SVNURL url) throws SVNException {
SVNErrorManager.authenticationFailed("Authentication failed for " + url, null);
return null;
}
/**
* This method has been deprecated as of hudson 2.2.0. This is for support for only old versions of svnkit where
* overriding acknowledgeAuthentication needed to be overriden.
*
*/
@Override
@Deprecated
public void acknowledgeAuthentication(boolean accepted, String kind, String realm, SVNErrorMessage errorMessage,
SVNAuthentication authentication) throws SVNException {
authenticationAcknowledged = true;
if (accepted) {
assert cred != null;
onSuccess(realm, cred,overrideGlobal);
} else {
logWriter.println("Failed to authenticate: " + errorMessage);
if (errorMessage.getCause() != null) {
errorMessage.getCause().printStackTrace(logWriter);
}
}
super.acknowledgeAuthentication(accepted, kind, realm, errorMessage, authentication);
}
/**
* Called upon a successful acceptance of the credential.
*/
protected void onSuccess(String realm, Credential cred, Boolean overrideGlobal) {
}
/**
* Verifies that the expected authentication happened.
*/
public void checkIfProtocolCompleted() throws SVNCancelException {
if (!authenticationAttempted) {
logWriter.println("No authentication was attempted.");
throw new SVNCancelException();
}
}
}
private static final Logger LOGGER = Logger.getLogger(UserProvidedCredential.class.getName());
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy