none
[E2007] [EWSMA] [C#]: Can Delegates Access Private Contacts? RRS feed

  • Question

  • Exchange Versions: 8.1 (Build 240.6) and 14.0 (Build 639.21)
    API: Exchange Web Services Managed API 1.1

    I'm trying to understand how EWS handles delegate access to private items—specifically Contacts—versus how Outlook handles it. We're developing an application in which delegates can work with Contacts, and we think they will expect their access to match that in Outlook.

    From what I understand, in Outlook, delegates' ability to view private items depends on both Calendar permissions and the "View Private Items" setting, like this:

    View Private = No + Calendar = None => No, cannot see private items
    View Private = No + Calendar = Reviewer => No, cannot see private items
    View Private = Yes + Calendar = None => No, cannot see private items
    View Private = Yes + Calendar = Reviewer => Yes, can see private items

    How is EWS meant to handle each of these scenarios? Or is it not related to EWS as much as to the version of Exchange?

    I have some code below that sets up each scenario and checks if private contacts are returned from a Find. It seems to work these two different ways depending on which version of Exchange I run it against. Is that expected?

    Exchange 2007:
    View Private = No + Calendar = None => No, cannot see private items
    View Private = No + Calendar = Reviewer => No, cannot see private items
    View Private = Yes + Calendar = None => Yes, can see private items
    View Private = Yes + Calendar = Reviewer => Yes, can see private items

    Exchange 2010:
    All 4 scenarios result in the delegate seeing the private items.

    Also, are these permissions cached somehow in Exchange or EWS, or do they take time to propagate? The code below also demonstrates changing the Calendar permissions and the View Private setting on "delegate5." When I run it against Exchange 2007, the changes don't seem to be reflected in the contacts returned from a Find.

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Exchange.WebServices.Data;
    
    namespace EwsDelegateTest
    {
      class Program
      {
        private const string SmtpAddress = "delegator@domain.com";
        private static readonly ExchangeService Service = GetService(SmtpAddress);
        private static readonly string FolderId = GetContactsFolderId();
    
        static void Main(string[] args)
        {
          AddContact(Sensitivity.Normal);
          AddContact(Sensitivity.Private);
    
          var delegate1 = new Delegate
          {
            SmtpAddress = "delegate1@domain.com",
            ViewPrivateItems = false,
            CalendarPermissions = DelegateFolderPermissionLevel.None
          };
          var delegate2 = new Delegate
          {
            SmtpAddress = "delegate2@domain.com",
            ViewPrivateItems = false,
            CalendarPermissions = DelegateFolderPermissionLevel.Reviewer
          };
          var delegate3 = new Delegate
          {
            SmtpAddress = "delegate3@domain.com",
            ViewPrivateItems = true,
            CalendarPermissions = DelegateFolderPermissionLevel.None
          };
          var delegate4 = new Delegate
          {
            SmtpAddress = "delegate4@domain.com",
            ViewPrivateItems = true,
            CalendarPermissions = DelegateFolderPermissionLevel.Reviewer
          };
          var delegate5 = new Delegate
          {
            SmtpAddress = "delegate5@domain.com",
            ViewPrivateItems = false,
            CalendarPermissions = DelegateFolderPermissionLevel.None
          };
    
          var delegates = new List<Delegate> {delegate1, delegate2, delegate3, delegate4, delegate5};
          AddDelegates(delegates);
    
          delegates.ForEach(PrintContacts);
          Console.WriteLine();
    
          FlipPermissions(delegate5);
          PrintContacts(delegate5);
    
          CleanUp();
    
          Console.Write("Done. Press any key to exit.");
          Console.Read();
        }
    
        private static void PrintContacts(Delegate @delegate)
        {
          PrintDelegate(@delegate);
          var service = GetService(@delegate.SmtpAddress);
    
          var contacts = GetContacts(service);
    
          foreach (var contact in contacts) 
          {
            Console.WriteLine(contact.GivenName + " " + contact.Surname);
          }
          Console.WriteLine();
        }
    
        private static IEnumerable<Contact> GetContacts(ExchangeService service)
        {
          var properties = new[] {ContactSchema.GivenName, ContactSchema.Surname};
          var view = new ItemView(int.MaxValue) {PropertySet = new PropertySet(properties)};
    
          return service.FindItems(FolderId, view).Cast<Contact>();
        }
    
        private static ExchangeService GetService(string username)
        {
          return new ExchangeService(ExchangeVersion.Exchange2007_SP1)
          {
            Url = new Uri("https://mail.domain.com/EWS/exchange.asmx"),
            Credentials = new WebCredentials(username, "MyPassword")
          };
        }
    
        private static string GetContactsFolderId()
        {
          var folder = Folder.Bind(Service, WellKnownFolderName.Contacts);
          return folder.Id.UniqueId;
        }
    
        private static void AddContact(Sensitivity sensitivity)
        {
          var contact = new Contact(Service)
          {
            GivenName = sensitivity.ToString(),
            Surname = "Contact",
            Sensitivity = sensitivity
          };
          contact.Save();
        }
    
        private static void AddDelegates(IEnumerable<Delegate> delegates)
        {
          var delegatesToAdd = from @delegate in delegates
                     select CreateDelegate(@delegate);
    
          var mailbox = new Mailbox(SmtpAddress);
    
          Service.AddDelegates(mailbox, null, delegatesToAdd);
        }
    
        private static DelegateUser CreateDelegate(Delegate @delegate)
        {
          var user = new DelegateUser(@delegate.SmtpAddress)
          {
            ViewPrivateItems = @delegate.ViewPrivateItems
          };
          user.Permissions.ContactsFolderPermissionLevel = DelegateFolderPermissionLevel.Reviewer;
          user.Permissions.CalendarFolderPermissionLevel = @delegate.CalendarPermissions;
    
          return user;
        }
    
        private static void PrintDelegate(Delegate @delegate)
        {
          var user = GetDelegate(@delegate);
          var msg = string.Format("Delegate={0}, Calendar={1}, ViewPrivate={2}",
                      user.UserId.PrimarySmtpAddress,
                      user.Permissions.CalendarFolderPermissionLevel,
                      user.ViewPrivateItems);
          Console.WriteLine(msg);
        }
    
        private static void FlipPermissions(Delegate @delegate)
        {
          Console.WriteLine("Flipping permissions for " + @delegate.SmtpAddress);
    
          var user = GetDelegate(@delegate);
          user.Permissions.ContactsFolderPermissionLevel = DelegateFolderPermissionLevel.Reviewer;
    
          user.Permissions.CalendarFolderPermissionLevel =
            user.Permissions.CalendarFolderPermissionLevel == DelegateFolderPermissionLevel.None
              ? DelegateFolderPermissionLevel.Reviewer
              : DelegateFolderPermissionLevel.None;
    
          user.ViewPrivateItems = !user.ViewPrivateItems;
    
          var mailbox = new Mailbox(SmtpAddress);
          Service.UpdateDelegates(mailbox, null, new[] {user});
        }
    
        private static DelegateUser GetDelegate(Delegate @delegate)
        {
          var mailbox = new Mailbox(SmtpAddress);
          var delegates = Service
            .GetDelegates(mailbox, true)
            .DelegateUserResponses
            .ToList()
            .ConvertAll(response => response.DelegateUser);
    
          return delegates
            .FirstOrDefault(x => x.UserId.PrimarySmtpAddress == @delegate.SmtpAddress);
        }
    
        private static void CleanUp()
        {
          var mailbox = new Mailbox(SmtpAddress);
          var delegates = Service.GetDelegates(mailbox, false).DelegateUserResponses;
          var userIds = from @delegate in delegates
                 select @delegate.DelegateUser.UserId;
          Service.RemoveDelegates(mailbox, userIds);
    
          var contacts = GetContacts(Service);
          contacts.ToList().ForEach(contact => contact.Delete(DeleteMode.HardDelete));
        }
    
        private class Delegate
        {
          public string SmtpAddress { get; set; }
          public bool ViewPrivateItems { get; set; }
          public DelegateFolderPermissionLevel CalendarPermissions { get; set; }
        }
      }
    }
    

     

    When I run this code, here's the output I get from Exchange 2007:

    Delegate=delegate1@domain.com, Calendar=None, ViewPrivate=False
    Normal Contact
    
    Delegate=delegate2@domain.com, Calendar=Reviewer, ViewPrivate=False
    Normal Contact
    
    Delegate=delegate3@domain.com, Calendar=None, ViewPrivate=True
    Private Contact
    Normal Contact
    
    Delegate=delegate4@domain.com, Calendar=Reviewer, ViewPrivate=True
    Private Contact
    Normal Contact
    
    Delegate=delegate5@domain.com, Calendar=None, ViewPrivate=False
    Normal Contact
    
    
    Flipping permissions for delegate5@domain.com
    Delegate=delegate5@domain.com, Calendar=Reviewer, ViewPrivate=True
    Normal Contact
    
    Done. Press any key to exit.

     

    But here's the output I get from Exchange 2010:

    Delegate=delegate1@domain.com, Calendar=None, ViewPrivate=False
    Private Contact
    Normal Contact
    
    Delegate=delegate2@domain.com, Calendar=Reviewer, ViewPrivate=False
    Private Contact
    Normal Contact
    
    Delegate=delegate3@domain.com, Calendar=None, ViewPrivate=True
    Private Contact
    Normal Contact
    
    Delegate=delegate4@domain.com, Calendar=Reviewer, ViewPrivate=True
    Private Contact
    Normal Contact
    
    Delegate=delegate5@domain.com, Calendar=None, ViewPrivate=False
    Private Contact
    Normal Contact
    
    
    Flipping permissions for delegate5@domain.com
    Delegate=delegate5@domain.com, Calendar=Reviewer, ViewPrivate=True
    Private Contact
    Normal Contact
    
    Done. Press any key to exit.

     

    From this note in the Outlook 2007 documentation about delegates, I'm actually more surprised by the Exchange 2007 behavior than by that of 2010:

    IMPORTANT: You should not rely on the Private feature to prevent other people from accessing the details of your appointments, contacts, or tasks. To make sure that other people cannot read the items that you marked as private, do not grant them Reviewer (can read items) permission to your Calendar, Contacts, or Tasks folder. A person who is granted Reviewer (can read items) permission to access your folders could use programmatic methods or other e-mail programs to view the details of a private item. Use the Private feature only when you share folders with people whom you trust.

    From that, I was expecting EWS to always give the delegate access to private items, and for it to be up to the person coding the client to decide whether or not to show private items.

    Thanks,
    Amy

    Friday, January 28, 2011 12:53 PM