]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.ee/src/org/argeo/cms/websocket/server/CmsWebSocketConfigurator.java
Improve SSH server. Rename node directory to private.
[lgpl/argeo-commons.git] / org.argeo.cms.ee / src / org / argeo / cms / websocket / server / CmsWebSocketConfigurator.java
1 package org.argeo.cms.websocket.server;
2
3 import java.security.PrivilegedAction;
4 import java.util.ArrayList;
5 import java.util.List;
6
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;
15
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;
24
25 /**
26 * <strong>Disabled until third party issues are solved.</strong>. Customises
27 * the initialisation of a new web socket.
28 */
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";
32
33 private final static CmsLog log = CmsLog.getLog(CmsWebSocketConfigurator.class);
34 // final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
35
36 @Override
37 public boolean checkOrigin(String originHeaderValue) {
38 return true;
39 }
40
41 @Override
42 public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
43 try {
44 return endpointClass.getDeclaredConstructor().newInstance();
45 } catch (Exception e) {
46 throw new IllegalArgumentException("Cannot get endpoint instance", e);
47 }
48 }
49
50 @Override
51 public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested) {
52 return requested;
53 }
54
55 @Override
56 public String getNegotiatedSubprotocol(List<String> supported, List<String> requested) {
57 if ((requested == null) || (requested.size() == 0))
58 return "";
59 if ((supported == null) || (supported.isEmpty()))
60 return "";
61 for (String possible : requested) {
62 if (possible == null)
63 continue;
64 if (supported.contains(possible))
65 return possible;
66 }
67 return "";
68 }
69
70 @Override
71 public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
72 // if (true)
73 // return;
74
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());
82
83 // if (remoteAuthSession == null) {
84 // rejectResponse(response, null);
85 // }
86 ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader();
87 Thread.currentThread().setContextClassLoader(CmsServletContext.class.getClassLoader());
88 LoginContext lc;
89 try {
90 lc = CmsAuth.USER.newLoginContext(new RemoteAuthCallbackHandler(remoteAuthRequest, remoteAuthResponse));
91 lc.login();
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));
97 return;
98 } else {
99 lc = RemoteAuthUtils.anonymousLogin(remoteAuthRequest, remoteAuthResponse);
100 }
101 if (lc == null) {
102 rejectResponse(response, e);
103 return;
104 }
105 } finally {
106 Thread.currentThread().setContextClassLoader(currentThreadContextClassLoader);
107 }
108
109 Subject subject = lc.getSubject();
110 Subject.doAs(subject, new PrivilegedAction<Void>() {
111
112 @Override
113 public Void run() {
114 // TODO also set login context in order to log out ?
115 RemoteAuthUtils.configureRequestSecurity(remoteAuthRequest);
116 return null;
117 }
118
119 });
120 }
121
122 protected boolean authIsRequired(RemoteAuthRequest remoteAuthRequest, RemoteAuthResponse remoteAuthResponse) {
123 return true;
124 }
125
126 /**
127 * Behaviour when the web socket could not be authenticated. Throws an
128 * {@link IllegalStateException} by default.
129 *
130 * @param e can be null
131 */
132 protected void rejectResponse(HandshakeResponse response, Exception e) {
133 response.getHeaders().put(HandshakeResponse.SEC_WEBSOCKET_ACCEPT, new ArrayList<String>());
134 // violent implementation, as suggested in
135 // https://stackoverflow.com/questions/21763829/jsr-356-how-to-abort-a-websocket-connection-during-the-handshake
136 // throw new IllegalStateException("Web socket cannot be authenticated");
137 }
138 }