Example #1
0
            // TokenValidated event
            private Task TokenValidated(Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext context)
            {
                /* ---------------------
                *  // Replace this with your logic to validate the issuer/tenant
                *  ---------------------
                *  // Retriever caller data from the incoming principal
                *  string issuer = context.SecurityToken.Issuer;
                *  string subject = context.SecurityToken.Subject;
                *  string tenantID = context.Ticket.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
                *
                *  // Build a dictionary of approved tenants
                *  IEnumerable<string> approvedTenantIds = new List<string>
                *  {
                *   "<Your tenantID>",
                *   "9188040d-6c67-4c5b-b112-36a304b66dad" // MSA Tenant
                *  };
                *
                *  if (!approvedTenantIds.Contains(tenantID))
                *   throw new SecurityTokenValidationException();
                *  --------------------- */

                // Store the token in the token cache

                return(Task.FromResult(0));
            }
        /// <summary>
        /// This method contains the logic that validates the user's tenant and normalizes claims.
        /// </summary>
        /// <param name="context">The validated token context</param>
        /// <returns>A task</returns>
        public override async Task TokenValidated(TokenValidatedContext context)
        {
            var principal = context.Ticket.Principal;
            var tenantManager = context.HttpContext.RequestServices.GetService<TenantManager>();
            var userManager = context.HttpContext.RequestServices.GetService<UserManager>();
            var issuerValue = principal.GetIssuerValue();
            var tenant = await tenantManager.FindByIssuerValueAsync(issuerValue);

            // the caller comes from an admin-consented, recorded issuer
            if (tenant == null)
            {
                _logger.TokenValidationFailed(principal.GetObjectIdentifierValue(), issuerValue);
                // the caller was not from a trusted issuer - throw to block the authentication flow
                throw new SecurityTokenValidationException();
            }

            var identity = principal.Identities.First();

            // Adding new Claim for survey_userid
            var registeredUser = await userManager.FindByObjectIdentifier(principal.GetObjectIdentifierValue());
            identity.AddClaim(new Claim(SurveyClaimTypes.SurveyUserIdClaimType, registeredUser.Id.ToString()));
            identity.AddClaim(new Claim(SurveyClaimTypes.SurveyTenantIdClaimType, registeredUser.TenantId.ToString()));

            // Adding new Claim for Email
            var email = principal.FindFirst(ClaimTypes.Upn)?.Value;
            if (!string.IsNullOrWhiteSpace(email))
            {
                identity.AddClaim(new Claim(ClaimTypes.Email, email));
            }
            _logger.TokenValidationSucceeded(principal.GetObjectIdentifierValue(), issuerValue);
        }
Example #3
0
            // TokenValidated event
            private Task TokenValidated(Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext context)
            {
                //Replace this with your logic to validate the issuer/tenant

                // Store the token in the token cache

                return(Task.FromResult(0));
            }
            // TokenValidated event
            private Task TokenValidatedAsync(Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext context)
            {
                // Check if tenant is allowed
                string tenantID = context.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;

                if (!_azureOptions.TenantId.Equals(tenantID, StringComparison.InvariantCultureIgnoreCase) && !_azureOptions.AllowedTenants.Any(x => x.Equals(tenantID, StringComparison.InvariantCultureIgnoreCase)))
                {
                    return(Task.FromException(new SecurityTokenException("The tenant is not allowed.")));
                }

                return(Task.FromResult(0));
            }
