Jump to content

Cookie Key after migration and passwords cryptography


Recommended Posts

I have a question about the Cookie key and the question of password generation of the platform.

1. I currently have version 1.6.0.14, now I am upgrading to version 1.7.2.4, in a new installation / host, I know that a new key to the cookie is generated when installing this new installation, I wonder if there is any way to update the passwords of all clients according to this new cookie and not use the cookie of the old version? And if I want to change the cookie manually, is there any way to regenerate the passwords arranged in the database? I am doomed to always use the same cookie key?

2. Given the same scenario Store 1.6.0.14, the database has more than 50,000 registered customers, where the chosen encryption passwords is Rijndael with mcrypt library, the question is, if I switch to the class Blowfish adapted, how would be the behavior with the rest of the passwords of the clients already registered? Would they be regenerated with the new encryption class? Would there be an incorrect password error for all clients already in the database?

Link to comment
Share on other sites

On 1/17/2018 at 7:15 AM, DARLEI FERNANDO ZILL said:

1. I currently have version 1.6.0.14, now I am upgrading to version 1.7.2.4, in a new installation / host, I know that a new key to the cookie is generated when installing this new installation, I wonder if there is any way to update the passwords of all clients according to this new cookie and not use the cookie of the old version? And if I want to change the cookie manually, is there any way to regenerate the passwords arranged in the database? I am doomed to always use the same cookie key?

Passwords are hashed using the cookie key in a one way routine, that means that you will have no idea what the original password was, so you cannot re-hash it.  This is the code used by Prestashop, as you can see it takes the password, prepends the  cookie key to it, and then uses an md5 function to hash it
 

return md5(_COOKIE_KEY_.$passwd);
On 1/17/2018 at 7:15 AM, DARLEI FERNANDO ZILL said:

2. Given the same scenario Store 1.6.0.14, the database has more than 50,000 registered customers, where the chosen encryption passwords is Rijndael with mcrypt library, the question is, if I switch to the class Blowfish adapted, how would be the behavior with the rest of the passwords of the clients already registered? Would they be regenerated with the new encryption class? Would there be an incorrect password error for all clients already in the database?

md5 hash is used for password 'encryption', mcrypt and blowfish do not apply here

Link to comment
Share on other sites

  • 4 months later...
  • 1 year later...
On 5/29/2018 at 1:49 PM, Mahdi Shad said:

Hi

You should override prestashop to solve this problem:

if ( wrongPassWord ) {

    checkOldWay => setNewPassword

}

We did this for some of our clients after migration on store-migrations

Hi, it's a good solution.
I have had the same problem and I have solved changing directly the submit function of CustomerLoginForm.php in classes/form. (I don't know why override doesn't work)

This is the code that I have used, I leave it here for those who need it.

use PrestaShop\PrestaShop\Adapter\ServiceLocator;  /* put this at the beginning of the file */

/*then look for the function submit and replace it completely with this*/
 

    public function submit()
    {        
        if ($this->validate()) {
            Hook::exec('actionAuthenticationBefore');
           $oldkey = "xxxxxxxxxxxxxxxxxx_your old _COOKIE_KEY_xxxxxxxxxxxxxxxxxxxxxx";
            $pass_old_type = md5($oldkey . $this->getValue('password'));
            
        try {
            /** @var \PrestaShop\PrestaShop\Core\Crypto\Hashing $crypto */
            $crypto = ServiceLocator::get('\\PrestaShop\\PrestaShop\\Core\\Crypto\\Hashing');
            } catch (CoreException $e) {
                return false;
                }
                $customer = new Customer();
                $my_customer_values = $customer->getByEmail($this->getValue('email'));
                $passwordHash = $my_customer_values->passwd;
                        
            if ($pass_old_type === $passwordHash) {
                
                 $customer->passwd = $crypto->hash($this->getValue('password'), _COOKIE_KEY_);
                 $ok =  Db::getInstance()->update('customer', array( 'passwd' => $customer->passwd), '`id_customer` = '.(int)$customer->id);
            }
            
            $customer = new Customer();
            $authentication = $customer->getByEmail(
               $this->getValue('email'),
               $this->getValue('password')
            );
                    
            if (isset($authentication->active) && !$authentication->active) {
                $this->errors[''][] = $this->translator->trans('Your account isn\'t available at this time, please contact us', [], 'Shop.Notifications.Error');
            } elseif (!$authentication || !$customer->id || $customer->is_guest) {
                $this->errors[''][] = $this->translator->trans('Authentication failed.', [], 'Shop.Notifications.Error');
            } else {
                $this->context->updateCustomer($customer);

                Hook::exec('actionAuthentication', ['customer' => $this->context->customer]);

                // Login information have changed, so we check if the cart rules still apply
                CartRule::autoRemoveFromCart($this->context);
                CartRule::autoAddToCart($this->context);
            }
        }

        return !$this->hasErrors();
    }

