1 package org
.argeo
.cms
.websocket
;
3 import java
.security
.AccessController
;
4 import java
.security
.PrivilegedAction
;
7 import javax
.security
.auth
.Subject
;
8 import javax
.security
.auth
.login
.LoginContext
;
9 import javax
.websocket
.Extension
;
10 import javax
.websocket
.HandshakeResponse
;
11 import javax
.websocket
.server
.HandshakeRequest
;
12 import javax
.websocket
.server
.ServerEndpointConfig
;
13 import javax
.websocket
.server
.ServerEndpointConfig
.Configurator
;
15 import org
.argeo
.api
.cms
.CmsAuth
;
16 import org
.argeo
.api
.cms
.CmsLog
;
17 import org
.argeo
.cms
.auth
.RemoteAuthCallbackHandler
;
18 import org
.argeo
.cms
.auth
.RemoteAuthSession
;
19 import org
.argeo
.cms
.servlet
.ServletHttpSession
;
20 import org
.osgi
.service
.http
.context
.ServletContextHelper
;
22 /** Customises the initialisation of a new web socket. */
23 public class CmsWebSocketConfigurator
extends Configurator
{
24 public final static String WEBSOCKET_SUBJECT
= "org.argeo.cms.websocket.subject";
26 private final static CmsLog log
= CmsLog
.getLog(CmsWebSocketConfigurator
.class);
27 final static String HEADER_WWW_AUTHENTICATE
= "WWW-Authenticate";
30 public boolean checkOrigin(String originHeaderValue
) {
35 public <T
> T
getEndpointInstance(Class
<T
> endpointClass
) throws InstantiationException
{
37 return endpointClass
.getDeclaredConstructor().newInstance();
38 } catch (Exception e
) {
39 throw new IllegalArgumentException("Cannot get endpoint instance", e
);
44 public List
<Extension
> getNegotiatedExtensions(List
<Extension
> installed
, List
<Extension
> requested
) {
49 public String
getNegotiatedSubprotocol(List
<String
> supported
, List
<String
> requested
) {
50 if ((requested
== null) || (requested
.size() == 0))
52 if ((supported
== null) || (supported
.isEmpty()))
54 for (String possible
: requested
) {
57 if (supported
.contains(possible
))
64 public void modifyHandshake(ServerEndpointConfig sec
, HandshakeRequest request
, HandshakeResponse response
) {
66 RemoteAuthSession httpSession
= new ServletHttpSession((javax
.servlet
.http
.HttpSession
) request
.getHttpSession());
67 if (log
.isDebugEnabled() && httpSession
!= null)
68 log
.debug("Web socket HTTP session id: " + httpSession
.getId());
70 if (httpSession
== null) {
71 rejectResponse(response
, null);
74 LoginContext lc
= new LoginContext(CmsAuth
.LOGIN_CONTEXT_USER
,
75 new RemoteAuthCallbackHandler(httpSession
));
77 if (log
.isDebugEnabled())
78 log
.debug("Web socket logged-in as " + lc
.getSubject());
79 Subject
.doAs(lc
.getSubject(), new PrivilegedAction
<Void
>() {
83 sec
.getUserProperties().put(ServletContextHelper
.REMOTE_USER
, AccessController
.getContext());
88 } catch (Exception e
) {
89 rejectResponse(response
, e
);
94 * Behaviour when the web socket could not be authenticated. Throws an
95 * {@link IllegalStateException} by default.
97 * @param e can be null
99 protected void rejectResponse(HandshakeResponse response
, Exception e
) {
100 // violent implementation, as suggested in
101 // https://stackoverflow.com/questions/21763829/jsr-356-how-to-abort-a-websocket-connection-during-the-handshake
102 // throw new IllegalStateException("Web socket cannot be authenticated");
106 //if (!webServerConfig.isEmpty()) {
107 //webServerConfig.put("customizer.class", KernelConstants.CMS_JETTY_CUSTOMIZER_CLASS);
109 //// TODO centralise with Jetty extender
110 //Object webSocketEnabled = webServerConfig.get(InternalHttpConstants.WEBSOCKET_ENABLED);
111 //if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
112 // bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null);
113 // webServerConfig.put(InternalHttpConstants.WEBSOCKET_ENABLED, "true");