Example #5
0
            async Task OnTokenValidated(JwtBearer.TokenValidatedContext tokenValidatedContext)
            {
                var passed = false;

                var identity = (ClaimsIdentity)tokenValidatedContext.Principal.Identity;

                // See if there's a UPN, and if so, use that object id
                var upn = identity.Claims.FirstOrDefault(c => c.Type == "upn")?.Value;

                if (upn != null)
                {
                    var oid = identity.Claims.FirstOrDefault(c => c.Type == "oid")?.Value;

                    // get the user
                    var context    = new AuthenticationContext($"{_azureOptions.AADInstance}{_azureOptions.TenantId}", null); // No token caching
                    var credential = new ClientCredential(_azureOptions.ClientId, _azureOptions.ClientSecret);

                    var incomingToken = ((JwtSecurityToken)tokenValidatedContext.SecurityToken).RawData;
                    var result        = await context.AcquireTokenAsync(graphResourceId, credential, new UserAssertion(incomingToken));

                    var       url  = $"{adminOptions.Value.GraphInstance}{_azureOptions.TenantId}/users/{oid}?api-version=1.6";
                    GraphUser user = null;
                    using (var client = new HttpClient())
                    {
                        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
                        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                        var resp = await client.GetAsync(url).ConfigureAwait(false);

                        if (resp.IsSuccessStatusCode)
                        {
                            user = JsonConvert.DeserializeObject <GraphUser>(await resp.Content.ReadAsStringAsync().ConfigureAwait(false));
                        }
                    }

                    if (user?.SignServiceConfigured == true)
                    {
                        passed = true;

                        identity.AddClaim(new Claim("keyVaultUrl", user.KeyVaultUrl));
                        identity.AddClaim(new Claim("keyVaultCertificateName", user.KeyVaultCertificateName));
                        identity.AddClaim(new Claim("timestampUrl", user.TimestampUrl));
                        identity.AddClaim(new Claim("access_token", incomingToken));
                    }
                }

                if (!passed)
                {
                    // If we get here, it's an unknown value
                    tokenValidatedContext.Fail("User is not configured");
                }

                telemetryClient.Context.User.AuthenticatedUserId = upn;
            }
Example #6
0
        /// <summary>
        /// In a Web API, adds to the MSAL.NET cache, the account of the user for which a bearer token was received when the Web API was called.
        /// An access token and a refresh token are added to the cache, so that they can then be used to acquire another token on-behalf-of the
        /// same user in order to call to downstream APIs.
        /// </summary>
        /// <param name="tokenValidationContext">Token validation context passed to the handler of the OnTokenValidated event
        /// for the JwtBearer middleware</param>
        /// <param name="scopes">[Optional] scopes to pre-request for a downstream API</param>
        /// <example>
        /// From the configuration of the Authentication of the ASP.NET Core Web API (for example in the Startup.cs file)
        /// <code>JwtBearerOptions option;</code>
        ///
        /// Subscribe to the token validated event:
        /// <code>
        /// options.Events = new JwtBearerEvents();
        /// options.Events.OnTokenValidated = async context =>
        /// {
        ///   var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>();
        ///   tokenAcquisition.AddAccountToCacheFromJwt(context);
        /// };
        /// </code>
        /// </example>
        public void AddAccountToCacheFromJwt(JwtBearer.TokenValidatedContext tokenValidatedContext, IEnumerable <string> scopes)
        {
            if (tokenValidatedContext == null)
            {
                throw new ArgumentNullException(nameof(tokenValidatedContext));
            }

            AddAccountToCacheFromJwt(scopes,
                                     tokenValidatedContext.SecurityToken as JwtSecurityToken,
                                     tokenValidatedContext.Properties,
                                     tokenValidatedContext.Principal,
                                     tokenValidatedContext.HttpContext);
        }
Example #7
0
        private Task OnTokenValidated(Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext context)
        {
            // Example of how to validate for Microsoft Account + specific Azure AD tenant
            // Replace this with your logic to validate the issuer/tenant
            // Retriever caller data from the incoming principal
            string issuer   = context.SecurityToken.Issuer;
            string tenantID = context.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;

            // Build a dictionary of approved tenants
            IEnumerable <string> approvedTenantIds = new List <string>
            {
                Configuration["AzureAd:Tenant"], //{tenantid}
            };

            if (!approvedTenantIds.Contains(tenantID))
            {
                throw new SecurityTokenValidationException();
            }

            return(Task.FromResult(0));
        }