/* end of code */

This code validates the password of the client who wants to login and if it is old it becomes new and records it in the bd.

(forgive my english)

Regards

Edited by UniArt (see edit history)
  • Like 1
Link to comment
Share on other sites

  • 7 months later...

Holà UniArt, and thanks for your contribution on this subject.

I'm migrating an old userbase from 1.3.1.1 to the latest 1.7.6.4 . Rather than upgrading, I installed the 1.7 from scratch, then I imported the customers using CSV export from this query :

SELECT 
  id_customer, 
  active, 
  case id_gender when 9 then 0 else id_gender end as gender, 
  email,
  passwd,
  birthday,
  lastname,
  firstname,
  newsletter,
  optin,
  date_add,
  '' as groups, /* I don't use groups, adapt this if you need to */
  id_default_group
FROM `ps_customer`

 

In 1.3 the ps_customer.passwd field is a simple unsalted MD5 hash of the user-given password, with no use of the COOKIE_KEY value. I've tested it against my own password. 

When importing, Prestashop assumes the password in the CSV is plain-text and hashes it with the new cryptographic function. Therefore when trying to login, we must check the given password for new users, and if it fails try with an added md5. We do this in classes/form/CustomerLoginForm.php , replacing the sumbit() function with :

 

    public function submit()
    {
        if ($this->validate()) {
            Hook::exec('actionAuthenticationBefore');

            $customer = new Customer();
            $authentication = $customer->getByEmail(
                $this->getValue('email'),
                $this->getValue('password')
            );

            // legacy method : use the md5'd password 
            if (!$authentication || !$customer->id) {
            	$authentication = $customer->getByEmail(
            		$this->getValue('email'),
            		md5($this->getValue('password'))
            	);
            }

            if (isset($authentication->active) && !$authentication->active) {
                $this->errors[''][] = $this->translator->trans('Your account isn\'t available at this time, please contact us', [], 'Shop.Notifications.Error');
            } elseif (!$authentication || !$customer->id || $customer->is_guest) {
                $this->errors[''][] = $this->translator->trans('Authentication failed.', [], 'Shop.Notifications.Error');
            } else {
                $this->context->updateCustomer($customer);

                Hook::exec('actionAuthentication', ['customer' => $this->context->customer]);

                // Login information have changed, so we check if the cart rules still apply
                CartRule::autoRemoveFromCart($this->context);
                CartRule::autoAddToCart($this->context);
            }
        }

        return !$this->hasErrors();
    }

 

 

Edited by KickMe (see edit history)
Link to comment
Share on other sites

5 hours ago, KickMe said:

Holà UniArt, and thanks for your contribution on this subject.

I'm migrating an old userbase from 1.3.1.1 to the latest 1.7.6.4 . Rather than upgrading, I installed the 1.7 from scratch, then I imported the customers using CSV export from this query :


SELECT 
  id_customer, 
  active, 
  case id_gender when 9 then 0 else id_gender end as gender, 
  email,
  passwd,
  birthday,
  lastname,
  firstname,
  newsletter,
  optin,
  date_add,
  '' as groups, /* I don't use groups, adapt this if you need to */
  id_default_group
FROM `ps_customer`

 

In 1.3 the ps_customer.passwd field is a simple unsalted MD5 hash of the user-given password, with no use of the COOKIE_KEY value. I've tested it against my own password. 

