1 package org
.argeo
.cms
.websocket
.server
;
3 import java
.security
.PrivilegedAction
;
4 import java
.util
.ArrayList
;
7 import javax
.security
.auth
.Subject
;
8 import javax
.security
.auth
.login
.LoginContext
;
9 import javax
.security
.auth
.login
.LoginException
;
10 import javax
.websocket
.Extension
;
11 import javax
.websocket
.HandshakeResponse
;
12 import javax
.websocket
.server
.HandshakeRequest
;
13 import javax
.websocket
.server
.ServerEndpointConfig
;
14 import javax
.websocket
.server
.ServerEndpointConfig
.Configurator
;
16 import org
.argeo
.api
.cms
.CmsAuth
;
17 import org
.argeo
.api
.cms
.CmsLog
;
18 import org
.argeo
.cms
.auth
.RemoteAuthCallbackHandler
;
19 import org
.argeo
.cms
.auth
.RemoteAuthRequest
;
20 import org
.argeo
.cms
.auth
.RemoteAuthResponse
;
21 import org
.argeo
.cms
.auth
.RemoteAuthSession
;
22 import org
.argeo
.cms
.auth
.RemoteAuthUtils
;
23 import org
.argeo
.cms
.servlet
.CmsServletContext
;
26 * <strong>Disabled until third party issues are solved.</strong>. Customises
27 * the initialisation of a new web socket.
29 public class CmsWebSocketConfigurator
extends Configurator
{
30 public final static String WEBSOCKET_SUBJECT
= "org.argeo.cms.websocket.subject";
31 public final static String REMOTE_USER
= "org.osgi.service.http.authentication.remote.user";
33 private final static CmsLog log
= CmsLog
.getLog(CmsWebSocketConfigurator
.class);
34 final static String HEADER_WWW_AUTHENTICATE
= "WWW-Authenticate";
37 public boolean checkOrigin(String originHeaderValue
) {
42 public <T
> T
getEndpointInstance(Class
<T
> endpointClass
) throws InstantiationException
{
44 return endpointClass
.getDeclaredConstructor().newInstance();
45 } catch (Exception e
) {
46 throw new IllegalArgumentException("Cannot get endpoint instance", e
);
51 public List
<Extension
> getNegotiatedExtensions(List
<Extension
> installed
, List
<Extension
> requested
) {
56 public String
getNegotiatedSubprotocol(List
<String
> supported
, List
<String
> requested
) {
57 if ((requested
== null) || (requested
.size() == 0))
59 if ((supported
== null) || (supported
.isEmpty()))
61 for (String possible
: requested
) {
64 if (supported
.contains(possible
))
71 public void modifyHandshake(ServerEndpointConfig sec
, HandshakeRequest request
, HandshakeResponse response
) {
75 WebSocketHandshakeRequest remoteAuthRequest
= new WebSocketHandshakeRequest(request
);
76 WebSocketHandshakeResponse remoteAuthResponse
= new WebSocketHandshakeResponse(response
);
77 // RemoteAuthSession httpSession = new ServletHttpSession(
78 // (javax.servlet.http.HttpSession) request.getHttpSession());
79 RemoteAuthSession remoteAuthSession
= remoteAuthRequest
.getSession();
80 if (log
.isDebugEnabled() && remoteAuthSession
!= null)
81 log
.debug("Web socket HTTP session id: " + remoteAuthSession
.getId());
83 // if (remoteAuthSession == null) {
84 // rejectResponse(response, null);
86 ClassLoader currentThreadContextClassLoader
= Thread
.currentThread().getContextClassLoader();
87 Thread
.currentThread().setContextClassLoader(CmsServletContext
.class.getClassLoader());
90 lc
= CmsAuth
.USER
.newLoginContext(new RemoteAuthCallbackHandler(remoteAuthRequest
, remoteAuthResponse
));
92 } catch (LoginException e
) {
93 // FIXME better analyse failure so as not to try endlessly
94 if (authIsRequired(remoteAuthRequest
, remoteAuthResponse
)) {
95 int statusCode
= RemoteAuthUtils
.askForWwwAuth(remoteAuthResponse
, "Argeo", true);
96 remoteAuthResponse
.setHeader("Status-Code", Integer
.toString(statusCode
));
99 lc
= RemoteAuthUtils
.anonymousLogin(remoteAuthRequest
, remoteAuthResponse
);
102 rejectResponse(response
, e
);
104 Thread
.currentThread().setContextClassLoader(currentThreadContextClassLoader
);
107 Subject subject
= lc
.getSubject();
108 Subject
.doAs(subject
, new PrivilegedAction
<Void
>() {
112 // TODO also set login context in order to log out ?
113 RemoteAuthUtils
.configureRequestSecurity(remoteAuthRequest
);
120 protected boolean authIsRequired(RemoteAuthRequest remoteAuthRequest
, RemoteAuthResponse remoteAuthResponse
) {
125 * Behaviour when the web socket could not be authenticated. Throws an
126 * {@link IllegalStateException} by default.
128 * @param e can be null
130 protected void rejectResponse(HandshakeResponse response
, Exception e
) {
131 response
.getHeaders().put(HandshakeResponse
.SEC_WEBSOCKET_ACCEPT
, new ArrayList
<String
>());
132 // violent implementation, as suggested in
133 // https://stackoverflow.com/questions/21763829/jsr-356-how-to-abort-a-websocket-connection-during-the-handshake
134 // throw new IllegalStateException("Web socket cannot be authenticated");