dbeaver/pro#1257 Subject mata parameters API (#1325)

* dbeaver/pro#1257 Subject mata parameters API

* dbeaver/pro#1257 Access and teams membership view. Project access editor.

* dbeaver/pro#1257 Project permission editor. Permission read performance

* dbeaver/pro#1257 Teams and users membership edit. Security controller refactoring of current user specific functions.

* dbeaver/pro#1257 Users create/delete
This commit is contained in:
Serge Rider
2022-11-28 20:26:21 +03:00
committed by GitHub
parent c673007f9d
commit ec7a4a5357
8 changed files with 90 additions and 44 deletions
@@ -9,4 +9,13 @@
<extension-point id="io.cloudbeaver.event.handler" name="Wev event handler" schema="schema/io.cloudbeaver.event.handler.exsd"/>
<extension-point id="io.cloudbeaver.metaParameters" name="Meta parameters" schema="schema/io.cloudbeaver.metaParameters.exsd"/>
<extension point="io.cloudbeaver.metaParameters">
<metaParameters type="user">
<propertyGroup label="Main">
<property id="firstName" label="First Name" type="string" description="User first name"/>
<property id="lastName" label="Last Name" type="string" description="User last name"/>
</propertyGroup>
</metaParameters>
</extension>
</plugin>
@@ -127,7 +127,7 @@ public class WebSessionAuthProcessor {
if (authProviderExternal != null && !configMode && !alreadyLoggedIn) {
// We may need to associate new credentials with active user
if (linkWithActiveUser) {
securityController.setUserCredentials(authProviderDescriptor.getId(), authAttrs);
securityController.setCurrentUserCredentials(authProviderDescriptor.getId(), authAttrs);
}
}
@@ -22,6 +22,7 @@ import org.eclipse.core.runtime.Platform;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.impl.PropertyDescriptor;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.security.SMSubjectType;
import org.jkiss.utils.ArrayUtils;
import java.util.ArrayList;
@@ -56,6 +57,10 @@ public class WebMetaParametersRegistry {
return teamParameters;
}
public List<DBPPropertyDescriptor> getMetaParameters(SMSubjectType subjectType) {
return subjectType == SMSubjectType.user ? userParameters : teamParameters;
}
private void loadExtensions(IExtensionRegistry registry) {
IConfigurationElement[] extConfigs = registry.getConfigurationElementsFor(EXTENSION_ID);
for (IConfigurationElement ext : extConfigs) {
@@ -8,14 +8,6 @@
</service>
</extension>
<extension point="io.cloudbeaver.metaParameters">
<metaParameters type="user">
<propertyGroup label="Main">
<property id="firstName" label="First Name" type="string" description="User first name"/>
<property id="lastName" label="Last Name" type="string" description="User last name"/>
</propertyGroup>
</metaParameters>
</extension>
<extension point="io.cloudbeaver.handler">
<sessionHandler id="RPSessionHandler" class="io.cloudbeaver.service.auth.RPSessionHandler"/>
</extension>
@@ -70,7 +70,7 @@ public class WebUserInfo {
public List<String> getLinkedAuthProviders() throws DBWebException {
if (linkedProviders == null) {
try {
linkedProviders = session.getSecurityController().getUserLinkedProviders();
linkedProviders = session.getSecurityController().getCurrentUserLinkedProviders();
} catch (DBException e) {
throw new DBWebException("Error reading user linked providers", e);
}
@@ -86,7 +86,7 @@ public class WebUserInfo {
@Property
public Map<String, Object> getConfigurationParameters() throws DBWebException {
try {
return session.getSecurityController().getUserParameters();
return session.getSecurityController().getCurrentUserParameters();
} catch (DBException e) {
throw new DBWebException("Error reading user parameters", e);
}
@@ -216,7 +216,7 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
) throws DBWebException {
webSession.addInfoMessage("Set user parameter - " + name);
try {
webSession.getSecurityController().setUserParameter(name, value);
webSession.getSecurityController().setCurrentUserParameter(name, value);
return true;
} catch (DBException e) {
throw new DBWebException("Error setting user parameter", e);
@@ -115,7 +115,7 @@ public class LocalAuthProvider implements SMAuthProvider<LocalAuthSession> {
//String newPasswordHash = WebAuthProviderPropertyEncryption.hash.encrypt(userName, newPassword);
storedCredentials.put(CRED_PASSWORD, newPassword);
webSession.getSecurityController().setUserCredentials(authProvider.getId(), storedCredentials);
webSession.getSecurityController().setCurrentUserCredentials(authProvider.getId(), storedCredentials);
return true;
}
@@ -24,12 +24,14 @@ import io.cloudbeaver.auth.SMAuthProviderAssigner;
import io.cloudbeaver.auth.SMAuthProviderExternal;
import io.cloudbeaver.auth.SMAuthProviderFederated;
import io.cloudbeaver.auth.SMAutoAssign;
import io.cloudbeaver.model.app.WebAppConfiguration;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.model.app.WebAuthApplication;
import io.cloudbeaver.model.app.WebAuthConfiguration;
import io.cloudbeaver.model.session.WebAuthInfo;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebAuthProviderRegistry;
import io.cloudbeaver.registry.WebMetaParametersRegistry;
import io.cloudbeaver.service.security.db.CBDatabase;
import io.cloudbeaver.service.security.internal.AuthAttemptSessionInfo;
import io.cloudbeaver.service.security.internal.SMTokenInfo;
@@ -42,6 +44,7 @@ import org.jkiss.dbeaver.model.auth.*;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils;
import org.jkiss.dbeaver.model.impl.jdbc.exec.JDBCTransaction;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.LoggingProgressMonitor;
import org.jkiss.dbeaver.model.security.*;
@@ -118,6 +121,9 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
boolean enabled,
@Nullable String defaultAuthRole
) throws DBException {
if (CommonUtils.isEmpty(userId)) {
throw new DBCException("Empty user name is not allowed");
}
if (isSubjectExists(userId)) {
throw new DBCException("User or team '" + userId + "' already exists");
}
@@ -203,9 +209,23 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
}
}
private static Set<String> getAllLinkedSubjects(Connection dbCon, String subjectId) throws SQLException {
Set<String> allSubjects = new HashSet<>();
allSubjects.add(subjectId);
try (PreparedStatement dbStat = dbCon.prepareStatement("SELECT TEAM_ID FROM CB_USER_TEAM UR WHERE USER_ID=?")) {
dbStat.setString(1, subjectId);
try (ResultSet dbResult = dbStat.executeQuery()) {
while (dbResult.next()) {
allSubjects.add(dbResult.getString(1));
}
}
}
return allSubjects;
}
@NotNull
@Override
public SMTeam[] getUserTeams() throws DBException {
public SMTeam[] getCurrentUserTeams() throws DBException {
return getUserTeams(getUserIdOrThrow());
}
@@ -363,7 +383,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
}
@Override
public Map<String, Object> getUserParameters() throws DBCException {
public Map<String, Object> getCurrentUserParameters() throws DBCException {
String userId = getUserIdOrThrow();
try (Connection dbCon = database.openConnection()) {
Map<String, Object> result = new LinkedHashMap<>();
@@ -385,7 +405,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
}
@Override
public void setUserParameter(String name, Object value) throws DBException {
public void setCurrentUserParameter(String name, Object value) throws DBException {
String userId = getUserIdOrThrow();
try (Connection dbCon = database.openConnection()) {
try (JDBCTransaction txn = new JDBCTransaction(dbCon)) {
@@ -478,7 +498,7 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
}
@Override
public void setUserCredentials(
public void setCurrentUserCredentials(
@NotNull String authProviderId,
@NotNull Map<String, Object> credentials
) throws DBException {
@@ -639,12 +659,12 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
@NotNull
@Override
public Map<String, Object> getUserCredentials(@NotNull String authProviderId) throws DBException {
public Map<String, Object> getCurrentUserCredentials(@NotNull String authProviderId) throws DBException {
return getUserCredentials(getUserIdOrThrow(), authProviderId);
}
@Override
public String[] getUserLinkedProviders() throws DBException {
public String[] getCurrentUserLinkedProviders() throws DBException {
return getUserLinkedProviders(getUserIdOrThrow());
}
@@ -671,6 +691,32 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
}
}
@NotNull
@Override
public SMPropertyDescriptor[] getMetaParametersBySubjectType(SMSubjectType subjectType) throws DBException {
// First add global metas
List<DBPPropertyDescriptor> props = new ArrayList<>(
WebMetaParametersRegistry.getInstance().getMetaParameters(subjectType));
// Add metas from enabled auth providers
WebAppConfiguration appConfiguration = WebAppUtils.getWebApplication().getAppConfiguration();
if (appConfiguration instanceof WebAuthConfiguration) {
for (String apId : ((WebAuthConfiguration)appConfiguration).getEnabledAuthProviders()) {
WebAuthProviderDescriptor ap = WebAuthProviderRegistry.getInstance().getAuthProvider(apId);
if (ap != null) {
List<DBPPropertyDescriptor> metaProps = ap.getMetaParameters(SMSubjectType.team);
if (!CommonUtils.isEmpty(metaProps)) {
props.addAll(metaProps);
}
}
}
}
return props.stream()
.map(SMPropertyDescriptor::new)
.toArray(SMPropertyDescriptor[]::new);
}
///////////////////////////////////////////
// Teams
@@ -742,6 +788,9 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
@Override
public void createTeam(String teamId, String name, String description, String grantor) throws DBCException {
if (CommonUtils.isEmpty(teamId)) {
throw new DBCException("Empty team name is not allowed");
}
if (isSubjectExists(teamId)) {
throw new DBCException("User or team '" + teamId + "' already exists");
}
@@ -831,12 +880,12 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
// Subject functions
@Override
public void setSubjectMetas(String userId, Map<String, String> metaParameters) throws DBCException {
public void setSubjectMetas(@NotNull String subjectId, @NotNull Map<String, String> metaParameters) throws DBCException {
try (Connection dbCon = database.openConnection()) {
try (JDBCTransaction txn = new JDBCTransaction(dbCon)) {
cleanupSubjectMeta(dbCon, userId);
cleanupSubjectMeta(dbCon, subjectId);
if (!metaParameters.isEmpty()) {
saveSubjectMetas(dbCon, userId, metaParameters);
saveSubjectMetas(dbCon, subjectId, metaParameters);
}
txn.commit();
}
@@ -1943,10 +1992,10 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
try (Connection dbCon = database.openConnection()) {
try (JDBCTransaction txn = new JDBCTransaction(dbCon)) {
var sqlBuilder = new StringBuilder("DELETE FROM CB_OBJECT_PERMISSIONS WHERE SUBJECT_ID IN (");
appendStringParameters(sqlBuilder, subjectIds.toArray(String[]::new));
appendStringParameters(sqlBuilder, subjectIds);
sqlBuilder.append(") AND OBJECT_TYPE=? ")
.append("AND OBJECT_ID IN (");
appendStringParameters(sqlBuilder, objectIds.toArray(String[]::new));
appendStringParameters(sqlBuilder, objectIds);
sqlBuilder.append(")");
JDBCUtils.executeStatement(dbCon, sqlBuilder.toString(), objectType.getObjectType());
if (!CommonUtils.isEmpty(permissions)) {
@@ -2019,12 +2068,12 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
public List<SMObjectPermissions> getAllAvailableObjectsPermissions(@NotNull SMObjectType objectType) throws DBException {
String subjectId = getSubjectId();
Set<String> allSubjects = getAllLinkedSubjects(subjectId);
try (Connection dbCon = database.openConnection()) {
Set<String> allSubjects = getAllLinkedSubjects(dbCon, subjectId);
{
var sqlBuilder = new StringBuilder("SELECT OBJECT_ID,PERMISSION FROM CB_OBJECT_PERMISSIONS ");
sqlBuilder.append("WHERE SUBJECT_ID IN (");
appendStringParameters(sqlBuilder, allSubjects.toArray(String[]::new));
appendStringParameters(sqlBuilder, allSubjects);
sqlBuilder.append(") AND OBJECT_TYPE=?");
try (PreparedStatement dbStat = dbCon.prepareStatement(sqlBuilder.toString())) {
dbStat.setString(1, objectType.getObjectType());
@@ -2047,16 +2096,6 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
}
}
private Set<String> getAllLinkedSubjects(String subjectId) throws DBException {
Set<String> allSubjects = new HashSet<>();
allSubjects.add(subjectId);
var userTeamIds = Arrays.stream(getUserTeams(subjectId))
.map(SMTeam::getTeamId)
.collect(Collectors.toSet());
allSubjects.addAll(userTeamIds);
return allSubjects;
}
@NotNull
@Override
public SMObjectPermissions getObjectPermissions(
@@ -2064,12 +2103,12 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
@NotNull String objectId,
@NotNull SMObjectType objectType
) throws DBException {
Set<String> allSubjects = getAllLinkedSubjects(subjectId);
try (Connection dbCon = database.openConnection()) {
Set<String> allSubjects = getAllLinkedSubjects(dbCon, subjectId);
{
var sqlBuilder = new StringBuilder("SELECT PERMISSION FROM CB_OBJECT_PERMISSIONS ");
sqlBuilder.append("WHERE SUBJECT_ID IN (");
appendStringParameters(sqlBuilder, allSubjects.toArray(String[]::new));
appendStringParameters(sqlBuilder, allSubjects);
sqlBuilder.append(") AND OBJECT_TYPE=? AND OBJECT_ID=?");
try (PreparedStatement dbStat = dbCon.prepareStatement(sqlBuilder.toString())) {
@@ -2128,14 +2167,14 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
@Override
public List<SMObjectPermissionsGrant> getSubjectObjectPermissionGrants(@NotNull String subjectId, @NotNull SMObjectType smObjectType) throws DBException {
var allLinkedSubjects = getAllLinkedSubjects(subjectId);
var grantedPermissionsByObjectId = new HashMap<String, SMObjectPermissionsGrant.Builder>();
try (Connection dbCon = database.openConnection()) {
var allLinkedSubjects = getAllLinkedSubjects(dbCon, subjectId);
var sqlBuilder =
new StringBuilder("SELECT OP.OBJECT_ID,S.SUBJECT_TYPE,S.SUBJECT_ID,OP.PERMISSION\n")
.append("FROM CB_OBJECT_PERMISSIONS OP,CB_AUTH_SUBJECT S\n")
.append("WHERE S.SUBJECT_ID = OP.SUBJECT_ID AND OP.SUBJECT_ID IN (");
appendStringParameters(sqlBuilder, allLinkedSubjects.toArray(String[]::new));
appendStringParameters(sqlBuilder, allLinkedSubjects);
sqlBuilder.append(") AND OP.OBJECT_TYPE=?");
try (PreparedStatement dbStat = dbCon.prepareStatement(sqlBuilder.toString())) {
dbStat.setString(1, smObjectType.getObjectType());
@@ -2161,10 +2200,11 @@ public class CBEmbeddedSecurityController implements SMAdminController, SMAuthen
}
}
private void appendStringParameters(StringBuilder sql, @NotNull String[] subjectIds) {
for (int i = 0; i < subjectIds.length; i++) {
String id = subjectIds[i];
if (i > 0) sql.append(",");
private static void appendStringParameters(StringBuilder sql, @NotNull Collection<String> subjectIds) {
boolean first = true;
for (String id : subjectIds) {
if (!first) sql.append(",");
first = false;
sql.append("'").append(id.replace("'", "''")).append("'");
}
}