When importing, Prestashop assumes the password in the CSV is plain-text and hashes it with the new cryptographic function. Therefore when trying to login, we must check the given password for new users, and if it fails try with an added md5. We do this in classes/form/CustomerLoginForm.php , replacing the sumbit() function with :

 


    public function submit()
    {
        if ($this->validate()) {
            Hook::exec('actionAuthenticationBefore');

            $customer = new Customer();
            $authentication = $customer->getByEmail(
                $this->getValue('email'),
                $this->getValue('password')
            );

            // legacy method : use the md5'd password 
            if (!$authentication || !$customer->id) {
            	$authentication = $customer->getByEmail(
            		$this->getValue('email'),
            		md5($this->getValue('password'))
            	);
            }

            if (isset($authentication->active) && !$authentication->active) {
                $this->errors[''][] = $this->translator->trans('Your account isn\'t available at this time, please contact us', [], 'Shop.Notifications.Error');
            } elseif (!$authentication || !$customer->id || $customer->is_guest) {
                $this->errors[''][] = $this->translator->trans('Authentication failed.', [], 'Shop.Notifications.Error');
            } else {
                $this->context->updateCustomer($customer);

                Hook::exec('actionAuthentication', ['customer' => $this->context->customer]);

                // Login information have changed, so we check if the cart rules still apply
                CartRule::autoRemoveFromCart($this->context);
                CartRule::autoAddToCart($this->context);
            }
        }

        return !$this->hasErrors();
    }

 

 

Wow, what courage. From 1.3 to 1.7. Epic!!!
The solution I have provided is for cases where the two stores have different cookie keys. 
It is sloppy but it works.
And have you managed not to lose your passwords with the code above?

Link to comment
Share on other sites

One more thing, it is better to take advantage of the visit of the old client to change the password to the current system, that will make this type of intervention in the code less necessary in the next updates of prestashop.
I do it directly in the modified submit function but you can search the native prestashop function for a password change and use it to update your clients.
Another idea is for those who want to do everything "within the law" is  make a module and register it in the hook actionAuthenticationBefore.
I think the module could override the submit function inside the hook without having to override the class or make direct code changes.
I think I'll try doing it and keep my prestashop clean. 😊.

Link to comment
Share on other sites

13 hours ago, UniArt said:

Wow, what courage. From 1.3 to 1.7. Epic!!!
The solution I have provided is for cases where the two stores have different cookie keys. 
It is sloppy but it works.
And have you managed not to lose your passwords with the code above?

Thanks! It's been running like this for 10 years... The upgrade is overdue.

Old users can still use their password, that was the point. What they don't know is their actual password (hashed with the 1.7 method then stored in DB) is the MD5 hash of what they typed in the password field.

I won't bother with the module and hook system for now, it's my first week of prestashop developping and I'm trying to keep it simple. Anyway, thanks for pointing me in the right direction to solve this!

Link to comment
Share on other sites

Hello altogether,

I post in this thread since my tpoic is exaclty the same. (Just that we went from Prestashop 1.6 to 1.7. (at least not such a huge jump like KickMe ;)))

Our Presta1.6 did password hashing using just md5. The new Prestashop1.7. does it differently.

I understand I should have used the same values for cookie_key and cookie_iv as in the old version.
Didn't do that due to lack of knowledge (isn't documented anywhere, is it?)

'cookie_key' => 'newlyGeneratedUnfortunately',
'cookie_iv' => 'alsoNewlyGeneratedUnfortunately',
'new_cookie_key' => 'reallyLongNewCode',

So in the mean time the shop is running for a few months like this. With 400 newly users registered.
These can log in just fine, of course. The old users can't log in, I guess.

If I change cookie_key and cookie_iv to the former values from the old installation, can these new 400 users still log in?

What cookie keys are used for hashing passwords of new users since 1.7?

Cheers, Pat

Link to comment
Share on other sites

I just made it work as an override on a PS version 1.7.6.4.

But, it was necessary to copy the entire file, due to errors in the $context object, and I have only changed the submit function and the beginning of the file to:
 

use Symfony\Component\Translation\TranslatorInterface;
use PrestaShop\PrestaShop\Adapter\ServiceLocator;
class CustomerLoginForm extends CustomerLoginFormCore

 

Link to comment
Share on other sites

These overrides only work as long as the overriden class is not changed too much, right?

Doesn't seem so susatinable to me 😕

