Home | History | Annotate | Download | only in fake
      1 /*
      2  * Copyright 2008 the original author or authors.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package org.mockftpserver.fake;
     17 
     18 import org.mockftpserver.core.util.Assert;
     19 import org.mockftpserver.fake.filesystem.FileSystemEntry;
     20 import org.mockftpserver.fake.filesystem.Permissions;
     21 
     22 import java.util.List;
     23 
     24 /**
     25  * Represents a single user account on the server, including the username, password, home
     26  * directory, list of groups to which this user belongs, and default permissions applied to
     27  * newly-created files and directories.
     28  * <p/>
     29  * The <code>username</code> and <code>homeDirectory</code> property must be non-null
     30  * and non-empty. The <code>homeDirectory</code> property must also match the name of an existing
     31  * directory within the file system configured for the <code>FakeFtpServer</code>.
     32  * <p/>
     33  * The group name applied to newly created files/directories is determined by the <code>groups</code> property.
     34  * If null or empty, then the default group name ("users") is used. Otherwise, the first value in the
     35  * <code>groups</code> List is used. The <code>groups</code> property defaults to an empty List.
     36  * <p/>
     37  * The default value for <code>defaultPermissionsForNewFile</code> is read and write permissions for
     38  * all (user/group/world). The default value for <code>defaultPermissionsForNewDirectory</code> is read,
     39  * write and execute permissions for all (user/group/world).
     40  * <p/>
     41  * The <code>isValidPassword()</code> method returns true if the specified password matches
     42  * the password value configured for this user account. This implementation uses the
     43  * <code>isEquals()</code> method to compare passwords.
     44  * <p/>
     45  * If you want to provide a custom comparison, for instance using encrypted passwords, you can
     46  * subclass this class and override the <code>comparePassword()</code> method to provide your own
     47  * custom implementation.
     48  * <p/>
     49  * If the <code>passwordCheckedDuringValidation</code> property is set to false, then the password
     50  * value is ignored, and the <code>isValidPassword()</code> method just returns <code<true</code>.
     51  * <p/>
     52  * The <code>accountRequiredForLogin</code> property defaults to false. If it is set to true, then
     53  * it is expected that the login for this account will require an ACCOUNT (ACCT) command after the
     54  * PASSWORD (PASS) command is completed.
     55  */
     56 public class UserAccount {
     57 
     58     public static final String DEFAULT_USER = "system";
     59     public static final String DEFAULT_GROUP = "users";
     60     public static final Permissions DEFAULT_PERMISSIONS_FOR_NEW_FILE = new Permissions("rw-rw-rw-");
     61     public static final Permissions DEFAULT_PERMISSIONS_FOR_NEW_DIRECTORY = Permissions.ALL;
     62 
     63     private String username;
     64     private String password;
     65     private String homeDirectory;
     66     private List groups;
     67     private boolean passwordRequiredForLogin = true;
     68     private boolean passwordCheckedDuringValidation = true;
     69     private boolean accountRequiredForLogin = false;
     70     private Permissions defaultPermissionsForNewFile = DEFAULT_PERMISSIONS_FOR_NEW_FILE;
     71     private Permissions defaultPermissionsForNewDirectory = DEFAULT_PERMISSIONS_FOR_NEW_DIRECTORY;
     72 
     73 
     74     /**
     75      * Construct a new uninitialized instance.
     76      */
     77     public UserAccount() {
     78     }
     79 
     80     /**
     81      * Construct a new initialized instance.
     82      *
     83      * @param username      - the user name
     84      * @param password      - the password
     85      * @param homeDirectory - the home directory
     86      */
     87     public UserAccount(String username, String password, String homeDirectory) {
     88         setUsername(username);
     89         setPassword(password);
     90         setHomeDirectory(homeDirectory);
     91     }
     92 
     93     public String getUsername() {
     94         return username;
     95     }
     96 
     97     public void setUsername(String username) {
     98         this.username = username;
     99     }
    100 
    101     public String getPassword() {
    102         return password;
    103     }
    104 
    105     public void setPassword(String password) {
    106         this.password = password;
    107     }
    108 
    109     public String getHomeDirectory() {
    110         return homeDirectory;
    111     }
    112 
    113     public void setHomeDirectory(String homeDirectory) {
    114         this.homeDirectory = homeDirectory;
    115     }
    116 
    117     public List getGroups() {
    118         return groups;
    119     }
    120 
    121     public void setGroups(List groups) {
    122         this.groups = groups;
    123     }
    124 
    125     public boolean isPasswordRequiredForLogin() {
    126         return passwordRequiredForLogin;
    127     }
    128 
    129     public void setPasswordRequiredForLogin(boolean passwordRequiredForLogin) {
    130         this.passwordRequiredForLogin = passwordRequiredForLogin;
    131     }
    132 
    133     public boolean isPasswordCheckedDuringValidation() {
    134         return passwordCheckedDuringValidation;
    135     }
    136 
    137     public void setPasswordCheckedDuringValidation(boolean passwordCheckedDuringValidation) {
    138         this.passwordCheckedDuringValidation = passwordCheckedDuringValidation;
    139     }
    140 
    141     public boolean isAccountRequiredForLogin() {
    142         return accountRequiredForLogin;
    143     }
    144 
    145     public void setAccountRequiredForLogin(boolean accountRequiredForLogin) {
    146         this.accountRequiredForLogin = accountRequiredForLogin;
    147     }
    148 
    149     public Permissions getDefaultPermissionsForNewFile() {
    150         return defaultPermissionsForNewFile;
    151     }
    152 
    153     public void setDefaultPermissionsForNewFile(Permissions defaultPermissionsForNewFile) {
    154         this.defaultPermissionsForNewFile = defaultPermissionsForNewFile;
    155     }
    156 
    157     public Permissions getDefaultPermissionsForNewDirectory() {
    158         return defaultPermissionsForNewDirectory;
    159     }
    160 
    161     public void setDefaultPermissionsForNewDirectory(Permissions defaultPermissionsForNewDirectory) {
    162         this.defaultPermissionsForNewDirectory = defaultPermissionsForNewDirectory;
    163     }
    164 
    165     /**
    166      * Return the name of the primary group to which this user belongs. If this account has no associated
    167      * groups set, then this method returns the <code>DEFAULT_GROUP</code>. Otherwise, this method
    168      * returns the first group name in the <code>groups</code> list.
    169      *
    170      * @return the name of the primary group for this user
    171      */
    172     public String getPrimaryGroup() {
    173         return (groups == null || groups.isEmpty()) ? DEFAULT_GROUP : (String) groups.get(0);
    174     }
    175 
    176     /**
    177      * Return true if the specified password is the correct, valid password for this user account.
    178      * This implementation uses standard (case-sensitive) String comparison. Subclasses can provide
    179      * custom comparison behavior, for instance using encrypted password values, by overriding this
    180      * method.
    181      *
    182      * @param password - the password to compare against the configured value
    183      * @return true if the password is correct and valid
    184      * @throws org.mockftpserver.core.util.AssertFailedException
    185      *          - if the username property is null
    186      */
    187     public boolean isValidPassword(String password) {
    188         Assert.notNullOrEmpty(username, "username");
    189         return !passwordCheckedDuringValidation || comparePassword(password);
    190     }
    191 
    192     /**
    193      * @return true if this UserAccount object is valid; i.e. if the homeDirectory is non-null and non-empty.
    194      */
    195     public boolean isValid() {
    196         return homeDirectory != null && homeDirectory.length() > 0;
    197     }
    198 
    199     /**
    200      * @return the String representation of this object
    201      */
    202     public String toString() {
    203         return "UserAccount[username=" + username + "; password=" + password + "; homeDirectory="
    204                 + homeDirectory + "; passwordRequiredForLogin=" + passwordRequiredForLogin + "]";
    205     }
    206 
    207     /**
    208      * Return true if this user has read access to the file/directory represented by the specified FileSystemEntry object.
    209      *
    210      * @param entry - the FileSystemEntry representing the file or directory
    211      * @return true if this use has read access
    212      */
    213     public boolean canRead(FileSystemEntry entry) {
    214         Permissions permissions = entry.getPermissions();
    215         if (permissions == null) {
    216             return true;
    217         }
    218 
    219         if (equalOrBothNull(username, entry.getOwner())) {
    220             return permissions.canUserRead();
    221         }
    222         if (groups != null && groups.contains(entry.getGroup())) {
    223             return permissions.canGroupRead();
    224         }
    225         return permissions.canWorldRead();
    226     }
    227 
    228     /**
    229      * Return true if this user has write access to the file/directory represented by the specified FileSystemEntry object.
    230      *
    231      * @param entry - the FileSystemEntry representing the file or directory
    232      * @return true if this use has write access
    233      */
    234     public boolean canWrite(FileSystemEntry entry) {
    235         Permissions permissions = entry.getPermissions();
    236         if (permissions == null) {
    237             return true;
    238         }
    239 
    240         if (equalOrBothNull(username, entry.getOwner())) {
    241             return permissions.canUserWrite();
    242         }
    243         if (groups != null && groups.contains(entry.getGroup())) {
    244             return permissions.canGroupWrite();
    245         }
    246         return permissions.canWorldWrite();
    247     }
    248 
    249     /**
    250      * Return true if this user has execute access to the file/directory represented by the specified FileSystemEntry object.
    251      *
    252      * @param entry - the FileSystemEntry representing the file or directory
    253      * @return true if this use has execute access
    254      */
    255     public boolean canExecute(FileSystemEntry entry) {
    256         Permissions permissions = entry.getPermissions();
    257         if (permissions == null) {
    258             return true;
    259         }
    260 
    261         if (equalOrBothNull(username, entry.getOwner())) {
    262             return permissions.canUserExecute();
    263         }
    264         if (groups != null && groups.contains(entry.getGroup())) {
    265             return permissions.canGroupExecute();
    266         }
    267         return permissions.canWorldExecute();
    268     }
    269 
    270     /**
    271      * Return true if the specified password matches the password configured for this user account.
    272      * This implementation uses standard (case-sensitive) String comparison. Subclasses can provide
    273      * custom comparison behavior, for instance using encrypted password values, by overriding this
    274      * method.
    275      *
    276      * @param password - the password to compare against the configured value
    277      * @return true if the passwords match
    278      */
    279     protected boolean comparePassword(String password) {
    280         return password != null && password.equals(this.password);
    281     }
    282 
    283     /**
    284      * Return true only if both Strings are null or they are equal (have the same contents).
    285      *
    286      * @param string1 - the first String
    287      * @param string2 - the second String
    288      * @return true if both are null or both are equal
    289      */
    290     protected boolean equalOrBothNull(String string1, String string2) {
    291         return (string1 == null && string2 == null) || (string1 != null && string1.equals(string2));
    292     }
    293 
    294 }