diff --git a/core/modules/jsonapi/tests/src/Functional/UserTest.php b/core/modules/jsonapi/tests/src/Functional/UserTest.php index b08df8eb26b..5261f4d5f28 100644 --- a/core/modules/jsonapi/tests/src/Functional/UserTest.php +++ b/core/modules/jsonapi/tests/src/Functional/UserTest.php @@ -412,6 +412,18 @@ class UserTest extends ResourceTestBase { $this->assertArrayNotHasKey('mail', $doc['data'][2]['attributes']); $this->assertSame($user_b->uuid(), $doc['data'][count($doc['data']) - 1]['id']); $this->assertArrayHasKey('mail', $doc['data'][count($doc['data']) - 1]['attributes']); + + // Now grant permission to access user mail and verify. + $this->grantPermissionsToTestedRole(['access user mail']); + // Viewing user A as user B: "mail" field should be accessible. + $response = $this->request('GET', $user_a_url, $request_options); + $doc = Json::decode((string) $response->getBody()); + $this->assertArrayHasKey('mail', $doc['data']['attributes']); + // Also when looking at the collection. + $response = $this->request('GET', $collection_url, $request_options); + $doc = Json::decode((string) $response->getBody()); + $this->assertSame($user_a->uuid(), $doc['data']['2']['id']); + $this->assertArrayHasKey('mail', $doc['data'][2]['attributes']); } /** diff --git a/core/modules/user/src/UserAccessControlHandler.php b/core/modules/user/src/UserAccessControlHandler.php index 2c67acb1be2..597acfcb556 100644 --- a/core/modules/user/src/UserAccessControlHandler.php +++ b/core/modules/user/src/UserAccessControlHandler.php @@ -113,10 +113,15 @@ class UserAccessControlHandler extends EntityAccessControlHandler { return AccessResult::neutral(); } + case 'mail': + // Only check for the access user mail permission and a view operation. + // Use case fall-through for all other cases. + if ($operation == 'view' && $account->hasPermission('access user mail')) { + return AccessResult::allowed()->cachePerPermissions(); + } case 'preferred_langcode': case 'preferred_admin_langcode': case 'timezone': - case 'mail': // Allow view access to own mail address and other personalization // settings. if ($operation == 'view') { diff --git a/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php b/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php index c7195d126ea..6a51692aea9 100644 --- a/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php +++ b/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php @@ -32,6 +32,13 @@ class UserAccessControlHandlerTest extends UnitTestCase { */ protected $viewer; + /** + * The mock user account with 'access user mail' permission. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $emailViewer; + /** * The mock user account that is able to change their own account name. * @@ -96,6 +103,18 @@ class UserAccessControlHandlerTest extends UnitTestCase { ->method('hasPermission') ->will($this->returnValue(TRUE)); + $this->emailViewer = $this->createMock('\Drupal\Core\Session\AccountInterface'); + $this->emailViewer + ->expects($this->any()) + ->method('hasPermission') + ->will($this->returnValueMap([ + ['access user mail', TRUE], + ])); + $this->emailViewer + ->expects($this->any()) + ->method('id') + ->will($this->returnValue(3)); + $entity_type = $this->createMock('Drupal\Core\Entity\EntityTypeInterface'); $this->accessControlHandler = new UserAccessControlHandler($entity_type); @@ -240,6 +259,14 @@ class UserAccessControlHandlerTest extends UnitTestCase { 'view' => TRUE, 'edit' => TRUE, ]; + $access_info[] = [ + 'field' => $field, + 'viewer' => 'emailViewer', + 'target' => 'owner', + 'view' => $field === 'mail', + // See note above. + 'edit' => TRUE, + ]; } return $access_info; diff --git a/core/modules/user/user.permissions.yml b/core/modules/user/user.permissions.yml index 984b5ce118f..29566c799c2 100644 --- a/core/modules/user/user.permissions.yml +++ b/core/modules/user/user.permissions.yml @@ -11,6 +11,9 @@ administer users: restrict access: true access user profiles: title: 'View user information' +access user mail: + title: 'View user email addresses' + description: 'Users without this permission will not have access to email addresses on user pages or other places where they might be shown, such as Views and JSON:API responses.' change own username: title: 'Change own username' select account cancellation method: