Skip to content

Commit 4b02442

Browse files
committed
v0.5.14 update
Updated dependency PostgreSQL JDBC 42.7.5 -> 42.7.7 Updated dependency JSch 0.2.24 -> 2.27.2 Updated dependency JSON-java 20250107 -> 20250517 Shortened output of 'about' command Fixed bug in version comparison logic Minor front-end improvements Order server list frontend to show offline servers last added option to reenable WebCTRL's password policy for managed operators connected servers will only auto-push operator updates back to the database when that operator has logged in within the past 8 hours for WebCTRL8.0, auto-pushing operator updates to the database will no longer function added auto_logout_exclude_ids setting to prevent operator session timeouts from syncing to particular servers updated README
1 parent 01b93bc commit 4b02442

File tree

16 files changed

+140
-55
lines changed

16 files changed

+140
-55
lines changed

README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ Now you are ready to test the add-on's connection to your PostgreSQL server.
143143

144144
Fill out all the required fields, click *Save Changes* and then click *Sync Now*. Be sure to specify the correct database name in the connection URL. After waiting a minute, go to the log viewer page and verify that the sync was successful. I suggest using `0 0 * * * *` for the cron expression and `900000` milliseconds for the random maximum offset. This cron expression specifies to start a sync at the beginning of each hour. The random maximum offset specifies to start the sync randomly at some time during the first 15 minutes of the hour. This randomization is important when there are many add-on instances trying to connect to the PostgreSQL database. It ensures the database is not flooded with too many requests all at once.
145145

146-
When the add-on connects to the PostgreSQL database for the first time, it generates a unique server ID for itself. The *Reset ID* button can be used to delete the saved ID and generate a new one.
146+
When the add-on connects to the PostgreSQL database for the first time, it generates a unique server ID for itself. The *Reset ID* button can be used to delete the saved ID and generate a new one. By default, WebCTRL's password policy is disabled for operators managed by this add-on. The setting that forces users to change their passwords at next login is also disabled by default. To permit both behaviors, you may uncheck the *Bypass Password Policy* box.
147147

148148
If firewall restrictions limit PostgreSQL traffic, you can try using an SSH proxy server as an intermediary. In the below example, you would connect to `127.0.0.1:5433/database` after the proxy is set. The proxy is activated only when the add-on tries to sync, and then is deactivated afterwards. For security and simplicity, proxy settings cannot be viewed from a web browser after they are set.
149149

