Merge pull request #433 from GPrathap/release-3.0.x

oauth token retrieval mechanism changed
merge-requests/1/head
Charitha Goonetilleke 8 years ago committed by GitHub
commit 58b6be50f0

@ -18,17 +18,27 @@
function onRequest(context) { function onRequest(context) {
var log = new Log("stats.js"); var log = new Log("stats.js");
var carbonServer = require("carbon").server;
var device = context.unit.params.device; var device = context.unit.params.device;
var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"]; var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"];
var constants = require("/app/modules/constants.js"); var constants = require("/app/modules/constants.js");
var websocketEndpoint = devicemgtProps["wssURL"].replace("https", "wss"); var websocketEndpoint = devicemgtProps["wssURL"].replace("https", "wss");
var tokenPair = session.get(constants["TOKEN_PAIR"]); var jwtService = carbonServer.osgiService(
if (tokenPair) { 'org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService');
var token = parse(tokenPair)["accessToken"]; var jwtClient = jwtService.getJWTClient();
websocketEndpoint = websocketEndpoint + "/secured-websocket/org.wso2.iot.devices.temperature/1.0.0?" + var encodedClientKeys = session.get(constants["ENCODED_TENANT_BASED_WEB_SOCKET_CLIENT_CREDENTIALS"]);
"token="+ token +"&deviceId=" + device.deviceIdentifier + "&deviceType=" + device.type; var token = "";
} if (encodedClientKeys) {
var tokenUtil = require("/app/modules/oauth/token-handler-utils.js")["utils"];
var resp = tokenUtil.decode(encodedClientKeys).split(":");
var tokenPair = jwtClient.getAccessToken(resp[0], resp[1], context.user.username,"default", {});
if (tokenPair) {
token = tokenPair.accessToken;
}
websocketEndpoint = websocketEndpoint + "/secured-websocket/org.wso2.iot.devices.temperature/1.0.0?"
+ "deviceId=" + device.deviceIdentifier + "&deviceType=" + device.type;
var websocketToken= {'name':'websocket-token','value': token, 'path':'/', "maxAge":18000};
response.addCookie(websocketToken);
}
return {"device": device, "websocketEndpoint": websocketEndpoint}; return {"device": device, "websocketEndpoint": websocketEndpoint};
} }

@ -18,17 +18,27 @@
function onRequest(context) { function onRequest(context) {
var log = new Log("stats.js"); var log = new Log("stats.js");
var carbonServer = require("carbon").server;
var device = context.unit.params.device; var device = context.unit.params.device;
var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"]; var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"];
var constants = require("/app/modules/constants.js"); var constants = require("/app/modules/constants.js");
var websocketEndpoint = devicemgtProps["wssURL"].replace("https", "wss"); var websocketEndpoint = devicemgtProps["wssURL"].replace("https", "wss");
var tokenPair = session.get(constants["TOKEN_PAIR"]); var jwtService = carbonServer.osgiService(
if (tokenPair) { 'org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService');
var token = parse(tokenPair)["accessToken"]; var jwtClient = jwtService.getJWTClient();
websocketEndpoint = websocketEndpoint + "/secured-websocket/org.wso2.iot.devices.temperature/1.0.0?" + var encodedClientKeys = session.get(constants["ENCODED_TENANT_BASED_WEB_SOCKET_CLIENT_CREDENTIALS"]);
"token="+ token +"&deviceId=" + device.deviceIdentifier + "&deviceType=" + device.type; var token = "";
} if (encodedClientKeys) {
var tokenUtil = require("/app/modules/oauth/token-handler-utils.js")["utils"];
var resp = tokenUtil.decode(encodedClientKeys).split(":");
var tokenPair = jwtClient.getAccessToken(resp[0], resp[1], context.user.username,"default", {});
if (tokenPair) {
token = tokenPair.accessToken;
}
websocketEndpoint = websocketEndpoint + "/secured-websocket/org.wso2.iot.devices.temperature/1.0.0?"
+ "deviceId=" + device.deviceIdentifier + "&deviceType=" + device.type;
var websocketToken= {'name':'websocket-token','value': token, 'path':'/', "maxAge":18000};
response.addCookie(websocketToken);
}
return {"device": device, "websocketEndpoint": websocketEndpoint}; return {"device": device, "websocketEndpoint": websocketEndpoint};
} }

