Example #1
0
        /// <summary>
        /// In a Web App, adds, to the MSAL.NET cache, the account of the user authenticating to the Web App, when the authorization code is received (after the user
        /// signed-in and consented)
        /// An On-behalf-of token contained in the <see cref="AuthorizationCodeReceivedContext"/> is added to the cache, so that it can then be used to acquire another token on-behalf-of the
        /// same user in order to call to downstream APIs.
        /// </summary>
        /// <param name="context">The context used when an 'AuthorizationCode' is received over the OpenIdConnect protocol.</param>
        /// <param name="scopes"></param>
        /// <example>
        /// From the configuration of the Authentication of the ASP.NET Core Web API:
        /// <code>OpenIdConnectOptions options;</code>
        ///
        /// Subscribe to the authorization code recieved event:
        /// <code>
        ///  options.Events = new OpenIdConnectEvents();
        ///  options.Events.OnAuthorizationCodeReceived = OnAuthorizationCodeReceived;
        /// }
        /// </code>
        ///
        /// And then in the OnAuthorizationCodeRecieved method, call <see cref="AddAccountToCacheFromAuthorizationCodeAsync"/>:
        /// <code>
        /// private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        /// {
        ///   var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService&lt;ITokenAcquisition&gt;();
        ///    await _tokenAcquisition.AddAccountToCacheFromAuthorizationCode(context, new string[] { "user.read" });
        /// }
        /// </code>
        /// </example>
        public async Task AddAccountToCacheFromAuthorizationCodeAsync(AuthorizationCodeReceivedContext context, IEnumerable <string> scopes)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (scopes == null)
            {
                throw new ArgumentNullException(nameof(scopes));
            }

            try
            {
                // As AcquireTokenByAuthorizationCodeAsync is asynchronous we want to tell ASP.NET core that we are handing the code
                // even if it's not done yet, so that it does not concurrently call the Token endpoint.
                context.HandleCodeRedemption();

                var application = BuildConfidentialClientApplication(context.HttpContext, context.Principal);

                // Do not share the access token with ASP.NET Core otherwise ASP.NET will cache it and will not send the OAuth 2.0 request in
                // case a further call to AcquireTokenByAuthorizationCodeAsync in the future for incremental consent (getting a code requesting more scopes)
                // Share the ID Token
                var result = await application
                             .AcquireTokenByAuthorizationCode(scopes.Except(_scopesRequestedByMsalNet), context.ProtocolMessage.Code)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                context.HandleCodeRedemption(null, result.IdToken);
            }
            catch (MsalException ex)
            {
                Debug.WriteLine(ex.Message);
                throw;
            }
        }
        public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        {
            // Acquire a Token for the Graph API and cache it using ADAL.  In the TodoListController, we'll use the cache to acquire a token to the Todo List API
            context.HttpContext.User = context.Ticket.Principal;
            _serviceProvider.GetService <IHttpContextAccessor>().HttpContext = context.HttpContext;

            TokenCache            tc          = _serviceProvider.GetService <TokenCache>();
            ClientCredential      clientCred  = new ClientCredential(_config.ClientId, _config.ClientSecret);
            AuthenticationContext authContext = new AuthenticationContext(_config.Authority, tc);
            AuthenticationResult  authResult  = await authContext.AcquireTokenByAuthorizationCodeAsync(
                context.ProtocolMessage.Code, new Uri(context.Properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey]), clientCred, "https://graph.windows.net");

            // Notify the OIDC middleware that we already took care of code redemption.
            context.HandleCodeRedemption();
            context.HandleResponse();
        }
