blob: 2b87cbe0aceae8b0f45b4dc85f1e7465709c4e3c [file] [log] [blame]
// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 com.google.enterprise.adaptor.fs;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import org.junit.*;
import org.junit.rules.ExpectedException;
import com.sun.jna.platform.win32.Advapi32Util.Account;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinError;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.WinNT.SID_NAME_USE;
import java.nio.file.attribute.AclEntry;
import java.nio.file.attribute.AclEntryFlag;
import java.nio.file.attribute.AclEntryPermission;
import java.nio.file.attribute.AclEntryType;
import java.nio.file.attribute.GroupPrincipal;
import java.nio.file.attribute.UserPrincipal;
import java.util.EnumSet;
import java.util.Set;
/** Tests for {@link WindowsAclFileAttributeViews} */
public class WindowsAclFileAttributeViewsTest {
private final WindowsAclFileAttributeViews wafav =
new TestAclFileAttributeViews();
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testNewAclEntryUnsupportedAccessType() throws Exception {
WinNT.ACCESS_ACEStructure ace = new AceBuilder()
.setType(WinNT.SYSTEM_AUDIT_ACE_TYPE).build();
assertNull(wafav.newAclEntry(ace));
}
@Test
public void testNewAclEntryUnresolvableSid() throws Exception {
TestHelper.assumeOsIsWindows(); // For new Win32Exception().
WinNT.ACCESS_ACEStructure ace = new AceBuilder()
.setSid(new AccountSid(null)).build();
assertNull(wafav.newAclEntry(ace));
}
@Test
public void testNewAclEntryUnsupportedAccountType() throws Exception {
WinNT.ACCESS_ACEStructure ace = new AceBuilder()
.setSid(new AccountSid(SID_NAME_USE.SidTypeUnknown, "", "")).build();
assertNull(wafav.newAclEntry(ace));
}
@Test
public void testNewAclEntryUserPrincipal() throws Exception {
testNewAclEntryUserPrincipal(AccountSid.user("userName", null), "userName");
}
@Test
public void testNewAclEntryUserWithDomainPrincipal() throws Exception {
testNewAclEntryUserPrincipal(AccountSid.user("userName", "domain"),
"domain\\userName");
}
private void testNewAclEntryUserPrincipal(AccountSid account,
String expectedName) throws Exception {
WinNT.ACCESS_ACEStructure ace = new AceBuilder().setSid(account).build();
AclEntry aclEntry = wafav.newAclEntry(ace);
assertNotNull(aclEntry);
UserPrincipal principal = aclEntry.principal();
assertNotNull(principal);
assertFalse(principal instanceof GroupPrincipal);
assertEquals(expectedName, principal.getName());
}
@Test
public void testNewAclEntryGroupPrincipal() throws Exception {
testNewAclEntryGroupPrincipal(AccountSid.group("groupName", null),
"groupName");
}
@Test
public void testNewAclEntryGroupWithDomainPrincipal() throws Exception {
testNewAclEntryGroupPrincipal(AccountSid.group("groupName", "domain"),
"domain\\groupName");
}
@Test
public void testNewAclEntryAliasPrincipal() throws Exception {
AccountSid account =
new AccountSid(SID_NAME_USE.SidTypeAlias, "alias", "domain");
testNewAclEntryGroupPrincipal(account, "domain\\alias");
}
@Test
public void testNewAclEntryWellKnownGroupPrincipal() throws Exception {
AccountSid account =
new AccountSid(SID_NAME_USE.SidTypeWellKnownGroup, "wellKnown", null);
testNewAclEntryGroupPrincipal(account, "wellKnown");
}
private void testNewAclEntryGroupPrincipal(AccountSid account,
String expectedName) throws Exception {
WinNT.ACCESS_ACEStructure ace = new AceBuilder().setSid(account).build();
AclEntry aclEntry = wafav.newAclEntry(ace);
assertNotNull(aclEntry);
UserPrincipal principal = aclEntry.principal();
assertNotNull(principal);
assertTrue(principal instanceof GroupPrincipal);
assertEquals(expectedName, principal.getName());
}
@Test
public void testNewAclEntryIndividualPermissions() throws Exception {
testNewAclEntryPermissions(WinNT.FILE_READ_DATA,
AclEntryPermission.READ_DATA);
testNewAclEntryPermissions(WinNT.FILE_READ_ATTRIBUTES,
AclEntryPermission.READ_ATTRIBUTES);
testNewAclEntryPermissions(WinNT.FILE_READ_EA,
AclEntryPermission.READ_NAMED_ATTRS);
testNewAclEntryPermissions(WinNT.READ_CONTROL,
AclEntryPermission.READ_ACL);
testNewAclEntryPermissions(WinNT.FILE_WRITE_DATA,
AclEntryPermission.WRITE_DATA);
testNewAclEntryPermissions(WinNT.FILE_APPEND_DATA,
AclEntryPermission.APPEND_DATA);
testNewAclEntryPermissions(WinNT.FILE_WRITE_ATTRIBUTES,
AclEntryPermission.WRITE_ATTRIBUTES);
testNewAclEntryPermissions(WinNT.FILE_WRITE_EA,
AclEntryPermission.WRITE_NAMED_ATTRS);
testNewAclEntryPermissions(WinNT.WRITE_DAC,
AclEntryPermission.WRITE_ACL);
testNewAclEntryPermissions(WinNT.WRITE_OWNER,
AclEntryPermission.WRITE_OWNER);
testNewAclEntryPermissions(WinNT.DELETE,
AclEntryPermission.DELETE);
testNewAclEntryPermissions(WinNT.FILE_DELETE_CHILD,
AclEntryPermission.DELETE_CHILD);
testNewAclEntryPermissions(WinNT.SYNCHRONIZE,
AclEntryPermission.SYNCHRONIZE);
testNewAclEntryPermissions(WinNT.FILE_EXECUTE,
AclEntryPermission.EXECUTE);
}
@Test
public void testNewAclEntryFullPermissions() throws Exception {
testNewAclEntryPermissions(WinNT.FILE_ALL_ACCESS,
AclEntryPermission.values());
}
@Test
public void testNewAclEntryGenericPermissions() throws Exception {
testNewAclEntryPermissions(WinNT.GENERIC_READ, AclEntryPermission.READ_DATA,
AclEntryPermission.READ_ATTRIBUTES, AclEntryPermission.READ_NAMED_ATTRS,
AclEntryPermission.READ_ACL, AclEntryPermission.SYNCHRONIZE);
testNewAclEntryPermissions(WinNT.GENERIC_WRITE,
AclEntryPermission.WRITE_DATA, AclEntryPermission.APPEND_DATA,
AclEntryPermission.READ_ACL, AclEntryPermission.WRITE_ATTRIBUTES,
AclEntryPermission.WRITE_NAMED_ATTRS, AclEntryPermission.SYNCHRONIZE);
testNewAclEntryPermissions(WinNT.GENERIC_EXECUTE,
AclEntryPermission.EXECUTE, AclEntryPermission.READ_ATTRIBUTES,
AclEntryPermission.READ_ACL, AclEntryPermission.SYNCHRONIZE);
testNewAclEntryPermissions(WinNT.GENERIC_ALL, AclEntryPermission.values());
}
private void testNewAclEntryPermissions(int acePermissions,
AclEntryPermission... expectedPermissions) throws Exception {
Set<AclEntryPermission> expected =
EnumSet.noneOf(AclEntryPermission.class);
for (AclEntryPermission perm : expectedPermissions) {
expected.add(perm);
}
WinNT.ACCESS_ACEStructure ace = new AceBuilder()
.setSid(AccountSid.user("userName", null))
.setPerms(acePermissions)
.build();
AclEntry aclEntry = wafav.newAclEntry(ace);
assertNotNull(aclEntry);
assertEquals(expected, aclEntry.permissions());
}
@Test
public void testNewAclEntryIndividualFlags() throws Exception {
testNewAclEntryFlags(WinNT.OBJECT_INHERIT_ACE, AclEntryFlag.FILE_INHERIT);
testNewAclEntryFlags(WinNT.INHERIT_ONLY_ACE, AclEntryFlag.INHERIT_ONLY);
testNewAclEntryFlags(WinNT.CONTAINER_INHERIT_ACE,
AclEntryFlag.DIRECTORY_INHERIT);
testNewAclEntryFlags(WinNT.NO_PROPAGATE_INHERIT_ACE,
AclEntryFlag.NO_PROPAGATE_INHERIT);
}
@Test
public void testNewAclEntryMultipleFlags() throws Exception {
testNewAclEntryFlags((byte) (WinNT.OBJECT_INHERIT_ACE |
WinNT.CONTAINER_INHERIT_ACE | WinNT.INHERIT_ONLY_ACE |
WinNT.NO_PROPAGATE_INHERIT_ACE), AclEntryFlag.values());
}
private void testNewAclEntryFlags(byte aceFlags,
AclEntryFlag... expectedFlags) throws Exception {
Set<AclEntryFlag> expected = EnumSet.noneOf(AclEntryFlag.class);
for (AclEntryFlag flag : expectedFlags) {
expected.add(flag);
}
WinNT.ACCESS_ACEStructure ace = new AceBuilder()
.setSid(AccountSid.user("userName", null))
.setFlags(aceFlags)
.build();
AclEntry aclEntry = wafav.newAclEntry(ace);
assertNotNull(aclEntry);
assertEquals(expected, aclEntry.flags());
}
static class AceBuilder {
private Ace ace = new Ace();
public AceBuilder setType(byte type) {
ace.AceType = type;
return this;
}
public AceBuilder setFlags(byte... flags) {
for (byte flag : flags) {
ace.AceFlags |= flag;
}
return this;
}
public AceBuilder setPerms(int... perms) {
for (int perm : perms) {
ace.Mask |= perm;
}
return this;
}
public AceBuilder setSid(WinNT.PSID sid) {
ace.setSID(sid);
return this;
}
public WinNT.ACCESS_ACEStructure build() {
return ace;
}
}
static class Ace extends WinNT.ACCESS_ACEStructure {
// psid is not publicly settable in ACCESS_ACEStructure.
private WinNT.PSID sid;
public void setSID(WinNT.PSID sid) {
this.sid = sid;
}
@Override
public WinNT.PSID getSID() {
return (sid != null) ? sid : super.getSID();
}
@Override
public String getSidString() {
return (sid != null) ? sid.toString() : super.getSidString();
}
}
/** A SID implemention that wraps an Account, avoiding AD lookup. */
static class AccountSid extends WinNT.PSID {
private final Account account;
public static AccountSid user(String name, String domain) {
return new AccountSid(SID_NAME_USE.SidTypeUser, name, domain);
}
public static AccountSid group(String name, String domain) {
return new AccountSid(SID_NAME_USE.SidTypeGroup, name, domain);
}
public AccountSid(Account account) {
this.account = account;
}
public AccountSid(int type, String name, String domain) {
account = new Account();
account.accountType = type;
account.name = name;
account.domain = domain;
}
public Account getAccount() throws Win32Exception {
if (account == null) {
throw new Win32Exception(WinError.ERROR_NONE_MAPPED);
}
return account;
}
@Override
public String toString() {
if (account == null) {
return "null";
} else {
return (account.domain == null) ? account.name
: account.domain + "\\" + account.name;
}
}
}
/**
* An subclass of WindowsAclFileAttributeViews that avoids making
* actual Windows API calls.
*/
static class TestAclFileAttributeViews extends WindowsAclFileAttributeViews {
public TestAclFileAttributeViews() {
super(null, null, null, null, null);
}
@Override
Account getAccountBySid(WinNT.PSID sid) throws Win32Exception {
if (sid instanceof AccountSid) {
return ((AccountSid) sid).getAccount();
} else {
return super.getAccountBySid(sid);
}
}
}
}