Why do you do the override anyway?

Isn't the functionality that md5 is checked as a second step on validation (and even overwriting the password with the new encrpytion method bycrpt) done by prestashop itself already?

Edited by PatStevens (see edit history)
Link to comment
Share on other sites

1 hour ago, PatStevens said:

These overrides only work as long as the overriden class is not changed too much, right?

Doesn't seem so susatinable to me 😕

Why do you do the override anyway?

Isn't the functionality that md5 is checked as a second step on validation (and even overwriting the password with the new encrpytion method bycrpt) done by prestashop itself already?

I have not understood your questions well.
But I answer what I think you asked me.
It is better to override than to modify the class to raw. For the override to work, the cache must be cleared. For me this has worked by copying all the code in the class.

On why to make this modification:
Updating is one thing and migrating is another.
An update preserves the cookiekey and prestashop does both checks. But in the case of migration the cookiekey is different between new and old shop. In old versions you could copy the cookiekey from one PS to another and that's it. But that no longer works in PS 1.7.

Due to many errors that appear when updating to 1.7 (really, it is not a very compatible version with old versions) many people prefer to migrate the data to a clean prestashop and with that the passwords of the clients are lost.

What we are doing is using the old cookiekey to validate old customers in a new store.

Link to comment
Share on other sites

4 hours ago, PatStevens said:

Hello altogether,

I post in this thread since my tpoic is exaclty the same. (Just that we went from Prestashop 1.6 to 1.7. (at least not such a huge jump like KickMe ;)))

Our Presta1.6 did password hashing using just md5. The new Prestashop1.7. does it differently.

I understand I should have used the same values for cookie_key and cookie_iv as in the old version.
Didn't do that due to lack of knowledge (isn't documented anywhere, is it?)


'cookie_key' => 'newlyGeneratedUnfortunately',
'cookie_iv' => 'alsoNewlyGeneratedUnfortunately',
'new_cookie_key' => 'reallyLongNewCode',

So in the mean time the shop is running for a few months like this. With 400 newly users registered.
These can log in just fine, of course. The old users can't log in, I guess.

If I change cookie_key and cookie_iv to the former values from the old installation, can these new 400 users still log in?

What cookie keys are used for hashing passwords of new users since 1.7?

Cheers, Pat

If you change it, new clients will not be able to login. I recommend you do the modification as I did or as KickMe so that the two types of clients can login.

Link to comment
Share on other sites

Hello UniArt,

You're right. So I will ask more comprehensive.

I agree that overrides are at least way better than chaning actual Prestashop Code.
But still, they are not granted to work for the next updates to come.
Especially now, where whole parts of the shop-software are under rewrite from the Prestashop Team.

You've seen yourself that you needed to make changes for your ovveride to work with Version 1.7.6.4.

I'm writing this, because I'm struggling with what I think about overrides in Presta, not to diss you :)

Guess one should probably have an automated test-suite to make sure nothing breaks after an update :)

 

Link to comment
Share on other sites

46 minutes ago, UniArt said:

If you change it, new clients will not be able to login. I recommend you do the modification as I did or as KickMe so that the two types of clients can login.

The way I understand it, new clients that get their password hashed by bcrypt shouldn't have any problems, as I understand the code in:

src/Core/Crypto/Hashing.php

private function initHashMethods()
    {
        $this->hashMethods = array(
            'bcrypt' => array(
                'option' => array(),
                'hash' => function ($passwd, $staticSalt, $option) {
                    return password_hash($passwd, PASSWORD_BCRYPT);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return password_verify($passwd, $hash);
                },
            ),
            'md5' => array(
                'option' => array(),
                'hash' => function ($passwd, $staticSalt, $option) {
                    return md5($staticSalt . $passwd);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return md5($staticSalt . $passwd) === $hash;
                },
            ),
        );
    }

 

The closures (see bcrpyt) for 'init' and 'verify' don't make any use of $staticSalt (which is the COOKIE_KEY passed in).
Only the second hashMethod 'md5' makes use of the COOKIE_KEY.

Or am I getting something wrong?

I just tested it on my installation and suddenly old users could log in again, while newly created users still can.

I'm on 1.7.6.2