Example #3
0
        public static async Task CodeRedemptionAsync(AuthorizationCodeReceivedContext ctx)
        {
            var id_token = ctx.ProtocolMessage.IdToken;
            var code     = ctx.ProtocolMessage.Code;
            IConfidentialClientApplication clientapp = ConfidentialClientApplicationBuilder.Create(Globals.ClientId)
                                                       .WithClientSecret(Globals.ClientSecret)
                                                       .WithRedirectUri(Globals.RedirectUri)
                                                       .WithAuthority(new Uri(Globals.Authority))
                                                       .Build();

            var authResult = await clientapp
                             .AcquireTokenByAuthorizationCode(Globals.BasicSignInScopes, code)
                             .ExecuteAsync();

            ctx.HandleCodeRedemption(authResult.AccessToken, id_token);
        }
        public override async Task AuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        {
            var contextAccessor = context.HttpContext.RequestServices.GetRequiredService <IHttpContextAccessor>();
            var azureOptions    = context.HttpContext.RequestServices.GetRequiredService <IOptionsMonitor <AzureADOptions> >().Get(AzureADDefaults.AuthenticationScheme);

            var userId = context.Principal.FindFirst("oid").Value;

            var adal = new AuthenticationContext($"{azureOptions.Instance}{azureOptions.TenantId}", new ADALSessionCache(userId, contextAccessor));

            var redirect = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}";
            // Store in cache for later redemption

            var res = await adal.AcquireTokenByAuthorizationCodeAsync(context.ProtocolMessage.Code, new Uri(redirect), new ClientCredential(azureOptions.ClientId, azureOptions.ClientSecret), "https://graph.windows.net");

            context.HandleCodeRedemption(res.AccessToken, res.IdToken);
        }
        /// <summary>
        /// This handler is executed after the authorization code is received (once the user signs-in and consents) during the
        /// <a href='https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow'>Authorization code flow grant flow</a> in a web app.
        /// It uses the code to request an access token from the Microsoft Identity platform and caches the tokens and an entry about the signed-in user's account in the MSAL's token cache.
        /// The access token (and refresh token) provided in the <see cref="AuthorizationCodeReceivedContext"/>, once added to the cache, are then used to acquire more tokens using the
        /// <a href='https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow'>on-behalf-of flow</a> for the signed-in user's account,
        /// in order to call to downstream APIs.
        /// </summary>
        /// <param name="context">The context used when an 'AuthorizationCode' is received over the OpenIdConnect protocol.</param>
        /// <param name="scopes">scopes to request access to.</param>
        /// <example>
        /// From the configuration of the Authentication of the ASP.NET Core Web API:
        /// <code>OpenIdConnectOptions options;</code>
        ///
        /// Subscribe to the authorization code received event:
        /// <code>
        ///  options.Events = new OpenIdConnectEvents();
        ///  options.Events.OnAuthorizationCodeReceived = OnAuthorizationCodeReceived;
        /// }
        /// </code>
        ///
        /// And then in the OnAuthorizationCodeRecieved method, call <see cref="AddAccountToCacheFromAuthorizationCodeAsync"/>:
        /// <code>
        /// private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        /// {
        ///   var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService&lt;ITokenAcquisition&gt;();
        ///    await _tokenAcquisition.AddAccountToCacheFromAuthorizationCode(context, new string[] { "user.read" });
        /// }
        /// </code>
        /// </example>
        public async Task AddAccountToCacheFromAuthorizationCodeAsync(
            AuthorizationCodeReceivedContext context,
            IEnumerable <string> scopes)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (scopes == null)
            {
                throw new ArgumentNullException(nameof(scopes));
            }

            try
            {
                string?userFlow = context.Principal?.Claims?.FirstOrDefault(c => c.Type == ClaimConstants.UserFlow)?.Value;
                _application = await GetOrBuildConfidentialClientApplicationAsync().ConfigureAwait(false);

                // Do not share the access token with ASP.NET Core otherwise ASP.NET will cache it and will not send the OAuth 2.0 request in
                // case a further call to AcquireTokenByAuthorizationCodeAsync in the future is required for incremental consent (getting a code requesting more scopes)
                // Share the ID Token though
                var builder = _application
                              .AcquireTokenByAuthorizationCode(scopes.Except(_scopesRequestedByMsal), context.ProtocolMessage.Code)
                              .WithSendX5C(_microsoftIdentityOptions.SendX5C);

                if (_microsoftIdentityOptions.IsB2C)
                {
                    var authority = $"{_applicationOptions.Instance}{Constants.Tfp}/{_microsoftIdentityOptions.Domain}/{userFlow ?? _microsoftIdentityOptions.DefaultUserFlow}";
                    builder.WithB2CAuthority(authority);
                }

                var result = await builder.ExecuteAsync()
                             .ConfigureAwait(false);

                context.HandleCodeRedemption(null, result.IdToken);
            }
            catch (MsalException ex)
            {
                _logger.LogInformation(
                    ex,
                    string.Format(
                        CultureInfo.InvariantCulture,
                        LogMessages.ExceptionOccurredWhenAddingAnAccountToTheCacheFromAuthCode));
                throw;
            }
        }
