001: /*
002: * SSHTools - Java SSH2 API
003: *
004: * Copyright (C) 2002-2003 Lee David Painter and Contributors.
005: *
006: * Contributions made by:
007: *
008: * Brett Smith
009: * Richard Pernavas
010: * Erwin Bolwidt
011: *
012: * This program is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU General Public License
014: * as published by the Free Software Foundation; either version 2
015: * of the License, or (at your option) any later version.
016: *
017: * This program is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
020: * GNU General Public License for more details.
021: *
022: * You should have received a copy of the GNU General Public License
023: * along with this program; if not, write to the Free Software
024: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
025: */
026: package com.sshtools.daemon.authentication;
027:
028: import com.sshtools.daemon.configuration.*;
029: import com.sshtools.daemon.platform.*;
030:
031: import com.sshtools.j2ssh.*;
032: import com.sshtools.j2ssh.authentication.*;
033: import com.sshtools.j2ssh.configuration.*;
034: import com.sshtools.j2ssh.transport.*;
035:
036: import org.apache.commons.logging.*;
037:
038: import java.io.*;
039:
040: import java.util.*;
041:
042: /**
043: *
044: *
045: * @author $author$
046: * @version $Revision: 1.11 $
047: */
048: public class AuthenticationProtocolServer extends AsyncService {
049: private static Log log = LogFactory
050: .getLog(AuthenticationProtocolServer.class);
051: private List completedAuthentications = new ArrayList();
052: private Map acceptServices = new HashMap();
053: private List availableAuths;
054: private String serviceToStart;
055: private int[] messageFilter = new int[1];
056: private SshMessageStore methodMessages = new SshMessageStore();
057: private int attempts = 0;
058: private boolean completed = false;
059:
060: /**
061: * Creates a new AuthenticationProtocolServer object.
062: */
063: public AuthenticationProtocolServer() {
064: super ("ssh-userauth");
065: messageFilter[0] = SshMsgUserAuthRequest.SSH_MSG_USERAUTH_REQUEST;
066: }
067:
068: /**
069: *
070: *
071: * @throws java.io.IOException
072: */
073: protected void onServiceAccept() throws java.io.IOException {
074: }
075:
076: /**
077: *
078: *
079: * @param startMode
080: *
081: * @throws java.io.IOException
082: */
083: protected void onServiceInit(int startMode)
084: throws java.io.IOException {
085: // Register the required messages
086: messageStore.registerMessage(
087: SshMsgUserAuthRequest.SSH_MSG_USERAUTH_REQUEST,
088: SshMsgUserAuthRequest.class);
089: transport.addMessageStore(methodMessages);
090: }
091:
092: /**
093: *
094: *
095: * @return
096: */
097: public byte[] getSessionIdentifier() {
098: return transport.getSessionIdentifier();
099: }
100:
101: /**
102: *
103: *
104: * @return
105: */
106: public TransportProtocolState getConnectionState() {
107: return transport.getState();
108: }
109:
110: /**
111: *
112: *
113: * @param msg
114: *
115: * @throws IOException
116: */
117: public void sendMessage(SshMessage msg) throws IOException {
118: transport.sendMessage(msg, this );
119: }
120:
121: /**
122: *
123: *
124: * @return
125: *
126: * @throws IOException
127: * @throws SshException
128: */
129: public SshMessage readMessage() throws IOException {
130: try {
131: return methodMessages.nextMessage();
132: } catch (InterruptedException ex) {
133: throw new SshException("The thread was interrupted");
134: }
135: }
136:
137: /**
138: *
139: *
140: * @param messageId
141: * @param cls
142: */
143: public void registerMessage(int messageId, Class cls) {
144: methodMessages.registerMessage(messageId, cls);
145: }
146:
147: /**
148: *
149: *
150: * @throws java.io.IOException
151: * @throws AuthenticationProtocolException
152: */
153: protected void onServiceRequest() throws java.io.IOException {
154: // Send a user auth banner if configured
155: ServerConfiguration server = (ServerConfiguration) ConfigurationLoader
156: .getConfiguration(ServerConfiguration.class);
157:
158: if (server == null) {
159: throw new AuthenticationProtocolException(
160: "Server configuration unavailable");
161: }
162:
163: availableAuths = new ArrayList();
164:
165: Iterator it = SshAuthenticationServerFactory
166: .getSupportedMethods().iterator();
167: String method;
168: List allowed = server.getAllowedAuthentications();
169:
170: while (it.hasNext()) {
171: method = (String) it.next();
172:
173: if (allowed.contains(method)) {
174: availableAuths.add(method);
175: }
176: }
177:
178: if (availableAuths.size() <= 0) {
179: throw new AuthenticationProtocolException(
180: "No valid authentication methods have been specified");
181: }
182:
183: // Accept the service request
184: sendServiceAccept();
185:
186: String bannerFile = server.getAuthenticationBanner();
187:
188: if (bannerFile != null) {
189: if (bannerFile.length() > 0) {
190: InputStream in = ConfigurationLoader
191: .loadFile(bannerFile);
192:
193: if (in != null) {
194: byte[] data = new byte[in.available()];
195: in.read(data);
196: in.close();
197:
198: SshMsgUserAuthBanner bannerMsg = new SshMsgUserAuthBanner(
199: new String(data));
200: transport.sendMessage(bannerMsg, this );
201: } else {
202: log.info("The banner file '" + bannerFile
203: + "' was not found");
204: }
205: }
206: }
207: }
208:
209: /**
210: *
211: *
212: * @param msg
213: *
214: * @throws java.io.IOException
215: * @throws AuthenticationProtocolException
216: */
217: protected void onMessageReceived(SshMessage msg)
218: throws java.io.IOException {
219: switch (msg.getMessageId()) {
220: case SshMsgUserAuthRequest.SSH_MSG_USERAUTH_REQUEST: {
221: onMsgUserAuthRequest((SshMsgUserAuthRequest) msg);
222:
223: break;
224: }
225:
226: default:
227: throw new AuthenticationProtocolException(
228: "Unregistered message received!");
229: }
230: }
231:
232: /**
233: *
234: *
235: * @return
236: */
237: protected int[] getAsyncMessageFilter() {
238: return messageFilter;
239: }
240:
241: /**
242: *
243: *
244: * @param service
245: */
246: public void acceptService(Service service) {
247: acceptServices.put(service.getServiceName(), service);
248: }
249:
250: private void sendUserAuthFailure(boolean success)
251: throws IOException {
252: Iterator it = availableAuths.iterator();
253: String auths = null;
254:
255: while (it.hasNext()) {
256: auths = ((auths == null) ? "" : (auths + ","))
257: + (String) it.next();
258: }
259:
260: SshMsgUserAuthFailure reply = new SshMsgUserAuthFailure(auths,
261: success);
262: transport.sendMessage(reply, this );
263: }
264:
265: /**
266: *
267: */
268: protected void onStop() {
269: try {
270: // If authentication succeeded then wait for the
271: // disconnect and logoff the user
272: if (completed) {
273: try {
274: transport.getState().waitForState(
275: TransportProtocolState.DISCONNECTED);
276: } catch (InterruptedException ex) {
277: log
278: .warn("The authentication service was interrupted");
279: }
280:
281: NativeAuthenticationProvider nap = NativeAuthenticationProvider
282: .getInstance();
283: nap.logoffUser();
284: }
285: } catch (IOException ex) {
286: log.warn("Failed to logoff "
287: + SshThread.getCurrentThreadUser());
288: }
289: }
290:
291: private void sendUserAuthSuccess() throws IOException {
292: SshMsgUserAuthSuccess msg = new SshMsgUserAuthSuccess();
293: Service service = (Service) acceptServices.get(serviceToStart);
294: service.init(Service.ACCEPTING_SERVICE, transport); //, nativeSettings);
295: service.start();
296: transport.sendMessage(msg, this );
297: completed = true;
298: stop();
299: }
300:
301: private void onMsgUserAuthRequest(SshMsgUserAuthRequest msg)
302: throws IOException {
303: if (msg.getMethodName().equals("none")) {
304: sendUserAuthFailure(false);
305: } else {
306: if (attempts >= ((ServerConfiguration) ConfigurationLoader
307: .getConfiguration(ServerConfiguration.class))
308: .getMaxAuthentications()) {
309: // Too many authentication attempts
310: transport
311: .disconnect("Too many failed authentication attempts");
312: } else {
313: // If the service is supported then perfrom the authentication
314: if (acceptServices.containsKey(msg.getServiceName())) {
315: String method = msg.getMethodName();
316:
317: if (availableAuths.contains(method)) {
318: SshAuthenticationServer auth = SshAuthenticationServerFactory
319: .newInstance(method);
320: serviceToStart = msg.getServiceName();
321:
322: //auth.setUsername(msg.getUsername());
323: int result = auth.authenticate(this , msg); //, nativeSettings);
324:
325: if (result == AuthenticationProtocolState.FAILED) {
326: sendUserAuthFailure(false);
327: } else if (result == AuthenticationProtocolState.COMPLETE) {
328: completedAuthentications.add(auth
329: .getMethodName());
330:
331: ServerConfiguration sc = (ServerConfiguration) ConfigurationLoader
332: .getConfiguration(ServerConfiguration.class);
333: Iterator it = sc
334: .getRequiredAuthentications()
335: .iterator();
336:
337: while (it.hasNext()) {
338: if (!completedAuthentications
339: .contains(it.next())) {
340: sendUserAuthFailure(true);
341:
342: return;
343: }
344: }
345:
346: thread.setUsername(msg.getUsername());
347: sendUserAuthSuccess();
348: } else {
349: // Authentication probably returned READY as no completion
350: // evaluation was needed
351: }
352: } else {
353: sendUserAuthFailure(false);
354: }
355: } else {
356: sendUserAuthFailure(false);
357: }
358:
359: attempts++;
360: }
361: }
362: }
363: }
|