Skip to content

Commit

Permalink
Merge pull request #13278 from thisaltennakoon/Integration-test-for-A…
Browse files Browse the repository at this point in the history
…PI-Key-authentication-for-WebSocket-API-1

Integration test - API-KEY authentication support for web socket APIs
  • Loading branch information
tharikaGitHub committed Mar 27, 2024
2 parents 13a58d7 + b5e81c4 commit 4b1915a
Show file tree
Hide file tree
Showing 2 changed files with 225 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ public void testWebSocketAPIInvocation() throws Exception {
consumerSecret = applicationKeyDTO.getConsumerSecret();
WebSocketClient client = new WebSocketClient();
try {
invokeAPI(client, tokenJti, WebSocketAPITestCase.AUTH_IN.HEADER, null, apiEndPoint);
invokeAPI(client, tokenJti, WebSocketAPITestCase.AUTH_IN.QUERY, null, apiEndPoint);
invokeAPI(client, tokenJti, WebSocketAPITestCase.AUTH_IN.OAUTH_HEADER, null, apiEndPoint);
invokeAPI(client, tokenJti, WebSocketAPITestCase.AUTH_IN.OAUTH_QUERY, null, apiEndPoint);
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
Expand Down Expand Up @@ -278,10 +278,10 @@ private void invokeAPI(WebSocketClient client, String accessToken, WebSocketAPIT
ClientUpgradeRequest request = new ClientUpgradeRequest();
URI echoUri = null;

if (WebSocketAPITestCase.AUTH_IN.HEADER == in) {
if (WebSocketAPITestCase.AUTH_IN.OAUTH_HEADER == in) {
request.setHeader("Authorization", "Bearer " + accessToken);
echoUri = new URI(apiEndPoint);
} else if (WebSocketAPITestCase.AUTH_IN.QUERY == in) {
} else if (WebSocketAPITestCase.AUTH_IN.OAUTH_QUERY == in) {
echoUri = new URI(apiEndPoint + "?access_token=" + accessToken);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand All @@ -48,6 +47,7 @@
import org.wso2.am.integration.clients.publisher.api.v1.dto.APIListDTO;
import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationDTO;
import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationKeyDTO;
import org.wso2.am.integration.clients.store.api.v1.dto.APIKeyDTO;
import org.wso2.am.integration.clients.store.api.v1.dto.ApplicationKeyGenerateRequestDTO;
import org.wso2.am.integration.clients.store.api.v1.dto.SubscriptionDTO;
import org.wso2.am.integration.test.impl.DtoFactory;
Expand All @@ -64,7 +64,6 @@
import org.wso2.carbon.apimgt.api.model.APIIdentifier;
import org.wso2.carbon.automation.engine.annotations.ExecutionEnvironment;
import org.wso2.carbon.automation.engine.annotations.SetEnvironment;
import org.wso2.carbon.automation.engine.context.AutomationContext;
import org.wso2.carbon.automation.engine.context.TestUserMode;
import org.wso2.carbon.automation.engine.frameworkutils.FrameworkPathUtil;
import org.wso2.carbon.automation.test.utils.common.TestConfigurationProvider;
Expand All @@ -75,15 +74,12 @@
import javax.ws.rs.core.Response;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URI;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand All @@ -98,8 +94,10 @@ public class WebSocketAPITestCase extends APIMIntegrationBaseTest {

private final Log log = LogFactory.getLog(WebSocketAPITestCase.class);
enum AUTH_IN {
HEADER,
QUERY
OAUTH_HEADER,
OAUTH_QUERY,
APIKEY_HEADER,
APIKEY_QUERY
}
private final String apiName = "WebSocketAPI";
private final String apiNameWithMalformedContext = "WebSocketAPIWithMalformedContext";
Expand Down Expand Up @@ -132,6 +130,8 @@ enum AUTH_IN {
long throttleMarkTime = 0;
String apiVersion2 = "2.0.0";
String endPointApplication = "EndPointApplication";
ArrayList<String> securityScheme = new ArrayList<>();
String apiKey = "api_key";
Server server = null;

@Factory(dataProvider = "userModeDataProvider")
Expand Down Expand Up @@ -231,13 +231,15 @@ public void testWebSocketAPIInvocation() throws Exception {
applicationKeyDTO = restAPIStore.generateKeys(appId, "3600", null,
ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, null, grantTypes);
String accessToken = applicationKeyDTO.getToken().getAccessToken();
String tokenJti = TokenUtils.getJtiOfJwtToken(accessToken);
String opaqueToken = TokenUtils.getJtiOfJwtToken(accessToken);
consumerKey = applicationKeyDTO.getConsumerKey();
consumerSecret = applicationKeyDTO.getConsumerSecret();
WebSocketClient client = new WebSocketClient();
try {
invokeAPI(client, tokenJti, AUTH_IN.HEADER, null, apiEndPoint);
invokeAPI(client, tokenJti, AUTH_IN.QUERY, null, apiEndPoint);
invokeAPI(client, accessToken, AUTH_IN.OAUTH_HEADER, null, apiEndPoint);
invokeAPI(client, accessToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint);
invokeAPI(client, opaqueToken, AUTH_IN.OAUTH_HEADER, null, apiEndPoint);
invokeAPI(client, opaqueToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint);
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
Expand Down Expand Up @@ -268,8 +270,8 @@ public void testWebSocketAPIInvocationWithJWTToken() throws Exception {
//consumerSecret = applicationKeyDTO.getConsumerSecret();
WebSocketClient client = new WebSocketClient();
try {
invokeAPI(client, accessToken, AUTH_IN.HEADER, null, apiEndPoint);
invokeAPI(client, accessToken, AUTH_IN.QUERY, null, apiEndPoint);
invokeAPI(client, accessToken, AUTH_IN.OAUTH_HEADER, null, apiEndPoint);
invokeAPI(client, accessToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint);
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
Expand Down Expand Up @@ -334,8 +336,8 @@ public void testWebSocketAPIRemoveEndpoint() throws Exception {

WebSocketClient client0 = new WebSocketClient();
try {
invokeAPI(client0, sandboxAccessToken, AUTH_IN.HEADER, null, apiEndPoint);
invokeAPI(client0, sandboxAccessToken, AUTH_IN.QUERY, null, apiEndPoint);
invokeAPI(client0, sandboxAccessToken, AUTH_IN.OAUTH_HEADER, null, apiEndPoint);
invokeAPI(client0, sandboxAccessToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint);
Assert.assertTrue(true, "Client can connect to the sandbox endpoint");
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Expand All @@ -350,7 +352,7 @@ public void testWebSocketAPIRemoveEndpoint() throws Exception {
String prodAccessToken = prodApplicationKeyDTO.getToken().getAccessToken();
WebSocketClient client1 = new WebSocketClient();
try {
invokeAPI(client1, prodAccessToken, AUTH_IN.QUERY, null, apiEndPoint);
invokeAPI(client1, prodAccessToken, AUTH_IN.OAUTH_QUERY, null, apiEndPoint);
Assert.fail("Client can connect to the production endpoint when production endpoint is not configured");
} catch (Exception e) {
log.debug("Exception in connecting to server", e);
Expand Down Expand Up @@ -453,7 +455,8 @@ public void testWebSocketAPIInvalidTokenInvocation() throws Exception {
WebSocketClient client = new WebSocketClient();
boolean apiInvocationFailed = false;
try {
invokeAPI(client, "00000000-0000-0000-0000-000000000000", AUTH_IN.HEADER, null, apiEndPoint);
invokeAPI(client, "00000000-0000-0000-0000-000000000000", AUTH_IN.OAUTH_HEADER,
null, apiEndPoint);
} catch (APIManagerIntegrationTestException e) {
log.error("Exception in connecting to server", e);
apiInvocationFailed = true;
Expand All @@ -469,6 +472,201 @@ public void testWebSocketAPIInvalidTokenInvocation() throws Exception {
}
}

@Test(description = "Invoke API using API key when API Key authentication is not enabled",
dependsOnMethods = "testWebSocketAPIInvalidTokenInvocation")
public void testWebSocketAPIInvocationUsingAPIKeyWhenAPIKeyAuthenticationDisabled() throws Exception {

APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.
PRODUCTION.toString(), -1, null, null);
String accessToken = apiKeyDTO.getApikey();
WebSocketClient client = new WebSocketClient();
boolean apiInvocationFailed = false;
try {
invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint);
} catch (APIManagerIntegrationTestException e) {
apiInvocationFailed = true;
assertTrue(true, "Exception in connecting to server because API Key authentication is not enabled");
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
} finally {
if (!apiInvocationFailed) {
Assert.fail("WS API was invoked using API key when API Key authentication is not enabled");
}
client.stop();
}
}

@Test(description = "Invoke API using API key",
dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKeyWhenAPIKeyAuthenticationDisabled")
public void testWebSocketAPIInvocationUsingAPIKey() throws Exception {

// Update API to enable API Key authentication
HttpResponse response = restAPIPublisher.getAPI(websocketAPIID);
Gson g = new Gson();
APIDTO apidto = g.fromJson(response.getData(), APIDTO.class);
securityScheme.add(apiKey);
apidto.setSecurityScheme(securityScheme);
restAPIPublisher.updateAPI(apidto);
Thread.sleep(1000); // Delay is needed to propagate changes to the components
APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.
PRODUCTION.toString(), -1, null, null);
String accessToken = apiKeyDTO.getApikey();
WebSocketClient client = new WebSocketClient();
try {
invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint);
invokeAPI(client, accessToken, AUTH_IN.APIKEY_QUERY, null, apiEndPoint);
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
} finally {
client.stop();
}
}

@Test(description = "Invoke API using OAuth access token when OAuth authentication is not enabled",
dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKey")
public void testWebSocketAPIInvocationUsingOAuthWhenOAuthAuthenticationDisabled() throws Exception {

WebSocketClient client = new WebSocketClient();
boolean apiInvocationFailed = false;
try {
invokeAPI(client, applicationKeyDTO.getToken().getAccessToken(), AUTH_IN.OAUTH_HEADER,
null, apiEndPoint);
} catch (APIManagerIntegrationTestException e) {
apiInvocationFailed = true;
assertTrue(true, "Exception in connecting to server because OAuth authentication is not enabled");
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
} finally {
if (!apiInvocationFailed) {
Assert.fail("WS API was invoked using OAuth access token when OAuth authentication is not enabled");
}
client.stop();
}
}

@Test(description = "Invoke API using Expired API key",
dependsOnMethods = "testWebSocketAPIInvocationUsingOAuthWhenOAuthAuthenticationDisabled")
public void testWebSocketAPIInvocationUsingExpiredAPIKey() throws Exception {

APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.
PRODUCTION.toString(), 1, null, null);
String accessToken = apiKeyDTO.getApikey();
WebSocketClient client = new WebSocketClient();
boolean apiInvocationFailed = false;
try {
Thread.sleep(2000);
invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint);
} catch (APIManagerIntegrationTestException e) {
apiInvocationFailed = true;
assertTrue(true, "Exception in connecting to server because the API Key is expired");
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
} finally {
if (!apiInvocationFailed) {
Assert.fail("WS API was invoked with an expired API key");
}
client.stop();
}
}

@Test(description = "Invoke API using API key generated using IP restrictions",
dependsOnMethods = "testWebSocketAPIInvocationUsingExpiredAPIKey")
public void testWebSocketAPIInvocationUsingAPIKeyGeneratedUsingIPRestrictions() throws Exception {

APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.
PRODUCTION.toString(), -1, "192.168.1.2, 152.12.0.0/13, 2002:eb8::2, 1001:ab8::/44," +
" 127.0.0.1", null);
String accessToken = apiKeyDTO.getApikey();
WebSocketClient client = new WebSocketClient();
try {
invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint);
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
} finally {
client.stop();
}
}

@Test(description = "Invoke API using an API key restricted for another IP",
dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKeyGeneratedUsingIPRestrictions")
public void testWebSocketAPIInvocationUsingAPIKeyRestrictedForAnotherIP() throws Exception {

APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.
PRODUCTION.toString(), -1, "192.168.1.2, 152.12.0.0/13, 2002:eb8::2, 1001:ab8::/44," +
" 1.1.1.1", null);
String accessToken = apiKeyDTO.getApikey();
WebSocketClient client = new WebSocketClient();
boolean apiInvocationFailed = false;
try {
invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint);
} catch (APIManagerIntegrationTestException e) {
apiInvocationFailed = true;
assertTrue(true, "Client cannot connect to server because the API Key is restricted for another IP");
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
} finally {
if (!apiInvocationFailed) {
Assert.fail("WS API was invoked using API key restricted for another IP");
}
client.stop();
}
}

@Test(description = "Invoke API using API key generated using Referer restrictions",
dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKeyRestrictedForAnotherIP")
public void testWebSocketAPIInvocationUsingAPIKeyGeneratedUsingRefererRestrictions() throws Exception {

APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.
PRODUCTION.toString(), -1, null, "www.example.com/path, " +
"sub.example.com/*, *.example.com/*, www.wso2.com");
HttpHeaders headers = new DefaultHttpHeaders();
headers.add("Referer", "www.wso2.com");
String accessToken = apiKeyDTO.getApikey();
WebSocketClient client = new WebSocketClient();
try {
invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, headers, apiEndPoint);
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
} finally {
client.stop();
}
}

@Test(description = "Invoke API using API key restricted for another Referer",
dependsOnMethods = "testWebSocketAPIInvocationUsingAPIKeyGeneratedUsingRefererRestrictions")
public void testWebSocketAPIInvocationUsingAPIKeyGeneratedForAnotherReferer() throws Exception {

APIKeyDTO apiKeyDTO = restAPIStore.generateAPIKeys(appId, ApplicationKeyGenerateRequestDTO.KeyTypeEnum.
PRODUCTION.toString(), -1, null, "www.example.com/path, " +
"sub.example.com/*, *.example.com/*, www.wso2.com");
HttpHeaders headers = new DefaultHttpHeaders();
headers.add("Referer", "www.wso2.org");
String accessToken = apiKeyDTO.getApikey();
WebSocketClient client = new WebSocketClient();
boolean apiInvocationFailed = false;
try {
invokeAPI(client, accessToken, AUTH_IN.APIKEY_HEADER, null, apiEndPoint);
} catch (APIManagerIntegrationTestException e) {
apiInvocationFailed = true;
assertTrue(true, "Client cannot connect to server because the API Key is restricted for another Referer");
} catch (Exception e) {
log.error("Exception in connecting to server", e);
Assert.fail("Client cannot connect to server");
} finally {
if (!apiInvocationFailed) {
Assert.fail("WS API was invoked using API key generated for another Referer");
}
client.stop();
}
}

@Test(description = "Create WebSocket API with malformed context",
dependsOnMethods = "testWebSocketAPIRemoveEndpoint")
public void testCreateWebSocketAPIWithMalformedContext() throws Exception {
Expand Down Expand Up @@ -603,11 +801,16 @@ private void invokeAPI(WebSocketClient client, String accessToken, AUTH_IN in, H
ClientUpgradeRequest request = new ClientUpgradeRequest();
URI echoUri = null;

if (AUTH_IN.HEADER == in) {
if (AUTH_IN.OAUTH_HEADER == in) {
request.setHeader("Authorization", "Bearer " + accessToken);
echoUri = new URI(apiEndPoint);
} else if (AUTH_IN.QUERY == in) {
} else if (AUTH_IN.OAUTH_QUERY == in) {
echoUri = new URI(apiEndPoint + "?access_token=" + accessToken);
} else if (AUTH_IN.APIKEY_HEADER == in) {
request.setHeader("apikey", accessToken);
echoUri = new URI(apiEndPoint);
} else if (AUTH_IN.APIKEY_QUERY == in) {
echoUri = new URI(apiEndPoint + "?apikey=" + accessToken);
}

if (optionalRequestHeaders != null) {
Expand Down

0 comments on commit 4b1915a

Please sign in to comment.