160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair/*
260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * Copyright 2008 the original author or authors.
360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair *
460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * Licensed under the Apache License, Version 2.0 (the "License");
560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * you may not use this file except in compliance with the License.
660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * You may obtain a copy of the License at
760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair *
860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair *      http://www.apache.org/licenses/LICENSE-2.0
960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair *
1060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * Unless required by applicable law or agreed to in writing, software
1160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * distributed under the License is distributed on an "AS IS" BASIS,
1260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * See the License for the specific language governing permissions and
1460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * limitations under the License.
1560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair */
1660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairpackage org.mockftpserver.fake;
1760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
1860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport org.mockftpserver.core.util.Assert;
1960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport org.mockftpserver.fake.filesystem.FileSystemEntry;
2060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport org.mockftpserver.fake.filesystem.Permissions;
2160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
2260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairimport java.util.List;
2360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
2460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair/**
2560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * Represents a single user account on the server, including the username, password, home
2660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * directory, list of groups to which this user belongs, and default permissions applied to
2760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * newly-created files and directories.
2860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <p/>
2960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * The <code>username</code> and <code>homeDirectory</code> property must be non-null
3060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * and non-empty. The <code>homeDirectory</code> property must also match the name of an existing
3160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * directory within the file system configured for the <code>FakeFtpServer</code>.
3260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <p/>
3360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * The group name applied to newly created files/directories is determined by the <code>groups</code> property.
3460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * If null or empty, then the default group name ("users") is used. Otherwise, the first value in the
3560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <code>groups</code> List is used. The <code>groups</code> property defaults to an empty List.
3660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <p/>
3760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * The default value for <code>defaultPermissionsForNewFile</code> is read and write permissions for
3860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * all (user/group/world). The default value for <code>defaultPermissionsForNewDirectory</code> is read,
3960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * write and execute permissions for all (user/group/world).
4060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <p/>
4160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * The <code>isValidPassword()</code> method returns true if the specified password matches
4260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * the password value configured for this user account. This implementation uses the
4360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <code>isEquals()</code> method to compare passwords.
4460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <p/>
4560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * If you want to provide a custom comparison, for instance using encrypted passwords, you can
4660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * subclass this class and override the <code>comparePassword()</code> method to provide your own
4760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * custom implementation.
4860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <p/>
4960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * If the <code>passwordCheckedDuringValidation</code> property is set to false, then the password
5060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * value is ignored, and the <code>isValidPassword()</code> method just returns <code<true</code>.
5160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * <p/>
5260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * The <code>accountRequiredForLogin</code> property defaults to false. If it is set to true, then
5360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * it is expected that the login for this account will require an ACCOUNT (ACCT) command after the
5460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair * PASSWORD (PASS) command is completed.
5560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair */
5660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismairpublic class UserAccount {
5760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
5860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public static final String DEFAULT_USER = "system";
5960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public static final String DEFAULT_GROUP = "users";
6060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public static final Permissions DEFAULT_PERMISSIONS_FOR_NEW_FILE = new Permissions("rw-rw-rw-");
6160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public static final Permissions DEFAULT_PERMISSIONS_FOR_NEW_DIRECTORY = Permissions.ALL;
6260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
6360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private String username;
6460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private String password;
6560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private String homeDirectory;
6660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private List groups;
6760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private boolean passwordRequiredForLogin = true;
6860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private boolean passwordCheckedDuringValidation = true;
6960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private boolean accountRequiredForLogin = false;
7060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private Permissions defaultPermissionsForNewFile = DEFAULT_PERMISSIONS_FOR_NEW_FILE;
7160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    private Permissions defaultPermissionsForNewDirectory = DEFAULT_PERMISSIONS_FOR_NEW_DIRECTORY;
7260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
7360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
7460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
7560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Construct a new uninitialized instance.
7660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
7760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public UserAccount() {
7860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
7960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
8060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
8160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Construct a new initialized instance.
8260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
8360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param username      - the user name
8460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param password      - the password
8560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param homeDirectory - the home directory
8660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
8760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public UserAccount(String username, String password, String homeDirectory) {
8860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        setUsername(username);
8960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        setPassword(password);
9060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        setHomeDirectory(homeDirectory);
9160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
9260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
9360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public String getUsername() {
9460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return username;
9560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
9660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
9760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void setUsername(String username) {
9860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.username = username;
9960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
10060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
10160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public String getPassword() {
10260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return password;
10360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
10460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
10560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void setPassword(String password) {
10660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.password = password;
10760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
10860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
10960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public String getHomeDirectory() {
11060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return homeDirectory;
11160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
11260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
11360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void setHomeDirectory(String homeDirectory) {
11460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.homeDirectory = homeDirectory;
11560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
11660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
11760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public List getGroups() {
11860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return groups;
11960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
12060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
12160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void setGroups(List groups) {
12260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.groups = groups;
12360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
12460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
12560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean isPasswordRequiredForLogin() {
12660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return passwordRequiredForLogin;
12760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
12860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
12960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void setPasswordRequiredForLogin(boolean passwordRequiredForLogin) {
13060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.passwordRequiredForLogin = passwordRequiredForLogin;
13160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
13260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
13360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean isPasswordCheckedDuringValidation() {
13460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return passwordCheckedDuringValidation;
13560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
13660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
13760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void setPasswordCheckedDuringValidation(boolean passwordCheckedDuringValidation) {
13860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.passwordCheckedDuringValidation = passwordCheckedDuringValidation;
13960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
14060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
14160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean isAccountRequiredForLogin() {
14260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return accountRequiredForLogin;
14360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
14460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
14560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void setAccountRequiredForLogin(boolean accountRequiredForLogin) {
14660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.accountRequiredForLogin = accountRequiredForLogin;
14760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
14860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
14960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public Permissions getDefaultPermissionsForNewFile() {
15060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return defaultPermissionsForNewFile;
15160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
15260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
15360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void setDefaultPermissionsForNewFile(Permissions defaultPermissionsForNewFile) {
15460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.defaultPermissionsForNewFile = defaultPermissionsForNewFile;
15560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
15660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
15760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public Permissions getDefaultPermissionsForNewDirectory() {
15860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return defaultPermissionsForNewDirectory;
15960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
16060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
16160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public void setDefaultPermissionsForNewDirectory(Permissions defaultPermissionsForNewDirectory) {
16260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        this.defaultPermissionsForNewDirectory = defaultPermissionsForNewDirectory;
16360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
16460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
16560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
16660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Return the name of the primary group to which this user belongs. If this account has no associated
16760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * groups set, then this method returns the <code>DEFAULT_GROUP</code>. Otherwise, this method
16860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * returns the first group name in the <code>groups</code> list.
16960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
17060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return the name of the primary group for this user
17160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
17260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public String getPrimaryGroup() {
17360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return (groups == null || groups.isEmpty()) ? DEFAULT_GROUP : (String) groups.get(0);
17460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
17560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
17660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
17760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Return true if the specified password is the correct, valid password for this user account.
17860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * This implementation uses standard (case-sensitive) String comparison. Subclasses can provide
17960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * custom comparison behavior, for instance using encrypted password values, by overriding this
18060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * method.
18160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
18260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param password - the password to compare against the configured value
18360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return true if the password is correct and valid
18460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @throws org.mockftpserver.core.util.AssertFailedException
18560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *          - if the username property is null
18660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
18760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean isValidPassword(String password) {
18860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        Assert.notNullOrEmpty(username, "username");
18960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return !passwordCheckedDuringValidation || comparePassword(password);
19060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
19160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
19260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
19360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return true if this UserAccount object is valid; i.e. if the homeDirectory is non-null and non-empty.
19460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
19560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean isValid() {
19660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return homeDirectory != null && homeDirectory.length() > 0;
19760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
19860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
19960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
20060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return the String representation of this object
20160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
20260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public String toString() {
20360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return "UserAccount[username=" + username + "; password=" + password + "; homeDirectory="
20460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair                + homeDirectory + "; passwordRequiredForLogin=" + passwordRequiredForLogin + "]";
20560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
20660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
20760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
20860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Return true if this user has read access to the file/directory represented by the specified FileSystemEntry object.
20960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
21060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param entry - the FileSystemEntry representing the file or directory
21160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return true if this use has read access
21260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
21360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean canRead(FileSystemEntry entry) {
21460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        Permissions permissions = entry.getPermissions();
21560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        if (permissions == null) {
21660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair            return true;
21760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        }
21860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
21960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        if (equalOrBothNull(username, entry.getOwner())) {
22060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair            return permissions.canUserRead();
22160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        }
22260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        if (groups != null && groups.contains(entry.getGroup())) {
22360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair            return permissions.canGroupRead();
22460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        }
22560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return permissions.canWorldRead();
22660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
22760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
22860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
22960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Return true if this user has write access to the file/directory represented by the specified FileSystemEntry object.
23060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
23160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param entry - the FileSystemEntry representing the file or directory
23260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return true if this use has write access
23360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
23460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean canWrite(FileSystemEntry entry) {
23560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        Permissions permissions = entry.getPermissions();
23660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        if (permissions == null) {
23760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair            return true;
23860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        }
23960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
24060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        if (equalOrBothNull(username, entry.getOwner())) {
24160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair            return permissions.canUserWrite();
24260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        }
24360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        if (groups != null && groups.contains(entry.getGroup())) {
24460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair            return permissions.canGroupWrite();
24560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        }
24660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return permissions.canWorldWrite();
24760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
24860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
24960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
25060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Return true if this user has execute access to the file/directory represented by the specified FileSystemEntry object.
25160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
25260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param entry - the FileSystemEntry representing the file or directory
25360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return true if this use has execute access
25460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
25560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    public boolean canExecute(FileSystemEntry entry) {
25660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        Permissions permissions = entry.getPermissions();
25760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        if (permissions == null) {
25860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair            return true;
25960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        }
26060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
26160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        if (equalOrBothNull(username, entry.getOwner())) {
26260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair            return permissions.canUserExecute();
26360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        }
26460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        if (groups != null && groups.contains(entry.getGroup())) {
26560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair            return permissions.canGroupExecute();
26660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        }
26760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return permissions.canWorldExecute();
26860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
26960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
27060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
27160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Return true if the specified password matches the password configured for this user account.
27260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * This implementation uses standard (case-sensitive) String comparison. Subclasses can provide
27360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * custom comparison behavior, for instance using encrypted password values, by overriding this
27460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * method.
27560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
27660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param password - the password to compare against the configured value
27760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return true if the passwords match
27860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
27960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    protected boolean comparePassword(String password) {
28060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return password != null && password.equals(this.password);
28160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
28260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
28360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    /**
28460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * Return true only if both Strings are null or they are equal (have the same contents).
28560b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     *
28660b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param string1 - the first String
28760b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @param string2 - the second String
28860b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     * @return true if both are null or both are equal
28960b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair     */
29060b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    protected boolean equalOrBothNull(String string1, String string2) {
29160b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair        return (string1 == null && string2 == null) || (string1 != null && string1.equals(string2));
29260b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair    }
29360b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair
29460b81e2faf8511148f0d1e8f296e0b40ce9c7971chrismair}