Package hudson.scm

Source Code of hudson.scm.UserProvidedCredential$AuthenticationManagerImpl

/*
* 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 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 org.tmatesoft.svn.core.wc.SVNWCUtil;

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 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;
    /**
     * 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 = username;
        this.password = password;
        this.keyFile = keyFile;
        this.inContextOf = inContextOf;
    }

    /**
     * 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);


        // 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,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 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;

        public AuthenticationManagerImpl(PrintWriter logWriter) {
            super(SVNWCUtil.getDefaultConfigurationDirectory(), true, username, password, keyFile, password);
            this.logWriter = logWriter;
            SVNAuthStoreHandlerImpl.install(this);
        }

        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 {
            authenticationAttempted = true;
            if (kind.equals(ISVNAuthenticationManager.USERNAME))
                // when using svn+ssh, lib.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);
            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;
        }

        @Override
        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);
            } 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) {
        }

        /**
         * Verifies that the expected authentication happened.
         */
        public void checkIfProtocolCompleted() throws SVNCancelException {
            if(!authenticationAttempted) {
                logWriter.println("No authentication was attempted.");
                throw new SVNCancelException();
            }
            if (!authenticationAcknowledged) {
                logWriter.println("Authentication was not acknowledged.");
                throw new SVNCancelException();
            }
        }
    }

    private static final Logger LOGGER = Logger.getLogger(UserProvidedCredential.class.getName());
}
TOP

Related Classes of hudson.scm.UserProvidedCredential$AuthenticationManagerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.