1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.internal.transport.sshd;
11
12 import java.net.InetSocketAddress;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.concurrent.ConcurrentHashMap;
17
18 import org.apache.sshd.client.auth.keyboard.UserInteraction;
19 import org.apache.sshd.client.session.ClientSession;
20 import org.apache.sshd.common.session.Session;
21 import org.apache.sshd.common.session.SessionListener;
22 import org.eclipse.jgit.transport.CredentialItem;
23 import org.eclipse.jgit.transport.CredentialsProvider;
24 import org.eclipse.jgit.transport.SshConstants;
25 import org.eclipse.jgit.transport.URIish;
26
27
28
29
30
31 public class JGitUserInteraction implements UserInteraction {
32
33 private final CredentialsProvider provider;
34
35
36
37
38
39 private final Map<Session, SessionListener> ongoing = new ConcurrentHashMap<>();
40
41
42
43
44
45
46
47
48 public JGitUserInteraction(CredentialsProvider provider) {
49 this.provider = provider;
50 }
51
52 @Override
53 public boolean isInteractionAllowed(ClientSession session) {
54 return provider != null && provider.isInteractive();
55 }
56
57 @Override
58 public String[] interactive(ClientSession session, String name,
59 String instruction, String lang, String[] prompt, boolean[] echo) {
60
61 List<CredentialItem> items = new ArrayList<>();
62 int numberOfHiddenInputs = 0;
63 for (int i = 0; i < prompt.length; i++) {
64 boolean hidden = i < echo.length && !echo[i];
65 if (hidden) {
66 numberOfHiddenInputs++;
67 }
68 }
69
70
71
72
73
74 if (name != null && !name.isEmpty()) {
75 items.add(new CredentialItem.InformationalMessage(name));
76 }
77 if (instruction != null && !instruction.isEmpty()) {
78 items.add(new CredentialItem.InformationalMessage(instruction));
79 }
80 for (int i = 0; i < prompt.length; i++) {
81 boolean hidden = i < echo.length && !echo[i];
82 if (hidden && numberOfHiddenInputs == 1) {
83
84
85
86 items.add(new CredentialItem.Password());
87
88
89
90 } else {
91 items.add(new CredentialItem.StringType(prompt[i], hidden));
92 }
93 }
94 if (items.isEmpty()) {
95
96 return prompt;
97 }
98 URIish uri = toURI(session.getUsername(),
99 (InetSocketAddress) session.getConnectAddress());
100
101
102
103 if (numberOfHiddenInputs > 0) {
104 SessionListener listener = ongoing.get(session);
105 if (listener != null) {
106 provider.reset(uri);
107 } else {
108 listener = new SessionAuthMarker(ongoing);
109 ongoing.put(session, listener);
110 session.addSessionListener(listener);
111 }
112 }
113 if (provider.get(uri, items)) {
114 return items.stream().map(i -> {
115 if (i instanceof CredentialItem.Password) {
116 return new String(((CredentialItem.Password) i).getValue());
117 } else if (i instanceof CredentialItem.StringType) {
118 return ((CredentialItem.StringType) i).getValue();
119 }
120 return null;
121 }).filter(s -> s != null).toArray(String[]::new);
122 }
123
124
125
126
127
128
129
130
131 return null;
132 }
133
134 @Override
135 public String getUpdatedPassword(ClientSession session, String prompt,
136 String lang) {
137
138 return null;
139 }
140
141
142
143
144
145
146
147
148
149
150 public static URIish toURI(String userName, InetSocketAddress remote) {
151 String host = remote.getHostString();
152 int port = remote.getPort();
153 return new URIish()
154 .setScheme(SshConstants.SSH_SCHEME)
155 .setHost(host)
156 .setPort(port)
157 .setUser(userName);
158 }
159
160
161
162
163
164 private static class SessionAuthMarker implements SessionListener {
165
166 private final Map<Session, SessionListener> registered;
167
168 public SessionAuthMarker(Map<Session, SessionListener> registered) {
169 this.registered = registered;
170 }
171
172 @Override
173 public void sessionEvent(Session session, SessionListener.Event event) {
174 if (event == SessionListener.Event.Authenticated) {
175 session.removeSessionListener(this);
176 registered.remove(session, this);
177 }
178 }
179
180 @Override
181 public void sessionClosed(Session session) {
182 session.removeSessionListener(this);
183 registered.remove(session, this);
184 }
185 }
186 }