5 * Contains \Drupal\security_review\Form\SettingsForm.
8 namespace Drupal\security_review\Form;
10 use Drupal\Component\Utility\SafeMarkup;
11 use Drupal\Core\Config\ConfigFactoryInterface;
12 use Drupal\Core\Form\ConfigFormBase;
13 use Drupal\Core\Form\FormStateInterface;
14 use Drupal\Core\Session\AccountInterface;
15 use Drupal\security_review\Checklist;
16 use Drupal\security_review\Security;
17 use Drupal\security_review\SecurityReview;
18 use Symfony\Component\DependencyInjection\ContainerInterface;
21 * Settings page for Security Review.
23 class SettingsForm extends ConfigFormBase {
26 * The security_review.checklist service.
28 * @var \Drupal\security_review\Checklist
33 * The security_review.security service.
35 * @var \Drupal\security_review\Security
40 * The security_review service.
42 * @var \Drupal\security_review\SecurityReview
44 protected $securityReview;
47 * Constructs a SettingsForm.
49 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
51 * @param \Drupal\security_review\Checklist $checklist
52 * The security_review.checklist service.
53 * @param \Drupal\security_review\Security $security
54 * The security_review.security service.
55 * @param \Drupal\security_review\SecurityReview $security_review
56 * The security_review service.
58 public function __construct(ConfigFactoryInterface $config_factory, Checklist $checklist, Security $security, SecurityReview $security_review) {
59 parent::__construct($config_factory);
60 $this->checklist = $checklist;
61 $this->security = $security;
62 $this->securityReview = $security_review;
68 public static function create(ContainerInterface $container) {
70 $container->get('config.factory'),
71 $container->get('security_review.checklist'),
72 $container->get('security_review.security'),
73 $container->get('security_review')
80 public function getFormId() {
81 return 'security-review-settings';
87 public function buildForm(array $form, FormStateInterface $form_state) {
88 // Get the list of checks.
89 $checks = $this->checklist->getChecks();
91 // Get the user roles.
92 $roles = user_roles();
94 foreach ($roles as $rid => $role) {
95 $options[$rid] = SafeMarkup::checkPlain($role->label());
98 // Notify the user if anonymous users can create accounts.
100 if (in_array(AccountInterface::AUTHENTICATED_ROLE, $this->security->defaultUntrustedRoles())) {
101 $message = $this->t('You have allowed anonymous users to create accounts without approval so the authenticated role defaults to untrusted.');
104 // Show the untrusted roles form element.
105 $form['untrusted_roles'] = [
106 '#type' => 'checkboxes',
107 '#title' => $this->t('Untrusted roles'),
108 '#description' => $this->t(
109 'Define which roles are for less trusted users. The anonymous role defaults to untrusted. @message Most Security Review checks look for resources usable by untrusted roles.',
110 ['@message' => $message]
112 '#options' => $options,
113 '#default_value' => $this->security->untrustedRoles(),
116 $form['advanced'] = [
117 '#type' => 'details',
118 '#title' => $this->t('Advanced'),
122 // Show the logging setting.
123 $form['advanced']['logging'] = [
124 '#type' => 'checkbox',
125 '#title' => $this->t('Log checklist results and skips'),
126 '#description' => $this->t('The result of each check and skip can be logged to watchdog for tracking.'),
127 '#default_value' => $this->securityReview->isLogging(),
133 foreach ($checks as $check) {
134 // Determine if check is being skipped.
135 if ($check->isSkipped()) {
136 $values[] = $check->id();
138 '@name <em>skipped by UID @uid on @date</em>',
140 '@name' => $check->getTitle(),
141 '@uid' => $check->skippedBy()->id(),
142 '@date' => format_date($check->skippedOn()),
147 $label = $check->getTitle();
149 $options[$check->id()] = $label;
151 $form['advanced']['skip'] = [
152 '#type' => 'checkboxes',
153 '#title' => $this->t('Checks to skip'),
154 '#description' => $this->t('Skip running certain checks. This can also be set on the <em>Run & review</em> page. It is recommended that you do not skip any checks unless you know the result is wrong or the process times out while running.'),
155 '#options' => $options,
156 '#default_value' => $values,
159 // Iterate through checklist and get check-specific setting pages.
160 foreach ($checks as $check) {
161 // Get the check's setting form.
162 $check_form = $check->settings()->buildForm();
164 // If not empty, add it to the form.
165 if (!empty($check_form)) {
166 // If this is the first non-empty setting page initialize the 'details'
167 if (!isset($form['advanced']['check_specific'])) {
168 $form['advanced']['check_specific'] = [
169 '#type' => 'details',
170 '#title' => $this->t('Check-specific settings'),
177 $sub_form = &$form['advanced']['check_specific'][$check->id()];
179 $title = $check->getTitle();
180 // If it's an external check, show its namespace.
181 if ($check->getMachineNamespace() != 'security_review') {
182 $title .= $this->t('%namespace', [
183 '%namespace' => $check->getNamespace(),
187 '#type' => 'details',
191 'form' => $check_form,
196 // Return the finished form.
197 return parent::buildForm($form, $form_state);
203 public function validateForm(array &$form, FormStateInterface $form_state) {
204 // Run validation for check-specific settings.
205 if (isset($form['advanced']['check_specific'])) {
206 $check_specific_values = $form_state->getValue('check_specific');
207 foreach ($this->checklist->getChecks() as $check) {
208 $check_form = &$form['advanced']['check_specific'][$check->id()];
209 if (isset($check_form)) {
211 ->validateForm($check_form, $check_specific_values[$check->id()]);
220 public function submitForm(array &$form, FormStateInterface $form_state) {
221 // Frequently used configuration items.
222 $check_settings = $this->config('security_review.checks');
224 // Save that the module has been configured.
225 $this->securityReview->setConfigured(TRUE);
227 // Save the new untrusted roles.
228 $untrusted_roles = array_keys(array_filter($form_state->getValue('untrusted_roles')));
229 $this->securityReview->setUntrustedRoles($untrusted_roles);
231 // Save the new logging setting.
232 $logging = $form_state->getValue('logging') == 1;
233 $this->securityReview->setLogging($logging);
235 // Skip selected checks.
236 $skipped = array_keys(array_filter($form_state->getValue('skip')));
237 foreach ($this->checklist->getChecks() as $check) {
238 if (in_array($check->id(), $skipped)) {
246 // Save the check-specific settings.
247 if (isset($form['advanced']['check_specific'])) {
248 $check_specific_values = $form_state->getValue('check_specific');
249 foreach ($check_specific_values as $id => $values) {
250 // Get corresponding Check.
251 $check = $this->checklist->getCheckById($id);
253 // Submit parameters.
254 $check_form = &$form['advanced']['check_specific'][$id]['form'];
255 $check_form_values = $check_specific_values[$id]['form'];
258 $check->settings()->submitForm($check_form, $check_form_values);
262 // Commit the settings.
263 $check_settings->save();
265 // Finish submitting the form.
266 parent::submitForm($form, $form_state);
272 protected function getEditableConfigNames() {
273 return ['security_review.checks'];