Skip to content

Office.Cloud.Microsoft

apobekiaris edited this page Oct 17, 2020 · 23 revisions

GitHub issues GitHub close issues

About

The Microsoft authenticates against Azure Active Directory and queries the MSGraph endpoints.

Details


Credits: to Brokero that sponsor the initial implementation of this module.


This is a platform agnostic module.

App Service configuration

First off you have to create an Azure application following the next steps:

  1. Go to App registrations in the Azure portal.
  2. Select New registration, then enter an application name.
  3. Select the Supported account types, depending on your case.
  4. Select Register and copy the Application (Client) ID to the related XAF model entry.
  5. From the left pane, select Authentication.
    • If you target the XAF web click on Add Platform, select Web enter a uri like http://localhost:2064/login.aspx and and copy this value to the related XAF model entry. Enable the implicit grant flow by selecting both Access Token and ID Tokens.
    • If you target the XAF win click on Add Platform and select Mobile and desktop applications. Check on one of the predefined Url e.g the https://login.live.com/oauth20_desktop.srf and copy this value to the related XAF model entry.
  6. From the left pane, select Certificates & secrets > New client secret. Enter a description, select the validity duration, and select Add. Copy the value into the related XAF model entry. This step is only required for Web applications.
  7. From the left pane, select API permissions > Add a permission to configure additional endpoint access. In the Query the MSGraph endpoints you can see an example of how to use the API to query the User endpoint. Copy these permissions to into the related XAF model.
  8. The related XAF model is available at: image

Authentication

The module does not replace nor requires the XAF authentication. The module will use the credentials from the application configuration file authenticate/link it self with the Azure application. To authenticate, the end user must execute the Sign in with Microsoft action. If XAF has security installed the action is only active in current user profile, else it is always active. Once there is a valid authentication the Sign in with Microsoft action will be deactivated and the Sing out Microsoft will be activated.

For both platforms once the user authenticated the RefreshToken and AccessToken will be saved with the help of the MSAuthentication business object. When the AccessToken expires the module will use the RefreshToken to silently request a new AccessToken until the lifetime limit reached (6 months). If the MSAuthentication contains data for the current user and a new AccessToken cannot be acquired, a message will notify the end user to navigate to his/her profile for authentication.

Query the MSGraph endpoints

In the screencast on the examples section, we executed the Show MS Account Info action to display a popup view with all the details of the connected MS account. Below is all the module code used for it:

internal static class ShowMSAccountInfoService{
	// The ShowMSAccountInfo action declaration. Refer to the Reactive module wiki for details
	public static SimpleAction ShowMSAccountInfo(this (AgnosticModule, Frame frame) tuple) => 
		tuple.frame.Action(nameof(ShowMSAccountInfo)).As<SimpleAction>();

	public static IObservable<Unit> ShowMSAccountInfo(this ApplicationModulesManager manager){
		//export the Microsoft.Graph.User as we want to display as XAF view for it
		manager.Modules.OfType<AgnosticModule>().First().AdditionalExportedTypes.Add(typeof(Microsoft.Graph.User));
		//The ShowMSAccountInfo registration. Refer to the Reactive module wiki for details.
		//also we publish the registration as we want to reuse it without running it twice
		var registerViewSimpleAction = manager.RegisterViewSimpleAction(nameof(ShowMSAccountInfo)).ActivateInUserDetails().Publish().RefCount(); 
		//when the application is available at runtime we chain the ShowMSAccountInfo action execute event to the ShowAccountInfoView method
		return manager.WhenApplication(application => registerViewSimpleAction.WhenExecute().ShowAccountInfoView().ToUnit())
			//subscribe early before an application is created to expose the action to the design time enviroment.
			.Merge(registerViewSimpleAction.ToUnit());
	}

