/* | |
* Copyright 2008 the original author or authors. | |
* | |
* Licensed 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. | |
*/ | |
package org.mockftpserver.fake; | |
import org.mockftpserver.core.util.Assert; | |
import org.mockftpserver.fake.filesystem.FileSystemEntry; | |
import org.mockftpserver.fake.filesystem.Permissions; | |
import java.util.List; | |
/** | |
* Represents a single user account on the server, including the username, password, home | |
* directory, list of groups to which this user belongs, and default permissions applied to | |
* newly-created files and directories. | |
* <p/> | |
* The <code>username</code> and <code>homeDirectory</code> property must be non-null | |
* and non-empty. The <code>homeDirectory</code> property must also match the name of an existing | |
* directory within the file system configured for the <code>FakeFtpServer</code>. | |
* <p/> | |
* The group name applied to newly created files/directories is determined by the <code>groups</code> property. | |
* If null or empty, then the default group name ("users") is used. Otherwise, the first value in the | |
* <code>groups</code> List is used. The <code>groups</code> property defaults to an empty List. | |
* <p/> | |
* The default value for <code>defaultPermissionsForNewFile</code> is read and write permissions for | |
* all (user/group/world). The default value for <code>defaultPermissionsForNewDirectory</code> is read, | |
* write and execute permissions for all (user/group/world). | |
* <p/> | |
* The <code>isValidPassword()</code> method returns true if the specified password matches | |
* the password value configured for this user account. This implementation uses the | |
* <code>isEquals()</code> method to compare passwords. | |
* <p/> | |
* If you want to provide a custom comparison, for instance using encrypted passwords, you can | |
* subclass this class and override the <code>comparePassword()</code> method to provide your own | |
* custom implementation. | |
* <p/> | |
* If the <code>passwordCheckedDuringValidation</code> property is set to false, then the password | |
* value is ignored, and the <code>isValidPassword()</code> method just returns <code<true</code>. | |
* <p/> | |
* The <code>accountRequiredForLogin</code> property defaults to false. If it is set to true, then | |
* it is expected that the login for this account will require an ACCOUNT (ACCT) command after the | |
* PASSWORD (PASS) command is completed. | |
*/ | |
public class UserAccount { | |
public static final String DEFAULT_USER = "system"; | |
public static final String DEFAULT_GROUP = "users"; | |
public static final Permissions DEFAULT_PERMISSIONS_FOR_NEW_FILE = new Permissions("rw-rw-rw-"); | |
public static final Permissions DEFAULT_PERMISSIONS_FOR_NEW_DIRECTORY = Permissions.ALL; | |
private String username; | |
private String password; | |
private String homeDirectory; | |
private List groups; | |
private boolean passwordRequiredForLogin = true; | |
private boolean passwordCheckedDuringValidation = true; | |
private boolean accountRequiredForLogin = false; | |
private Permissions defaultPermissionsForNewFile = DEFAULT_PERMISSIONS_FOR_NEW_FILE; | |
private Permissions defaultPermissionsForNewDirectory = DEFAULT_PERMISSIONS_FOR_NEW_DIRECTORY; | |
/** | |
* Construct a new uninitialized instance. | |
*/ | |
public UserAccount() { | |
} | |
/** | |
* Construct a new initialized instance. | |
* | |
* @param username - the user name | |
* @param password - the password | |
* @param homeDirectory - the home directory | |
*/ | |
public UserAccount(String username, String password, String homeDirectory) { | |
setUsername(username); | |
setPassword(password); | |
setHomeDirectory(homeDirectory); | |
} | |
public String getUsername() { | |
return username; | |
} | |
public void setUsername(String username) { | |
this.username = username; | |
} | |
public String getPassword() { | |
return password; | |
} | |
public void setPassword(String password) { | |
this.password = password; | |
} | |
public String getHomeDirectory() { | |
return homeDirectory; | |
} | |
public void setHomeDirectory(String homeDirectory) { | |
this.homeDirectory = homeDirectory; | |
} | |
public List getGroups() { | |
return groups; | |
} | |
public void setGroups(List groups) { | |
this.groups = groups; | |
} | |
public boolean isPasswordRequiredForLogin() { | |
return passwordRequiredForLogin; | |
} | |
public void setPasswordRequiredForLogin(boolean passwordRequiredForLogin) { | |
this.passwordRequiredForLogin = passwordRequiredForLogin; | |
} | |
public boolean isPasswordCheckedDuringValidation() { | |
return passwordCheckedDuringValidation; | |
} | |
public void setPasswordCheckedDuringValidation(boolean passwordCheckedDuringValidation) { | |
this.passwordCheckedDuringValidation = passwordCheckedDuringValidation; | |
} | |
public boolean isAccountRequiredForLogin() { | |
return accountRequiredForLogin; | |
} | |
public void setAccountRequiredForLogin(boolean accountRequiredForLogin) { | |
this.accountRequiredForLogin = accountRequiredForLogin; | |
} | |
public Permissions getDefaultPermissionsForNewFile() { | |
return defaultPermissionsForNewFile; | |
} | |
public void setDefaultPermissionsForNewFile(Permissions defaultPermissionsForNewFile) { | |
this.defaultPermissionsForNewFile = defaultPermissionsForNewFile; | |
} | |
public Permissions getDefaultPermissionsForNewDirectory() { | |
return defaultPermissionsForNewDirectory; | |
} | |
public void setDefaultPermissionsForNewDirectory(Permissions defaultPermissionsForNewDirectory) { | |
this.defaultPermissionsForNewDirectory = defaultPermissionsForNewDirectory; | |
} | |
/** | |
* Return the name of the primary group to which this user belongs. If this account has no associated | |
* groups set, then this method returns the <code>DEFAULT_GROUP</code>. Otherwise, this method | |
* returns the first group name in the <code>groups</code> list. | |
* | |
* @return the name of the primary group for this user | |
*/ | |
public String getPrimaryGroup() { | |
return (groups == null || groups.isEmpty()) ? DEFAULT_GROUP : (String) groups.get(0); | |
} | |
/** | |
* Return true if the specified password is the correct, valid password for this user account. | |
* This implementation uses standard (case-sensitive) String comparison. Subclasses can provide | |
* custom comparison behavior, for instance using encrypted password values, by overriding this | |
* method. | |
* | |
* @param password - the password to compare against the configured value | |
* @return true if the password is correct and valid | |
* @throws org.mockftpserver.core.util.AssertFailedException | |
* - if the username property is null | |
*/ | |
public boolean isValidPassword(String password) { | |
Assert.notNullOrEmpty(username, "username"); | |
return !passwordCheckedDuringValidation || comparePassword(password); | |
} | |
/** | |
* @return true if this UserAccount object is valid; i.e. if the homeDirectory is non-null and non-empty. | |
*/ | |
public boolean isValid() { | |
return homeDirectory != null && homeDirectory.length() > 0; | |
} | |
/** | |
* @return the String representation of this object | |
*/ | |
public String toString() { | |
return "UserAccount[username=" + username + "; password=" + password + "; homeDirectory=" | |
+ homeDirectory + "; passwordRequiredForLogin=" + passwordRequiredForLogin + "]"; | |
} | |
/** | |
* Return true if this user has read access to the file/directory represented by the specified FileSystemEntry object. | |
* | |
* @param entry - the FileSystemEntry representing the file or directory | |
* @return true if this use has read access | |
*/ | |
public boolean canRead(FileSystemEntry entry) { | |
Permissions permissions = entry.getPermissions(); | |
if (permissions == null) { | |
return true; | |
} | |
if (equalOrBothNull(username, entry.getOwner())) { | |
return permissions.canUserRead(); | |
} | |
if (groups != null && groups.contains(entry.getGroup())) { | |
return permissions.canGroupRead(); | |
} | |
return permissions.canWorldRead(); | |
} | |
/** | |
* Return true if this user has write access to the file/directory represented by the specified FileSystemEntry object. | |
* | |
* @param entry - the FileSystemEntry representing the file or directory | |
* @return true if this use has write access | |
*/ | |
public boolean canWrite(FileSystemEntry entry) { | |
Permissions permissions = entry.getPermissions(); | |
if (permissions == null) { | |
return true; | |
} | |
if (equalOrBothNull(username, entry.getOwner())) { | |
return permissions.canUserWrite(); | |
} | |
if (groups != null && groups.contains(entry.getGroup())) { | |
return permissions.canGroupWrite(); | |
} | |
return permissions.canWorldWrite(); | |
} | |
/** | |
* Return true if this user has execute access to the file/directory represented by the specified FileSystemEntry object. | |
* | |
* @param entry - the FileSystemEntry representing the file or directory | |
* @return true if this use has execute access | |
*/ | |
public boolean canExecute(FileSystemEntry entry) { | |
Permissions permissions = entry.getPermissions(); | |
if (permissions == null) { | |
return true; | |
} | |
if (equalOrBothNull(username, entry.getOwner())) { | |
return permissions.canUserExecute(); | |
} | |
if (groups != null && groups.contains(entry.getGroup())) { | |
return permissions.canGroupExecute(); | |
} | |
return permissions.canWorldExecute(); | |
} | |
/** | |
* Return true if the specified password matches the password configured for this user account. | |
* This implementation uses standard (case-sensitive) String comparison. Subclasses can provide | |
* custom comparison behavior, for instance using encrypted password values, by overriding this | |
* method. | |
* | |
* @param password - the password to compare against the configured value | |
* @return true if the passwords match | |
*/ | |
protected boolean comparePassword(String password) { | |
return password != null && password.equals(this.password); | |
} | |
/** | |
* Return true only if both Strings are null or they are equal (have the same contents). | |
* | |
* @param string1 - the first String | |
* @param string2 - the second String | |
* @return true if both are null or both are equal | |
*/ | |
protected boolean equalOrBothNull(String string1, String string2) { | |
return (string1 == null && string2 == null) || (string1 != null && string1.equals(string2)); | |
} | |
} |