Password Encryptors

1. Write the Password Encryptor Class

The main plugin interface in Passport 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 Passport 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 com.inversoft.passport.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.passport.plugins;

import com.inversoft.passport.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 Passport can use it for users.

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

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

/**
 * A cool Passport plugin module (plus a Password Encryptor).
 */
@PluginModule
public class MyCompanyPassportPluginsModule 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.passport.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 Passport 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@inversoft.com",
    "encryptionScheme": "reverse",
    "password": "password",
    "username": "username0",
    "timezone": "Denver",
    "data": {
      "attributes": {
        "attr1": "value1",
        "attr2": ["value2", "value3"]
      },
      "preferredLanguages": ["en", "fr"]
    },
    "registrations": [
      {
        "applicationId": "00000000-0000-0000-0000-000000000042",
        "data": {
          "attributes": {
            "attr3": "value3",
            "attr4": ["value4", "value5"]
          },
          "preferredLanguages": ["de"]
        },
        "id": "00000000-0000-0000-0000-000000000003",
        "roles": ["role 1"],
        "username": "username0"
      }
    ]
  }
}

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