You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by GitBox <gi...@apache.org> on 2021/11/30 10:36:26 UTC

[GitHub] [james-project] Arsnael commented on a change in pull request #761: JAMES-3534 Identity/set update + delete and Identity/get should fail for identities whose alias is deleted

Arsnael commented on a change in pull request #761:
URL: https://github.com/apache/james-project/pull/761#discussion_r759144073



##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$customIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$customIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"newState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"notUpdated": {
+           |		"$customIdentityId": {
+           |			"type": "notFound",
+           |			"description": "IdentityId($customIdentityId) could not be found"
+           |		}
+           |	}
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get that identity should no longer return
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$serverIdentityId"]
+         |			}, "c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$serverIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when

Review comment:
       indent

##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$customIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$customIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`

Review comment:
       indent

##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$customIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$customIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"newState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"notUpdated": {
+           |		"$customIdentityId": {
+           |			"type": "notFound",
+           |			"description": "IdentityId($customIdentityId) could not be found"
+           |		}
+           |	}
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get that identity should no longer return
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$serverIdentityId"]
+         |			}, "c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$serverIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$serverIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`

Review comment:
       indent

##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$customIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$customIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"newState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"notUpdated": {
+           |		"$customIdentityId": {
+           |			"type": "notFound",
+           |			"description": "IdentityId($customIdentityId) could not be found"
+           |		}
+           |	}
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get that identity should no longer return
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$serverIdentityId"]
+         |			}, "c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`

Review comment:
       indent

##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when

Review comment:
       indent

##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`

Review comment:
       indent

##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$customIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$customIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when

Review comment:
       indent

##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$customIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$customIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"newState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"notUpdated": {
+           |		"$customIdentityId": {
+           |			"type": "notFound",
+           |			"description": "IdentityId($customIdentityId) could not be found"
+           |		}
+           |	}
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get that identity should no longer return
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$serverIdentityId"]
+         |			}, "c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when

Review comment:
       indent

##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$customIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$customIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"newState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"notUpdated": {
+           |		"$customIdentityId": {
+           |			"type": "notFound",
+           |			"description": "IdentityId($customIdentityId) could not be found"
+           |		}
+           |	}
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get that identity should no longer return
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$serverIdentityId"]
+         |			}, "c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$serverIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$serverIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when

Review comment:
       indent

##########
File path: server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/IdentitySetContract.scala
##########
@@ -1666,5 +1666,318 @@ trait IdentitySetContract {
            |    ]
            |}""".stripMargin)
   }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWithItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get no longer returns the identity
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$customIdentityId"]
+         |			}, "c1"
+         |		]
+         |
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$customIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndCreateACustomIdentityWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // Bob create a new custom identity with bob-alias@domain.tld
+    val customIdentityId = createNewIdentity(UUID.randomUUID().toString, "bob-alias@domain.tld")
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/set update of that identity fails
+    val request: String =
+      s"""{
+         |	"using": [
+         |		"urn:ietf:params:jmap:core",
+         |		"urn:ietf:params:jmap:submission"
+         |	],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/set",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"update": {
+         |					"$customIdentityId": {
+         |						"name": "NewName1",
+         |						"replyTo": [{
+         |							"name": "Difference Alice",
+         |							"email": "alice2@domain.tld"
+         |						}],
+         |						"bcc": [{
+         |							"name": "Difference David",
+         |							"email": "david2@domain.tld"
+         |						}],
+         |						"textSignature": "Difference text signature",
+         |						"htmlSignature": "<p>Difference html signature</p>"
+         |					}
+         |				}
+         |			},
+         |			"c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"newState": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"notUpdated": {
+           |		"$customIdentityId": {
+           |			"type": "notFound",
+           |			"description": "IdentityId($customIdentityId) could not be found"
+           |		}
+           |	}
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenFetchThatIdentityShouldNoLongerReturn(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+
+    // WHEN an admin delete bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).removeUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+
+    // THEN Identity/get that identity should no longer return
+    val request: String =
+      s"""{
+         |	"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:submission"],
+         |	"methodCalls": [
+         |		[
+         |			"Identity/get",
+         |			{
+         |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+         |				"ids": ["$serverIdentityId"]
+         |			}, "c1"
+         |		]
+         |	]
+         |}""".stripMargin
+
+    val response: String = `given`
+      .body(request)
+      .when
+      .post
+      .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    assertThatJson(response)
+      .inPath("methodResponses[0][1]")
+      .isEqualTo(
+        s"""{
+           |	"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |	"notFound": [
+           |		"$serverIdentityId"
+           |	],
+           |	"state": "2c9f1b12-b35a-43e6-9af2-0106fb53a943",
+           |	"list": []
+           |}""".stripMargin)
+  }
+
+  @Test
+  def givenServerSetAliasAndUserUpdateItWhenAdminRemoveThatAliasThenUpdateThatIdentityShouldFail(server: GuiceJamesServer): Unit = {
+    // GIVEN bob-alias@domain.tld
+    server.getProbe(classOf[DataProbeImpl]).addUserAliasMapping("bob-alias", "domain.tld", "bob@domain.tld")
+    val serverIdentityId = UUID.nameUUIDFromBytes("bob-alias@domain.tld".getBytes(StandardCharsets.UTF_8))
+
+    // Bob update the default identity of bob-alias@domain.tld
+    `given`
+      .body(
+        s"""{
+           |	"using": [
+           |		"urn:ietf:params:jmap:core",
+           |		"urn:ietf:params:jmap:submission"
+           |	],
+           |	"methodCalls": [
+           |		[
+           |			"Identity/set",
+           |			{
+           |				"accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6",
+           |				"update": {
+           |					"$serverIdentityId": {
+           |						"name": "NewName1",
+           |						"replyTo": [{
+           |							"name": "Difference Alice",
+           |							"email": "alice2@domain.tld"
+           |						}],
+           |						"bcc": [{
+           |							"name": "Difference David",
+           |							"email": "david2@domain.tld"
+           |						}],
+           |						"textSignature": "Difference text signature",
+           |						"htmlSignature": "<p>Difference html signature</p>"
+           |					}
+           |				}
+           |			},
+           |			"c1"
+           |		]
+           |	]
+           |}""".stripMargin)
+      .when
+      .post
+      .`then`

Review comment:
       indent




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org