Edited by PatStevens
typos (see edit history)
Link to comment
Share on other sites

6 hours ago, PatStevens said:

The way I understand it, new clients that get their password hashed by bcrypt shouldn't have any problems, as I understand the code in:

src/Core/Crypto/Hashing.php


private function initHashMethods()
    {
        $this->hashMethods = array(
            'bcrypt' => array(
                'option' => array(),
                'hash' => function ($passwd, $staticSalt, $option) {
                    return password_hash($passwd, PASSWORD_BCRYPT);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return password_verify($passwd, $hash);
                },
            ),
            'md5' => array(
                'option' => array(),
                'hash' => function ($passwd, $staticSalt, $option) {
                    return md5($staticSalt . $passwd);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return md5($staticSalt . $passwd) === $hash;
                },
            ),
        );
    }

 

The closures (see bcrpyt) for 'init' and 'verify' don't make any use of $staticSalt (which is the COOKIE_KEY passed in).
Only the second hashMethod 'md5' makes use of the COOKIE_KEY.

Or am I getting something wrong?

I just tested it on my installation and suddenly old users could log in again, while newly created users still can.

I'm on 1.7.6.2

Man, yes it works, I just did it in PS 1.7.6.0 and it doesn't interfere with other things. ( I think so).  🤗🤩. Tomorrow I will try on PS1.7.6.4.

I had not gone any further and thought that new customers would use the cookiekey as $salt when hashing the password.

Imagine that I started to whork in this "roll up" because a year ago there was no official documentation on this and even some moderators convince store owners that "...In case of migrating working passwords of customers between ps in version 1.6 to ps in version 1.7 is much more complicated. In this case it is required to change the way of how correctness of password is checked in prestashop 1.7. This requires core code changes.... "(textual words) since it is only necessary to change two lines of code. I feel deceived by those who hide the truth to sell modules.

Thanks for open my eyes 😁. And forgive me for not understanding English very well.

Link to comment
Share on other sites

  • 1 year later...
On 4/23/2020 at 3:15 AM, UniArt said:

Man, yes it works, I just did it in PS 1.7.6.0 and it doesn't interfere with other things. ( I think so).  🤗🤩. Tomorrow I will try on PS1.7.6.4.

I had not gone any further and thought that new customers would use the cookiekey as $salt when hashing the password.

Imagine that I started to whork in this "roll up" because a year ago there was no official documentation on this and even some moderators convince store owners that "...In case of migrating working passwords of customers between ps in version 1.6 to ps in version 1.7 is much more complicated. In this case it is required to change the way of how correctness of password is checked in prestashop 1.7. This requires core code changes.... "(textual words) since it is only necessary to change two lines of code. I feel deceived by those who hide the truth to sell modules.

Thanks for open my eyes 😁. And forgive me for not understanding English very well.

Hi 

Finally what can I for the  customers do not lose the old password?  

Prestashop 1.6 to 1.7 

which code can solve this problem?

Thank you

Link to comment
Share on other sites

On 4/22/2020 at 7:39 PM, PatStevens said:

The way I understand it, new clients that get their password hashed by bcrypt shouldn't have any problems, as I understand the code in:

src/Core/Crypto/Hashing.php


private function initHashMethods()
    {
        $this->hashMethods = array(
            'bcrypt' => array(
                'option' => array(),
                'hash' => function ($passwd, $staticSalt, $option) {
                    return password_hash($passwd, PASSWORD_BCRYPT);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return password_verify($passwd, $hash);
                },
            ),
            'md5' => array(
                'option' => array(),
                'hash' => function ($passwd, $staticSalt, $option) {
                    return md5($staticSalt . $passwd);
                },
                'verify' => function ($passwd, $hash, $staticSalt) {
                    return md5($staticSalt . $passwd) === $hash;
                },
            ),
        );
    }

 

The closures (see bcrpyt) for 'init' and 'verify' don't make any use of $staticSalt (which is the COOKIE_KEY passed in).
Only the second hashMethod 'md5' makes use of the COOKIE_KEY.

Or am I getting something wrong?

I just tested it on my installation and suddenly old users could log in again, while newly created users still can.

I'm on 1.7.6.2

Hi 

Finally what can I for the  customers do not lose the old password?  