@ -22,15 +22,23 @@ function onRequest(context) {
var device = context.unit.params.device; var device = context.unit.params.device;
var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"]; var devicemgtProps = require("/app/modules/conf-reader/main.js")["conf"];
var constants = require("/app/modules/constants.js"); var constants = require("/app/modules/constants.js");
var websocketEndpoint = devicemgtProps["wssURL"].replace("https", "wss"); var websocketEndpoint = devicemgtProps["wssURL"].replace("https", "wss");
var jwtService = carbonServer.osgiService(
var tokenPair = session.get(constants["TOKEN_PAIR"]); 'org.wso2.carbon.identity.jwt.client.extension.service.JWTClientManagerService');
if (tokenPair) { var jwtClient = jwtService.getJWTClient();
var token = parse(tokenPair)["accessToken"]; var encodedClientKeys = session.get(constants["ENCODED_TENANT_BASED_WEB_SOCKET_CLIENT_CREDENTIALS"]);
websocketEndpoint = websocketEndpoint + "/secured-websocket/org.wso2.iot.devices.temperature/1.0.0?" + var token = "";
"token=" + token + "&deviceId=" + device.deviceIdentifier + "&deviceType=" + device.type; if (encodedClientKeys) {
} var tokenUtil = require("/app/modules/oauth/token-handler-utils.js")["utils"];
var resp = tokenUtil.decode(encodedClientKeys).split(":");
var tokenPair = jwtClient.getAccessToken(resp[0], resp[1], context.user.username,"default", {});
if (tokenPair) {
token = tokenPair.accessToken;
}
websocketEndpoint = websocketEndpoint + "/secured-websocket/org.wso2.iot.devices.temperature/1.0.0?"
+ "deviceId=" + device.deviceIdentifier + "&deviceType=" + device.type;
var websocketToken= {'name':'websocket-token','value': token, 'path':'/', "maxAge":18000};
response.addCookie(websocketToken);
}
return {"device": device, "websocketEndpoint": websocketEndpoint}; return {"device": device, "websocketEndpoint": websocketEndpoint};
} }

@ -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<String, List<String>> httpHeaders = request.getHeaders();
config.getUserProperties().put(Constants.HTTP_HEADERS, httpHeaders);
}
}

