1 /*
2 * SSHTools - Java SSH2 API
3 *
4 * Copyright (C) 2002-2003 Lee David Painter and Contributors.
5 *
6 * Contributions made by:
7 *
8 * Brett Smith
9 * Richard Pernavas
10 * Erwin Bolwidt
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 */
26 package com.sshtools.daemon.authentication;
27
28 import com.sshtools.daemon.configuration;
29 import com.sshtools.daemon.platform;
30
31 import com.sshtools.j2ssh;
32 import com.sshtools.j2ssh.authentication;
33 import com.sshtools.j2ssh.configuration;
34 import com.sshtools.j2ssh.transport;
35
36 import org.apache.commons.logging;
37
38 import java.io;
39
40 import java.util;
41
42
43 /**
44 *
45 *
46 * @author $author$
47 * @version $Revision: 1.11 $
48 */
49 public class AuthenticationProtocolServer extends AsyncService {
50 private static Log log = LogFactory.getLog(AuthenticationProtocolServer.class);
51 private List completedAuthentications = new ArrayList();
52 private Map acceptServices = new HashMap();
53 private List availableAuths;
54 private String serviceToStart;
55 private int[] messageFilter = new int[1];
56 private SshMessageStore methodMessages = new SshMessageStore();
57 private int attempts = 0;
58 private boolean completed = false;
59
60 /**
61 * Creates a new AuthenticationProtocolServer object.
62 */
63 public AuthenticationProtocolServer() {
64 super("ssh-userauth");
65 messageFilter[0] = SshMsgUserAuthRequest.SSH_MSG_USERAUTH_REQUEST;
66 }
67
68 /**
69 *
70 *
71 * @throws java.io.IOException
72 */
73 protected void onServiceAccept() throws java.io.IOException {
74 }
75
76 /**
77 *
78 *
79 * @param startMode
80 *
81 * @throws java.io.IOException
82 */
83 protected void onServiceInit(int startMode) throws java.io.IOException {
84 // Register the required messages
85 messageStore.registerMessage(SshMsgUserAuthRequest.SSH_MSG_USERAUTH_REQUEST,
86 SshMsgUserAuthRequest.class);
87 transport.addMessageStore(methodMessages);
88 }
89
90 /**
91 *
92 *
93 * @return
94 */
95 public byte[] getSessionIdentifier() {
96 return transport.getSessionIdentifier();
97 }
98
99 /**
100 *
101 *
102 * @return
103 */
104 public TransportProtocolState getConnectionState() {
105 return transport.getState();
106 }
107
108 /**
109 *
110 *
111 * @param msg
112 *
113 * @throws IOException
114 */
115 public void sendMessage(SshMessage msg) throws IOException {
116 transport.sendMessage(msg, this);
117 }
118
119 /**
120 *
121 *
122 * @return
123 *
124 * @throws IOException
125 * @throws SshException
126 */
127 public SshMessage readMessage() throws IOException {
128 try {
129 return methodMessages.nextMessage();
130 } catch (InterruptedException ex) {
131 throw new SshException("The thread was interrupted");
132 }
133 }
134
135 /**
136 *
137 *
138 * @param messageId
139 * @param cls
140 */
141 public void registerMessage(int messageId, Class cls) {
142 methodMessages.registerMessage(messageId, cls);
143 }
144
145 /**
146 *
147 *
148 * @throws java.io.IOException
149 * @throws AuthenticationProtocolException
150 */
151 protected void onServiceRequest() throws java.io.IOException {
152 // Send a user auth banner if configured
153 ServerConfiguration server = (ServerConfiguration) ConfigurationLoader.getConfiguration(ServerConfiguration.class);
154
155 if (server == null) {
156 throw new AuthenticationProtocolException(
157 "Server configuration unavailable");
158 }
159
160 availableAuths = new ArrayList();
161
162 Iterator it = SshAuthenticationServerFactory.getSupportedMethods()
163 .iterator();
164 String method;
165 List allowed = server.getAllowedAuthentications();
166
167 while (it.hasNext()) {
168 method = (String) it.next();
169
170 if (allowed.contains(method)) {
171 availableAuths.add(method);
172 }
173 }
174
175 if (availableAuths.size() <= 0) {
176 throw new AuthenticationProtocolException(
177 "No valid authentication methods have been specified");
178 }
179
180 // Accept the service request
181 sendServiceAccept();
182
183 String bannerFile = server.getAuthenticationBanner();
184
185 if (bannerFile != null) {
186 if (bannerFile.length() > 0) {
187 InputStream in = ConfigurationLoader.loadFile(bannerFile);
188
189 if (in != null) {
190 byte[] data = new byte[in.available()];
191 in.read(data);
192 in.close();
193
194 SshMsgUserAuthBanner bannerMsg = new SshMsgUserAuthBanner(new String(
195 data));
196 transport.sendMessage(bannerMsg, this);
197 } else {
198 log.info("The banner file '" + bannerFile +
199 "' was not found");
200 }
201 }
202 }
203 }
204
205 /**
206 *
207 *
208 * @param msg
209 *
210 * @throws java.io.IOException
211 * @throws AuthenticationProtocolException
212 */
213 protected void onMessageReceived(SshMessage msg) throws java.io.IOException {
214 switch (msg.getMessageId()) {
215 case SshMsgUserAuthRequest.SSH_MSG_USERAUTH_REQUEST: {
216 onMsgUserAuthRequest((SshMsgUserAuthRequest) msg);
217
218 break;
219 }
220
221 default:
222 throw new AuthenticationProtocolException(
223 "Unregistered message received!");
224 }
225 }
226
227 /**
228 *
229 *
230 * @return
231 */
232 protected int[] getAsyncMessageFilter() {
233 return messageFilter;
234 }
235
236 /**
237 *
238 *
239 * @param service
240 */
241 public void acceptService(Service service) {
242 acceptServices.put(service.getServiceName(), service);
243 }
244
245 private void sendUserAuthFailure(boolean success) throws IOException {
246 Iterator it = availableAuths.iterator();
247 String auths = null;
248
249 while (it.hasNext()) {
250 auths = ((auths == null) ? "" : (auths + ",")) +
251 (String) it.next();
252 }
253
254 SshMsgUserAuthFailure reply = new SshMsgUserAuthFailure(auths, success);
255 transport.sendMessage(reply, this);
256 }
257
258 /**
259 *
260 */
261 protected void onStop() {
262 try {
263 // If authentication succeeded then wait for the
264 // disconnect and logoff the user
265 if (completed) {
266 try {
267 transport.getState().waitForState(TransportProtocolState.DISCONNECTED);
268 } catch (InterruptedException ex) {
269 log.warn("The authentication service was interrupted");
270 }
271
272 NativeAuthenticationProvider nap = NativeAuthenticationProvider.getInstance();
273 nap.logoffUser();
274 }
275 } catch (IOException ex) {
276 log.warn("Failed to logoff " + SshThread.getCurrentThreadUser());
277 }
278 }
279
280 private void sendUserAuthSuccess() throws IOException {
281 SshMsgUserAuthSuccess msg = new SshMsgUserAuthSuccess();
282 Service service = (Service) acceptServices.get(serviceToStart);
283 service.init(Service.ACCEPTING_SERVICE, transport); //, nativeSettings);
284 service.start();
285 transport.sendMessage(msg, this);
286 completed = true;
287 stop();
288 }
289
290 private void onMsgUserAuthRequest(SshMsgUserAuthRequest msg)
291 throws IOException {
292 if (msg.getMethodName().equals("none")) {
293 sendUserAuthFailure(false);
294 } else {
295 if (attempts >= ((ServerConfiguration) ConfigurationLoader.getConfiguration(
296 ServerConfiguration.class)).getMaxAuthentications()) {
297 // Too many authentication attempts
298 transport.disconnect("Too many failed authentication attempts");
299 } else {
300 // If the service is supported then perfrom the authentication
301 if (acceptServices.containsKey(msg.getServiceName())) {
302 String method = msg.getMethodName();
303
304 if (availableAuths.contains(method)) {
305 SshAuthenticationServer auth = SshAuthenticationServerFactory.newInstance(method);
306 serviceToStart = msg.getServiceName();
307
308 //auth.setUsername(msg.getUsername());
309 int result = auth.authenticate(this, msg); //, nativeSettings);
310
311 if (result == AuthenticationProtocolState.FAILED) {
312 sendUserAuthFailure(false);
313 } else if (result == AuthenticationProtocolState.COMPLETE) {
314 completedAuthentications.add(auth.getMethodName());
315
316 ServerConfiguration sc = (ServerConfiguration) ConfigurationLoader.getConfiguration(ServerConfiguration.class);
317 Iterator it = sc.getRequiredAuthentications()
318 .iterator();
319
320 while (it.hasNext()) {
321 if (!completedAuthentications.contains(
322 it.next())) {
323 sendUserAuthFailure(true);
324
325 return;
326 }
327 }
328
329 thread.setUsername(msg.getUsername());
330 sendUserAuthSuccess();
331 } else {
332 // Authentication probably returned READY as no completion
333 // evaluation was needed
334 }
335 } else {
336 sendUserAuthFailure(false);
337 }
338 } else {
339 sendUserAuthFailure(false);
340 }
341
342 attempts++;
343 }
344 }
345 }
346 }