Example #6
0
        private async Task AcquireTokenForResourceByCode(AuthorizationCodeReceivedContext context, IDistributedCache cache, NaiveSessionCacheResource resource, string resourceId)
        {
            string userObjectID = context.Ticket.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;


            AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID, resource, cache));

            // Acquire a Token for the Graph API and cache it in Session.
            ClientCredential clientCred = new ClientCredential(ClientId, ClientSecret);

            // Per sample: https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore/blob/master/WebApp-WebAPI-OpenIdConnect-DotNet/Startup.cs
            AuthenticationResult authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
                context.ProtocolMessage.Code, new Uri(context.Properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey]), clientCred, resourceId);

            // -- See https://github.com/aspnet/Security/issues/1068
            context.HandleCodeRedemption(authResult.AccessToken, authResult.IdToken);
        }
            //Used to handle when an authCode has been received. Not added by configuration wizard
            private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
            {
                var tokenData = GetTokenData(context);

                //used to exchange the authCode for an access and refresh token and then store those tokens in the token cache.
                //Current token cache is in memory and will need to be updated to an external store before production worthy
                //Not added by configuration wizard
                await _tokenHandler.StoreAccessToken(tokenData);

                //used to obtain the idToken passed in on the signin request
                var idToken = context.ProtocolMessage.IdToken;

                //used to tell the handler to skip the code redemption process. Allows for us to handle the exchanging an authCode
                //for an access token
                //https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.openidconnect.authorizationcodereceivedcontext.handlecoderedemption?view=aspnetcore-2.2
                context.HandleCodeRedemption(null, idToken);
            }
Example #8
0
        /// <summary>
        /// This handler is executed after the authorization code is received (once the user signs-in and consents) during the
        /// <a href='https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow'>authorization code flow</a> in a web app.
        /// It uses the code to request an access token from the Microsoft identity platform and caches the tokens and an entry about the signed-in user's account in the MSAL's token cache.
        /// The access token (and refresh token) provided in the <see cref="AuthorizationCodeReceivedContext"/>, once added to the cache, are then used to acquire more tokens using the
        /// <a href='https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow'>on-behalf-of flow</a> for the signed-in user's account,
        /// in order to call to downstream APIs.
        /// </summary>
        /// <param name="context">The context used when an 'AuthorizationCode' is received over the OpenIdConnect protocol.</param>
        /// <param name="scopes">scopes to request access to.</param>
        /// <example>
        /// From the configuration of the Authentication of the ASP.NET Core web API:
        /// <code>OpenIdConnectOptions options;</code>
        ///
        /// Subscribe to the authorization code received event:
        /// <code>
        ///  options.Events = new OpenIdConnectEvents();
        ///  options.Events.OnAuthorizationCodeReceived = OnAuthorizationCodeReceived;
        /// }
        /// </code>
        ///
        /// And then in the OnAuthorizationCodeRecieved method, call <see cref="AddAccountToCacheFromAuthorizationCodeAsync"/>:
        /// <code>
        /// private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        /// {
        ///   var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService&lt;ITokenAcquisition&gt;();
        ///    await _tokenAcquisition.AddAccountToCacheFromAuthorizationCode(context, new string[] { "user.read" });
        /// }
        /// </code>
        /// </example>
        public async Task AddAccountToCacheFromAuthorizationCodeAsync(
            AuthorizationCodeReceivedContext context,
            IEnumerable <string> scopes)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (scopes == null)
            {
                throw new ArgumentNullException(nameof(scopes));
            }

            try
            {
                var application = GetOrBuildConfidentialClientApplication();

                context.TokenEndpointRequest.Parameters.TryGetValue(OAuthConstants.CodeVerifierKey, out string?codeVerifier);
                // Do not share the access token with ASP.NET Core otherwise ASP.NET will cache it and will not send the OAuth 2.0 request in
                // case a further call to AcquireTokenByAuthorizationCodeAsync in the future is required for incremental consent (getting a code requesting more scopes)
                // Share the ID token though
                var builder = application
                              .AcquireTokenByAuthorizationCode(scopes.Except(_scopesRequestedByMsal), context.ProtocolMessage.Code)
                              .WithSendX5C(_microsoftIdentityOptions.SendX5C)
                              .WithPkceCodeVerifier(codeVerifier);

                if (_microsoftIdentityOptions.IsB2C)
                {
                    string?userFlow  = context.Principal?.GetUserFlowId();
                    var    authority = $"{_applicationOptions.Instance}{ClaimConstants.Tfp}/{_microsoftIdentityOptions.Domain}/{userFlow ?? _microsoftIdentityOptions.DefaultUserFlow}";
                    builder.WithB2CAuthority(authority);
                }

                var result = await builder.ExecuteAsync()
                             .ConfigureAwait(false);

                context.HandleCodeRedemption(null, result.IdToken);
            }
            catch (MsalException ex)
            {
                Logger.TokenAcquisitionError(_logger, LogMessages.ExceptionOccurredWhenAddingAnAccountToTheCacheFromAuthCode, ex);
                throw;
            }
        }
