Skip to content

Commit e9321eb

Browse files
committed
Reestructure the permission database and make permissions by role work.
1 parent 33ddac8 commit e9321eb

File tree

7 files changed

+111
-65
lines changed

7 files changed

+111
-65
lines changed

src/etc/scripts/java-security.sql

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,53 @@
1-
create sequence seq_permission_group start with 2;
1+
create sequence seq_permission_group;
22

33
create table permission_group (
4-
id bigint not null constraint permission_group_pk primary key,
4+
id bigint not null constraint pergro_pk primary key,
55
name varchar(255) not null
66
);
77

88
create table permission (
9-
permission_group bigint not null constraint permission_pg_fk references permission_group,
10-
user_name varchar(31) not null,
9+
permission_group bigint not null constraint per_fk01 references permission_group,
1110
class_name varchar(255) not null,
1211
arg1 varchar(255),
1312
arg2 varchar(255)
1413
);
1514

16-
create table database_permission_group (
17-
database_pattern varchar(255) not null,
18-
permission_group bigint not null constraint database_permission_group_pg_fk references permission_group
15+
create table permission_group_grant (
16+
permission_group bigint not null constraint pergrogra_fk01 references permission_group,
17+
database_pattern varchar(1024) not null,
18+
grantee_type varchar(4) not null constraint pergrogra_ck01 check (grantee_type in ('USER', 'ROLE')),
19+
grantee_pattern varchar(512) not null
1920
);
2021

21-
-- Common permission group
22-
insert into permission_group (id, name)
23-
values (1, 'COMMON');
24-
25-
-- Public permissions
26-
insert into permission (permission_group, user_name, class_name, arg1, arg2)
27-
values (1, 'PUBLIC', 'java.util.PropertyPermission', 'file.separator', 'read');
28-
insert into permission (permission_group, user_name, class_name, arg1, arg2)
29-
values (1, 'PUBLIC', 'java.util.PropertyPermission', 'java.version', 'read');
30-
insert into permission (permission_group, user_name, class_name, arg1, arg2)
31-
values (1, 'PUBLIC', 'java.util.PropertyPermission', 'java.vendor', 'read');
32-
insert into permission (permission_group, user_name, class_name, arg1, arg2)
33-
values (1, 'PUBLIC', 'java.util.PropertyPermission', 'java.vendor.url', 'read');
34-
insert into permission (permission_group, user_name, class_name, arg1, arg2)
35-
values (1, 'PUBLIC', 'java.util.PropertyPermission', 'line.separator', 'read');
36-
insert into permission (permission_group, user_name, class_name, arg1, arg2)
37-
values (1, 'PUBLIC', 'java.util.PropertyPermission', 'os.*', 'read');
38-
insert into permission (permission_group, user_name, class_name, arg1, arg2)
39-
values (1, 'PUBLIC', 'java.util.PropertyPermission', 'path.separator', 'read');
40-
41-
-- Common permissions
42-
insert into database_permission_group (database_pattern, permission_group)
43-
values ('%', 1);
22+
set term !;
23+
24+
execute block
25+
as
26+
declare pergro_id type of column permission_group.id;
27+
begin
28+
-- Common permissions, by default granted to all users.
29+
30+
insert into permission_group (id, name)
31+
values (next value for seq_permission_group, 'COMMON')
32+
returning id into pergro_id;
33+
34+
insert into permission (permission_group, class_name, arg1, arg2)
35+
values (:pergro_id, 'java.util.PropertyPermission', 'file.separator', 'read');
36+
insert into permission (permission_group, class_name, arg1, arg2)
37+
values (:pergro_id, 'java.util.PropertyPermission', 'java.version', 'read');
38+
insert into permission (permission_group, class_name, arg1, arg2)
39+
values (:pergro_id, 'java.util.PropertyPermission', 'java.vendor', 'read');
40+
insert into permission (permission_group, class_name, arg1, arg2)
41+
values (:pergro_id, 'java.util.PropertyPermission', 'java.vendor.url', 'read');
42+
insert into permission (permission_group, class_name, arg1, arg2)
43+
values (:pergro_id, 'java.util.PropertyPermission', 'line.separator', 'read');
44+
insert into permission (permission_group, class_name, arg1, arg2)
45+
values (:pergro_id, 'java.util.PropertyPermission', 'os.*', 'read');
46+
insert into permission (permission_group, class_name, arg1, arg2)
47+
values (:pergro_id, 'java.util.PropertyPermission', 'path.separator', 'read');
48+
49+
insert into permission_group_grant (permission_group, database_pattern, grantee_type, grantee_pattern)
50+
values (:pergro_id, '%', 'USER', '%');
51+
end!
52+
53+
set term ;!

src/fbjava/src/main/java/org/firebirdsql/fbjava/impl/DbPolicy.java

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@
3333
import java.sql.PreparedStatement;
3434
import java.sql.ResultSet;
3535
import java.sql.SQLException;
36+
import java.sql.Statement;
3637
import java.util.HashMap;
3738
import java.util.HashSet;
3839

3940
import javax.security.auth.Subject;
4041

42+
import org.firebirdsql.fbjava.impl.FbClientLibrary.IExternalContext;
43+
import org.firebirdsql.fbjava.impl.FbClientLibrary.IStatus;
4144
import org.firebirdsql.gds.ISCConstants;
4245
import org.firebirdsql.gds.TransactionParameterBuffer;
4346
import org.firebirdsql.jdbc.FBConnection;
@@ -82,13 +85,16 @@ static void databaseOpened() throws SQLException
8285

8386
stmt = securityDb.prepareStatement(
8487
"select p.class_name, p.arg1, p.arg2\n" +
85-
" from database_permission_group dpg\n" +
88+
" from permission_group_grant pgg\n" +
8689
" join permission_group pg\n" +
87-
" on pg.id = dpg.permission_group\n" +
90+
" on pg.id = pgg.permission_group\n" +
8891
" join permission p\n" +
8992
" on p.permission_group = pg.id\n" +
90-
" where cast(? as varchar(1024)) similar to dpg.database_pattern escape '\\' and\n" +
91-
" p.user_name in (?, 'PUBLIC')");
93+
" where cast(? as varchar(1024)) similar to pgg.database_pattern escape '\\' and\n" +
94+
" ((pgg.grantee_type = 'USER' and\n" +
95+
" cast(? as varchar(512)) similar to pgg.grantee_pattern escape '\\') or\n" +
96+
" (pgg.grantee_type = 'ROLE' and\n" +
97+
" cast(? as varchar(512)) similar to pgg.grantee_pattern escape '\\'))");
9298
}
9399
}
94100
}
@@ -106,19 +112,41 @@ static void databaseClosed() throws SQLException
106112
}
107113
}
108114

