Skip to main content

Login Extension

Zuora

Login Extension

The Zephr login extension plugin enables Zephr customers to seamlessly import users with legacy password information while ensuring that these users can log in as typical Zephr users. This functionality is accomplished by converting the legacy password details to Zephr's standard bcrypt format during the user login process.

Features

  • Enables login for users who have been imported to Zephr with password details in the following formats:
    • MD5
    • bcrypt
    • SHA-256
    • SHA-512
    • Drupal Hash
    • PBKDF2
    • PWDTK (an alternative implementation of PBKDF2)
    • ASP.net HashPasswordV2
    • SHA-1
  • Upon user login, their credentials undergo conversion to Zephr's robustbcryptformat, ensuring high security. Subsequent logins utilize Zephr's core user authentication mechanism.
  • All legacy logins are entirely transparent to end users: whether a user is imported with legacy credentials or directly created within Zephr, the experience remains the same.

Configuring the Login Extension

To enable the Login Extension within Zephr, navigate to Settings > Extensions > Login Extension. If you cannot see the Login option in your list of Extensions, email support@zephr.com.

To activate the Login Extension, simply confirm which of your Sites the extension should be active on. To do this, use the toggles for each site under the Activate Plugin section, or choose Select All Sites.

Once completed, click Save.

Usage

The plugin is active in the background and will orchestrate login for any users that are imported with legacy credentials.

To import a legacy user, you will need to make POSTs to /v3/users as detailed in the Zephr Admin API documentation. However, in the validators section, you will need to include a legacy_password field, the value of which will be a stringified JSON object including fields relating to the user’s credentials (these vary by algorithm; check below for details).

Here is an example, providing some md5 legacy password details:

{
    "identifiers": {
        "email_address": "bob.smith@example.com"
    },
    "validators": {
        "legacy_password": "{\"algorithm\": \"md5\",\"hash\": \"cc58db7c46ddbee969c257af0c505498\", \"salt\": \"mySuperSecureHash\"}"
    },
    "attributes": {
        "first-name": "Bob",
        "last-name": "Smith"
    }
}

Each of the supported legacy password algorithms may require different fields in the legacy_password object.

The JSON objects below are presented as plain JSON for ease of reading. They must be stringified before being used to create users with legacy password credentials.

MD5

{
    "algorithm": "md5",
    "salt": "<salt>", // string
    "hash": "<hash>" // string
}

bcrypt

{
    "algorithm": "bcrypt",
    "hash": "<hash>",  // string
    "salt": "<salt>",  // string
    "rounds": <rounds> // number (int)
}

Note: bcrypt hashes must be split into their constituent parts before submission, as per the example here.

For a hash of $2a$12$5gL.SoMV.kKijer1iArWWeH7DJFqBL1NvBRoW2cGC4xHZquPleauO

  • The red section is the bcrypt version (not needed).
  • The blue section is the cost factor. The cost factor is the base-2 exponent, which gives the number of rounds of hashing to which the string has been subjected. To calculate the number of rounds from the cost factor calculate the output of 2<cost_factor>. For example, a cost factor of 12 would result in a number of rounds of 4096 (212 = 4096). Once you know the number of rounds for your hashes, please provide this as an integer in the rounds field.
  • The 22 characters in green comprise the salt. Add this as a string to the salt field (there will be a dollar sign – $ – separating the rounds from the salt: do not include the dollar sign in the salt value that you provide in the legacy password object).
  • The section in pink is the hash. Add this as a string to the hash field.

A full JSON payload to create a user with a legacy hash as above would look like:

{
    "identifiers": {
        "email_address": "alice.smith@example.com"
    },
    "validators": {
        "legacy_password": "{\"algorithm\": \"bcrypt\",\"hash\": \"H7DJFqBL1NvBRoW2cGC4xHZquPleauO\", \"salt\": \"5gL.SoMV.kKijer1iArWWe\", \"rounds\": 4096}"
    },
    "attributes": {
        "first-name": "Alice",
        "last-name": "Smith"
    }
}

SHA-256

{
    "algorithm": "SHA-256",
    "salt": "<salt>",        // string
    "hash": "<hash>"         // string
}

SHA-512

{
    "algorithm": "sha512",
    "salt": "<salt>",        // string
    "hash": "<hash>"        // string
}

Please note that the algorithm should be provided as sha512.

Drupal Hash

{
    "algorithm": "DRUPAL-HASH",
    "hash": "<hash>"            // string
}

PBKDF2

{
    "algorithm": "pbkdf2",                        // REQUIRED: string (must be "pbkdf2")
    "hash": "<hash>",                             // REQUIRED: string
    "salt": "<salt>",                             // REQUIRED: string
    "rounds": <rounds>,                           // REQUIRED: number (int)
    "keyLength": <keyLength>,                     // OPTIONAL: number (int); default: 128
    "cipher": "<cipher>",                         // OPTIONAL: string (one of: "sha-1", "sha-256", "sha-512"); default: "sha-1"
    "saltBase64EncodedPostHashing": <boolean>     // OPTIONAL: boolean; default: true,
    "hashBytesTruncation": <hashBytesTruncation>, // OPTIONAL: number (int)
}

Zephr’s handling for PBKDF2 legacy password hashes currently supports SHA-1 and SHA-256 ciphers.

Depending on the system from which you are exporting the hashes, you may need to split up the data into its constituent parts before users are imported to Zephr. Portable hashes of this usually have segments of data delimited by a $ character. Example hash:

pbkdf2_sha256$10000$WtfwHgrhdWFb$HbQyTOwl/hxjb9I10OMj+Efb6zhwgOnsYoKLfeLjCf3g=

  • Algorithm
  • Rounds
  • Salt
  • Hash

The hash above is purely to demonstrate delimiting: characters do not represent a valid hash.

By default, only four of the fields above are required in the legacy password object:

  • algorithm (must be pbkdf2)
  • hash (must be base64 encoded)
  • salt
  • rounds

There are also some optional fields that can be used to declare the settings that were used to originally hash the passwords in the system from which you are exporting:

  • keyLength: the number of bits for the key. Defaults to 128, but can be set to a value such as 256 or 512 etc.
  • cipher: the cipher used in the algorithm. Defaults to sha-1. If declared, the value of this field must be one of sha-1 or sha-256.
  • saltBase64EncodedPostHashing: Declares whether the salt value provided has been base 64 encoded since it was used to create the hash. Defaults to true. If the salts you provided are the exact strings that were used to originally salt the hashes (i.e. they have not since been base 64 encoded), set this field to false.
  • hashBytesTruncation: The number of bytes that the original hash was truncated to.

PBKDF2-PWDTK

Zephr provider support for hashes generated by the alternative PWDTK implementation of PBKDF2.

{
    "algorithm": "pbkdf2-pwdtk",
    "hash": "<hash>", // string (hex)
    "saltLength": <saltLength>, // number (int)
    "iterations": <iterations> // number (int)
}

ASP.net HashPasswordV2

The extension currently only supports the HashPasswordV2 format.

{
    "algorithm": "aspNetIdentity-HashPasswordV2",
    "hash": "" // string (base64)
}

SHA-1

You must ensure that the algorithm is specified as SHA-1.

{
    "algorithm": "sha-1",
    "hashFormat": "<hashFormat>", // string: "base64" or "hexstring"
    "hash": "<hash>"             // string
}