Example #9
0
        private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        {
            // Acquire a Token for the Graph API and cache it using ADAL.
            //In the TodoListController, we'll use the cache to acquire a token to the Todo List API

            string           userObjectId = (context.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
            ClientCredential credential   = new ClientCredential(Configuration["OpenIdConnect:ClientId"],
                                                                 Configuration["OpenIdConnect:ClientSecret"]);

            AuthenticationContext authContext = new AuthenticationContext(Configuration["OpenIdConnect:Authority"],
                                                                          new NaiveSessionCache(userObjectId, context.HttpContext.Session));

            AuthenticationResult authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
                context.ProtocolMessage.Code, new Uri(context.Properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey])
                , credential, Configuration["OpenIdConnect:Resource"]);

            // Notify the OIDC middleware that we already took care of code redemption.
            context.HandleCodeRedemption(authResult.AccessToken, authResult.IdToken);
        }
Example #10
0
        /// <summary>
        /// Redeems the authorization code by calling AcquireTokenByAuthorizationCodeAsync
        /// in order to ensure
        /// that the cache has a token for the signed-in user, which will then enable
        /// the controllers
        /// to call AcquireTokenSilentAsync successfully.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedContext context)
        {
            // Acquire a Token for the API and cache it.
            var credential = new ClientCredential(context.Options.ClientId,
                                                  context.Options.ClientSecret);

            // TODO : Refactor!!!
            var provider    = context.HttpContext.RequestServices.GetRequiredService <ITokenCacheProvider>();
            var tokenCache  = provider.GetCache($"OID:{context.Principal.GetObjectId()}");
            var authContext = new AuthenticationContext(context.Options.Authority, tokenCache);

            var authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
                context.TokenEndpointRequest.Code,
                new Uri(context.TokenEndpointRequest.RedirectUri, UriKind.RelativeOrAbsolute),
                credential, context.Options.Resource);

            // Notify the OIDC middleware that we already took care of code redemption.
            context.HandleCodeRedemption(authResult.AccessToken, context.ProtocolMessage.IdToken);
        }
Example #11
0
            private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
            {
                var code = context.ProtocolMessage.Code;

                var signedInUserID = context.Ticket.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;
                var cca            = new ConfidentialClientApplication(
                    _azureOptions.ClientId,
                    _azureOptions.Authority,
                    _azureOptions.RedirectUri,
                    new ClientCredential(_azureOptions.ClientSecret),
                    userTokenCache: null,
                    appTokenCache: null);

                var result = await cca.AcquireTokenByAuthorizationCodeAsync(code, _azureOptions.ApiScopes.Split(' '));

                context.HandleCodeRedemption(result.AccessToken, result.IdToken);

                _cache.Set(signedInUserID, result.AccessToken);
            }
