]> git.argeo.org Git - lgpl/argeo-commons.git/blob - websocket/CmsWebSocketConfigurator.java
Prepare next development cycle
[lgpl/argeo-commons.git] / websocket / CmsWebSocketConfigurator.java
1 package org.argeo.cms.websocket;
2
3 import java.security.AccessController;
4 import java.security.PrivilegedAction;
5 import java.util.List;
6
7 import javax.security.auth.Subject;
8 import javax.security.auth.login.LoginContext;
9 import javax.servlet.http.HttpSession;
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;
15
16 import org.apache.commons.logging.Log;
17 import org.apache.commons.logging.LogFactory;
18 import org.argeo.cms.auth.HttpRequestCallbackHandler;
19 import org.argeo.node.NodeConstants;
20 import org.osgi.service.http.context.ServletContextHelper;
21
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";
25
26 private final static Log log = LogFactory.getLog(CmsWebSocketConfigurator.class);
27 final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
28
29 @Override
30 public boolean checkOrigin(String originHeaderValue) {
31 return true;
32 }
33
34 @Override
35 public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
36 try {
37 return endpointClass.getDeclaredConstructor().newInstance();
38 } catch (Exception e) {
39 throw new IllegalArgumentException("Cannot get endpoint instance", e);
40 }
41 }
42
43 @Override
44 public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested) {
45 return requested;
46 }
47
48 @Override
49 public String getNegotiatedSubprotocol(List<String> supported, List<String> requested) {
50 if ((requested == null) || (requested.size() == 0))
51 return "";
52 if ((supported == null) || (supported.isEmpty()))
53 return "";
54 for (String possible : requested) {
55 if (possible == null)
56 continue;
57 if (supported.contains(possible))
58 return possible;
59 }
60 return "";
61 }
62
63 @Override
64 public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
65 HttpSession httpSession = (HttpSession) request.getHttpSession();
66 if (log.isDebugEnabled() && httpSession != null)
67 log.debug("Web socket HTTP session id: " + httpSession.getId());
68
69 if (httpSession == null) {
70 rejectResponse(response, null);
71 }
72 try {
73 LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER,
74 new HttpRequestCallbackHandler(httpSession));
75 lc.login();
76 if (log.isDebugEnabled())
77 log.debug("Web socket logged-in as " + lc.getSubject());
78 Subject.doAs(lc.getSubject(), new PrivilegedAction<Void>() {
79
80 @Override
81 public Void run() {
82 sec.getUserProperties().put(ServletContextHelper.REMOTE_USER, AccessController.getContext());
83 return null;
84 }
85
86 });
87 } catch (Exception e) {
88 rejectResponse(response, e);
89 }
90 }
91
92 /**
93 * Behaviour when the web socket could not be authenticated. Throws an
94 * {@link IllegalStateException} by default.
95 *
96 * @param e can be null
97 */
98 protected void rejectResponse(HandshakeResponse response, Exception e) {
99 // violent implementation, as suggested in
100 // https://stackoverflow.com/questions/21763829/jsr-356-how-to-abort-a-websocket-connection-during-the-handshake
101 // throw new IllegalStateException("Web socket cannot be authenticated");
102 }
103 }