1

I have a Webform setup with a secure token URL, allowing anonymous users to edit and submit draft submissions, like this:

https://website.com/webform/test_save?token=mV8_GX7CRu7J9S9XiJ6ghR_DNdKTQbpCMSFdNd8fCa8&webform_submission=18

However, when accessing the draft submission via this link (without being logged in), the user receives a new session. The PDF file, generated using Entity Print in Webform, is accessible through a link on the confirmation page:

/print/pdf/webform_submission/[webform_submission:sid]

The issue: Although a session cookie is generated when editing via the secure token, it appears that the new session doesn't allow access to the PDF. This might be because the new session is not recognized as the same "anonymous user" session that created the draft.

This behavior differs from cases where a Webform is filled out and submitted without saving a draft. In such cases, the user can access the PDF immediately upon form submission as long as the session is active.

Question: Is there a workaround or configuration option in Webform that would allow access to the PDF of a draft submission, even if the session has changed? Or is there a way to associate the new session with the original draft submission?

8
  • This may be impossible because of Core’s protections for CVE-2017-6922 in drupal.org/forum/newsletters/…. Whether that is true depends on how Webform handles files on drafts. I haven’t yet checked the details.
    – mona lisa
    Commented Oct 30 at 11:27
  • 1
    To wit: If I am guessing correctly it would have to be the same session and that’s impossible.
    – mona lisa
    Commented Oct 30 at 11:41
  • @monlisa the PDF File is generated on the fly and isn't stored in private files but anyway the user needs the permissions to access it's own submissions and as you said it would be another session even if a session would be created. On the other hand its a bit strange when submitting the form finally one can't download the results, while it works if no draft was in place before.
    – macbert
    Commented Oct 30 at 12:18
  • What is the technical means of generating the PDF? It think that is missing from the question.
    – mona lisa
    Commented Oct 30 at 13:26
  • added some details about the pdf generation
    – macbert
    Commented Oct 30 at 13:41

1 Answer 1

1

Okay, I endet up with adding the following to my custom_webform module: Routing adding custom access:

    entity_print.view:
  path: 'print/{export_type}/{entity_type}/{entity_id}'
  defaults:
    _controller: '\Drupal\entity_print\Controller\EntityPrintController::viewPrint'
    _title: 'Entity Print'
  requirements:
    _custom_access: 'custom_webform_custom_access'

adding a new Token:

function custom_webform_token_info()
{
  $info['tokens']['webform_submission']['secure_pdf_url'] = [
    'name' => t('Secure PDF URL'),
    'description' => t('A secure link to download the PDF with token-based access.'),
  ];
  return $info;
}

function custom_webform_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata, WebformSubmissionInterface $webform_submission = NULL) {
  $replacements = [];
  foreach ($tokens as $name => $original) {
    if ($name === 'secure_pdf_url' && $webform_submission instanceof WebformSubmissionInterface) {
      $replacements[$original] = custom_webform_generate_secure_pdf_url($webform_submission);
    }
  }
    return $replacements;
}

Generating the secure token url:

function custom_webform_generate_secure_pdf_url(WebformSubmissionInterface $submission) {
  if (!$submission instanceof WebformSubmissionInterface) {
    \Drupal::logger('custom_webform')->warning('Invalid WebformSubmission provided to custom_webform_generate_secure_pdf_url().');
    return '';
  } 

  $pdf_uri = "print/pdf/webform_submission/{$submission->id()}";
  $token = _webform_entity_print_token_generate($pdf_uri);

  $pdf_url = $pdf_uri . '?webform_entity_print_itok=' . $token;

  return $pdf_url;
}

Here I found that, there is already a token generate in webform submodule webform_entity_print but it isn't exposed and there isn't a custom access for that. It is used for the PDF-Print button I guess but that couldn't be used in our use case somehow. Maybe this could be exposed as token in the future.

Then I added the custom_access method:

/**
 * Custom access callback for entity print routes.
 */
function custom_webform_custom_access($export_type, $entity_type, $entity_id, AccountInterface $account) {
  \Drupal::logger('custom_webform')->notice("Checking access for export_type: $export_type, entity_type: $entity_type, entity_id: $entity_id.");

  // Nur für den Export-Typ „pdf“ und Entitätstyp „webform_submission“.
  if ($export_type !== 'pdf' || $entity_type !== 'webform_submission') {
    \Drupal::logger('custom_webform')->warning("Access denied due to incorrect type.");
    return AccessResult::forbidden();
  }

  // Token aus der URL holen und prüfen.
  $token = \Drupal::request()->query->get('webform_entity_print_itok');
  if ($token) {
    $pdf_uri = "print/$export_type/$entity_type/$entity_id";
    $expected_token = _webform_entity_print_token_generate($pdf_uri);

    \Drupal::logger('custom_webform')->notice("Generated URI for token: $pdf_uri, Expected token: $expected_token");

    \Drupal::logger('custom_webform')->notice("URL-Token: $token, Expected Token: $expected_token");


    // Zugriff gewähren, wenn das Token korrekt ist.
    if ($token === $expected_token) {
      \Drupal::logger('custom_webform')->notice("Access allowed due to valid token.");
      return AccessResult::allowed();
    } else {
      \Drupal::logger('custom_webform')->warning("Access denied due to invalid token.");
    }
  } else {
    \Drupal::logger('custom_webform')->warning("Access denied due to missing token.");
  }

  // Standard-Zugriffsprüfung für „view own submissions“ verwenden.
  $webform_submission = WebformSubmission::load($entity_id);
  if ($webform_submission && $webform_submission->access('view', $account)) {
    \Drupal::logger('custom_webform')->notice("Access allowed based on 'view own submissions' permission.");
    return AccessResult::allowed();
  }

  \Drupal::logger('custom_webform')->warning("Access denied due to failed permissions check.");
  return AccessResult::forbidden();
}

There might be an easier way or maybe I did overlook something that's already there but this seems to work quite good. Now I too can add those pdf links for later use to an email for generating tickets instead of only containing the submissions values.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.