Example #12
0
        private async Task HandleApiToken(AuthorizationCodeReceivedContext context)
        {
            if (!context.HandledCodeRedemption)
            {
                string                      userId                = context.Principal.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier");
                IDistributedCache           distributedCache      = context.HttpContext.RequestServices.GetService <IDistributedCache>();
                DistributedMemoryTokenCache tokenCache            = new DistributedMemoryTokenCache(userId, distributedCache);
                string                      authority             = context.Options.Authority;
                string                      code                  = context.TokenEndpointRequest.Code;
                string                      resource              = context.Options.Resource;
                string                      clientId              = context.Options.ClientId;
                string                      clientSecret          = context.Options.ClientSecret;
                string                      redirectUri           = context.TokenEndpointRequest.RedirectUri;
                AuthenticationContext       authenticationContext = new AuthenticationContext(authority, true, tokenCache);
                var result = await authenticationContext.AcquireTokenByAuthorizationCodeAsync(code, new Uri(redirectUri), new ClientCredential(clientId, clientSecret), resource);

                context.HandleCodeRedemption(result.AccessToken, result.IdToken);
            }
        }
            private async Task OnAuthroizationCodeReceivedAsync(AuthorizationCodeReceivedContext context)
            {
                var code = context.ProtocolMessage.Code;

                string     signedInUserID         = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;
                TokenCache userTokenCache         = new MSALSessionCache(signedInUserID, context.HttpContext).GetMsalCacheInstance();
                ConfidentialClientApplication cca = new ConfidentialClientApplication(_azureOptions.ClientId, _azureOptions.Authority, "https://localhost:44337/" + $"{_azureOptions.CallbackPath}", new ClientCredential(_azureOptions.ClientSecret), userTokenCache, null);

                try
                {
                    AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, _azureOptions.ApiScopes.Split(' '));

                    context.HandleCodeRedemption(result.AccessToken, result.IdToken);
                }
                catch (Exception ex)
                {
                    throw;
                }
            }
Example #14
0
        protected async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        {
            HttpRequest request = context.HttpContext.Request;
            //We need to also specify the redirect URL used
            string currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
            //Credentials for app itself
            var credential = new ClientCredential(context.Options.ClientId, context.Options.ClientSecret);

            //Construct token cache
            ITokenCacheFactory cacheFactory = context.HttpContext.RequestServices.GetRequiredService <ITokenCacheFactory>();
            TokenCache         cache        = cacheFactory.CreateForUser(context.Principal);
            var authContext = new AuthenticationContext(context.Options.Authority, cache);

            AuthenticationResult authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
                context.ProtocolMessage.Code, new Uri(currentUri), credential, context.Options.Resource);


            // Notify the OIDC middleware that we already took care of code redemption.
            context.HandleCodeRedemption(authResult.AccessToken, context.ProtocolMessage.IdToken);
        }
Example #15
0
        private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        {
            if (!context.HandledCodeRedemption)
            {
                IConfidentialClientApplication confidentialClient =
                    ConfidentialClientApplicationBuilder.Create(Configuration["AzureAD:ClientId"])
                    .WithClientSecret(Configuration["AzureAD:ClientSecret"])
                    .WithAuthority(Configuration["AzureAD:Authority"])
                    .WithRedirectUri(context.TokenEndpointRequest.RedirectUri)
                    .Build();

                string scope = Configuration["AzureAD:Scopes"];
                string code  = context.TokenEndpointRequest.Code;

                var result = await confidentialClient.AcquireTokenByAuthorizationCode(new string[] { scope }, code)
                             .ExecuteAsync();

                context.HandleCodeRedemption(result.AccessToken, result.IdToken);
            }
        }
Example #16
0
        public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        {
            var code = context.ProtocolMessage.Code;

            string SignedInUserID = context.Principal.Claims.FirstOrDefault(x => x.Type.Equals(ClaimTypes.NameIdentifier)).Value;

            TokenCache localTokenCache = new MSALSessionCache(SignedInUserID, context.HttpContext).GetMSALCacheInstance();

            AuthenticationContext authContext = new AuthenticationContext(AzureAdB2cOptions.Authority, localTokenCache);

            ClientCredential ca = new ClientCredential(AzureAdB2cOptions.ClientID, AzureAdB2cOptions.ClientSecret);

            try
            {
                var result = await authContext.AcquireTokenByAuthorizationCodeAsync(code, new System.Uri(AzureAdB2cOptions.RedirectURI), ca, "");

                context.HandleCodeRedemption(result.AccessToken, result.IdToken);
            }
            catch { }
        }
