Unverified 提交 6c004246 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1211 from katzyn/misc

Assorted minor changes
......@@ -33,7 +33,7 @@ Change Log
</li>
<li>PR #1176: Magic value replacement with constant
</li>
<li>PR #1171: Introduce last commited value into a VersionedValue
<li>PR #1171: Introduce last committed value into a VersionedValue
</li>
<li>PR #1175: tighten test conditions - do not ignore any exceptions
</li>
......
......@@ -174,6 +174,7 @@
90141=Serializer cannot be changed because there is a data table: {0}
90142=Step size must not be zero
90143=Row {1} not found in primary index {0}
90144=Authenticator not enabled on database {0}
HY000=General error: {0}
HY004=Unknown data type: {0}
HYC00=Feature not supported: {0}
......
......@@ -9,8 +9,8 @@ import org.h2.security.auth.AuthenticationInfo;
import org.h2.security.auth.Configurable;
/**
* A class that implement this interface can be used to validate
* credentials provided by client.
* A class that implement this interface can be used to validate credentials
* provided by client.
* <p>
* <b>This feature is experimental and subject to change</b>
* </p>
......@@ -18,10 +18,14 @@ import org.h2.security.auth.Configurable;
public interface CredentialsValidator extends Configurable {
/**
* Validate user credential
* @param authenticationInfo = authentication info
* Validate user credential.
*
* @param authenticationInfo
* = authentication info
* @return true if credentials are valid, otherwise false
* @throws Exception any exception occurred (invalid credentials or internal issue) prevent user login
* @throws Exception
* any exception occurred (invalid credentials or internal
* issue) prevent user login
*/
boolean validateCredentials(AuthenticationInfo authenticationInfo) throws Exception;
......
......@@ -6,15 +6,14 @@
package org.h2.api;
import java.util.Collection;
import java.util.Set;
import org.h2.security.auth.AuthenticationException;
import org.h2.security.auth.AuthenticationInfo;
import org.h2.security.auth.Configurable;
/**
* A class that implement this interface can be used during
* authentication to map external users to database roles.
* A class that implement this interface can be used during authentication to
* map external users to database roles.
* <p>
* <b>This feature is experimental and subject to change</b>
* </p>
......@@ -22,10 +21,13 @@ import org.h2.security.auth.Configurable;
public interface UserToRolesMapper extends Configurable {
/**
* Map user identified by authentication info to a set of granted roles
* Map user identified by authentication info to a set of granted roles.
*
* @param authenticationInfo
* authentication information
* @return list of roles to be assigned to the user temporary
* @throws AuthenticationException
* on authentication exception
*/
Collection<String> mapUserToRoles(AuthenticationInfo authenticationInfo) throws AuthenticationException;
}
......@@ -321,7 +321,7 @@ public abstract class Command implements CommandInterface {
if (start != 0 && TimeUnit.NANOSECONDS.toMillis(now - start) > session.getLockTimeout()) {
throw DbException.get(ErrorCode.LOCK_TIMEOUT_1, e);
}
// Only in PageStore mode we need to sleep here to avoid buzy wait loop
// Only in PageStore mode we need to sleep here to avoid busy wait loop
Database database = session.getDatabase();
if (database.getMvStore() == null) {
int sleep = 1 + MathUtils.randomInt(10);
......
......@@ -548,9 +548,10 @@ public class Set extends Prepared {
}
addOrUpdateSetting(name,expression.getValue(session).getString(),0);
} catch (Exception e) {
//Errors during start are ignored to allow to open the database
// Errors during start are ignored to allow to open the database
if (database.isStarting()) {
database.getTrace(Trace.DATABASE).error(e, "{0}: failed to set authenticator during database start ",expression.toString());
database.getTrace(Trace.DATABASE).error(e,
"{0}: failed to set authenticator during database start ", expression.toString());
} else {
throw DbException.convert(e);
}
......
......@@ -664,6 +664,9 @@ public class ConnectionInfo implements Cloneable {
return url;
}
/**
* Clear authentication properties.
*/
public void cleanAuthenticationInfo() {
removeProperty("AUTHREALM", false);
removeProperty("AUTHZPWD", false);
......
......@@ -2989,7 +2989,7 @@ public class Database implements DataHandler {
public void setAuthenticator(Authenticator authenticator) {
if (authenticator!=null) {
authenticator.init(this);
};
}
this.authenticator=authenticator;
}
}
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.engine;
import org.h2.security.auth.AuthenticationInfo;
......@@ -6,16 +11,24 @@ import org.h2.util.MathUtils;
public class UserBuilder {
/**
* build the database user starting from authentication informations
* @param authenticationInfo = authentication info
* @param database = target database
* @param persistent = true if the user will be persisted in the database
* Build the database user starting from authentication informations.
*
* @param authenticationInfo
* authentication info
* @param database
* target database
* @param persistent
* true if the user will be persisted in the database
* @return user bean
*/
public static User buildUser(AuthenticationInfo authenticationInfo, Database database, boolean persistent) {
User user = new User(database, persistent ? database.allocateObjectId() : -1, authenticationInfo.getFullyQualifiedName(), false);
//In case of external authentication fill the password hash with random data
user.setUserPasswordHash( authenticationInfo.getRealm()==null ? authenticationInfo.getConnectionInfo().getUserPasswordHash(): MathUtils.secureRandomBytes(64));
User user = new User(database, persistent ? database.allocateObjectId() : -1,
authenticationInfo.getFullyQualifiedName(), false);
// In case of external authentication fill the password hash with random
// data
user.setUserPasswordHash(
authenticationInfo.getRealm() == null ? authenticationInfo.getConnectionInfo().getUserPasswordHash()
: MathUtils.secureRandomBytes(64));
user.setTemporary(!persistent);
return user;
}
......
......@@ -11,7 +11,6 @@ import org.h2.schema.Sequence;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.value.Value;
import org.h2.value.ValueInt;
import org.h2.value.ValueLong;
/**
......@@ -27,9 +26,9 @@ public class SequenceValue extends Expression {
@Override
public Value getValue(Session session) {
long value = sequence.getNext(session);
session.setLastIdentity(ValueLong.get(value));
return ValueLong.get(value);
ValueLong value = ValueLong.get(sequence.getNext(session));
session.setLastIdentity(value);
return value;
}
@Override
......@@ -59,12 +58,12 @@ public class SequenceValue extends Expression {
@Override
public long getPrecision() {
return ValueInt.PRECISION;
return ValueLong.PRECISION;
}
@Override
public int getDisplaySize() {
return ValueInt.DISPLAY_SIZE;
return ValueLong.DISPLAY_SIZE;
}
@Override
......
......@@ -40,11 +40,10 @@ import org.h2.command.CommandInterface;
import org.h2.engine.ConnectionInfo;
import org.h2.engine.Constants;
import org.h2.engine.Mode;
import org.h2.engine.Mode.ModeEnum;
import org.h2.engine.SessionInterface;
import org.h2.engine.SessionRemote;
import org.h2.engine.SysProperties;
import org.h2.engine.Mode.ModeEnum;
import org.h2.engine.Session;
import org.h2.message.DbException;
import org.h2.message.TraceObject;
import org.h2.result.ResultInterface;
......
......@@ -114,6 +114,7 @@ public class DatabaseInfo implements DatabaseInfoMBean {
return database.isMultiThreaded();
}
@Deprecated
@Override
public boolean isMvcc() {
return database.isMVStore();
......
......@@ -53,6 +53,7 @@ public interface DatabaseInfoMBean {
*
* @return true if MVCC is enabled, false otherwise
*/
@Deprecated
boolean isMvcc();
/**
......
......@@ -2568,7 +2568,7 @@ public class MVStore {
String oldName = getMapName(id);
if (oldName != null && !oldName.equals(newName)) {
String idHexStr = Integer.toHexString(id);
// we need to cope whith the case of previously unfinished rename
// we need to cope with the case of previously unfinished rename
String existingIdHexStr = meta.get("name." + newName);
DataUtils.checkArgument(
existingIdHexStr == null || existingIdHexStr.equals(idHexStr),
......
......@@ -119,7 +119,7 @@ public class MVTable extends TableBase {
*/
private final ArrayDeque<Session> waitingSessions = new ArrayDeque<>();
private final Trace traceLock;
private final AtomicInteger changesUnitlAnalyze;
private final AtomicInteger changesUntilAnalyze;
private int nextAnalyze;
private final boolean containsLargeObject;
private Column rowIdColumn;
......@@ -130,7 +130,7 @@ public class MVTable extends TableBase {
public MVTable(CreateTableData data, MVTableEngine.Store store) {
super(data);
nextAnalyze = database.getSettings().analyzeAuto;
changesUnitlAnalyze = nextAnalyze <= 0 ? null : new AtomicInteger(nextAnalyze);
changesUntilAnalyze = nextAnalyze <= 0 ? null : new AtomicInteger(nextAnalyze);
this.store = store;
this.transactionStore = store.getTransactionStore();
this.isHidden = data.isHidden;
......@@ -714,8 +714,8 @@ public class MVTable extends TableBase {
Index index = indexes.get(i);
index.truncate(session);
}
if (changesUnitlAnalyze != null) {
changesUnitlAnalyze.set(nextAnalyze);
if (changesUntilAnalyze != null) {
changesUntilAnalyze.set(nextAnalyze);
}
}
......@@ -745,12 +745,12 @@ public class MVTable extends TableBase {
}
private void analyzeIfRequired(Session session) {
if (changesUnitlAnalyze != null) {
if (changesUnitlAnalyze.decrementAndGet() == 0) {
if (changesUntilAnalyze != null) {
if (changesUntilAnalyze.decrementAndGet() == 0) {
if (nextAnalyze <= Integer.MAX_VALUE / 2) {
nextAnalyze *= 2;
}
changesUnitlAnalyze.set(nextAnalyze);
changesUntilAnalyze.set(nextAnalyze);
session.markTableForAnalyze(this);
}
}
......
......@@ -149,7 +149,7 @@ public class MVTableEngine implements TableEngine {
* @param builder the builder
* @param encrypted whether the store is encrypted
*/
private void open(Database db, MVStore.Builder builder, boolean encrypted) {
void open(Database db, MVStore.Builder builder, boolean encrypted) {
this.encrypted = encrypted;
try {
this.store = builder.open();
......
......@@ -28,7 +28,7 @@ final class CommitDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
assert decision == null;
if (existingValue == null ||
// map entry was treated as already committed, and then
// it has been removed by another transaction (commited and closed by now )
// it has been removed by another transaction (committed and closed by now)
existingValue.getOperationId() != undoKey) {
// this is not a final undo log entry for this key,
// or map entry was treated as already committed and then
......
......@@ -30,8 +30,8 @@ final class RollbackDecisionMaker extends MVMap.DecisionMaker<Object[]> {
@Override
public MVMap.Decision decide(Object[] existingValue, Object[] providedValue) {
assert decision == null;
// normaly existingValue will always be there except of db initialization
// where some undo log enty was captured on disk but actual map entry was not
// normally existingValue will always be there except of db initialization
// where some undo log entry was captured on disk but actual map entry was not
if (existingValue != null ) {
VersionedValue valueToRestore = (VersionedValue) existingValue[2];
long operationId;
......
......@@ -475,14 +475,19 @@ public class Transaction {
public boolean waitFor(Transaction toWaitFor) {
if (isDeadlocked(toWaitFor)) {
StringBuilder details = new StringBuilder(String.format("Transaction %d has been chosen as a deadlock victim. Details:%n", transactionId));
for(Transaction tx = toWaitFor, nextTx; (nextTx = tx.blockingTransaction) != null; tx = nextTx) {
details.append(String.format("Transaction %d attempts to update map <%s> entry with key <%s> modified by transaction %s%n",
StringBuilder details = new StringBuilder(
String.format("Transaction %d has been chosen as a deadlock victim. Details:%n", transactionId));
for (Transaction tx = toWaitFor, nextTx; (nextTx = tx.blockingTransaction) != null; tx = nextTx) {
details.append(String.format(
"Transaction %d attempts to update map <%s> entry with key <%s> modified by transaction %s%n",
tx.transactionId, tx.blockingMap.getName(), tx.blockingKey, tx.blockingTransaction));
if (nextTx == this) {
details.append(String.format("Transaction %d attempts to update map <%s> entry with key <%s> modified by transaction %s%n",
details.append(String.format(
"Transaction %d attempts to update map <%s> entry with key <%s>"
+ " modified by transaction %s%n",
transactionId, blockingMap.getName(), blockingKey, toWaitFor));
throw DataUtils.newIllegalStateException(DataUtils.ERROR_TRANSACTIONS_DEADLOCK, details.toString());
throw DataUtils.newIllegalStateException(DataUtils.ERROR_TRANSACTIONS_DEADLOCK,
details.toString());
}
}
}
......
......@@ -109,7 +109,7 @@ public class TransactionMap<K, V> {
// Entries describing removals from the map by this transaction and all transactions,
// which are committed but not closed yet,
// and antries about additions to the map by other uncommitted transactions were counted,
// and entries about additions to the map by other uncommitted transactions were counted,
// but they should not contribute into total count.
if (2 * undoLogSize > size) {
// the undo log is larger than half of the map - scan the entries of the map directly
......@@ -130,7 +130,8 @@ public class TransactionMap<K, V> {
}
}
} else {
// The undo logs are much smaller than the map - scan all undo logs, and then lookup relevant map entry.
// The undo logs are much smaller than the map - scan all undo logs,
// and then lookup relevant map entry.
for (MVMap.RootReference undoLogRootReference : undoLogRootReferences) {
if (undoLogRootReference != null) {
Cursor<Long, Object[]> cursor = new Cursor<>(undoLogRootReference.root, null);
......@@ -139,12 +140,15 @@ public class TransactionMap<K, V> {
Object op[] = cursor.getValue();
if ((int) op[0] == map.getId()) {
VersionedValue currentValue = map.get(mapRootPage, op[1]);
// If map entry is not there, then we never counted it, in the first place, so skip it.
// This is possible when undo entry exists because it belongs
// to a committed but not yet closed transaction,
// and it was later deleted by some other already committed and closed transaction.
// If map entry is not there, then we never counted
// it, in the first place, so skip it.
// This is possible when undo entry exists because
// it belongs to a committed but not yet closed
// transaction, and it was later deleted by some
// other already committed and closed transaction.
if (currentValue != null) {
// only the last undo entry for any given map key should be considered
// only the last undo entry for any given map
// key should be considered
long operationId = cursor.getKey();
if (currentValue.getOperationId() == operationId) {
int txId = TransactionStore.getTransactionId(operationId);
......@@ -204,7 +208,8 @@ public class TransactionMap<K, V> {
*/
public V putIfAbsent(K key, V value) {
DataUtils.checkArgument(value != null, "The value may not be null");
TxDecisionMaker decisionMaker = new TxDecisionMaker.PutIfAbsentDecisionMaker(map.getId(), key, value, transaction);
TxDecisionMaker decisionMaker = new TxDecisionMaker.PutIfAbsentDecisionMaker(map.getId(), key, value,
transaction);
return set(key, decisionMaker);
}
......@@ -275,8 +280,10 @@ public class TransactionMap<K, V> {
} while (blockingTransaction.sequenceNum > sequenceNumWhenStarted || transaction.waitFor(blockingTransaction));
throw DataUtils.newIllegalStateException(DataUtils.ERROR_TRANSACTION_LOCKED,
"Map entry <{0}> with key <{1}> and value {2} is locked by tx {3} and can not be updated by tx {4} within allocated time interval {5} ms.",
map.getName(), key, result, blockingTransaction.transactionId, transaction.transactionId, transaction.timeoutMillis);
"Map entry <{0}> with key <{1}> and value {2} is locked by tx {3} and can not be updated by tx {4}"
+ " within allocated time interval {5} ms.",
map.getName(), key, result, blockingTransaction.transactionId, transaction.transactionId,
transaction.timeoutMillis);
}
/**
......@@ -319,7 +326,8 @@ public class TransactionMap<K, V> {
*/
public boolean trySet(K key, V value) {
try {
// TODO: effective transaction.timeoutMillis should be set to 0 here and restored before return
// TODO: effective transaction.timeoutMillis should be set to 0 here
// and restored before return
// TODO: eliminate exception usage as part of normal control flaw
set(key, value);
return true;
......
......@@ -89,7 +89,7 @@ public class TransactionStore {
private final AtomicReferenceArray<Transaction> transactions =
new AtomicReferenceArray<>(MAX_OPEN_TRANSACTIONS + 1);
private static final String UNDO_LOG_NAME_PEFIX = "undoLog";
private static final String UNDO_LOG_NAME_PREFIX = "undoLog";
private static final char UNDO_LOG_COMMITTED = '-'; // must come before open in lexicographical order
private static final char UNDO_LOG_OPEN = '.';
......@@ -101,7 +101,7 @@ public class TransactionStore {
public static String getUndoLogName(boolean committed, int transactionId) {
return UNDO_LOG_NAME_PEFIX +
return UNDO_LOG_NAME_PREFIX +
(committed ? UNDO_LOG_COMMITTED : UNDO_LOG_OPEN) +
(transactionId > 0 ? String.valueOf(transactionId) : "");
}
......@@ -120,7 +120,7 @@ public class TransactionStore {
*
* @param store the store
* @param dataType the data type for map keys and values
* @param timeoutMillis lock aquisition timeout in milliseconds, 0 means no wait
* @param timeoutMillis lock acquisition timeout in milliseconds, 0 means no wait
*/
public TransactionStore(MVStore store, DataType dataType, int timeoutMillis) {
this.store = store;
......@@ -143,10 +143,10 @@ public class TransactionStore {
public void init() {
if (!init) {
for (String mapName : store.getMapNames()) {
if (mapName.startsWith(UNDO_LOG_NAME_PEFIX)) {
boolean committed = mapName.charAt(UNDO_LOG_NAME_PEFIX.length()) == UNDO_LOG_COMMITTED;
if (mapName.startsWith(UNDO_LOG_NAME_PREFIX)) {
boolean committed = mapName.charAt(UNDO_LOG_NAME_PREFIX.length()) == UNDO_LOG_COMMITTED;
if (store.hasData(mapName) || committed) {
int transactionId = Integer.parseInt(mapName.substring(UNDO_LOG_NAME_PEFIX.length() + 1));
int transactionId = Integer.parseInt(mapName.substring(UNDO_LOG_NAME_PREFIX.length() + 1));
VersionedBitSet openTxBitSet = openTransactions.get();
if (!openTxBitSet.get(transactionId)) {
Object[] data = preparedTransactions.get(transactionId);
......@@ -168,7 +168,8 @@ public class TransactionStore {
assert committed || lastUndoKey != null;
assert committed || getTransactionId(lastUndoKey) == transactionId;
long logId = lastUndoKey == null ? 0 : getLogId(lastUndoKey) + 1;
registerTransaction(transactionId, status, name, logId, timeoutMillis, 0, RollbackListener.NONE);
registerTransaction(transactionId, status, name, logId, timeoutMillis, 0,
RollbackListener.NONE);
}
}
}
......
......@@ -49,10 +49,11 @@ public abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue
logIt(existingValue.value == null ? null : VersionedValue.getInstance(existingValue.value));
decision = MVMap.Decision.PUT;
} else if(fetchTransaction(blockingId) == null) {
// condition above means transaction has been committed/rplled back and closed by now
// condition above means transaction has been committed/rolled back and closed by now
decision = MVMap.Decision.REPEAT;
} else {
// this entry comes from a different transaction, and this transaction is not committed yet
// this entry comes from a different transaction, and this
// transaction is not committed yet
// should wait on blockingTransaction that was determined earlier
decision = MVMap.Decision.ABORT;
}
......
......@@ -11,8 +11,9 @@ import java.util.BitSet;
* Class VersionedBitSet extends standard BitSet to add a version field.
* This will allow bit set and version to be changed atomically.
*/
final class VersionedBitSet extends BitSet
{
final class VersionedBitSet extends BitSet {
private static final long serialVersionUID = 1L;
private long version;
public VersionedBitSet() {}
......
......@@ -35,7 +35,7 @@ public class VersionedValue {
return new Uncommitted(operationId, value, committedValue);
}
private VersionedValue(Object value) {
VersionedValue(Object value) {
this.value = value;
}
......
......@@ -174,6 +174,7 @@
90141=#Serializer cannot be changed because there is a data table: {0}
90142=#Step size must not be zero
90143=#Row {1} not found in primary index {0}
90144=#Authenticator not enabled on database {0}
HY000=Obecná chyba: {0}
HY004=Neznámý datový typ: {0}
HYC00=Vlastnost není podporována: {0}
......
......@@ -174,6 +174,7 @@
90141=Serialisierer kann nicht geändert werden wenn eine Daten-Tabelle existiert: {0}
90142=Schrittgrösse darf nicht 0 sein
90143=#Row {1} not found in primary index {0}
90144=#Authenticator not enabled on database {0}
HY000=Allgemeiner Fehler: {0}
HY004=Unbekannter Datentyp: {0}
HYC00=Dieses Feature wird nicht unterstützt: {0}
......
......@@ -174,6 +174,7 @@
90141=#Serializer cannot be changed because there is a data table: {0}
90142=#Step size must not be zero
90143=#Row {1} not found in primary index {0}
90144=#Authenticator not enabled on database {0}
HY000=Error General : {0}
HY004=Tipo de dato desconocido : {0}
HYC00=Caracteristica no soportada: {0}
......
......@@ -174,6 +174,7 @@
90141=Le sérialiseur ne peut être changé parce que il y a des données dans la table: {0}
90142=La taille de l'étape ne doit pas être de 0
90143=#Row {1} not found in primary index {0}
90144=#Authenticator not enabled on database {0}
HY000=Erreur générale: {0}
HY004=Type de données inconnu: {0}
HYC00=Fonctionnalité non supportée: {0}
......
......@@ -174,6 +174,7 @@
90141=データテーブル {0} があるため、シリアライザを変更することはできません
90142=ステップサイズに0は指定できません
90143=#Row {1} not found in primary index {0}
90144=#Authenticator not enabled on database {0}
HY000=一般エラー: {0}
HY004=不明なデータ型: {0}
HYC00=機能はサポートされていません: {0}
......
......@@ -174,6 +174,7 @@
90141=Serializator nie może być zmieniony ponieważ istnieje tabela z danymi: {0}
90142=#Step size must not be zero
90143=#Row {1} not found in primary index {0}
90144=#Authenticator not enabled on database {0}
HY000=Błąd ogólny: {0}
HY004=Nieznany typ danych: {0}
HYC00=Cecha nie jest wspierana: {0}
......
......@@ -174,6 +174,7 @@
90141=#Serializer cannot be changed because there is a data table: {0}
90142=#Step size must not be zero
90143=#Row {1} not found in primary index {0}
90144=#Authenticator not enabled on database {0}
HY000=Erro geral: {0}
HY004=Tipo de dados desconhecido: {0}
HYC00=Recurso não suportado: {0}
......
......@@ -174,6 +174,7 @@
90141=Serializer не может быть изменен, потому что есть таблица данных: {0}
90142=Размер шага не должен быть равен нулю
90143=Строка {1} не найдена в первичном индексе {0}
90144=Внешняя аутентификация не включена в базе данных {0}
HY000=Внутренняя ошибка: {0}
HY004=Неизвестный тип данных: {0}
HYC00=Данная функция не поддерживается: {0}
......
......@@ -174,6 +174,7 @@
90141=#Serializer cannot be changed because there is a data table: {0}
90142=#Step size must not be zero
90143=#Row {1} not found in primary index {0}
90144=#Authenticator not enabled on database {0}
HY000=Všeobecná chyba: {0}
HY004=Neznámy dátový typ: {0}
HYC00=Vlastnosť nie je podporovaná: {0}
......
......@@ -174,6 +174,7 @@
90141=#Serializer cannot be changed because there is a data table: {0}
90142=#Step size must not be zero
90143=#Row {1} not found in primary index {0}
90144=#Authenticator not enabled on database {0}
HY000=常规错误: {0}
HY004=位置数据类型: {0}
HYC00=不支持的特性: {0}
......
......@@ -10,6 +10,7 @@ package org.h2.security.auth;
*
*/
public class AuthConfigException extends RuntimeException {
private static final long serialVersionUID = 1L;
public AuthConfigException() {
super();
......
......@@ -9,6 +9,7 @@ package org.h2.security.auth;
* Exception thrown in case of errors during authentication
*/
public class AuthenticationException extends Exception {
private static final long serialVersionUID = 1L;
public AuthenticationException() {
super();
......
......@@ -27,8 +27,8 @@ public class AuthenticationInfo {
public AuthenticationInfo(ConnectionInfo connectionInfo) {
this.connectionInfo = connectionInfo;
this.realm = connectionInfo.getProperty("AUTHREALM", null);
if (this.realm!=null) {
this.realm=StringUtils.toUpperEnglish(this.realm);
if (this.realm != null) {
this.realm = StringUtils.toUpperEnglish(this.realm);
}
this.password = connectionInfo.getProperty("AUTHZPWD", null);
}
......@@ -50,15 +50,16 @@ public class AuthenticationInfo {
}
public String getFullyQualifiedName() {
if (realm==null) {
if (realm == null) {
return connectionInfo.getUserName();
} else {
return connectionInfo.getUserName()+"@"+realm;
return connectionInfo.getUserName() + "@" + realm;
}
}
/**
* get nested identity
*
* @return
*/
public Object getNestedIdentity() {
......@@ -66,8 +67,11 @@ public class AuthenticationInfo {
}
/**
* Method used by authenticators to hold informations about authenticated user
* @param nestedIdentity = nested identity object
* Method used by authenticators to hold informations about authenticated
* user
*
* @param nestedIdentity
* = nested identity object
*/
public void setNestedIdentity(Object nestedIdentity) {
this.nestedIdentity = nestedIdentity;
......
......@@ -9,25 +9,27 @@ import org.h2.engine.Database;
import org.h2.engine.User;
/**
* Low level interface to implement full authentication process
* Low level interface to implement full authentication process.
*/
public interface Authenticator {
/**
* perform user authentication
* Perform user authentication.
*
* @param authenticationInfo
* @param database
* @return valid database user or null if user doesn't exists in the database
* @return valid database user or null if user doesn't exists in the
* database
* @throws AuthenticationException
*/
User authenticate(AuthenticationInfo authenticationInfo, Database database) throws AuthenticationException;
/**
* Initialize the authenticator. This method is invoked by databases when the authenticator is set
* when the authenticator is set.
* @param database = target database
* Initialize the authenticator. This method is invoked by databases when
* the authenticator is set when the authenticator is set.
*
* @param database
* target database
* @throws AuthConfigException
*/
void init(Database database) throws AuthConfigException;
......
......@@ -23,16 +23,16 @@ public class ConfigProperties {
properties = new HashMap<>();
}
public ConfigProperties(PropertyConfig...configProperties) {
this(configProperties==null?null:Arrays.asList(configProperties));
public ConfigProperties(PropertyConfig... configProperties) {
this(configProperties == null ? null : Arrays.asList(configProperties));
}
public ConfigProperties(Collection<PropertyConfig> configProperties) {
properties = new HashMap<>();
if (properties != null) {
for (PropertyConfig currentProperty : configProperties) {
if (properties.put(currentProperty.getName(), currentProperty.getValue())!=null) {
throw new AuthConfigException("duplicate property "+currentProperty.getName());
if (properties.put(currentProperty.getName(), currentProperty.getValue()) != null) {
throw new AuthConfigException("duplicate property " + currentProperty.getName());
}
}
}
......@@ -49,7 +49,7 @@ public class ConfigProperties {
public String getStringValue(String name) {
String result = properties.get(name);
if (result == null) {
throw new AuthConfigException("missing config property "+name);
throw new AuthConfigException("missing config property " + name);
}
return result;
}
......@@ -65,7 +65,7 @@ public class ConfigProperties {
public int getIntValue(String name) {
String result = properties.get(name);
if (result == null) {
throw new AuthConfigException("missing config property "+name);
throw new AuthConfigException("missing config property " + name);
}
return Integer.parseInt(result);
}
......
......@@ -33,8 +33,8 @@ import org.h2.util.StringUtils;
* Default authenticator implementation.
* <p>
* When client connectionInfo contains property AUTHREALM={realName} credentials
* (typically user id and password) are validated by
* by {@link org.h2.api.CredentialsValidator} configured for that realm.
* (typically user id and password) are validated by by
* {@link org.h2.api.CredentialsValidator} configured for that realm.
* </p>
* <p>
* When client connectionInfo doesn't contains AUTHREALM property credentials
......@@ -44,8 +44,9 @@ import org.h2.util.StringUtils;
* Rights assignment can be managed through {@link org.h2.api.UserToRolesMapper}
* </p>
* <p>
* Default configuration has a realm H2 that validate credentials through JAAS api (appName=h2).
* To customize configuration set h2.authConfigFile system property to refer a valid h2auth.xml config file
* Default configuration has a realm H2 that validate credentials through JAAS
* api (appName=h2). To customize configuration set h2.authConfigFile system
* property to refer a valid h2auth.xml config file
* </p>
*/
public class DefaultAuthenticator implements Authenticator {
......@@ -69,8 +70,8 @@ public class DefaultAuthenticator implements Authenticator {
private static DefaultAuthenticator instance;
protected static final DefaultAuthenticator getInstance() {
if (instance==null) {
instance= new DefaultAuthenticator();
if (instance == null) {
instance = new DefaultAuthenticator();
}
return instance;
}
......@@ -119,8 +120,8 @@ public class DefaultAuthenticator implements Authenticator {
}
/**
* When set create roles not found in the database. If not set roles not found
* in the database are silently skipped
* When set create roles not found in the database. If not set roles not
* found in the database are silently skipped
*
* @return
*/
......@@ -135,8 +136,10 @@ public class DefaultAuthenticator implements Authenticator {
/**
* Add an authentication realm. Realms are case insensitive
*
* @param name realm name
* @param credentialsValidator credentials validator for realm
* @param name
* realm name
* @param credentialsValidator
* credentials validator for realm
*/
public void addRealm(String name, CredentialsValidator credentialsValidator) {
realms.put(StringUtils.toUpperEnglish(name), credentialsValidator);
......@@ -160,17 +163,20 @@ public class DefaultAuthenticator implements Authenticator {
}
/**
* Initializes the authenticator (it is called by AuthententicationManager)
* Initializes the authenticator.
*
* this method is skipped if skipDefaultInitialization is set
* Order of initialization is
* this method is skipped if skipDefaultInitialization is set Order of
* initialization is
* <ol>
* <li>Check h2.authConfigFile system property.</li>
* <li>Use the default configuration hard coded</li>
* </ol>
* @param database where authenticator is initialized
*
* @param database
* where authenticator is initialized
* @throws AuthConfigException
*/
@Override
public void init(Database database) throws AuthConfigException {
if (skipDefaultInitialization) {
return;
......@@ -182,13 +188,14 @@ public class DefaultAuthenticator implements Authenticator {
if (initialized) {
return;
}
Trace trace=database.getTrace(Trace.DATABASE);
Trace trace = database.getTrace(Trace.DATABASE);
URL h2AuthenticatorConfigurationUrl = null;
try {
String configFile = SysProperties.AUTH_CONFIG_FILE;
if (configFile != null) {
if (trace.isDebugEnabled()) {
trace.debug("DefaultAuthenticator.config: configuration read from system property h2auth.configurationfile={0}", configFile);
trace.debug("DefaultAuthenticator.config: configuration read from system property"
+ " h2auth.configurationfile={0}", configFile);
}
h2AuthenticatorConfigurationUrl = new URL(configFile);
}
......@@ -201,11 +208,12 @@ public class DefaultAuthenticator implements Authenticator {
configureFromUrl(h2AuthenticatorConfigurationUrl);
}
} catch (Exception e) {
trace.error(e, "DefaultAuthenticator.config: an error occurred during configuration from {0} ", h2AuthenticatorConfigurationUrl);
throw new AuthConfigException("Failed to configure authentication from " + h2AuthenticatorConfigurationUrl,
e);
trace.error(e, "DefaultAuthenticator.config: an error occurred during configuration from {0} ",
h2AuthenticatorConfigurationUrl);
throw new AuthConfigException(
"Failed to configure authentication from " + h2AuthenticatorConfigurationUrl, e);
}
initialized=true;
initialized = true;
}
}
......@@ -224,7 +232,8 @@ public class DefaultAuthenticator implements Authenticator {
/**
* Configure the authenticator from a configuration file
*
* @param configUrl URL of configuration file
* @param configUrl
* URL of configuration file
* @throws Exception
*/
public void configureFromUrl(URL configUrl) throws Exception {
......
......@@ -25,9 +25,10 @@ public class PropertyConfig {
}
public PropertyConfig(String name, String value) {
this.name=name;
this.value=value;
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
......
......@@ -13,6 +13,9 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
/**
* Configuration for authentication realm.
*/
@XmlAccessorType(XmlAccessType.FIELD)
public class RealmConfig {
......
......@@ -13,6 +13,9 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
/**
* Configuration for class that maps users to roles.
*/
@XmlAccessorType(XmlAccessType.FIELD)
public class UserToRolesMapperConfig {
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: Alessandro Ventura
*/
package org.h2.security.auth.impl;
import java.util.Arrays;
......
......@@ -75,7 +75,8 @@ public class JaasCredentialsValidator implements CredentialsValidator {
@Override
public boolean validateCredentials(AuthenticationInfo authenticationInfo) throws Exception {
LoginContext loginContext = new LoginContext(appName,new AuthenticationInfoCallbackHandler(authenticationInfo));
LoginContext loginContext = new LoginContext(appName,
new AuthenticationInfoCallbackHandler(authenticationInfo));
loginContext.login();
authenticationInfo.setNestedIdentity(loginContext.getSubject());
return true;
......
......@@ -21,9 +21,10 @@ import org.h2.security.auth.ConfigProperties;
* Configuration parameters:
* </p>
* <ul>
* <li>bindDnPattern bind dn pattern with %u instead of username (example: uid=%u,ou=users,dc=example,dc=com)</li>
* <li>bindDnPattern bind dn pattern with %u instead of username
* (example: uid=%u,ou=users,dc=example,dc=com)</li>
* <li>host ldap server</li>
* <li>port of ldap service; optional, by default 389 for unsecure, 636 for secure</li>
* <li>port of ldap service; optional, by default 389 for insecure, 636 for secure</li>
* <li>secure, optional by default is true (use SSL)</li>
* </ul>
*/
......
/*
* Copyright 2004-2018 H2 Group. Mul tiple-Licensed under the MPL 2.0,
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: Alessandro Ventura
*/
......@@ -41,7 +41,6 @@ public class StaticUserCredentialsValidator implements CredentialsValidator {
@Override
public boolean validateCredentials(AuthenticationInfo authenticationInfo) throws AuthenticationException {
if (userNamePattern!=null) {
if (!userNamePattern.matcher(authenticationInfo.getUserName()).matches()) {
return false;
......@@ -50,14 +49,15 @@ public class StaticUserCredentialsValidator implements CredentialsValidator {
if (password!=null) {
return password.equals(authenticationInfo.getPassword());
}
return Utils.compareSecure(hashWithSalt,SHA256.getHashWithSalt(authenticationInfo.getPassword().getBytes(), salt));
return Utils.compareSecure(hashWithSalt,
SHA256.getHashWithSalt(authenticationInfo.getPassword().getBytes(), salt));
}
@Override
public void configure(ConfigProperties configProperties) {
String userNamePatternString=configProperties.getStringValue("userNamePattern",null);
if (userNamePatternString!=null) {
userNamePattern=userNamePattern.compile(userNamePatternString);
userNamePattern = Pattern.compile(userNamePatternString);
}
password=configProperties.getStringValue("password",password);
String saltString =configProperties.getStringValue("salt",null);
......
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0, Version 1.0,
and under the Eclipse Public License, Version 1.0
Initial Developer: H2 Group
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
Javadoc package documentation
</title></head><body style="font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;"><p>
Authentication classes.
</p></body></html>
\ No newline at end of file
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0, Version 1.0,
and under the Eclipse Public License, Version 1.0
Initial Developer: H2 Group
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
Javadoc package documentation
</title></head><body style="font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;"><p>
Authentication classes.
</p></body></html>
\ No newline at end of file
......@@ -1072,8 +1072,8 @@ public class MetaTable extends Table {
Long.toString(fs.getWriteCount()));
add(rows, "info.FILE_READ",
Long.toString(fs.getReadCount()));
int updateFailureRatio = (int)(10000 * mvStore.getStore().getUpdateFailureRatio());
add(rows, "info.UPDATE_FAILURE_PERCENT", "" + updateFailureRatio / 100 + "." + updateFailureRatio % 100 + "%");
add(rows, "info.UPDATE_FAILURE_PERCENT",
String.format(Locale.ENGLISH, "%.2f%%", 100 * mvStore.getStore().getUpdateFailureRatio()));
long size;
try {
size = fs.getFile().size();
......
......@@ -510,7 +510,8 @@ public abstract class Table extends SchemaObjectBase {
try {
removeRow(session, o);
} catch (DbException e) {
if (e.getErrorCode() == ErrorCode.CONCURRENT_UPDATE_1 || e.getErrorCode() == ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1) {
if (e.getErrorCode() == ErrorCode.CONCURRENT_UPDATE_1
|| e.getErrorCode() == ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1) {
session.rollbackTo(rollback, false);
session.startStatementWithinTransaction();
rollback = session.setSavepoint();
......
......@@ -31,6 +31,9 @@ import org.h2.security.auth.impl.StaticRolesMapper;
import org.h2.security.auth.impl.StaticUserCredentialsValidator;
import org.h2.test.TestBase;
/**
* Test for custom authentication.
*/
public class TestAuthentication extends TestBase {
public static void main(String... a) throws Exception {
......@@ -123,7 +126,7 @@ public class TestAuthentication extends TestBase {
protected void allTests() throws Exception {
testInvalidPassword();
testExternalUserWihoutRealm();
testExternalUserWithoutRealm();
testExternalUser();
testAssignRealNameRole();
testStaticRole();
......@@ -143,7 +146,7 @@ public class TestAuthentication extends TestBase {
}
}
protected void testExternalUserWihoutRealm() throws Exception {
protected void testExternalUserWithoutRealm() throws Exception {
try {
Connection wrongLoginConnection = DriverManager.getConnection(getDatabaseURL(), getExternalUser(),
getExternalUserPassword());
......@@ -221,7 +224,8 @@ public class TestAuthentication extends TestBase {
try {
try {
Connection wrongLoginConnection = DriverManager.getConnection(
getDatabaseURL() + ";AUTHREALM=" + getRealmName().toUpperCase(), "___" + getExternalUser(), "");
getDatabaseURL() + ";AUTHREALM=" + getRealmName().toUpperCase(), "___" + getExternalUser(),
"");
wrongLoginConnection.close();
throw new Exception(
"unregistered external users should not be able to login when allowUserRegistration=false");
......@@ -261,8 +265,8 @@ public class TestAuthentication extends TestBase {
try {
try {
testExternalUser();
throw new Exception("External user shouldnt be allowed");
}catch (Exception e) {
throw new Exception("External user shouldn't be allowed");
} catch (Exception e) {
}
} finally {
configureAuthentication(database);
......
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0, Version 1.0,
and under the Eclipse Public License, Version 1.0
Initial Developer: H2 Group
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
Javadoc package documentation
</title></head><body style="font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;"><p>
Tests for custom authentication.
</p></body></html>
\ No newline at end of file
......@@ -17,6 +17,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import org.h2.message.TraceSystem;
import org.h2.store.FileLister;
import org.h2.test.TestBase;
......@@ -297,6 +298,11 @@ public class TestBigResult extends TestBase {
}
private void testLOB() throws SQLException {
if (config.traceLevelFile == TraceSystem.DEBUG) {
// Trace system on this level can throw OOME with such large
// arguments as used in this test.
return;
}
deleteDb("bigResult");
Connection conn = getConnection("bigResult");
Statement stat = conn.createStatement();
......
......@@ -66,7 +66,6 @@ public class TestMvcc4 extends TestBase {
c1.setAutoCommit(false);
//Fire off a concurrent update.
final Thread mainThread = Thread.currentThread();
final CountDownLatch executedUpdate = new CountDownLatch(1);
new Thread() {
@Override
......@@ -83,7 +82,8 @@ public class TestMvcc4 extends TestBase {
executedUpdate.countDown();
// interrogate new "blocker_id" metatable field instead of
// relying on stacktraces!? to determine when session is blocking
PreparedStatement stmt = c2.prepareStatement("SELECT * FROM INFORMATION_SCHEMA.SESSIONS WHERE BLOCKER_ID = SESSION_ID()");
PreparedStatement stmt = c2.prepareStatement(
"SELECT * FROM INFORMATION_SCHEMA.SESSIONS WHERE BLOCKER_ID = SESSION_ID()");
ResultSet resultSet;
do {
resultSet = stmt.executeQuery();
......
......@@ -39,7 +39,7 @@ public class TestMvccMultiThreaded2 extends TestBase {
test.test();
}
private int getTestDuration() {
int getTestDuration() {
// to save some testing time
return config.big ? TEST_TIME_SECONDS : TEST_TIME_SECONDS / 10;
}
......
......@@ -299,7 +299,8 @@ public class TestScript extends TestBase {
private void process(String sql, boolean allowReconnect) throws Exception {
if (allowReconnect && reconnectOften) {
if (!containsTempTables() && ((JdbcConnection) conn).isRegularMode() && conn.getSchema().equals("PUBLIC")) {
if (!containsTempTables() && ((JdbcConnection) conn).isRegularMode()
&& conn.getSchema().equals("PUBLIC")) {
boolean autocommit = conn.getAutoCommit();
if (autocommit && random.nextInt(10) < 1) {
// reconnect 10% of the time
......
......@@ -404,7 +404,7 @@ public class TestTransactionStore extends TestBase {
}
}
// re-open TransactionStore, because we rolled back
// underlying MVStore without rolling back TranactionStore
// underlying MVStore without rolling back TransactionStore
s.close();
s = MVStore.open(fileName);
ts = new TransactionStore(s);
......
......@@ -86,7 +86,6 @@ public class TestCrashAPI extends TestBase implements Runnable {
}
@Override
@SuppressWarnings("deprecation")
public void run() {
while (--maxWait > 0) {
try {
......@@ -103,11 +102,11 @@ public class TestCrashAPI extends TestBase implements Runnable {
if (maxWait == 0 && running) {
objects.clear();
if (running) {
println("stopping (force)...");
println("stopping (trying to interrupt)...");
for (StackTraceElement e : mainThread.getStackTrace()) {
System.out.println(e.toString());
}
mainThread.stop(new SQLException("stop"));
mainThread.interrupt();
}
}
}
......
......@@ -777,4 +777,9 @@ geometries sourceschema destschema generatedcolumn alphanumerically usages
sizable instantiates renders sdt txcommit unhelpful optimiser treats rejects referring untrusted computes vacate inverted
reordered colliding evgenij archaic invocations apostrophe hypothetically testref ryazanov useless completes highlighting tends degrade
summands minuend subtrahend
summands minuend subtrahend localtime localtimestamp governs unfinished pressure closure discovered victim seemingly
flaw capture coherent removals silence opentransactions picture tokar mailto andrei dur discarded blocker captures txdm
intentionally authenticator authrealm ventura credentials alessandro validator acquisition vital mariadb preventing
ewkt ewkb informations authzpwd realms mappers jaxb realmname configurationfile unmarshal jaas externals customize
authenticators appname interrogate metatable barrier preliminary staticuser staticpassword unregistered inquiry
ldapexample remoteuser assignments djava validators mock relate mapid tighten
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论