Adding anonymous user tracking to Entityforms submissions so that anonymous users can edit their submissions.

This will probably be done in an Entityforms Anonymous submodule.

I welcome feedback and suggestions. I will be starting on this very soon as it is sponsored development so let me know soon.

Here's what it will look like so far:

Entityform Types

  • New Anonymous Tracking settings section. Anonymous tracking will be optional.
  • 2 types of tracking. Allow via browsers session or allow via unique link(or both).

Browser Sessions

Browser sessions would obviously have security implications. It will be up to site admins to deal with this through other modules or sessions timeouts.

Unique Links

This will allow unique anonymous links for each entityform submission.
Submit link: eform/submit/[id]/[random_key] - this would allow access to a submission that is in the draft state.
Edit link: entityform/[id]/edit/[random_key] - edit previous submission
View link: entityform/id/view/[random_key] - view previous submission

Obviously these links would be very powerful. Anyone who has access to the links to could access the submissions.
The permissions for anonymous users would respected for these links.

The links would available as tokens on the entityform submission entity. This would allow them to be shown in different places such as the confirmation page, like:

Copy this link to edit your submission later

It could also be sent in Emails(if an email is collected on the form) that would allow a user to come back and edit the form.

Developer Notes

The submodule will add a unique key field to the entityform table. It will just store random key for the submission so that the links and session cookies would be hard to spoof. I thought about using the UUID module for this but it seems very heavy for the solution.

hook_menu?

Not sure if I will actually need to implement hook_menu(as detailed above). Could just use regular entityform links and use hook_entityform_access to determine access. In this case hook_entityform_access could be used to determine access.

If not using hook_menu then be need to pass random key via query string like so: entityform/[id]/edit?key=[key]

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

joachim’s picture

You should look at how Flag module handles anonymous flaggings -- it uses the Session API module.

DamienMcKenna’s picture

If you do this you might want to add something to the README.txt and hook_requirements staging it is only advisable to use the submodule on a secure site, otherwise the cookie / link could be sniffed. There might also be implications for using reverse proxy caches, e.g. Varnish.

tedbow’s picture

Because of concerns like state in #2, maybe this would be something that would better in separate module(sandbox?).

Then the caveats could be better explained. I don't know if anyone is going to read a README.txt on a submodule.

tedbow’s picture

Re #1

Yeah I was looking at session_api as used in Flag. Might want to use this but it looks like Flag just uses the session id from session_api_get_sid to associate the flag. That will just be sequential integer I think so that would be easier to guess when replacing in the link.

tedbow’s picture

I think 1 thing that Flag does that this should do eventually would be to convert the anonymous submission for the user to be owned by the user if they register after being anonymous.

But I will probably not add right now to keep it simplier.

joachim’s picture

The SID isn't visible: the unflag link, for example, looks like flag/unflag/test_2154251_active/7?destination=node&token=19b1b1f1ff1f500d0df95111e2fd05aa&has_js=1

The 7 is the node ID.

tedbow’s picture

@joachim ok thanks. I see how flag_get_token does this now. It makes sense.

tedbow’s picture

So guess I could use something like entityform/[id]?token=19b1b1f1ff1f500d0df95111e2fd05aa

for the external link.

Then just store the sid on the entityform table. No need for a random key to be stored?

tedbow’s picture

Status: Active » Needs work

Ok I have created a new branch for this: http://drupalcode.org/project/entityform.git/shortlog/refs/heads/7.x-2.x...
It's rough now but any feedback would be appreciated.

Currently it only deals with providing access via links with the tokens. Nothing is stored in the browser sessions.

There is a settings area called Anonymous Tracking on the Entityform Type edit form

The links are provided as tokens.

I have just made Rule locally to display on links when viewing an Entityform Submission. One way to use the tokens on a site maybe to display them on the confirmation page of a form.

The links are View, Edit, Submit.

Submit works with the resubmit setting of the form and if the submission has been saved as a draft.

I have made a new hook in entityform, hook_entityform_previous_submission_alter . This allows a module to explicitly which Entityform submission is used as the Previous submission for an Entityform Type. This works for determining which draft submission to use and the re-submit action.

i can see other uses for hook_entityform_previous_submission_alter.

I know there is an issue with the Confirm page right now for resubmitting a form view the link.

tedbow’s picture

I pushed changes to this branch which add the anonymous session tracking.

@joachim, thanks for tip to look at Flag.

tedbow’s picture

Status: Needs work » Needs review

I have pushed merged Entityform Anonymous into 7.x-2.x

It obviously will need more testing.

I put warnings on the Entityform Type settings section for this.

I have created a readme file.

I am not sure what warnings to put in here. If anyone has suggestions that would be great.

skadu’s picture

Hi tedbow,

This module looks pretty nice, and I really like where it's heading. Just wanted to mention something I noticed.

When viewing a submission using a link, the anonymous user is shown the local tabs (View and Edit in my case). These tabs however, do not contain the token, and if clicked lead to an access denied page. For my purposes I wanted to have those tabs work for the anonymous users and allow them to edit their submission right from the view link they clicked.

I went about this by adding a hook_menu_local_tasks_alter to the entityforms_anonymous module. I am not sure if this is something you want to occur by default or not, but I figured I would send along the work I did.

I have attached a diff that I hope is helpful, but pasted below is the function I added:

/**
 * Implements hook_menu_local_tasks_alter()
 *
 * Alter the tabs that are presented to anonymous users when viewing/editing
 * their submission. By default these tabs will not have the tokens that allow
 * access to their submission, so we need to append them.
 *
 */
function entityform_anonymous_menu_local_tasks_alter(&$data, $router_item, $router_name){
  //set up a switch on the router name so we can react accordingly
  switch($router_name){
    case 'entityform/%/edit':
    case 'entityform/%':
    case 'entityform/%/delete':
      //check to see if this is an anon user
      if(user_is_anonymous()){
        //now check to be sure we have a fully loaded object
        if(isset($router_item['page_arguments'][0]) && is_object($router_item['page_arguments'][0])){
          //make sure this is an anon submitted form
          $entityform = $router_item['page_arguments'][0];
          if(_entityform_anonymous_user_submitted_form($entityform)){
            //then grab the token from the GET request
            $token = $_GET['token'];
            $query = array(
              'token' => $token
            );
            //loop through our tabs (view/edit/delete)
            //@todo ensure we are only modifying entityform tabs
            foreach($data['tabs'][0]['output'] as $k => &$v){
              $v['#link']['localized_options']['query'] = isset($v['#link']['localized_options']['query']) && is_array($v['#link']['options']['query'])
                ? array_merge($v['#link']['localized_options']['query'],$query)
                : $query;
            }
          }
        }
      }
      break;
  }
}

A couple of things still to do:

  • Ensure we are only adding the token to tabs that really require the token, only the edit/view/delete tabs.
  • Maybe bring into play the session API option, but at that point, altering the menu wouldn't matter. So this function would need to bail out instead of looking for a token that doesn't exist.

Hope this helps, let me know if you need anything else from me, and keep up the good work.

~ Skadu

Status: Needs review » Needs work

The last submitted patch, 12: entityform_anonymous-alter_local_menu_tasks-2181691-12.patch, failed testing.

tedbow’s picture

Hmm I am not sure. It seems like the patch would assume anonymous should have the right to edit their submissions. This might not be the case. Have you tried turning on both anonymous options. I think then it should work. But then that there is probably a problem with entityform_access.

skadu’s picture

Hi tedbow,

Thanks for taking a look, a couple of things:

Both Anonymous Options

I tried turning on both anonymous options and the tabs (without a token) do not allow view/edit access. This is because in the codebase I have:

  • version = "7.x-2.0-beta4"
  • core = "7.x"
  • project = "entityform"
  • datestamp = "1405024728"

The function _entityform_anonymous_user_submitted_form, which is called by the access_alter hook only supports the query string token, it doesn't do any checking for session based access:

**
 * Utility function to determine if current user submitted the form.
 *
 * Currently only supports query string token
 * @param $entityform
 * @return bool
 */
