package ftp.service;
import org.apache.ftpserver.ftplet.*;
import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.io.File;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
public class FtpUserManager implements UserManager {
private static final AtomicReference<FtpUserManager> ROOT_FS = new AtomicReference<>();
private final FtpUserRepository ftpUserRepository;
private final File rootFileSystem;
public FtpUserManager(FtpUserRepository ftpUserRepository, File rootFileSystem) {
this.ftpUserRepository = ftpUserRepository;
this.rootFileSystem = rootFileSystem;
ROOT_FS.compareAndSet(null, this);
}
public static File getHomeDirectory(String username) {
FtpUserManager ftpUserManager = ROOT_FS.get();
return ftpUserManager.getHomeDirectoryFor(username);
}
public File getHomeDirectoryFor(String username) {
return this.ftpUserRepository.findByUsername(username)
.map(u -> new File(this.rootFileSystem, u.getWorkspace()))
.orElseThrow(() -> new IllegalArgumentException(username + " doesn't exist"));
}
@Override
public User getUserByName(String s) throws FtpException {
return this.ftpUserRepository.findByUsername(s).orElse(null);
}
@Override
public String[] getAllUserNames() throws FtpException {
List<String> collect = this.ftpUserRepository.findAll()
.stream()
.map(FtpUser::getName)
.collect(Collectors.toList());
return collect.toArray(new String[collect.size()]);
}
@Override
public void delete(String s) throws FtpException {
this.ftpUserRepository.findByUsername(s).ifPresent(this.ftpUserRepository::delete);
}
@Override
public void save(User user) throws FtpException {
Class<FtpUser> ftpUserClass = FtpUser.class;
Assert.isInstanceOf(ftpUserClass, user);
FtpUser ftpUser = ftpUserClass.cast(user);
this.ftpUserRepository.save(ftpUser);
}
@Override
public boolean doesExist(String s) throws FtpException {
return this.ftpUserRepository.findByUsername(s).isPresent();
}
private void assertAboutAuthentication(boolean condition, String msg) throws AuthenticationFailedException {
if (!condition) throw new AuthenticationFailedException(msg);
}
@Override
public User authenticate(Authentication authentication) throws AuthenticationFailedException {
Class<UsernamePasswordAuthentication> authenticationClass = UsernamePasswordAuthentication.class;
assertAboutAuthentication(authenticationClass.isAssignableFrom(authentication.getClass()),
"you must login using a username and password");
UsernamePasswordAuthentication auth = authenticationClass.cast(authentication);
assertAboutAuthentication(StringUtils.hasText(auth.getUsername()), "you must provide a username");
assertAboutAuthentication(StringUtils.hasText(auth.getPassword()), "you must provide a password");
return this.ftpUserRepository.findByUsername(auth.getUsername())
.filter(u -> u.getPassword().equals(auth.getPassword()))
.orElseThrow(() -> new AuthenticationFailedException(
"the provided username and password is invalid"));
}
@Override
public String getAdminName() throws FtpException {
return "admin";
}
@Override
public boolean isAdmin(String s) throws FtpException {
return getAdminName().equals(s);
}
}