Daniel Bach
8 Feb 2019 | Aktualisiert am: 16 Dez 2022
Expertenbeiträge | 8 Min. Lesezeit

In einem unserer Microsoft-Dynamics-365-Implementierungsprojekten für einen Kunden standen wir vor der Herausforderung, benutzerdefinierte Attribute mit Systembenutzern zu synchronisieren.

Standardmäßig werden Systembenutzer aus Azure Active Directory (AAD) synchronisiert (wo Einstellungen entweder über die Office 365 oder Azure-Portals verwaltet werden) oder mit der AD-Connect-Funktion über das lokale Active Directory (AD) synchronisiert. Dort wird die Synchronisierung von benutzerdefinierten Attributen eingerichtet.

Bei dieser standardmäßigen Synchronisierung werden nur statische Attribute mit Dynamics 365 synchronisiert. Da die Synchronisierung ein wiederkehrender Prozess ist und unsere Entwickler mit anderen Projekten beschäftigt waren, haben wir eine auf Microsoft Flow basierende Synchronisierung entwickelt. Dafür haben wir den in Flow enthaltenen AAD Connector benutzt.

Vorbereitung

Im Beispiel für diesen Post verwenden wir nur Azure AD ohne ein lokales AD. Um eine Extension Property abzurufen, müssen wir zunächst eine Erweiterung erstellen. Das geht ganz einfach mit dem Graph Explorer. Dort fügen wir einfach eine Beispiel-Erweiterung zu unserem AAD hinzu.

Nachdem wir uns beim Graph Explorer eingeloggt haben, klicken wir auf show more examples, um den Kategoriebereich aufzurufen, wo wir Extensions auswählen können.

Im Menübereich Post findet sich ein Beispiel, um eine Extension Property für den derzeit eingeloggten Nutzer zu erstellen.

Wenn wir dies ausführen, wird eine Extension Property für unseren Nutzer generiert, die wir  abrufen können, um sie mit Dynamics 365 zu synchronisieren.

 

Azure Active Directory Flow Connector

Wir haben die Einstellungen des AAD Connectors in der Dokumentation überprüft, aber wir konnten keine Anzeichen dafür finden, dass die AAD Extension Properties genutzt wurden. Wir haben es trotzdem ausprobiert und auf ein undokumentiertes Wunder gehofft.

AAD-Benutzerinformationen-Abruf – Flow

Wir beginnen mit einem Wiederholung-Trigger, um unsere Datensätze planmäßig zu aktualisieren. Dann laden wir die aktiven Systembenutzer aus Dynamics 365 via CDS, um sie gegen das AAD abzufragen und die entsprechenden Benutzerinformationen abzurufen.

 

AAD Benutzerinformationen Abruf – Ergebnisse

Nachdem wir unseren Flow ausgeführt hatten, prüften wir die Ergebnisse und waren genervt. Den Text, den wir abgerufen haben, enthielt die folgenden Informationen (*** = anonymisiert):

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
  "businessPhones": [
    "***"
  ],
  "displayName": "Daniel Bach",
  "givenName": "Daniel",
  "jobTitle": "Head of R&D",
  "mail": "***",
  "mobilePhone": "+49 1234",
  "officeLocation": "GS",
  "preferredLanguage": "en",
  "surname": "Bach",
  "userPrincipalName": "***",
  "id": "***"
}

Wie man sieht, existiert keine Extension Property in diesem abgerufenen Text. Stattdessen haben wir nur standardmäßige Informationen erhalten, die bei jeder Synchronisierung in das Dynamics-365-System enthalten sind.

AAD-Benutzerinformationen-Abruf – Zusammenfassung

Wir konnten die Benutzerinformationen erfolgreich aus der Azure Active Directory abrufen, aber darunter war keine Extension Property.

Der standardmäßige AAD Connector ist hilfreich, wenn man bestehende Informationen mit neuen benutzerdefinierten Attributen in eine Dynamics-365-Organisation synchronisieren will. Aber er bietet keine zusätzlichen Funktionen.

In einigen Fällen kann es helfen, Telefonnummern in leere Dynamics-365-Attribute zu synchronisieren, um alle verwandten Felder zu füllen und Informationen wie officeLocation oder preferredLanguage zu hinterlegen.

In unserem Szenario der Synchronisierung von Attributen war diese Evaluation nicht erfolgreich. Deshalb hielten wir nach einer besseren Lösung Ausschau.