@@ -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.13` | When `auto_update` is enabled, any connected client whose add-on version is less than this value will be updated. |
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. |
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. |
@@ -206,6 +206,7 @@ In addition to the SFTP connection settings shown in the previous section, there
206206
| `ftp_key` | `-----BEGIN OPENSSH PRIVATE KEY----- ...` | Private key which authenticates the client to the SFTP server. |
207207
| `ftp_port_secondary` | `443` | Secondary SFTP port which may be utilized by some servers. This may be useful to bypass certain firewalls. |
208208
| `ftp_port_secondary_ids` | `46;51;60;61;62` | Semi-colon delimited list of server IDs which should use the secondary SFTP port. |
209+
| `auto_logout_exclude_ids` | `46;51;60;61;62` | Semi-colon delimited list of server IDs which should not synchronize operator session timeout thresholds. |
209210

210211
When trying to push out an update for the add-on, you should do things in the following order:
211212

@@ -229,7 +230,7 @@ This page lists all connected servers. If a server is decomissioned or permanent
229230
| ID | `1` | Internal ID which uniquely identifies the server within the PostgreSQL database. (Read-only) |
230231
| Name | `ACES Main Building` | User-friendly display name for the server. This defaults to the display name of the root of the Geo tree. |
231232
| WebCTRL Version | `8.5.002.20230323-123687` | Full version of the WebCTRL server. (Read-only) |
232-
| Add-On Version | `0.5.13` | Installed version of the PostgreSQL_Connect add-on. (Read-only) |
233+
| Add-On Version | `0.5.14` | Installed version of the PostgreSQL_Connect add-on. (Read-only) |
233234
| IP Address | `123.45.67.89` | External IP address of the server as viewed by the PostgreSQL database. (Read-only) |
234235
| 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) |
235236
| License | `WebCTRL Premium` | Click this field to download WebCTRL's license. (Read-only) |
@@ -284,7 +285,7 @@ The table structure of this page is identical to that of the operator whitelist
284285

285286
### Reverse Operator Sync
286287

287-
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. This process can be sped up by clicking the *Sync Operator Data* item in WebCTRL's main menu in the upper-right corner (then propogation will only take one sync cycle).
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.
288289

289290
### Operator Blacklist
290291

@@ -346,12 +347,12 @@ Commands chained together using new-lines in a single entry are fail-fast, which
346347
| `exists <path>` | Asserts that the specified file or directory exists. If non-existent, then command execution is terminated. |
347348
| `!exists <path>` | Asserts that the specified file or directory does not exists. If it exists, then command execution is terminated. |
348349
| `regex <file_path> <find> [replace]` | If a replacement string is not given, then this commands logs all matches of the regular expression in the specified file. If a replacement string is given, then this command edits the specified file by replacing all matches of the regular expression. The file's contents are assumed to be UTF-8 encoded text. The [MULTILINE](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Pattern.html#MULTILINE) and [DOTALL](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/regex/Pattern.html#DOTALL) flags are used by default. |
349-
| `download <sftp_file_path> <local_file_path>` | Downloads a file from the SFTP server into the local file system of the WebCTRL server. |
350+
| `download <sftp_file_path> <local_file_path>` | Downloads a file from the SFTP server into the local file system of the WebCTRL server, overwriting if the file already exists. |
350351
| `upload <local_file_path> <sftp_file_path>` | Uploads a file from the local file system of the WebCTRL server into the SFTP server. |
351352
| `canApplyUpdate <file_path>` | Asserts that WebCTRL is able to apply the specified *.update* patch file. If the update cannot be applied, then command execution is terminated. |
352353
| `!canApplyUpdate <file_path>` | Asserts that WebCTRL is not able to apply the specified *.update* patch file. If the update can be applied, then command execution is terminated. |
353354
| `updateDST` | Updates daylight savings dates stored in the WebCTRL database and marks controllers for a pending parameter download. |
354-
| `opentunnel <listen_port> <target_port> [timeout]` | Open a reverse SSH tunnel from the WebCTRL server to the SFTP server. `listen_port` is opened on the SFTP server, and connections to this port are forwarded to `target_port` on the WebCTRL server. After `timeout` expires, the tunnel will be closed at the next sync. If `timeout` is undefined, then the tunnel stays open until the next server reboot. |
355+
| `opentunnel <listen_port> <target_port> [timeout]` | Open a reverse SSH tunnel from the WebCTRL server to the SFTP server. `listen_port` is opened on the SFTP server, and connections to this port are forwarded to `target_port` on the WebCTRL server. After `timeout` expires (milliseconds), the tunnel will be closed at the next sync. If `timeout` is undefined, then the tunnel stays open until the next server reboot. |
355356
| `closetunnel [listen_port]` | Close a reverse SSH tunnel that was previously opened with the `opentunnel` command. If `listen_port` is unspecified, all tunnels are closed (excluding those configured in the [SSH Tunnels](#ssh-tunnels) section). |
356357
| `listtunnels` | Logs a list of all open SSH tunnels. |
357358

@@ -463,9 +464,9 @@ CREATE INDEX webctrl_trend_data_time ON webctrl.trend_data ("time" DESC);
463464

464465
### Packaged Dependencies
465466

466-
- [PostgreSQL JDBC 42.7.5](https://jdbc.postgresql.org/) - Used to connect to PostgreSQL databases.
467-
- [JSch 0.2.24](https://github.com/mwiede/jsch) - Used to connect to SFTP servers.
468-
- [JSON-java 20250107](https://github.com/stleary/JSON-java) - Used to encode and decode JSON data.
467+
- [PostgreSQL JDBC 42.7.7](https://jdbc.postgresql.org/) - Used to connect to PostgreSQL databases.
468+
- [JSch 2.27.2](https://github.com/mwiede/jsch) - Used to connect to SFTP servers.
469+
- [JSON-java 20250517](https://github.com/stleary/JSON-java) - Used to encode and decode JSON data.
469470

470471
### Server ID Reset
471472

config/BUILD_DETAILS

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
JDK Version:
2-
openjdk 22.0.1 2024-04-16
3-
OpenJDK Runtime Environment (build 22.0.1+8-16)
4-
OpenJDK 64-Bit Server VM (build 22.0.1+8-16, mixed mode, sharing)
2+
openjdk 24.0.1 2025-04-15
3+
OpenJDK Runtime Environment (build 24.0.1+9-30)
4+
OpenJDK 64-Bit Server VM (build 24.0.1+9-30, mixed mode, sharing)
55

66
Compilation Flags:
77
--release 11
@@ -10,7 +10,10 @@ Runtime Dependencies:
1010
addonsupport-api-addon-1.10.0
1111
alarmmanager-api-addon-1.10.0
1212
bacnet-api-core-1.10.007-20240227.1003r
13+
datatable-api-addon-1.10.0
1314
directaccess-api-addon-1.10.0
15+
logicbuilder-api-addon-1.10.0
16+
semantics-api-addon-1.10.0
1417
tomcat-embed-core-9.0.87
1518
webaccess-api-addon-1.10.0
1619
xdatabase-api-addon-1.10.0
@@ -33,9 +36,9 @@ webserver-api-9.0.002
3336
webui-9.0.002
3437

3538
Packaged Dependencies:
36-
jsch-0.2.24-sources
37-
jsch-0.2.24
38-
json-20250107-sources
39-
json-20250107
40-
postgresql-42.7.5-sources
41-
postgresql-42.7.5
39+
jsch-2.27.2-sources
40+
jsch-2.27.2
41+
json-20250517-sources
42+
json-20250517
43+
postgresql-42.7.7-sources
44+
postgresql-42.7.7

config/EXTERNAL_DEPS

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
url:postgresql-42.7.5.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.5/postgresql-42.7.5.jar
2-
url:postgresql-42.7.5-sources.jar:https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.5/postgresql-42.7.5-sources.jar
3-
url:jsch-0.2.24.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.24/jsch-0.2.24.jar
4-
url:jsch-0.2.24-sources.jar:https://repo1.maven.org/maven2/com/github/mwiede/jsch/0.2.24/jsch-0.2.24-sources.jar
5-
url:json-20250107.jar:https://repo1.maven.org/maven2/org/json/json/20250107/json-20250107.jar
6-
url:json-20250107-sources.jar:https://repo1.maven.org/maven2/org/json/json/20250107/json-20250107-sources.jar
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
5+
url:json-20250517.jar:https://repo1.maven.org/maven2/org/json/json/20250517/json-20250517.jar
6+
url:json-20250517-sources.jar:https://repo1.maven.org/maven2/org/json/json/20250517/json-20250517-sources.jar

resources/postgresql_config.png

4.43 KB
Loading

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.13</version>
4+
<version>0.5.14</version>
55
<vendor>Automatic Controls Equipment Systems, Inc.</vendor>
66
<system-menu-provider>aces.webctrl.postgresql.web.SystemMenuEditor</system-menu-provider>
77
</extension>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public class Config {
88
public volatile static String username = null;
99
public volatile static String password = null;
1010
public volatile static String keystorePassword = null;
11+
public volatile static boolean bypassPasswordPolicy = true;
1112
public volatile static int ID;
1213
public final static CronExpression cron = new CronExpression();
1314
public volatile static long maxRandomOffset;
@@ -18,6 +19,7 @@ private static void revertDefaults(){
1819
username = "";
1920
password = "";
2021
keystorePassword = "";
22+
bypassPasswordPolicy = true;
2123
maxRandomOffset = 900000L;
2224
cron.set("0 0 * * * *");
2325
}

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

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -179,20 +179,33 @@ public static void about(final StringBuilder sb){
179179
int i,j;
180180
String[] jvmAtt;
181181
String[] jvmVal;
182+
String s;
183+
final HashSet<String> ignore = new HashSet<String>();
184+
ignore.add("java.class.path");
185+
ignore.add("jarstoskip");
182186
for (Object[] jvmProp : jvm.getOrderedJavaProperties()) {
183-
jvmAtt = CJStringTokenizer.split((String)jvmProp[0], 39);
187+
s = (String)jvmProp[0];
188+
if (ignore.contains(s.toLowerCase())){
189+
continue;
190+
}
191+
jvmAtt = CJStringTokenizer.split(s, 39);
184192
jvmVal = CJStringTokenizer.split((String)jvmProp[1], 135);
185193
j = Math.max(jvmAtt.length, jvmVal.length);
194+
if (j>4){
195+
continue;
196+
}
186197
for (i = 0; i < j; ++i) {
187198
if (i < jvmAtt.length) {
188-
w.print(CJIO.formatToLength(jvmAtt[i], 40, true));
199+
if (i < jvmVal.length && jvmVal[i].length()>0){
200+
w.print(CJIO.formatToLength(jvmAtt[i], 40, true));
201+
}else{
202+
w.print(jvmAtt[i]);
203+
}
189204
} else {
190205
w.print(CJIO.formatToLength("", 40, true));
191206
}
192207
if (i < jvmVal.length) {
193-
w.print(CJIO.formatToLength(jvmVal[i], 135, true));
194-
} else {
195-
w.print(CJIO.formatToLength("", 135, true));
208+
w.print(jvmVal[i]);
196209
}
197210
w.println();
198211
}
@@ -838,10 +851,10 @@ private void writeUpdatesForType(PrintWriter out, List<UpdateInfo> updatesByType
838851
if ("null".equalsIgnoreCase(notesText)) {
839852
notesText = "No notes available.";
840853
}
841-
out.println("Update : " + nextUpdInfo.getFileName());
842-
out.println("Created: " + nextUpdInfo.getCreatedDate());
843-
out.println("Applied: " + nextUpdInfo.getDateApplied());
844-
out.println("Notes : " + notesText);
854+
out.println(nextUpdInfo.getFileName());
855+
//out.println("Created: " + nextUpdInfo.getCreatedDate());
856+
//out.println("Applied: " + nextUpdInfo.getDateApplied());
857+
//out.println("Notes : " + notesText);
845858
out.println();
846859
}
847860
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public class Initializer implements ServletContextListener {
3232
public volatile static Path pgsslkey;
3333
/** Path to the SSL key file to use for SFTP */
3434
public volatile static Path sftpkey;
35+
/** The existence of this file indicates that WebCTRL's password policy should not be bypassed */
36+
public volatile static Path pwPolicyFlag;
3537
/** Path to a temporary file used when downloading addons */
3638
public volatile static Path tmpAddonFile;
3739
/** Path to the directory containing addons */
@@ -141,6 +143,7 @@ public class Initializer implements ServletContextListener {
141143
pgsslroot = root.resolve("pgsslroot.cer");
142144
pgsslkey = root.resolve("pgsslkey.pfx");
143145
sftpkey = root.resolve("id_rsa");
146+
pwPolicyFlag = root.resolve("enf_pw_policy");
144147
if (EMBEDDED_CONNECTION){
145148
try{
146149
if (!Files.exists(pgsslroot)){
@@ -157,6 +160,11 @@ public class Initializer implements ServletContextListener {
157160
}
158161
}
159162
Config.load();
163+
try{
164+
Config.bypassPasswordPolicy = !Files.exists(pwPolicyFlag);
165+
}catch(Throwable t){
166+
log(t);
167+
}
160168
TableCache.init();
161169
try{
162170
Class.forName("org.postgresql.Driver");
@@ -281,6 +289,7 @@ public static boolean debug(){
281289
* Tells the processing thread to invoke a synchronization event ASAP.
282290
*/
283291
public static void syncNow(){
292+
status = "Sync Initiated";
284293
syncNow = true;
285294
synchronized (syncNotifier){
286295
syncNotifier.notifyAll();

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ public void read(CoreNode op, boolean readUsername) throws CoreNotFoundException
3434
public void write(OperatorLink link, CoreNode op, boolean admin) throws CoreNotFoundException, CoreDatabaseException, CJDataValueException {
3535
op.setAttribute(CoreNode.KEY, username);
3636
op.setAttribute(NodeAttribute.lookup(CoreNode.DISPLAY_NAME, "en", true), display_name);
37-
link.setRawPassword(op, password, false);
37+
link.setRawPassword(op, password, false, false);
3838
final CoreNode pref = op.getChild("preferences");
3939
pref.getChild("lvl5_auto_collapse").setBooleanAttribute(CoreNode.VALUE, lvl5_auto_collapse);
40-
pref.getChild("lvl5_auto_logout").setIntAttribute(CoreNode.VALUE, lvl5_auto_logout);
40+
if (!Sync.excludeAutoLogoutTime){
41+
pref.getChild("lvl5_auto_logout").setIntAttribute(CoreNode.VALUE, lvl5_auto_logout);
42+
}
4143
if (admin){
4244
link.assignAdminRole(op);
4345
}
@@ -48,7 +50,7 @@ public void write(OperatorLink link, CoreNode op, boolean admin) throws CoreNotF
4850
}
4951
if (obj instanceof OperatorData){
5052
OperatorData op = (OperatorData)obj;
51-
return lvl5_auto_collapse==op.lvl5_auto_collapse && 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);
5254
}else{
5355
return false;
5456
}
@@ -73,7 +75,7 @@ public String query(OperatorData op){
7375
}
7476
sb.append(" \"password\" = ").append(Utility.escapePostgreSQL(op.password));
7577
}
76-
if (lvl5_auto_logout!=op.lvl5_auto_logout){
78+
if (!Sync.excludeAutoLogoutTime && lvl5_auto_logout!=op.lvl5_auto_logout){
7779
if (first){
7880
first = false;
7981
}else{

0 commit comments

Comments
 (0)