View Javadoc
1   /*
2    * Copyright (C) 2019 Thomas Wolf <thomas.wolf@paranor.ch> and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.internal.transport.sshd;
11  
12  import static org.eclipse.jgit.internal.transport.ssh.OpenSshConfigFile.flag;
13  
14  import java.net.InetSocketAddress;
15  import java.net.SocketAddress;
16  import java.security.PublicKey;
17  import java.util.Collections;
18  import java.util.List;
19  import java.util.Locale;
20  
21  import org.apache.sshd.client.config.hosts.HostConfigEntry;
22  import org.apache.sshd.client.config.hosts.KnownHostHashValue;
23  import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
24  import org.apache.sshd.client.session.ClientSession;
25  import org.apache.sshd.common.util.net.SshdSocketAddress;
26  import org.eclipse.jgit.annotations.NonNull;
27  import org.eclipse.jgit.transport.CredentialsProvider;
28  import org.eclipse.jgit.transport.SshConstants;
29  import org.eclipse.jgit.transport.sshd.ServerKeyDatabase;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  /**
34   * A bridge between the {@link ServerKeyVerifier} from Apache MINA sshd and our
35   * {@link ServerKeyDatabase}.
36   */
37  public class JGitServerKeyVerifier
38  		implements ServerKeyVerifier, ServerKeyLookup {
39  
40  	private static final Logger LOG = LoggerFactory
41  			.getLogger(JGitServerKeyVerifier.class);
42  
43  	private final @NonNull ServerKeyDatabase database;
44  
45  	/**
46  	 * Creates a new {@link JGitServerKeyVerifier} using the given
47  	 * {@link ServerKeyDatabase}.
48  	 *
49  	 * @param database
50  	 *            to use
51  	 */
52  	public JGitServerKeyVerifier(@NonNull ServerKeyDatabase database) {
53  		this.database = database;
54  	}
55  
56  	@Override
57  	public List<PublicKey> lookup(ClientSession session,
58  			SocketAddress remoteAddress) {
59  		if (!(session instanceof JGitClientSession)) {
60  			LOG.warn("Internal error: wrong session kind: " //$NON-NLS-1$
61  					+ session.getClass().getName());
62  			return Collections.emptyList();
63  		}
64  		if (!(remoteAddress instanceof InetSocketAddress)) {
65  			return Collections.emptyList();
66  		}
67  		SessionConfig config = new SessionConfig((JGitClientSession) session);
68  		SshdSocketAddress connectAddress = SshdSocketAddress
69  				.toSshdSocketAddress(session.getConnectAddress());
70  		String connect = KnownHostHashValue.createHostPattern(
71  				connectAddress.getHostName(), connectAddress.getPort());
72  		return database.lookup(connect, (InetSocketAddress) remoteAddress,
73  				config);
74  	}
75  
76  	@Override
77  	public boolean verifyServerKey(ClientSession session,
78  			SocketAddress remoteAddress, PublicKey serverKey) {
79  		if (!(session instanceof JGitClientSession)) {
80  			LOG.warn("Internal error: wrong session kind: " //$NON-NLS-1$
81  					+ session.getClass().getName());
82  			return false;
83  		}
84  		if (!(remoteAddress instanceof InetSocketAddress)) {
85  			return false;
86  		}
87  		SessionConfig config = new SessionConfig((JGitClientSession) session);
88  		SshdSocketAddress connectAddress = SshdSocketAddress
89  				.toSshdSocketAddress(session.getConnectAddress());
90  		String connect = KnownHostHashValue.createHostPattern(
91  				connectAddress.getHostName(), connectAddress.getPort());
92  		CredentialsProvider provider = ((JGitClientSession) session)
93  				.getCredentialsProvider();
94  		return database.accept(connect, (InetSocketAddress) remoteAddress,
95  				serverKey, config, provider);
96  	}
97  
98  	private static class SessionConfig
99  			implements ServerKeyDatabase.Configuration {
100 
101 		private final JGitClientSession session;
102 
103 		public SessionConfig(JGitClientSession session) {
104 			this.session = session;
105 		}
106 
107 		private List<String> get(String key) {
108 			HostConfigEntry entry = session.getHostConfigEntry();
109 			if (entry instanceof JGitHostConfigEntry) {
110 				// Always true!
111 				return ((JGitHostConfigEntry) entry).getMultiValuedOptions()
112 						.get(key);
113 			}
114 			return Collections.emptyList();
115 		}
116 
117 		@Override
118 		public List<String> getUserKnownHostsFiles() {
119 			return get(SshConstants.USER_KNOWN_HOSTS_FILE);
120 		}
121 
122 		@Override
123 		public List<String> getGlobalKnownHostsFiles() {
124 			return get(SshConstants.GLOBAL_KNOWN_HOSTS_FILE);
125 		}
126 
127 		@Override
128 		public StrictHostKeyChecking getStrictHostKeyChecking() {
129 			HostConfigEntry entry = session.getHostConfigEntry();
130 			String value = entry
131 					.getProperty(SshConstants.STRICT_HOST_KEY_CHECKING, "ask"); //$NON-NLS-1$
132 			switch (value.toLowerCase(Locale.ROOT)) {
133 			case SshConstants.YES:
134 			case SshConstants.ON:
135 				return StrictHostKeyChecking.REQUIRE_MATCH;
136 			case SshConstants.NO:
137 			case SshConstants.OFF:
138 				return StrictHostKeyChecking.ACCEPT_ANY;
139 			case "accept-new": //$NON-NLS-1$
140 				return StrictHostKeyChecking.ACCEPT_NEW;
141 			default:
142 				return StrictHostKeyChecking.ASK;
143 			}
144 		}
145 
146 		@Override
147 		public boolean getHashKnownHosts() {
148 			HostConfigEntry entry = session.getHostConfigEntry();
149 			return flag(entry.getProperty(SshConstants.HASH_KNOWN_HOSTS));
150 		}
151 
152 		@Override
153 		public String getUsername() {
154 			return session.getUsername();
155 		}
156 	}
157 }