View source
<?php
namespace Drupal\Tests\apigee_edge_teams\Functional;
use Drupal\apigee_edge_teams\Entity\TeamRoleInterface;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Route;
class AccessTest extends ApigeeEdgeTeamsFunctionalTestBase {
protected $teamStorage;
protected $teamAppStorage;
protected $account;
protected $teamMemberAccount;
protected $nonTeamMemberAccount;
protected $teamMembershipManager;
protected $team;
protected $teamApp;
protected $teamEntityRoutes = [];
protected $teamAppEntityRoutes = [];
protected const ADMIN_ROUTES = [
'apigee_edge_teams.settings.team',
'apigee_edge_teams.settings.team_app',
];
protected const TEAM_PERMISSION_MATRIX = [
'view any team' => [
'canonical',
],
'create team' => [
'add_form',
],
'update any team' => [
'edit_form',
],
'delete any team' => [
'delete_form',
],
'manage team members' => [
'members',
'add_members',
'member.edit',
'member.remove',
],
];
protected const TEAM_MEMBER_PERMISSION_MATRIX = [
'team_manage_members' => [
'members',
'add_members',
'member.edit',
'member.remove',
],
'team_app_view' => [
'canonical',
'collection_by_team',
'api_keys',
],
'team_app_create' => [
'add_form_for_team',
],
'team_app_update' => [
'edit_form',
],
'team_app_delete' => [
'delete_form',
],
'team_app_analytics' => [
'analytics',
],
'team_app_add_api_key' => [
'add_api_key_form',
],
];
protected $roles;
protected $teamRoleStorage;
protected $teamMemberRoleStorage;
protected $teamPermissionHandler;
protected $state;
protected static $modules = [
'apigee_edge_teams_test',
];
protected function setUp() {
parent::setUp();
$this->teamStorage = $this->container
->get('entity_type.manager')
->getStorage('team');
$this->teamAppStorage = $this->container
->get('entity_type.manager')
->getStorage('team_app');
$this->teamRoleStorage = $this->container
->get('entity_type.manager')
->getStorage('team_role');
$this->teamMemberRoleStorage = $this->container
->get('entity_type.manager')
->getStorage('team_member_role');
$this->teamMembershipManager = $this->container
->get('apigee_edge_teams.team_membership_manager');
$this->teamPermissionHandler = $this->container
->get('apigee_edge_teams.team_permissions');
$this->state = $this->container
->get('state');
$team_entity_type = $this->container
->get('entity_type.manager')
->getDefinition('team');
$team_app_entity_type = $this->container
->get('entity_type.manager')
->getDefinition('team_app');
foreach ($this->container
->get('entity_type.manager')
->getRouteProviders('team') as $provider) {
foreach ($provider
->getRoutes($team_entity_type) as $id => $route) {
$this->teamEntityRoutes[$id] = $route;
}
}
foreach ($this->container
->get('entity_type.manager')
->getRouteProviders('team_app') as $provider) {
foreach ($provider
->getRoutes($team_app_entity_type) as $id => $route) {
$this->teamAppEntityRoutes[$id] = $route;
}
}
$this->teamAppEntityRoutes = array_filter($this->teamAppEntityRoutes, function (Route $route) {
return strpos($route
->getPath(), '{consumer_key}') === FALSE;
});
$this->team = $this->teamStorage
->create([
'name' => mb_strtolower($this
->getRandomGenerator()
->name()),
]);
$this->team
->save();
$this->teamApp = $this->teamAppStorage
->create([
'name' => mb_strtolower($this
->getRandomGenerator()
->name()),
'companyName' => $this->team
->getName(),
]);
$this->teamApp
->save();
$this->account = $this
->createAccount();
$this->nonTeamMemberAccount = $this
->createAccount();
$this->teamMemberAccount = $this
->createAccount();
$this->teamMembershipManager
->addMembers($this->team
->getName(), [
$this->teamMemberAccount
->getEmail(),
]);
foreach (array_keys(static::TEAM_PERMISSION_MATRIX) as $permission) {
$this->roles[$permission] = $this
->createRole([
$permission,
], preg_replace('/[^a-z0-9_]+/', '_', $permission));
}
$this->roles['administer apigee edge'] = $this
->createRole([
'administer apigee edge',
], 'administer_apigee_edge');
$this->roles['administer team'] = $this
->createRole([
'administer team',
], 'administer_team');
$this->roles['manage team apps'] = $this
->createRole([
'manage team apps',
], 'manage_team_apps');
}
protected function tearDown() {
if ($this->team !== NULL) {
try {
$this->teamStorage
->delete([
$this->team,
]);
} catch (\Exception $exception) {
$this
->logException($exception);
}
}
if ($this->account !== NULL) {
try {
$this->account
->delete();
} catch (\Exception $exception) {
$this
->logException($exception);
}
}
if ($this->teamMemberAccount !== NULL) {
try {
$this->teamMemberAccount
->delete();
} catch (\Exception $exception) {
$this
->logException($exception);
}
}
if ($this->nonTeamMemberAccount !== NULL) {
try {
$this->nonTeamMemberAccount
->delete();
} catch (\Exception $exception) {
$this
->logException($exception);
}
}
parent::tearDown();
}
public function testAccess() {
$this
->teamAccessTest();
$this
->teamRoleAccessTest();
$this
->teamExpansionTest();
}
protected function teamAccessTest() {
if ($this->loggedInUser) {
$this
->drupalLogout();
}
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
$this
->validateAccessToAdminRoutes(FALSE);
$this
->drupalLogin($this->account);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
foreach (array_keys(self::TEAM_PERMISSION_MATRIX) as $permission) {
$this
->setUserPermissions([
$permission,
]);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
}
$this
->setUserPermissions(array_keys(self::TEAM_PERMISSION_MATRIX));
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
$this->teamMembershipManager
->addMembers($this->team
->getName(), [
$this->account
->getEmail(),
]);
$this
->setUserPermissions([]);
$this
->setTeamRolePermissionsOnUi(TeamRoleInterface::TEAM_MEMBER_ROLE, []);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
foreach (array_keys(self::TEAM_MEMBER_PERMISSION_MATRIX) as $permission) {
$this
->setTeamRolePermissionsOnUi(TeamRoleInterface::TEAM_MEMBER_ROLE, [
$permission,
]);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
}
$this
->setTeamRolePermissionsOnUi(TeamRoleInterface::TEAM_MEMBER_ROLE, array_keys(self::TEAM_MEMBER_PERMISSION_MATRIX));
$this->teamMembershipManager
->removeMembers($this->team
->getName(), [
$this->account
->getEmail(),
]);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
$this
->setUserPermissions([
'administer apigee edge',
]);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
$this
->validateAccessToAdminRoutes(FALSE);
$this
->setUserPermissions([
'manage team apps',
]);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess(TRUE);
$this
->validateAccessToAdminRoutes(FALSE);
$this
->setUserPermissions([
'administer team',
]);
$this
->validateTeamAccess(TRUE);
$this
->validateTeamAppAccess(TRUE);
$this
->validateAccessToAdminRoutes(TRUE);
}
protected function teamRoleAccessTest() {
if ($this->loggedInUser) {
$this
->drupalLogout();
}
$this
->setUserPermissions([]);
$this
->setTeamRolePermissionsOnUi(TeamRoleInterface::TEAM_MEMBER_ROLE, []);
$this->teamMembershipManager
->addMembers($this->team
->getName(), [
$this->account
->getEmail(),
]);
$this
->drupalLogin($this->rootUser);
foreach (array_keys(self::TEAM_MEMBER_PERMISSION_MATRIX) as $permission) {
$this
->drupalPostForm(Url::fromRoute('entity.team_role.add_form'), [
'label' => $permission,
'id' => $permission,
], 'Save');
$this
->setTeamRolePermissionsOnUi($permission, [
$permission,
]);
}
foreach (array_keys(self::TEAM_MEMBER_PERMISSION_MATRIX) as $permission) {
$this
->drupalLogin($this->rootUser);
$this->teamMemberRoleStorage
->addTeamRoles($this->account, $this->team, [
$permission,
]);
$this
->drupalLogin($this->account);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
$this
->drupalLogout();
}
foreach (array_keys(self::TEAM_MEMBER_PERMISSION_MATRIX) as $permission) {
$this
->drupalLogin($this->rootUser);
$this->teamMemberRoleStorage
->addTeamRoles($this->account, $this->team, [
$permission,
]);
$this
->drupalLogin($this->account);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
$this
->drupalLogout();
}
}
protected function teamExpansionTest() {
$this
->drupalLogin($this->rootUser);
$this
->drupalGet(Url::fromRoute('apigee_edge_teams.settings.team.permissions'));
$this
->assertSession()
->pageTextContains('Apigee Edge Teams: Testing');
$this
->assertSession()
->pageTextContains('Team permission test');
$this
->assertSession()
->pageTextContains('Team permission test 1');
$this
->assertSession()
->pageTextContains('This is the 1st team test permission.');
$this
->assertSession()
->pageTextContains('Team permission test 2');
$this
->assertSession()
->pageTextContains('Team permission test 3');
$this
->assertSession()
->pageTextContains('This is the 3rd team test permission.');
$this
->assertSession()
->pageTextContains('Team permission test 4');
$this
->disableUserPresave();
$this->account
->setUsername(APIGEE_EDGE_TEAMS_TEST_SPECIAL_USERNAME_WITH_ALL_TEAM_PERMISSIONS);
$this->account
->save();
$this
->enableUserPresave();
if (in_array($this->team
->id(), $this->teamMembershipManager
->getTeams($this->account
->getEmail()))) {
$this->teamMembershipManager
->removeMembers($this->team
->getName(), [
$this->account
->getEmail(),
]);
}
$this
->assertNotContains($this->team
->id(), $this->teamMembershipManager
->getTeams($this->account
->getEmail()));
$this
->drupalLogin($this->account);
$this
->validateTeamAccess();
$this
->validateTeamAppAccess();
$this->state
->set(APIGEE_EDGE_TEAMS_TEST_SPECIAL_USERNAME_CAN_VIEW_ANY_TEAM_STATE_KEY, TRUE);
$this
->validateAccess($this->team
->toUrl(), Response::HTTP_OK);
}
protected function validateTeamAccess(bool $admin_access = FALSE) {
$route_ids_with_access = [];
if ($admin_access) {
$route_ids_with_access = array_map(function (string $route_id) {
return str_replace('entity.team.', '', $route_id);
}, array_keys($this->teamEntityRoutes));
}
else {
foreach (array_keys(self::TEAM_PERMISSION_MATRIX) as $permission) {
if ($this->account
->hasPermission($permission)) {
$route_ids_with_access = array_merge($route_ids_with_access, self::TEAM_PERMISSION_MATRIX[$permission]);
}
}
if ($this
->drupalUserIsLoggedIn($this->account)) {
$route_ids_with_access[] = 'collection';
}
if (in_array($this->account
->getEmail(), $this->teamMembershipManager
->getMembers($this->team
->getName()))) {
$route_ids_with_access[] = 'canonical';
}
if (in_array('team_manage_members', $this->teamPermissionHandler
->getDeveloperPermissionsByTeam($this->team, $this->account))) {
$route_ids_with_access = array_merge($route_ids_with_access, self::TEAM_MEMBER_PERMISSION_MATRIX['team_manage_members']);
}
}
foreach ($this->teamEntityRoutes as $route_id => $route) {
$short_route_id = str_replace('entity.team.', '', $route_id);
$rel = str_replace('_', '-', $short_route_id);
if ($this->team
->hasLinkTemplate($rel)) {
$url = $this->team
->toUrl($rel);
if (in_array($short_route_id, $route_ids_with_access)) {
$this
->validateAccess($url, Response::HTTP_OK);
}
else {
$this
->validateAccess($url, Response::HTTP_FORBIDDEN);
}
}
else {
$params = [
'team' => $this->team
->id(),
];
$this
->validateAccess(Url::fromRoute($route_id, $params + [
'developer' => $this->teamMemberAccount
->getEmail(),
]), in_array($short_route_id, $route_ids_with_access) ? Response::HTTP_OK : Response::HTTP_FORBIDDEN);
$this
->validateAccess(Url::fromRoute($route_id, $params + [
'developer' => $this->nonTeamMemberAccount
->getEmail(),
]), Response::HTTP_FORBIDDEN);
$this
->validateAccess(Url::fromRoute($route_id, $params + [
'developer' => $this
->randomMachineName() . '@example.com',
]), Response::HTTP_NOT_FOUND);
}
}
}
protected function validateTeamAppAccess(bool $admin_access = FALSE) {
$route_ids_with_access = [];
if ($admin_access) {
$route_ids_with_access = array_map(function (string $route_id) {
return str_replace('entity.team_app.', '', $route_id);
}, array_keys($this->teamAppEntityRoutes));
}
else {
foreach (array_keys(self::TEAM_MEMBER_PERMISSION_MATRIX) as $permission) {
if (in_array($permission, $this->teamPermissionHandler
->getDeveloperPermissionsByTeam($this->team, $this->account))) {
$route_ids_with_access = array_merge($route_ids_with_access, self::TEAM_MEMBER_PERMISSION_MATRIX[$permission]);
}
}
}
foreach ($this->teamAppEntityRoutes as $route_id => $route) {
$short_route_id = str_replace('entity.team_app.', '', $route_id);
$rel = str_replace('_', '-', $short_route_id);
if ($this->teamApp
->hasLinkTemplate($rel)) {
$url = $this->teamApp
->toUrl($rel);
}
else {
$params = [
'team' => $this->team
->id(),
];
if (strpos($route
->getPath(), '{app}') !== FALSE) {
$params['app'] = $this->teamApp
->getName();
}
$url = Url::fromRoute($route_id, $params);
}
if (in_array($short_route_id, $route_ids_with_access)) {
$this
->validateAccess($url, Response::HTTP_OK);
}
else {
$this
->validateAccess($url, Response::HTTP_FORBIDDEN);
}
}
}
protected function validateAccess(Url $url, int $expected_response_status_code) {
$this
->drupalGet($url
->toString());
$code = $this
->getSession()
->getStatusCode();
$current_user_roles = implode(', ', $this->account
->getRoles());
$this
->assertEquals($expected_response_status_code, $code, "Visited path: {$url->getInternalPath()}. User roles: {$current_user_roles}");
}
protected function validateAccessToAdminRoutes(bool $user_has_access) {
foreach (self::ADMIN_ROUTES as $route_name) {
$this
->validateAccess(Url::fromRoute($route_name), $user_has_access ? Response::HTTP_OK : Response::HTTP_FORBIDDEN);
}
}
protected function setUserPermissions(array $permissions) {
$old_roles = $this->account
->getRoles(TRUE);
foreach ($old_roles as $old_role) {
$this->account
->removeRole($old_role);
}
foreach ($permissions as $permission) {
$this->account
->addRole($this->roles[$permission]);
}
$this
->disableUserPresave();
$this->account
->save();
$this
->enableUserPresave();
}
protected function setTeamRolePermissionsOnUi(string $role_name, array $permissions) {
$oldNotRootLoggedInUser = NULL;
if ($this->loggedInUser && $this->loggedInUser
->id() != $this->rootUser
->id()) {
$oldNotRootLoggedInUser = clone $this->loggedInUser;
}
if ($oldNotRootLoggedInUser === NULL || $oldNotRootLoggedInUser
->id() !== $this->rootUser
->id()) {
$this
->drupalLogin($this->rootUser);
}
$permission_changes = [];
foreach (array_keys(self::TEAM_MEMBER_PERMISSION_MATRIX) as $permission) {
$permission_changes["{$role_name}[{$permission}]"] = in_array($permission, $permissions);
}
$this
->drupalPostForm(Url::fromRoute('apigee_edge_teams.settings.team.permissions'), $permission_changes, 'Save permissions');
$this
->drupalGet(Url::fromRoute('apigee_edge_teams.settings.team.permissions'));
$this->teamRoleStorage
->resetCache([
$role_name,
]);
if ($oldNotRootLoggedInUser) {
if ($oldNotRootLoggedInUser
->id() === $this->account
->id()) {
$this
->drupalLogin($this->account);
}
else {
throw new \Exception("Unable to switch back to the originally logged user because it was neither the root user nor the simple authenticated user. Its user id: {$oldNotRootLoggedInUser->id()}.");
}
}
}
}