Ausgehend von der Antwort des Graph-APIs, dachten wir über die Möglichkeit nach, die gegebene API und ihre Optionen direkt zu nutzen.

Der folgende Abschnitt erklärt, wie man eine vorhandene API nutzt und Microsoft Flow erweitert, wenn kein standardmäßiger Connector den Ansprüchen entspricht. Das Stichwort lautet: Do-it-yourself.

 

Graph API

Die Graph API ermöglicht Zugriff auf AAD. Anwendungen können die Graph API nutzen, um Erstell-, Lese-, Aktualisierungs- und Löschvorgänge für das Verzeichnis und seine Objekte auszuführen. Um ein Verzeichnis aufzurufen, muss die Anwendung bei AAD registriert sein und den entsprechenden Zugriff erhalten. Die Authentifizierung wird über JSON Web Token gehandhabt. Den Vorgang, der uns interessiert, ist der Get a user Abruf.

Weiter unten werden wir die Authentifizierungs-Anwendung in Azure und den entsprechenden Microsoft Flow einrichten.

Azure AD Authentifizierungs-App

Um unseren Microsoft Flow für die Graph API authentifizieren zu können, müssen wir unserem AAD eine neue Anwendung hinzufügen. Dafür öffnen wir den Bereich App-Registrierungen im Azure Management Portal.

Wir erstellen eine neue Anwendung namens „Authentication”. Welche URL wir verwenden, ist nicht wichtig. Notieren Sie sich die Anwendungs-ID, wir benötigen sie später für den Flow.

Gemäß der Anwendungseinstellungen müssen wir den benötigten Zugriff gewähren und unser Geheimnis definieren. Dafür öffnen wir Einstellungen und gehen zu Erforderliche Berechtigungen im Bereich API-Zugriff. Das Azure AD existiert bereits, aber wir müssen den Microsoft Graph hinzufügen und die Berechtigungen einstellen:

Windows Azure Active Directory

–  Read directory data

– Delegate – Sign in and read user profile

– Delegate – Read directory data

Microsoft Graph

– Read directory data

– Delegate – Sign in and read user profile

– Delegate – Read directory data

Sobald die Berechtigungen hinzugefügt wurden, gewähren wir sie unserer Anwendung. Im letzten Schritt öffnen wir Schlüssel im Bereich API-Zugriff, um unser Geheimnis zu speichern. Denken Sie daran, dass das Geheimnis nach dem Speichern verborgen sein wird. Also erstellen Sie eine Kopie. In unserem Beispiel stellen wir ein nie ablaufendes Geheimnis ein.

 

 

Microsoft Flow

Zuerst müssen wir unseren Flow mit der bereits erstellten App authentifizieren. Dazu werden Variablen, die unsere tenant id, authentication app und unser kleines Geheimnis enthalten, definiert.

Der initiale Trigger unseres Flows wird von einer wöchentlich geplanten Wiederholung gehandhabt, die auf Samstagabend gesetzt ist.

 

Authentifizierung

Um einen gültigen Token zu erhalten, müssen wir einen Bearer-Token generieren, indem wir die verbundene Graph API nutzen. In unserem Szenario prüften wir graph.microsoft.com oder graph.windows.net. Die entsprechende Adresse muss als Bereich in der Authorisierungsanfrage definiert werden. (Wir haben die windows.net-API genutzt. Möglicherweise funktionieren aber beide.)

Danach müssen wir den Ergebnistext unserer Anfrage analysieren. Dazu verwenden wir parse-JSON Datenvorgänge. Wir verwenden dieses Schema:

{
    "type": "object",
    "properties": {
        "token_type": {
            "type": "string"
        },
        "expires_in": {
            "type": "integer"
        },
        "ext_expires_in": {
            "type": "integer"
        },
        "access_token": {
            "type": "string"
        }
    }
}

 

Benutzerinformationen abrufen

Wenn wir unseren Zugriffstoken haben, können wir die Nutzerdaten mit der Graph API direkt abrufen. Als ganz einfachen Versuch laden wir alle aktiven Systemnutzer aus Dynamics 365 und durchlaufen alle einmaligen Systembenutzer.

Aber Achtung: In der Autorisierung gibt es ein Leerzeichen zwischen Tokentyp und dem eigentlichen Zugriffstoken!