function _entityform_anonymous_user_submitted_form($entityform) {
  if (user_is_anonymous()) {
    $entityform_type = entityform_type_load($entityform->type);
    if (!empty($entityform_type->data['anonymous_links']) && !empty($_GET['token'])) {
      if ($_GET['token'] == _entityform_anonymous_get_token($entityform->entityform_id)) {
        return TRUE;
      }
      // @todo Message about bad token/link
    }
  }
}

Is there another codebase somewhere that checks on the session based setting? If so I would happily test and report back.

Permissions Assumption
I was under the impression (and could certainly be wrong) that permissions were handled elsewhere. In my instance, users are not allowed to delete their own entries and the delete tab does not appear on screen, even though it is available during the local_task_alter hook.

I believe this is because of the access_alter function being fired off by entityform_anonymous that checks for user access based on the current operation:

/**
 * Implements hook_entityform_access_alter().
 *
 * If user is anonymous determine if they should have access to submission
 */
function entityform_anonymous_entityform_access_alter(&$access, $op, $context) {
  // Only alter if $access not TRUE

  $account = $context['account'];
  $entityform = $context['entityform'];
  if (!$access && isset($entityform->uid) && $account->uid == 0 && $entityform->uid == 0) {
    if (_entityform_anonymous_user_submitted_form($entityform)) {
      if ($op == 'confirm') {
        $access = TRUE;
      }
      else {
        if (user_access("$op own entityform")) {
          // This is an anonymously submitted and the current user is anonymous

          $access = TRUE;
        }
      }
    }
  }
}

I just ran a quick test where I removed edit permissions, and the tab does not appear to the user. I also tried that with delete permissions being turned on and my delete link appeared, but the edit link did not. I will admit I did not take a look at entityform_access, just the access_alter being used by entityform_anonymous.

I can certainly modify the patch to first check if the user has the correct permissions before modifying the links. It seems like double work to me if the other access check is already going to ensure that the tabs are not visible to those without the correct permissions.

Happy to help debugging further. Did the patch fail to test because I'm coming from the beta version, not 2.x?

Thanks again.

~ Skadu

  • tedbow committed 8eb093e on 7.x-2-metatags-2344293
    Issue #2181691 by tedbow:Added anonymous session tracking of submissions
    
  • tedbow committed 2e14ab5 on 7.x-2-metatags-2344293
    Issue #2181691 by tedbow: Added readme to entityform anonymous with...
Michael G’s picture

Hello...

Not sure this is the right place, but this is my input:

I used Rules, Tokens and an email submitted in the entityform to send an anonymous user,
links to view and edit his entityform submission.

The email received, contained full links, but when clicked on, produced:
"Access denied
You are not authorized to access this page."

Any ideas / leads?

Thank you,
Michael.

skadu’s picture

Hi Michael,

The flow you describe is exactly what I'm doing which works perfectly. Are you sure that the entityform configuration has "Provide Anonymous Links" checked?

Also, was it actually an anonymous individual who submitted the entityform? I've found that if an admin (or anyone signed in actually) fills out a form, the anonymous links are indeed generated, but they don't work for an anonymous user, instead I get the access denied message.

~ skadu

Michael G’s picture

Thank you skadu..
- Yes, the entityform configuration has "Provide Anonymous Links" checked,
otherwise, no links are sent..
- Yes it was an anonymous individual who submitted the entityform, on a different computer,
without any authenticated user or admin logged on from that computer..
Michael.

skadu’s picture

Michael, have you actually given anonymous users the right permissions? It's not enough to just install the module. You need to give view/edit/delete (whichever ones you want) to the anonymous role on the permission page at:

  • /admin/people/permissions#module-entityform

Can you double check those permissions and let me know what you find?

~ Skadu

Michael G’s picture

You are a genius! It is working !!!
Thank you so much...
If you ever come to Israel, you have a tour to The Dead sea credit...


Michael.

skadu’s picture

Glad to you got it working! I'd love to take a tour if I ever find my way to Israel. Is that what your company does?

~ Skady

Michael G’s picture

Yes...It is caled "In Low Gear" 4x4 tours of Israel..