@ -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.AuthenticationInfo;
import org.wso2.carbon.device.mgt.output.adapter.websocket.authentication.Authenticator; 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.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.device.mgt.output.adapter.websocket.endpoint.util.ServiceHolder;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import javax.websocket.CloseReason; import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.Session;
import javax.websocket.OnClose; import javax.websocket.OnClose;
import javax.websocket.OnError; import javax.websocket.OnError;
import javax.websocket.OnMessage; import javax.websocket.OnMessage;
import javax.websocket.OnOpen; import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam; import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpoint;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Map;
/** /**
* Connect to web socket with Super tenant * Connect to web socket with Super tenant
*/ */
@ServerEndpoint(value = "/{streamname}/{version}") @ServerEndpoint(value = "/{streamname}/{version}", configurator = HttpSessionConfigurator.class)
public class SuperTenantSubscriptionEndpoint extends SubscriptionEndpoint { public class SuperTenantSubscriptionEndpoint extends SubscriptionEndpoint {
private static final Log log = LogFactory.getLog(SuperTenantSubscriptionEndpoint.class); 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. * @param version - Version extracted from the ws url.
*/ */
@OnOpen @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) { @PathParam("version") String version) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("WebSocket opened, for Session id: " + session.getId() + ", for the Stream:" + streamName); log.debug("WebSocket opened, for Session id: " + session.getId() + ", for the Stream:" + streamName);
} }
Map<String, List<String>> httpHeaders;
httpHeaders = (Map<String, List<String>>) config.getUserProperties().get(Constants.HTTP_HEADERS);
Authenticator authenticator = ServiceHolder.getWebsocketValidationService().getAuthenticator(); Authenticator authenticator = ServiceHolder.getWebsocketValidationService().getAuthenticator();
AuthenticationInfo authenticationInfo = authenticator.isAutenticated(session); AuthenticationInfo authenticationInfo = authenticator.isAuthenticated(httpHeaders);
if (authenticationInfo != null && authenticationInfo.isAuthenticated()) { if (authenticationInfo != null && authenticationInfo.isAuthenticated()) {
Authorizer authorizer = ServiceHolder.getWebsocketValidationService().getAuthorizer(); Authorizer authorizer = ServiceHolder.getWebsocketValidationService().getAuthorizer();
boolean isAuthorized = authorizer.isAuthorized(authenticationInfo, session, streamName); boolean isAuthorized = authorizer.isAuthorized(authenticationInfo, session, streamName);

@ -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.AuthenticationInfo;
import org.wso2.carbon.device.mgt.output.adapter.websocket.authentication.Authenticator; 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.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.device.mgt.output.adapter.websocket.endpoint.util.ServiceHolder;
import javax.websocket.CloseReason; import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.Session;
import javax.websocket.OnClose; import javax.websocket.OnClose;
import javax.websocket.OnError; import javax.websocket.OnError;
import javax.websocket.OnMessage; import javax.websocket.OnMessage;
import javax.websocket.OnOpen; import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam; import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpoint;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.Map;
/** /**
* Connect to web socket with a tenant * 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 { public class TenantSubscriptionEndpoint extends SubscriptionEndpoint {
private static final Log log = LogFactory.getLog(TenantSubscriptionEndpoint.class); 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. * @param tdomain - Tenant domain extracted from ws url.
*/ */
@OnOpen @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, @PathParam("tdomain") String tdomain) { @PathParam("version") String version, @PathParam("tdomain") String tdomain) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("WebSocket opened, for Session id: "+session.getId()+", for the Stream:"+streamName); log.debug("WebSocket opened, for Session id: "+session.getId()+", for the Stream:"+streamName);
} }
Map<String, List<String>> httpHeaders;
httpHeaders = (Map<String, List<String>>) config.getUserProperties().get(Constants.HTTP_HEADERS);
Authenticator authenticator = ServiceHolder.getWebsocketValidationService().getAuthenticator(); Authenticator authenticator = ServiceHolder.getWebsocketValidationService().getAuthenticator();
AuthenticationInfo authenticationInfo = authenticator.isAutenticated(session); AuthenticationInfo authenticationInfo = authenticator.isAuthenticated(httpHeaders);
if (authenticationInfo != null && authenticationInfo.isAuthenticated()) { if (authenticationInfo != null && authenticationInfo.isAuthenticated()) {
Authorizer authorizer = ServiceHolder.getWebsocketValidationService().getAuthorizer(); Authorizer authorizer = ServiceHolder.getWebsocketValidationService().getAuthorizer();
boolean isAuthorized = authorizer.isAuthorized(authenticationInfo, session, streamName); boolean isAuthorized = authorizer.isAuthorized(authenticationInfo, session, streamName);
@ -68,9 +74,8 @@ public class TenantSubscriptionEndpoint extends SubscriptionEndpoint {
try { try {
PrivilegedCarbonContext.startTenantFlow(); PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tdomain, true); PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tdomain, true);
ServiceHolder.getInstance().getUiOutputCallbackControllerService().subscribeWebsocket(streamName, ServiceHolder.getInstance().getUiOutputCallbackControllerService().subscribeWebsocket(streamName
version, , version, session);
session);
} finally { } finally {
PrivilegedCarbonContext.endTenantFlow(); PrivilegedCarbonContext.endTenantFlow();
} }

@ -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";
}

