When i checkout as authenticated user there's no problem.
The bit problem is when I checkout as anonymous, all rules are triggered - New user account is created, email is sent and order is created. But when redirected from paypal's sandbox site page not found appears. Page not found
The requested page "/checkout/20/payment/return/7Lk24PDIS3LxjGoND8MdS9olNbOCLVhRSYAGph1vZtc" could not be found.
manually entered "checkout/20/complete" brings the same error as well, although that order is created in orders list. Permissions for anonymous are the same as authenticated user but authenticated users don't experience that problem? Please help i have no idea where the problem might be, any suggestion are welcomed. Thank you.

Comments

pmol123’s picture

To get around this I created a view PAGE with a PATH as follows:

checkout/%/payment/return/%

Then I added a Global Text area telling my new user to check their email.

Just a thought.

Patrick

luchoh’s picture

Subscribing

luchoh’s picture

I had this debugged and I would suggest checking the order access and particularly the session.

function commerce_checkout_router($order, $checkout_page = NULL) {

........

  // If the user does not have access to checkout the order, return a 404. We
  // could return a 403, but then the user would know they've identified a
  // potentially valid checkout URL.
  if (!commerce_checkout_access($order)) {
    return drupal_not_found();
  }
function commerce_checkout_access($order, $account = NULL) {

......


elseif (empty($_SESSION['commerce_cart_completed_orders']) ||
    !in_array($order->order_id, $_SESSION['commerce_cart_completed_orders'])) {
    // Return FALSE if the order does have a uid.
    if ($order->uid) {
      return FALSE;
    }

    // And then return FALSE if the anonymous user's session doesn't specify
    // this order ID.
    if (empty($_SESSION['commerce_cart_orders']) || !in_array($order->order_id, $_SESSION['commerce_cart_orders'])) {
      return FALSE;
    }
  }

I believe here is the problem. If the session is not properly set the function returns FALSE.

I will debug it further and keep you posted.

m4r71n’s picture

I got around this by using panels with nameholders as well. I'm sure that's not the best way to avoid this error but for now that helps. Weirdly I downloaded the site to my local pc and the error disappeared? Right now my site is on an acquia server. When i change the host I will feedback if I experience the same error.

luchoh’s picture

Well,
the $_SESSION is empty when PayPal posts the IPN result and therefore the commerce_cart_completed_orders session array is always empty.

I'm getting an empty $_SESSION array here:

function commerce_cart_order_session_exists($order_id = NULL, $completed = FALSE) {
  $key = $completed ? 'commerce_cart_completed_orders' : 'commerce_cart_orders';

	watchdog(
			'commerce_order',
			'Checking if session exists for order ID %orderid<br>
			with key: %key<br>
			Session:<br><br>
			%session',
			array('%orderid' => $order_id, '%key' => $key, '%session' => serialize($_SESSION))
	);
	
  // If an order was specified, look for it in the array.
  if (!empty($order_id)) {
    return !empty($_SESSION[$key]) && in_array($order_id, $_SESSION[$key]);
  }
  else {
    // Otherwise look for any value.
    return !empty($_SESSION[$key]);
  }
}

So what happens is Drupal checks commerce_cart_orders session array to find the existing orders, receives an empty array and never gets to save the session in function commerce_cart_order_session_save($order_id, $completed = FALSE)

The order is saved, but the session is not updated and never gets the commerce_cart_completed_orders array initialized - hence the error.

I don't have enough experience with Drupal session management to be certain what is exactly happening, but it is obvious we have a POST from a different IP address (PayPal site) than the one the cookie was originally set with.

Please comment.

luchoh’s picture

Title: Completion message problem with anonymous users only » Workaround: Completion message problem with anonymous users only

Disclaimer: This workaround is necessary if one is using the standard rules and is creating accounts and associating the orders with the latter.

Well, the workaround is quite simple:

1. In hook_menu_alter override commerce_checkout_router: $item['checkout/%commerce_order']['page callback'] = 'your_callback'

2. In your_callback:

if($order->status == 'completed' && !commerce_checkout_access($order)){
	commerce_cart_commerce_checkout_complete($order);
}
	
return commerce_checkout_router($order, $checkout_page);

Beware, in my case the status is completed, but in reality your case could be quite different.

Please advise whether the proposed workaround can have security consequences.

netsensei’s picture

I got the same problem. To me, this is a commerce problem rather then a paypal problem: #1362412: commerce_checkout_access() blocks anonymous checkout I solved this by disabling the "Create a new account for an anonymous order" and "Assign an anonymous order to a pre-existing user" rules.

no_longer_active_123’s picture

Sorry, I'm new to this. Could you please explain in more detail how to implement this workaround? Where can I find hook_menu_alter? Override means to replace the text "your_callback" with the code you provided?

Any help would be greatly appreciated.

mediapal’s picture

Any help would be greatly appreciated.

no_longer_active_123’s picture

In the end, Patrick's suggestion of creating a view for the checkout completion page worked for me. Thank you very much, Patrick.

kiwimind’s picture

I have also implemented the idea from #1, although mine isn't just generic text, I've created a view that shows the order finalised, with the items purchased. A bit more elegant.

Thanks Patrick for the idea, seemed to be the simple option.

tommy kaneko’s picture

Category: support » bug
Status: Active » Needs review
StatusFileSize
new1.36 KB

Thanks for the analysis from netsensei on #1362412: commerce_checkout_access() blocks anonymous checkout. Using that, and the patch on #946954: Make commerce_checkout_access() extensible comment #4 for Commerce, I have used the following code:

The code checks to see if the loaded order object's $order['payment_redirect_key'] and the return URL key match. Once this is matched, the user is logged in with the account that was created as part of the checkout process, and the page is loaded again, with success in my case.

NOTE: you must use the patch on #946954: Make commerce_checkout_access() extensible comment #4 for the following code to take effect

<?php
/**
 * Implements hook_commerce_checkout_access().
 */
function commerce_paypal_wps_commerce_checkout_access($order, $checkout_page) {
  // Check that the redirect key matches with the order.
  if (arg(3) == 'return' && arg(4) == $order->data['payment_redirect_key'] && $order->data['payment_method'] == 'paypal_wps|commerce_payment_paypal_wps'  ) {
    global $user;
    // If anonymous user and a user ID is set for the order,
    // automatically log the user in.
    if ($user->uid === 0 && isset($order->uid)) {
      // Log user in.
      $form_state['uid'] = $order->uid;
      user_login_submit(array(), $form_state);
      // Redirect the user after login to current page.
      global $base_url;
      drupal_goto($base_url . '/' . arg(0) . '/' . arg(1) . '/' . arg(2) . '/' . arg(3) . '/' . arg(4));
    }
  }
}
?>

Before this patch is adopted, we really need someone to assess if there are security holes in this approach. The crucial security check is in matching up the user's redirect URL with the $order['payment_redirect_key']. The anonymous user is automatically logged in without a password check on this sole security check. I believe the $order object is loaded using the $_SESSION['commerce_cart_orders'] variable. I don't know enough about commerce and Drupal 7, so I would love to hear a third opinion.

Also, this code is implemented for Paypal WPS module. It can easily be modified for using WPP too - let me know if it is needed.

alexiswatson’s picture

Title: Completion message problem with anonymous users only » Workaround: Completion message problem with anonymous users only

If created via Rules, the anonymous user's new account won't have a password to begin with: it has to be set via the one-time login process (EDIT: or manually, obviously). If we're receiving a callback that matches the order in question, we should be able to rely on $order->uid stored therein (which, again, would be reassigned via Rules to match the newly created account). So this approach looks sane from a security perspective.

My biggest concern is actually whether other hooks are prevented from firing after the drupal_goto() here, but I'll see if I can't test this when I have cycles to spare. Might take me several days at this rate, though.

alexiswatson’s picture

Title: Workaround: Completion message problem with anonymous users only » Completion message problem with anonymous users only

Changing the title to reflect the fact that we have an actual patch now.

alexiswatson’s picture

Title: Workaround: Completion message problem with anonymous users only » Completion message problem with anonymous users only
Status: Needs review » Closed (duplicate)

Original issue is fixed by the commit made in #1362412: commerce_checkout_access() blocks anonymous checkout, stripping away a redundant access check. The hook implementation above isn't necessary to allow anonymous users to access their own checkouts if the order's uid changes, but the functionality in #946954: Make commerce_checkout_access() extensible is still worthwhile if other people care to review it.