diff --git a/changelog.d/4-docs/update-fed-error-docs b/changelog.d/4-docs/update-fed-error-docs new file mode 100644 index 0000000000..3783c4da3e --- /dev/null +++ b/changelog.d/4-docs/update-fed-error-docs @@ -0,0 +1 @@ +Update federation error documentation after changes to the federation API diff --git a/libs/wire-api-federation/src/Wire/API/Federation/Error.hs b/libs/wire-api-federation/src/Wire/API/Federation/Error.hs index ffe9896207..0229727eee 100644 --- a/libs/wire-api-federation/src/Wire/API/Federation/Error.hs +++ b/libs/wire-api-federation/src/Wire/API/Federation/Error.hs @@ -15,6 +15,56 @@ -- You should have received a copy of the GNU Affero General Public License along -- with this program. If not, see . +-- | Map federation errors to client-facing errors. +-- +-- This module contains most of the error-mapping logic that turns the various +-- possible errors that can occur while making a federated request into errors +-- that are meaningful for the clients. +-- +-- There are three types of errors, from lowest level to highest: +-- +-- * 'FederatorClientHTTP2Error': this is thrown when something fails while +-- connecting or making a request to the local federator. +-- * 'FederatorClientError': this is the most common type of error, +-- corresponding to a failure at the level of the federator client. It +-- includes, for example, a failure to reach a remote federator, or an +-- error on the remote side. +-- * 'FederatorError': this is created by users of the federator client. It +-- can either wrap a 'FederatorClientError', or be an error that is outside +-- the scope of the client, such as when a federated request succeeds with +-- an unexpected result. +-- +-- A general federated request is normally performed as a chain of HTTP +-- requests (some of which are HTTP2). Errors can occur at each node of the +-- chain, as well as in the communication between two adjacent nodes. A +-- successful request goes through the following stages: +-- +-- 1) a service (say brig) makes a request to (the outward service of) the +-- local federator (HTTP2); +-- 2) the local federator processes this request; +-- 3) the local federator makes a request to (the inward service of) a remote +-- one (HTTP2); +-- 4) the remote federator processes this request; +-- 5) from the remote federator to a service on that backend (HTTP); +-- 6) the remote service processes this request. +-- +-- Failures at step 1 in the chain result in 'FederatorClientHTTP2Error', while +-- any other failure results in a 'FederatorClientError'. +-- +-- Immediate failures in the outward service of a federator (stage 2) result in +-- a 403 status code being returned to the federator client, which is then +-- translated into an error with label federation-local-error. +-- +-- Failures which occurred while making a request to a remote federator (stages +-- 3 to 6) are turned into 5xx errors by federator itself, and then passed on +-- through without any further mapping. This includes issues in stage 4, +-- which are seen by the local federator as 403 status codes returned by the +-- remote, as well as arbitrary error codes returned by a service. +-- +-- Note that the federation API follows the convention that any error should be +-- returned as part of a successful response with status code 200. Therefore any +-- error response from services during a federated call should be considered a bug +-- in the implementation of the federation API, and is therefore wrapped in a 533. module Wire.API.Federation.Error ( FederatorClientHTTP2Error (..), FederatorClientError (..), @@ -122,7 +172,7 @@ federationRemoteHTTP2Error (FederatorClientHTTP2Exception e) = federationRemoteHTTP2Error (FederatorClientTLSException e) = Wai.mkError (HTTP.mkStatus 525 "SSL Handshake Failure") - "tls-failure" + "federation-tls-error" (LT.fromStrict (displayTLSException e)) federationRemoteHTTP2Error (FederatorClientConnectionError e) = Wai.mkError @@ -139,7 +189,7 @@ federationClientHTTP2Error (FederatorClientConnectionError e) = federationClientHTTP2Error e = Wai.mkError HTTP.status500 - "federator-client-error" + "federation-local-error" (LT.pack (displayException e)) federationRemoteResponseError :: HTTP.Status -> Wai.Error @@ -169,11 +219,12 @@ displayTLSError (Error_Packet_Parsing msg) = "packet parsing error: " <> T.pack federationServantErrorToWai :: ClientError -> Wai.Error federationServantErrorToWai (DecodeFailure msg _) = federationInvalidBody msg +-- the following error is never thrown by federator client federationServantErrorToWai (FailureResponse _ _) = federationUnknownError federationServantErrorToWai (InvalidContentTypeHeader res) = Wai.mkError unexpectedFederationResponseStatus - "federation-invalid-content-type-header" + "federation-invalid-content-type" ("Content-type: " <> federationErrorContentType res) federationServantErrorToWai (UnsupportedContentType mediaType res) = Wai.mkError @@ -194,9 +245,6 @@ federationErrorContentType = . find (\(name, _) -> name == "Content-Type") . responseHeaders -noFederationStatus :: Status -noFederationStatus = status403 - unexpectedFederationResponseStatus :: Status unexpectedFederationResponseStatus = HTTP.Status 533 "Unexpected Federation Response" @@ -206,7 +254,7 @@ federatorConnectionRefusedStatus = HTTP.Status 521 "Remote Federator Connection federationNotImplemented :: Wai.Error federationNotImplemented = Wai.mkError - noFederationStatus + HTTP.status500 "federation-not-implemented" "Federation is not yet implemented for this endpoint" diff --git a/services/brig/Setup.hs b/services/brig/Setup.hs new file mode 100644 index 0000000000..49233e2b3a --- /dev/null +++ b/services/brig/Setup.hs @@ -0,0 +1,65 @@ +-- This file is part of the Wire Server implementation. +-- +-- Copyright (C) 2021 Wire Swiss GmbH +-- +-- This program is free software: you can redistribute it and/or modify it under +-- the terms of the GNU Affero General Public License as published by the Free +-- Software Foundation, either version 3 of the License, or (at your option) any +-- later version. +-- +-- This program is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +-- details. +-- +-- You should have received a copy of the GNU Affero General Public License along +-- with this program. If not, see . + +import Data.Char +import Data.Foldable +import qualified Data.Map as Map +import Data.Maybe +import Distribution.Simple +import Distribution.Simple.BuildPaths +import Distribution.Simple.LocalBuildInfo +import System.Directory +import System.FilePath + +main :: IO () +main = + defaultMainWithHooks + simpleUserHooks + { buildHook = \desc info hooks flags -> do + withLibLBI desc info $ \_ lib -> do + let base = autogenComponentModulesDir info lib "Brig" "Docs" + generateDocs base "swagger.md" + buildHook simpleUserHooks desc info hooks flags + } + +generateDocs :: FilePath -> FilePath -> IO () +generateDocs base src = do + contents <- readFile ("docs" src) + let name = moduleName src + dest = base (moduleName src <> ".hs") + createDirectoryIfMissing True base + putStrLn ("Generating " <> dest <> " ...") + let out = + unlines + [ "module Brig.Docs." <> name <> " where", + "", + "import Imports", + "", + "contents :: Text", + "contents = " ++ show contents + ] + writeFile dest out + +moduleName :: String -> String +moduleName = go . dropExtension + where + go [] = [] + go (c : cs) = case break (== '-') cs of + (w, rest) -> + (toUpper c : w) <> case rest of + ('-' : name) -> go name + _ -> [] diff --git a/services/brig/brig.cabal b/services/brig/brig.cabal index af88a6605d..7016d5cb60 100644 --- a/services/brig/brig.cabal +++ b/services/brig/brig.cabal @@ -1,10 +1,10 @@ -cabal-version: 1.12 +cabal-version: 1.24 -- This file has been generated from package.yaml by hpack version 0.33.0. -- -- see: https://github.com/sol/hpack -- --- hash: 0613764ce9b6730901fb4a909cae6c25607a3df9e7c5d97b3f51a84c80185e91 +-- hash: c37f84d005641650921717e1f340e18d82edd30045196f89649cefd53e549dfb name: brig version: 1.35.0 @@ -15,7 +15,17 @@ maintainer: Wire Swiss GmbH copyright: (c) 2017 Wire Swiss GmbH license: AGPL-3 license-file: LICENSE -build-type: Simple +build-type: Custom +data-files: + docs/swagger.md + +custom-setup + setup-depends: + Cabal + , base + , containers + , directory + , filepath library exposed-modules: @@ -111,6 +121,7 @@ library Main other-modules: Paths_brig + Brig.Docs.Swagger hs-source-dirs: src default-extensions: AllowAmbiguousTypes BangPatterns ConstraintKinds DataKinds DefaultSignatures DerivingStrategies DerivingVia DeriveFunctor DeriveGeneric DeriveLift DeriveTraversable EmptyCase FlexibleContexts FlexibleInstances FunctionalDependencies GADTs InstanceSigs KindSignatures LambdaCase MultiParamTypeClasses MultiWayIf NamedFieldPuns NoImplicitPrelude OverloadedStrings PackageImports PatternSynonyms PolyKinds QuasiQuotes RankNTypes ScopedTypeVariables StandaloneDeriving TemplateHaskell TupleSections TypeApplications TypeFamilies TypeFamilyDependencies TypeOperators UndecidableInstances ViewPatterns @@ -167,7 +178,6 @@ library , http-types >=0.8 , imports , insert-ordered-containers - , interpolate , iproute >=1.5 , iso639 >=0.1 , lens >=3.8 diff --git a/services/brig/docs/swagger.md b/services/brig/docs/swagger.md new file mode 100644 index 0000000000..63ec978afb --- /dev/null +++ b/services/brig/docs/swagger.md @@ -0,0 +1,75 @@ +## General + +**NOTE**: only a few endpoints are visible here at the moment, more will come as we migrate them to Swagger 2.0. In the meantime please also look at the old swagger docs link for the not-yet-migrated endpoints. See https://docs.wire.com/understand/api-client-perspective/swagger.html for the old endpoints. + +## SSO Endpoints + +### Overview + +`/sso/metadata` will be requested by the IdPs to learn how to talk to wire. + +`/sso/initiate-login`, `/sso/finalize-login` are for the SAML authentication handshake performed by a user in order to log into wire. They are not exactly standard in their details: they may return HTML or XML; redirect to error URLs instead of throwing errors, etc. + +`/identity-providers` end-points are for use in the team settings page when IdPs are registered. They talk json. + + +### Configuring IdPs + +IdPs usually allow you to copy the metadata into your clipboard. That should contain all the details you need to post the idp in your team under `/identity-providers`. (Team id is derived from the authorization credentials of the request.) + +#### okta.com + +Okta will ask you to provide two URLs when you set it up for talking to wireapp: + +1. The `Single sign on URL`. This is the end-point that accepts the user's credentials after successful authentication against the IdP. Choose `/sso/finalize-login` with schema and hostname of the wire server you are configuring. + +2. The `Audience URI`. You can find this in the metadata returned by the `/sso/metadata` end-point. It is the contents of the `md:OrganizationURL` element. + +#### centrify.com + +Centrify allows you to upload the metadata xml document that you get from the `/sso/metadata` end-point. You can also enter the metadata url and have centrify retrieve the xml, but to guarantee integrity of the setup, the metadata should be copied from the team settings page and pasted into the centrify setup page without any URL indirections. + +## Federation errors + +Endpoints involving federated calls to other domains can return some extra failure responses, common to all endpoints. Instead of listing them as possible responses for each endpoint, we document them here. + +For errors that are more likely to be transient, we suggest clients to retry whatever request resulted in the error. Transient errors are indicated explicitly below. + +**Note**: when a failure occurs as a result of making a federated RPC to another backend, the error response contains the following extra fields: + + - `domain`: the target backend of the RPC that failed; + - `path`: the path of the RPC that failed. + +### Domain errors + +Errors in this category result from trying to communicate with a backend that is considered non-existent or invalid. They can result from invalid user input or client issues, but they can also be a symptom of misconfiguration in one or multiple backends. These errors have a 4xx status code. + + - **Remote backend not found** (status: 422, label: `invalid-domain`): This backend attempted to contact a backend which does not exist or is not properly configured. For the most part, clients can consider this error equivalent to a domain not existing, although it should be noted that certain mistakes in the DNS configuration on a remote backend can lead to the backend not being recognized, and hence to this error. It is therefore not advisable to take any destructive action upon encountering this error, such as deleting remote users from conversations. + - **Federation denied locally** (status: 400, label: `federation-denied`): This backend attempted an RPC to a non-whitelisted backend. Similar considerations as for the previous error apply. + - **Federation not enabled** (status: 400, label: `federation-not-enabled`): Federation has not been configured for this backend. This will happen if a federation-aware client tries to talk to a backend for which federation is disabled, or if federation was disabled on the backend after reaching a federation-specific state (e.g. conversations with remote users). There is no way to cleanly recover from these errors at this point. + +### Local federation errors + +An error in this category likely indicates an issue with the configuration of federation on the local backend. Possibly transient errors are indicated explicitly below. All these errors have a 500 status code. + + - **Federation unavailable** (status: 500, label: `federation-not-available`): Federation is configured for this backend, but the local federator cannot be reached. This can be transient, so clients should retry the request. + - **Federation not implemented** (status: 500, label: `federation-not-implemented`): Federated behaviour for a certain endpoint is not yet implemented. + - **Federator discovery failed** (status: 500, label: `discovery-failure`): A DNS error occurred during discovery of a remote backend. This can be transient, so clients should retry the request. + - **Local federation error** (status: 500, label: `federation-local-error`): An error occurred in the communication between this backend and its local federator. These errors are most likely caused by bugs in the backend, and should be reported as such. + +### Remote federation errors + +Errors in this category are returned in case of communication issues between the local backend and a remote one, or if the remote side encountered an error while processing an RPC. Some errors in this category might be caused by incorrect client behaviour, wrong user input, or incorrect certificate configuration. Possibly transient errors are indicated explicitly. We use non-standard 5xx status codes for these errors. + + - **HTTP2 error** (status: 533, label: `federation-http2-error`): The current federator encountered an error when making an HTTP2 request to a remote one. Check the error message for more details. + - **Connection refused** (status: 521, label: `federation-connection-refused`): The local federator could not connect to a remote one. This could be transient, so clients should retry the request. + - **TLS failure**: (status: 525, label: `federation-tls-error`): An error occurred during the TLS handshake between the local federator and a remote one. This is most likely due to an issue with the certificate on the remote end. + - **Remote federation error** (status: 533, label: `federation-remote-error`): The remote backend could not process a request coming from this backend. Check the error message for more details. + +### Backend compatibility errors + +An error in this category will be returned when this backend makes an invalid or unsupported RPC to another backend. This can indicate some incompatibility between backends or a backend bug. These errors are unlikely to be transient, so retrying requests is *not* advised. + + - **Version mismatch** (status: 531, label: `federation-version-mismatch`): A remote backend is running an unsupported version of the federator. + - **Invalid content type** (status: 533, label: `federation-invalid-content-type`): An RPC to another backend returned with an invalid content type. + - **Unsupported content type** (status: 533, label: `federation-unsupported-content-type`): An RPC to another backend returned with an unsupported content type. diff --git a/services/brig/package.yaml b/services/brig/package.yaml index a0520b4412..a790657c20 100644 --- a/services/brig/package.yaml +++ b/services/brig/package.yaml @@ -10,8 +10,18 @@ copyright: (c) 2017 Wire Swiss GmbH license: AGPL-3 ghc-options: - -funbox-strict-fields +custom-setup: + dependencies: + - Cabal + - base + - containers + - directory + - filepath library: source-dirs: src + other-modules: + - Paths_brig + - Brig.Docs.Swagger dependencies: - aeson >=0.11 - amazonka >=1.3.7 @@ -63,7 +73,6 @@ library: - http-types >=0.8 - imports - insert-ordered-containers - - interpolate - iproute >=1.5 - iso639 >=0.1 - lens >=3.8 diff --git a/services/brig/src/Brig/API/Public.hs b/services/brig/src/Brig/API/Public.hs index aadf64e82b..081c96f800 100644 --- a/services/brig/src/Brig/API/Public.hs +++ b/services/brig/src/Brig/API/Public.hs @@ -40,6 +40,7 @@ import Brig.App import qualified Brig.Calling.API as Calling import qualified Brig.Data.Connection as Data import qualified Brig.Data.User as Data +import qualified Brig.Docs.Swagger import qualified Brig.IO.Intra as Intra import Brig.Options hiding (internalEvents, sesQueue) import qualified Brig.Provider.API as Provider @@ -73,7 +74,6 @@ import qualified Data.Map.Strict as Map import Data.Misc (IpAddr (..)) import Data.Qualified import Data.Range -import Data.String.Interpolate as QQ import qualified Data.Swagger as S import qualified Data.Swagger.Build.Api as Doc import qualified Data.Text as Text @@ -133,7 +133,7 @@ swaggerDocsAPI = swaggerSchemaUIServer $ (BrigAPI.swagger <> GalleyAPI.swaggerDoc <> LegalHoldAPI.swaggerDoc <> SparAPI.swaggerDoc) & S.info . S.title .~ "Wire-Server API" - & S.info . S.description ?~ desc + & S.info . S.description ?~ Brig.Docs.Swagger.contents <> mempty & S.security %~ nub -- sanitise definitions & S.definitions . traverse %~ sanitise @@ -153,97 +153,6 @@ swaggerDocsAPI = (S.properties . traverse . S._Inline %~ sanitise) . (S.required %~ nubOrd) . (S.enum_ . _Just %~ nub) - desc = - Text.pack - [QQ.i| -## General - -**NOTE**: only a few endpoints are visible here at the moment, more will come as we migrate them to Swagger 2.0. In the meantime please also look at the old swagger docs link for the not-yet-migrated endpoints. See https://docs.wire.com/understand/api-client-perspective/swagger.html for the old endpoints. - -## SSO Endpoints - -### Overview - -`/sso/metadata` will be requested by the IdPs to learn how to talk to wire. - -`/sso/initiate-login`, `/sso/finalize-login` are for the SAML authentication handshake performed by a user in order to log into wire. They are not exactly standard in their details: they may return HTML or XML; redirect to error URLs instead of throwing errors, etc. - -`/identity-providers` end-points are for use in the team settings page when IdPs are registered. They talk json. - - -### Configuring IdPs - -IdPs usually allow you to copy the metadata into your clipboard. That should contain all the details you need to post the idp in your team under `/identity-providers`. (Team id is derived from the authorization credentials of the request.) - -#### okta.com - -Okta will ask you to provide two URLs when you set it up for talking to wireapp: - -1. The `Single sign on URL`. This is the end-point that accepts the user's credentials after successful authentication against the IdP. Choose `/sso/finalize-login` with schema and hostname of the wire server you are configuring. - -2. The `Audience URI`. You can find this in the metadata returned by the `/sso/metadata` end-point. It is the contents of the `md:OrganizationURL` element. - -#### centrify.com - -Centrify allows you to upload the metadata xml document that you get from the `/sso/metadata` end-point. You can also enter the metadata url and have centrify retrieve the xml, but to guarantee integrity of the setup, the metadata should be copied from the team settings page and pasted into the centrify setup page without any URL indirections. - -## Federation errors - -Endpoints involving federated calls to other domains can return some extra failure responses, common to all endpoints. Instead of listing them as possible responses for each endpoint, we document them here. - -For errors that are more likely to be transient, we suggest clients to retry whatever request resulted in the error. Transient errors are indicated explicitly below. - -**Note**: when a failure occurs as a result of making a federated RPC to another backend, the error response contains the following extra fields: - - - `domain`: the target backend of the RPC that failed; - - `path`: the path of the RPC that failed. - -### Domain errors - -Errors in this category result from trying to communicate with a backend that is considered non-existent or invalid. They can result from invalid user input or client issues, but they can also be a symptom of misconfiguration in one or multiple backends. - - - **Remote backend not found** (status: 422, label: `srv-record-not-found`): This backend attempted to contact a backend which does not exist or is not properly configured. For the most part, clients can consider this error equivalent to a domain not existing, although it should be noted that certain mistakes in the DNS configuration on a remote backend can lead to the backend not being recognized, and hence to this error. It is therefore not advisable to take any destructive action upon encountering this error, such as deleting remote users from conversations. - - **Federation denied locally** (status: 400, label: `federation-not-allowed`): This backend attempted an RPC to a non-whitelisted backend. Similar considerations as for the previous error apply. - -### Local federation errors - -An error in this category likely indicates an issue with configuration of federation on the local backend. Possibly transient errors are indicated explicitly below. - - - **Federation not enabled** (status: 400, label: `federation-not-enabled`): Federation has not been configured for this backend. This will happen if a federation-aware client tries to talk to a backend for which federation is disabled, or if federation was disabled on the backend after reaching a federation-specific state (e.g. conversations with remote users). There is no way to cleanly recover from these errors at this point. - - **Federation unavailable** (status: 500, label: `federation-not-available`): Federation is configured for this backend, but the local federator cannot be reached. This can be transient, so clients should retry the request. - - **Federation not implemented** (status: 403, label: `federation-not-implemented`): Federated behaviour for a certain endpoint is not yet implemented. - - **Federator discovery failed** (status: 500, label: `srv-lookup-dns-error`): A DNS error occurred during discovery of a remote backend. This can be transient, so clients should retry the request. - - **Too much concurrency** (status: 533, label: `too-much-concurrency`): Too many concurrent requests from this backend. This can be transient, so clients should retry the request. - -### Remote federation errors - -Errors in this category are returned in case of communication issues between the local backend and a remote one, or if the remote side encountered an error while processing an RPC. Some errors in this category might be caused by incorrect client behaviour or wrong user input. All of these errors can be transient, so clients should retry the request that caused them. - - - **gRPC error** (status: 533, label: `grpc-error`): The current federator encountered an error when making an RPC to a remote one. Check the error message for more details. - - **Client RPC error** (status: 500, label: `client-rpc-error`): There was a non-specified error when making a request to another backend. Check the error message for more details. - - **Connection refused** (status: 521, label: `cannot-connect-to-remote-federator`): The local federator could not connect to a remote one. - - **Unknown remote error** (status: 500, label: `unknown-federation-error`): An RPC failed but no specific error was returned by the remote side. Check the error message for more details. - -### Backend compatibility errors - -An error in this category will be returned when this backend makes an invalid or unsupported RPC to another backend. This can indicate some incompatibility between backends or a backend bug. These errors are unlikely to be transient, so retrying requests is *not* advised. - - - **Version mismatch** (status: 531): A remote backend is running an unsupported version of the federator. - - **Invalid method** / **Streaming not supported** (status: 500, label: `federation-invalid-call`): There was an error in the communication between a service on this backend and the local federator. - - **Invalid request** (status: 500, label: `invalid-request-to-federator`): The local federator made an invalid request to a remote one. Check the error message for more details. - - **Invalid content type** (status: 503, label: `federation-invalid-content-type-header`): An RPC to another backend returned an invalid content type. - - **Unsupported content type** (status: 503, label: `federation-unsupported-content-type`): An RPC to another backend returned an unsupported content type. - - **Invalid origin domain** (status: 533, label: `invalid-origin-domain`): The current backend attempted an RPC with an invalid origin domain field. - - **Forbidden endpoint** (status: 533, label: `forbidden-endpoint`): The current backend attempted an RPC to a forbidden or inaccessible remote endpoint. - - **Unknown federation error** (status: 503, label: `unknown-federation-error`): The target of an RPC returned an unexpected reponse. Check the error message for more details. - -### Authentication errors - -The errors in this category relate to authentication or authorization issues between backends. These errors are unlikely to be transient, so retrying requests is *not* advised. - - - **TLS failure**: (status: 525): An error occurred during the TLS handshake between the local federator and a remote one. This is most likely due to an issue with the certificate on the remote end. - - **Federation denied remotely** (status: 532): The current backend made an unauthorized request to a remote one. -|] servantSitemap :: ServerT ServantAPI Handler servantSitemap = diff --git a/services/federator/src/Federator/Discovery.hs b/services/federator/src/Federator/Discovery.hs index 096213f676..65844e33d8 100644 --- a/services/federator/src/Federator/Discovery.hs +++ b/services/federator/src/Federator/Discovery.hs @@ -48,7 +48,7 @@ instance AsWai DiscoveryFailure where toWai e = Wai.mkError status label (LText.fromStrict (waiErrorDescription e)) where (status, label) = case e of - DiscoveryFailureSrvNotAvailable _ -> (HTTP.status422, "srv-record-not-found") + DiscoveryFailureSrvNotAvailable _ -> (HTTP.status422, "invalid-domain") DiscoveryFailureDNSError _ -> (HTTP.status500, "discovery-failure") waiErrorDescription :: DiscoveryFailure -> Text waiErrorDescription (DiscoveryFailureSrvNotAvailable msg) = diff --git a/services/federator/src/Federator/Validation.hs b/services/federator/src/Federator/Validation.hs index 57a130a376..4d7f35867d 100644 --- a/services/federator/src/Federator/Validation.hs +++ b/services/federator/src/Federator/Validation.hs @@ -59,7 +59,7 @@ instance Exception ValidationError instance AsWai ValidationError where toWai err = - Wai.mkError HTTP.status403 (validationErrorLabel err) + Wai.mkError (validationErrorStatus err) (validationErrorLabel err) . LText.fromStrict $ waiErrorDescription err @@ -82,6 +82,13 @@ validationErrorLabel (DomainParseError _) = "domain-parse-error" validationErrorLabel (AuthenticationFailure _) = "authentication-failure" validationErrorLabel (FederationDenied _) = "federation-denied" +validationErrorStatus :: ValidationError -> HTTP.Status +-- the FederationDenied case is handled differently, because it may be caused +-- by wrong input in the original request, so we let this error propagate to the +-- client +validationErrorStatus (FederationDenied _) = HTTP.status400 +validationErrorStatus _ = HTTP.status403 + -- | Validates an already-parsed domain against the allowList using the federator -- startup configuration. ensureCanFederateWith ::