I just noticed magento enterprise and community both edition uses different algorithms for storing password. I know community edition uses md5. Can anyone tell me which mechanism is used in enterprise edition and how can we decrypt enterprise password if we want to migrate to community edition?
I think it's on your app/etc/local.xml or app/etc/enterprise.xml on Magento EE
The Decrypt function On Magento Enterprise Edition
/**
* Decrypt a string
*
* #param string $data
* #return string
*/
public function decrypt($data)
{
return str_replace("\x0", '', trim($this->_getCrypt()->decrypt(base64_decode((string)$data))));
}
and
/**
* Instantiate crypt model
*
* #param string $key
* #return Varien_Crypt_Mcrypt
*/
protected function _getCrypt($key = null)
{
if (!$this->_crypt) {
if (null === $key) {
$key = (string)Mage::getConfig()->getNode('global/crypt/key');
}
$this->_crypt = Varien_Crypt::factory()->init($key);
}
return $this->_crypt;
}
it seems like the same function on Enterprise Edition or Community Edition.
You should ask the cript key to Magento Enterprise Edition's Owner and decrypt it with CE. It would be fine because i'm sneaking to Magento Enterprise Edition's Code and the code is the same with Community Edition (for encryption/decryption)
added after comment 1:
/**
* Hash a string
*
* #param string $data
* #return string
*/
public function hash($data)
{
return md5($data);
}
/**
* Validate hash against hashing method (with or without salt)
*
* #param string $password
* #param string $hash
* #return bool
* #throws Exception
*/
public function validateHash($password, $hash)
{
$hashArr = explode(':', $hash);
switch (count($hashArr)) {
case 1:
return $this->hash($password) === $hash;
case 2:
return $this->hash($hashArr[1] . $password) === $hashArr[0];
}
Mage::throwException('Invalid hash.');
}
Hashes are one way encryption. You're not supposed to be able to decrypt the password.
Basic operations for passwords:
The customer signs up for an account and enters a password. The system adds a salt, encrypts the password and stores the resulting password hash in the database.
The customer logs in, enters the password. The system adds a salt, encrypts the password and compares the generated password hash with the stored password hash. When the hashes are equal, the login system knows the customer knows the password without actually knowing the password itself.
So, if one system uses SHA1 and another uses old, expired MD5, the only way you can get the password back into the system is to have the customer reenter the password so the new hash algorithm gets invoked and the new hash gets stored.
You have the Enterprise source code, write a module that uses the Enterprise hashing function to store and compare the passwords and you'll have CE with an updated, security enhanced method to store passwords and should be able to bring the password hashes over from the old site.
Some additional information:
The encryption method used is found in the Mage_Core_Model_Encryption class.
Three functions of interest are:
public function hash($data)
public function getHash($password, $salt = false)
public function validateHash($password, $hash)
Function Code From 1.7.x.x
>
public function hash($data)
{
return md5($data);
}
>
public function getHash($password, $salt = false)
{
if (is_integer($salt)) {
$salt = $this->_helper->getRandomString($salt);
}
return $salt === false ? $this->hash($password) : $this->hash($salt . $password) . ':' . $salt;
}
>
public function validateHash($password, $hash)
{
$hashArr = explode(':', $hash);
switch (count($hashArr)) {
case 1:
return $this->hash($password) === $hash;
case 2:
return $this->hash($hashArr[1] . $password) === $hashArr[0];
}
Mage::throwException('Invalid hash.');
}
It appears that both CE and Enterprise use the same routines, you will have to check that out as you have the Enterprise code.
Changing the Encryption Key in your app/etc/local.xml file to match the key in your Enterprise version and then importing the Enterprise data into the CE datapbase will allow access to encrypted data. Passwords, though are stored as hashes (see above function blocks) and non-reversible due to that. The pertinent section in local.xml where the encryption key is stored:
<crypt>
<key>< ![CDATA[-encryption-key-here-]]></key>
</crypt>
We also moved to a different system with a different password algorithm. What we did was indeed like Fiasco suggests:
-> write a custom module that overwrites Magento_Core_Model_Encryption and change the hash function to match the algorithm of the encrypted passwords.
In your module config:
<global>
<helpers>
<core>
<encryption_model>MyCompany_Module_Model_Encryption</encryption_model>
</core>
</helpers>
</global>
I have done a successful migration from Magento Enterprise to Magento Community in the past. If the passwords are salted you will not be able to decrypt them to use them for Magento Community.
Your best option is to send out a mass newsletter saying people have to change their password OR auto generate a password for each customer and send it to them.
They should both use MD5.
Perhaps one has salt and one doesn't - but it will be backwards compatible.
Related
Lets say in my lang/en/general.php there are multiple translation lines for example:
"token" => "This password reset token is invalid.",
"sent" => "Password reminder sent!",
"reset" => "Password has been reset!",
But in my lang/de/general.php these lines are missing.
So later, when I use the Lang::get('general.token') or simply trans('general.token')
The english version will return
This password reset token is invalid.
And the german (de) version will return
general.token
Is there any way I can handle a 'translation not found' function, like a filter but not creating a special class for it? For example, when a line has no translation, I want to throw an Exception.
Thanks in advance!
In Laravel 4 only, you can use Lang::has() as below, here is the doc
if (\Lang::has('general.token')) {
// line exists.
} else {
// line not exist.
}
In current Laravel versions you can just use trans helper like so:
#if (trans()->has('general.token'))
{{ trans('general.token') }}
#endif
This question is getting a little bit old but as per version 5.8 you can simply check as this :
array_key_exists('your-word-key', trans('your-file'))
or
array_key_exists('your-word-key', trans('your-file.array_key'))
for nested translations
You might want to write a helper similar to the one below to help with fallbacks:
/**
* Makes translation fall back to specified value if definition does not exist
*
* #param string $key
* #param null|string $fallback
* #param null|string $locale
* #param array|null $replace
*
* #return array|\Illuminate\Contracts\Translation\Translator|null|string
*/
function trans_fb(string $key, ?string $fallback = null, ?string $locale = null, ?array $replace = [])
{
if (\Illuminate\Support\Facades\Lang::has($key, $locale)) {
return trans($key, $replace, $locale);
}
return $fallback;
}
Note: The helper only works on PHP 7.1 (which has support nullable types). Adjust it to your PHP version if it's lower than 7.1.
You can create your own TranslationServiceProvider and Translator and override the get() method in translator to throw an exception when the parent::get() returns a translation string that is equal to the translation key that was passed in. Both #lang() and trans() functions call the get() method of the translator.
Seems like a whole lot of trouble only to get another reason for a "Whoops! something went wrong!" on your site. You will only get the exception when the translation is encountered.
Another solution: you can use the barryvdh/laravel-translation-manager package, it has a translation service provider that logs missing translation keys and a web interface for managing translations. It will log missing translation keys per locale and let you edit them through a web interface.
It is simple to setup and easy to modify. So you can replace the logging with throwing an exception.
I tried to upgrade Magento 1.9.0.1 to 1.9.1 via the Magento Connect facility and it seems to have stopped me being able to add users and roles for API access.
Here's the error:
Invalid method Mage_Admin_Model_User::validateCurrentPassword(Array
Has anyone ever come across this?
this issues can be solve
1) open the file app/code/core/Mage/Adminhtml/Controller/Action.php
2) After that see the function on line number 395 and comment the internel code into this.
protected function _validateCurrentPassword($password){
/*$user = Mage::getSingleton('admin/session')->getUser();
return $user->validateCurrentPassword($password);*/
}
I recently came across this same issue after upgrading Magento to a newer version of 1.9.
It should be noted that you should never modify core files, and the password validation should not necessarily be removed.
In my personal case, I restored the original function to the core file, however, you could just as easily extend the Mage_Admin_Model_User class.
The version of the function I used can be found below.
/**
* Validate password against current user password
* Returns true or array of errors.
*
* #return mixed
*/
public function validateCurrentPassword($password)
{
$result = array();
if (!Zend_Validate::is($password, 'NotEmpty')) {
$result[] = $this->_getHelper('adminhtml')->__('Current password field cannot be empty.');
} elseif (is_null($this->getId()) || !$this->_getHelper('core')->validateHash($password, $this->getPassword())){
$result[] = $this->_getHelper('adminhtml')->__('Invalid current password.');
}
if (empty($result)) {
$result = true;
}
return $result;
}
I want run store by IP of the customer.
In the backend of Magento, the user may configure the concret Store to load per country.
Taking a glance, I see the method at class Mage_Core_Model_App
public function run($params)
{
$options = isset($params['options']) ? $params['options'] : array();
$this->baseInit($options);
if ($this->_cache->processRequest()) {
$this->getResponse()->sendResponse();
} else {
$this->_initModules();
$this->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS);
if ($this->_config->isLocalConfigLoaded()) {
//$scopeCode = isset($params['scope_code']) ? $params['scope_code'] : '';
//===============custom scope by country======================
$scopeCode = Mage::helper('custom/module')->getStoreByGeoip();
//===============custom scope by country======================
$scopeType = isset($params['scope_type']) ? $params['scope_type'] : 'store';
$this->_initCurrentStore($scopeCode, $scopeType);
$this->_initRequest();
Mage_Core_Model_Resource_Setup::applyAllDataUpdates();
}
$this->getFrontController()->dispatch();
}
return $this;
}
In my progress to get a good solution, I thought another alternative.
In the index.php write the next code:
Mage::app();
Mage::Helper('custom/helper')->getRunCodeByGeoio();
Mage::run($mageRunCode, $mageRunType);
I thinks this haven´t dangerous of performance because this method only create object if you not have before
/**
* Get initialized application object.
*
* #param string $code
* #param string $type
* #param string|array $options
* #return Mage_Core_Model_App
*/
public static function app($code = '', $type = 'store', $options = array())
{
if (null === self::$_app) {
self::$_app = new Mage_Core_Model_App();
self::setRoot();
self::$_events = new Varien_Event_Collection();
self::$_config = new Mage_Core_Model_Config();
Varien_Profiler::start('self::app::init');
self::$_app->init($code, $type, $options);
Varien_Profiler::stop('self::app::init');
self::$_app->loadAreaPart(Mage_Core_Model_App_Area::AREA_GLOBAL, Mage_Core_Model_App_Area::PART_EVENTS);
}
return self::$_app;
}
And my question is......
Are this the best approach for get the solution??
I think is very dangerous modify Mage_Core_Model_App even using rewrite
I don´t have any event at tier
Another option is made the business in the index.php but lost the management by the backend
Searching...., found a extension that cover many of my requirements,
http://www.mageworx.com/store-and-currency-auto-switcher-magento-extension.html
then I'll buy this or made a similar extension.
You shyould never touch any core files when developing with Magento, or any other application if you can avoid it.
Doing this will mean possible future upgrades will overwrite your changes and break your store.
The simplest way would be to do everything index.php as this is the entry point where the store is selected anyway, all you are doing is selecting the store on different criteria (ie IP address).
One simple way would be to use a free library, such as maxmind GeoLite: http://dev.maxmind.com/geoip/geolite
You can either load an apache module, or via a pecl extensions, or even plain PHP.
This will return you the iso country code for the country of your visitor.
You could then name your stores with a country iso code for the store code, and this will make it really simple to load the correct store depending on IP
something simple like this:
$countryCode = getUsersCountryCode(); // which ever method you use in here...
$stores = array(
'gb',
'us',
'fr',
);
if(in_array(countryCode, $stores)) {
Mage::run(countryCode, 'store');
}
else {
Mage::run($mageRunCode, $mageRunType);
}
You could of course make it into a Magento extensions, but this is by far the simplest way. You could even get a list of the countries/stores from Magento rather than hard coding them if you required.
Can anybody explain how magento customer login works.
In fact, I have a bit weird situation. I need to copy all the customer from existing website to new magento website (I want my customers to use the same username password to login to new website). I know how the passwords have been encrypted in the old website (using normal php encrypt() function with salt) but I can't decrypt them. So I thought of adding a new field in customer account called 'oldpassword' (I followed this blog to create new field in customer account).
What I want now is, when importing the customers, save the old encrypted passwords in 'oldpassword' field. When customer tries to login, it should match the password with oldpassword field using the old encryption method. If password, matches, it should generate the standard magento password and save that in default password field. So next time when customer tries to log in, it should check if default password field is not empty, then just login normally.
ADDED
Still waiting for help
I have overwritten the customer->advanceContoller but not quite sure what changes to make in loginPostAction.
Please go to page: app/code/core/Mage/Customer/Model/Customer.php
You can see function public function authenticate($login, $password)
Also you can see
/**
* Validate password with salted hash
*
* #param string $password
* #return boolean
*/
public function validatePassword($password)
{
if (!($hash = $this->getPasswordHash())) {
return false;
}
return Mage::helper('core')->validateHash($password, $hash);
}
/**
* Encrypt password
*
* #param string $password
* #return string
*/
public function encryptPassword($password)
{
return Mage::helper('core')->encrypt($password);
}
/**
* Decrypt password
*
* #param string $password
* #return string
*/
public function decryptPassword($password)
{
return Mage::helper('core')->decrypt($password);
}
Please check this file.
I have multiple blocks shown on the user profile page, user/uid
On each of them, I need to print the user name.
I've been doing a $user = user_load(arg(1)); print $user->name; on each block. Since there is no caching, as you can image the performance is HORRIBLE.
Is there either a way to get the user name more efficiently or to cache user_load.
Thanks.
Just add an intermediate function to provide the static caching yourself:
/**
* Proxy for user_load(), providing static caching
* NOTE: Only works for the common use of user_load($uid) - will NOT load by name or email
*
* #param int $uid - The uid of the user to load
* #param bool $reset - Wether to reset the static cache for the given uid, defaults to FALSE
* #return stdClass - A fully-loaded $user object upon successful user load or FALSE if user cannot be loaded.
*/
function yourModule_user_load_cached($uid, $reset = FALSE) {
static $users = array();
// Do we need to (re)load the user?
if (!isset($users[$uid]) || $reset) {
$users[$uid] = user_load($uid);
}
return $users[$uid];
}
Use menu_get_object() which is the proper way to retrieve an object (user, node, etc.) loaded from the URL of a properly declared page. It will return the user object that has already been loaded using the uid found at arg(1) for a menu item which use %user in its path (ie. $items['user/%user'], $items['user/%user/view'], etc. in user_menu().
$account = menu_get_object('user');
The user is a global.
function myfunction() {
global $user;
}