blob: a06d3adeeba59f1b429e0a3303ed21b3f911517b [file] [log] [blame]
package org.apache.clerezza.sshshell;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.security.auth.Subject;
import org.apache.clerezza.shell.Shell;
import org.apache.clerezza.shell.ShellFactory;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sshd.*;
import org.apache.sshd.common.Factory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.apache.stanbol.commons.security.UserUtil;
import org.apache.stanbol.commons.security.auth.AuthenticationChecker;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Hello world!
*/
@Component(metatype = true, enabled = true)
public class SshShell {
@Property(intValue = 8022, description = "The port on which the ssh service listens)")
public static final String PORT = "port";
@Reference
private ShellFactory shellFactory;
@Reference
AuthenticationChecker authenticationChecker;
public int port = 8022;
private SshServer sshd;
private static ThreadLocal<Subject> currentSubject = new ThreadLocal<Subject>();
private static Logger log = LoggerFactory.getLogger(SshShell.class);
public SshShell() {
sshd = SshServer.setUpDefaultServer();
File clerezzaUserConfigDir = new File(new File(System.getProperty("user.home")), ".clerezza");
if (!clerezzaUserConfigDir.exists()) {
clerezzaUserConfigDir.mkdir();
}
File hostKeyDir = new File(clerezzaUserConfigDir, "ssh");
if (!hostKeyDir.exists()) {
hostKeyDir.mkdir();
}
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File(hostKeyDir,"hostkey.ser").getAbsolutePath()));
sshd.setPasswordAuthenticator(new MyPasswordAuthenticator());
}
protected void activate(ComponentContext cc) throws IOException {
port = (Integer) cc.getProperties().get(PORT);
sshd.setPort(port);
sshd.setShellFactory(new Factory<Command>() {
@Override
public Command create() {
return new Command() {
private InputStream in;
private OutputStream out;
private Shell shell;
private ExitCallback ec;
@Override
public void setInputStream(InputStream in) {
this.in = in;
}
@Override
public void setOutputStream(OutputStream out) {
this.out = out;
}
@Override
public void setErrorStream(OutputStream out) {
}
@Override
public void setExitCallback(ExitCallback ec) {
this.ec = ec;
}
@Override
public void start(Environment e) throws IOException {
final OutputStream newLineWrapperStream = new OutputStream() {
@Override
public void write(int b) throws IOException {
if (b == '\n') {
out.write('\r');
out.write('\n');
} else {
out.write(b);
}
}
@Override
public void flush() throws IOException {
out.flush();
}
@Override
public void close() throws IOException {
out.close();
}
};
Subject subject = currentSubject.get();
log.debug("doing as {}", subject);
try {
Subject.doAsPrivileged(subject, new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
shell = shellFactory.createShell(in, newLineWrapperStream);
shell.addTerminationListener(new Shell.TerminationListener() {
public void terminated() {
ec.onExit(0);
}
});
shell.start();
return null;
}
}, null);
} catch (PrivilegedActionException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else {
throw new RuntimeException(cause);
}
}
}
@Override
public void destroy() {
if (shell != null) {
shell.stop();
}
shell = null;
}
};
}
});
sshd.start();
}
protected void deactivate(ComponentContext cc) throws Exception {
sshd.stop();
}
private class MyPasswordAuthenticator implements PasswordAuthenticator {
public MyPasswordAuthenticator() {
}
@Override
public boolean authenticate(String userName, String password, ServerSession ss) {
log.debug("Authenticating {}, {}.", userName, password);
try {
if (authenticationChecker.authenticate(userName, password)) {
Subject subject = UserUtil.createSubject(userName);
currentSubject.set(subject);
return true;
} else {
return false;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}