Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/src/org/labkey/api/admin/AdminUrls.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public interface AdminUrls extends UrlProvider
ActionURL getCspReportToURL();

ActionURL getAllowedExternalRedirectHostsURL();
ActionURL getDeleteEncryptedContentURL();

/**
* Simply adds an "Admin Console" link to nav trail if invoked in the root container. Otherwise, root is unchanged.
Expand Down
40 changes: 38 additions & 2 deletions api/src/org/labkey/api/data/EncryptedPropertyStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@ protected PropertyEncryption getPreferredPropertyEncryption()
protected void appendWhereFilter(SQLFragment sql)
{
sql.append("NOT Encryption = ?");
sql.add("None");
sql.add(PropertyEncryption.None.toString());
}

@Override
public String getDescription()
{
return "Encrypted Property Sets";
}

@Override
Expand All @@ -103,7 +109,7 @@ public void migrateEncryptedContent(String oldPassPhrase, String keySource, AESC
TableInfo sets = PropertySchema.getInstance().getTableInfoPropertySets();
TableInfo props = PropertySchema.getInstance().getTableInfoProperties();

new TableSelector(sets, Set.of("Set", "Category", "Encryption"), new SimpleFilter(FieldKey.fromParts("Encryption"), "None", CompareType.NEQ), null).forEachMap(map -> {
new TableSelector(sets, Set.of("Set", "Category", "Encryption"), getEncryptedSetFilter(), null).forEachMap(map -> {
int set = (int)map.get("Set");
String encryption = (String)map.get("Encryption");
String propertySetName = "\"" + map.get("Category") + "\" (Set = " + set + ")";
Expand Down Expand Up @@ -165,4 +171,34 @@ public void migrateEncryptedContent(String oldPassPhrase, String keySource, AESC
clearCache();
LOG.info(" Migration of encrypted property store values is complete");
}

@Override
public void deleteEncryptedContent()
{
LOG.info("Deleting all encrypted property sets");
TableInfo sets = PropertySchema.getInstance().getTableInfoPropertySets();
new TableSelector(
sets,
Set.of("Set", "Category", "Encryption"),
getEncryptedSetFilter(),
null
).forEachMap(map -> {
int set = (int)map.get("Set");
PropertyManager.deleteSetDirectly(set);
});
}

public long getEncryptedPropertySetCount()
{
return new TableSelector(
PropertySchema.getInstance().getTableInfoPropertySets(),
getEncryptedSetFilter(),
null
).getRowCount();
}

private Filter getEncryptedSetFilter()
{
return new SimpleFilter(FieldKey.fromParts("Encryption"), PropertyEncryption.None.toString(), CompareType.NEQ);
}
}
27 changes: 27 additions & 0 deletions api/src/org/labkey/api/data/PropertyManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,33 @@ public static void deleteSetDirectly(User user, String objectId, String category
new SqlExecutor(SCHEMA.getSchema()).execute(deleteSets);
}

// Note: caller is responsible for clearing caches
public static void deleteSetDirectly(int propertySet)
{
SqlExecutor executor = new SqlExecutor(SCHEMA.getSchema());
var setSelectName = SCHEMA.getTableInfoProperties().getColumn("Set").getSelectIdentifier(); // Keyword in some dialects

try (Transaction t = SCHEMA.getSchema().getScope().ensureTransaction())
{
SQLFragment deleteProps = new SQLFragment("DELETE FROM ")
.append(SCHEMA.getTableInfoProperties())
.append(" WHERE ")
.appendIdentifier(setSelectName)
.append(" = ?")
.add(propertySet);
executor.execute(deleteProps);

SQLFragment deleteSet = new SQLFragment("DELETE FROM ")
.append(SCHEMA.getTableInfoPropertySets())
.append(" WHERE ")
.appendIdentifier(setSelectName)
.append(" = ?")
.add(propertySet);
executor.execute(deleteSet);
t.commit();
}
}

public static class PropertyEntry
{
private int _userId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,13 @@ private RConnection getConnection(RConnectionHolder rh, ScriptContext context)
if (rconn.needLogin())
{
LOG.debug("Logging in to RServe as '" + _def.getUser() + "'");
rconn.login(_def.getUser(), _def.getPassword());
String password = _def.getPassword();
if (password == null)
{
LOG.warn("RServe password is null! Login will likely fail.");
password = "";
}
rconn.login(_def.getUser(), password);
}

initEnv(rconn, context);
Expand Down
77 changes: 52 additions & 25 deletions api/src/org/labkey/api/security/AuthenticationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -327,41 +327,68 @@ public static void reorderConfigurations(User user, String name, int[] rowIds)
}
}

static final EncryptionMigrationHandler ENCRYPTION_MIGRATION_HANDLER = (oldPassPhrase, keySource, oldConfig) -> {
Algorithm decryptAes = Encryption.getAES128(oldPassPhrase, keySource, oldConfig);
_log.info(" Attempting to migrate encrypted properties in authentication configurations");
TableInfo tinfo = CoreSchema.getInstance().getTableInfoAuthenticationConfigurations();
Map<Integer, String> map = new TableSelector(tinfo, PageFlowUtil.set("RowId", "EncryptedProperties"),
static final EncryptionMigrationHandler ENCRYPTION_MIGRATION_HANDLER = new EncryptionMigrationHandler()
{
@Override
public String getDescription()
{
return "Encrypted Authentication Properties";
}

@Override
public void migrateEncryptedContent(String oldPassPhrase, String keySource, Encryption.AESConfig oldConfig)
{
Algorithm decryptAes = Encryption.getAES128(oldPassPhrase, keySource, oldConfig);
_log.info(" Attempting to migrate encrypted properties in authentication configurations");
TableInfo tinfo = CoreSchema.getInstance().getTableInfoAuthenticationConfigurations();
Map<Integer, String> map = new TableSelector(tinfo, PageFlowUtil.set("RowId", "EncryptedProperties"),
new SimpleFilter(FieldKey.fromParts("EncryptedProperties"), null, CompareType.NONBLANK), null).getValueMap(Integer.class);
Map<String, String> saveMap = new HashMap<>();
Map<String, String> saveMap = new HashMap<>();

map.forEach((key, value) -> {
try
{
_log.info(" Migrating encrypted properties for configuration " + key);
map.forEach((key, value) -> {
try
{
String decryptedValue = decryptAes.decrypt(Base64.decodeBase64(value));
String newEncryptedValue = Base64.encodeBase64String(AES.get().encrypt(decryptedValue));
assert decryptedValue.equals(AES.get().decrypt(Base64.decodeBase64(newEncryptedValue)));
_log.info(" Migrating encrypted properties for configuration {}", key);
try
{
String decryptedValue = decryptAes.decrypt(Base64.decodeBase64(value));
String newEncryptedValue = Base64.encodeBase64String(AES.get().encrypt(decryptedValue));
assert decryptedValue.equals(AES.get().decrypt(Base64.decodeBase64(newEncryptedValue)));

if (newEncryptedValue != null)
if (newEncryptedValue != null)
{
saveMap.put("EncryptedProperties", newEncryptedValue);
Table.update(null, tinfo, saveMap, key);
}
}
catch (DecryptionException e)
{
saveMap.put("EncryptedProperties", newEncryptedValue);
Table.update(null, tinfo, saveMap, key);
_log.info(" Failed to decrypt encrypted properties for configuration {}. It will be skipped.", key);
}
}
catch (DecryptionException e)
catch (Exception e)
{
_log.info(" Failed to decrypt encrypted properties for configuration " + key + ". It will be skipped.");
_log.error("Exception while migrating configuration {}", key, e);
}
}
catch (Exception e)
{
_log.error("Exception while migrating configuration " + key, e);
}
});
_log.info(" Migration of encrypted properties in authentication configurations is complete");
});
_log.info(" Migration of encrypted properties in authentication configurations is complete");
}

@Override
public void deleteEncryptedContent()
{
_log.info("Clearing the core.AuthenticationConfigurations.EncryptedProperties column");
TableInfo tinfo = CoreSchema.getInstance().getTableInfoAuthenticationConfigurations();
new TableSelector(
tinfo,
PageFlowUtil.set("RowId"),
new SimpleFilter(FieldKey.fromParts("EncryptedProperties"), null, CompareType.NONBLANK),
null
).forEach(
Integer.class,
rowId -> Table.update(null, tinfo, PageFlowUtil.map("EncryptedProperties", null), rowId)
);
}
};

// Register a handler so encrypted properties are migrated whenever the encryption key changes
Expand Down
4 changes: 2 additions & 2 deletions api/src/org/labkey/api/security/ConfigurationSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ public ConfigurationSettings(Map<String, Object> settings)
}
catch (Encryption.DecryptionException e)
{
LOG.warn("Encrypted properties can't be read", e);
LOG.warn("Encrypted properties can't be decrypted", e);
}
}
else
{
LOG.warn("Encrypted properties can't be read: encryption key has not been set in " + AppProps.getInstance().getWebappConfigurationFilename() + "!");
LOG.warn("Encrypted properties can't be read: encryption key has not been set in {}!", AppProps.getInstance().getWebappConfigurationFilename());
}
}

Expand Down
Loading
Loading