Example #17
0
            public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
            {
                // Use MSAL to swap the code for an access token
                // Extract the code from the response notification
                var code = context.ProtocolMessage.Code;

                string signedInUserID = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;
                IConfidentialClientApplication cca = ConfidentialClientApplicationBuilder.Create(AzureAdB2COptions.ClientId)
                                                     .WithB2CAuthority(AzureAdB2COptions.Authority)
                                                     .WithRedirectUri(AzureAdB2COptions.RedirectUri)
                                                     .WithClientSecret(AzureAdB2COptions.ClientSecret)
                                                     .Build();

                new MSALStaticCache(signedInUserID, context.HttpContext).EnablePersistence(cca.UserTokenCache);

                // This timing's JWT Token is incomplete, missing scp, and could not use for Authentication.

                try
                {
                    // get jwt id_token, accesstoken
                    AuthenticationResult result = await cca.AcquireTokenByAuthorizationCode(AzureAdB2COptions.ApiScopes.Split(' '), code)
                                                  .ExecuteAsync();

                    context.HandleCodeRedemption(result.AccessToken, result.IdToken);

                    var ckey = $".tmp_aspnet_jwtaccesstoken_{context.JwtSecurityToken.Subject}";
                    context.Response.Cookies.Delete(ckey);
                    context.Response.Cookies.Append(ckey, result.AccessToken, new CookieOptions
                    {
                        Expires = DateTimeOffset.UtcNow.AddSeconds(30),
                        MaxAge  = TimeSpan.FromSeconds(30),
                        Secure  = true
                    });
                }
                catch (Exception ex)
                {
                    //TODO: Handle
                    throw;
                }
            }
            /// <summary>
            /// Redeems the authorization code by calling AcquireTokenByAuthorizationCodeAsync in order to ensure
            /// that the cache has a token for the signed-in user, which will then enable the pages (like the
            /// Api page, to call AcquireTokenSilentAsync successfully.
            /// </summary>
            private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
            {
                // Acquire a Token for the API and cache it using ADAL. In the Api page, we'll use the cache to acquire a token for the Todo List API
                string userObjectId = (context.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
                var    authContext  = new AuthenticationContext(
                    authority: context.Options.Authority,
                    tokenCache: new NaiveSessionCache(
                        userId: userObjectId,
                        cache: _memoryCache));
                var credential = new ClientCredential(
                    clientId: context.Options.ClientId,
                    clientSecret: context.Options.ClientSecret);

                var authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
                    authorizationCode : context.TokenEndpointRequest.Code,
                    redirectUri : new Uri(context.TokenEndpointRequest.RedirectUri, UriKind.RelativeOrAbsolute),
                    clientCredential : credential,
                    resource : context.Options.Resource);

                // Notify the OIDC middleware that we already took care of code redemption.
                context.HandleCodeRedemption(authResult.AccessToken, context.ProtocolMessage.IdToken);
            }
Example #19
0
        public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        {
            // Use MSAL to swap the code for an access token
            // Extract the code from the response notification
            var code = context.ProtocolMessage.Code;

            string     signedInUserID         = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;
            TokenCache userTokenCache         = new MSALSessionCache(signedInUserID, context.HttpContext).GetMsalCacheInstance();
            ConfidentialClientApplication cca = new ConfidentialClientApplication(AzureAdB2COptions.ClientId, AzureAdB2COptions.Authority, AzureAdB2COptions.RedirectUri, new ClientCredential(AzureAdB2COptions.ClientSecret), userTokenCache, null);

            try
            {
                AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, AzureAdB2COptions.ApiScopes.Split(' '));

                context.HandleCodeRedemption(result.AccessToken, result.IdToken);
            }
            catch (Exception ex)
            {
                //TODO: Handle
                throw;
            }
        }
