ed1f8b1684381304e4e355e78a637db3c1223954
[teamcity/git-plugin.git] / git-agent / src / jetbrains / buildServer / buildTriggers / vcs / git / agent / command / impl / SshHandler.java
1 /*
2  * Copyright 2000-2018 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package jetbrains.buildServer.buildTriggers.vcs.git.agent.command.impl;
18
19 import jetbrains.buildServer.buildTriggers.vcs.git.AuthSettings;
20 import jetbrains.buildServer.buildTriggers.vcs.git.AuthenticationMethod;
21 import jetbrains.buildServer.buildTriggers.vcs.git.agent.Context;
22 import jetbrains.buildServer.buildTriggers.vcs.git.agent.GitCommandLine;
23 import jetbrains.buildServer.log.Loggers;
24 import jetbrains.buildServer.ssh.TeamCitySshKey;
25 import jetbrains.buildServer.ssh.VcsRootSshKeyManager;
26 import jetbrains.buildServer.util.FileUtil;
27 import jetbrains.buildServer.vcs.VcsException;
28 import jetbrains.buildServer.vcs.VcsRoot;
29 import jetbrains.buildServer.version.ServerVersionHolder;
30 import jetbrains.buildServer.version.ServerVersionInfo;
31 import org.jetbrains.annotations.NotNull;
32 import org.jetbrains.annotations.Nullable;
33 import org.jetbrains.git4idea.ssh.GitSSHHandler;
34 import org.jetbrains.git4idea.ssh.GitSSHService;
35
36 import java.io.File;
37 import java.io.IOException;
38 import java.util.ArrayList;
39 import java.util.List;
40 import java.util.Vector;
41
42 /**
43  * SSH handler implementation
44  */
45 public class SshHandler implements GitSSHService.Handler {
46   /**
47    * The handler number
48    */
49   private final int myHandlerNo;
50   /**
51    * SSH service
52    */
53   private final GitSSHService mySsh;
54   private final AuthSettings myAuthSettings;
55   private final List<File> myFilesToClean = new ArrayList<File>();
56
57   /**
58    * The constructor that registers the handler in the SSH service and command line
59    *
60    * @param ssh the SSH service
61    * @param authSettings authentication settings
62    * @param cmd the command line to register with
63    * @throws VcsException if there is a problem with registering the handler
64    */
65   public SshHandler(@NotNull GitSSHService ssh,
66                     @Nullable VcsRootSshKeyManager sshKeyManager,
67                     @NotNull AuthSettings authSettings,
68                     @NotNull GitCommandLine cmd,
69                     @NotNull File tmpDir,
70                     @NotNull Context ctx) throws VcsException {
71     mySsh = ssh;
72     myAuthSettings = authSettings;
73     cmd.addEnvParam(GitSSHHandler.SSH_PORT_ENV, Integer.toString(mySsh.getXmlRcpPort()));
74     if (myAuthSettings.isIgnoreKnownHosts())
75       cmd.addEnvParam(GitSSHHandler.SSH_IGNORE_KNOWN_HOSTS_ENV, "true");
76     if (authSettings.getAuthMethod() == AuthenticationMethod.TEAMCITY_SSH_KEY) {
77       String keyId = authSettings.getTeamCitySshKeyId();
78       if (keyId != null && sshKeyManager != null) {
79         VcsRoot root = myAuthSettings.getRoot();
80         if (root != null) {
81           TeamCitySshKey key = sshKeyManager.getKey(root);
82           if (key != null) {
83             try {
84               File privateKey = FileUtil.createTempFile(tmpDir, "key", "", true);
85               myFilesToClean.add(privateKey);
86               FileUtil.writeFileAndReportErrors(privateKey, new String(key.getPrivateKey()));
87               cmd.addEnvParam(GitSSHHandler.TEAMCITY_PRIVATE_KEY_PATH, privateKey.getCanonicalPath());
88               String passphrase = myAuthSettings.getPassphrase();
89               cmd.addEnvParam(GitSSHHandler.TEAMCITY_PASSPHRASE, passphrase != null ? passphrase : "");
90             } catch (Exception e) {
91               deleteKeys();
92               throw new VcsException(e);
93             }
94           }
95         }
96       }
97     }
98     if (ctx.getSshMacType() != null)
99       cmd.addEnvParam(GitSSHHandler.TEAMCITY_SSH_MAC_TYPE, ctx.getSshMacType());
100     if (ctx.getPreferredSshAuthMethods() != null)
101       cmd.addEnvParam(GitSSHHandler.TEAMCITY_SSH_PREFERRED_AUTH_METHODS, ctx.getPreferredSshAuthMethods());
102     cmd.addEnvParam(GitSSHHandler.TEAMCITY_DEBUG_SSH, String.valueOf(Loggers.VCS.isDebugEnabled()));
103     String teamCityVersion = getTeamCityVersion();
104     if (teamCityVersion != null) {
105       cmd.addEnvParam(GitSSHHandler.TEAMCITY_VERSION, teamCityVersion);
106     }
107     try {
108       cmd.addEnvParam(GitSSHHandler.GIT_SSH_ENV, ssh.getScriptPath());
109     } catch (IOException e) {
110       deleteKeys();
111       throw new VcsException("SSH script cannot be generated", e);
112     }
113     myHandlerNo = ssh.registerHandler(this);
114     cmd.addEnvParam(GitSSHHandler.SSH_HANDLER_ENV, Integer.toString(myHandlerNo));
115   }
116
117   /**
118    * Unregister the handler
119    */
120   public void unregister() {
121     deleteKeys();
122     mySsh.unregisterHandler(myHandlerNo);
123   }
124
125
126   private void deleteKeys() {
127     for (File f : myFilesToClean) {
128       FileUtil.delete(f);
129     }
130   }
131
132   public boolean verifyServerHostKey(String hostname,
133                                      int port,
134                                      String serverHostKeyAlgorithm,
135                                      String serverHostKey,
136                                      boolean isNew) {
137     return false;
138   }
139
140   public String askPassphrase(String username, String keyPath, boolean resetPassword, String lastError) {
141     if (resetPassword) {
142       return null;
143     }
144     return myAuthSettings.getPassphrase();
145   }
146
147   public Vector<String> replyToChallenge(String username,
148                                          String name,
149                                          String instruction,
150                                          int numPrompts,
151                                          Vector<String> prompt,
152                                          Vector<Boolean> echo,
153                                          String lastError) {
154     return null;
155   }
156
157   public String askPassword(String username, boolean resetPassword, String lastError) {
158     // The password is injected into URL
159     return null;
160   }
161
162   @Nullable
163   private static String getTeamCityVersion() {
164     try {
165       ServerVersionInfo version = ServerVersionHolder.getVersion();
166       return "TeamCity Agent " + version.getDisplayVersion();
167     } catch (Exception e) {
168       return null;
169     }
170   }
171 }