@ -14,7 +14,8 @@
package org.wso2.carbon.device.mgt.output.adapter.websocket.authentication; 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 * This interface is used to authenticate a websocket session
@ -24,7 +25,7 @@ public interface Authenticator {
/** /**
* Check whether the client is authenticated to connect. * Check whether the client is authenticated to connect.
* @param session user object. * @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<String, List<String>> webSocketConnectionProperties);
} }

@ -15,12 +15,13 @@
package org.wso2.carbon.device.mgt.output.adapter.websocket.authentication; package org.wso2.carbon.device.mgt.output.adapter.websocket.authentication;
import org.wso2.carbon.device.mgt.output.adapter.websocket.authentication.oauth.OAuthTokenValdiator; 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 { public class OAuthAuthenticator implements Authenticator {
@Override public AuthenticationInfo isAuthenticated(Map<String, List<String>> webSocketConnectionProperties) {
public AuthenticationInfo isAutenticated(Session session) { return OAuthTokenValdiator.getInstance().validateToken(webSocketConnectionProperties);
return OAuthTokenValdiator.getInstance().validateToken(session);
} }
} }

@ -31,7 +31,6 @@ import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.utils.CarbonUtils; import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import javax.websocket.Session;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.rmi.RemoteException; import java.rmi.RemoteException;
@ -50,10 +49,11 @@ public class OAuthTokenValdiator {
private static Log log = LogFactory.getLog(OAuthTokenValdiator.class); private static Log log = LogFactory.getLog(OAuthTokenValdiator.class);
private static final String WEBSOCKET_CONFIG_LOCATION = private static final String WEBSOCKET_CONFIG_LOCATION =
CarbonUtils.getEtcCarbonConfigDirPath() + File.separator + "websocket-validation.properties"; CarbonUtils.getEtcCarbonConfigDirPath() + File.separator + "websocket-validation.properties";
private static final String QUERY_STRING_SEPERATOR = "&"; private static final String COOKIE_KEY_VALUE_SEPERATOR = "=";
private static final String QUERY_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_TYPE = "bearer";
private static final String TOKEN_IDENTIFIER = "token"; private static final String TOKEN_IDENTIFIER = "websocket-token";
private static OAuthTokenValdiator oAuthTokenValdiator; private static OAuthTokenValdiator oAuthTokenValdiator;
public static OAuthTokenValdiator getInstance() { public static OAuthTokenValdiator getInstance() {
@ -79,12 +79,11 @@ public class OAuthTokenValdiator {
/** /**
* This method gets a string accessToken and validates it * This method gets a string accessToken and validates it
* * @param webSocketConnectionProperties WebSocket connection information including http headers
* @param session which need to be validated.
* @return AuthenticationInfo with the validated results. * @return AuthenticationInfo with the validated results.
*/ */
public AuthenticationInfo validateToken(Session session) { public AuthenticationInfo validateToken(Map<String, List<String>> webSocketConnectionProperties) {
String token = getTokenFromSession(session); String token = getToken(webSocketConnectionProperties);
if (token == null) { if (token == null) {
AuthenticationInfo authenticationInfo = new AuthenticationInfo(); AuthenticationInfo authenticationInfo = new AuthenticationInfo();
authenticationInfo.setAuthenticated(false); authenticationInfo.setAuthenticated(false);
@ -189,26 +188,21 @@ public class OAuthTokenValdiator {
} }
/** /**
* @param session of the user. * Retrieving the token from the http header
* @return retreive the token from the query string * @param webSocketConnectionProperties WebSocket connection information including http headers
* @return retrieved token
*/ */
private String getTokenFromSession(Session session) { private String getToken(Map<String, List<String>> webSocketConnectionProperties) {
String queryString = session.getQueryString(); String cookieString = webSocketConnectionProperties.get(COOKIE).get(0);
if (queryString != null) { String[] properties = cookieString.split(COOKIE_KEYPAIR_SEPERATOR);
String[] allQueryParamPairs = queryString.split(QUERY_STRING_SEPERATOR); String token;
for (String keyValuePair: properties) {
for (String keyValuePair : allQueryParamPairs) { if(TOKEN_IDENTIFIER.equals((keyValuePair.split(COOKIE_KEY_VALUE_SEPERATOR)[0]).trim())){
String[] queryParamPair = keyValuePair.split(QUERY_KEY_VALUE_SEPERATOR); token = (keyValuePair.split(COOKIE_KEY_VALUE_SEPERATOR)[1]).trim();
return token;
if (queryParamPair.length != 2) { }
log.warn("Invalid query string [" + queryString + "] passed in."); }
break; log.error("WebSocket token should be specified in cookie");
}
if (queryParamPair[0].equals(TOKEN_IDENTIFIER)) {
return queryParamPair[1];
}
}
}
return null; return null;
} }
} }

Loading…
Cancel
Save