コード例 #1
0
        /// <summary>
        /// Create a formatter for the specified contract type
        /// </summary>
        public static RestMessageDispatchFormatter CreateFormatter(Type contractType)
        {
            RestMessageDispatchFormatter retVal = null;

            if (!m_formatters.TryGetValue(contractType, out retVal))
            {
                lock (m_formatters)
                {
                    if (!m_formatters.ContainsKey(contractType))
                    {
                        var typeFormatter = typeof(RestMessageDispatchFormatter <>).MakeGenericType(contractType);
                        retVal = Activator.CreateInstance(typeFormatter) as RestMessageDispatchFormatter;
                        m_formatters.Add(contractType, retVal);
                    }
                }
            }
            return(retVal);
        }
コード例 #2
0
        /// <summary>
        /// Provide fault
        /// </summary>
        public bool ProvideFault(Exception error, RestResponseMessage faultMessage)
        {
            var uriMatched = RestOperationContext.Current.IncomingRequest.Url;

            while (error.InnerException != null)
            {
                error = error.InnerException;
            }

            var fault      = new RestServiceFault(error);
            var authScheme = RestOperationContext.Current.AppliedPolicies.OfType <BasicAuthorizationAccessBehavior>().Any() ? "Basic" : "Bearer";
            var authRealm  = RestOperationContext.Current.IncomingRequest.Url.Host;

            // Formulate appropriate response
            if (error is DomainStateException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.ServiceUnavailable;
            }
            else if (error is ObjectLockedException lockException)
            {
                faultMessage.StatusCode = 423;
                fault.Data.Add(lockException.LockedUser);
            }
            else if (error is PolicyViolationException)
            {
                var pve = error as PolicyViolationException;
                if (pve.PolicyDecision == PolicyGrantType.Elevate)
                {
                    // Ask the user to elevate themselves
                    faultMessage.StatusCode = 401;
                    faultMessage.AddAuthenticateHeader(authScheme, authRealm, "insufficient_scope", pve.PolicyId, error.Message);
                }
                else
                {
                    faultMessage.StatusCode = 403;
                }
            }
            else if (error is SecurityException)
            {
                faultMessage.StatusCode = (int)HttpStatusCode.Forbidden;
            }
            else if (error is SecurityTokenException)
            {
                // TODO: Audit this
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                var authHeader = $"Bearer realm=\"{RestOperationContext.Current.IncomingRequest.Url.Host}\" error=\"invalid_token\" error_description=\"{error.Message}\"";
                faultMessage.AddAuthenticateHeader(authScheme, authRealm, error: "invalid_token", description: error.Message);
            }
            else if (error is LimitExceededException)
            {
                faultMessage.StatusCode        = (int)(HttpStatusCode)429;
                faultMessage.StatusDescription = "Too Many Requests";
                faultMessage.Headers.Add("Retry-After", "1200");
            }
            else if (error is AuthenticationException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                faultMessage.AddAuthenticateHeader(authScheme, authRealm, "invalid_token", description: error.Message);
            }
            else if (error is UnauthorizedAccessException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Forbidden;
            }
            else if (error is SecuritySessionException ses)
            {
                switch (ses.Type)
                {
                case SessionExceptionType.Expired:
                case SessionExceptionType.NotYetValid:
                case SessionExceptionType.NotEstablished:
                    faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                    faultMessage.AddAuthenticateHeader(authScheme, authRealm, error: "unauthorized");
                    break;

                default:
                    faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Forbidden;
                    break;
                }
            }
            else if (error is FaultException)
            {
                faultMessage.StatusCode = (int)(error as FaultException).StatusCode;
            }
            else if (error is Newtonsoft.Json.JsonException ||
                     error is System.Xml.XmlException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
            }
            else if (error is DuplicateKeyException || error is DuplicateNameException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Conflict;
            }
            else if (error is FileNotFoundException || error is KeyNotFoundException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
            }
            else if (error is DomainStateException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.ServiceUnavailable;
            }
            else if (error is DetectedIssueException)
            {
                faultMessage.StatusCode = (int)(System.Net.HttpStatusCode) 422;
            }
            else if (error is NotImplementedException)
            {
                faultMessage.StatusCode = (int)HttpStatusCode.NotImplemented;
            }
            else if (error is NotSupportedException)
            {
                faultMessage.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
            }
            else if (error is PatchException)
            {
                faultMessage.StatusCode = (int)HttpStatusCode.Conflict;
            }
            else
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
            }

            switch (faultMessage.StatusCode)
            {
            case 409:
            case 429:
            case 503:
                this.m_traceSource.TraceInfo("Issue on REST pipeline: {0}", error);
                break;

            case 401:
            case 403:
            case 501:
            case 405:
                this.m_traceSource.TraceWarning("Warning on REST pipeline: {0}", error);
                break;

            default:
                this.m_traceSource.TraceError("Error on REST pipeline: {0}", error);
                break;
            }

            RestMessageDispatchFormatter.CreateFormatter(RestOperationContext.Current.ServiceEndpoint.Description.Contract.Type).SerializeResponse(faultMessage, null, fault);
            AuditUtil.AuditNetworkRequestFailure(error, uriMatched, RestOperationContext.Current.IncomingRequest.Headers.AllKeys.ToDictionary(o => o, o => RestOperationContext.Current.IncomingRequest.Headers[o]), RestOperationContext.Current.OutgoingResponse.Headers.AllKeys.ToDictionary(o => o, o => RestOperationContext.Current.OutgoingResponse.Headers[o]));
            return(true);
        }