Have user sign in, but use application permissions instead of delegated permissions ASP.Net MVC Microsoft Graph

0

A need has come up to build an web application in which the users uses Azure AD to sign in for authentication, but the application needs to use permissions it has. This is because the user won't have the permissions.

I have cloned and altered the code here https://github.com/microsoftgraph/msgraph-training-aspnetmvcapp for my purposes and using delegate permissions it works perfectly, but when I try to do application permissions it doesn't like it.

When I attempt to change the code to get application token and pass that to create a graph service client it gives me an error. I have looked everywhere online and tried several different methods, the only thing I haven't tried is using direct HTTPS calls which I want to avoid if possible as the graph service client is easier to deal with IMHO.

Here is the code that runs when the user signs in commented code is for delegated permissions

public partial class Startup
    {
        private static string appId = ConfigurationManager.AppSettings["ida:AppId"];
        private static string appSecret = ConfigurationManager.AppSettings["ida:AppSecret"];
        private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
        private static string graphScopes = ConfigurationManager.AppSettings["ida:AppScopes"];
        private static string tenantId = ConfigurationManager.AppSettings["ida:TenantId"];
        private static string authorityFormat = "https://login.microsoftonline.com/{0}/v2.0";
        private static string msGraphScope = "https://graph.microsoft.com/.default";

        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions());

            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = appId,
                    Authority = "https://login.microsoftonline.com/common/v2.0",
                    Scope = $"openid email profile offline_access {graphScopes}",
                    RedirectUri = redirectUri,
                    PostLogoutRedirectUri = redirectUri,
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = false
                    },
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = OnAuthenticationFailedAsync,
                        AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
                    }
                }
            );
        }

        private static Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage,
          OpenIdConnectAuthenticationOptions> notification)
        {
            notification.HandleResponse();
            string redirect = $"/Home/Error?message={notification.Exception.Message}";
            if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription))
            {
                redirect += $"&debug={notification.ProtocolMessage.ErrorDescription}";
            }
            notification.Response.Redirect(redirect);
            return Task.FromResult(0);
        }

        private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
        {
             var daemonClient = ConfidentialClientApplicationBuilder.Create(appId)
            .WithAuthority(String.Format(authorityFormat, tenantId))
            .WithRedirectUri(redirectUri)
            .WithClientSecret(appSecret)
            .Build();


            //var idClient = ConfidentialClientApplicationBuilder.Create(appId)
            //    .WithRedirectUri(redirectUri)
            //    .WithClientSecret(appSecret)
            //    .Build();

            var signedInUser = new ClaimsPrincipal(notification.AuthenticationTicket.Identity);
            var tokenStore = new SessionTokenStore(daemonClient.UserTokenCache, HttpContext.Current, signedInUser);

            try
            {
                var authResult = await daemonClient.AcquireTokenForClient(new string[] { msGraphScope }).ExecuteAsync();
                string[] scopes = graphScopes.Split(' ');

                //var result = await daemonClient.AcquireTokenByAuthorizationCode(
                //    scopes, notification.Code).ExecuteAsync();

                var userDetails = await GraphHelper.GetUserDetailsAsync(authResult.AccessToken);

                var cachedUser = new CachedUser()
                {
                    DisplayName = userDetails.DisplayName,
                    Email = string.IsNullOrEmpty(userDetails.Mail) ?
                    userDetails.UserPrincipalName : userDetails.Mail,
                    Avatar = string.Empty,
                    Id = userDetails.Id
                };

                tokenStore.SaveUserDetails(cachedUser);
            }
            catch (MsalException ex)
            {
                string message = "AcquireTokenByAuthorizationCodeAsync threw an exception";
                notification.HandleResponse();
                notification.Response.Redirect($"/Home/Error?message={message}&debug={ex.Message}");
            }
            catch (Microsoft.Graph.ServiceException ex)
            {
                string message = "GetUserDetailsAsync threw an exception";
                notification.HandleResponse();
                notification.Response.Redirect($"/Home/Error?message={message}&debug={ex.Message}");
            }
        }
    }

Here is the code that runs to create the graph service client

public static async Task<Microsoft.Graph.User> GetUserDetailsAsync(string accessToken)
        {
            graphClient = new GraphServiceClient(
                new DelegateAuthenticationProvider(
                    async (requestMessage) =>
                    {
                        requestMessage.Headers.Authorization =
                            new AuthenticationHeaderValue("Bearer", accessToken);
                    }));
             return await graphClient.Me.Request().GetAsync();
        }

and finally here is the error I get

Could not load file or assembly 'Microsoft.Graph.Core, Version=1.19.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

If anyone can help it would be greatly appreciated.

c#
asp.net-mvc
asked on Stack Overflow Feb 6, 2020 by chris b

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0