109-
static synchronized Subject getUserSubject(String databaseName, String userName)
115+
static synchronized Subject getUserSubject(IStatus status, IExternalContext context, DbClassLoader classLoader)
116+
throws Exception
110117
{
118+
String databaseName = classLoader.databaseName;
119+
String userName = context.getUserName();
120+
String key = databaseName + "\0" + userName;
121+
111122
synchronized (userSubjects)
112123
{
113-
Subject subj = userSubjects.get(userName);
124+
Subject subj = userSubjects.get(key);
114125
if (subj != null)
115126
return subj;
116127

128+
String roleName;
129+
130+
try (InternalContext internalContext = InternalContext.get(status, context))
131+
{
132+
try (Connection conn = internalContext.getConnection())
133+
{
134+
try (Statement stmt = conn.createStatement())
135+
{
136+
try (ResultSet rs = stmt.executeQuery("select current_role from rdb$database"))
137+
{
138+
rs.next();
139+
roleName = rs.getString(1);
140+
}
141+
}
142+
}
143+
}
144+
117145
final HashSet<Principal> principals = new HashSet<Principal>();
118-
principals.add(new DbPrincipal(databaseName, userName));
146+
principals.add(new DbPrincipal(databaseName, roleName, userName));
119147
subj = new Subject(true, principals, new HashSet<Object>(), new HashSet<Object>());
120148

121-
userSubjects.put(userName, subj);
149+
userSubjects.put(key, subj);
122150

123151
return subj;
124152
}
@@ -143,7 +171,11 @@ public PermissionCollection run()
143171
for (Principal principal : domain.getPrincipals())
144172
{
145173
if (principal instanceof DbPrincipal)
146-
loadPermissions(((DbPrincipal) principal).getDatabaseName(), principal.getName(), permissions);
174+
{
175+
DbPrincipal dbPrincipal = (DbPrincipal) principal;
176+
loadPermissions(dbPrincipal.getDatabaseName(), dbPrincipal.getRoleName(), dbPrincipal.getName(),
177+
permissions);
178+
}
147179
}
148180

149181
return permissions;
@@ -168,7 +200,8 @@ public Boolean run()
168200
});
169201
}
170202

