roleManager = $roleManager; $this->config = $config; $this->logger = $logger; $this->hookContainer = $hookContainer; $this->services = $services; $this->dynamicConfigManager = $dynamicConfigManager; $this->presets = new ExtensionAttributeBasedRegistry( 'BlueSpicePermissionManagerPermissionPresets' ); } /** * Enable role system */ public function enableRoleSystem() { $this->roleManager->enableRoleSystem(); } /** * Apply permission preset */ public function applyCurrentPreset() { try { $preset = $this->getActivePreset(); $preset->apply(); $this->services->getHookContainer()->run( 'BSPermissionManagerAfterApplyPreset', [ $preset, $this->roleManager ] ); } catch ( Throwable $exception ) { $this->logger->critical( 'Exception while applying preset: {error}', [ 'error' => $exception->getMessage() ] ); } } /** * @return IPreset */ public function getActivePreset() { $activePreset = $this->config->get( 'PermissionManagerActivePreset' ); $preset = $this->getPreset( $activePreset ); if ( $preset === null ) { $this->logger->critical( 'Attempted to apply unrecognized preset: {preset}', [ 'preset' => $activePreset ] ); throw new UnexpectedValueException( "Permission preset \"$activePreset\" is not registered or not allowed" ); } return $preset; } /** * Get names of available presets * * @return array */ public function getAvailablePresets() { return array_intersect( $this->presets->getAllKeys(), $this->config->get( 'PermissionManagerAllowedPresets' ) ); } /** * Get preset instance * * @param string $name * @return IPreset|null */ public function getPreset( $name ) { if ( !in_array( $name, $this->config->get( 'PermissionManagerAllowedPresets' ) ) ) { return null; } if ( !$this->presets->getValue( $name, null ) ) { return null; } $callable = $this->presets->getValue( $name ); $preset = call_user_func( $callable ); if ( !$preset instanceof IPreset ) { $this->logger->critical( 'Preset expected to be an instance of {preset_class}, {actual} given', [ 'preset_class' => IPreset::class, 'actual' => get_class( $preset ) ] ); return null; } return $preset; } /** * Get all permissions assigned to given role * * @param IRole|string $role * @param bool $includeDesc * @return array */ public function getRolePermissions( $role, $includeDesc = false ) { if ( $role instanceof IRole ) { $role = $role->getName(); } $role = $this->roleManager->getRole( $role ); if ( $role instanceof IRole === false ) { return []; } $permissions = $role->getPermissions(); if ( !$includeDesc ) { return $permissions; } $permissionsAndDescs = []; foreach ( $permissions as $permission ) { $permissionsAndDescs[ $permission ] = wfMessage( "right-$permission" )->text(); } return $permissionsAndDescs; } /** * @return RoleManager */ public function getRoleManager() { return $this->roleManager; } /** * * @param array $data * @return array */ public function saveRoles( $data ) { if ( !isset( $data ) || !isset( $data['groupRoles'] ) || !isset( $data['roleLockdown'] ) ) { throw new InvalidArgumentException(); } $groupRoles = $data['groupRoles']; $roleLockdown = $data['roleLockdown']; $status = $this->hookContainer->run( 'BsPermissionManager::beforeSaveRoles', [ &$groupRoles, &$roleLockdown ] ); if ( !$status ) { throw new \RuntimeException( 'Hook aborted' ); } return $this->persistRoles( $groupRoles, $roleLockdown ); } /** * * @return array */ public function getNamespaceRolesLockdown() { return $this->config->get( 'NamespaceRolesLockdown' ); } /** * * @return array */ public function getRoleDependencyTree() { $roles = $this->roleManager->getRoleNames(); $tree = []; foreach ( $roles as $roleName ) { $role = $this->roleManager->getRole( $roleName ); if ( !$role instanceof \BlueSpice\Permission\IRole ) { continue; } if ( empty( $role->getRequiredPermissions() ) ) { continue; } $requiredPermissions = $role->getRequiredPermissions(); $neededRoles = []; foreach ( $requiredPermissions as $permission ) { $rolesWithPermission = $this->roleManager->getRolesWithPermission( $permission ); if ( in_array( $roleName, $rolesWithPermission ) ) { continue; } $neededRoles[$permission] = $rolesWithPermission; } $tree[$roleName] = $neededRoles; } return $tree; } /** * * @param array $groupRoles * @param array $roleLockdown * @return array */ private function persistRoles( $groupRoles, $roleLockdown ) { if ( $this->services->getReadOnlyMode()->isReadOnly() ) { return [ 'success' => false, 'message' => wfMessage( 'bs-readonly', $this->services->getReadOnlyMode()->getReason() )->text() ]; } $roleMatrixDiff = new RoleMatrixDiff( $this->config, $groupRoles, $roleLockdown ); $globalDiff = $roleMatrixDiff->getGlobalDiff(); $nsDiff = $roleMatrixDiff->getNsDiff(); $status = $this->dynamicConfigManager->storeConfig( $this->dynamicConfigManager->getConfigObject( 'bs-permissionmanager-roles' ), [ 'groupRoles' => $groupRoles, 'roleLockdown' => $roleLockdown ] ); if ( $status ) { $this->doLog( $globalDiff, $nsDiff ); return [ 'success' => true ]; } else { return [ 'success' => false, 'message' => Message::newFromKey( 'bs-permissionmanager-write-config-file-error', 'bs-permissionmanager-roles' )->text() ]; } } /** * * @param array $globalDiff * @param array $nsDiff */ private function doLog( $globalDiff, $nsDiff ) { foreach ( $globalDiff as $group => $roles ) { $addedRoles = []; $removedRoles = []; foreach ( $roles as $role => $added ) { if ( $added ) { $addedRoles[] = $role; } else { $removedRoles[] = $role; } } if ( !empty( $addedRoles ) ) { $this->insertLog( 'global-add', [ '4::diffGroup' => $group, '5::diffRoles' => implode( ',', $addedRoles ), '6::roleCount' => count( $addedRoles ) ] ); } if ( !empty( $removedRoles ) ) { $this->insertLog( 'global-remove', [ '4::diffGroup' => $group, '5::diffRoles' => implode( ',', $removedRoles ), '6::roleCount' => count( $removedRoles ) ] ); } } foreach ( $nsDiff as $group => $namespaces ) { foreach ( $namespaces as $ns => $roles ) { $namespaceInfo = $this->services->getNamespaceInfo(); $nsCanonical = $namespaceInfo->getCanonicalName( $ns ); if ( $ns === NS_MAIN ) { $nsCanonical = wfMessage( 'bs-ns_main' )->text(); } $addedRoles = []; $removedRoles = []; foreach ( $roles as $role => $added ) { if ( $added ) { $addedRoles[] = $role; } else { $removedRoles[] = $role; } } if ( !empty( $addedRoles ) ) { $this->insertLog( 'ns-add', [ '4::diffGroup' => $group, '5::diffRoles' => implode( ',', $addedRoles ), '6::roleCount' => count( $addedRoles ), '7::ns' => $nsCanonical ] ); } if ( !empty( $removedRoles ) ) { $this->insertLog( 'ns-remove', [ '4::diffGroup' => $group, '5::diffRoles' => implode( ',', $removedRoles ), '6::roleCount' => count( $removedRoles ), '7::ns' => $nsCanonical ] ); } } } } /** * * @param string $type * @param array $params */ private function insertLog( $type, $params ) { $targetTitle = SpecialPage::getTitleFor( 'PermissionManager' ); $user = RequestContext::getMain()->getUser(); $logger = new ManualLogEntry( 'bs-permission-manager', $type ); $logger->setPerformer( $user ); $logger->setTarget( $targetTitle ); $logger->setParameters( $params ); $logger->insert( $this->services->getDBLoadBalancer()->getConnection( DB_PRIMARY ) ); } }