	private static IObservable<User> ShowAccountInfoView(this IObservable<SimpleActionExecuteEventArgs> source) =>
		source.SelectMany(e => {
				e.ShowViewParameters.CreatedView = e.Action.Application.NewView(ViewType.DetailView, typeof(User));
				e.ShowViewParameters.TargetWindow = TargetWindow.NewWindow;
				//we get the OutlookUser and display it on a view
				return e.Action.Application.OutlookUser().ObserveOn(SynchronizationContext.Current)
					.Do(user => e.ShowViewParameters.CreatedView.CurrentObject = user);
			});

	//authorize to get the MSClient and use it to query the Me endpoint
	private static IObservable<User> OutlookUser(this XafApplication application) =>
		application.AuthorizeMS().SelectMany(client => client.Me.Request().GetAsync());
}

Prerequisites

In order to execute the asynchronous operations:

  1. The Async attribute the Default.aspx must be true.

    <%@ Page Language="C#" AutoEventWireup="true" Inherits="Default" EnableViewState="false"
     ValidateRequest="false" CodeBehind="Default.aspx.cs" Async="true" %>
  2. The AspNetSynchronizationContext context should be used by setting the targetFramework to a value greater than 4.5.1 in the web.config.

    <system.web>
     <httpRuntime targetFramework="4.5.1"/>

Possible future improvements:

  1. Authenticate against XAF.
  2. Any other need you may have.

Let me know if you want me to implement them for you.


Examples

Below is a demonstration of the package authenticating against AAD for both Win/Web. Also the API is used to call the MSGraph Me endpoint for displaying the authenticated user info in a XAF view. At the bottom the Reactive.Logger.Client.Win is reporting as the module is used. This demo is Easytested with this script for the last three XAF major versions, compliments of the Xpand.VersionConverter

Xpand XAF Modules Office Cloud Microsoft

image

Also, refer to:

Installation

  1. First you need the nuget package so issue this command to the VS Nuget package console

    Install-Package Xpand.XAF.Modules.Office.Cloud.Microsoft.

    The above only references the dependencies and nexts steps are mandatory.

  2. Ways to Register a Module or simply add the next call to your module constructor

    RequiredModuleTypes.Add(typeof(Xpand.XAF.Modules.Office.Cloud.MicrosoftModule));

Versioning

The module is not bound to DevExpress versioning, which means you can use the latest version with your old DevExpress projects Read more.

The module follows the Nuget Version Basics.

Dependencies

.NetFramework: net461

DevExpress.Persistent.Base Any
Fasterflect.Xpand 2.0.7
JetBrains.Annotations 2020.1.0
Microsoft.Graph.Beta 0.18.0-preview
Microsoft.Graph.Core 1.19.0
Microsoft.Identity.Client 4.13.0
Microsoft.IdentityModel.Protocols.OpenIdConnect 6.6.0
Microsoft.IdentityModel.Tokens 6.6.0
Microsoft.Owin 4.1.0
Microsoft.Owin.Host.SystemWeb 4.1.0
Microsoft.Owin.Security 4.1.0
Microsoft.Owin.Security.Cookies 4.1.0
Microsoft.Owin.Security.OpenIdConnect 4.1.0
Newtonsoft.Json 12.0.3
Owin 1.0.0
System.Reactive 4.4.1
System.ValueTuple 4.5.0
Xpand.Extensions 2.202.57
Xpand.Extensions.Office.Cloud 2.202.58
Xpand.Extensions.Reactive 2.202.58
Xpand.Extensions.XAF 2.202.58
Xpand.XAF.Modules.Reactive 2.202.58
Xpand.VersionConverter 2.202.10

Issues-Debugging-Troubleshooting

To Step in the source code you need to enable Source Server support in your Visual Studio/Tools/Options/Debugging/Enable Source Server Support. See also How to boost your DevExpress Debugging Experience.

If the package is installed in a way that you do not have access to uninstall it, then you can unload it with the next call at the constructor of your module.

Xpand.XAF.Modules.Reactive.ReactiveModuleBase.Unload(typeof(Xpand.XAF.Modules.Office.Cloud.Microsoft.Office.Office.Cloud.MicrosoftModule))

Tests

The module is tested on Azure for each build with these tests. All Tests run as per our Compatibility Matrix