Skip to content
Merged
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
1 change: 1 addition & 0 deletions changelog.d/2-features/no-federated-proteus
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `federationProtocols` setting to galley, which can be used to disable the creation of federated conversations with a given protocol
3 changes: 3 additions & 0 deletions charts/galley/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ data:
{{ fail "settings.conversationCodeURI and settings.multiIngress are mutually exclusive" }}
{{- end }}
federationDomain: {{ .settings.federationDomain }}
{{- if .settings.federationProtocols }}
federationProtocols: {{ .settings.federationProtocols }}
{{- end }}
{{- if $.Values.secrets.mlsPrivateKeys }}
mlsPrivateKeyPaths:
removal:
Expand Down
4 changes: 4 additions & 0 deletions charts/galley/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ config:
iterations: 1
parallelism: 32
memory: 180224 # 176 MiB

# To disable proteus for new federated conversations:
# federationProtocols: ["mls"]

featureFlags: # see #RefConfigOptions in `/docs/reference` (https://github.com/wireapp/wire-server/)
appLock:
defaults:
Expand Down
12 changes: 12 additions & 0 deletions docs/src/developer/reference/config-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,18 @@ federator:
clientPrivateKey: client-key.pem
```

### Federation protocols

A backend can restrict creation of new federated conversations according to the protocol used (Proteus or MLS). This is controlled by the `federationProtocols` setting. For example:

```yaml
galley:
settings:
federationProtocols: ["mls"]
```

will prevent the creation of a Proteus conversation containing federated users, and will prevent federated users from joining a Proteus conversation on this backend. However, existing Proteus conversations with federated users will continue to function, and users of this backend will be allowed to join new and existing Proteus conversations on federated backends.

### Outlook calendar integration

This feature setting only applies to the Outlook Calendar extension for Wire. As it is an external service, it should only be configured through this feature flag and otherwise ignored by the backend.
Expand Down
25 changes: 25 additions & 0 deletions integration/test/Test/Conversation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -908,3 +908,28 @@ testPostConvWithUnreachableRemoteUsers = do
for_ convs $ \conv -> conv %. "type" `shouldNotMatchInt` 0
assertNoEvent 2 wssAlice
assertNoEvent 2 wssAlex

testNoFederationWithProteus :: (HasCallStack) => App ()
testNoFederationWithProteus = do
withModifiedBackend
( def
{ galleyCfg = \conf ->
conf & setField "settings.federationProtocols" ["mls"]
}
)
$ \domain -> do
charlieDomain <- asString $ make OwnDomain
[alice, alex, arnold, bob] <- createAndConnectUsers [domain, domain, domain, charlieDomain]

do
conv <- postConversation alice defProteus {qualifiedUsers = [alex]} >>= getJSON 201
bindResponse (addMembers alice conv def {users = [bob]}) $ \resp -> do
resp.status `shouldMatchInt` 409
resp.json %. "label" `shouldMatch` "federation-disabled-for-protocol"
void $ addMembers alice conv def {users = [arnold]} >>= getJSON 200

bindResponse (postConversation alice defProteus {qualifiedUsers = [bob]}) $ \resp -> do
resp.status `shouldMatchInt` 409
resp.json %. "label" `shouldMatch` "federation-disabled-for-protocol"

void $ postConversation bob defProteus {qualifiedUsers = [alice]} >>= getJSON 201
10 changes: 10 additions & 0 deletions libs/wire-api-federation/src/Wire/API/Federation/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ data FederationError
| -- | No federator endpoint has been set, so no call to federator client can
-- be made.
FederationNotConfigured
| -- | Federation is disabled for the given protocol
FederationDisabledForProtocol
| -- | An error occurred while invoking federator client (see
-- 'FederatorClientError' for more details).
FederationCallFailure FederatorClientError
Expand Down Expand Up @@ -188,6 +190,7 @@ instance APIError FederationError where
federationErrorToWai :: FederationError -> Wai.Error
federationErrorToWai FederationNotImplemented = federationNotImplemented
federationErrorToWai FederationNotConfigured = federationNotConfigured
federationErrorToWai FederationDisabledForProtocol = federationDisabledForProtocol
federationErrorToWai (FederationCallFailure err) = federationClientErrorToWai err
federationErrorToWai (FederationUnexpectedBody s) = federationUnexpectedBody s
federationErrorToWai (FederationUnexpectedError t) = federationUnexpectedError t
Expand Down Expand Up @@ -358,6 +361,13 @@ federationNotConfigured =
"federation-not-enabled"
"no federator configured"

federationDisabledForProtocol :: Wai.Error
federationDisabledForProtocol =
Wai.mkError
HTTP.status409
"federation-disabled-for-protocol"
"Federation is disabled for the given protocol"

federationUnavailable :: Text -> Wai.Error
federationUnavailable err =
Wai.mkError
Expand Down
1 change: 1 addition & 0 deletions services/galley/galley.integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ settings:
# Once set, DO NOT change it: if you do, existing users may have a broken experience and/or stop working
# Remember to keep it the same in Brig
federationDomain: example.com
federationProtocols: ["mls", "proteus"]
mlsPrivateKeyPaths:
removal:
ed25519: test/resources/backendA/ed25519.pem
Expand Down
17 changes: 16 additions & 1 deletion services/galley/src/Galley/API/Action.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module Galley.API.Action
addLocalUsersToRemoteConv,
ConversationUpdate,
getFederationStatus,
enforceFederationProtocol,
checkFederationStatus,
firstConflictOrFullyConnected,
)
Expand Down Expand Up @@ -121,7 +122,7 @@ import Wire.API.Team.Feature
import Wire.API.Team.LegalHold
import Wire.API.Team.Member
import Wire.API.Team.Permission (Perm (AddRemoveConvMember, ModifyConvName))
import Wire.API.User qualified as User
import Wire.API.User as User
import Wire.NotificationSubsystem

data NoChanges = NoChanges
Expand Down Expand Up @@ -327,6 +328,19 @@ type family HasConversationActionGalleyErrors (tag :: ConversationActionTag) ::
ErrorS 'TeamNotFound
]

enforceFederationProtocol ::
( Member (Error FederationError) r,
Member (Input Opts) r
) =>
ProtocolTag ->
[Remote ()] ->
Sem r ()
enforceFederationProtocol proto domains = do
unless (null domains) $ do
mAllowedProtos <- view (settings . federationProtocols) <$> input
unless (maybe True (elem proto) mAllowedProtos) $
throw FederationDisabledForProtocol

checkFederationStatus ::
( Member (Error UnreachableBackends) r,
Member (Error NonFederatingBackends) r,
Expand Down Expand Up @@ -521,6 +535,7 @@ performConversationJoin qusr lconv (ConversationJoin invited role) = do
ensureMemberLimit (convProtocolTag conv) (toList (convLocalMembers conv)) newMembers
ensureAccess conv InviteAccess
checkLocals lusr (convTeam conv) (ulLocals newMembers)
enforceFederationProtocol (protocolTag conv.convProtocol) (fmap void (ulRemotes newMembers))
checkRemotes lusr (ulRemotes newMembers)
checkLHPolicyConflictsLocal (ulLocals newMembers)
checkLHPolicyConflictsRemote (FutureWork (ulRemotes newMembers))
Expand Down
1 change: 1 addition & 0 deletions services/galley/src/Galley/API/Create.hs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ createGroupConversation ::
Sem r CreateGroupConversationResponse
createGroupConversation lusr conn newConv = do
let remoteDomains = void <$> snd (partitionQualified lusr $ newConv.newConvQualifiedUsers)
enforceFederationProtocol (baseProtocolToProtocol newConv.newConvProtocol) remoteDomains
checkFederationStatus (RemoteDomains $ Set.fromList remoteDomains)
cnv <-
createGroupConversationGeneric
Expand Down
3 changes: 3 additions & 0 deletions services/galley/src/Galley/Options.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module Galley.Options
concurrentDeletionEvents,
deleteConvThrottleMillis,
federationDomain,
federationProtocols,
mlsPrivateKeyPaths,
featureFlags,
defConcurrentDeletionEvents,
Expand Down Expand Up @@ -72,6 +73,7 @@ import Network.AMQP.Extended
import System.Logger.Extended (Level, LogFormat)
import Util.Options hiding (endpoint)
import Util.Options.Common
import Wire.API.Conversation.Protocol
import Wire.API.Routes.Version
import Wire.API.Team.Member

Expand Down Expand Up @@ -136,6 +138,7 @@ data Settings = Settings
-- - wire.com
-- - example.com
_federationDomain :: !Domain,
_federationProtocols :: !(Maybe [ProtocolTag]),
_mlsPrivateKeyPaths :: !(Maybe MLSPrivateKeyPaths),
-- | FUTUREWORK: 'setFeatureFlags' should be renamed to 'setFeatureConfigs' in all types.
_featureFlags :: !FeatureFlags,
Expand Down
2 changes: 1 addition & 1 deletion services/galley/src/Galley/Types/UserList.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ data UserList a = UserList
{ ulLocals :: [a],
ulRemotes :: [Remote a]
}
deriving (Functor, Foldable, Traversable)
deriving (Show, Functor, Foldable, Traversable)

instance Semigroup (UserList a) where
UserList locals1 remotes1 <> UserList locals2 remotes2 =
Expand Down