コード例 #1
0
 /// <inheritdoc/>
 public Task ReplyForbiddenWithWwwAuthenticateHeaderAsync(IEnumerable <string> scopes, MsalUiRequiredException msalServiceException, HttpResponse?httpResponse = null)
 {
     // Not implemented for the moment
     throw new NotImplementedException();
 }
コード例 #2
0
        /// <summary>
        /// Used in web APIs (no user interaction).
        /// Replies to the client through the HTTP response by sending a 403 (forbidden) and populating the 'WWW-Authenticate' header so that
        /// the client, in turn, can trigger a user interaction so that the user consents to more scopes.
        /// </summary>
        /// <param name="scopes">Scopes to consent to.</param>
        /// <param name="msalServiceException">The <see cref="MsalUiRequiredException"/> that triggered the challenge.</param>
        /// <param name="httpResponse">The <see cref="HttpResponse"/> to update.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task ReplyForbiddenWithWwwAuthenticateHeaderAsync(IEnumerable <string> scopes, MsalUiRequiredException msalServiceException, HttpResponse?httpResponse = null)
        {
            // A user interaction is required, but we are in a web API, and therefore, we need to report back to the client through a 'WWW-Authenticate' header https://tools.ietf.org/html/rfc6750#section-3.1
            string proposedAction = Constants.Consent;

            if (msalServiceException.ErrorCode == MsalError.InvalidGrantError)
            {
                if (AcceptedTokenVersionMismatch(msalServiceException))
                {
                    throw msalServiceException;
                }
            }

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

            string consentUrl = $"{_application.Authority}/oauth2/v2.0/authorize?client_id={_applicationOptions.ClientId}"
                                + $"&response_type=code&redirect_uri={_application.AppConfig.RedirectUri}"
                                + $"&response_mode=query&scope=offline_access%20{string.Join("%20", scopes)}";

            IDictionary <string, string> parameters = new Dictionary <string, string>()
            {
                { Constants.ConsentUrl, consentUrl },
                { Constants.Claims, msalServiceException.Claims },
                { Constants.Scopes, string.Join(",", scopes) },
                { Constants.ProposedAction, proposedAction },
            };

            string parameterString = string.Join(", ", parameters.Select(p => $"{p.Key}=\"{p.Value}\""));

            httpResponse ??= CurrentHttpContext?.Response;

            if (httpResponse == null)
            {
                throw new InvalidOperationException(IDWebErrorMessage.HttpContextAndHttpResponseAreNull);
            }

            var headers = httpResponse.Headers;

            httpResponse.StatusCode = (int)HttpStatusCode.Forbidden;

            headers[HeaderNames.WWWAuthenticate] = new StringValues($"{Constants.Bearer} {parameterString}");
        }
コード例 #3
0
        /// <summary>
        /// Used in Web APIs (which therefore cannot have an interaction with the user).
        /// Replies to the client through the HttpReponse by sending a 403 (forbidden) and populating wwwAuthenticateHeaders so that
        /// the client can trigger an iteraction with the user so that the user consents to more scopes
        /// </summary>
        /// <param name="httpContext">HttpContext</param>
        /// <param name="scopes">Scopes to consent to</param>
        /// <param name="msalSeviceException"><see cref="MsalUiRequiredException"/> triggering the challenge</param>

        public void ReplyForbiddenWithWwwAuthenticateHeader(HttpContext httpContext, IEnumerable <string> scopes, MsalUiRequiredException msalSeviceException)
        {
            // A user interaction is required, but we are in a Web API, and therefore, we need to report back to the client through an wwww-Authenticate header https://tools.ietf.org/html/rfc6750#section-3.1
            string proposedAction = "consent";

            if (msalSeviceException.ErrorCode == MsalUiRequiredException.InvalidGrantError)
            {
                if (AcceptedTokenVersionIsNotTheSameAsTokenVersion(msalSeviceException))
                {
                    throw msalSeviceException;
                }
            }

            IDictionary <string, string> parameters = new Dictionary <string, string>()
            {
                { "clientId", _azureAdOptions.ClientId },
                { "claims", msalSeviceException.Claims },
                { "scopes", string.Join(",", scopes) },
                { "proposedAction", proposedAction }
            };

            string       parameterString = string.Join(", ", parameters.Select(p => $"{p.Key}=\"{p.Value}\""));
            string       scheme          = "Bearer";
            StringValues v = new StringValues($"{scheme} {parameterString}");

            //  StringValues v = new StringValues(new string[] { $"Bearer clientId=\"{jwtToken.Audiences.First()}\", claims=\"{ex.Claims}\", scopes=\" {string.Join(",", scopes)}\"" });
            var httpResponse = httpContext.Response;
            var headers      = httpResponse.Headers;

            httpResponse.StatusCode = (int)HttpStatusCode.Forbidden;
            if (headers.ContainsKey(HeaderNames.WWWAuthenticate))
            {
                headers.Remove(HeaderNames.WWWAuthenticate);
            }
            headers.Add(HeaderNames.WWWAuthenticate, v);
        }
