Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Make SCIM error responses comply with RFC7644. Any code that processes SCIM error responses must be changed to follow the standard, instead of the previous Wire implementation.

Previous schema (incompatible with RFC):

```
{
"code": 400,
"label": "scim-error",
"message": "{\"detail\":\"[...]\",\"schemas\":[\"urn:ietf:params:scim:api:messages:2.0:Error\"],\"scimType\":\"invalidValue\",\"status\":\"400\"}"
}
```

New schema (RFC-compliant):

```
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": "400"
"scimType": "invalidValue",
"detail": "[...]",
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make scim error responses comply with RFC7644.
1 change: 1 addition & 0 deletions services/spar/spar.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ test-suite spec
Paths_spar
Test.Spar.APISpec
Test.Spar.DataSpec
Test.Spar.ErrorSpec
Test.Spar.Intra.BrigSpec
Test.Spar.Roundtrip.ByteString
Test.Spar.Saml.IdPSpec
Expand Down
8 changes: 7 additions & 1 deletion services/spar/src/Spar/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,13 @@ sparToServerErrorWithLogging logger err = do
pure errServant

sparToServerError :: SparError -> ServerError
sparToServerError = httpErrorToServerError . renderSparError
-- SCIM errors have their own response format (RFC 7644, section 3.12): the body
-- must be the bare SCIM error object. Going through 'renderSparError' /
-- 'httpErrorToServerError' would instead nest it into a wire-server 'Wai.Error'
-- ('{"code":..,"label":"scim-error","message":<scim error as string>}'), so we
-- render it directly here.
sparToServerError (SAML.CustomError (SparScimError err)) = Scim.scimToServerError err
sparToServerError err = httpErrorToServerError (renderSparError err)

waiToServant :: Wai.Error -> ServerError
waiToServant waierr =
Expand Down
55 changes: 55 additions & 0 deletions services/spar/test/Test/Spar/ErrorSpec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{-# LANGUAGE OverloadedStrings #-}

-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2025 Wire Swiss GmbH <opensource@wire.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- Copyright (C) 2025 Wire Swiss GmbH <opensource@wire.com>
-- Copyright (C) 2026 Wire Swiss GmbH <opensource@wire.com>

--
-- 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 <https://www.gnu.org/licenses/>.

module Test.Spar.ErrorSpec where

import Data.Aeson (eitherDecode')
import Data.Aeson.QQ (aesonQQ)
import Imports
import qualified SAML2.WebSSO as SAML
import Servant (ServerError (..))
import Spar.Error
import Test.Hspec
import qualified Web.Scim.Schema.Error as Scim

spec :: Spec
spec = describe "sparToServerError" $ do
-- RFC 7644 section 3.12 requires that the response body of a SCIM error *is*
-- the SCIM error object, not a wire-server 'Wai.Error' with the SCIM error
-- object nested (double-encoded) into its 'message' field.
it "renders a SCIM error as the bare RFC 7644 error object" $ do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is great to show that the rendering works. But, it would also be good to prove that it is actually used. Either with dedicated integration or effect tests or by adding assertions to existing tests. I would lean to the latter, because that's quicker to do.

let scimErr =
Scim.badRequest
Scim.InvalidValue
(Just "Could not process externalId.")
serverErr = sparToServerError (SAML.CustomError (SparScimError scimErr))
eitherDecode' (errBody serverErr)
`shouldBe` Right
[aesonQQ|
{
"detail": "Could not process externalId.",
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:Error"
],
"scimType": "invalidValue",
"status": "400"
}|]
errHTTPCode serverErr `shouldBe` 400
lookup "Content-Type" (errHeaders serverErr)
`shouldBe` Just "application/scim+json;charset=utf-8"