By the way, I am not sure it is related, but if I use the HTML Mail module instead of the Mime Mail module, I keep getting the
"Access denied
You are not authorized to access this page." message..

Thank you again,
Michael.

skadu’s picture

What pages (or what action) are you trying to access that's related to the mail modules? The entityforms? Those two things shouldn't have anything to do with each other from a permissions standpoint.

Michael G’s picture

The same one that did work finally with your advice:
I have a rule that sends an email with an "viewlink" to an anonymous entity form submitter.

email message:
test
[entityform:anonymous_submission_view_link]

If I set the system mail
Site-wide default MailSystemInterface class
to
DefaultMailSystem
rather than to
HtmlMailSystem
the email is received correctly (as I reported already), but without HTML features..

Michael.

skadu’s picture

Dealing with HTML formatting of emails is outside the scope of the entityform_anonymous module. I know that the DefaultMailSystem is plain text. So you have to take additional steps to add HTML.

It sounded like you were telling me that the link stops working if sent in plain text though? is that right? If so, it could be an encoding issue, but that's going to be real hard for me to figure out without digging into by hand, and I'm just not sure I can do that right now.

Michael G’s picture

The plain text is working excelent (thanks to you).
But don't worry about the HTML Mail module. I will keep trying myself..
Thank you, Skadu..
And my offer for Israel is an "open date" (:
Michael.

toddwoof’s picture

I see these two tokens as available:

[entityform:anonymous_submission_submit_link]
[entityform:anonymous_submission_token]

I was expecting that they would both create the same random key, but they create different keys for the same submission. Is this the expected behavior?

skadu’s picture

@toddwoof - Can you confirm that the settings for the entityform in question have the resubmit action set to edit the old submission?

From the module:

$tokens['anonymous_submission_submit_link'] = array(
    'name' => t('Anonymous Submission Submit Link'),
    'description' => t('Link to allow resubmitting anonymous submission, used when resubmit action is edit old submission.'),
  );
toddwoof’s picture

I didn't. I'll test again. Thanks!

museumboy’s picture

I don't understand how this module does anything useful.

The link I get from [entity:anonymous_submission_view_link] is http://myurl.com/entityform/2253?token=e8f7e9df9ff8e9d675af29b3618f317f&...

Great, but if I delete everything after 2253 I get the same page and in order for it to work I have to open up read access to all of my entity forms.

What's to stop someone from going through my entityform submissions? I would have no problem with allowing read access to forms if the token was required but it's not. The root http://myurl.com/entityform/2253 url is still valid. How to make the token required?

skadu’s picture

FileSize
17.06 KB

It sounds like you have granted permission for anyone to view any entityform submission. I'm using this module to handle form submissions, and the token is required to access the form submission as well as edit the form submission. Can you confirm your permissions for entityforms look something like this:

Permissions

museumboy’s picture

My apologies! I read the instructions on #20 but did not see specific directions on the correct permissions. This works! Thanks

museumboy’s picture

Authenticated users are also contributing form submissions. The anon links for these submissions don't work because of permission issues. Is there any way around this? I'd like to allow anon access to these forms regardless of which users submit them.

Thanks

museumboy’s picture

I found this line in entityform_anonymous.module
(line 108)

if (!$access && isset($entityform->uid) && $account->uid == 0 && $entityform->uid == 0) {

change to:

if (!$access && isset($entityform->uid)) {

If I delete the 2nd && of the statement I can view authenticated submissions with the anon link. As far as I can tell I don't have any other access to submissions without a valid token.

Does this open me up in an unexpected way?

skadu’s picture

If you submit an entityform while authenticated, that entityform cannot be accessed using anonymous links. The owner of that entityform is automatically assigned to the user account that created it.

I am not the author of this module nor do I claim to fully understand the security impacts of your change....

However, it seems that change will sort of open you up. It will indeed grant you access to the form created by an authenticated user if you are using the anonymous access link which it sounds like is the desired impact for you.

It means that an anonymous visitor could access the entityform of the authenticated user, which feels wrong to me.

Although, I guess it is really no different than if someone else ever gained access to any other anonymous link.