Allow PasswordGenerator to use different alphabets

Per mcilwain's suggestion in the LRP design doc, LRP tokens should use a Base58 alphabet. I'll move PasswordGenerator out of the tools package and into a utils class in a future CL, as we'll want to use this generator in the LrpToken class itself rather than relegate the token definition to a tool.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=132358363
This commit is contained in:
ctingue 2016-09-06 13:56:46 -07:00 committed by Ben McIlwain
parent dbb9ef80c5
commit daca7d65c2
14 changed files with 98 additions and 56 deletions

View file

@ -72,14 +72,14 @@ final class CreateAnchorTenantCommand extends MutatingEppToolCommand implements
private boolean fee;
@Inject
PasswordGenerator passwordGenerator;
StringGenerator passwordGenerator;
@Override
protected void initMutatingEppToolCommand() {
checkArgument(superuser, "This command must be run as a superuser.");
findTldForNameOrThrow(InternetDomainName.from(domainName)); // Check that the tld exists.
if (isNullOrEmpty(password)) {
password = passwordGenerator.createPassword(PASSWORD_LENGTH);
password = passwordGenerator.createString(PASSWORD_LENGTH);
}
Money cost = null;

View file

@ -103,14 +103,14 @@ final class CreateContactCommand extends MutatingEppToolCommand implements Gtech
private String password;
@Inject
PasswordGenerator passwordGenerator;
StringGenerator passwordGenerator;
private static final int PASSWORD_LENGTH = 16;
@Override
protected void initMutatingEppToolCommand() {
if (isNullOrEmpty(password)) {
password = passwordGenerator.createPassword(PASSWORD_LENGTH);
password = passwordGenerator.createString(PASSWORD_LENGTH);
}
checkArgument(street == null || street.size() <= 3,
"Addresses must contain at most 3 street lines.");

View file

@ -76,14 +76,14 @@ final class CreateDomainCommand extends MutatingEppToolCommand implements GtechC
private String password;
@Inject
PasswordGenerator passwordGenerator;
StringGenerator passwordGenerator;
private static final int PASSWORD_LENGTH = 16;
@Override
protected void initMutatingEppToolCommand() {
if (isNullOrEmpty(password)) {
password = passwordGenerator.createPassword(PASSWORD_LENGTH);
password = passwordGenerator.createString(PASSWORD_LENGTH);
}
checkArgument(ns == null || ns.size() <= 13, "There can be at most 13 nameservers.");

View file

@ -1,22 +0,0 @@
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.tools;
/** Password generator interface. */
interface PasswordGenerator {
/** Generates a password of a specified length. */
String createPassword(int length);
}

View file

@ -18,27 +18,26 @@ import static com.google.common.base.Preconditions.checkArgument;
import java.util.Random;
import javax.inject.Inject;
import javax.inject.Named;
/** Password generator. */
class RandomPasswordGenerator implements PasswordGenerator {
private static final String SYMBOLS =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-=";
/** Random string generator. */
class RandomStringGenerator extends StringGenerator {
private final Random random;
@Inject
RandomPasswordGenerator(Random random) {
RandomStringGenerator(@Named("alphabet") String alphabet, Random random) {
super(alphabet);
this.random = random;
}
/** Generates a password of a specified length. */
/** Generates a random string of a specified length. */
@Override
public String createPassword(int length) {
public String createString(int length) {
checkArgument(length > 0);
char[] password = new char[length];
for (int i = 0; i < length; ++i) {
password[i] = SYMBOLS.charAt(random.nextInt(SYMBOLS.length()));
password[i] = alphabet.charAt(random.nextInt(alphabet.length()));
}
return new String(password);
}

View file

@ -22,6 +22,8 @@ import java.security.ProviderException;
import java.security.SecureRandom;
import java.util.Random;
import javax.inject.Named;
/** Dagger module for Registry Tool. */
@Module
abstract class RegistryToolModule {
@ -32,7 +34,7 @@ abstract class RegistryToolModule {
}
@Binds
abstract PasswordGenerator providePasswordGenerator(RandomPasswordGenerator passwordGenerator);
abstract StringGenerator provideStringGenerator(RandomStringGenerator stringGenerator);
@Provides
static Random provideRandom() {
@ -42,4 +44,10 @@ abstract class RegistryToolModule {
throw new ProviderException(e);
}
}
@Provides
@Named("alphabet")
static String provideAlphabet() {
return StringGenerator.Alphabets.BASE_64;
}
}

View file

@ -81,7 +81,7 @@ final class SetupOteCommand extends ConfirmingCommand implements RemoteApiComman
private String premiumList = DEFAULT_PREMIUM_LIST;
@Inject
PasswordGenerator passwordGenerator;
StringGenerator passwordGenerator;
/**
* Long registrar names are truncated and then have an incrementing digit appended at the end so
@ -188,16 +188,16 @@ final class SetupOteCommand extends ConfirmingCommand implements RemoteApiComman
// Storing names and credentials in a list of tuples for later play-back.
List<List<String>> registrars = new ArrayList<>();
registrars.add(ImmutableList.<String>of(
registrar + "-1", passwordGenerator.createPassword(PASSWORD_LENGTH),
registrar + "-1", passwordGenerator.createString(PASSWORD_LENGTH),
registrar + "-sunrise"));
registrars.add(ImmutableList.<String>of(
registrar + "-2", passwordGenerator.createPassword(PASSWORD_LENGTH),
registrar + "-2", passwordGenerator.createString(PASSWORD_LENGTH),
registrar + "-landrush"));
registrars.add(ImmutableList.<String>of(
registrar + "-3", passwordGenerator.createPassword(PASSWORD_LENGTH),
registrar + "-3", passwordGenerator.createString(PASSWORD_LENGTH),
registrar + "-ga"));
registrars.add(ImmutableList.<String>of(
registrar + "-4", passwordGenerator.createPassword(PASSWORD_LENGTH),
registrar + "-4", passwordGenerator.createString(PASSWORD_LENGTH),
registrar + "-ga"));
for (List<String> r : registrars) {

View file

@ -0,0 +1,44 @@
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
/** String generator. */
abstract class StringGenerator {
/** A class containing different alphabets used to generate strings. */
public static class Alphabets {
/** A URL-safe Base64 alphabet (alphanumeric, hyphen, underscore). */
public static final String BASE_64 =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-";
/** An alphanumeric alphabet that omits visually similar characters. */
public static final String BASE_58 =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
}
protected String alphabet;
StringGenerator(String alphabet) {
checkArgument(!isNullOrEmpty(alphabet), "Alphabet cannot be null or empty.");
this.alphabet = alphabet;
}
/** Generates a string of a specified length. */
abstract String createString(int length);
}

View file

@ -28,6 +28,7 @@ java_library(
"//third_party/java/joda_money",
"//third_party/java/joda_time",
"//third_party/java/json_simple",
"//third_party/java/jsr330_inject",
"//third_party/java/junit",
"//third_party/java/mockito",
"//third_party/java/objectify:objectify-v4_1",

View file

@ -29,7 +29,7 @@ public class CreateAnchorTenantCommandTest
@Before
public void initCommand() {
command.passwordGenerator = new FakePasswordGenerator("abcdefghijklmnopqrstuvwxyz");
command.passwordGenerator = new DeterministicStringGenerator("abcdefghijklmnopqrstuvwxyz");
}
@Test

View file

@ -23,7 +23,7 @@ public class CreateContactCommandTest extends EppToolCommandTestCase<CreateConta
@Before
public void initCommand() {
command.passwordGenerator = new FakePasswordGenerator("abcdefghijklmnopqrstuvwxyz");
command.passwordGenerator = new DeterministicStringGenerator("abcdefghijklmnopqrstuvwxyz");
}
@Test

View file

@ -23,7 +23,7 @@ public class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomain
@Before
public void initCommand() {
command.passwordGenerator = new FakePasswordGenerator("abcdefghijklmnopqrstuvwxyz");
command.passwordGenerator = new DeterministicStringGenerator("abcdefghijklmnopqrstuvwxyz");
}
@Test

View file

@ -15,21 +15,32 @@
package google.registry.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Lists.charactersOf;
import com.google.common.collect.Iterators;
import java.util.Iterator;
/** A password generator that produces a password from a predefined string. */
class FakePasswordGenerator implements PasswordGenerator {
import javax.inject.Named;
/**
* A string generator that produces strings using sequential characters in its alphabet. This is
* most useful in tests as a "fake" password generator (which would otherwise use
* {@link RandomStringGenerator}.
*
* <p>Note that consecutive calls to createString will continue where the last call left off in
* the alphabet.
*/
class DeterministicStringGenerator extends StringGenerator {
private Iterator<Character> iterator;
/** Produces a password from the password source string. */
/**
* Generates a string using sequential characters in the generator's alphabet, cycling back to the
* beginning of the alphabet if necessary.
*/
@Override
public String createPassword(int length) {
checkArgument(length > 0, "Password length must be positive.");
public String createString(int length) {
checkArgument(length > 0, "String length must be positive.");
String password = "";
for (int i = 0; i < length; i++) {
password += iterator.next();
@ -37,8 +48,8 @@ class FakePasswordGenerator implements PasswordGenerator {
return password;
}
public FakePasswordGenerator(String passwordSource) {
checkArgument(!isNullOrEmpty(passwordSource), "Password source cannot be null or empty.");
iterator = Iterators.cycle(charactersOf(passwordSource));
public DeterministicStringGenerator(@Named("alphabet") String alphabet) {
super(alphabet);
iterator = Iterators.cycle(charactersOf(alphabet));
}
}

View file

@ -41,7 +41,8 @@ public class SetupOteCommandTest extends CommandTestCase<SetupOteCommand> {
ImmutableList<String> passwords = ImmutableList.of(
"abcdefghijklmnop", "qrstuvwxyzabcdef", "ghijklmnopqrstuv", "wxyzabcdefghijkl");
FakePasswordGenerator passwordGenerator = new FakePasswordGenerator("abcdefghijklmnopqrstuvwxyz");
DeterministicStringGenerator passwordGenerator =
new DeterministicStringGenerator("abcdefghijklmnopqrstuvwxyz");
@Before
public void init() {