Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
b940440b
提交
b940440b
authored
5月 27, 2018
作者:
andrei
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'h2database/master' into txcommit-atomic
上级
a4640445
47ff9145
隐藏空白字符变更
内嵌
并排
正在显示
41 个修改的文件
包含
1931 行增加
和
122 行删除
+1931
-122
help.csv
h2/src/docsrc/help/help.csv
+41
-13
features.html
h2/src/docsrc/html/features.html
+75
-0
CredentialsValidator.java
h2/src/main/org/h2/api/CredentialsValidator.java
+28
-0
ErrorCode.java
h2/src/main/org/h2/api/ErrorCode.java
+14
-1
UserToRolesMapper.java
h2/src/main/org/h2/api/UserToRolesMapper.java
+31
-0
Command.java
h2/src/main/org/h2/command/Command.java
+2
-2
CommandContainer.java
h2/src/main/org/h2/command/CommandContainer.java
+3
-2
CommandList.java
h2/src/main/org/h2/command/CommandList.java
+4
-2
Parser.java
h2/src/main/org/h2/command/Parser.java
+80
-84
MergeUsing.java
h2/src/main/org/h2/command/dml/MergeUsing.java
+0
-10
Set.java
h2/src/main/org/h2/command/dml/Set.java
+21
-0
SetTypes.java
h2/src/main/org/h2/command/dml/SetTypes.java
+7
-1
ConnectionInfo.java
h2/src/main/org/h2/engine/ConnectionInfo.java
+13
-2
Database.java
h2/src/main/org/h2/engine/Database.java
+24
-0
Engine.java
h2/src/main/org/h2/engine/Engine.java
+25
-4
RightOwner.java
h2/src/main/org/h2/engine/RightOwner.java
+23
-0
SysProperties.java
h2/src/main/org/h2/engine/SysProperties.java
+10
-0
UserBuilder.java
h2/src/main/org/h2/engine/UserBuilder.java
+23
-0
_messages_en.prop
h2/src/main/org/h2/res/_messages_en.prop
+1
-0
AuthConfigException.java
h2/src/main/org/h2/security/auth/AuthConfigException.java
+29
-0
AuthenticationException.java
...rc/main/org/h2/security/auth/AuthenticationException.java
+29
-0
AuthenticationInfo.java
h2/src/main/org/h2/security/auth/AuthenticationInfo.java
+82
-0
Authenticator.java
h2/src/main/org/h2/security/auth/Authenticator.java
+34
-0
AuthenticatorFactory.java
h2/src/main/org/h2/security/auth/AuthenticatorFactory.java
+16
-0
ConfigProperties.java
h2/src/main/org/h2/security/auth/ConfigProperties.java
+81
-0
Configurable.java
h2/src/main/org/h2/security/auth/Configurable.java
+17
-0
DefaultAuthenticator.java
h2/src/main/org/h2/security/auth/DefaultAuthenticator.java
+339
-0
H2AuthConfig.java
h2/src/main/org/h2/security/auth/H2AuthConfig.java
+73
-0
PropertyConfig.java
h2/src/main/org/h2/security/auth/PropertyConfig.java
+46
-0
RealmConfig.java
h2/src/main/org/h2/security/auth/RealmConfig.java
+51
-0
UserToRolesMapperConfig.java
...rc/main/org/h2/security/auth/UserToRolesMapperConfig.java
+40
-0
AssignRealmNameRole.java
...c/main/org/h2/security/auth/impl/AssignRealmNameRole.java
+43
-0
JaasCredentialsValidator.java
...n/org/h2/security/auth/impl/JaasCredentialsValidator.java
+84
-0
LdapCredentialsValidator.java
...n/org/h2/security/auth/impl/LdapCredentialsValidator.java
+72
-0
StaticRolesMapper.java
h2/src/main/org/h2/security/auth/impl/StaticRolesMapper.java
+51
-0
StaticUserCredentialsValidator.java
...h2/security/auth/impl/StaticUserCredentialsValidator.java
+73
-0
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+2
-0
MyLoginModule.java
h2/src/test/org/h2/test/auth/MyLoginModule.java
+61
-0
TestAuthentication.java
h2/src/test/org/h2/test/auth/TestAuthentication.java
+256
-0
TestMergeUsing.java
h2/src/test/org/h2/test/db/TestMergeUsing.java
+1
-1
mergeUsing.sql
h2/src/test/org/h2/test/scripts/dml/mergeUsing.sql
+26
-0
没有找到文件。
h2/src/docsrc/help/help.csv
浏览文件 @
b940440b
...
...
@@ -45,11 +45,7 @@ SELECT * FROM (SELECT ID, COUNT(*) FROM TEST
"
"Commands (DML)","INSERT","
INSERT INTO tableName
{ [ ( columnName [,...] ) ]
{ VALUES { ( { DEFAULT | expression } [,...] ) } [,...]
| [ DIRECT ] [ SORTED ] select } } |
{ SET { columnName = { DEFAULT | expression } } [,...] }
INSERT INTO tableName insertColumnsAndSource
","
Inserts a new row / new rows into a table.
...
...
@@ -61,9 +57,7 @@ INSERT INTO TEST VALUES(1, 'Hello')
"
"Commands (DML)","UPDATE","
UPDATE tableName [ [ AS ] newTableAlias ] SET
{ { columnName = { DEFAULT | expression } } [,...] } |
{ ( columnName [,...] ) = ( select ) }
UPDATE tableName [ [ AS ] newTableAlias ] SET setClauseList
[ WHERE expression ] [ ORDER BY order [,...] ] [ LIMIT expression ]
","
Updates data in a table.
...
...
@@ -74,7 +68,7 @@ UPDATE PERSON P SET NAME=(SELECT A.NAME FROM ADDRESS A WHERE A.ID=P.ID);
"
"Commands (DML)","DELETE","
DELETE [ TOP term ] FROM tableName
[ WHERE expression ] [ LIMIT term ]
DELETE [ TOP term ] FROM tableName
deleteSearchCondition
","
Deletes rows form a table.
If TOP or LIMIT is specified, at most the specified number of rows are deleted (no limit if null or smaller than zero).
...
...
@@ -129,16 +123,19 @@ MERGE INTO TEST KEY(ID) VALUES(2, 'World')
MERGE INTO targetTableName [ [AS] targetAlias]
USING { ( select ) | sourceTableName }[ [AS] sourceAlias ]
ON ( expression )
[ WHEN MATCHED THEN [ update ] [ delete] ]
[ WHEN NOT MATCHED THEN insert ]
[ WHEN MATCHED THEN
[ UPDATE SET setClauseList ] [ DELETE deleteSearchCondition ] ]
[ WHEN NOT MATCHED THEN INSERT insertColumnsAndSource ]
","
Updates or deletes existing rows, and insert rows that don't exist. The ON clause
specifies the matching column expression and must be specified. If more than one row
is updated per input row, an exception is thrown.
If the source data contains duplicate rows (specifically those columns used in the
row matching ON clause), then an exception is thrown to prevent two updates applying
to the same target row. The embedded update, delete or insert statements can not re-specify
the target table name.
to the same target row.
WHEN MATCHED THEN or WHEN NOT MATCHED THEN clauses or both of them in any order should be specified.
If WHEN MATCHED THEN is specified it should contain UPDATE or DELETE clauses of both of them.
If statement doesn't need a source table a DUAL table can be substituted.
","
MERGE INTO TARGET_TABLE AS T USING SOURCE_TABLE AS S
ON (T.ID = S.ID)
...
...
@@ -154,6 +151,9 @@ MERGE INTO TARGET_TABLE AS T USING (SELECT * FROM SOURCE_TABLE) AS S
DELETE WHERE T.COL2='FINAL'
WHEN NOT MATCHED THEN
INSERT (ID,COL1,COL2) VALUES(S.ID,S.COL1,S.COL2)
MERGE INTO TARGET_TABLE USING DUAL ON (ID = 1)
WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (1, 'Test')
WHEN MATCHED THEN UPDATE SET NAME = 'Test'
"
"Commands (DML)","RUNSCRIPT","
...
...
@@ -2252,6 +2252,14 @@ SELECT CAST(0 AS DOUBLE)
SELECT -1.4e-10
"
"Other Grammar","Delete search condition","
[ WHERE expression ] [ LIMIT term ]
","
Search condition for DELETE statement.
","
WHERE ID = 2
"
"Other Grammar","Digit","
0-9
","
...
...
@@ -2313,6 +2321,17 @@ the column in the same way.
NAME
"
"Other Grammar","Insert columns and source","
{ [ ( columnName [,...] ) ]
{ VALUES { ( { DEFAULT | expression } [,...] ) } [,...]
| [ DIRECT ] [ SORTED ] select } } |
{ SET { columnName = { DEFAULT | expression } } [,...] }
","
Names of columns and their values for INSERT statement.
","
(ID, NAME) VALUES (1, 'Test')
"
"Other Grammar","Int","
[ + | - ] number
","
...
...
@@ -2438,6 +2457,15 @@ An expression in a SELECT statement.
ID AS VALUE
"
"Other Grammar","Set clause list","
{ { columnName = { DEFAULT | expression } } [,...] } |
{ ( columnName [,...] ) = ( select ) }
","
List of SET clauses.
","
NAME = 'Test', VALUE = 2
"
"Other Grammar","String","
'anythingExceptSingleQuote'
","
...
...
h2/src/docsrc/html/features.html
浏览文件 @
b940440b
...
...
@@ -83,6 +83,8 @@ Features
Compacting a Database
</a><br
/>
<a
href=
"#cache_settings"
>
Cache Settings
</a><br
/>
<a
href=
"#external_authentication"
>
External Authentication (Experimental)
</a><br
/>
<h2
id=
"feature_list"
>
Feature List
</h2>
<h3>
Main Features
</h3>
...
...
@@ -1826,6 +1828,79 @@ To get information about page reads and writes, and the current caching algorith
call
<code>
SELECT * FROM INFORMATION_SCHEMA.SETTINGS
</code>
. The number of pages read / written
is listed.
</p>
<h2
id=
"external_authentication"
>
External authentication (Experimental)
</h2>
<p>
External authentication allows to optionally validate user credentials externally (JAAS,LDAP,custom classes).
Is also possible to temporary assign roles to to externally authenticated users.
<b>
This feature is experimental and subject to change
</b>
</p>
<p>
Master user cannot be externally authenticated
</p>
<p>
To enable external authentication on a database execute statement
<code>
SET AUTHENTICATOR TRUE
</code>
. This setting in persisted on the database.
</p>
<p>
To connect on a database by using external credentials client must append
<code>
AUTHREALM=H2
</code>
to the database URL.
<code>
H2
</code>
is the identifier of the authentication realm (see later).
</p>
<p>
External authentication requires to send password to the server. For this reason is works only on local connection or remote over ssl
</p>
<p>
By default external authentication is performed through JAAS login interface (configuration name is
<code>
h2
</code>
).
To configure JAAS add argument
<code>
-Djava.security.auth.login.config=jaas.conf
</code>
Here an example of
<a
href=
"https://docs.oracle.com/javase/7/docs/technotes/guides/security/jgss/tutorials/LoginConfigFile.html"
>
JAAS login configuration file
</a>
content:
</p>
<pre>
h2 {
com.sun.security.auth.module.LdapLoginModule REQUIRED \
userProvider="ldap://127.0.0.1:10389" authIdentity="uid={USERNAME},ou=people,dc=example,dc=com" \
debug=true useSSL=false ;
};
</pre>
<p>
Is it possible to specify custom authentication settings by using
JVM argument
<code>
-Dh2auth.configurationFile={urlOfH2Auth.xml}
</code>
. Here an example of h2auth.xml file content:
</p>
<pre>
<
h2Auth allowUserRegistration="false" createMissingRoles="true"
>
<
!-- realm: DUMMY authenticate users named DUMMY[0-9] with a static password --
>
<
realm name="DUMMY"
validatorClass="org.h2.security.auth.impl.FixedPasswordCredentialsValidator"
>
<
property name="userNamePattern" value="DUMMY[0-9]" /
>
<
property name="password" value="mock" /
>
<
/realm
>
<
!-- realm LDAPEXAMPLE:perform credentials validation on LDAP --
>
<
realm name="LDAPEXAMPLE"
validatorClass="org.h2.security.auth.impl.LdapCredentialsValidator"
>
<
property name="bindDnPattern" value="uid=%u,ou=people,dc=example,dc=com" /
>
<
property name="host" value="127.0.0.1" /
>
<
property name="port" value="10389" /
>
<
property name="secure" value="false" /
>
<
/realm
>
<
!-- realm JAAS: perform credentials validation by using JAAS api --
>
<
realm name="JAAS"
validatorClass="org.h2.security.auth.impl.JaasCredentialsValidator"
>
<
property name="appName" value="H2" /
>
<
/realm
>
<
!--Assign to each user role @{REALM} --
>
<
userToRolesMapper class="org.h2.security.auth.impl.AssignRealmNameRole"/
>
<
!--Assign to each user role REMOTEUSER --
>
<
userToRolesMapper class="org.h2.security.auth.impl.StaticRolesMapper"
>
<
property name="roles" value="REMOTEUSER"/
>
<
/userToRolesMapper
>
<
/h2Auth
>
</pre>
<p>
Custom credentials validators must implement the interface
<code>
org.h2.api.CredentialsValidator
</code>
</p>
<p>
Custom criteria for role assignments must implement the interface
<code>
org.h2.api.UserToRoleMapper
</code>
</p>
<!-- [close] { -->
</div></td></tr></table>
<!-- } --><!-- analytics -->
</body></html>
h2/src/main/org/h2/api/CredentialsValidator.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
.
api
;
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.
* <p>
* <b>This feature is experimental and subject to change</b>
* </p>
*/
public
interface
CredentialsValidator
extends
Configurable
{
/**
* 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
*/
boolean
validateCredentials
(
AuthenticationInfo
authenticationInfo
)
throws
Exception
;
}
h2/src/main/org/h2/api/ErrorCode.java
浏览文件 @
b940440b
...
...
@@ -1990,7 +1990,20 @@ public class ErrorCode {
*/
public
static
final
int
ROW_NOT_FOUND_IN_PRIMARY_INDEX
=
90143
;
// next are 90122, 90144
/**
* The error with code <code>90144</code> is thrown when
* user trying to login into a database with AUTHREALM set and
* the target database doesn't have an authenticator defined
* <p>Authenticator experimental feature can be enabled by
* </p>
* <pre>
* SET AUTHENTICATOR TRUE
* </pre>
*/
public
static
final
int
AUTHENTICATOR_NOT_AVAILABLE
=
90144
;
// next are 90122, 90145
private
ErrorCode
()
{
// utility class
...
...
h2/src/main/org/h2/api/UserToRolesMapper.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
.
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.
* <p>
* <b>This feature is experimental and subject to change</b>
* </p>
*/
public
interface
UserToRolesMapper
extends
Configurable
{
/**
* Map user identified by authentication info to a set of granted roles
* @param authenticationInfo
* @return list of roles to be assigned to the user temporary
* @throws AuthenticationException
*/
Collection
<
String
>
mapUserToRoles
(
AuthenticationInfo
authenticationInfo
)
throws
AuthenticationException
;
}
h2/src/main/org/h2/command/Command.java
浏览文件 @
b940440b
...
...
@@ -48,8 +48,8 @@ public abstract class Command implements CommandInterface {
private
boolean
canReuse
;
Command
(
Parser
parser
,
String
sql
)
{
this
.
session
=
parser
.
getSession
()
;
Command
(
Session
session
,
String
sql
)
{
this
.
session
=
session
;
this
.
sql
=
sql
;
trace
=
session
.
getDatabase
().
getTrace
(
Trace
.
COMMAND
);
}
...
...
h2/src/main/org/h2/command/CommandContainer.java
浏览文件 @
b940440b
...
...
@@ -9,6 +9,7 @@ import java.util.ArrayList;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.command.dml.Explain
;
import
org.h2.command.dml.Query
;
import
org.h2.engine.Session
;
import
org.h2.expression.Parameter
;
import
org.h2.expression.ParameterInterface
;
import
org.h2.result.ResultInterface
;
...
...
@@ -26,8 +27,8 @@ public class CommandContainer extends Command {
private
boolean
readOnlyKnown
;
private
boolean
readOnly
;
CommandContainer
(
Parser
parser
,
String
sql
,
Prepared
prepared
)
{
super
(
parser
,
sql
);
CommandContainer
(
Session
session
,
String
sql
,
Prepared
prepared
)
{
super
(
session
,
sql
);
prepared
.
setCommand
(
this
);
this
.
prepared
=
prepared
;
}
...
...
h2/src/main/org/h2/command/CommandList.java
浏览文件 @
b940440b
...
...
@@ -6,6 +6,8 @@
package
org
.
h2
.
command
;
import
java.util.ArrayList
;
import
org.h2.engine.Session
;
import
org.h2.expression.ParameterInterface
;
import
org.h2.result.ResultInterface
;
...
...
@@ -17,8 +19,8 @@ class CommandList extends Command {
private
final
Command
command
;
private
final
String
remaining
;
CommandList
(
Parser
parser
,
String
sql
,
Command
c
,
String
remaining
)
{
super
(
parser
,
sql
);
CommandList
(
Session
session
,
String
sql
,
Command
c
,
String
remaining
)
{
super
(
session
,
sql
);
this
.
command
=
c
;
this
.
remaining
=
remaining
;
}
...
...
h2/src/main/org/h2/command/Parser.java
浏览文件 @
b940440b
...
...
@@ -8,6 +8,13 @@
*/
package
org
.
h2
.
command
;
import
static
org
.
h2
.
util
.
ParserUtil
.
FALSE
;
import
static
org
.
h2
.
util
.
ParserUtil
.
IDENTIFIER
;
import
static
org
.
h2
.
util
.
ParserUtil
.
KEYWORD
;
import
static
org
.
h2
.
util
.
ParserUtil
.
NULL
;
import
static
org
.
h2
.
util
.
ParserUtil
.
ROWNUM
;
import
static
org
.
h2
.
util
.
ParserUtil
.
TRUE
;
import
java.math.BigDecimal
;
import
java.math.BigInteger
;
import
java.nio.charset.Charset
;
...
...
@@ -189,13 +196,7 @@ public class Parser {
private
static
final
int
CHAR_STRING
=
7
,
CHAR_DOT
=
8
,
CHAR_DOLLAR_QUOTED_STRING
=
9
;
// this are token types
private
static
final
int
KEYWORD
=
ParserUtil
.
KEYWORD
;
private
static
final
int
IDENTIFIER
=
ParserUtil
.
IDENTIFIER
;
private
static
final
int
NULL
=
ParserUtil
.
NULL
;
private
static
final
int
TRUE
=
ParserUtil
.
TRUE
;
private
static
final
int
FALSE
=
ParserUtil
.
FALSE
;
private
static
final
int
ROWNUM
=
ParserUtil
.
ROWNUM
;
// this are token types, see also types in ParserUtil
private
static
final
int
PARAMETER
=
10
,
END
=
11
,
VALUE
=
12
;
private
static
final
int
EQUAL
=
13
,
BIGGER_EQUAL
=
14
,
BIGGER
=
15
;
private
static
final
int
SMALLER
=
16
,
SMALLER_EQUAL
=
17
,
NOT_EQUAL
=
18
;
...
...
@@ -285,11 +286,11 @@ public class Parser {
throw
getSyntaxError
();
}
p
.
prepare
();
Command
c
=
new
CommandContainer
(
this
,
sql
,
p
);
Command
c
=
new
CommandContainer
(
session
,
sql
,
p
);
if
(
hasMore
)
{
String
remaining
=
originalSQL
.
substring
(
parseIndex
);
if
(!
StringUtils
.
isWhitespaceOrEmpty
(
remaining
))
{
c
=
new
CommandList
(
this
,
sql
,
c
,
remaining
);
c
=
new
CommandList
(
session
,
sql
,
c
,
remaining
);
}
}
return
c
;
...
...
@@ -574,7 +575,7 @@ public class Parser {
command
.
setTable
(
table
);
}
if
(
readIf
(
"SAMPLE_SIZE"
))
{
command
.
setTop
(
read
Posi
tiveInt
());
command
.
setTop
(
read
NonNega
tiveInt
());
}
return
command
;
}
...
...
@@ -734,10 +735,9 @@ public class Parser {
}
private
Column
readTableColumn
(
TableFilter
filter
)
{
String
tableAlias
=
null
;
String
columnName
=
readColumnIdentifier
();
if
(
readIf
(
"."
))
{
tableAlias
=
columnName
;
String
tableAlias
=
columnName
;
columnName
=
readColumnIdentifier
();
if
(
readIf
(
"."
))
{
String
schema
=
tableAlias
;
...
...
@@ -1156,11 +1156,15 @@ public class Parser {
TableFilter
sourceTableFilter
=
readSimpleTableFilter
(
0
,
excludeIdentifiers
);
command
.
setSourceTableFilter
(
sourceTableFilter
);
StringBuilder
buff
=
new
StringBuilder
(
"SELECT * FROM "
);
appendTableWithSchemaAndAlias
(
buff
,
sourceTableFilter
.
getTable
(),
sourceTableFilter
.
getTableAlias
());
Prepared
preparedQuery
=
prepare
(
session
,
buff
.
toString
(),
null
/*paramValues*/
);
command
.
setQuery
((
Select
)
preparedQuery
);
Select
preparedQuery
=
new
Select
(
session
);
ArrayList
<
Expression
>
expr
=
new
ArrayList
<>(
1
);
expr
.
add
(
new
Wildcard
(
null
,
null
));
preparedQuery
.
setExpressions
(
expr
);
TableFilter
filter
=
new
TableFilter
(
session
,
sourceTableFilter
.
getTable
(),
sourceTableFilter
.
getTableAlias
(),
rightsChecked
,
preparedQuery
,
0
,
null
);
preparedQuery
.
addTableFilter
(
filter
,
true
);
preparedQuery
.
init
();
command
.
setQuery
(
preparedQuery
);
}
read
(
"ON"
);
read
(
"("
);
...
...
@@ -1168,9 +1172,20 @@ public class Parser {
command
.
setOnCondition
(
condition
);
read
(
")"
);
boolean
matched
=
parseWhenMatched
(
command
);
if
(
parseWhenNotMatched
(
command
)
&&
!
matched
)
{
read
(
"WHEN"
);
boolean
matched
=
readIf
(
"MATCHED"
);
if
(
matched
)
{
parseWhenMatched
(
command
);
}
else
{
parseWhenNotMatched
(
command
);
}
if
(
readIf
(
"WHEN"
))
{
if
(
matched
)
{
parseWhenNotMatched
(
command
);
}
else
{
read
(
"MATCHED"
);
parseWhenMatched
(
command
);
}
}
setSQL
(
command
,
"MERGE"
,
start
);
...
...
@@ -1188,17 +1203,17 @@ public class Parser {
return
command
;
}
private
boolean
parseWhenMatched
(
MergeUsing
command
)
{
if
(!
readIfAll
(
"WHEN"
,
"MATCHED"
,
"THEN"
))
{
return
false
;
}
private
void
parseWhenMatched
(
MergeUsing
command
)
{
read
(
"THEN"
);
int
startMatched
=
lastParseIndex
;
boolean
ok
=
false
;
if
(
readIf
(
"UPDATE"
))
{
Update
updateCommand
=
new
Update
(
session
);
TableFilter
filter
=
command
.
getTargetTableFilter
();
updateCommand
.
setTableFilter
(
filter
);
parseUpdateSetClause
(
updateCommand
,
filter
,
startMatched
);
command
.
setUpdateCommand
(
updateCommand
);
ok
=
true
;
}
startMatched
=
lastParseIndex
;
if
(
readIf
(
"DELETE"
))
{
...
...
@@ -1207,21 +1222,25 @@ public class Parser {
deleteCommand
.
setTableFilter
(
filter
);
parseDeleteGivenTable
(
deleteCommand
,
null
,
startMatched
);
command
.
setDeleteCommand
(
deleteCommand
);
ok
=
true
;
}
if
(!
ok
)
{
throw
getSyntaxError
();
}
return
true
;
}
private
boolean
parseWhenNotMatched
(
MergeUsing
command
)
{
if
(!
readIfAll
(
"WHEN"
,
"NOT"
,
"MATCHED"
,
"THEN"
))
{
return
false
;
}
private
void
parseWhenNotMatched
(
MergeUsing
command
)
{
read
(
"NOT"
);
read
(
"MATCHED"
)
;
read
(
"THEN"
);
if
(
readIf
(
"INSERT"
))
{
Insert
insertCommand
=
new
Insert
(
session
);
insertCommand
.
setTable
(
command
.
getTargetTable
());
parseInsertGivenTable
(
insertCommand
,
command
.
getTargetTable
());
command
.
setInsertCommand
(
insertCommand
);
}
else
{
throw
getSyntaxError
();
}
return
true
;
}
private
static
void
appendTableWithSchemaAndAlias
(
StringBuilder
buff
,
Table
table
,
String
alias
)
{
...
...
@@ -1964,9 +1983,8 @@ public class Parser {
}
private
Query
parseSelect
()
{
Query
command
=
null
;
int
paramIndex
=
parameters
.
size
();
command
=
parseSelectUnion
();
Query
command
=
parseSelectUnion
();
int
size
=
parameters
.
size
();
ArrayList
<
Parameter
>
params
=
new
ArrayList
<>(
size
);
for
(
int
i
=
paramIndex
;
i
<
size
;
i
++)
{
...
...
@@ -2042,10 +2060,7 @@ public class Parser {
}
ArrayList
<
SelectOrderBy
>
orderList
=
Utils
.
newSmallArrayList
();
do
{
boolean
canBeNumber
=
true
;
if
(
readIf
(
"="
))
{
canBeNumber
=
false
;
}
boolean
canBeNumber
=
!
readIf
(
"="
);
SelectOrderBy
order
=
new
SelectOrderBy
();
Expression
expr
=
readExpression
();
if
(
canBeNumber
&&
expr
instanceof
ValueExpression
&&
...
...
@@ -2159,7 +2174,7 @@ public class Parser {
return
command
;
}
if
(
readIf
(
"WITH"
))
{
Query
query
=
null
;
Query
query
;
try
{
query
=
(
Query
)
parseWith
();
}
catch
(
ClassCastException
e
)
{
...
...
@@ -2691,7 +2706,7 @@ public class Parser {
}
private
JavaFunction
readJavaFunction
(
Schema
schema
,
String
functionName
,
boolean
throwIfNotFound
)
{
FunctionAlias
functionAlias
=
null
;
FunctionAlias
functionAlias
;
if
(
schema
!=
null
)
{
functionAlias
=
schema
.
findFunction
(
functionName
);
}
else
{
...
...
@@ -3403,10 +3418,10 @@ public class Parser {
return
function
;
}
private
int
read
Posi
tiveInt
()
{
private
int
read
NonNega
tiveInt
()
{
int
v
=
readInt
();
if
(
v
<
0
)
{
throw
DbException
.
getInvalidValueException
(
"
posi
tive integer"
,
v
);
throw
DbException
.
getInvalidValueException
(
"
non-nega
tive integer"
,
v
);
}
return
v
;
}
...
...
@@ -3452,14 +3467,21 @@ public class Parser {
}
private
boolean
readBooleanSetting
()
{
if
(
currentTokenType
==
VALUE
)
{
switch
(
currentTokenType
)
{
case
TRUE:
read
();
return
true
;
case
FALSE:
read
();
return
false
;
case
VALUE:
boolean
result
=
currentValue
.
getBoolean
();
read
();
return
result
;
}
if
(
readIf
(
"
TRUE"
)
||
readIf
(
"
ON"
))
{
if
(
readIf
(
"ON"
))
{
return
true
;
}
else
if
(
readIf
(
"
FALSE"
)
||
readIf
(
"
OFF"
))
{
}
else
if
(
readIf
(
"OFF"
))
{
return
false
;
}
else
{
throw
getSyntaxError
();
...
...
@@ -3547,26 +3569,6 @@ public class Parser {
return
false
;
}
/*
* Reads every token in list, in order - returns true if all are found.
* If any are not found, returns false - AND resets parsing back to state when called.
*/
private
boolean
readIfAll
(
String
...
tokens
)
{
// save parse location in case we have to fail this test
int
start
=
lastParseIndex
;
for
(
String
token:
tokens
)
{
if
(!
currentTokenQuoted
&&
equalsToken
(
token
,
currentToken
))
{
read
();
}
else
{
// read failed - revert parse location to before when called
parseIndex
=
start
;
read
();
return
false
;
}
}
return
true
;
}
private
boolean
isToken
(
String
token
)
{
boolean
result
=
equalsToken
(
token
,
currentToken
)
&&
!
currentTokenQuoted
;
...
...
@@ -3753,12 +3755,11 @@ public class Parser {
return
;
}
case
CHAR_DOLLAR_QUOTED_STRING:
{
String
result
=
null
;
int
begin
=
i
-
1
;
while
(
types
[
i
]
==
CHAR_DOLLAR_QUOTED_STRING
)
{
i
++;
}
result
=
sqlCommand
.
substring
(
begin
,
i
);
String
result
=
sqlCommand
.
substring
(
begin
,
i
);
currentToken
=
"'"
;
checkLiterals
(
true
);
currentValue
=
ValueString
.
get
(
StringUtils
.
cache
(
result
),
...
...
@@ -3877,10 +3878,6 @@ public class Parser {
currentTokenType
=
VALUE
;
}
public
Session
getSession
()
{
return
session
;
}
private
void
initialize
(
String
sql
)
{
if
(
sql
==
null
)
{
sql
=
""
;
...
...
@@ -4306,7 +4303,7 @@ public class Parser {
column
.
setSequence
(
sequence
);
}
if
(
readIf
(
"SELECTIVITY"
))
{
int
value
=
read
Posi
tiveInt
();
int
value
=
read
NonNega
tiveInt
();
column
.
setSelectivity
(
value
);
}
String
comment
=
readCommentIf
();
...
...
@@ -4354,7 +4351,7 @@ public class Parser {
}
}
else
if
(
readIf
(
"TIME"
))
{
if
(
readIf
(
"("
))
{
originalScale
=
read
Posi
tiveInt
();
originalScale
=
read
NonNega
tiveInt
();
if
(
originalScale
>
ValueTime
.
MAXIMUM_SCALE
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_VALUE_SCALE_PRECISION
,
Integer
.
toString
(
originalScale
));
}
...
...
@@ -4367,10 +4364,10 @@ public class Parser {
}
}
else
if
(
readIf
(
"TIMESTAMP"
))
{
if
(
readIf
(
"("
))
{
originalScale
=
read
Posi
tiveInt
();
originalScale
=
read
NonNega
tiveInt
();
// Allow non-standard TIMESTAMP(..., ...) syntax
if
(
readIf
(
","
))
{
originalScale
=
read
Posi
tiveInt
();
originalScale
=
read
NonNega
tiveInt
();
}
if
(
originalScale
>
ValueTimestamp
.
MAXIMUM_SCALE
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_VALUE_SCALE_PRECISION
,
Integer
.
toString
(
originalScale
));
...
...
@@ -4458,7 +4455,7 @@ public class Parser {
}
}
else
if
(
original
.
equals
(
"DATETIME"
)
||
original
.
equals
(
"DATETIME2"
))
{
if
(
readIf
(
"("
))
{
originalScale
=
read
Posi
tiveInt
();
originalScale
=
read
NonNega
tiveInt
();
if
(
originalScale
>
ValueTime
.
MAXIMUM_SCALE
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_VALUE_SCALE_PRECISION
,
Integer
.
toString
(
originalScale
));
...
...
@@ -4506,7 +4503,7 @@ public class Parser {
}
}
else
if
(
dataType
.
type
==
Value
.
DOUBLE
&&
original
.
equals
(
"FLOAT"
))
{
if
(
readIf
(
"("
))
{
int
p
=
read
Posi
tiveInt
();
int
p
=
read
NonNega
tiveInt
();
read
(
")"
);
if
(
p
>
53
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_VALUE_SCALE_PRECISION
,
Integer
.
toString
(
p
));
...
...
@@ -4540,7 +4537,7 @@ public class Parser {
}
else
if
(
readIf
(
"("
))
{
// Support for MySQL: INT(11), MEDIUMINT(8) and so on.
// Just ignore the precision.
read
Posi
tiveInt
();
read
NonNega
tiveInt
();
read
(
")"
);
}
if
(
readIf
(
"FOR"
))
{
...
...
@@ -4793,7 +4790,7 @@ public class Parser {
Select
command
=
new
Select
(
session
);
currentSelect
=
command
;
TableFilter
filter
=
parseValuesTable
(
0
);
ArrayList
<
Expression
>
list
=
Utils
.
newSmallArrayList
(
);
ArrayList
<
Expression
>
list
=
new
ArrayList
<>(
1
);
list
.
add
(
new
Wildcard
(
null
,
null
));
command
.
setExpressions
(
list
);
command
.
addTableFilter
(
filter
,
true
);
...
...
@@ -5087,7 +5084,7 @@ public class Parser {
command
.
setRowBased
(
false
);
}
if
(
readIf
(
"QUEUE"
))
{
command
.
setQueueSize
(
read
Posi
tiveInt
());
command
.
setQueueSize
(
read
NonNega
tiveInt
());
}
command
.
setNoWait
(
readIf
(
"NOWAIT"
));
if
(
readIf
(
"AS"
))
{
...
...
@@ -5170,7 +5167,7 @@ public class Parser {
viewsCreated
.
add
(
parseSingleCommonTableExpression
(
isPersistent
));
}
while
(
readIf
(
","
));
Prepared
p
=
null
;
Prepared
p
;
// reverse the order of constructed CTE views - as the destruction order
// (since later created view may depend on previously created views -
// we preserve that dependency order in the destruction sequence )
...
...
@@ -5218,7 +5215,6 @@ public class Parser {
private
TableView
parseSingleCommonTableExpression
(
boolean
isPersistent
)
{
String
cteViewName
=
readIdentifierWithSchema
();
Schema
schema
=
getSchema
();
Table
recursiveTable
=
null
;
ArrayList
<
Column
>
columns
=
Utils
.
newSmallArrayList
();
String
[]
cols
=
null
;
...
...
@@ -5233,7 +5229,7 @@ public class Parser {
}
}
Table
oldViewFound
=
null
;
Table
oldViewFound
;
if
(
isPersistent
)
{
oldViewFound
=
getSchema
().
findTableOrView
(
session
,
cteViewName
);
}
else
{
...
...
@@ -5265,7 +5261,7 @@ public class Parser {
* work (its removed after creation in this method). Only create table
* data and table if we don't have a working CTE already.
*/
recursiveTable
=
TableView
.
createShadowTableForRecursiveTableExpression
(
Table
recursiveTable
=
TableView
.
createShadowTableForRecursiveTableExpression
(
isPersistent
,
session
,
cteViewName
,
schema
,
columns
,
database
);
List
<
Column
>
columnTemplateList
;
String
[]
querySQLOutput
=
{
null
};
...
...
@@ -5653,7 +5649,7 @@ public class Parser {
}
else
if
(
readIf
(
"NUMBERS"
))
{
command
.
setInt
(
Constants
.
ALLOW_LITERALS_NUMBERS
);
}
else
{
command
.
setInt
(
read
Posi
tiveInt
());
command
.
setInt
(
read
NonNega
tiveInt
());
}
return
command
;
}
else
if
(
readIf
(
"DEFAULT_TABLE_TYPE"
))
{
...
...
@@ -5664,7 +5660,7 @@ public class Parser {
}
else
if
(
readIf
(
"CACHED"
))
{
command
.
setInt
(
Table
.
TYPE_CACHED
);
}
else
{
command
.
setInt
(
read
Posi
tiveInt
());
command
.
setInt
(
read
NonNega
tiveInt
());
}
return
command
;
}
else
if
(
readIf
(
"CREATE"
))
{
...
...
@@ -6163,7 +6159,7 @@ public class Parser {
// Oracle specifies (but will not require) an opening parenthesis
boolean
hasOpeningBracket
=
readIf
(
"("
);
String
columnName
=
readColumnIdentifier
();
AlterTableAlterColumn
command
=
null
;
AlterTableAlterColumn
command
;
NullConstraintType
nullConstraint
=
parseNotNullConstraint
();
switch
(
nullConstraint
)
{
case
NULL_IS_ALLOWED:
...
...
h2/src/main/org/h2/command/dml/MergeUsing.java
浏览文件 @
b940440b
...
...
@@ -390,31 +390,21 @@ public class MergeUsing extends Prepared {
query
.
prepare
();
}
int
embeddedStatementsCount
=
0
;
// Prepare each of the sub-commands ready to aid in the MERGE
// collaboration
if
(
updateCommand
!=
null
)
{
updateCommand
.
setSourceTableFilter
(
sourceTableFilter
);
updateCommand
.
setCondition
(
appendOnCondition
(
updateCommand
));
updateCommand
.
prepare
();
embeddedStatementsCount
++;
}
if
(
deleteCommand
!=
null
)
{
deleteCommand
.
setSourceTableFilter
(
sourceTableFilter
);
deleteCommand
.
setCondition
(
appendOnCondition
(
deleteCommand
));
deleteCommand
.
prepare
();
embeddedStatementsCount
++;
}
if
(
insertCommand
!=
null
)
{
insertCommand
.
setSourceTableFilter
(
sourceTableFilter
);
insertCommand
.
prepare
();
embeddedStatementsCount
++;
}
if
(
embeddedStatementsCount
==
0
)
{
throw
DbException
.
get
(
ErrorCode
.
SYNTAX_ERROR_1
,
"At least UPDATE, DELETE or INSERT embedded statement must be supplied."
);
}
// setup the targetMatchQuery - for detecting if the target row exists
...
...
h2/src/main/org/h2/command/dml/Set.java
浏览文件 @
b940440b
...
...
@@ -18,9 +18,11 @@ import org.h2.engine.Setting;
import
org.h2.expression.Expression
;
import
org.h2.expression.ValueExpression
;
import
org.h2.message.DbException
;
import
org.h2.message.Trace
;
import
org.h2.result.ResultInterface
;
import
org.h2.result.RowFactory
;
import
org.h2.schema.Schema
;
import
org.h2.security.auth.AuthenticatorFactory
;
import
org.h2.table.Table
;
import
org.h2.tools.CompressTool
;
import
org.h2.util.JdbcUtils
;
...
...
@@ -540,6 +542,25 @@ public class Set extends Prepared {
session
.
getColumnNamerConfiguration
().
configure
(
expression
.
getColumnName
());
break
;
}
case
SetTypes
.
AUTHENTICATOR
:
{
session
.
getUser
().
checkAdmin
();
try
{
if
(
expression
.
getBooleanValue
(
session
))
{
database
.
setAuthenticator
(
AuthenticatorFactory
.
createAuthenticator
());
}
else
{
database
.
setAuthenticator
(
null
);
}
addOrUpdateSetting
(
name
,
expression
.
getValue
(
session
).
getString
(),
0
);
}
catch
(
Exception
e
)
{
//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
());
}
else
{
throw
DbException
.
convert
(
e
);
}
}
break
;
}
default
:
DbException
.
throwInternalError
(
"type="
+
type
);
}
...
...
h2/src/main/org/h2/command/dml/SetTypes.java
浏览文件 @
b940440b
...
...
@@ -252,7 +252,12 @@ public class SetTypes {
*/
public
static
final
int
COLUMN_NAME_RULES
=
48
;
private
static
final
int
COUNT
=
COLUMN_NAME_RULES
+
1
;
/**
* The type of a SET AUTHENTICATOR statement.
*/
public
static
final
int
AUTHENTICATOR
=
49
;
private
static
final
int
COUNT
=
AUTHENTICATOR
+
1
;
private
static
final
ArrayList
<
String
>
TYPES
;
...
...
@@ -311,6 +316,7 @@ public class SetTypes {
list
.
add
(
LAZY_QUERY_EXECUTION
,
"LAZY_QUERY_EXECUTION"
);
list
.
add
(
BUILTIN_ALIAS_OVERRIDE
,
"BUILTIN_ALIAS_OVERRIDE"
);
list
.
add
(
COLUMN_NAME_RULES
,
"COLUMN_NAME_RULES"
);
list
.
add
(
AUTHENTICATOR
,
"AUTHENTICATOR"
);
TYPES
=
list
;
}
...
...
h2/src/main/org/h2/engine/ConnectionInfo.java
浏览文件 @
b940440b
...
...
@@ -74,9 +74,9 @@ public class ConnectionInfo implements Cloneable {
readProperties
(
info
);
readSettingsFromURL
();
setUserName
(
removeProperty
(
"USER"
,
""
));
convertPasswords
();
name
=
url
.
substring
(
Constants
.
START_URL
.
length
());
parseName
();
convertPasswords
();
String
recoverTest
=
removeProperty
(
"RECOVER_TEST"
,
null
);
if
(
recoverTest
!=
null
)
{
FilePathRec
.
register
();
...
...
@@ -95,7 +95,7 @@ public class ConnectionInfo implements Cloneable {
"IFEXISTS"
,
"INIT"
,
"PASSWORD"
,
"RECOVER"
,
"RECOVER_TEST"
,
"USER"
,
"AUTO_SERVER"
,
"AUTO_SERVER_PORT"
,
"NO_UPGRADE"
,
"AUTO_RECONNECT"
,
"OPEN_NEW"
,
"PAGE_SIZE"
,
"PASSWORD_HASH"
,
"JMX"
,
"SCOPE_GENERATED_KEYS"
};
"SCOPE_GENERATED_KEYS"
,
"AUTHREALM"
,
"AUTHZPWD"
};
HashSet
<
String
>
set
=
new
HashSet
<>(
128
);
set
.
addAll
(
SetTypes
.
getTypes
());
for
(
String
key
:
connectionTime
)
{
...
...
@@ -274,8 +274,15 @@ public class ConnectionInfo implements Cloneable {
}
}
private
void
preservePasswordForAuthentication
(
Object
password
)
{
if
((!
isRemote
()
||
isSSL
())
&&
prop
.
containsKey
(
"AUTHREALM"
)
&&
password
!=
null
)
{
prop
.
put
(
"AUTHZPWD"
,
password
);
}
}
private
char
[]
removePassword
()
{
Object
p
=
prop
.
remove
(
"PASSWORD"
);
preservePasswordForAuthentication
(
p
);
if
(
p
==
null
)
{
return
new
char
[
0
];
}
else
if
(
p
instanceof
char
[])
{
...
...
@@ -657,4 +664,8 @@ public class ConnectionInfo implements Cloneable {
return
url
;
}
public
void
cleanAuthenticationInfo
()
{
removeProperty
(
"AUTHREALM"
,
false
);
removeProperty
(
"AUTHZPWD"
,
false
);
}
}
h2/src/main/org/h2/engine/Database.java
浏览文件 @
b940440b
...
...
@@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentHashMap;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicLong
;
import
java.util.concurrent.atomic.AtomicReference
;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.JavaObjectSerializer
;
...
...
@@ -43,6 +44,8 @@ import org.h2.schema.Schema;
import
org.h2.schema.SchemaObject
;
import
org.h2.schema.Sequence
;
import
org.h2.schema.TriggerObject
;
import
org.h2.security.auth.Authenticator
;
import
org.h2.security.auth.AuthenticatorFactory
;
import
org.h2.store.DataHandler
;
import
org.h2.store.FileLock
;
import
org.h2.store.FileLockMethod
;
...
...
@@ -225,6 +228,8 @@ public class Database implements DataHandler {
private
QueryStatisticsData
queryStatisticsData
;
private
RowFactory
rowFactory
=
RowFactory
.
DEFAULT
;
private
Authenticator
authenticator
;
public
Database
(
ConnectionInfo
ci
,
String
cipher
)
{
if
(
ASSERT
)
{
META_LOCK_DEBUGGING
.
set
(
null
);
...
...
@@ -2973,4 +2978,23 @@ public class Database implements DataHandler {
return
engine
;
}
/**
* get authenticator for database users
* @return authenticator set for database
*/
public
Authenticator
getAuthenticator
()
{
return
authenticator
;
}
/**
* Set current database authenticator
*
* @param authenticator = authenticator to set, null to revert to the Internal authenticator
*/
public
void
setAuthenticator
(
Authenticator
authenticator
)
{
if
(
authenticator
!=
null
)
{
authenticator
.
init
(
this
);
};
this
.
authenticator
=
authenticator
;
}
}
h2/src/main/org/h2/engine/Engine.java
浏览文件 @
b940440b
...
...
@@ -14,6 +14,9 @@ import org.h2.command.Parser;
import
org.h2.command.dml.SetTypes
;
import
org.h2.message.DbException
;
import
org.h2.message.Trace
;
import
org.h2.security.auth.AuthenticationException
;
import
org.h2.security.auth.AuthenticationInfo
;
import
org.h2.security.auth.Authenticator
;
import
org.h2.store.FileLock
;
import
org.h2.store.FileLockMethod
;
import
org.h2.util.MathUtils
;
...
...
@@ -90,10 +93,26 @@ public class Engine implements SessionFactory {
}
if
(
user
==
null
)
{
if
(
database
.
validateFilePasswordHash
(
cipher
,
ci
.
getFilePasswordHash
()))
{
user
=
database
.
findUser
(
ci
.
getUserName
());
if
(
user
!=
null
)
{
if
(!
user
.
validateUserPasswordHash
(
ci
.
getUserPasswordHash
()))
{
user
=
null
;
if
(
ci
.
getProperty
(
"AUTHREALM"
)==
null
)
{
user
=
database
.
findUser
(
ci
.
getUserName
());
if
(
user
!=
null
)
{
if
(!
user
.
validateUserPasswordHash
(
ci
.
getUserPasswordHash
()))
{
user
=
null
;
}
}
}
else
{
Authenticator
authenticator
=
database
.
getAuthenticator
();
if
(
authenticator
==
null
)
{
throw
DbException
.
get
(
ErrorCode
.
AUTHENTICATOR_NOT_AVAILABLE
,
name
);
}
else
{
try
{
AuthenticationInfo
authenticationInfo
=
new
AuthenticationInfo
(
ci
);
user
=
database
.
getAuthenticator
().
authenticate
(
authenticationInfo
,
database
);
}
catch
(
AuthenticationException
authenticationError
)
{
database
.
getTrace
(
Trace
.
DATABASE
).
error
(
authenticationError
,
"an error occurred during authentication; user: \""
+
ci
.
getUserName
()
+
"\""
);
}
}
}
}
...
...
@@ -110,6 +129,8 @@ public class Engine implements SessionFactory {
database
.
removeSession
(
null
);
throw
er
;
}
//Prevent to set _PASSWORD
ci
.
cleanAuthenticationInfo
();
checkClustering
(
ci
,
database
);
Session
session
=
database
.
createSession
(
user
);
if
(
session
==
null
)
{
...
...
h2/src/main/org/h2/engine/RightOwner.java
浏览文件 @
b940440b
...
...
@@ -5,7 +5,10 @@
*/
package
org
.
h2
.
engine
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map.Entry
;
import
org.h2.table.Table
;
...
...
@@ -150,6 +153,26 @@ public abstract class RightOwner extends DbObjectBase {
grantedRoles
=
null
;
}
}
/**
* Remove all the temporary rights granted on roles
*/
public
void
revokeTemporaryRightsOnRoles
()
{
if
(
grantedRoles
==
null
)
{
return
;
}
List
<
Role
>
rolesToRemove
=
new
ArrayList
<>();
for
(
Entry
<
Role
,
Right
>
currentEntry
:
grantedRoles
.
entrySet
())
{
if
(
currentEntry
.
getValue
().
isTemporary
()
||
!
currentEntry
.
getValue
().
isValid
())
{
rolesToRemove
.
add
(
currentEntry
.
getKey
());
}
}
for
(
Role
currentRoleToRemove
:
rolesToRemove
)
{
revokeRole
(
currentRoleToRemove
);
}
}
/**
* Get the 'grant schema' right of this object.
...
...
h2/src/main/org/h2/engine/SysProperties.java
浏览文件 @
b940440b
...
...
@@ -555,6 +555,16 @@ public class SysProperties {
public
static
final
String
CUSTOM_DATA_TYPES_HANDLER
=
Utils
.
getProperty
(
"h2.customDataTypesHandler"
,
null
);
/**
* System property <code>h2.authConfigFile</code>
* (default: null).<br />
* authConfigFile define the URL of configuration file
* of {@link org.h2.security.auth.DefaultAuthenticator}
*
*/
public
static
final
String
AUTH_CONFIG_FILE
=
Utils
.
getProperty
(
"h2.authConfigFile"
,
null
);
private
static
final
String
H2_BASE_DIR
=
"h2.baseDir"
;
private
SysProperties
()
{
...
...
h2/src/main/org/h2/engine/UserBuilder.java
0 → 100644
浏览文件 @
b940440b
package
org
.
h2
.
engine
;
import
org.h2.security.auth.AuthenticationInfo
;
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
* @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
.
setTemporary
(!
persistent
);
return
user
;
}
}
h2/src/main/org/h2/res/_messages_en.prop
浏览文件 @
b940440b
...
...
@@ -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}
...
...
h2/src/main/org/h2/security/auth/AuthConfigException.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
/**
* Exception thrown when an issue occurs during the authentication configuration
*
*/
public
class
AuthConfigException
extends
RuntimeException
{
public
AuthConfigException
()
{
super
();
}
public
AuthConfigException
(
String
message
)
{
super
(
message
);
}
public
AuthConfigException
(
Throwable
cause
)
{
super
(
cause
);
}
public
AuthConfigException
(
String
message
,
Throwable
cause
)
{
super
(
message
,
cause
);
}
}
h2/src/main/org/h2/security/auth/AuthenticationException.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
/**
* Exception thrown in case of errors during authentication
*/
public
class
AuthenticationException
extends
Exception
{
public
AuthenticationException
()
{
super
();
}
public
AuthenticationException
(
String
message
)
{
super
(
message
);
}
public
AuthenticationException
(
Throwable
cause
)
{
super
(
cause
);
}
public
AuthenticationException
(
String
message
,
Throwable
cause
)
{
super
(
message
,
cause
);
}
}
h2/src/main/org/h2/security/auth/AuthenticationInfo.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
import
org.h2.engine.ConnectionInfo
;
import
org.h2.util.StringUtils
;
/**
* Input data for authenticators; it wraps ConnectionInfo
*/
public
class
AuthenticationInfo
{
private
ConnectionInfo
connectionInfo
;
private
String
password
;
private
String
realm
;
/*
* Can be used by authenticator to hold informations
*/
Object
nestedIdentity
;
public
AuthenticationInfo
(
ConnectionInfo
connectionInfo
)
{
this
.
connectionInfo
=
connectionInfo
;
this
.
realm
=
connectionInfo
.
getProperty
(
"AUTHREALM"
,
null
);
if
(
this
.
realm
!=
null
)
{
this
.
realm
=
StringUtils
.
toUpperEnglish
(
this
.
realm
);
}
this
.
password
=
connectionInfo
.
getProperty
(
"AUTHZPWD"
,
null
);
}
public
String
getUserName
()
{
return
connectionInfo
.
getUserName
();
}
public
String
getRealm
()
{
return
realm
;
}
public
String
getPassword
()
{
return
password
;
}
public
ConnectionInfo
getConnectionInfo
()
{
return
connectionInfo
;
}
public
String
getFullyQualifiedName
()
{
if
(
realm
==
null
)
{
return
connectionInfo
.
getUserName
();
}
else
{
return
connectionInfo
.
getUserName
()+
"@"
+
realm
;
}
}
/**
* get nested identity
* @return
*/
public
Object
getNestedIdentity
()
{
return
nestedIdentity
;
}
/**
* Method used by authenticators to hold informations about authenticated user
* @param nestedIdentity = nested identity object
*/
public
void
setNestedIdentity
(
Object
nestedIdentity
)
{
this
.
nestedIdentity
=
nestedIdentity
;
}
public
void
clean
()
{
this
.
password
=
null
;
this
.
nestedIdentity
=
null
;
connectionInfo
.
cleanAuthenticationInfo
();
}
}
h2/src/main/org/h2/security/auth/Authenticator.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
import
org.h2.engine.Database
;
import
org.h2.engine.User
;
/**
* Low level interface to implement full authentication process
*/
public
interface
Authenticator
{
/**
* perform user authentication
*
* @param authenticationInfo
* @param 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
* @throws AuthConfigException
*/
void
init
(
Database
database
)
throws
AuthConfigException
;
}
h2/src/main/org/h2/security/auth/AuthenticatorFactory.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
/**
* Authenticator factory
*/
public
class
AuthenticatorFactory
{
public
static
Authenticator
createAuthenticator
()
{
return
DefaultAuthenticator
.
getInstance
();
}
}
h2/src/main/org/h2/security/auth/ConfigProperties.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.h2.util.Utils
;
/**
* wrapper for configuration properties
*/
public
class
ConfigProperties
{
private
Map
<
String
,
String
>
properties
;
public
ConfigProperties
()
{
properties
=
new
HashMap
<>();
}
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
());
}
}
}
}
public
String
getStringValue
(
String
name
,
String
defaultValue
)
{
String
result
=
properties
.
get
(
name
);
if
(
result
==
null
)
{
return
defaultValue
;
}
return
result
;
}
public
String
getStringValue
(
String
name
)
{
String
result
=
properties
.
get
(
name
);
if
(
result
==
null
)
{
throw
new
AuthConfigException
(
"missing config property "
+
name
);
}
return
result
;
}
public
int
getIntValue
(
String
name
,
int
defaultValue
)
{
String
result
=
properties
.
get
(
name
);
if
(
result
==
null
)
{
return
defaultValue
;
}
return
Integer
.
parseInt
(
result
);
}
public
int
getIntValue
(
String
name
)
{
String
result
=
properties
.
get
(
name
);
if
(
result
==
null
)
{
throw
new
AuthConfigException
(
"missing config property "
+
name
);
}
return
Integer
.
parseInt
(
result
);
}
public
boolean
getBooleanValue
(
String
name
,
boolean
defaultValue
)
{
String
result
=
properties
.
get
(
name
);
if
(
result
==
null
)
{
return
defaultValue
;
}
return
Utils
.
parseBoolean
(
result
,
defaultValue
,
true
);
}
}
h2/src/main/org/h2/security/auth/Configurable.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
/**
* describe how to perform objects runtime configuration
*/
public
interface
Configurable
{
/**
* configure the component
* @param configProperties = configuration properties
*/
void
configure
(
ConfigProperties
configProperties
);
}
h2/src/main/org/h2/security/auth/DefaultAuthenticator.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
import
java.net.URL
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
javax.xml.bind.JAXB
;
import
org.h2.api.CredentialsValidator
;
import
org.h2.api.UserToRolesMapper
;
import
org.h2.engine.Database
;
import
org.h2.engine.Right
;
import
org.h2.engine.Role
;
import
org.h2.engine.SysProperties
;
import
org.h2.engine.User
;
import
org.h2.engine.UserBuilder
;
import
org.h2.message.Trace
;
import
org.h2.security.auth.impl.AssignRealmNameRole
;
import
org.h2.security.auth.impl.JaasCredentialsValidator
;
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.
* </p>
* <p>
* When client connectionInfo doesn't contains AUTHREALM property credentials
* are validated internally on the database
* </p>
* <p>
* 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
* </p>
*/
public
class
DefaultAuthenticator
implements
Authenticator
{
public
static
final
String
DEFAULT_REALMNAME
=
"H2"
;
private
Map
<
String
,
CredentialsValidator
>
realms
=
new
HashMap
<>();
private
List
<
UserToRolesMapper
>
userToRolesMappers
=
new
ArrayList
<>();
private
boolean
allowUserRegistration
;
private
boolean
persistUsers
;
private
boolean
createMissingRoles
;
private
boolean
skipDefaultInitialization
;
private
boolean
initialized
;
private
static
DefaultAuthenticator
instance
;
protected
static
final
DefaultAuthenticator
getInstance
()
{
if
(
instance
==
null
)
{
instance
=
new
DefaultAuthenticator
();
}
return
instance
;
}
/**
* Create the Authenticator with default configurations
*/
public
DefaultAuthenticator
()
{
}
/**
* Create authenticator and optionally skip the default configuration. This
* option is useful when the authenticator is configured at code level
*
* @param skipDefaultInitialization
* if true default initialization is skipped
*/
public
DefaultAuthenticator
(
boolean
skipDefaultInitialization
)
{
this
.
skipDefaultInitialization
=
skipDefaultInitialization
;
}
/**
* If set save users externals defined during the authentication.
*
* @return
*/
public
boolean
isPersistUsers
()
{
return
persistUsers
;
}
public
void
setPersistUsers
(
boolean
persistUsers
)
{
this
.
persistUsers
=
persistUsers
;
}
/**
* If set create external users in the database if not present.
*
* @return
*/
public
boolean
isAllowUserRegistration
()
{
return
allowUserRegistration
;
}
public
void
setAllowUserRegistration
(
boolean
allowUserRegistration
)
{
this
.
allowUserRegistration
=
allowUserRegistration
;
}
/**
* When set create roles not found in the database. If not set roles not found
* in the database are silently skipped
*
* @return
*/
public
boolean
isCreateMissingRoles
()
{
return
createMissingRoles
;
}
public
void
setCreateMissingRoles
(
boolean
createMissingRoles
)
{
this
.
createMissingRoles
=
createMissingRoles
;
}
/**
* Add an authentication realm. Realms are case insensitive
*
* @param name realm name
* @param credentialsValidator credentials validator for realm
*/
public
void
addRealm
(
String
name
,
CredentialsValidator
credentialsValidator
)
{
realms
.
put
(
StringUtils
.
toUpperEnglish
(
name
),
credentialsValidator
);
}
/**
* UserToRoleMappers assign roles to authenticated users
*
* @return current UserToRoleMappers active
*/
public
List
<
UserToRolesMapper
>
getUserToRolesMappers
()
{
return
userToRolesMappers
;
}
public
void
setUserToRolesMappers
(
UserToRolesMapper
...
userToRolesMappers
)
{
List
<
UserToRolesMapper
>
userToRolesMappersList
=
new
ArrayList
<>();
for
(
UserToRolesMapper
current
:
userToRolesMappers
)
{
userToRolesMappersList
.
add
(
current
);
}
this
.
userToRolesMappers
=
userToRolesMappersList
;
}
/**
* Initializes the authenticator (it is called by AuthententicationManager)
*
* 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
* @throws AuthConfigException
*/
public
void
init
(
Database
database
)
throws
AuthConfigException
{
if
(
skipDefaultInitialization
)
{
return
;
}
if
(
initialized
)
{
return
;
}
synchronized
(
this
)
{
if
(
initialized
)
{
return
;
}
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
);
}
h2AuthenticatorConfigurationUrl
=
new
URL
(
configFile
);
}
if
(
h2AuthenticatorConfigurationUrl
==
null
)
{
if
(
trace
.
isDebugEnabled
())
{
trace
.
debug
(
"DefaultAuthenticator.config: default configuration"
);
}
defaultConfiguration
();
}
else
{
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
);
}
initialized
=
true
;
}
}
void
defaultConfiguration
()
{
createMissingRoles
=
false
;
allowUserRegistration
=
true
;
realms
=
new
HashMap
<>();
CredentialsValidator
jaasCredentialsValidator
=
new
JaasCredentialsValidator
();
jaasCredentialsValidator
.
configure
(
new
ConfigProperties
());
realms
.
put
(
DEFAULT_REALMNAME
,
jaasCredentialsValidator
);
UserToRolesMapper
assignRealmNameRole
=
new
AssignRealmNameRole
();
assignRealmNameRole
.
configure
(
new
ConfigProperties
());
userToRolesMappers
.
add
(
assignRealmNameRole
);
}
/**
* Configure the authenticator from a configuration file
*
* @param configUrl URL of configuration file
* @throws Exception
*/
public
void
configureFromUrl
(
URL
configUrl
)
throws
Exception
{
H2AuthConfig
config
=
JAXB
.
unmarshal
(
configUrl
,
H2AuthConfig
.
class
);
configureFrom
(
config
);
}
void
configureFrom
(
H2AuthConfig
config
)
throws
Exception
{
allowUserRegistration
=
config
.
isAllowUserRegistration
();
createMissingRoles
=
config
.
isCreateMissingRoles
();
Map
<
String
,
CredentialsValidator
>
newRealms
=
new
HashMap
<>();
for
(
RealmConfig
currentRealmConfig
:
config
.
getRealms
())
{
String
currentRealmName
=
currentRealmConfig
.
getName
();
if
(
currentRealmName
==
null
)
{
throw
new
Exception
(
"Missing realm name"
);
}
currentRealmName
=
currentRealmName
.
toUpperCase
();
CredentialsValidator
currentValidator
=
null
;
try
{
currentValidator
=
(
CredentialsValidator
)
Class
.
forName
(
currentRealmConfig
.
getValidatorClass
())
.
newInstance
();
}
catch
(
Exception
e
)
{
throw
new
Exception
(
"invalid validator class fo realm "
+
currentRealmName
,
e
);
}
currentValidator
.
configure
(
new
ConfigProperties
(
currentRealmConfig
.
getProperties
()));
if
(
newRealms
.
put
(
currentRealmConfig
.
getName
().
toUpperCase
(),
currentValidator
)
!=
null
)
{
throw
new
Exception
(
"Duplicate realm "
+
currentRealmConfig
.
getName
());
}
}
this
.
realms
=
newRealms
;
List
<
UserToRolesMapper
>
newUserToRolesMapper
=
new
ArrayList
<>();
for
(
UserToRolesMapperConfig
currentUserToRolesMapperConfig
:
config
.
getUserToRolesMappers
())
{
UserToRolesMapper
currentUserToRolesMapper
=
null
;
try
{
currentUserToRolesMapper
=
(
UserToRolesMapper
)
Class
.
forName
(
currentUserToRolesMapperConfig
.
getClassName
()).
newInstance
();
}
catch
(
Exception
e
)
{
throw
new
Exception
(
"Invalid class in UserToRolesMapperConfig"
,
e
);
}
currentUserToRolesMapper
.
configure
(
new
ConfigProperties
(
currentUserToRolesMapperConfig
.
getProperties
()));
newUserToRolesMapper
.
add
(
currentUserToRolesMapper
);
}
this
.
userToRolesMappers
=
newUserToRolesMapper
;
}
boolean
updateRoles
(
AuthenticationInfo
authenticationInfo
,
User
user
,
Database
database
)
throws
AuthenticationException
{
boolean
updatedDb
=
false
;
Set
<
String
>
roles
=
new
HashSet
<>();
for
(
UserToRolesMapper
currentUserToRolesMapper
:
userToRolesMappers
)
{
Collection
<
String
>
currentRoles
=
currentUserToRolesMapper
.
mapUserToRoles
(
authenticationInfo
);
if
(
currentRoles
!=
null
&&
!
currentRoles
.
isEmpty
())
{
roles
.
addAll
(
currentRoles
);
}
}
for
(
String
currentRoleName
:
roles
)
{
if
(
currentRoleName
==
null
||
currentRoleName
.
isEmpty
())
{
continue
;
}
Role
currentRole
=
database
.
findRole
(
currentRoleName
);
if
(
currentRole
==
null
&&
isCreateMissingRoles
())
{
synchronized
(
database
.
getSystemSession
())
{
currentRole
=
new
Role
(
database
,
database
.
allocateObjectId
(),
currentRoleName
,
false
);
database
.
addDatabaseObject
(
database
.
getSystemSession
(),
currentRole
);
database
.
getSystemSession
().
commit
(
false
);
updatedDb
=
true
;
}
}
if
(
currentRole
==
null
)
{
continue
;
}
if
(
user
.
getRightForRole
(
currentRole
)
==
null
)
{
// NON PERSISTENT
Right
currentRight
=
new
Right
(
database
,
-
1
,
user
,
currentRole
);
currentRight
.
setTemporary
(
true
);
user
.
grantRole
(
currentRole
,
currentRight
);
}
}
return
updatedDb
;
}
@Override
public
final
User
authenticate
(
AuthenticationInfo
authenticationInfo
,
Database
database
)
throws
AuthenticationException
{
String
userName
=
authenticationInfo
.
getFullyQualifiedName
();
User
user
=
database
.
findUser
(
userName
);
if
(
user
==
null
&&
!
isAllowUserRegistration
())
{
throw
new
AuthenticationException
(
"User "
+
userName
+
" not found in db"
);
}
CredentialsValidator
validator
=
realms
.
get
(
authenticationInfo
.
getRealm
());
if
(
validator
==
null
)
{
throw
new
AuthenticationException
(
"realm "
+
authenticationInfo
.
getRealm
()
+
" not configured"
);
}
try
{
if
(!
validator
.
validateCredentials
(
authenticationInfo
))
{
return
null
;
}
}
catch
(
Exception
e
)
{
throw
new
AuthenticationException
(
e
);
}
if
(
user
==
null
)
{
synchronized
(
database
.
getSystemSession
())
{
user
=
UserBuilder
.
buildUser
(
authenticationInfo
,
database
,
isPersistUsers
());
database
.
addDatabaseObject
(
database
.
getSystemSession
(),
user
);
database
.
getSystemSession
().
commit
(
false
);
}
}
user
.
revokeTemporaryRightsOnRoles
();
updateRoles
(
authenticationInfo
,
user
,
database
);
return
user
;
}
}
h2/src/main/org/h2/security/auth/H2AuthConfig.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
import
java.util.ArrayList
;
import
java.util.List
;
import
javax.xml.bind.annotation.XmlAccessType
;
import
javax.xml.bind.annotation.XmlAccessorType
;
import
javax.xml.bind.annotation.XmlAttribute
;
import
javax.xml.bind.annotation.XmlElement
;
import
javax.xml.bind.annotation.XmlRootElement
;
/**
* Describe configuration of H2 DefaultAuthenticator
*/
@XmlRootElement
(
name
=
"h2Auth"
)
@XmlAccessorType
(
XmlAccessType
.
FIELD
)
public
class
H2AuthConfig
{
@XmlAttribute
private
boolean
allowUserRegistration
=
true
;
public
boolean
isAllowUserRegistration
()
{
return
allowUserRegistration
;
}
public
void
setAllowUserRegistration
(
boolean
allowUserRegistration
)
{
this
.
allowUserRegistration
=
allowUserRegistration
;
}
@XmlAttribute
boolean
createMissingRoles
=
true
;
public
boolean
isCreateMissingRoles
()
{
return
createMissingRoles
;
}
public
void
setCreateMissingRoles
(
boolean
createMissingRoles
)
{
this
.
createMissingRoles
=
createMissingRoles
;
}
@XmlElement
(
name
=
"realm"
)
List
<
RealmConfig
>
realms
;
public
List
<
RealmConfig
>
getRealms
()
{
if
(
realms
==
null
)
{
realms
=
new
ArrayList
<>();
}
return
realms
;
}
public
void
setRealms
(
List
<
RealmConfig
>
realms
)
{
this
.
realms
=
realms
;
}
@XmlElement
(
name
=
"userToRolesMapper"
)
List
<
UserToRolesMapperConfig
>
userToRolesMappers
;
public
List
<
UserToRolesMapperConfig
>
getUserToRolesMappers
()
{
if
(
userToRolesMappers
==
null
)
{
userToRolesMappers
=
new
ArrayList
<>();
}
return
userToRolesMappers
;
}
public
void
setUserToRolesMappers
(
List
<
UserToRolesMapperConfig
>
userToRolesMappers
)
{
this
.
userToRolesMappers
=
userToRolesMappers
;
}
}
h2/src/main/org/h2/security/auth/PropertyConfig.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
import
javax.xml.bind.annotation.XmlAccessType
;
import
javax.xml.bind.annotation.XmlAccessorType
;
import
javax.xml.bind.annotation.XmlAttribute
;
/**
* Configuration property
*/
@XmlAccessorType
(
XmlAccessType
.
FIELD
)
public
class
PropertyConfig
{
@XmlAttribute
(
required
=
true
)
private
String
name
;
@XmlAttribute
private
String
value
;
public
PropertyConfig
()
{
}
public
PropertyConfig
(
String
name
,
String
value
)
{
this
.
name
=
name
;
this
.
value
=
value
;
}
public
String
getName
()
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
String
getValue
()
{
return
value
;
}
public
void
setValue
(
String
value
)
{
this
.
value
=
value
;
}
}
h2/src/main/org/h2/security/auth/RealmConfig.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
import
java.util.ArrayList
;
import
java.util.List
;
import
javax.xml.bind.annotation.XmlAccessType
;
import
javax.xml.bind.annotation.XmlAccessorType
;
import
javax.xml.bind.annotation.XmlAttribute
;
import
javax.xml.bind.annotation.XmlElement
;
@XmlAccessorType
(
XmlAccessType
.
FIELD
)
public
class
RealmConfig
{
@XmlAttribute
(
required
=
true
)
private
String
name
;
public
String
getName
()
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
@XmlAttribute
(
required
=
true
)
String
validatorClass
;
public
String
getValidatorClass
()
{
return
validatorClass
;
}
public
void
setValidatorClass
(
String
validatorClass
)
{
this
.
validatorClass
=
validatorClass
;
}
@XmlElement
(
name
=
"property"
)
List
<
PropertyConfig
>
properties
;
public
List
<
PropertyConfig
>
getProperties
()
{
if
(
properties
==
null
)
{
properties
=
new
ArrayList
<>();
}
return
properties
;
}
}
h2/src/main/org/h2/security/auth/UserToRolesMapperConfig.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
import
java.util.ArrayList
;
import
java.util.List
;
import
javax.xml.bind.annotation.XmlAccessType
;
import
javax.xml.bind.annotation.XmlAccessorType
;
import
javax.xml.bind.annotation.XmlAttribute
;
import
javax.xml.bind.annotation.XmlElement
;
@XmlAccessorType
(
XmlAccessType
.
FIELD
)
public
class
UserToRolesMapperConfig
{
@XmlAttribute
(
required
=
true
,
name
=
"class"
)
private
String
className
;
@XmlElement
(
name
=
"property"
)
private
List
<
PropertyConfig
>
properties
;
public
String
getClassName
()
{
return
className
;
}
public
void
setClassName
(
String
className
)
{
this
.
className
=
className
;
}
public
List
<
PropertyConfig
>
getProperties
()
{
if
(
properties
==
null
)
{
properties
=
new
ArrayList
<>();
}
return
properties
;
}
}
h2/src/main/org/h2/security/auth/impl/AssignRealmNameRole.java
0 → 100644
浏览文件 @
b940440b
package
org
.
h2
.
security
.
auth
.
impl
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
org.h2.api.UserToRolesMapper
;
import
org.h2.security.auth.AuthenticationException
;
import
org.h2.security.auth.AuthenticationInfo
;
import
org.h2.security.auth.ConfigProperties
;
/**
* Assign to user a role based on realm name
*
* * <p>
* Configuration parameters:
* </p>
* <ul>
* <li> roleNameFormat, optional by default is @{realm}</li>
* </ul>
*/
public
class
AssignRealmNameRole
implements
UserToRolesMapper
{
private
String
roleNameFormat
;
public
AssignRealmNameRole
()
{
this
(
"@%s"
);
}
public
AssignRealmNameRole
(
String
roleNameFormat
)
{
this
.
roleNameFormat
=
roleNameFormat
;
}
@Override
public
void
configure
(
ConfigProperties
configProperties
)
{
roleNameFormat
=
configProperties
.
getStringValue
(
"roleNameFormat"
,
roleNameFormat
);
}
@Override
public
Collection
<
String
>
mapUserToRoles
(
AuthenticationInfo
authenticationInfo
)
throws
AuthenticationException
{
return
Arrays
.
asList
(
String
.
format
(
roleNameFormat
,
authenticationInfo
.
getRealm
()));
}
}
h2/src/main/org/h2/security/auth/impl/JaasCredentialsValidator.java
0 → 100644
浏览文件 @
b940440b
/*
* 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.io.IOException
;
import
javax.security.auth.callback.Callback
;
import
javax.security.auth.callback.CallbackHandler
;
import
javax.security.auth.callback.NameCallback
;
import
javax.security.auth.callback.PasswordCallback
;
import
javax.security.auth.callback.UnsupportedCallbackException
;
import
javax.security.auth.login.LoginContext
;
import
org.h2.api.CredentialsValidator
;
import
org.h2.security.auth.AuthenticationInfo
;
import
org.h2.security.auth.ConfigProperties
;
/**
* Validate credentials by using standard Java Authentication and Authorization Service
*
* <p>
* Configuration parameters:
* </p>
* <ul>
* <li>appName inside the JAAS configuration (by default h2)</li>
* </ul>
*
*/
public
class
JaasCredentialsValidator
implements
CredentialsValidator
{
public
static
final
String
DEFAULT_APPNAME
=
"h2"
;
private
String
appName
;
public
JaasCredentialsValidator
()
{
this
(
DEFAULT_APPNAME
);
}
/**
* Create the validator with the given name of JAAS configuration
* @param appName = name of JAAS configuration
*/
public
JaasCredentialsValidator
(
String
appName
)
{
this
.
appName
=
appName
;
}
@Override
public
void
configure
(
ConfigProperties
configProperties
)
{
appName
=
configProperties
.
getStringValue
(
"appName"
,
appName
);
}
class
AuthenticationInfoCallbackHandler
implements
CallbackHandler
{
AuthenticationInfo
authenticationInfo
;
AuthenticationInfoCallbackHandler
(
AuthenticationInfo
authenticationInfo
)
{
this
.
authenticationInfo
=
authenticationInfo
;
}
@Override
public
void
handle
(
Callback
[]
callbacks
)
throws
IOException
,
UnsupportedCallbackException
{
for
(
int
i
=
0
;
i
<
callbacks
.
length
;
i
++)
{
if
(
callbacks
[
i
]
instanceof
NameCallback
)
{
((
NameCallback
)
callbacks
[
i
]).
setName
(
authenticationInfo
.
getUserName
());
}
else
if
(
callbacks
[
i
]
instanceof
PasswordCallback
)
{
((
PasswordCallback
)
callbacks
[
i
]).
setPassword
(
authenticationInfo
.
getPassword
().
toCharArray
());
}
}
}
}
@Override
public
boolean
validateCredentials
(
AuthenticationInfo
authenticationInfo
)
throws
Exception
{
LoginContext
loginContext
=
new
LoginContext
(
appName
,
new
AuthenticationInfoCallbackHandler
(
authenticationInfo
));
loginContext
.
login
();
authenticationInfo
.
setNestedIdentity
(
loginContext
.
getSubject
());
return
true
;
}
}
h2/src/main/org/h2/security/auth/impl/LdapCredentialsValidator.java
0 → 100644
浏览文件 @
b940440b
/*
* 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.Hashtable
;
import
javax.naming.Context
;
import
javax.naming.directory.DirContext
;
import
javax.naming.directory.InitialDirContext
;
import
org.h2.api.CredentialsValidator
;
import
org.h2.security.auth.AuthenticationInfo
;
import
org.h2.security.auth.ConfigProperties
;
/**
* Validate credentials by performing an LDAP bind
* <p>
* 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>host ldap server</li>
* <li>port of ldap service; optional, by default 389 for unsecure, 636 for secure</li>
* <li>secure, optional by default is true (use SSL)</li>
* </ul>
*/
public
class
LdapCredentialsValidator
implements
CredentialsValidator
{
private
String
bindDnPattern
;
private
String
host
;
private
int
port
;
private
boolean
secure
;
private
String
url
;
@Override
public
void
configure
(
ConfigProperties
configProperties
)
{
bindDnPattern
=
configProperties
.
getStringValue
(
"bindDnPattern"
);
host
=
configProperties
.
getStringValue
(
"host"
);
secure
=
configProperties
.
getBooleanValue
(
"secure"
,
true
);
port
=
configProperties
.
getIntValue
(
"port"
,
secure
?
636
:
389
);
url
=
"ldap"
+
(
secure
?
"s"
:
""
)
+
"://"
+
host
+
":"
+
port
;
}
@Override
public
boolean
validateCredentials
(
AuthenticationInfo
authenticationInfo
)
throws
Exception
{
DirContext
dirContext
=
null
;
try
{
String
dn
=
bindDnPattern
.
replace
(
"%u"
,
authenticationInfo
.
getUserName
());
Hashtable
<
String
,
String
>
env
=
new
Hashtable
<>();
env
.
put
(
Context
.
INITIAL_CONTEXT_FACTORY
,
"com.sun.jndi.ldap.LdapCtxFactory"
);
env
.
put
(
Context
.
PROVIDER_URL
,
url
);
env
.
put
(
Context
.
SECURITY_AUTHENTICATION
,
"simple"
);
env
.
put
(
Context
.
SECURITY_PRINCIPAL
,
dn
);
env
.
put
(
Context
.
SECURITY_CREDENTIALS
,
authenticationInfo
.
getPassword
());
if
(
secure
)
{
env
.
put
(
Context
.
SECURITY_PROTOCOL
,
"ssl"
);
}
dirContext
=
new
InitialDirContext
(
env
);
authenticationInfo
.
setNestedIdentity
(
dn
);
return
true
;
}
finally
{
if
(
dirContext
!=
null
)
{
dirContext
.
close
();
}
}
}
}
h2/src/main/org/h2/security/auth/impl/StaticRolesMapper.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
;
import
java.util.Collection
;
import
java.util.HashSet
;
import
org.h2.api.UserToRolesMapper
;
import
org.h2.security.auth.AuthenticationException
;
import
org.h2.security.auth.AuthenticationInfo
;
import
org.h2.security.auth.ConfigProperties
;
/**
* Assign static roles to authenticated users
* <p>
* Configuration parameters:
* </p>
* <ul>
* <li>roles role list separated by comma</li>
* </ul>
*
*/
public
class
StaticRolesMapper
implements
UserToRolesMapper
{
private
Collection
<
String
>
roles
;
public
StaticRolesMapper
()
{
}
public
StaticRolesMapper
(
String
...
roles
)
{
this
.
roles
=
Arrays
.
asList
(
roles
);
}
@Override
public
void
configure
(
ConfigProperties
configProperties
)
{
String
rolesString
=
configProperties
.
getStringValue
(
"roles"
,
""
);
if
(
rolesString
!=
null
)
{
roles
=
new
HashSet
<>(
Arrays
.
asList
(
rolesString
.
split
(
","
)));
}
}
@Override
public
Collection
<
String
>
mapUserToRoles
(
AuthenticationInfo
authenticationInfo
)
throws
AuthenticationException
{
return
roles
;
}
}
h2/src/main/org/h2/security/auth/impl/StaticUserCredentialsValidator.java
0 → 100644
浏览文件 @
b940440b
/*
* Copyright 2004-2018 H2 Group. Mul tiple-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.regex.Pattern
;
import
org.h2.api.CredentialsValidator
;
import
org.h2.security.SHA256
;
import
org.h2.security.auth.AuthenticationException
;
import
org.h2.security.auth.AuthenticationInfo
;
import
org.h2.security.auth.ConfigProperties
;
import
org.h2.util.MathUtils
;
import
org.h2.util.StringUtils
;
import
org.h2.util.Utils
;
/**
* This credentials validator matches the user and password with the configured
* Usage should be limited to test purposes
*
*/
public
class
StaticUserCredentialsValidator
implements
CredentialsValidator
{
private
Pattern
userNamePattern
;
private
String
password
;
private
byte
[]
salt
;
private
byte
[]
hashWithSalt
;
public
StaticUserCredentialsValidator
()
{
}
public
StaticUserCredentialsValidator
(
String
userNamePattern
,
String
password
)
{
if
(
userNamePattern
!=
null
)
{
this
.
userNamePattern
=
Pattern
.
compile
(
userNamePattern
.
toUpperCase
());
}
salt
=
MathUtils
.
secureRandomBytes
(
256
);
hashWithSalt
=
SHA256
.
getHashWithSalt
(
password
.
getBytes
(),
salt
);
}
@Override
public
boolean
validateCredentials
(
AuthenticationInfo
authenticationInfo
)
throws
AuthenticationException
{
if
(
userNamePattern
!=
null
)
{
if
(!
userNamePattern
.
matcher
(
authenticationInfo
.
getUserName
()).
matches
())
{
return
false
;
}
}
if
(
password
!=
null
)
{
return
password
.
equals
(
authenticationInfo
.
getPassword
());
}
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
);
}
password
=
configProperties
.
getStringValue
(
"password"
,
password
);
String
saltString
=
configProperties
.
getStringValue
(
"salt"
,
null
);
if
(
saltString
!=
null
)
{
salt
=
StringUtils
.
convertHexToBytes
(
saltString
);
}
String
hashString
=
configProperties
.
getStringValue
(
"hash"
,
null
);
if
(
hashString
!=
null
)
{
hashWithSalt
=
SHA256
.
getHashWithSalt
(
StringUtils
.
convertHexToBytes
(
hashString
),
salt
);
}
}
}
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
b940440b
...
...
@@ -15,6 +15,7 @@ import org.h2.Driver;
import
org.h2.engine.Constants
;
import
org.h2.store.fs.FilePathRec
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.auth.TestAuthentication
;
import
org.h2.test.bench.TestPerformance
;
import
org.h2.test.db.TestAlter
;
import
org.h2.test.db.TestAlterSchemaRename
;
...
...
@@ -972,6 +973,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest
(
new
TestSampleApps
());
addTest
(
new
TestStringCache
());
addTest
(
new
TestValueMemory
());
addTest
(
new
TestAuthentication
());
runAddedTests
(
1
);
...
...
h2/src/test/org/h2/test/auth/MyLoginModule.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
.
test
.
auth
;
import
java.util.Map
;
import
javax.security.auth.Subject
;
import
javax.security.auth.callback.Callback
;
import
javax.security.auth.callback.CallbackHandler
;
import
javax.security.auth.callback.NameCallback
;
import
javax.security.auth.callback.PasswordCallback
;
import
javax.security.auth.login.LoginException
;
import
javax.security.auth.spi.LoginModule
;
/**
* Dummy login module used for test cases
*/
public
class
MyLoginModule
implements
LoginModule
{
String
password
;
CallbackHandler
callbackHandler
;
@Override
public
void
initialize
(
Subject
subject
,
CallbackHandler
callbackHandler
,
Map
<
String
,
?>
sharedState
,
Map
<
String
,
?>
options
)
{
this
.
callbackHandler
=
callbackHandler
;
password
=
""
+
options
.
get
(
"password"
);
}
@Override
public
boolean
login
()
throws
LoginException
{
if
(
callbackHandler
==
null
)
{
throw
new
LoginException
(
"no callbackHandler available"
);
}
NameCallback
nameCallback
=
new
NameCallback
(
"user name"
);
PasswordCallback
passwordCallback
=
new
PasswordCallback
(
"user name"
,
false
);
try
{
callbackHandler
.
handle
(
new
Callback
[]
{
nameCallback
,
passwordCallback
});
}
catch
(
Exception
exception
)
{
throw
new
LoginException
(
"an exception occurred during inquiry of username and password"
);
}
return
password
.
equals
(
new
String
(
passwordCallback
.
getPassword
()));
}
@Override
public
boolean
logout
()
throws
LoginException
{
return
true
;
}
@Override
public
boolean
abort
()
throws
LoginException
{
return
true
;
}
@Override
public
boolean
commit
()
throws
LoginException
{
return
true
;
}
}
h2/src/test/org/h2/test/auth/TestAuthentication.java
0 → 100644
浏览文件 @
b940440b
/*
* 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
.
test
.
auth
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
import
java.sql.SQLException
;
import
java.util.HashMap
;
import
java.util.Properties
;
import
java.util.UUID
;
import
javax.security.auth.login.AppConfigurationEntry
;
import
javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag
;
import
javax.security.auth.login.Configuration
;
import
org.h2.engine.ConnectionInfo
;
import
org.h2.engine.Database
;
import
org.h2.engine.Engine
;
import
org.h2.engine.Role
;
import
org.h2.engine.Session
;
import
org.h2.engine.User
;
import
org.h2.security.auth.DefaultAuthenticator
;
import
org.h2.security.auth.impl.AssignRealmNameRole
;
import
org.h2.security.auth.impl.JaasCredentialsValidator
;
import
org.h2.security.auth.impl.StaticRolesMapper
;
import
org.h2.security.auth.impl.StaticUserCredentialsValidator
;
import
org.h2.test.TestBase
;
public
class
TestAuthentication
extends
TestBase
{
public
static
void
main
(
String
...
a
)
throws
Exception
{
TestBase
.
createCaller
().
init
().
test
();
}
String
externalUserPassword
;
String
getExternalUserPassword
()
{
if
(
externalUserPassword
==
null
)
{
externalUserPassword
=
UUID
.
randomUUID
().
toString
();
}
return
externalUserPassword
;
}
String
getRealmName
()
{
return
"testRealm"
;
}
String
getJaasConfigName
()
{
return
"testJaasH2"
;
}
String
getStaticRoleName
()
{
return
"staticRole"
;
}
DefaultAuthenticator
defaultAuthenticator
;
void
configureAuthentication
(
Database
database
)
{
defaultAuthenticator
=
new
DefaultAuthenticator
(
true
);
defaultAuthenticator
.
setAllowUserRegistration
(
true
);
defaultAuthenticator
.
setCreateMissingRoles
(
true
);
defaultAuthenticator
.
addRealm
(
getRealmName
(),
new
JaasCredentialsValidator
(
getJaasConfigName
()));
defaultAuthenticator
.
addRealm
(
getRealmName
()
+
"_STATIC"
,
new
StaticUserCredentialsValidator
(
"staticuser[0-9]"
,
"staticpassword"
));
defaultAuthenticator
.
setUserToRolesMappers
(
new
AssignRealmNameRole
(
"@%s"
),
new
StaticRolesMapper
(
getStaticRoleName
()));
database
.
setAuthenticator
(
defaultAuthenticator
);
}
void
configureJaas
()
{
final
Configuration
innerConfiguration
=
Configuration
.
getConfiguration
();
Configuration
.
setConfiguration
(
new
Configuration
()
{
@Override
public
AppConfigurationEntry
[]
getAppConfigurationEntry
(
String
name
)
{
if
(
name
.
equals
(
getJaasConfigName
()))
{
HashMap
<
String
,
String
>
options
=
new
HashMap
<>();
options
.
put
(
"password"
,
getExternalUserPassword
());
return
new
AppConfigurationEntry
[]
{
new
AppConfigurationEntry
(
MyLoginModule
.
class
.
getName
(),
LoginModuleControlFlag
.
REQUIRED
,
options
)
};
}
return
innerConfiguration
.
getAppConfigurationEntry
(
name
);
}
});
}
protected
String
getDatabaseURL
()
{
return
"jdbc:h2:mem:"
+
getClass
().
getSimpleName
();
}
protected
String
getExternalUser
()
{
return
"user"
;
}
Session
session
;
Database
database
;
@Override
public
void
test
()
throws
Exception
{
Configuration
oldConfiguration
=
Configuration
.
getConfiguration
();
try
{
configureJaas
();
Properties
properties
=
new
Properties
();
properties
.
setProperty
(
"USER"
,
"dba"
);
ConnectionInfo
connectionInfo
=
new
ConnectionInfo
(
getDatabaseURL
(),
properties
);
session
=
Engine
.
getInstance
().
createSession
(
connectionInfo
);
database
=
session
.
getDatabase
();
configureAuthentication
(
database
);
try
{
allTests
();
}
finally
{
session
.
close
();
}
}
finally
{
Configuration
.
setConfiguration
(
oldConfiguration
);
}
}
protected
void
allTests
()
throws
Exception
{
testInvalidPassword
();
testExternalUserWihoutRealm
();
testExternalUser
();
testAssignRealNameRole
();
testStaticRole
();
testStaticUserCredentials
();
testUserRegistration
();
testSet
();
}
protected
void
testInvalidPassword
()
throws
Exception
{
try
{
Connection
wrongLoginConnection
=
DriverManager
.
getConnection
(
getDatabaseURL
()
+
";AUTHREALM="
+
getRealmName
().
toUpperCase
(),
getExternalUser
(),
""
);
wrongLoginConnection
.
close
();
throw
new
Exception
(
"user should not be able to login with an invalid password"
);
}
catch
(
SQLException
e
)
{
}
}
protected
void
testExternalUserWihoutRealm
()
throws
Exception
{
try
{
Connection
wrongLoginConnection
=
DriverManager
.
getConnection
(
getDatabaseURL
(),
getExternalUser
(),
getExternalUserPassword
());
wrongLoginConnection
.
close
();
throw
new
Exception
(
"user should not be able to login without a realm"
);
}
catch
(
SQLException
e
)
{
}
}
protected
void
testExternalUser
()
throws
Exception
{
Connection
rightConnection
=
DriverManager
.
getConnection
(
getDatabaseURL
()
+
";AUTHREALM="
+
getRealmName
().
toUpperCase
(),
getExternalUser
(),
getExternalUserPassword
());
try
{
User
user
=
session
.
getDatabase
().
findUser
((
getExternalUser
()
+
"@"
+
getRealmName
()).
toUpperCase
());
assertNotNull
(
user
);
}
finally
{
rightConnection
.
close
();
}
}
protected
void
testAssignRealNameRole
()
throws
Exception
{
String
realmNameRoleName
=
"@"
+
getRealmName
().
toUpperCase
();
Role
realmNameRole
=
database
.
findRole
(
realmNameRoleName
);
if
(
realmNameRole
==
null
)
{
realmNameRole
=
new
Role
(
database
,
database
.
allocateObjectId
(),
realmNameRoleName
,
false
);
session
.
getDatabase
().
addDatabaseObject
(
session
,
realmNameRole
);
session
.
commit
(
false
);
}
Connection
rightConnection
=
DriverManager
.
getConnection
(
getDatabaseURL
()
+
";AUTHREALM="
+
getRealmName
().
toUpperCase
(),
getExternalUser
(),
getExternalUserPassword
());
try
{
User
user
=
session
.
getDatabase
().
findUser
((
getExternalUser
()
+
"@"
+
getRealmName
()).
toUpperCase
());
assertNotNull
(
user
);
assertTrue
(
user
.
isRoleGranted
(
realmNameRole
));
}
finally
{
rightConnection
.
close
();
}
}
protected
void
testStaticRole
()
throws
Exception
{
Connection
rightConnection
=
DriverManager
.
getConnection
(
getDatabaseURL
()
+
";AUTHREALM="
+
getRealmName
().
toUpperCase
(),
getExternalUser
(),
getExternalUserPassword
());
try
{
User
user
=
session
.
getDatabase
().
findUser
((
getExternalUser
()
+
"@"
+
getRealmName
()).
toUpperCase
());
assertNotNull
(
user
);
Role
staticRole
=
session
.
getDatabase
().
findRole
(
getStaticRoleName
());
if
(
staticRole
!=
null
)
{
assertTrue
(
user
.
isRoleGranted
(
staticRole
));
}
}
finally
{
rightConnection
.
close
();
}
}
protected
void
testUserRegistration
()
throws
Exception
{
boolean
initialValueAllow
=
defaultAuthenticator
.
isAllowUserRegistration
();
defaultAuthenticator
.
setAllowUserRegistration
(
false
);
try
{
try
{
Connection
wrongLoginConnection
=
DriverManager
.
getConnection
(
getDatabaseURL
()
+
";AUTHREALM="
+
getRealmName
().
toUpperCase
(),
"___"
+
getExternalUser
(),
""
);
wrongLoginConnection
.
close
();
throw
new
Exception
(
"unregistered external users should not be able to login when allowUserRegistration=false"
);
}
catch
(
SQLException
e
)
{
}
String
validUserName
=
"new_"
+
getExternalUser
();
User
validUser
=
new
User
(
database
,
database
.
allocateObjectId
(),
(
validUserName
.
toUpperCase
()
+
"@"
+
getRealmName
()).
toUpperCase
(),
false
);
validUser
.
setUserPasswordHash
(
new
byte
[]
{});
database
.
addDatabaseObject
(
session
,
validUser
);
session
.
commit
(
false
);
Connection
connectionWithRegisterUser
=
DriverManager
.
getConnection
(
getDatabaseURL
()
+
";AUTHREALM="
+
getRealmName
().
toUpperCase
(),
validUserName
,
getExternalUserPassword
());
connectionWithRegisterUser
.
close
();
}
finally
{
defaultAuthenticator
.
setAllowUserRegistration
(
initialValueAllow
);
}
}
public
void
testStaticUserCredentials
()
throws
Exception
{
String
userName
=
"STATICUSER3"
;
Connection
rightConnection
=
DriverManager
.
getConnection
(
getDatabaseURL
()
+
";AUTHREALM="
+
getRealmName
().
toUpperCase
()+
"_STATIC"
,
userName
,
"staticpassword"
);
try
{
User
user
=
session
.
getDatabase
().
findUser
(
userName
+
"@"
+
getRealmName
().
toUpperCase
()+
"_STATIC"
);
assertNotNull
(
user
);
}
finally
{
rightConnection
.
close
();
}
}
protected
void
testSet
()
throws
Exception
{
Connection
rightConnection
=
DriverManager
.
getConnection
(
getDatabaseURL
()+
";AUTHENTICATOR=FALSE"
,
"DBA"
,
""
);
try
{
try
{
testExternalUser
();
throw
new
Exception
(
"External user shouldnt be allowed"
);
}
catch
(
Exception
e
)
{
}
}
finally
{
configureAuthentication
(
database
);
rightConnection
.
close
();
}
testExternalUser
();
}
}
\ No newline at end of file
h2/src/test/org/h2/test/db/TestMergeUsing.java
浏览文件 @
b940440b
...
...
@@ -161,7 +161,7 @@ public class TestMergeUsing extends TestBase implements Trigger {
GATHER_ORDERED_RESULTS_SQL
,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) WHERE X<0"
,
0
,
"
At least UPDATE, DELETE or INSERT embedded statement must be supplied.
"
);
"
expected \"WHEN\"
"
);
// Two updates to same row - update and delete together - emptying the
// parent table
testMergeUsing
(
...
...
h2/src/test/org/h2/test/scripts/dml/mergeUsing.sql
浏览文件 @
b940440b
...
...
@@ -149,3 +149,29 @@ SELECT * FROM TEST ORDER BY C1, C2;
DROP
TABLE
TEST
;
>
ok
CREATE
TABLE
TEST
(
ID
INT
,
VALUE
INT
);
>
ok
MERGE
INTO
TEST
USING
DUAL
ON
(
ID
=
1
)
WHEN
MATCHED
THEN
UPDATE
SET
VALUE
=
1
WHEN
;
>
exception
SYNTAX_ERROR_2
MERGE
INTO
TEST
USING
DUAL
ON
(
ID
=
1
)
WHEN
MATCHED
THEN
UPDATE
SET
VALUE
=
1
WHEN
NOT
MATCHED
THEN
;
>
exception
SYNTAX_ERROR_2
MERGE
INTO
TEST
USING
DUAL
ON
(
ID
=
1
)
WHEN
NOT
MATCHED
THEN
INSERT
(
ID
,
VALUE
)
VALUES
(
1
,
1
)
WHEN
;
>
exception
SYNTAX_ERROR_2
MERGE
INTO
TEST
USING
DUAL
ON
(
ID
=
1
)
WHEN
NOT
MATCHED
THEN
INSERT
(
ID
,
VALUE
)
VALUES
(
1
,
1
)
WHEN
MATCHED
THEN
;
>
exception
SYNTAX_ERROR_2
DROP
TABLE
TEST
;
>
ok
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论