Tuesday, 8 December 2015

Using Microsoft Graph API from a daemon process (in Perl on Linux!)

At work, I've been asked to look at how easy (or difficult) it will be to give folk using Microsoft Office365 access to the student timetables.  We already provide a feed into our Google Apps for Education accounts for the students, and this has been very popular.  However The Powers That Be have had a funny five minutes and decided to move future students to Office365 (no, none of us can work out why either!).

Now in the past we've bodged up a means of staff seeing time table information in Office365 (as they've been stuck in there for some years now) using iCal files.  This works but:

  • requires the user to make an active decision to register and then past the link into their Office365 Web Access (OWA) calendar setup
  • means that Microsoft's servers whack our servers ever 4 hours to update this iCal link (which is OK for a small subset of the staff, but would be less fun for our servers when 15000+ students start to hit them).
So I've been looking at the exciting new Microsoft Graph API that they released a week or two back. Actually its been lurking in beta for a while, but v1.0 appeared more or less as soon as we started to look at how to do this, which is supposed to be the first general release for production use.  According to some Microsoft folk we talked to, this API is going to be the way of the future, so its what we started to look at using (as opposed to the older SOAP based Exchange Web Services API).

The Graph API uses RESTful calls, JSON, and OAuth2.0, so it looks pretty sane.  That was a surprise for me: I'm used to Microsoft stuff looking awful from the start from the point of view of a Linux hacker.  Much of the documentation for the API's OAuth2.0 flows assumes that you're going to be writing a web delivered app.  In this case, the app interacts with the user to get them to log into Azure Active Directory and then delegate rights to do specified things as them to your code.  That isn't much use for a daemon process which is what we want, but luckily Microsoft also implement the "client credentials" flow in OAuth2.0.  This means that you can get a client token (aka client_id) for your daemon application and you can then use the API to swap the client token for a bearer access token that can access any user's data in your Office365 tenancy, limited to the scopes set by the admins. One initial stumbling block for me was that I'm not normally an AD admin in our tenancy, and it looks like you need to be in order to assign application authorization scopes to the app in the Azure management console (luckily our AD guys were OK with giving me admin access to a test tenancy where I could break things to my hearts content whilst working out how this all works).  Still, this is very similar to Google Apps, where you give access scopes to a service account that can then act as other users.

Just to make things a bit sicker, my end of the Graph API calls is coming from Perl scripts sitting on a Linux box.  I'm a Perl hacker, and I've already written Perl modules to wrap up some of the Google APIs in the past, so this isn't overly concerning to me.  Indeed one of the selling points of the Microsoft Graph API's RESTful, OData standards basis is that its pretty much language and platform agnostic.  Its just as happy talking to a Perl script on a Linux box as it is a C# program on a Windows server.

Being version 1.0, the current Microsoft Graph API has a few oddities. I'm not sure why these didn't get fixed in the beta period - maybe the fact that it was a beta put off normal Microsoft developers from using it (use Open Source folk are used to using alpha and beta releases in production, as we've got the code to fix things if they go wrong!).

For example, lets say you want to use Graph to add a member to a Unified Group.  Unified Groups which are an exciting new type of group that can have calendars, files and conversations associated with them (they have nothing to do with local AD groups, existing security or mail enabled groups, calendar groups or distribution groups.  Microsoft really need to stop using the word "group" for new collections of things!). That's easy: there's a documented RESTful call for adding members.  Simiilarly, you can list members of the group. Great - those all work a treat. Now how do you remove members from the group?  Ah.  There doesn't seem to be an API call for that.  Or at least if there is, its not currently documented or its not in the same place as the creating/list members calls. I've flagged it up on Stackoverflow, so hopefully someone will either point me in the right direction or fix the API/documentation. That would be a bit of a show stopper for us though - students are flighty, jittery types who do tend to jump around the modules they are studying so we need to be able to add and remove them from the groups easily (and preferably without them getting an email every time this happens).

On the flip side, Microsoft have said that Unified Groups have some interesting new features, such as being able to have calendars attached directly to them. That sounds like just want we need: we can have a Unified Group for each module's timetable, add the students (and staff teaching it) to this group (possibly by adding the existing local AD module groups into the Azure AD and then adding those groups as members of the Unified Groups) and then fill the group with calendar events for all the lectures, labs, seminars and tutorials. Unfortunately this doesn't seem to work at the moment... the API documentation seems to indicate it should, but I and others are getting errors that the Unified Groups don't have a mailbox.  The odd thing is that I can use the Graph API to add events to an individual user's calendar and if I set the attendees to be the group, it does appear in the group calendar in OWA.  That behaviour is... odd.  But then it could be because I'm not getting how Microsoft intend Office365 calendars to work  I'm used to Google's calendars - ACLs in Google calendars land actually seem to work fine for sharing calendars, although you do have to make quite a few API calls for large numbers of students when setting them up (which Microsoft's Unified Groups would do away with if it worked).

Anyway, I'll keep plugging away at it.  I just hope I don't accidentally turn into the department's Microsoft Graph API "expert".  That would be embarrassing for a Linux hacker!

UPDATE: According to the Marek Rycharski from Microsoft on Stackoverflow, it turns out that the Graph API can't (yet) handle calendars on Unified Groups.  Its "on the roadmap" but no immediate plans for implementing it in the near future.  Drat!  Still at least I got told how to remove users from the Unified Groups ready for when I do need it at some point in the distant future.