Prestashop 1.6 to 1.7 

which code can solve this problem?

Thank you

Link to comment
Share on other sites

On 1/17/2018 at 2:15 PM, DARLEI FERNANDO ZILL said:

I have a question about the Cookie key and the question of password generation of the platform.

1. I currently have version 1.6.0.14, now I am upgrading to version 1.7.2.4, in a new installation / host, I know that a new key to the cookie is generated when installing this new installation, I wonder if there is any way to update the passwords of all clients according to this new cookie and not use the cookie of the old version? And if I want to change the cookie manually, is there any way to regenerate the passwords arranged in the database? I am doomed to always use the same cookie key?

2. Given the same scenario Store 1.6.0.14, the database has more than 50,000 registered customers, where the chosen encryption passwords is Rijndael with mcrypt library, the question is, if I switch to the class Blowfish adapted, how would be the behavior with the rest of the passwords of the clients already registered? Would they be regenerated with the new encryption class? Would there be an incorrect password error for all clients already in the database?

Hi 

Have you got a solution.

I have the same problem!!

Link to comment
Share on other sites

  • 1 year later...
On 4/20/2020 at 6:05 PM, KickMe said:

Holà UniArt, and thanks for your contribution on this subject.

I'm migrating an old userbase from 1.3.1.1 to the latest 1.7.6.4 . Rather than upgrading, I installed the 1.7 from scratch, then I imported the customers using CSV export from this query :

SELECT 
  id_customer, 
  active, 
  case id_gender when 9 then 0 else id_gender end as gender, 
  email,
  passwd,
  birthday,
  lastname,
  firstname,
  newsletter,
  optin,
  date_add,
  '' as groups, /* I don't use groups, adapt this if you need to */
  id_default_group
FROM `ps_customer`

 

Thank you KickMe for your contribution. Using your idea, I was able to migrate old userbase from 1.5.x to the latest 1.7.8.x. The trick was, in the 1.5.x database the COOKIE_KEY was used as salt, so no plain md5 hashes in the DB. So I did the following:

1. From 1.5.x php files, extracted the key from config\settings.inc.php :

define('_COOKIE_KEY_', 'XYZ');

2. In prestashop 1.7, changed classes/form/CustomerLoginForm.php, replacing the sumbit() function with :

    public function submit()
    {
        if ($this->validate()) {
            Hook::exec('actionAuthenticationBefore');

            $customer = new Customer();
            $authentication = $customer->getByEmail(
                $this->getValue('email'),
                $this->getValue('password')
            );
            
            //change for prestashop 1.5.x passwords, using COOKIE_KEY XYZ
            if (!$authentication || !$customer->id) {
        	$authentication = $customer->getByEmail(
        	    $this->getValue('email'),
        	    md5('XYZ'.$this->getValue('password'))
        	);
            }

            if (isset($authentication->active) && !$authentication->active) {
                $this->errors[''][] = $this->translator->trans('Your account isn\'t available at this time, please contact us', [], 'Shop.Notifications.Error');
            } elseif (!$authentication || !$customer->id || $customer->is_guest) {
                $this->errors[''][] = $this->translator->trans('Authentication failed.', [], 'Shop.Notifications.Error');
            } else {
                $this->context->updateCustomer($customer);

                Hook::exec('actionAuthentication', ['customer' => $this->context->customer]);

                // Login information have changed, so we check if the cart rules still apply
                CartRule::autoRemoveFromCart($this->context);
                CartRule::autoAddToCart($this->context);
            }
        }

        return !$this->hasErrors();
    }

3. Extracted the customer data to CSV using your select, and imported it using Prestashop backend 

4. Additionaly, I did the same with customer addresses, using following SQL:

SELECT 
  id_address,
  alias,
  psa.active,
  email,
  psc.id_customer, 
  phone,
  phone_mobile,
  psa.company,
  psa.lastname,
  psa.firstname,
  address1,
  address2,
  postcode,
  city,
  psa.id_country,
  vat_number,
  other
FROM ps_address psa, ps_customer psc where 
psc.id_customer = psa.id_customer and psa.deleted = 0 and is_guest = 0 and psc.deleted = 0

I'm keeping this here for reference, maybe it will help somebody.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...