diff --git a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/HttpSessionConfigurator.java b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/HttpSessionConfigurator.java new file mode 100644 index 000000000..a38a5e635 --- /dev/null +++ b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/HttpSessionConfigurator.java @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint; + +import org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint.constants.Constants; + +import javax.websocket.HandshakeResponse; +import javax.websocket.server.HandshakeRequest; +import javax.websocket.server.ServerEndpointConfig; +import java.util.List; +import java.util.Map; + +public class HttpSessionConfigurator extends ServerEndpointConfig.Configurator { + public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) { + Map> httpHeaders = request.getHeaders(); + config.getUserProperties().put(Constants.HTTP_HEADERS, httpHeaders); + } +} diff --git a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/SuperTenantSubscriptionEndpoint.java b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/SuperTenantSubscriptionEndpoint.java index 53b40d1ba..5eac9280e 100644 --- a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/SuperTenantSubscriptionEndpoint.java +++ b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/SuperTenantSubscriptionEndpoint.java @@ -24,24 +24,28 @@ import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.output.adapter.websocket.authentication.AuthenticationInfo; import org.wso2.carbon.device.mgt.output.adapter.websocket.authentication.Authenticator; import org.wso2.carbon.device.mgt.output.adapter.websocket.authorization.Authorizer; +import org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint.constants.Constants; import org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint.util.ServiceHolder; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import javax.websocket.CloseReason; +import javax.websocket.EndpointConfig; +import javax.websocket.Session; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; -import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; +import java.util.List; +import java.util.Map; /** * Connect to web socket with Super tenant */ -@ServerEndpoint(value = "/{streamname}/{version}") +@ServerEndpoint(value = "/{streamname}/{version}", configurator = HttpSessionConfigurator.class) public class SuperTenantSubscriptionEndpoint extends SubscriptionEndpoint { private static final Log log = LogFactory.getLog(SuperTenantSubscriptionEndpoint.class); @@ -54,13 +58,15 @@ public class SuperTenantSubscriptionEndpoint extends SubscriptionEndpoint { * @param version - Version extracted from the ws url. */ @OnOpen - public void onOpen(Session session, @PathParam("streamname") String streamName, + public void onOpen(Session session, EndpointConfig config, @PathParam("streamname") String streamName, @PathParam("version") String version) { if (log.isDebugEnabled()) { log.debug("WebSocket opened, for Session id: " + session.getId() + ", for the Stream:" + streamName); } + Map> httpHeaders; + httpHeaders = (Map>) config.getUserProperties().get(Constants.HTTP_HEADERS); Authenticator authenticator = ServiceHolder.getWebsocketValidationService().getAuthenticator(); - AuthenticationInfo authenticationInfo = authenticator.isAutenticated(session); + AuthenticationInfo authenticationInfo = authenticator.isAuthenticated(httpHeaders); if (authenticationInfo != null && authenticationInfo.isAuthenticated()) { Authorizer authorizer = ServiceHolder.getWebsocketValidationService().getAuthorizer(); boolean isAuthorized = authorizer.isAuthorized(authenticationInfo, session, streamName); diff --git a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/TenantSubscriptionEndpoint.java b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/TenantSubscriptionEndpoint.java index 553cdcbea..9243498a1 100644 --- a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/TenantSubscriptionEndpoint.java +++ b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/TenantSubscriptionEndpoint.java @@ -24,23 +24,27 @@ import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.output.adapter.websocket.authentication.AuthenticationInfo; import org.wso2.carbon.device.mgt.output.adapter.websocket.authentication.Authenticator; import org.wso2.carbon.device.mgt.output.adapter.websocket.authorization.Authorizer; +import org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint.constants.Constants; import org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint.util.ServiceHolder; import javax.websocket.CloseReason; +import javax.websocket.EndpointConfig; +import javax.websocket.Session; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; -import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; +import java.util.List; +import java.util.Map; /** * Connect to web socket with a tenant */ -@ServerEndpoint(value = "/t/{tdomain}/{streamname}/{version}") +@ServerEndpoint(value = "/t/{tdomain}/{streamname}/{version}", configurator = HttpSessionConfigurator.class) public class TenantSubscriptionEndpoint extends SubscriptionEndpoint { private static final Log log = LogFactory.getLog(TenantSubscriptionEndpoint.class); @@ -54,13 +58,15 @@ public class TenantSubscriptionEndpoint extends SubscriptionEndpoint { * @param tdomain - Tenant domain extracted from ws url. */ @OnOpen - public void onOpen (Session session, @PathParam("streamname") String streamName , - @PathParam("version") String version, @PathParam("tdomain") String tdomain) { + public void onOpen (Session session, EndpointConfig config, @PathParam("streamname") String streamName , + @PathParam("version") String version, @PathParam("tdomain") String tdomain) { if (log.isDebugEnabled()) { log.debug("WebSocket opened, for Session id: "+session.getId()+", for the Stream:"+streamName); } + Map> httpHeaders; + httpHeaders = (Map>) config.getUserProperties().get(Constants.HTTP_HEADERS); Authenticator authenticator = ServiceHolder.getWebsocketValidationService().getAuthenticator(); - AuthenticationInfo authenticationInfo = authenticator.isAutenticated(session); + AuthenticationInfo authenticationInfo = authenticator.isAuthenticated(httpHeaders); if (authenticationInfo != null && authenticationInfo.isAuthenticated()) { Authorizer authorizer = ServiceHolder.getWebsocketValidationService().getAuthorizer(); boolean isAuthorized = authorizer.isAuthorized(authenticationInfo, session, streamName); @@ -68,9 +74,8 @@ public class TenantSubscriptionEndpoint extends SubscriptionEndpoint { try { PrivilegedCarbonContext.startTenantFlow(); PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tdomain, true); - ServiceHolder.getInstance().getUiOutputCallbackControllerService().subscribeWebsocket(streamName, - version, - session); + ServiceHolder.getInstance().getUiOutputCallbackControllerService().subscribeWebsocket(streamName + , version, session); } finally { PrivilegedCarbonContext.endTenantFlow(); } diff --git a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/constants/Constants.java b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/constants/Constants.java new file mode 100644 index 000000000..14b4e968c --- /dev/null +++ b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/endpoint/constants/Constants.java @@ -0,0 +1,25 @@ +/* + * + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.wso2.carbon.device.mgt.output.adapter.websocket.endpoint.constants; + +public class Constants { + public static final String HTTP_HEADERS = "HttpHeaders"; +} diff --git a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/Authenticator.java b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/Authenticator.java index a9a5dc07b..d1d06cc5c 100644 --- a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/Authenticator.java +++ b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/Authenticator.java @@ -14,7 +14,8 @@ package org.wso2.carbon.device.mgt.output.adapter.websocket.authentication; -import javax.websocket.Session; +import java.util.List; +import java.util.Map; /** * This interface is used to authenticate a websocket session @@ -24,7 +25,7 @@ public interface Authenticator { /** * Check whether the client is authenticated to connect. * @param session user object. - * @return AuthenicationInfo which contains authentication client information. + * @return AuthenticationInfo which contains authentication client information. */ - AuthenticationInfo isAutenticated(Session session); + AuthenticationInfo isAuthenticated(Map> webSocketConnectionProperties); } diff --git a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/OAuthAuthenticator.java b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/OAuthAuthenticator.java index 7eaab2b5b..698f4f826 100644 --- a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/OAuthAuthenticator.java +++ b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/OAuthAuthenticator.java @@ -15,12 +15,13 @@ package org.wso2.carbon.device.mgt.output.adapter.websocket.authentication; import org.wso2.carbon.device.mgt.output.adapter.websocket.authentication.oauth.OAuthTokenValdiator; -import javax.websocket.Session; + +import java.util.List; +import java.util.Map; public class OAuthAuthenticator implements Authenticator { - @Override - public AuthenticationInfo isAutenticated(Session session) { - return OAuthTokenValdiator.getInstance().validateToken(session); + public AuthenticationInfo isAuthenticated(Map> webSocketConnectionProperties) { + return OAuthTokenValdiator.getInstance().validateToken(webSocketConnectionProperties); } } diff --git a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/oauth/OAuthTokenValdiator.java b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/oauth/OAuthTokenValdiator.java index 5c55a5c21..b92f08ae0 100644 --- a/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/oauth/OAuthTokenValdiator.java +++ b/components/extensions/cdmf-transport-adapters/output/org.wso2.carbon.device.mgt.output.adapter.websocket/src/main/java/org/wso2/carbon/device/mgt/output/adapter/websocket/authentication/oauth/OAuthTokenValdiator.java @@ -31,7 +31,6 @@ import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.multitenancy.MultitenantUtils; -import javax.websocket.Session; import java.io.File; import java.io.IOException; import java.rmi.RemoteException; @@ -50,10 +49,11 @@ public class OAuthTokenValdiator { private static Log log = LogFactory.getLog(OAuthTokenValdiator.class); private static final String WEBSOCKET_CONFIG_LOCATION = CarbonUtils.getEtcCarbonConfigDirPath() + File.separator + "websocket-validation.properties"; - private static final String QUERY_STRING_SEPERATOR = "&"; - private static final String QUERY_KEY_VALUE_SEPERATOR = "="; + private static final String COOKIE_KEY_VALUE_SEPERATOR = "="; + private static final String COOKIE_KEYPAIR_SEPERATOR = ";"; + private static final String COOKIE = "cookie"; private static final String TOKEN_TYPE = "bearer"; - private static final String TOKEN_IDENTIFIER = "token"; + private static final String TOKEN_IDENTIFIER = "websocket-token"; private static OAuthTokenValdiator oAuthTokenValdiator; public static OAuthTokenValdiator getInstance() { @@ -79,12 +79,11 @@ public class OAuthTokenValdiator { /** * This method gets a string accessToken and validates it - * - * @param session which need to be validated. + * @param webSocketConnectionProperties WebSocket connection information including http headers * @return AuthenticationInfo with the validated results. */ - public AuthenticationInfo validateToken(Session session) { - String token = getTokenFromSession(session); + public AuthenticationInfo validateToken(Map> webSocketConnectionProperties) { + String token = getToken(webSocketConnectionProperties); if (token == null) { AuthenticationInfo authenticationInfo = new AuthenticationInfo(); authenticationInfo.setAuthenticated(false); @@ -189,26 +188,21 @@ public class OAuthTokenValdiator { } /** - * @param session of the user. - * @return retreive the token from the query string + * Retrieving the token from the http header + * @param webSocketConnectionProperties WebSocket connection information including http headers + * @return retrieved token */ - private String getTokenFromSession(Session session) { - String queryString = session.getQueryString(); - if (queryString != null) { - String[] allQueryParamPairs = queryString.split(QUERY_STRING_SEPERATOR); - - for (String keyValuePair : allQueryParamPairs) { - String[] queryParamPair = keyValuePair.split(QUERY_KEY_VALUE_SEPERATOR); - - if (queryParamPair.length != 2) { - log.warn("Invalid query string [" + queryString + "] passed in."); - break; - } - if (queryParamPair[0].equals(TOKEN_IDENTIFIER)) { - return queryParamPair[1]; - } - } - } + private String getToken(Map> webSocketConnectionProperties) { + String cookieString = webSocketConnectionProperties.get(COOKIE).get(0); + String[] properties = cookieString.split(COOKIE_KEYPAIR_SEPERATOR); + String token; + for (String keyValuePair: properties) { + if(TOKEN_IDENTIFIER.equals((keyValuePair.split(COOKIE_KEY_VALUE_SEPERATOR)[0]).trim())){ + token = (keyValuePair.split(COOKIE_KEY_VALUE_SEPERATOR)[1]).trim(); + return token; + } + } + log.error("WebSocket token should be specified in cookie"); return null; } }