/* Copyright (c) 2001 - 2010 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.ftp; import java.io.File; import java.io.IOException; import org.apache.ftpserver.ftplet.DefaultFtplet; import org.apache.ftpserver.ftplet.FileSystemView; import org.apache.ftpserver.ftplet.FtpException; import org.apache.ftpserver.ftplet.FtpFile; import org.apache.ftpserver.ftplet.FtpRequest; import org.apache.ftpserver.ftplet.FtpSession; import org.apache.ftpserver.ftplet.Ftplet; import org.apache.ftpserver.ftplet.FtpletResult; import org.apache.ftpserver.ftplet.User; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; /** * Adapts an {@link FTPCallback}s as an {@link Ftplet} * * @author groldan * @see FtpLetFinder * @see FTPServerManager */ class FtpLetCallBackAdapter extends DefaultFtplet { private final FTPCallback callback; public FtpLetCallBackAdapter(final FTPCallback callback) { this.callback = callback; } private UserDetails user(User ftpUser) { String username = ftpUser.getName(); String password = ftpUser.getPassword(); boolean isEnabled = ftpUser.getEnabled(); GrantedAuthority[] authorities = new GrantedAuthority[0]; boolean accountNonExpired = true; boolean credentialsNonExpired = true; boolean accountNonLocked = true; UserDetails userDetails = new org.springframework.security.core.userdetails.User(username, password, isEnabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); return userDetails; } /** * Notifies the {@link FTPCallback} of file delete requests * * @see FTPCallback#onDeleteStart */ @Override public FtpletResult onDeleteStart(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onDeleteStart(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} of file deletion success * * @see FTPCallback#onDeleteEnd */ @Override public FtpletResult onDeleteEnd(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onDeleteEnd(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} of file upload requests * * @see FTPCallback#onUploadStart */ @Override public FtpletResult onUploadStart(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onUploadStart(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} of file upload success * * @see FTPCallback#onUploadEnd */ @Override public FtpletResult onUploadEnd(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onUploadEnd(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} of file download requests * * @see FTPCallback#onDownloadStart */ @Override public FtpletResult onDownloadStart(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onDownloadStart(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} of file download success * * @see FTPCallback#onDownloadEnd */ @Override public FtpletResult onDownloadEnd(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onDownloadEnd(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} of remove directory requests * * @see FTPCallback#onRemoveDirStart */ @Override public FtpletResult onRmdirStart(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String dirName = request.getArgument(); return toFtpResult(callback.onRemoveDirStart(user, workingDir, dirName)); } /** * Notifies the {@link FTPCallback} of remove directory success * * @see FTPCallback#onRemoveDirEnd */ @Override public FtpletResult onRmdirEnd(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String dirName = request.getArgument(); return toFtpResult(callback.onRemoveDirEnd(user, workingDir, dirName)); } /** * Notifies the {@link FTPCallback} of make directory requests * * @see FTPCallback#onMakeDirStart */ @Override public FtpletResult onMkdirStart(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String dirName = request.getArgument(); return toFtpResult(callback.onMakeDirStart(user, workingDir, dirName)); } /** * Notifies the {@link FTPCallback} of make directory success * * @see FTPCallback#onMakeDirEnd */ @Override public FtpletResult onMkdirEnd(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String dirName = request.getArgument(); return toFtpResult(callback.onMakeDirEnd(user, workingDir, dirName)); } /** * Notifies the {@link FTPCallback} of requests to append content to an existing file * * @see FTPCallback#onAppendStart */ @Override public FtpletResult onAppendStart(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onAppendStart(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} of a finished request to append content to an existing file * * @see FTPCallback#onAppendEnd */ @Override public FtpletResult onAppendEnd(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onAppendEnd(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} of a "upload unique file" request to the current directory. * <p> * This has effectively the same effect than {@link #onUploadStart(FtpSession, FtpRequest)} for * the purposes of this module? See <a * href="http://www.nsftools.com/tips/RawFTP.htm#STOU">here</a> * </p> * * @see FTPCallback#onUploadStart */ @Override public FtpletResult onUploadUniqueStart(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onUploadStart(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} that an "upload unique file" to the current directory has * finished. * <p> * This has effectively the same effect than {@link #onUploadEnd(FtpSession, FtpRequest)} for * the purposes of this module? See <a * href="http://www.nsftools.com/tips/RawFTP.htm#STOU">here</a> * </p> * * @see FTPCallback#onUploadEnd */ @Override public FtpletResult onUploadUniqueEnd(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); return toFtpResult(callback.onUploadEnd(user, workingDir, fileName)); } /** * Notifies the {@link FTPCallback} of a request to rename a file * * @see FTPCallback#onRenameStart */ @Override public FtpletResult onRenameStart(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); File renameTo = new File(workingDir, fileName); File renameFrom = new File(session.getRenameFrom().getAbsolutePath()); return toFtpResult(callback.onRenameStart(user, workingDir, renameFrom, renameTo)); } /** * Notifies the {@link FTPCallback} that a request to rename a file finished * * @see FTPCallback#onRenameEnd */ @Override public FtpletResult onRenameEnd(FtpSession session, FtpRequest request) throws FtpException, IOException { UserDetails user = user(session.getUser()); File workingDir = workingDir(session); String fileName = request.getArgument(); File renameTo = new File(workingDir, fileName); File renameFrom = new File(session.getRenameFrom().getAbsolutePath()); return toFtpResult(callback.onRenameEnd(user, workingDir, renameFrom, renameTo)); } private static FtpletResult toFtpResult(CallbackAction action) { if (action == null) { return FtpletResult.DEFAULT; } switch (action) { case CONTINUE: return FtpletResult.DEFAULT; case DISCONNECT: return FtpletResult.DISCONNECT; case SKIP: return FtpletResult.SKIP; default: throw new IllegalArgumentException("Unknown FTP Callback action: " + action); } } /** * Extracts the working directory of the current session to an absolute file system path * (contrary to what {@link FileSystemView#getWorkingDirectory() returns, which is relative to * the user's home dir}) */ private File workingDir(FtpSession session) throws FtpException { FtpFile workingDirectory = session.getFileSystemView().getWorkingDirectory(); String home = session.getUser().getHomeDirectory(); String absolutePath = workingDirectory.getAbsolutePath().substring(1); File workingDir = new File(new File(home), absolutePath); return workingDir; } /** * Overrides to disallow SITE commands, so no server administration can be done through the FTP * protocol (like managing users, */ /* * @TODO: REVISIT public FtpletResult onSite(FtpSession session, FtpRequest request) throws * FtpException, IOException { return FtpletResult.SKIP; } */ }