Password Encryptors

1. Write the Password Encryptor Class

The main plugin interface in FusionAuth is the Password Encryptors interface. This allows you to write a custom password encryption scheme. A custom password encryption scheme is useful when you import users from an existing database into FusionAuth so that the users don’t need to reset their passwords to login into your applications.

To write a Password Encryptor, you must first implement the io.fusionauth.plugin.spi.security.PasswordEncryptor interface. Here’s an example of a simple Password Encryptor. This implementation simply reverses the password.

DO NOT use this password encryption scheme in a production environment!

Password Encryptor
package com.mycompany.fusionauth.plugins;

import io.fusionauth.plugin.spi.security.PasswordEncryptor;

/**
 * Super strong encryption that reverses the password. DO NOT USE IN PRODUCTION!
 */
public class ReversePasswordEncryptor implements PasswordEncryptor {
  @Override
  public int defaultFactor() {
    return 1;
  }

  @Override
  public String encrypt(String password, String salt) {
    return new StringBuilder(password).reverse().toString();
  }
}

2. Adding the Guice Bindings

To complete the main plugin code (before we write a unit test), you need to add Guice binding for your new Password Encryptor. Password Encryptors use Guice Multibindings via Map. Here is an example of binding our new Password Encryptor so that FusionAuth can use it for users.

Guice Module
package com.mycompany.fusionauth.plugins.guice;

import com.google.inject.AbstractModule;
import com.google.inject.multibindings.MapBinder;
import io.fusionauth.plugin.spi.PluginModule;
import io.fusionauth.plugin.spi.security.PasswordEncryptor;
import com.mycompany.fusionauth.plugins.ReversePasswordEncryptor;

/**
 * A cool FusionAuth plugin module (plus a Password Encryptor).
 */
@PluginModule
public class MyCompanyFusionAuthPluginsModule extends AbstractModule {
  @Override
  protected void configure() {
    MapBinder<String, PasswordEncryptor> passwordEncryptorMapBinder = MapBinder.newMapBinder(binder(), String.class, PasswordEncryptor.class);
    passwordEncryptorMapBinder.addBinding("reverse").to(ReversePasswordEncryptor.class);
  }
}

You can see that we have bound the Password Encryptor under the name "reverse". This is the same name that you will use when creating users via the /api/user API.

3. Writing a Unit Test

You’ll probably want to write some tests to ensure that your new Password Encryptor is working properly. Our example uses TestNG, but you can use JUnit or another framework if you prefer. Here’s a simple unit test for our Password Encryptor:

Unit Test
package com.mycompany.fusionauth.plugins;

import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;

/**
 * A simple unit test
 */
public class ReversePasswordEncryptorTest {
  @Test
  public void reverse() {
    ReversePasswordEncryptor reversePasswordEncryptor = new ReversePasswordEncryptor();
    assertEquals(reversePasswordEncryptor.encrypt("hello world", null), "dlrow olleh");
  }
}

If you are using our Savant build file, you can run this test by executing this command:

sb test

4. Integration Test

After you have completed your plugin, the unit test and installed the plugin into a running FusionAuth installation, you can test it by hitting the /api/user API and creating a test user. Here’s an example JSON request that uses the new Password Encryptor:

{
  "user": {
    "id": "00000000-0000-0000-0000-000000000001",
    "active": true,
    "email": "test0@fusionauth.io",
    "encryptionScheme": "reverse",
    "password": "password",
    "username": "username0",
    "timezone": "Denver",
    "data": {
      "attr1": "value1",
      "attr2": ["value2", "value3"]
    },
    "preferredLanguages": ["en", "fr"],
    "registrations": [
      {
        "applicationId": "00000000-0000-0000-0000-000000000042",
        "data": {
          "attr3": "value3",
          "attr4": ["value4", "value5"]
        },
        "id": "00000000-0000-0000-0000-000000000003",
        "preferredLanguages": ["de"],
        "roles": ["role 1"],
        "username": "username0"
      }
    ]
  }
}

Notice that we’ve passed in the encryptionScheme property with a value of reverse. This will instruct FusionAuth to use your newly written Password Encryptor.