{"id":55766,"date":"2022-11-22T09:58:38","date_gmt":"2022-11-22T04:28:38","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=55766"},"modified":"2022-11-25T10:00:18","modified_gmt":"2022-11-25T04:30:18","slug":"password-migration-in-drupal-9-from-drupal-7-wordpress-and-custom-cms","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/password-migration-in-drupal-9-from-drupal-7-wordpress-and-custom-cms\/","title":{"rendered":"Password Migration in Drupal 9 from Drupal 7, WordPress, and Custom CMS"},"content":{"rendered":"<p>Password migration is basically part of website migration. We can migrate content, images, documents, categories, and other content very easily because these are almost straightforward. In migration, We pick the content from the source and put it into a destination which is called the lift-and-shift approach. In Drupal 9, Password migration is a bit tricky due to the different encryption algorithms used in each application.<\/p>\n<p>In this article, I am going to describe how you can migrate the following types of passwords into Drupal 8, Drupal 9, and Drupal 10+:<\/p>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">MD5 Hash Algorithm<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Portable Phpass Hashes\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Custom Password Algorithm<\/span><\/li>\n<li>Plain Password Migration<\/li>\n<\/ul>\n<p><em>Prerequisites: You should have knowledge of Drupal migration.<\/em><\/p>\n<h2><strong>MD5 Hash Algorithm:<\/strong><\/h2>\n<p>MD5 Password Algorithm used in Drupal 5, Drupal 6, Drupal 7, <span style=\"font-weight: 400;\">osCommerce, <\/span><span style=\"font-weight: 400;\">SuiteCRM, <\/span><span style=\"font-weight: 400;\">miniBB, <\/span><span style=\"font-weight: 400;\">SugarCRM and etc.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">MD5 password hashes must be migrated to Drupal 8+ using the <\/span><strong>md5_passwords: true<\/strong><span style=\"font-weight: 400;\"> configuration option so that the users can use their old passwords. The passwords are salted and re-hashed before they are saved into the Drupal 8+ database. The identifier of md5 migrated password id <\/span><span style=\"font-weight: 400;\"><strong>U$<\/strong>. <\/span><span style=\"font-weight: 400;\">When the user logs in to your Drupal site for the first time, Drupal will re-hash the password.<\/span><\/p>\n<p>Create a custom module custom_migrate inside modules\/custom\/ folder with all the basic required files.<\/p>\n<p>1. Migration Group configuration file: web\/modules\/custom\/custom_migrate\/config\/install\/migrate_plus.migration_group.md5hash.yml<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-55823\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.md5hash-1024x795.png\" alt=\"\" width=\"625\" height=\"485\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.md5hash-1024x795.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.md5hash-300x233.png 300w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.md5hash-768x596.png 768w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.md5hash-624x485.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.md5hash.png 1504w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<p>2. Migration configuration files: web\/modules\/custom\/custom_migrate\/config\/install\/migrate_plus.migration.md5_hash.yml<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-55824\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.md5_hash-1024x924.png\" alt=\"\" width=\"625\" height=\"564\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.md5_hash-1024x924.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.md5_hash-300x271.png 300w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.md5_hash-768x693.png 768w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.md5_hash-624x563.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.md5_hash.png 1346w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<h2><strong>Portable Phpass hashes:<\/strong><\/h2>\n<p>phpass (pronounced &#8220;pH pass&#8221;) is a portable public domain password hashing framework for use in PHP applications. Phpass has been integrated into <strong>WordPress 2.5+ 2, bbPress 3, Vanilla 4, phpBB3 8, and Joomla starting with versions 2.5.18 and 3.2.1.<\/strong><\/p>\n<p>The password hashes generated with Phpass look like this: <strong>$P$B4J4RkvSe3QowfF\/v6oHionn8CyW.a.<\/strong> The <strong>$P$<\/strong> is the so-called hash type identifier which indicates that the hash is a portable Phpass hash. The string after that consists of salt and a hash. The <strong>portable Phpass hashes can be migrated to Drupal 8 as-is<\/strong>. When the user logs in to your Drupal 8 site for the first time, Drupal will re-hash the password.<\/p>\n<p>1. Migration Group configuration file: web\/modules\/custom\/custom_migrate\/config\/install\/migrate_plus.migration_group.portable_phpass.yml<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-55825\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.portable_phpass-1024x728.png\" alt=\"Portable Phpass Hashes Algorithm migration\" width=\"625\" height=\"444\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.portable_phpass-1024x728.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.portable_phpass-300x213.png 300w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.portable_phpass-768x546.png 768w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.portable_phpass-624x444.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.portable_phpass.png 1474w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<p>2. Migration configuration files: web\/modules\/custom\/custom_migrate\/config\/install\/migrate_plus.migration.portable_phpass.yml<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-55826\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.portable_phpass-1024x896.png\" alt=\"Portable Phpass Hashes Algorithm migration\" width=\"625\" height=\"547\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.portable_phpass-1024x896.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.portable_phpass-300x263.png 300w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.portable_phpass-768x672.png 768w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.portable_phpass-624x546.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.portable_phpass.png 1298w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<h2><strong>Custom Password algorithm:<\/strong><\/h2>\n<p>If the source system passwords are hashed with some other algorithm, it is possible to add support for these hashes by extending the Drupal core password service. When the user tries to log in, the password hash checking is done in <strong>PhpassHashedPassword::check()<\/strong>. As you can see, there is handling for different hash types, which are identified by hash type identifiers such as <strong>U$, $S$, $P$, and $H$<\/strong>. You can add handling for your legacy hashes, provided that you know the algorithm that was used to generate the hashes in your source system. You will need to prefix the old hashes with a special hash type identifier.<\/p>\n<p>1. Migration Group configuration file: web\/modules\/custom\/custom_migrate\/config\/install\/migrate_plus.migration_group.custom_hash.yml<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-55829\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.custom_hash-1024x815.png\" alt=\"Drupal 9 Custom Hash Algorithm migration.\" width=\"625\" height=\"497\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.custom_hash-1024x815.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.custom_hash-300x239.png 300w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.custom_hash-768x611.png 768w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.custom_hash-624x497.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration_group.custom_hash.png 1470w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<p>2. Migration configuration files: web\/modules\/custom\/custom_migrate\/config\/install\/migrate_plus.migration.sha512_hash.yml<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-55830\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.sha512_hash-1024x870.png\" alt=\"Drupal 9 Custom Hash Algorithm migration.\" width=\"625\" height=\"531\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.sha512_hash-1024x870.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.sha512_hash-300x255.png 300w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.sha512_hash-768x653.png 768w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.sha512_hash-624x530.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/migrate_plus.migration.sha512_hash.png 1304w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<p>3. Migration source plugin file <strong>web\/modules\/custom\/custom_migrate\/src\/Plugin\/migrate\/source\/Sha512Hash.php<\/strong><\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-55831\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/Sha512Hash-761x1024.png\" alt=\"Drupal 9 Custom Hash Algorithm migration.\" width=\"625\" height=\"841\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/Sha512Hash-761x1024.png 761w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/Sha512Hash-223x300.png 223w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/Sha512Hash-768x1034.png 768w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/Sha512Hash-1141x1536.png 1141w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/Sha512Hash-624x840.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/Sha512Hash.png 1420w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<p>4. Override the service file <strong>web\/modules\/custom\/custom_migrate\/custom_migrate.services.yml<\/strong><\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-55827\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/custom_migrate.services-1024x178.png\" alt=\"Password Migration in Drupal 9 from Drupal 7, WordPress, and Custom CMS.\" width=\"625\" height=\"109\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/custom_migrate.services-1024x178.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/custom_migrate.services-300x52.png 300w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/custom_migrate.services-768x134.png 768w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/custom_migrate.services-624x109.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/custom_migrate.services.png 1252w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<p>5. Create a class file in <strong>web\/modules\/custom\/custom_migrate\/src\/Services\/CustomMigratePasswordService.php<\/strong><\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-large wp-image-55828\" src=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-1017x1024.png\" alt=\"Password Migration in Drupal 9 from Drupal 7, WordPress, and Custom CMS.\" width=\"625\" height=\"629\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-1017x1024.png 1017w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-298x300.png 298w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-150x150.png 150w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-768x773.png 768w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-1526x1536.png 1526w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-624x628.png 624w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-120x120.png 120w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-24x24.png 24w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-48x48.png 48w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService-96x96.png 96w, \/blog\/wp-ttn-blog\/uploads\/2022\/11\/CustomMigratePasswordService.png 1798w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/p>\n<h2>Plain Password Migration:<\/h2>\n<p>If the passwords are plain text in the source, you can preserve the passwords by processing them through <strong>md5<\/strong> during the migration using the Callback process plugin and then using the <strong>md5_passwords: true<\/strong> configuration option in the yml file, same as the MD5 Password Algorithm.<\/p>\n<div class=\"ap-custom-wrapper\"><\/div><!--ap-custom-wrapper-->","protected":false},"excerpt":{"rendered":"<p>Password migration is basically part of website migration. We can migrate content, images, documents, categories, and other content very easily because these are almost straightforward. In migration, We pick the content from the source and put it into a destination which is called the lift-and-shift approach. In Drupal 9, Password migration is a bit tricky [&hellip;]<\/p>\n","protected":false},"author":1038,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":58},"categories":[3602],"tags":[3601,4884,5044],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/55766"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1038"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=55766"}],"version-history":[{"count":8,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/55766\/revisions"}],"predecessor-version":[{"id":55847,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/55766\/revisions\/55847"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=55766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=55766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=55766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}