Example #20
0
        /// <summary>
        /// This handler is executed after the authorization code is received (once the user signs-in and consents) during the
        /// <a href='https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow'>Authorization code flow grant flow</a> in a web app.
        /// It uses the code to request an access token from the Microsoft Identity platform and caches the tokens and an entry about the signed-in user's account in the MSAL's token cache.
        /// The access token (and refresh token) provided in the <see cref="AuthorizationCodeReceivedContext"/>, once added to the cache, are then used to acquire more tokens using the
        /// <a href='https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow'>on-behalf-of flow</a> for the signed-in user's account,
        /// in order to call to downstream APIs.
        /// </summary>
        /// <param name="context">The context used when an 'AuthorizationCode' is received over the OpenIdConnect protocol.</param>
        /// <param name="scopes">scopes to request access to.</param>
        /// <example>
        /// From the configuration of the Authentication of the ASP.NET Core Web API:
        /// <code>OpenIdConnectOptions options;</code>
        ///
        /// Subscribe to the authorization code received event:
        /// <code>
        ///  options.Events = new OpenIdConnectEvents();
        ///  options.Events.OnAuthorizationCodeReceived = OnAuthorizationCodeReceived;
        /// }
        /// </code>
        ///
        /// And then in the OnAuthorizationCodeRecieved method, call <see cref="AddAccountToCacheFromAuthorizationCodeAsync"/>:
        /// <code>
        /// private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        /// {
        ///   var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService&lt;ITokenAcquisition&gt;();
        ///    await _tokenAcquisition.AddAccountToCacheFromAuthorizationCode(context, new string[] { "user.read" });
        /// }
        /// </code>
        /// </example>
        public async Task AddAccountToCacheFromAuthorizationCodeAsync(
            AuthorizationCodeReceivedContext context,
            IEnumerable <string> scopes)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (scopes == null)
            {
                throw new ArgumentNullException(nameof(scopes));
            }

            try
            {
                _application = await GetOrBuildConfidentialClientApplicationAsync().ConfigureAwait(false);

                // Do not share the access token with ASP.NET Core otherwise ASP.NET will cache it and will not send the OAuth 2.0 request in
                // case a further call to AcquireTokenByAuthorizationCodeAsync in the future is required for incremental consent (getting a code requesting more scopes)
                // Share the ID Token though
                var result = await _application
                             .AcquireTokenByAuthorizationCode(scopes.Except(_scopesRequestedByMsal), context.ProtocolMessage.Code)
                             .WithSendX5C(_microsoftIdentityOptions.SendX5C)
                             .ExecuteAsync()
                             .ConfigureAwait(false);

                context.HandleCodeRedemption(null, result.IdToken);
            }
            catch (MsalException ex)
            {
                _logger.LogInformation(
                    ex,
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Exception occurred while adding an account to the cache from the auth code. "));
                throw;
            }
        }
            /// <summary>
            /// Method to handle the event upon successful login and authorization code is received
            /// This method further acquires the access token and store it in the user context in order to get it accessed by the login action
            /// </summary>
            /// <param name="context"> The context that contains authorization code received from Azure AD B2C </param>
            /// <returns></returns>
            public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
            {
                // Use MSAL to swap the code for an access token
                // Extract the code from the response notification
                var code = context.ProtocolMessage.Code;

                // Get the signed in user's Object ID
                string signedInUserID = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;

                // Creating client application withe the required configuration to request the token
                IConfidentialClientApplication cca = ConfidentialClientApplicationBuilder.Create(AzureAdB2C.ClientId)
                    .WithB2CAuthority(AzureAdB2C.Authority)
                    .WithClientSecret(AzureAdB2C.ClientSecret)
                    .Build();

                // Static cache that sign-in flow uses on transit intermediately on callback
                new MSALStaticCache(signedInUserID, context.HttpContext).EnablePersistence(cca.UserTokenCache);

                try
                {
                    // Acquire the token based on authorization code received
                    AuthenticationResult result = await cca.AcquireTokenByAuthorizationCode(AzureAdB2C.ApiScopes.Split(DataConstant.Space), code)
                        .ExecuteAsync();

                    // Setting the context that the user is signed-in
                    context.HandleCodeRedemption(result.AccessToken, result.IdToken);

                    // Store the received Id Token to make it available for the controller to return to the request
                    context.HttpContext.Session.SetString(DataConstant.IdToken, result.IdToken);

                }
                catch (Exception ex)
                {
                    // Throw the exception to log the failure message in ApplicationInsights AND respond user with system failure message
                    // This is further handled by ExceptionAttribute class
                    throw ex;
                }
            }
Example #22
0
        private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        {
            string authority    = context.Options.Authority;
            string clientId     = context.Options.ClientId;
            string clientSecret = context.Options.ClientSecret;
            string redirectUri  = context.TokenEndpointRequest.RedirectUri;

            string code = context.TokenEndpointRequest.Code;
            IEnumerable <string> scopes = context.Options.Scope.ToList();

            IConfidentialClientApplication app = ConfidentialClientApplicationBuilder
                                                 .Create(clientId)
                                                 .WithClientSecret(clientSecret)
                                                 .WithB2CAuthority(authority)
                                                 .WithRedirectUri(redirectUri)
                                                 .Build();

            var result = await app.AcquireTokenByAuthorizationCode(scopes, code)
                         .WithB2CAuthority(authority)
                         .ExecuteAsync();

            context.HandleCodeRedemption(result.AccessToken, result.IdToken);
        }
