Customer - account and password confusion

bobmeetinbobmeetin Member
in Help edited January 2015
I'm trying to get a demo shop working, www.dottedi.us/foxycart (aka https://dottedi.foxycart.com/cart) with single sign on. To keep things single, eliminate variables, in foxycart administration 'STORE/advanced' I chose the customer password hash type as "MD5 Unsalted (not recommended).

Back on my demo website I set up a simple password creation mechanism for new accounts like this:

<?php
$password = addslashes($_POST["password"]);
$encrypted_password = md5($password);

$query = "insert into sp_users
( fname, lname, username, email, password )
values
('$fname','$lname','$username','$email','$encrypted_password')
";
?>

The md5 password looks like: "05051dad8ad9ea621e2ef671c9ea18ad" and works perfectly on my website. However going through SSO once I get redirected back to foxycart to the https://dottedi.foxycart.com/checkout?fc_auth_token= page, I enter the email address of the customer (from my website) and it foxycart indicates the account exists and opens the password field.

Logging in fails, however. I also try logging in as that customer at https://admin.foxycart.com/admin.php and that fails too. Where is the password disconnect?
Tagged:
Comments
  • fc_adamfc_adam FoxyCart Team
    edited January 2015
    @bobmeetin,

    To have that same login work on the FoxyCart side - you'll need to use the API to communicate the customers password and add it against the customers account within FoxyCart.

    In terms of SSO though - if you're trying to have the customer automatically logged in - you will need to ensure you're passing through the correct auth_token and customer_id, as if passed correctly, the customer will be automatically logged in and won't need to specify a password or email. More details on setting up SSO completely at http://wiki.foxycart.com/static/redirect/sso

    I also try logging in as that customer at https://admin.foxycart.com/admin.php and that fails too.

    The FoxyCart administration is completely separate from your own store - customers won't ever interact with the FoxyCart administration, that's just for store owners to manage their stores.
  • I have been working on this for several days trying to get both single sign on and the API working. I have a separate open ticket, https://forum.foxycart.com/discussion/8982/setting-up-sso-redirect-back-to-cart#Item_7, where I've been working through this.

    If I turn on var_dump($foxyResponse) I see the following:

    object(SimpleXMLElement)#1 (36) {
    ["store_version"]=>
    string(3) "2.0"
    ["result"]=>
    string(7) "SUCCESS"
    ["messages"]=>
    object(SimpleXMLElement)#2 (1) {
    ["message"]=>
    string(16) "Customer Updated"
    }
    ["customer_id"]=>
    string(8) "16999999"
    ["last_modified_date"]=>
    string(19) "2015-01-06 01:57:51"
    ["customer_first_name"]=>
    string(2) "So"
    ["customer_last_name"]=>
    string(4) "What"
    ["customer_company"]=>
    object(SimpleXMLElement)#3 (0) {
    }
    ["customer_address1"]=>
    object(SimpleXMLElement)#4 (0) {
    }
    ["customer_address2"]=>
    object(SimpleXMLElement)#5 (0) {
    }
    ["customer_city"]=>
    object(SimpleXMLElement)#6 (0) {
    }
    ["customer_state"]=>
    object(SimpleXMLElement)#7 (0) {
    }
    ["customer_postal_code"]=>
    object(SimpleXMLElement)#8 (0) {
    }
    ["customer_country"]=>
    object(SimpleXMLElement)#9 (0) {
    }
    ["customer_phone"]=>
    object(SimpleXMLElement)#10 (0) {
    }
    ["customer_email"]=>
    string(18) "sowhat@dottedi.biz"
    ["shipping_first_name"]=>
    string(2) "So"
    ["shipping_last_name"]=>
    string(4) "What"
    ["shipping_company"]=>
    object(SimpleXMLElement)#11 (0) {
    }
    ["shipping_address1"]=>
    object(SimpleXMLElement)#12 (0) {
    }
    ["shipping_address2"]=>
    object(SimpleXMLElement)#13 (0) {
    }
    ["shipping_city"]=>
    object(SimpleXMLElement)#14 (0) {
    }
    ["shipping_state"]=>
    object(SimpleXMLElement)#15 (0) {
    }
    ["shipping_postal_code"]=>
    object(SimpleXMLElement)#16 (0) {
    }
    ["shipping_country"]=>
    object(SimpleXMLElement)#17 (0) {
    }
    ["shipping_phone"]=>
    object(SimpleXMLElement)#18 (0) {
    }
    ["customer_password"]=>
    string(32) "c0e5ede91449541ac217ba0fbdc57510"
    ["customer_password_salt"]=>
    object(SimpleXMLElement)#19 (0) {
    }
    ["customer_password_hash_type"]=>
    string(3) "md5"
    ["customer_password_hash_config"]=>
    object(SimpleXMLElement)#20 (0) {
    }
    ["cc_type"]=>
    object(SimpleXMLElement)#21 (0) {
    }
    ["cc_number_masked"]=>
    object(SimpleXMLElement)#22 (0) {
    }
    ["cc_exp_month"]=>
    object(SimpleXMLElement)#23 (0) {
    }
    ["cc_exp_year"]=>
    object(SimpleXMLElement)#24 (0) {
    }
    ["shipto_addresses"]=>
    object(SimpleXMLElement)#25 (0) {
    }
    ["attributes"]=>
    object(SimpleXMLElement)#26 (0) {
    }
    }

    I'm far from an expert at interpreting this stuff (more of a novice) but it seems to indicate that the name, email, and md5 password should be working. However, if I turn off the response and re-enable the redirect, although the user is created or updated, the password is not matching.

    The foxycart response shows the encrypted password of "c0e5ede91449541ac217ba0fbdc57510" whereas the encrypted password stored in my database is "05051dad8ad9ea621e2ef671c9ea18ad".

    What do we need to do to get the passwords in sync? If the simple md5($password) method is the issue, how do I fix it?

  • I think I see where this is getting screwed up but don't understand how to make it work. Your default code I am using for single sign on has this line:

    $foxyData["customer_password"] = "my new password";

    which I changed to:

    $foxyData["customer_password"] = "$my_password";

    $my_password is the result of the md5 encrypted password stored in my database. I am guessing that foxycart is doing an md5 encryption on the already encrypted $my_password rather than passing it is as. I just set up a new account and confirmed this.

    The plain text password of:
    05051dad8ad9ea621e2ef671c9ea18ad
    corresponds to:
    c0e5ede91449541ac217ba0fbdc57510

    I verifield this password as sowhat" by adding:

    $my_password = "sowhat";
    $foxyData["customer_password"] = "$my_password";

    and testing going through the checkout.

    But of course this would be foolish as I would have to store passwords in plain text in my system.

    What is the way to make this work properly?
  • fc_adamfc_adam FoxyCart Team
    edited January 2015
    @bobmeetin,

    "customer_password" is as you noted hashed on the FoxyCart side - so you only specify the raw password in that field if you have it. If you've already hashed the password on your side, you would instead specify the hashed password as "customer_password_hash", and don't provide any "customer_password" value. That's the best approach as then you're not having to be handling raw passwords.

    Something to note - the "default code" you've referenced there isn't an example for SSO - but rather just a simple example of one way you can interface with our API. The SSO code example is available here: https://wiki.foxycart.com/integration/php/shared_authentication_example
  • I've spent a lot of time trying to sort this out and seem to be getting more and more confused. The goal seems to be to get single sign on to work in conjunction with the API. I'm a low-level programmer, do lots of php/mysql but no API stuff nothing like this. Currently I have a client that I have set up still in test mode with another system. I built a membership/registration system which works with PayPal. We can live with paypal if push comes to shove. If I am able to work this out then we have a choice.

    How it currently works:
    1) Visitor selects a membership package
    2) This passes the visitor to a customer info page where we collect name, address, username, password, memberhip info, etc.
    3) Completing this successfully passes the member to a paypal iframe type page where he/she pays.
    4) This talks to paypal. paypal responds. I spent days with paypal support getting this to work.
    5) Upon successful response the customer's username and membership are authorized and he/she can sign in to view membership content.

    I don't necessarily need to follow the same sequence here, but the same goal. We maintain the registration system, password reset, etc onsite. Give me some direction.

    How does Whisper work. It says you must select a recipient but there is no where to select or enter a name.
  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    To whisper, you enter the forum username you want to whisper to in the text input that appears when you check the "Whisper" checkbox. It appears just below the checkbox.

    Without seeing exactly how you've got it set up - I think you could actually get away with collecting all of the customer information from the checkout, and not need to collect that on a separate page. You can define any number of custom fields you need on the checkout to require more information from the customer. All of this information is then included in the XML datafeed so you can perform tasks with that information after the customer completes the purchase. It's also visible in the administration reports and through the API.

    If you're allowing memberships for your site that people can purchase - you're right that you'd want to integrate SSO with your store to keep everything in sync. That works in a few different ways depending on where the information is coming from.

    From your site it generally works like this - the customer will add a product to the cart and then proceed to the checkout. SSO hits your endpoint right before sending the customer to the checkout.
    * At this endpoint - you first check if a customer is logged in on your site. If noone is logged in - you can either send them to the checkout as a guest, or send them to a login form to force them to be logged in on your site.
    * If someone is logged in, and but you don't know their FoxyCart customer ID - then you can use the API to query that. You can first perform a customer_get to see if the customer exists on FoxyCart. If it does, then you can grab the customer ID there, but if not, you can perform a customer_save action based on the information you know, and then get the customer ID from the return of that.
    * With the customer ID, you then create the required parameters to send on to the checkout for SSO to finish off. Check the SSO details for what they are and how you create them: http://wiki.foxycart.com/static/redirect/sso

    Also from your site - if you allow customers to login on your side and make changes to their password - you'll want to trigger an API call to also update the password on your FoxyCart store to keep it in sync.

    From the FoxyCart side - the customer may trigger a password reset from the checkout if they logged in there, or created an account if you sent them through as a guest. To synchronise that to your own website, you would process the XML datafeed (http://wiki.foxycart.com/static/redirect/xml_datafeed) and update/create a user on your side based on the information in the datafeed.

    I hope that gives you a good overview of how it all comes together. For more details, take a look at the SSO wiki page I linked to earlier.
  • an inch closer ...

    With the clue on the password hash, customer_password_hash I now have the password working. I am working on this from the direction of username/password/email/uid will be created on my site then via SSO/API will update foxycart. However, I'm still missing something with SSO as when the customer gets redirected back to checkout via a URL like the following:

    https://dottedi.foxycart.com/checkout?fc_auth_token=0ed369f567bd2709e5be68aff0b01b31fd8a01fd&fc_customer_id=3×tamp=1420617400&fcsid=32a1vci4r4mg1lv2gk6fmm3im4

    the customer is not logged in. If I enable OrderDesk I can see the customer name, but a different, long $customer_id in OD.

    your_email.png

    The $customer_id that is going into the URL is the $id from my database, 3,4,5 etc... rather than the new or updated fc_customer_id, i.e.

    fc_customer_id=17013871

    So, whether it is a new customer or updated, how do I pull the fc_customer_id so that I can push it into the full_redirect URL? It seems that we need to make a callback to foxycart to obtain this value.

    The FAQ reads, "The customer ID must match the FoxyCart customer ID, as retrieved in the XML datafeed or API. This isn't (usually) the ID of the customer in your database."

    What do I add to this file to get this via the API?
  • https://wiki.foxycart.com/v/2.0/api - The FAQ lists an option, customer_get (with customer_email) but does not provide an example of how to employ the method to obtain the $customer_id to that I can subsequently pass the ID in the $full_redirect URL.

    I also see the command line curl example which works for testing and returns a whole acket of information including the id.
  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    You would need to perform the customer_get API call, and then get the customer_id value from the returned values. If you're synchronising customers with your own database as well - I'd definitely recommend storing the FoxyCart customer_id value against the user on your end as well. That would save having to perform an API request within your SSO endpoint as it would be already available to you.

    You can do that in two ways. Firstly - when creating a customer on your side, you could create one within your FoxyCart store as well using the API, and get the customer_id value from the response of the customer_save and add it to your database. You can also get the customer_id as part of the XML datafeed webhook - and update your customer record with their customer_id then as well.
  • I understand that I need to do the API call but I don't understanding the code/syntax to make that work. I tried a bunch of things yesterday with no success.
  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    Sure thing. So taking the example from the bottom of the API page here: https://wiki.foxycart.com/v/2.0/api - you'll need to adjust the variables at the top to set the action to "customer_get", and instead of passing the "customer_id" and "customer_password", just pass the "customer_email".

    If you run that example script as it is - that will output the response from the call - which will look essentially like the example output at the top of the API page.

    To then access the customer_id value, you would add the following line:
    $customer_id = (string)$foxyResponse->customer_id;
    

    That will set the customer_id value into the attribute of the same name. You could also ensure that a customer was returned by doing an if statement like this:
    if ((string)$foxyResponse->result == "SUCCESS") {
      // customer was found
    }
    
  • This now works. I had tried some things similar in nature to what you sent but not similar enough. I added this code after the initial API call that creates or updates the customer.

    $foxyData = array();
    $foxyData["api_action"] = "customer_get";
    $foxyData["api_token"] = "$foxycart_api_key";
    $foxyData["customer_email"] = "$my_email";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://"; . $foxycart_domain . "/api");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $foxyData);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    curl_setopt($ch, CURLOPT_TIMEOUT, 15);
    $response = trim(curl_exec($ch));
    $foxyResponse = simplexml_load_string($response, NULL, LIBXML_NOCDATA);

    $customer_id = (string)$foxyResponse->customer_id;
    $return_hash = sha1($customer_id . '|' . $timestamp . '|' . $foxycart_api_key);
    $full_redirect = $foxycart_redirect_url . $return_hash . '&fc_customer_id=' . $customer_id . '×tamp=' . $timestamp . '&fcsid=' . $fcsid;

    This now transparently (after 3-5 seconds) sends the newly created or recently updated customer to foxycart checkout as a signed in customer. With the $customer_id in hand I can store it locally if it helps, good.

    In my initial discussions before the forum someone emailed me a link where the customer could sign in as update their profile, at least that is what I understood. If I chose to go that route, what is the link, or is that only possible with orderdesk? If so, what is the customer orderdesk link?
  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    I'm not sure if there is a link within OrderDesk to facilitate that - that would be a question for @sparkweb. For the FoxyCart side - you can send the customer to yourstore.foxycart.com/cart?cart=updateinfo - and they can login to the checkout and update their address and payment information.

    Just as a quick aside - within your SSO endpoint I'd recommend only performing the API call if you have to. The main reason is the API call adds a delay to the SSO process - so if you can avoid having to make the call, then the process will be all the more quicker for customers proceeding to the checkout. That essentially relies on storing the customer_id on your end - and then only making the API call if the customer doesn't have that value stored on your end.
  • sparkwebsparkweb Member, Integration Developer, FoxyShop, Order Desk
    Just to chime in briefly here, Order Desk doesn't have any public user logins -- it's a backend tool for your business ops. Just wanted to clarify that. :)
  • I am currently using simple md5 to encrypt a password as:

    $encrypted_password = md5($password);

    It's time to make this a little more secure. In the advanced shop config you list some password options including "md5 salted (suffix)" with a default value of 16. What is the PHP routine I would use to create the salted password based upon 16?

  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    Increasing your password hashing method is definitely a good idea - I'd recommend going further than md5 salted though, it's not really that much better than md5 unsalted. I'd recommend SHA256 as a good place to step up to. For more information on the different hashing methods, see this page: http://wiki.foxycart.com/static/redirect/customers

    For implementation in your chosen language - a quick google search should give you some good examples.

    One other consideration when selecting a password hashing method, if you're using a system for your site, that may have some requirements in what algorithm you use.
  • I've been all over that page and I saw the sha256 salted suffix option which I've used in the past. What I'm not clear on is how the number variable enters into the password routine, whether it is a default of 16 for md5 or 48 for sha256.

    I need to see an example of how the password is created and a sample password output.
  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    In the case of SHA256 - the password configuration value (defaulting to 48) is the length of the random salt. You simply need to create a random salt value of the specified length, and append that to your password when hashing it with SHA256. To synchronise the password to FoxyCart, you would communicate it via the API with the hashed password as customer_password_hash and the 48 character salt value as customer_password_salt.
  • I did a lot of googling, but didn't find the right clue as to how to create a 48 character salt. This is not obvious to me.
  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    A salt is essentially a random set of bytes. In terms of a good way to create one, perhaps take a look at this page: http://stackoverflow.com/questions/2235434/how-to-generate-a-random-long-salt-for-use-in-hashing
  • The problem I'm having with this is that there may be millions of methods of generating a 16, 32, 48 etc character salt string. I choose one method to manage passwords in my local database but you have another 'foxycart standard' method you use to create/update passwords in your system.

    If the method I adopt does not synchronize with your standard then it will never work. I plan to use the API as I am not to sync the $customer_password_hash string between systems.

    So that uploads my version of the salted password to your system, but since your system employs a different method I assume that when the customer gets redirected to checkout that it will fail to autopopulate and the customer will be prompted for his/her password which will not work. If a new customer he/she will be re-prompted to enter their customer data which probably includes the foxycart password scheme.
  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    Actually - it doesn't matter if we generate salts in a different way to you as long as they end up with the correct length. If you create the hashed password on your side, you would upload the hashed password and the salt using the API to synchronise the logins. If the customer then logs in directly on the FoxyCart checkout, we would use the salt you've added using the API to validate the customers password. As we'd be using the same salt that you used, then there shouldn't be any issues with the customer being able to login.

    The important thing is that you generate the hashed password in the same way - and we show how we generate that on the customers page I linked to earlier. If you synchronise the salt you used when generating the hashed password - everything should work just fine.

    Does that help clarify things for you?
  • I created a new password function locally, matching the sha256 method on foxycart, and it worked, or at least it seems to be working. I logged out and in went through the cart and it autopopulated correctly. I also created a new user and that worked as well.

    However, on the now populated checkout page, I see some odd stuff. t the top of page is the green box which says:

    me@myemail.com

    You are already logged in. If you'd like to complete this transaction as a different user please logout and try again.


    Yet there is no link on the page to perform this action which in my case I don't want to happen anyhow, so the message is baffling, incorrect.

    your_email.png

    In addition to default cc payment I enabled paypal to see how it would work. Clicking on the PayPal payment option reveal some incomplete page stuff, including no button to complete the transaction on paypal.

    paypal1.png

    The second image represents what I see after clicking on PayPal

    paypal2.png

    The third oddball behavior I see is if I attempt to send the customer to the page,
    https://dottedi.foxycart.com/cart?cart=updateinfo
    which gets redirected to something like:
    https://dottedi.foxycart.com/checkout?fc_auth_token=d173ffed39179d09158bc458f5eea2f5b971e167&fc_customer_id=16968757×tamp=1421127096&fcsid=rq31vq08dn23ei3b2u3n6qo7l5

    Again, I'm probably not going to have customers update passwords through this route, but I understood that this was how it was supposed to happen.

    update_my_information.png

    There are fields to update billing information but no fields to update the password.
  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    Could you whisper us a username/password we could use to test out the SSO on your site? The two example logins on your SSO page aren't working for us.

    I'd love to confirm what you're seeing before responding to your post here.
  • When I was working on the password function yesterday I reset the test accounts numerous times, forgot. I just updated both to the defaults as noted on the signin page. Alternately you could use the Register link and create a new account. www/dottedi.us/foxycart/signin.php / www.dottedi.us/foxycart/register.php .
  • fc_adamfc_adam FoxyCart Team
    @bobmeetin,

    Sorry for the delay in getting back to you here.

    1) The language string there is confusing, you're right. As the customer was logged into the checkout automatically with SSO, they will need to actually return back to the website and log out of their session there and login as a new user. You can edit that language string displayed within the 'language' section of your store's FoxyCart administration to make that clearer. You'll find the "sso already logged in" language string within the "checkout" grouping.

    2) This looks to be caused because of the inclusion of the loader.js file on your checkout. That file doesn't need to be included on any of the FoxyCart based templates - so not on the cart, checkout or receipt templates. That file is just for inclusion on your own website. If you remove that it should start working fine. As an aside, you can also remove the "styles.css" stylesheet above loader.js - that's a stylesheet for previous versions of FoxyCart, so won't load for 2.0

    3) That is the expected behaviour in this situation. As the customer has logged in with SSO - the ability to change the password isn't presented on the checkout. The assumption is that as the customer was logged in with SSO, that the site that the user session came from is also managing the user's password management. If you'd like to allow users to change their password from the FoxyCart checkout, if you forward them to the checkout as a guest (and not auto-logged in with SSO), once they login there they will have the opportunity to change their password.

    I hope that helps!
  • It takes quite some effort to sort out the expected behavior which commonly seems not to be genuinely visitor-expected behavior. Something gets lost in the translation when you create your own beaten path.
Sign In or Register to comment.