/** * ACL is sensible information and as such we should expose as few information as possible * to users. This method allows to filter a {@link MailboxACL} in order to present it to * the connected user. */ @VisibleForTesting static MailboxACL filteredForSession(Mailbox mailbox, MailboxACL acl, MailboxSession mailboxSession) throws UnsupportedRightException { if (mailbox.generateAssociatedPath().belongsTo(mailboxSession)) { return acl; } MailboxACL.EntryKey userAsKey = MailboxACL.EntryKey.createUserEntryKey(mailboxSession.getUser().getUserName()); Rfc4314Rights rights = acl.getEntries().getOrDefault(userAsKey, new Rfc4314Rights()); if (rights.contains(MailboxACL.Right.Administer)) { return acl; } return new MailboxACL(ImmutableMap.of(userAsKey, rights)); } }
@Before public void setUp() throws Exception { path = MailboxPath.forUser(USER_1, MAILBOX_NAME); UnpooledStatusResponseFactory statusResponseFactory = new UnpooledStatusResponseFactory(); mailboxManager = mock(MailboxManager.class); subject = new ListRightsProcessor(mock(ImapProcessor.class), mailboxManager, statusResponseFactory, new NoopMetricFactory()); imapSession = mock(ImapSession.class); mailboxSession = mock(MailboxSession.class); User user1 = mock(User.class); MessageManager messageManager = mock(MessageManager.class); metaData = mock(MetaData.class); responder = mock(Responder.class); argumentCaptor = ArgumentCaptor.forClass(ImapResponseMessage.class); when(imapSession.getAttribute(ImapSessionUtils.MAILBOX_SESSION_ATTRIBUTE_SESSION_KEY)) .thenReturn(mailboxSession); when(imapSession.getState()) .thenReturn(ImapSessionState.AUTHENTICATED); when(mailboxSession.getUser()) .thenReturn(user1); when(user1.getUserName()) .thenReturn(USER_1); when(messageManager.getMetaData(anyBoolean(), any(MailboxSession.class), any(MetaData.FetchGroup.class))) .thenReturn(metaData); when(mailboxManager.getMailbox(any(MailboxPath.class), any(MailboxSession.class))) .thenReturn(messageManager); listRightsRequest = new ListRightsRequest("TAG", ImapCommand.anyStateCommand("Name"), MAILBOX_NAME, USER_1); user1Key = EntryKey.deserialize(USER_1); listRights = new Rfc4314Rights[] {Rfc4314Rights.fromSerializedRfc4314Rights("ae"), Rfc4314Rights.fromSerializedRfc4314Rights("i"), Rfc4314Rights.fromSerializedRfc4314Rights("k")}; }
/** * Creates a new instance of SimpleMailboxACLEntryKey from the given * serialized {@link String}. It supposes that negative rights are * marked with {@link MailboxACL#DEFAULT_NEGATIVE_MARKER} and that * groups are marked with {@link MailboxACL#DEFAULT_GROUP_MARKER}. * * @param serialized */ public static EntryKey deserialize(String serialized) { Preconditions.checkNotNull(serialized, "Cannot parse null"); Preconditions.checkArgument(!serialized.isEmpty(), "Cannot parse an empty string"); boolean negative = serialized.charAt(0) == DEFAULT_NEGATIVE_MARKER; int nameStart = negative ? 1 : 0; boolean isGroup = serialized.charAt(nameStart) == DEFAULT_GROUP_MARKER; Optional<NameType> explicitNameType = isGroup ? Optional.of(NameType.group) : Optional.empty(); String name = isGroup ? serialized.substring(nameStart + 1) : serialized.substring(nameStart); if (name.isEmpty()) { throw new IllegalStateException("Cannot parse a string with empty name"); } NameType nameType = explicitNameType.orElseGet(() -> computeImplicitNameType(name)); return new EntryKey(name, nameType, negative); }
final String aclKeyName = aclKey.getName(); final NameType aclKeyNameType = aclKey.getNameType(); if (SpecialName.anybody.name().equals(aclKeyName)) { String queryUserOrGroupName = queryKey.getName(); switch (queryKey.getNameType()) { case user: throw new IllegalStateException("Unexpected " + NameType.class.getName() + "." + queryKey.getNameType());
} else { EntryKey key = EntryKey.deserialize(identifier);
} else { EntryKey key = EntryKey.deserialize(identifier);
} else { EntryKey key = EntryKey.deserialize(identifier);
.stream() .map(entry -> Pair.of(entry.getKey(), entry.getKey().equals(key) ? replacement : entry.getValue())) .filter(pair -> pair.getValue() != null && !pair.getValue().isEmpty()) .collect(Guavate.toImmutableMap(Pair::getKey, Pair::getValue)));
@Before public void setUp() throws Exception { path = MailboxPath.forUser(USER_1, MAILBOX_NAME); UnpooledStatusResponseFactory statusResponseFactory = new UnpooledStatusResponseFactory(); mailboxManager = mock(MailboxManager.class); subject = new SetACLProcessor(mock(ImapProcessor.class), mailboxManager, statusResponseFactory, new NoopMetricFactory()); imapSession = mock(ImapSession.class); mailboxSession = mock(MailboxSession.class); User user1 = mock(User.class); MessageManager messageManager = mock(MessageManager.class); MetaData metaData = mock(MetaData.class); responder = mock(Responder.class); argumentCaptor = ArgumentCaptor.forClass(ImapResponseMessage.class); when(imapSession.getAttribute(ImapSessionUtils.MAILBOX_SESSION_ATTRIBUTE_SESSION_KEY)) .thenReturn(mailboxSession); when(imapSession.getState()) .thenReturn(ImapSessionState.AUTHENTICATED); when(mailboxSession.getUser()) .thenReturn(user1); when(user1.getUserName()) .thenReturn(USER_1); when(messageManager.getMetaData(anyBoolean(), any(MailboxSession.class), any(FetchGroup.class))) .thenReturn(metaData); when(mailboxManager.getMailbox(any(MailboxPath.class), any(MailboxSession.class))) .thenReturn(messageManager); replaceAclRequest = new SetACLRequest("TAG", ImapCommand.anyStateCommand("Name"), MAILBOX_NAME, USER_1, SET_RIGHTS); user1Key = EntryKey.deserialize(USER_1); setRights = Rfc4314Rights.fromSerializedRfc4314Rights(SET_RIGHTS); }
@Test public void updateShouldFilterOwnerACL() throws Exception { String myBox = "myBox"; String user2 = "user2"; MailboxId mailboxId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username, myBox); with() .header("Authorization", accessToken.serialize()) .body("[" + " [ \"setMailboxes\"," + " {" + " \"update\": {" + " \"" + mailboxId.serialize() + "\" : {" + " \"sharedWith\" : {\"" + username + "\": [\"a\", \"w\"]," + " \"" + user2 + "\": [\"a\", \"w\"]}" + " }" + " }" + " }," + " \"#0\"" + " ]" + "]") .post("/jmap"); MailboxACL acl = jmapServer.getProbe(ACLProbeImpl.class) .retrieveRights(MailboxPath.forUser(username, myBox)); assertThat(acl.getEntries()) .doesNotContainKeys(MailboxACL.EntryKey.createUserEntryKey(username)); }
USER_1); user1Key = EntryKey.deserialize(USER_1);
@Before public void setUp() throws Exception { user1Key = EntryKey.createUserEntryKey(USER_1); user2Key = EntryKey.createUserEntryKey(USER_2); group1Key = EntryKey.createGroupEntryKey(GROUP_1); group2Key = EntryKey.createGroupEntryKey(GROUP_2); MailboxACL acl = new MailboxACL(new Entry(MailboxACL.AUTHENTICATED_KEY, MailboxACL.FULL_RIGHTS)); authenticatedReadListWriteGlobal = new UnionMailboxACLResolver(acl, acl); acl = new MailboxACL(new Entry(MailboxACL.ANYBODY_KEY, Rfc4314Rights.fromSerializedRfc4314Rights("rl"))); anyoneReadListGlobal = new UnionMailboxACLResolver(acl, acl); acl = new MailboxACL(new Entry(MailboxACL.OWNER_KEY, MailboxACL.FULL_RIGHTS)); ownerFullGlobal = new UnionMailboxACLResolver(acl, acl); noGlobals = new UnionMailboxACLResolver(MailboxACL.EMPTY, MailboxACL.EMPTY); acl = new MailboxACL(new Entry(new EntryKey(GROUP_2, NameType.group, true), MailboxACL.FULL_RIGHTS)); negativeGroup2FullGlobal = new UnionMailboxACLResolver(acl, new MailboxACL(new Entry(new EntryKey(GROUP_2, NameType.group, true), MailboxACL.FULL_RIGHTS))); groupMembershipResolver = new SimpleGroupMembershipResolver(); groupMembershipResolver.addMembership(GROUP_1, USER_1); groupMembershipResolver.addMembership(GROUP_2, USER_2); user1Read = new MailboxACL(new Entry(user1Key, Rfc4314Rights.fromSerializedRfc4314Rights("r"))); user1ReadNegative = new MailboxACL(new Entry(EntryKey.createUserEntryKey(USER_1, true), Rfc4314Rights.fromSerializedRfc4314Rights("r"))); group1Read = new MailboxACL(new Entry(group1Key, Rfc4314Rights.fromSerializedRfc4314Rights("r"))); group1ReadNegative = new MailboxACL(new Entry(EntryKey.createGroupEntryKey(GROUP_1, true), Rfc4314Rights.fromSerializedRfc4314Rights("r"))); anybodyRead = new MailboxACL(new Entry(MailboxACL.ANYBODY_KEY, Rfc4314Rights.fromSerializedRfc4314Rights("r"))); anybodyReadNegative = new MailboxACL(new Entry(MailboxACL.ANYBODY_NEGATIVE_KEY, Rfc4314Rights.fromSerializedRfc4314Rights("r"))); authenticatedRead = new MailboxACL(new Entry(MailboxACL.AUTHENTICATED_KEY, Rfc4314Rights.fromSerializedRfc4314Rights("r"))); authenticatedReadNegative = new MailboxACL(new Entry(MailboxACL.AUTHENTICATED_NEGATIVE_KEY, Rfc4314Rights.fromSerializedRfc4314Rights("r"))); ownerRead = new MailboxACL(new Entry(MailboxACL.OWNER_KEY, Rfc4314Rights.fromSerializedRfc4314Rights("r"))); ownerReadNegative = new MailboxACL(new Entry(MailboxACL.OWNER_NEGATIVE_KEY, Rfc4314Rights.fromSerializedRfc4314Rights("r"))); }
@Test public void eventShouldDoNothingWhenNegativeACLEntry() throws Exception { EntryKey negativeUserKey = EntryKey.createUserEntryKey(SHARED_USER, true); storeRightManager.applyRightsCommand( GRAND_CHILD_MAILBOX, MailboxACL.command() .key(negativeUserKey) .rights(Right.Lookup) .asAddition(), mailboxSession); MailboxACL actualACL = storeMailboxManager.getMailbox(parentMailboxId, mailboxSession) .getMetaData(RESET_RECENT, mailboxSession, MessageManager.MetaData.FetchGroup.NO_COUNT) .getACL(); assertThat(actualACL.getEntries()) .hasSize(1) .doesNotContainKeys(negativeUserKey); } }
@Override protected void doEncode(ImapMessage acceptableMessage, ImapResponseComposer composer, ImapSession session) throws IOException { final ACLResponse aclResponse = (ACLResponse) acceptableMessage; final Map<EntryKey, Rfc4314Rights> entries = aclResponse.getAcl().getEntries(); composer.untagged(); composer.commandName(ImapConstants.ACL_RESPONSE_NAME); String mailboxName = aclResponse.getMailboxName(); composer.mailbox(mailboxName == null ? "" : mailboxName); if (entries != null) { for (Entry<EntryKey, Rfc4314Rights> entry : entries.entrySet()) { String identifier = entry.getKey().serialize(); composer.quote(identifier); String rights = entry.getValue().serialize(); composer.quote(rights == null ? "" : rights); } } composer.end(); }
public Entry(String key, String value) throws UnsupportedRightException { this(EntryKey.deserialize(key), Rfc4314Rights.fromSerializedRfc4314Rights(value)); }
public static EntryKey createUserEntryKey(String name) { return new EntryKey(name, NameType.user, false); }
@Test void twoConcurrentUpdatesWhenStoredShouldReturnACEWithTwoEntries(CassandraCluster cassandra) throws Exception { CountDownLatch countDownLatch = new CountDownLatch(2); MailboxACL.EntryKey keyBenwa = new MailboxACL.EntryKey("benwa", MailboxACL.NameType.user, false); MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read); cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(keyBenwa).rights(rights).asAddition()); MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false); MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false); Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights, countDownLatch::countDown); Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights, countDownLatch::countDown); awaitAll(future1, future2); assertThat(cassandraACLMapper.getACL(MAILBOX_ID).join()) .isEqualTo(new MailboxACL().union(keyBob, rights).union(keyAlice, rights).union(keyBenwa, rights)); }
public Builder forUser(String user) { key = EntryKey.createUserEntryKey(user); return this; }
public String toString() { return serialize(); } }
public Entry(String key, Right... rights) throws UnsupportedRightException { this(EntryKey.deserialize(key), new Rfc4314Rights(rights)); }