Example #23
0
            /// <summary>
            /// Redeems the authorization code by calling AcquireTokenByAuthorizationCodeAsync in order to ensure
            /// that the cache has a token for the signed-in user, which will then enable the controllers (like the
            /// TodoController, to call AcquireTokenSilentAsync successfully.
            /// </summary>
            private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
            {
                // refresh app secret
                await _azureOptions.InitializeAsync();

                // at this point you can augment the claim's principal if you know they belong to a special admin group or
                // have different privledges.
                string userObjectId = context.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;

                // retrieve the distributed cache and cache the access token by the user's object id.
                // for the local sample, a memory cache will be used and the session will not persist.
                IDistributedCache cache = context.HttpContext.RequestServices.GetRequiredService <IDistributedCache>();
                var mapsCache           = new NaiveSessionCache(userObjectId, cache);
                var mapsAuthContext     = new AuthenticationContext(context.Options.Authority, mapsCache);

                var credential = new ClientCredential(context.Options.ClientId, context.Options.ClientSecret);
                var authResult = await mapsAuthContext.AcquireTokenByAuthorizationCodeAsync(context.TokenEndpointRequest.Code,
                                                                                            new Uri(context.TokenEndpointRequest.RedirectUri, UriKind.RelativeOrAbsolute), credential,
                                                                                            context.Options.Resource);

                // Notify the OIDC middleware that we already took care of code redemption.
                context.HandleCodeRedemption(authResult.AccessToken, context.ProtocolMessage.IdToken);
            }
            public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
            {
                // Use MSAL to swap the code for an access token
                // Extract the code from the response notification
                var code = context.ProtocolMessage.Code;

                //var Identity = context.Principal.Identity as ClaimsIdentity;
                //Identity.RemoveClaim(Identity.FindFirst("Name"));


                string signedInUserID = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;
                IConfidentialClientApplication cca = ConfidentialClientApplicationBuilder.Create(AzureAdB2COptions.ClientId)
                                                     .WithB2CAuthority(AzureAdB2COptions.Authority)
                                                     .WithRedirectUri(AzureAdB2COptions.RedirectUri)
                                                     .WithClientSecret(AzureAdB2COptions.ClientSecret)
                                                     .Build();

                new MSALStaticCache(signedInUserID, context.HttpContext).EnablePersistence(cca.UserTokenCache);

                if (context.Principal != null)
                {
                    using (var scope = _scopeFactory.CreateScope())
                    {
                        var db = scope.ServiceProvider.GetRequiredService <DataContext>();

                        string email = context.Principal.Identities.First().Claims.Where(x => x.Type == "emails").First().Value;

                        var user = db.User.Include(x => x.Role).Where(x => x.EmailAdress == email).FirstOrDefault();

                        if (user == null)
                        {
                            string firstName = context.Principal.Identities.First().Claims.Where(x => x.Type == ClaimTypes.GivenName).First().Value;
                            string lastName  = context.Principal.Identities.First().Claims.Where(x => x.Type == ClaimTypes.Surname).First().Value;

                            db.User.Add(new User()
                            {
                                EmailAdress = email, RoleId = 3, FirstName = firstName, LastName = lastName, PhoneNumber = "111111111"
                            });
                            db.SaveChanges();

                            user = db.User.Include(x => x.Role).Where(x => x.EmailAdress == email).FirstOrDefault();
                        }

                        var Identity = context.Principal.Identity as ClaimsIdentity;
                        if (Identity.FindFirst("Name") != null)
                        {
                            Identity.RemoveClaim(Identity.FindFirst("Name"));
                        }
                        context.Principal.Identities.First().AddClaim(new Claim(ClaimTypes.Role, user.Role.Name));
                        context.Principal.Identities.First().AddClaim(new Claim(context.Principal.Identities.First().NameClaimType, user.FirstName + " " + user.LastName));
                    }

                    var p = context.Principal.Identities.First();
                }

                try
                {
                    AuthenticationResult result = await cca.AcquireTokenByAuthorizationCode(AzureAdB2COptions.ApiScopes.Split(' '), code)
                                                  .ExecuteAsync();

                    context.HandleCodeRedemption(result.AccessToken, result.IdToken);
                }
                catch
                {
                    //TODO: Handle
                    throw;
                }
            }