Add a password field to the account identities

Some types of identities, e.g. "username:", now support having
an optional password generated alongside of them.  This can be
used in the future to authenticate the user.

Currently we intend to use this only for authentication over
HTTP, so we generate the password for the user as they would
need to store it into a local ~/.netrc.  We don't want them
to reuse an existing password that might be vulnerable.

Change-Id: I047a97f00249c81638625d7654087ea71f8f386a
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce
2010-01-15 17:22:25 -08:00
parent fbb6029761
commit 37930f8d55
15 changed files with 460 additions and 190 deletions

View File

@@ -100,6 +100,13 @@ public class ChangeUserName implements Callable<VoidResult> {
try {
final AccountExternalId id =
new AccountExternalId(user.getAccountId(), key);
for (AccountExternalId i : old) {
if (i.getPassword() != null) {
id.setPassword(i.getPassword());
}
}
db.accountExternalIds().insert(Collections.singleton(id));
} catch (OrmDuplicateKeyException dupeErr) {
// If we are using this identity, don't report the exception.

View File

@@ -0,0 +1,93 @@
// Copyright (C) 2010 The Android Open Source Project
//
// 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 com.google.gerrit.server.account;
import com.google.gerrit.common.errors.NoSuchEntityException;
import com.google.gerrit.reviewdb.AccountExternalId;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.apache.commons.codec.binary.Base64;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.concurrent.Callable;
/** Operation to generate a password for an account. */
public class GeneratePassword implements Callable<AccountExternalId> {
private static final int LEN = 12;
private static final SecureRandom rng;
static {
try {
rng = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Cannot create RNG for password generator", e);
}
}
public interface Factory {
GeneratePassword create(AccountExternalId.Key forUser);
}
private final AccountCache accountCache;
private final ReviewDb db;
private final IdentifiedUser user;
private final AccountExternalId.Key forUser;
@Inject
GeneratePassword(final AccountCache accountCache, final ReviewDb db,
final IdentifiedUser user,
@Assisted AccountExternalId.Key forUser) {
this.accountCache = accountCache;
this.db = db;
this.user = user;
this.forUser = forUser;
}
public AccountExternalId call() throws OrmException, NoSuchEntityException {
AccountExternalId id = db.accountExternalIds().get(forUser);
if (id == null || !user.getAccountId().equals(id.getAccountId())) {
throw new NoSuchEntityException();
}
id.setPassword(generate());
db.accountExternalIds().update(Collections.singleton(id));
accountCache.evict(user.getAccountId());
return id;
}
private String generate() {
byte[] rand = new byte[LEN];
rng.nextBytes(rand);
byte[] enc = Base64.encodeBase64(rand, false);
StringBuilder r = new StringBuilder(LEN);
for (int i = 0; i < LEN; i++) {
if (enc[i] == '=') {
break;
}
r.append((char) enc[i]);
}
return r.toString();
}
}

View File

@@ -32,7 +32,7 @@ import java.util.List;
/** A version of the database schema. */
public abstract class SchemaVersion {
/** The current schema version. */
private static final Class<? extends SchemaVersion> C = Schema_23.class;
private static final Class<? extends SchemaVersion> C = Schema_24.class;
public static class Module extends AbstractModule {
@Override

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2010 The Android Open Source Project
//
// 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 com.google.gerrit.server.schema;
import com.google.inject.Inject;
import com.google.inject.Provider;
class Schema_24 extends SchemaVersion {
@Inject
Schema_24(Provider<Schema_23> prior) {
super(prior);
}
}