コード例 #4
0
        /// <summary>
        /// Used in Web APIs (which therefore cannot have an interaction with the user).
        /// Replies to the client through the HttpReponse by sending a 403 (forbidden) and populating wwwAuthenticateHeaders so that
        /// the client can trigger an iteraction with the user so that the user consents to more scopes
        /// </summary>
        /// <param name="scopes">Scopes to consent to</param>
        /// <param name="msalServiceException"><see cref="MsalUiRequiredException"/> triggering the challenge</param>
        public void ReplyForbiddenWithWwwAuthenticateHeader(IEnumerable <string> scopes, MsalUiRequiredException msalServiceException)
        {
            // A user interaction is required, but we are in a Web API, and therefore, we need to report back to the client through an wwww-Authenticate header https://tools.ietf.org/html/rfc6750#section-3.1
            string proposedAction = "consent";

            if (msalServiceException.ErrorCode == MsalError.InvalidGrantError)
            {
                if (AcceptedTokenVersionMismatch(msalServiceException))
                {
                    throw msalServiceException;
                }
            }

            string consentUrl = $"{application.Authority}/oauth2/v2.0/authorize?client_id={_azureAdOptions.ClientId}"
                                + $"&response_type=code&redirect_uri={application.AppConfig.RedirectUri}"
                                + $"&response_mode=query&scope=offline_access%20{string.Join("%20", scopes)}";

            IDictionary <string, string> parameters = new Dictionary <string, string>()
            {
                { "consentUri", consentUrl },
                { "claims", msalServiceException.Claims },
                { "scopes", string.Join(",", scopes) },
                { "proposedAction", proposedAction }
            };

            string       parameterString = string.Join(", ", parameters.Select(p => $"{p.Key}=\"{p.Value}\""));
            string       scheme          = "Bearer";
            StringValues v = new StringValues($"{scheme} {parameterString}");

            var httpResponse = CurrentHttpContext.Response;
            var headers      = httpResponse.Headers;

            httpResponse.StatusCode = (int)HttpStatusCode.Forbidden;
            if (headers.ContainsKey(HeaderNames.WWWAuthenticate))
            {
                headers.Remove(HeaderNames.WWWAuthenticate);
            }
            headers.Add(HeaderNames.WWWAuthenticate, v);
        }
コード例 #5
0
        /// <summary>
        /// Used in web APIs (no user interaction).
        /// Replies to the client through the HTTP response by sending a 403 (forbidden) and populating the 'WWW-Authenticate' header so that
        /// the client, in turn, can trigger a user interaction so that the user consents to more scopes.
        /// </summary>
        /// <param name="scopes">Scopes to consent to.</param>
        /// <param name="msalServiceException">The <see cref="MsalUiRequiredException"/> that triggered the challenge.</param>
        /// <param name="httpResponse">The <see cref="HttpResponse"/> to update.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task ReplyForbiddenWithWwwAuthenticateHeaderAsync(IEnumerable <string> scopes, MsalUiRequiredException msalServiceException, HttpResponse httpResponse, string additional_info = null)
        {
            // A user interaction is required, but we are in a web API, and therefore, we need to report back to the client through a 'WWW-Authenticate' header https://tools.ietf.org/html/rfc6750#section-3.1

            try
            {
                // Create response header as per https://tools.ietf.org/html/rfc6750#section-3.1
                string parameterString = CommonUtil.CreateResponseHeader(AuthenticationConfig, msalServiceException.Claims, scopes);

                var headers = httpResponse.Headers;

                httpResponse.StatusCode = (int)HttpStatusCode.Forbidden;

                headers[HeaderNames.WWWAuthenticate] = new StringValues($"Bearer {parameterString}");

                string message = msalServiceException.Message;

                // Create response content with error details.

                InsufficientClaimsResponse insufficientClaimsResponse = CommonUtil.CreateErrorResponseMessage(message, additional_info);
                httpResponse.Write(Newtonsoft.Json.JsonConvert.SerializeObject(insufficientClaimsResponse));
            }
            catch (Exception ex)
            {
                var a = ex.Message;
            }
        }
コード例 #6
0
        public void ExceptionsArePubliclyCreatable_MsalSilentTokenAcquisitionException()
        {
            var ex = new MsalUiRequiredException("code", "message");

            Assert.IsNull(ex.InnerException);
        }
コード例 #7
0
        /// <summary>
        /// Build Authentication properties needed for an incremental consent.
        /// </summary>
        /// <param name="scopes">Scopes to request</param>
        /// <returns>AuthenticationProperties</returns>
        private AuthenticationProperties BuildAuthenticationPropertiesForIncrementalConsent(string[] scopes, MsalUiRequiredException ex)
        {
            AuthenticationProperties properties = new AuthenticationProperties();

            // Set the scopes, including the scopes that ADAL.NET / MASL.NET need for the Token cache
            string[] additionalBuildInScopes = new string[] { "openid", "offline_access", "profile" };
            properties.SetParameter <ICollection <string> >(OpenIdConnectParameterNames.Scope, scopes.Union(additionalBuildInScopes).ToList());

            // Attempts to set the login_hint to avoid the logged-in user to be presented with an account selection dialog
            string loginHint = HttpContext.User.GetLoginHint();

            if (!string.IsNullOrWhiteSpace(loginHint))
            {
                properties.SetParameter <string>(OpenIdConnectParameterNames.LoginHint, loginHint);

                string domainHint = HttpContext.User.GetDomainHint();
                properties.SetParameter <string>(OpenIdConnectParameterNames.DomainHint, domainHint);
            }

            // Additional claims required (for instance MFA)
            if (!string.IsNullOrEmpty(ex.Claims))
            {
                properties.Items.Add("claims", ex.Claims);
            }

            return(properties);
        }
コード例 #8
0
 public void ReplyForbiddenWithWwwAuthenticateHeader(IEnumerable<string> scopes, MsalUiRequiredException msalSeviceException)
 {
     throw new NotImplementedException();
 }