Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
77 / 77
100.00% covered (success)
100.00%
20 / 20
CRAP
100.00% covered (success)
100.00%
1 / 1
AuthorizationProfile
100.00% covered (success)
100.00%
77 / 77
100.00% covered (success)
100.00%
20 / 20
38
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getProviderId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getConsumerId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasValidProvider
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 hasValidConsumer
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getProvider
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 getConsumer
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 loadProviderPlugin
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 loadConsumerPlugin
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 getProviderConfig
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getConsumerConfig
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getProviderMappings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getConsumerMappings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setProviderConfig
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setConsumerConfig
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setProviderMappings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setConsumerMappings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTokens
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 checkConditions
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 grantsAndRevokes
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
8
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\authorization\Entity;
6
7use Drupal\Core\Config\Entity\ConfigEntityBase;
8use Drupal\Core\StringTranslation\StringTranslationTrait;
9use Drupal\authorization\AuthorizationProfileInterface;
10use Drupal\authorization\AuthorizationResponse;
11use Drupal\authorization\AuthorizationSkipAuthorization;
12use Drupal\authorization\Consumer\ConsumerInterface;
13use Drupal\authorization\Provider\ProviderInterface;
14use Drupal\user\UserInterface;
15
16/**
17 * Defines the Authorization profile entity.
18 *
19 * @ConfigEntityType(
20 *   id = "authorization_profile",
21 *   label = @Translation("Authorization profile"),
22 *   handlers = {
23 *     "list_builder" = "Drupal\authorization\AuthorizationProfileListBuilder",
24 *     "form" = {
25 *       "add" = "Drupal\authorization\Form\AuthorizationProfileAddForm",
26 *       "edit" = "Drupal\authorization\Form\AuthorizationProfileEditForm",
27 *       "delete" = "Drupal\authorization\Form\AuthorizationProfileDeleteForm"
28 *     }
29 *   },
30 *   config_prefix = "authorization_profile",
31 *   config_export = {
32 *     "id",
33 *     "label",
34 *     "provider",
35 *     "provider_config",
36 *     "provider_mappings",
37 *     "consumer",
38 *     "consumer_config",
39 *     "consumer_mappings",
40 *     "synchronization_modes",
41 *     "synchronization_actions",
42 *   },
43 *   admin_permission = "administer site configuration",
44 *   entity_keys = {
45 *     "id" = "id",
46 *     "label" = "label",
47 *     "uuid" = "uuid"
48 *   },
49 *   links = {
50 *     "edit-form" = "/admin/config/people/authorization/profile/{authorization_profile}",
51 *     "delete-form" = "/admin/config/people/authorization/profile/{authorization_profile}/delete",
52 *     "collection" = "/admin/config/people/authorization/profile"
53 *   }
54 * )
55 */
56class AuthorizationProfile extends ConfigEntityBase implements AuthorizationProfileInterface {
57
58  use StringTranslationTrait;
59
60  /**
61   * The Authorization profile ID.
62   *
63   * @var string
64   */
65  protected $id;
66
67  /**
68   * The Authorization profile label.
69   *
70   * @var string
71   */
72  protected $label;
73
74  /**
75   * The id of the Authorization provider.
76   *
77   * @var string
78   */
79  protected $provider;
80
81  /**
82   * The id of the Authorization consumer.
83   *
84   * @var string
85   */
86  protected $consumer;
87
88  /**
89   * The provider plugin configuration.
90   *
91   * @var array
92   */
93  protected $provider_config = [];
94
95  /**
96   * The provider plugin mappings.
97   *
98   * @var array
99   */
100  protected $provider_mappings = [];
101
102  /**
103   * The provider plugin instance.
104   *
105   * @var \Drupal\authorization\Provider\ProviderInterface
106   */
107  protected $provider_plugin;
108
109  /**
110   * The consumer plugin configuration.
111   *
112   * @var array
113   */
114  protected $consumer_config = [];
115
116  /**
117   * The consumer plugin mappings.
118   *
119   * @var array
120   */
121  protected $consumer_mappings = [];
122
123  /**
124   * The consumer plugin instance.
125   *
126   * @var \Drupal\authorization\Consumer\ConsumerInterface
127   */
128  protected $consumer_plugin;
129
130  /**
131   * The provider plugin manager.
132   *
133   * @var \Drupal\authorization\Provider\ProviderPluginManager
134   */
135  protected $provider_plugin_manager;
136
137  /**
138   * The consumer plugin manager.
139   *
140   * @var \Drupal\authorization\Consumer\ConsumerPluginManager
141   */
142  protected $consumer_plugin_manager;
143
144
145  /**
146   * The authorization logger channel.
147   *
148   * @var \Psr\Log\LoggerInterface
149   */
150  protected $logger;
151
152  /**
153   * {@inheritdoc}
154   */
155  public function __construct($values, $entity_type) {
156    parent::__construct($values, $entity_type);
157    // Cannot inject those without moving the logic to a controller class, (see
158    // https://www.drupal.org/node/2913224).
159    $this->provider_plugin_manager = \Drupal::service('plugin.manager.authorization.provider');
160    $this->consumer_plugin_manager = \Drupal::service('plugin.manager.authorization.consumer');
161    $this->logger = \Drupal::service('logger.channel.authorization');
162  }
163
164  /**
165   * {@inheritdoc}
166   */
167  public function getProviderId(): ?string {
168    return $this->provider;
169  }
170
171  /**
172   * Get the Consumer ID.
173   *
174   * @return string
175   *   Consumer ID.
176   */
177  public function getConsumerId(): ?string {
178    return $this->consumer;
179  }
180
181  /**
182   * {@inheritdoc}
183   */
184  public function hasValidProvider(): bool {
185    if ($this->provider_plugin_manager->getDefinition($this->getProviderId(), FALSE)) {
186      return TRUE;
187    }
188    return FALSE;
189  }
190
191  /**
192   * {@inheritdoc}
193   */
194  public function hasValidConsumer(): bool {
195    if ($this->consumer_plugin_manager->getDefinition($this->getConsumerId(), FALSE)) {
196      return TRUE;
197    }
198    return FALSE;
199  }
200
201  /**
202   * {@inheritdoc}
203   */
204  public function getProvider(): ?ProviderInterface {
205    if (!$this->provider_plugin || $this->getProviderId() !== $this->provider_plugin->getPluginId()) {
206      $this->loadProviderPlugin();
207    }
208    return $this->provider_plugin;
209  }
210
211  /**
212   * {@inheritdoc}
213   */
214  public function getConsumer(): ?ConsumerInterface {
215    if (!$this->consumer_plugin || $this->getConsumerId() !== $this->consumer_plugin->getPluginId()) {
216      $this->loadConsumerPlugin();
217    }
218    return $this->consumer_plugin;
219  }
220
221  /**
222   * Load the provider plugin.
223   */
224  protected function loadProviderPlugin(): void {
225    $config = $this->getProviderConfig();
226    $config['profile'] = $this;
227    try {
228      $this->provider_plugin = $this->provider_plugin_manager->createInstance($this->getProviderId(), $config);
229    }
230    catch (\Exception $e) {
231      $this->logger->critical('The provider with ID "@provider" could not be retrieved for profile %profile.', [
232        '@provider' => $this->getProviderId(),
233        '%profile' => $this->label(),
234      ]
235      );
236    }
237  }
238
239  /**
240   * Load the consumer plugin.
241   */
242  protected function loadConsumerPlugin(): void {
243    $config = $this->getConsumerConfig();
244    $config['profile'] = $this;
245    try {
246      $this->consumer_plugin = $this->consumer_plugin_manager->createInstance($this->getConsumerId(), $config);
247    }
248    catch (\Exception $e) {
249      $this->logger->critical('The consumer with ID "@consumer" could not be retrieved for profile %profile.', [
250        '@consumer' => $this->getConsumerId(),
251        '%profile' => $this->label(),
252      ]
253      );
254    }
255  }
256
257  /**
258   * {@inheritdoc}
259   */
260  public function getProviderConfig(): array {
261    return $this->provider_config;
262  }
263
264  /**
265   * {@inheritdoc}
266   */
267  public function getConsumerConfig(): array {
268    return $this->consumer_config;
269  }
270
271  /**
272   * {@inheritdoc}
273   */
274  public function getProviderMappings(): array {
275    return $this->provider_mappings;
276  }
277
278  /**
279   * {@inheritdoc}
280   */
281  public function getConsumerMappings(): array {
282    return $this->consumer_mappings;
283  }
284
285  /**
286   * {@inheritdoc}
287   */
288  public function setProviderConfig(array $provider_config): void {
289    $this->provider_config = $provider_config;
290  }
291
292  /**
293   * {@inheritdoc}
294   */
295  public function setConsumerConfig(array $consumer_config): void {
296    $this->consumer_config = $consumer_config;
297  }
298
299  /**
300   * {@inheritdoc}
301   */
302  public function setProviderMappings(array $provider_mappings): void {
303    $this->provider_mappings = $provider_mappings;
304  }
305
306  /**
307   * {@inheritdoc}
308   */
309  public function setConsumerMappings(array $consumer_mappings): void {
310    $this->consumer_mappings = $consumer_mappings;
311  }
312
313  /**
314   * {@inheritdoc}
315   */
316  public function getTokens(): array {
317    $tokens = [];
318    $tokens['@profile_name'] = $this->label;
319    return $tokens;
320  }
321
322  /**
323   * {@inheritdoc}
324   */
325  public function checkConditions(): bool {
326
327    if (!$this->get('status')) {
328      return FALSE;
329    }
330
331    if (!$this->getProvider()) {
332      return FALSE;
333    }
334
335    if (!$this->getConsumer()) {
336      return FALSE;
337    }
338
339    return TRUE;
340  }
341
342  /**
343   * {@inheritdoc}
344   */
345  public function grantsAndRevokes(UserInterface $user, $user_save = FALSE): AuthorizationResponse {
346
347    $provider = $this->getProvider();
348    $consumer = $this->getConsumer();
349
350    try {
351      $proposals = $provider->getProposals($user);
352    }
353    catch (AuthorizationSkipAuthorization $e) {
354      return new AuthorizationResponse((string) $this->t('@name (skipped)', ['@name' => $this->label]), TRUE, []);
355    }
356
357    $proposals = $provider->sanitizeProposals($proposals);
358
359    $applied_grants = [];
360    // @todo This could be made more elegant with methods on this class checking
361    // for support on this and not checking here the array key directly.
362    $create_consumers = $this->get('synchronization_actions')['create_consumers'] ?? FALSE;
363    $revoke_provision = $this->get('synchronization_actions')['revoke_provider_provisioned'] ?? FALSE;
364    foreach ($this->getProviderMappings() as $provider_key => $provider_mapping) {
365      $provider_proposals = $provider->filterProposals($proposals, $provider_mapping);
366      $filtered_proposals = $consumer->filterProposals($provider_proposals, $this->getConsumerMappings()[$provider_key]);
367
368      if (!empty($filtered_proposals)) {
369        foreach ($filtered_proposals as $filtered_proposal) {
370          if ($create_consumers) {
371            $consumer->createConsumerTarget($filtered_proposal);
372          }
373          $consumer->grantSingleAuthorization($user, $filtered_proposal, $this->id());
374          $applied_grants[$filtered_proposal] = $filtered_proposal;
375        }
376      }
377    }
378
379    if ($revoke_provision) {
380      $consumer->revokeGrants($user, $applied_grants, $this->id());
381    }
382
383    if ($user_save === TRUE) {
384      $user->save();
385    }
386
387    return new AuthorizationResponse($this->label, FALSE, $applied_grants);
388  }
389
390}