Example #8
0
        /// <summary>
        /// Searches the 'Authorization' header for a 'Bearer' token. If the 'Bearer' token is found, it is validated using <see cref="TokenValidationParameters"/> set in the options.
        /// </summary>
        /// <returns></returns>
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            string token = null;

            try
            {
                // Give application opportunity to find from a different location, adjust, or reject token
                var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options);

                // event can set the token
                await Events.MessageReceived(messageReceivedContext);

                if (messageReceivedContext.Result != null)
                {
                    return(messageReceivedContext.Result);
                }

                // If application retrieved token from somewhere else, use that.
                token = messageReceivedContext.Token;

                if (string.IsNullOrEmpty(token))
                {
                    string authorization = Request.Headers["Authorization"];

                    // If no authorization header found, nothing to process further
                    if (string.IsNullOrEmpty(authorization))
                    {
                        return(AuthenticateResult.NoResult());
                    }

                    if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
                    {
                        token = authorization.Substring("Bearer ".Length).Trim();
                    }

                    // If no token found, no further work possible
                    if (string.IsNullOrEmpty(token))
                    {
                        return(AuthenticateResult.NoResult());
                    }
                }

                if (_configuration == null && Options.ConfigurationManager != null)
                {
                    _configuration = await Options.ConfigurationManager.GetConfigurationAsync(Context.RequestAborted);
                }

                var validationParameters = Options.TokenValidationParameters.Clone();
                if (_configuration != null)
                {
                    var issuers = new[] { _configuration.Issuer };
                    validationParameters.ValidIssuers = validationParameters.ValidIssuers?.Concat(issuers) ?? issuers;

                    validationParameters.IssuerSigningKeys = validationParameters.IssuerSigningKeys?.Concat(_configuration.SigningKeys)
                                                             ?? _configuration.SigningKeys;
                }

                List <Exception> validationFailures = null;
                SecurityToken    validatedToken;
                foreach (var validator in Options.SecurityTokenValidators)
                {
                    if (validator.CanReadToken(token))
                    {
                        ClaimsPrincipal principal;
                        try
                        {
                            principal = validator.ValidateToken(token, validationParameters, out validatedToken);
                        }
                        catch (Exception ex)
                        {
                            Logger.TokenValidationFailed(token, ex);

                            // Refresh the configuration for exceptions that may be caused by key rollovers. The user can also request a refresh in the event.
                            if (Options.RefreshOnIssuerKeyNotFound && Options.ConfigurationManager != null &&
                                ex is SecurityTokenSignatureKeyNotFoundException)
                            {
                                Options.ConfigurationManager.RequestRefresh();
                            }

                            if (validationFailures == null)
                            {
                                validationFailures = new List <Exception>(1);
                            }
                            validationFailures.Add(ex);
                            continue;
                        }

                        Logger.TokenValidationSucceeded();

                        var tokenValidatedContext = new TokenValidatedContext(Context, Scheme, Options)
                        {
                            Principal     = principal,
                            SecurityToken = validatedToken
                        };

                        await Events.TokenValidated(tokenValidatedContext);

                        if (tokenValidatedContext.Result != null)
                        {
                            return(tokenValidatedContext.Result);
                        }

                        if (Options.SaveToken)
                        {
                            tokenValidatedContext.Properties.StoreTokens(new[]
                            {
                                new AuthenticationToken {
                                    Name = "access_token", Value = token
                                }
                            });
                        }

                        tokenValidatedContext.Success();
                        return(tokenValidatedContext.Result);
                    }
                }

                if (validationFailures != null)
                {
                    var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options)
                    {
                        Exception = (validationFailures.Count == 1) ? validationFailures[0] : new AggregateException(validationFailures)
                    };

                    await Events.AuthenticationFailed(authenticationFailedContext);

                    if (authenticationFailedContext.Result != null)
                    {
                        return(authenticationFailedContext.Result);
                    }

                    return(AuthenticateResult.Fail(authenticationFailedContext.Exception));
                }

                return(AuthenticateResult.Fail("No SecurityTokenValidator available for token: " + token ?? "[null]"));
            }
            catch (Exception ex)
            {
                Logger.ErrorProcessingMessage(ex);

                var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options)
                {
                    Exception = ex
                };

                await Events.AuthenticationFailed(authenticationFailedContext);

                if (authenticationFailedContext.Result != null)
                {
                    return(authenticationFailedContext.Result);
                }

                throw;
            }
        }
Example #9
0
 /// <summary>
 /// Invoked after the security token has passed validation and a ClaimsIdentity has been generated.
 /// </summary>
 public virtual Task TokenValidated(TokenValidatedContext context) => OnTokenValidated(context);
Example #10
0
 public virtual Task TokenValidated(TokenValidatedContext context) => OnTokenValidated(context);
 private Task JwtBearerTokenValidated(Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext arg)
 {
     _logger.LogDebug("JwtBearerTokenValidated!");
     return(Task.FromResult(0));
 }
 // TokenValidated event
 private Task TokenValidated(Microsoft.AspNetCore.Authentication.JwtBearer.TokenValidatedContext context)
 {
     // Store the token in the token cache
     return(Task.FromResult(0));
 }
 private static Task OnTokenValidated(TokenValidatedContext arg) => Task.CompletedTask;
Example #14
0
 private static Task OnTokenValidated(TokenValidatedContext arg)
 {
     Console.WriteLine(arg);
     return(Task.FromResult(0));
 }