Skip to content

Commit c7f447e

Browse files
committed
v0.5.15 update
added check where the addon will only push password hashes of type {SSHA512} back to the database (important for backwards compatibility if WebCTRL10.0 servers are connected alongside earlier versions) added obfuscation for a couple parameters that were getting blocked by AWS load balancer firewalls updated dependency Jsch from 2.27.2 to 2.27.5 updated dependency pgJDBC from 42.7.7 to 42.7.8 remove ", Inc." from a couple license statements added a minor internal API that I might invoke from other addons minor README updates
1 parent 4b02442 commit c7f447e

18 files changed

+124
-120
lines changed

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# PostgreSQL_Connect
22

3-
WebCTRL is a trademark of Automated Logic Corporation. Any other trademarks mentioned herein are the property of their respective owners.
3+
WebCTRL is a trademark of Automated Logic Corporation. Any other trademarks mentioned herein are the property of their respective owners.
44

55
- [PostgreSQL\_Connect](#postgresql_connect)
66
- [Feature Summary](#feature-summary)
@@ -14,7 +14,7 @@ WebCTRL is a trademark of Automated Logic Corporation. Any other trademarks men
1414
- [Add-On Connection](#add-on-connection)
1515
- [SFTP Server](#sftp-server)
1616
- [Shared Settings](#shared-settings)
17-
- [Synchronizaton](#synchronizaton)
17+
- [Synchronization](#synchronization)
1818
- [Server List](#server-list)
1919
- [Add-On Whitelist](#add-on-whitelist)
2020
- [Add-On Blacklist](#add-on-blacklist)
@@ -49,7 +49,7 @@ When this WebCTRL add-on is installed and configured, it periodically communicat
4949
- Operator synchronization:
5050
- Synchronize a subnet of whitelisted operators between all connected servers
5151
- Create a whitelisted operator in the database, and it gets pushed out everywhere
52-
- Modify your password on one server, and the change propogates to all other servers
52+
- Modify your password on one server, and the change propagates to all other servers
5353
- Blacklist operators to delete them everywhere
5454
- Local operators (those that are not white or blacklisted) remain unaltered
5555
- WebCTRL's operator authentication provider is unaffected
@@ -196,7 +196,7 @@ In addition to the SFTP connection settings shown in the previous section, there
196196
| `debug` | `false` | When enabled, log messages will be more verbose. |
197197
| `log_expiration` | `60` | Specifies how many days to retain log messages in the database. |
198198
| `auto_update` | `true` | Specifies whether to attempt automatic updates for this add-on. |
199-
| `version` | `0.5.14` | When `auto_update` is enabled, any connected client whose add-on version is less than this value will be updated. |
199+
| `version` | `0.5.15` | When `auto_update` is enabled, any connected client whose add-on version is less than this value will be updated. |
200200
| `download_path` | `/webctrl/addons/PostgreSQL_Connect.addon` | When `auto_update` is enabled, this is the SFTP server path where the latest version add-on file will be retrieved. |
201201
| `license_directory` | `/webctrl/licenses` | Specifies an SFTP server directory path for where to store WebCTRL license files. |
202202
| `ftp_host` | `postgresql.domain.com` | SFTP server hostname or IP address. |
@@ -217,7 +217,7 @@ When trying to push out an update for the add-on, you should do things in the fo
217217

218218
You cannot use this mechanism to automatically downgrade the add-on to an earlier version.
219219

220-
## Synchronizaton
220+
## Synchronization
221221

222222
Now that your PostgreSQL database and SFTP server is configured, this section explains how to setup synchronization of operators, add-ons, reverse SSH tunnels, and trends. We will go through each page accessible from the web UI.
223223

@@ -230,7 +230,7 @@ This page lists all connected servers. If a server is decomissioned or permanent
230230
| ID | `1` | Internal ID which uniquely identifies the server within the PostgreSQL database. (Read-only) |
231231
| Name | `ACES Main Building` | User-friendly display name for the server. This defaults to the display name of the root of the Geo tree. |
232232
| WebCTRL Version | `8.5.002.20230323-123687` | Full version of the WebCTRL server. (Read-only) |
233-
| Add-On Version | `0.5.14` | Installed version of the PostgreSQL_Connect add-on. (Read-only) |
233+
| Add-On Version | `0.5.15` | Installed version of the PostgreSQL_Connect add-on. (Read-only) |
234234
| IP Address | `123.45.67.89` | External IP address of the server as viewed by the PostgreSQL database. (Read-only) |
235235
| Last Sync | `2024-12-02 14:05:32` | Timestamp of the last successful synchronization. If synced within the last 24 hours, the background color is green; otherwise, the background is red. (Read-only) |
236236
| License | `WebCTRL Premium` | Click this field to download WebCTRL's license. (Read-only) |
@@ -285,7 +285,9 @@ The table structure of this page is identical to that of the operator whitelist
285285

286286
### Reverse Operator Sync
287287

288-
When whitelisted operators changes their passwords (or other attributes) locally on the WebCTRL server, the changes are pushed back to the database during the next sync interval. It can take up to two full sync cycles for the password change to propogate to other connected server. With this logic as stated, it would be possible for a local admin at one site to reset the passwords of everyone across all sites (either accidentally or maliciously). To mitigiate this possibility, the whitelisted operators being updated must have logged into the server within the past 8 hours in order for changes to propagate. Note that this reverse sync only functions on WebCTRL versions 8.5 and later.
288+
When whitelisted operators changes their passwords (or other attributes) locally on the WebCTRL server, the changes are pushed back to the database during the next sync interval. It can take up to two full sync cycles for the password change to propogate to other connected servers. With this logic as stated, it would be possible for a local admin at one site to reset the passwords of everyone across all sites (either accidentally or maliciously). To mitigiate this possibility, the whitelisted operators being updated must have logged into the server within the past 8 hours in order for changes to propagate.
289+
290+
Note that this reverse sync only functions on WebCTRL versions 8.5 and 9.0. WebCTRL8.0 does not record the last login timestamp of operators, so the 8 hours propagation window cannot be determined in such cases. WebCTRL10.0 changed the default password hashing algorithm to PBKDF2. Since previous versions do not support PBKDF2, having WebCTRL10.0 hashes sync back to the database would break backwards compatibility. After sufficient time passes, we may drop support for these previous versions, and then PBKDF2 hashes will be preferred over SHA512.
289291

290292
### Operator Blacklist
291293

@@ -464,7 +466,7 @@ CREATE INDEX webctrl_trend_data_time ON webctrl.trend_data ("time" DESC);
464466

465467
### Packaged Dependencies
466468

467-
- [PostgreSQL JDBC 42.7.7](https://jdbc.postgresql.org/) - Used to connect to PostgreSQL databases.
469+
- [PostgreSQL JDBC 42.7.8](https://jdbc.postgresql.org/) - Used to connect to PostgreSQL databases.
468470
- [JSch 2.27.2](https://github.com/mwiede/jsch) - Used to connect to SFTP servers.
469471
- [JSON-java 20250517](https://github.com/stleary/JSON-java) - Used to encode and decode JSON data.
470472

config/BUILD_DETAILS

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,38 @@ Compilation Flags:
77
--release 11
88

99
Runtime Dependencies:
10-
addonsupport-api-addon-1.10.0
11-
alarmmanager-api-addon-1.10.0
12-
bacnet-api-core-1.10.007-20240227.1003r
13-
datatable-api-addon-1.10.0
14-
directaccess-api-addon-1.10.0
15-
logicbuilder-api-addon-1.10.0
16-
semantics-api-addon-1.10.0
17-
tomcat-embed-core-9.0.87
18-
webaccess-api-addon-1.10.0
19-
xdatabase-api-addon-1.10.0
20-
cjupdate-1.2.4
21-
common-9.0.002
10+
addonsupport-api-addon-1.11.0
11+
alarmmanager-api-addon-1.11.0
12+
bacnet-api-core-1.11.006-20250512.1103r
13+
datatable-api-addon-1.11.0
14+
directaccess-api-addon-1.11.0
15+
logicbuilder-api-addon-1.11.0
16+
semantics-api-addon-1.11.0
17+
tomcat-embed-core-9.0.107
18+
webaccess-api-addon-1.11.0
19+
xdatabase-api-addon-1.11.0
20+
cjupdate-1.2.5
21+
common-10.0.002
2222
commonbaseutils-2.0.5
23-
commonexceptions-9.0.002
24-
core-9.0.002
25-
core-api-9.0.002
26-
databasebridge-9.0.002
27-
datatable-9.0.002
28-
directaccess-9.0.002
29-
directaccess-api-9.0.002
30-
extensionsupport-api-9.0.002
31-
launcher-3.0.10
32-
serviceframework-9.0.002
33-
spring-context-5.3.33
34-
update-api-9.0.002
35-
webserver-api-9.0.002
36-
webui-9.0.002
23+
commonexceptions-10.0.002
24+
core-10.0.002
25+
core-api-10.0.002
26+
databasebridge-10.0.002
27+
datatable-10.0.002
28+
directaccess-10.0.002
29+
directaccess-api-10.0.002
30+
extensionsupport-api-10.0.002
31+
launcher-3.0.12
32+
serviceframework-10.0.002
33+
spring-context-5.3.39
34+
update-api-10.0.002
35+
webserver-api-10.0.002
36+
webui-10.0.002
3737

3838
Packaged Dependencies:
39-
jsch-2.27.2-sources
40-
jsch-2.27.2
39+
jsch-2.27.5-sources
40+
jsch-2.27.5
4141
json-20250517-sources
4242
json-20250517
43-
postgresql-42.7.7-sources
44-
postgresql-42.7.7
43+
postgresql-42.7.8-sources
44+
postgresql-42.7.8

config/EXTERNAL_DEPS

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
url:postgresql-42.7.7.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.7/postgresql-42.7.7.jar
2-
url:postgresql-42.7.7-sources.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.7/postgresql-42.7.7-sources.jar
3-
url:jsch-2.27.2.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/2.27.2/jsch-2.27.2.jar
4-
url:jsch-2.27.2-sources.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/2.27.2/jsch-2.27.2-sources.jar
1+
url:postgresql-42.7.8.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.8/postgresql-42.7.8.jar
2+
url:postgresql-42.7.8-sources.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.8/postgresql-42.7.8-sources.jar
3+
url:jsch-2.27.5.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/2.27.5/jsch-2.27.5.jar
4+
url:jsch-2.27.5-sources.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/2.27.5/jsch-2.27.5-sources.jar
55
url:json-20250517.jar:https://repo1.maven.org/maven2/org/json/json/20250517/json-20250517.jar
66
url:json-20250517-sources.jar:https://repo1.maven.org/maven2/org/json/json/20250517/json-20250517-sources.jar

root/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<extension version="1">
22
<name>PostgreSQL_Connect</name>
33
<description>Periodically synchronizes operators, add-ons, and specified trends with an external PostgreSQL database.</description>
4-
<version>0.5.14</version>
4+
<version>0.5.15</version>
55
<vendor>Automatic Controls Equipment Systems, Inc.</vendor>
66
<system-menu-provider>aces.webctrl.postgresql.web.SystemMenuEditor</system-menu-provider>
77
</extension>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package aces.webctrl.postgresql.core;
2+
import java.util.*;
3+
public class ExternalAPI {
4+
private final static HashMap<String,Long> loginTimestampOverrides = new HashMap<>();
5+
public static void simulateLogin(String username){
6+
final long cur = System.currentTimeMillis();
7+
loginTimestampOverrides.put(username.toLowerCase(), cur);
8+
Initializer.log("ExternalAPI simulated login for user: " + username);
9+
final long lim = cur - 86400000L;
10+
loginTimestampOverrides.values().removeIf(timestamp -> timestamp < lim);
11+
}
12+
protected static long getLoginOverride(String username){
13+
return loginTimestampOverrides.getOrDefault(username, 0L);
14+
}
15+
}

src/aces/webctrl/postgresql/core/OperatorData.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public void write(OperatorLink link, CoreNode op, boolean admin) throws CoreNotF
5050
}
5151
if (obj instanceof OperatorData){
5252
OperatorData op = (OperatorData)obj;
53-
return lvl5_auto_collapse==op.lvl5_auto_collapse && (Sync.excludeAutoLogoutTime || lvl5_auto_logout==op.lvl5_auto_logout) && username.equals(op.username) && display_name.equals(op.display_name) && password.equals(op.password);
53+
return lvl5_auto_collapse==op.lvl5_auto_collapse && (Sync.excludeAutoLogoutTime || lvl5_auto_logout==op.lvl5_auto_logout) && username.equals(op.username) && display_name.equals(op.display_name) && (password.equals(op.password) || op.password==null || !op.password.startsWith("{SSHA512}"));
5454
}else{
5555
return false;
5656
}
@@ -67,7 +67,7 @@ public String query(OperatorData op){
6767
}
6868
sb.append(" \"display_name\" = ").append(Utility.escapePostgreSQL(op.display_name));
6969
}
70-
if (!password.equals(op.password)){
70+
if (!password.equals(op.password) && op.password!=null && op.password.startsWith("{SSHA512}")){
7171
if (first){
7272
first = false;
7373
}else{

src/aces/webctrl/postgresql/core/SerializationStream.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
BSD 3-Clause License
3-
Copyright (c) 2022, Automatic Controls Equipment Systems, Inc.
3+
Copyright (c) 2022, Automatic Controls Equipment Systems
44
Contributors: Cameron Vogt (@cvogt729)
55
*/
66
package aces.webctrl.postgresql.core;
@@ -177,6 +177,22 @@ public void writeRaw(byte[] arr, int offset, int length){
177177
public void write(String str){
178178
write(str.getBytes(StandardCharsets.UTF_8));
179179
}
180+
/**
181+
* Encodes the given string into UTF_8 bytes and writes to the stream.
182+
* Optionally obfuscate the bytes.
183+
* <ul><li>Required capacity: {@code str.getBytes(StandardCharsets.UTF_8).length+4}</li></ul>
184+
*/
185+
public void write(String str, boolean obfuscate){
186+
if (obfuscate){
187+
byte[] arr = str.getBytes(StandardCharsets.UTF_8);
188+
for (int i=1;i<arr.length;++i){
189+
arr[i]^=arr[i-1];
190+
}
191+
write(arr);
192+
}else{
193+
write(str);
194+
}
195+
}
180196
/**
181197
* Reads a single byte from the stream.
182198
*/
@@ -255,6 +271,19 @@ public int readBytes(byte[] arr, int offset){
255271
public String readString(){
256272
return new String(readBytes(), StandardCharsets.UTF_8);
257273
}
274+
/**
275+
* Reads a UTF_8 encoded string from the stream.
276+
* Optionally de-obfuscate the bytes.
277+
*/
278+
public String readString(boolean obfuscate){
279+
byte[] arr = readBytes();
280+
if (obfuscate){
281+
for (int i=arr.length-1;i>0;--i){
282+
arr[i]^=arr[i-1];
283+
}
284+
}
285+
return new String(arr, StandardCharsets.UTF_8);
286+
}
258287
/**
259288
* @return a {@code ByteBuffer} wrapping the data of this stream.
260289
*/

src/aces/webctrl/postgresql/core/Sync.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ public Sync(Event event, String... args){
112112
for (int i=1;i<args.length;++i){
113113
if (Initializer.stop){ return; }
114114
if (debug){
115-
if (args[i].startsWith("INSERT INTO webctrl.operator_whitelist ") && !args[i].contains("{SSHA512}")){
115+
if (args[i].startsWith("INSERT INTO webctrl.operator_whitelist ") && !args[i].contains("{SSHA512}") && !args[i].contains("{PBKDF2}")){
116116
Initializer.log("INSERT INTO webctrl.operator_whitelist VALUES (**Sensitive Information**);");
117-
}else if (args[i].startsWith("UPDATE webctrl.operator_whitelist ") && !args[i].contains("{SSHA512}")){
117+
}else if (args[i].startsWith("UPDATE webctrl.operator_whitelist ") && !args[i].contains("{SSHA512}") && !args[i].contains("{PBKDF2}")){
118118
Initializer.log("UPDATE webctrl.operator_whitelist SET (**Sensitive Information**);");
119119
}else{
120120
Initializer.log(args[i]);
@@ -237,7 +237,7 @@ public void execute(SystemAccess sys){
237237
String opname;
238238
for (CoreNode op:link.getOperators()){
239239
opname = op.getAttribute(CoreNode.KEY).toLowerCase();
240-
if ((x = operatorWhitelist.get(opname))!=null && (link.getLastLogin(op)+28800L)*1000L>lastSyncTime){
240+
if ((x = operatorWhitelist.get(opname))!=null && (Math.max(ExternalAPI.getLoginOverride(opname),link.getLastLogin(op))+28800L)*1000L>lastSyncTime){
241241
y = new OperatorData(op,opname);
242242
if (!x.equals(y)){
243243
opUpdates.add(x.query(y));

src/aces/webctrl/postgresql/core/Utility.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
BSD 3-Clause License
3-
Copyright (c) 2022, Automatic Controls Equipment Systems, Inc.
3+
Copyright (c) 2022, Automatic Controls Equipment Systems
44
Contributors: Cameron Vogt (@cvogt729)
55
*/
66
package aces.webctrl.postgresql.core;
@@ -647,6 +647,12 @@ public static char[] obfuscate(char[] arr){
647647
}
648648
return arr;
649649
}
650+
/**
651+
* Reverses the order and XORs each character with 4.
652+
*/
653+
public static String obfuscate(String str){
654+
return new String(obfuscate(str.toCharArray()));
655+
}
650656
/**
651657
* @return a {@code String} containing the stack trace of the given {@code Throwable}.
652658
*/

src/aces/webctrl/postgresql/resources/FindTrendsPage.html

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
<!--
2-
BSD 3-Clause License
3-
Copyright (c) 2022, Automatic Controls Equipment Systems, Inc.
4-
Contributors: Cameron Vogt (@cvogt729)
5-
-->
61
<!DOCTYPE html>
72
<html lang="en">
83
<head>

0 commit comments

Comments
 (0)