171-
private void loadPermissions(String databaseName, String userName, PermissionCollection permissions)
203+
private void loadPermissions(String databaseName, String roleName, String userName,
204+
PermissionCollection permissions)
172205
{
173206
//// TODO: cache
174207
synchronized (stmt)
@@ -177,8 +210,9 @@ private void loadPermissions(String databaseName, String userName, PermissionCol
177210
{
178211
stmt.setString(1, databaseName);
179212
stmt.setString(2, userName);
180-
ResultSet rs = stmt.executeQuery();
181-
try
213+
stmt.setString(3, roleName);
214+
215+
try (ResultSet rs = stmt.executeQuery())
182216
{
183217
while (rs.next())
184218
{
@@ -210,10 +244,6 @@ else if (arg1 != null)
210244
}
211245
}
212246
}
213-
finally
214-
{
215-
rs.close();
216-
}
217247
}
218248
catch (SQLException e)
219249
{

src/fbjava/src/main/java/org/firebirdsql/fbjava/impl/DbPrincipal.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,42 +29,50 @@
2929
final class DbPrincipal implements Principal
3030
{
3131
private String databaseName;
32-
private String name;
32+
private String roleName;
33+
private String userName;
3334

34-
public DbPrincipal(String databaseName, String name)
35+
public DbPrincipal(String databaseName, String roleName, String userName)
3536
{
3637
this.databaseName = databaseName;
37-
this.name = name;
38+
this.roleName = roleName;
39+
this.userName = userName;
3840
}
3941

4042
@Override
4143
public String getName()
4244
{
43-
return name;
45+
return userName;
4446
}
4547

4648
@Override
4749
public boolean equals(Object another)
4850
{
4951
return (another instanceof DbPrincipal) &&
5052
databaseName.equals(((DbPrincipal) another).databaseName) &&
51-
name.equals(((DbPrincipal) another).name);
53+
roleName.equals(((DbPrincipal) another).roleName) &&
54+
userName.equals(((DbPrincipal) another).userName);
5255
}
5356

5457
@Override
5558
public int hashCode()
5659
{
57-
return name.hashCode();
60+
return userName.hashCode();
5861
}
5962

6063
@Override
6164
public String toString()
6265
{
63-
return databaseName + "::" + name;
66+
return databaseName + "::" + userName;
6467
}
6568

6669
String getDatabaseName()
6770
{
6871
return databaseName;
6972
}
73+
74+
public String getRoleName()
75+
{
76+
return roleName;
77+
}
7078
}

src/fbjava/src/main/java/org/firebirdsql/fbjava/impl/ExternalEngine.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,7 @@ private Routine getRoutine(IStatus status, IExternalContext context, IRoutineMet
11521152
String className = entryPoint.substring(0, methodStart - 1).trim();
11531153
String methodName = entryPoint.substring(methodStart, paramsStart).trim();
11541154

1155-
Class<?> clazz = runInClassLoader(context.getUserName(), className, methodName,
1155+
Class<?> clazz = runInClassLoader(status, context, className, methodName,
11561156
() -> Class.forName(className, true, sharedData.classLoader));
11571157

11581158
Routine routine = new Routine(this);
@@ -1379,15 +1379,15 @@ private char peekChar(String s, int[] pos) throws FbException
13791379
return s.charAt(pos[0]);
13801380
}
13811381

1382-
<T> T runInClassLoader(String userName, String className, String methodName, CallableThrowable<T> callable)
1383-
throws Throwable
1382+
<T> T runInClassLoader(IStatus status, IExternalContext context, String className, String methodName,
1383+
CallableThrowable<T> callable) throws Throwable
13841384
{
13851385
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
13861386
try
13871387
{
13881388
Thread.currentThread().setContextClassLoader(sharedData.classLoader);
13891389

1390-
Subject subj = DbPolicy.getUserSubject(sharedData.classLoader.databaseName, userName);
1390+
Subject subj = DbPolicy.getUserSubject(status, context, sharedData.classLoader);
13911391

13921392
ProtectionDomain[] protectionDomains = {new ProtectionDomain(sharedData.classLoader.codeSource,
13931393
sharedData.classLoader.codeSourcePermission, sharedData.classLoader,

src/fbjava/src/main/java/org/firebirdsql/fbjava/impl/ExternalFunction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void execute(IStatus status, IExternalContext context, Pointer inMsg, Poi
6565
try (InternalContext internalContext = InternalContext.get(status, context))
6666
{
6767
Object[] in = routine.getFromMessage(status, context, routine.inputParameters, inMsg);
68-
Object[] out = {routine.run(context, in)};
68+
Object[] out = {routine.run(status, context, in)};
6969

7070
routine.putInMessage(status, context, routine.outputParameters, out, 0, outMsg);
7171
}

src/fbjava/src/main/java/org/firebirdsql/fbjava/impl/ExternalProcedure.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public IExternalResultSet open(IStatus status, IExternalContext context, Pointer
7979
for (int i = inCount; i < inOut.length; ++i)
8080
inOut[i] = Array.newInstance(routine.outputParameters.get(i - inCount).javaClass, 1);
8181

82-
ExternalResultSet rs = (ExternalResultSet) routine.run(context, inOut);
82+
ExternalResultSet rs = (ExternalResultSet) routine.run(status, context, inOut);
8383

8484
if (rs == null)
8585
{
@@ -91,8 +91,6 @@ public IExternalResultSet open(IStatus status, IExternalContext context, Pointer
9191
}
9292
else
9393
{
94-
String userName = context.getUserName();
95-
9694
//// FIXME: Stack trace filtering is not working fully correct here.
9795

9896
class ExtResultSet implements IExternalResultSetIntf
@@ -104,7 +102,7 @@ public void dispose()
104102
{
105103
try
106104
{
107-
routine.engine.runInClassLoader(userName,
105+
routine.engine.runInClassLoader(status, context,
108106
routine.method.getDeclaringClass().getName(), routine.method.getName(),
109107
() -> {
110108
rs.close();
@@ -126,7 +124,7 @@ public boolean fetch(IStatus status) throws FbException
126124

127125
try
128126
{
129-
return routine.engine.runInClassLoader(userName,
127+
return routine.engine.runInClassLoader(status, context,
130128
routine.method.getDeclaringClass().getName(), routine.method.getName(),
131129
() -> {
132130
if (rs.fetch())

src/fbjava/src/main/java/org/firebirdsql/fbjava/impl/Routine.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ void putInMessage(IStatus status, IExternalContext context, List<Parameter> para
112112
}
113113
}
114114

115-
Object run(IExternalContext context, Object[] args) throws Throwable
115+
Object run(IStatus status, IExternalContext context, Object[] args) throws Throwable
116116
{
117-
return engine.runInClassLoader(context.getUserName(), method.getDeclaringClass().getName(), method.getName(),
117+
return engine.runInClassLoader(status, context, method.getDeclaringClass().getName(), method.getName(),
118118
() -> {
119119
try
120120
{

0 commit comments

Comments
 (0)