Hi!
I am trying to make CORS upload work but it is not clear to me what should be done.
I have added the 'cors' => TRUE option in the S3 config in settings.php
But I understand I also need to provide the AllowedOrigins someway.
I see there is an s3-cors-example.json file, but I don't know what I'm supposed to do with this JSON config.

I don't know what you mean by "a template you can use to configure CORS using the REST API or the aws s3api put-bucket-cors command"

With the other module S3 File System CORS, there is an admin form that let's us fill in the allowed origins and then uses the s3Client->putBucketCors function to make it work.

With Flysystem S3, do I need to build my own admin form and do the same programmatically ?

Thank you!

Nick

Comments

Nicolas Bouteille created an issue. See original summary.

nicolas bouteille’s picture

OK here's what I did to make it work, and it indeed works now... but I feel like maybe I did too much?
If this was indeed necessary, I suggest we add the same kind of form that in S3 File System CORS...

<?php

namespace Drupal\my_module\Form;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\flysystem\FlysystemFactory;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
use Aws\S3\S3Client;

/**
 * Config settings for My Module S3 Cors.
 * 
 * This code is based S3 File System CORS s3fs_cors S3fsCorsAdminForm.php but adapted for Flysystem S3
 */
class MYMODULES3CorsForm extends ConfigFormBase {

  use StringTranslationTrait;

  /** @var FlysystemFactory */
  private $flysystemFactory;

  /**
   * MYMODULES3CorsForm constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory interface.
   * @param FlysystemFactory $flysystem_factory
   *   The Flysystem Factory
   */
  public function __construct(ConfigFactoryInterface $config_factory, FlysystemFactory $flysystem_factory) {
    parent::__construct($config_factory);
    $this->flysystemFactory = $flysystem_factory;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory'),
      $container->get('flysystem_factory')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'my_module_s3_cors_form';
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return ['my_module_s3_cors.settings'];
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    // You can debug this to verify the CORS config of your bucket
//    /** @var AwsS3Adapter $s3_adapter */
//    $s3_adapter = $this->flysystemFactory->getPlugin('s3')->getAdapter();
//    /** @var S3Client $s3_client */
//    $s3_client = $s3_adapter->getClient();
//
//    $bucket_cors = $s3_client->getBucketCors([
//      'Bucket' => $s3_adapter->getBucket()
//    ]);


    $config = $this->config('my_module_s3_cors.settings');

    $form['my_module_s3_cors_origin'] = [
      '#type' => 'textfield',
      '#title' => $this->t('CORS Origin'),
      '#description' => $this->t('Please enter the URL from which your users access this website, e.g. <i>www.example.com</i>.
      You may optionally specifiy up to one wildcard, e.g. <i>*.example.com</i>.<br>
      Upon submitting this form, if this field is filled, your S3 bucket will be configured to allow CORS
      requests from the specified origin. If the field is empty, your bucket\'s CORS config will be deleted.'),
      '#default_value' => !empty($config->get('my_module_s3_cors_origin')) ? $config->get('my_module_s3_cors_origin') : '',
    ];

    $form = parent::buildForm($form, $form_state);
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {

    try {
      /** @var AwsS3Adapter $s3_adapter */
      $s3_adapter = $this->flysystemFactory->getPlugin('s3')->getAdapter();
      /** @var S3Client $s3_client */
      $s3_client = $s3_adapter->getClient();

      $cors_origin = $form_state->getValue('my_module_s3_cors_origin');
      $this->config('my_module_s3_cors.settings')
        ->set('my_module_s3_cors_origin', $cors_origin)
        ->save();


      if (!empty($cors_origin)) {
        // Create an array of allowed CORS origins
        $cors_origins = array_filter(explode(',', str_replace(' ', ',', $cors_origin)));
        $allowed_origins = [];
        foreach ($cors_origins as $origin) {
          $allowed_origins[] = 'http://' . $origin;
          $allowed_origins[] = 'https://' . $origin;
        }
        $s3_client->putBucketCors([
          // REQUIRED.
          'Bucket' => $s3_adapter->getBucket(),
          // REQUIRED.
          'CORSConfiguration' => [
            // REQUIRED.
            'CORSRules' => [
              [
                'AllowedHeaders' => ['*'],
                'ExposeHeaders' => ['x-amz-version-id'],
                'AllowedMethods' => ['POST'],
                'MaxAgeSeconds' => 3000,
                'AllowedOrigins' => $allowed_origins,
              ],
              [
                'AllowedMethods' => ['GET'],
                'AllowedOrigins' => ['*'],
              ],
              // ...
            ],
          ],
        ]);
        $this->messenger()
          ->addMessage($this->t("CORS settings have been succesfully updated at AWS CORS"));
      }
      else {
        // If $form_state['values']['my_module_s3_cors_origin'] is empty, that means we
        // need to delete their bucket's CORS config.
        $s3_client->deleteBucketCors([
          'Bucket' => $s3_adapter->getBucket(),
        ]);
        $this->messenger()
          ->addMessage($this->t("CORS settings have been deleted succesfully"));
      }
    } catch (\Throwable $t) {
      $this->messenger()->addError($t->getMessage());
    }

  }

}
?>
eli-t’s picture

Status: Active » Closed (won't fix)

I'm assuming as this issue is 10 months old that either a way forward has been found, or is no longer require.

Please feel free to re-open if you still need support to resolve.

nicolas bouteille’s picture

Title: Need some help configuring S3 CORS » Make it possible to update Allowed Origins
Category: Support request » Feature request
Status: Closed (won't fix) » Active

No need for support indeed since I found a solution, but I suggested a form to update allowed origins like I did could be added to the module. Switching to feature request then.