Anschließend analysieren wir die ausgespukten Ergebnisse aus unserer Abfrage mit dem parse-JSON Datenvorgang. Das verwendete Schema kann über den Detail-Link generiert werden.

In unserem Beispiel-Output können wir sehen, dass wir die Extension Properties, die mit extension_* beginnen, erhalten.

Nun ist es sehr einfach, den entsprechenden Systembenutzer mit den verschiedenen Feldern, die direkt aus unserem AAD kommen, zu aktualisieren.

 

 

Graph API Benutzerinformationen Abruf – Ergebnis

Nachdem wir unseren Flow ausgeführt hatten, überprüften wir die Ergebnisse und sie enthielten unsere Eigenschaften.

Der Text, den wir abgerufen haben, enthielt die folgenden Informationen (*** = anonymisiert) – microsoft.com

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users",
  "value": [
    {
      "businessPhones": [
        "***"
      ],
      "displayName": "Daniel Bach",
      "givenName": "Daniel",
      "jobTitle": "Head of R&D",
      "mail": "***",
      "mobilePhone": "+49 1234",
      "officeLocation": "GS",
      "preferredLanguage": "en",
      "surname": "Bach",
      "userPrincipalName": "***",
      "id": "***",
      "extensions@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('***')/extensions",
      "extensions": [
        {
          "@odata.type": "#microsoft.graph.openTypeExtension",
          "theme": "dark",
          "extensionName": "roamingSettings",
          "id": "roamingSettings"
        }
      ]
    }
  ]
}

Wie man einfach erkennen kann, kommt die Extension Property in diesem abgerufenen Text vor.

Wie erhalten ähnliche Ergebnisse, wenn wir windows.net verwenden:

{
  "odata.metadata": "https://graph.windows.net/***/$metadata#directoryObjects/@Element",
  "odata.type": "Microsoft.DirectoryServices.User",
  "objectType": "User",
  "objectId": "***",
  "deletionTimestamp": null,
  "accountEnabled": true,
  "ageGroup": "Adult",
  "assignedLicenses": [
    ***
  ],
  "assignedPlans": [
    ***
  ],
  "city": "***",
  "companyName": null,
  "consentProvidedForMinor": null,
  "country": "Germany",
  "createdDateTime": null,
  "creationType": null,
  "department": "IT",
  "dirSyncEnabled": null,
  "displayName": "Daniel Bach",
  "employeeId": null,
  "facsimileTelephoneNumber": "fax",
  "givenName": "Daniel",
  "immutableId": null,
  "isCompromised": null,
  "jobTitle": "Head of R&D",
  "lastDirSyncTime": null,
  "legalAgeGroupClassification": "Adult",
  "mail": "***",
  "mailNickname": "***",
  "mobile": "+49 1234",
  "onPremisesDistinguishedName": null,
  "onPremisesSecurityIdentifier": null,
  "otherMails": [
    "***"
  ],
  "passwordPolicies": null,
  "passwordProfile": null,
  "physicalDeliveryOfficeName": "GS",
  "postalCode": "DE-90409",
  "preferredLanguage": "en",
  "provisionedPlans": [
    ***
  ],
  "provisioningErrors": [],
  "proxyAddresses": [
    "SMTP:***"
  ],
  "refreshTokensValidFromDateTime": "2018-06-26T16:28:49Z",
  "showInAddressList": null,
  "signInNames": [],
  "sipProxyAddress": "***",
  "state": "Bayern",
  "streetAddress": "***",
  "surname": "Bach",
  "telephoneNumber": "***",
  "thumbnailPhoto@odata.mediaEditLink": "directoryObjects/***/Microsoft.DirectoryServices.User/thumbnailPhoto",
  "usageLocation": "US",
  "userIdentities": [],
  "userPrincipalName": "***",
  "userState": null,
  "userStateChangedOn": null,
  "userType": "Member",
  "extension_***_personalTitle": "Master of the universe",
  "extension_***_employeeID": "1337"
}

 

Graph API Benutzerinformationen Abruf – Fazit

Wir konnten die Benutzerinformationen aus dem Azure Active Directory erfolgreich abrufen und auf unsere Extension Properties zugreifen.

Dieses Setup war sehr einfach und wir können unsere Attribute regelmäßig für die Systembenutzer synchronisieren. Mit Microsoft Flow ist es einfach, synchronisierte Attribute aufrechtzuerhalten und auszuweiten und die entsprechenden Systembenutzer-Felder zu aktualisieren.

Answering