Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test oauth authentication flow in websocket connections #13106

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.apache.commons.codec.binary.Base64;
import org.wso2.am.integration.test.utils.bean.APIMURLBean;
import org.wso2.am.integration.test.utils.http.HTTPSClientUtils;
import org.wso2.carbon.automation.test.utils.http.client.HttpResponse;

import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.HashMap;
Expand Down Expand Up @@ -56,4 +60,24 @@ public static String getBase64EncodedAppCredentials(String clientId, String clie
byte[] encodedBytes = Base64.encodeBase64(basicAuthHeader.getBytes(StandardCharsets.UTF_8));
return new String(encodedBytes, StandardCharsets.UTF_8);
}

/**
+ * Send token revocation request
+ * @param consumerKey of the application
+ * @param consumerSecret of the application
+ * @param token that needs to be revoked
+ * @param keyMangerUrl
+ * @return
+ * @throws IOException
+ */
public static HttpResponse revokeToken(String consumerKey, String consumerSecret,
String token, APIMURLBean keyMangerUrl) throws IOException {
Map<String, String> revokeRequestHeaders = new HashMap<>();
String basicAuthHeader = consumerKey + ":" + consumerSecret;
byte[] encodedBytes = Base64.encodeBase64(basicAuthHeader.getBytes(StandardCharsets.UTF_8));
revokeRequestHeaders.put("Authorization", "Basic " + new String(encodedBytes, StandardCharsets.UTF_8));
String input = "token=" + token;
URL revokeEndpointURL = new URL(keyMangerUrl.getWebAppURLHttps() + "oauth2/revoke");
return HTTPSClientUtils.doPost(revokeEndpointURL, input, revokeRequestHeaders);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import org.wso2.am.integration.test.utils.clients.APIPublisherRestClient;
import org.wso2.am.integration.test.utils.generic.APIMTestCaseUtils;
import org.wso2.am.integration.test.utils.token.TokenUtils;
import org.wso2.am.integration.tests.api.lifecycle.APIManagerConfigurationChangeTest;
import org.wso2.am.integration.tests.websocket.client.WebSocketClientImpl;
import org.wso2.am.integration.tests.websocket.server.WebSocketServerImpl;
import org.wso2.carbon.apimgt.api.model.APIIdentifier;
Expand Down Expand Up @@ -87,6 +88,7 @@

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertTrue;

@SetEnvironment(executionEnvironments = {ExecutionEnvironment.STANDALONE})
Expand All @@ -103,6 +105,7 @@ enum AUTH_IN {
private final String apiNameWithMalformedContext = "WebSocketAPIWithMalformedContext";
private final String applicationName = "WebSocketApplication";
private final String applicationJWTName = "WebSocketJWTTypeApplication";
private static final String OAUTH_TYPE_APPLICATION_NAME = "WebSocketOAuthTypeApplication";
private final String testMessage = "Web Socket Test Message";
private String apiEndPoint;
private APIPublisherRestClient apiPublisher;
Expand All @@ -126,7 +129,9 @@ enum AUTH_IN {
private final String originHeaderName = "http://global.config1.com";
String appId;
String appJWTId;
String oAuthAppId;
ApplicationKeyDTO applicationKeyDTO;
ApplicationKeyDTO oAuthAppKeyDto;
long throttleMarkTime = 0;
String apiVersion2 = "2.0.0";
String endPointApplication = "EndPointApplication";
Expand Down Expand Up @@ -280,8 +285,133 @@ public void testWebSocketAPIInvocationWithJWTToken() throws Exception {
}
}

@Test(description = "Invoke API using revoked JWT token", dependsOnMethods = "testWebSocketAPIInvocationWithJWTToken")
public void testWebSocketAPIInvocationWithRevokedJWTToken() throws Exception {
ArrayList grantTypes = new ArrayList();
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.PASSWORD);
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.REFRESH_CODE);
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.CLIENT_CREDENTIAL);
String accessToken = applicationKeyDTO.getToken().getAccessToken();
consumerKey = applicationKeyDTO.getConsumerKey();
consumerSecret = applicationKeyDTO.getConsumerSecret();
HttpResponse httpResponse = TokenUtils.revokeToken(consumerKey, consumerSecret, accessToken, keyMangerUrl);
int revocationResponseCode = httpResponse.getResponseCode();
if (revocationResponseCode != 200) {
Assert.fail(String.format("Could not revoke token. Response code for the revocation is : %s",
revocationResponseCode) );
}
Thread.sleep(5000);
WebSocketClient client = new WebSocketClient();
try {
WebSocketClientImpl socket = getActiveSocket(client, accessToken, AUTH_IN.HEADER, null, apiEndPoint);
String response = getSocketConnectionResponse(socket);
assertNotEquals(response, testMessage.toUpperCase(),
"Received the resource with revoked token.");
} catch (Exception e) {
log.info("Expected exception occured while creating a websocket connection with revoked token.");
} finally {
client.stop();
}
}

@Test(description = "Revoke JWT token after aquiring the connection and try to send the message",
dependsOnMethods = "testWebSocketAPIInvocationWithRevokedJWTToken")
public void testWebSocketAPIFrameMessageWithRevokedJWTToken() throws Exception {
ArrayList grantTypes = new ArrayList();
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.PASSWORD);
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.REFRESH_CODE);
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.CLIENT_CREDENTIAL);
applicationKeyDTO = restAPIStore.generateKeys(appJWTId, "3600", null,
ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, null, grantTypes);
String accessToken = applicationKeyDTO.getToken().getAccessToken();
WebSocketClient client = new WebSocketClient();
try {
WebSocketClientImpl socket = getActiveSocket(client, accessToken, AUTH_IN.HEADER, null, apiEndPoint);
getSocketConnectionResponse(socket);
HttpResponse httpResponse = TokenUtils.revokeToken(applicationKeyDTO.getConsumerKey(),
applicationKeyDTO.getConsumerSecret(), accessToken, keyMangerUrl);
int revocationResponseCode = httpResponse.getResponseCode();
if (revocationResponseCode != 200) {
Assert.fail(String.format("Could not revoke token. Response code for the revocation is : %s",
revocationResponseCode));
}
Thread.sleep(5000);
try {
String response = getSocketConnectionResponse(socket);
assertNotEquals(response, testMessage.toUpperCase(),
"Received the resource with revoked token.");
} catch (Exception e) {

}
} catch (Exception e) {
log.error("Unexpected error while creating web socket connection.", e);
} finally {
client.stop();
}
}

@Test(description = "Create Oauth Type Application and subscribe",
dependsOnMethods = "testWebSocketAPIFrameMessageWithRevokedJWTToken")
public void testWebSocketAPIOAuthApplicationSubscription() throws Exception {
HttpResponse applicationResponse = restAPIStore.createApplication(OAUTH_TYPE_APPLICATION_NAME,
"", APIMIntegrationConstants.API_TIER.UNLIMITED, ApplicationDTO.TokenTypeEnum.OAUTH);
oAuthAppId = applicationResponse.getData();
SubscriptionDTO subscriptionDTO = restAPIStore.subscribeToAPI(websocketAPIID, oAuthAppId,
APIMIntegrationConstants.API_TIER.ASYNC_UNLIMITED);
//Validate Subscription of the API
Assert.assertEquals(subscriptionDTO.getStatus(), SubscriptionDTO.StatusEnum.UNBLOCKED);
}

@Test(description = "Invoke API using token", dependsOnMethods = "testWebSocketAPIOAuthApplicationSubscription")
public void testWebSocketAPIInvocationWithOAuthToken() throws Exception {
ArrayList grantTypes = new ArrayList();
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.PASSWORD);
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.REFRESH_CODE);
grantTypes.add(APIMIntegrationConstants.GRANT_TYPE.CLIENT_CREDENTIAL);
oAuthAppKeyDto = restAPIStore.generateKeys(oAuthAppId, "3600", null,
ApplicationKeyGenerateRequestDTO.KeyTypeEnum.PRODUCTION, null, grantTypes);
String accessToken = oAuthAppKeyDto.getToken().getAccessToken();
String tokenJti = TokenUtils.getJtiOfJwtToken(accessToken);
WebSocketClient client = new WebSocketClient();
try {
invokeAPI(client, tokenJti, AUTH_IN.HEADER, null, apiEndPoint);
invokeAPI(client, tokenJti, AUTH_IN.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 a revoked token", dependsOnMethods = "testWebSocketAPIInvocationWithOAuthToken")
public void testWebSocketAPIInvocationWithRevokedOAuthToken() throws Exception {
String accessToken = oAuthAppKeyDto.getToken().getAccessToken();
String tokenJti = TokenUtils.getJtiOfJwtToken(accessToken);
HttpResponse httpResponse = TokenUtils.revokeToken(oAuthAppKeyDto.getConsumerKey(),
oAuthAppKeyDto.getConsumerSecret(), accessToken, keyMangerUrl);
int revocationResponseCode = httpResponse.getResponseCode();
if (revocationResponseCode != 200) {
Assert.fail(String.format("Could not revoke token. Response code for the revocation is : %s",
revocationResponseCode) );
}
Thread.sleep(5000);
WebSocketClient client = new WebSocketClient();
try {
WebSocketClientImpl socket = getActiveSocket(client, tokenJti, AUTH_IN.HEADER, null,
apiEndPoint);
String response = getSocketConnectionResponse(socket);
assertNotEquals(response, testMessage.toUpperCase(),
"Received response in not matching");
} catch (Exception e) {
log.info("Expected exception thrown when connecting to web socket api with revoked token");
} finally {
client.stop();
}
}

@Test(description = "Invoke API with only sandbox endpoint configured",
dependsOnMethods = "testWebSocketAPIInvocationWithJWTToken")
dependsOnMethods = "testWebSocketAPIInvocationWithRevokedOAuthToken")
public void testWebSocketAPIRemoveEndpoint() throws Exception {

HttpResponse response = restAPIPublisher.copyAPI(apiVersion2, websocketAPIID, false);
Expand Down Expand Up @@ -365,7 +495,8 @@ public void testWebSocketAPIRemoveEndpoint() throws Exception {
APIMIntegrationConstants.IS_API_NOT_EXISTS);
}

@Test(description = "Test Throttling for WebSocket API", dependsOnMethods = "testWebSocketAPIInvocation")
@Test(description = "Test Throttling for WebSocket API",
dependsOnMethods = "testWebSocketAPIInvocationWithRevokedOAuthToken")
public void testWebSocketAPIThrottling() throws Exception {
// Deploy Throttling policy with throttle limit set as 8 frames. One message is two frames, therefore 4
// messages can be sent.
Expand Down Expand Up @@ -796,6 +927,16 @@ private void testThrottling(String accessToken) throws Exception {
private void invokeAPI(WebSocketClient client, String accessToken, AUTH_IN in, HttpHeaders optionalRequestHeaders,
String apiEndPoint) throws Exception {

WebSocketClientImpl socket = getActiveSocket(client, accessToken, in, optionalRequestHeaders, apiEndPoint);
String response = getSocketConnectionResponse(socket);
assertEquals(StringUtils.isEmpty(response), false,
"Client did not receive response from server");
assertEquals(response, testMessage.toUpperCase(),
"Received response in not matching");
}

private WebSocketClientImpl getActiveSocket(WebSocketClient client, String accessToken, AUTH_IN in, HttpHeaders optionalRequestHeaders,
String apiEndPoint) throws Exception {
WebSocketClientImpl socket = new WebSocketClientImpl();
client.start();
ClientUpgradeRequest request = new ClientUpgradeRequest();
Expand All @@ -822,17 +963,19 @@ private void invokeAPI(WebSocketClient client, String accessToken, AUTH_IN in, H
}

client.connect(socket, echoUri, request);
return socket;
}

private String getSocketConnectionResponse(WebSocketClientImpl socket) throws Exception {
if (socket.getLatch().await(30, TimeUnit.SECONDS)) {
socket.sendMessage(testMessage);
waitForReply(socket);
if (StringUtils.isEmpty(socket.getResponseMessage())) {
throw new APIManagerIntegrationTestException("Unable to create client connection");
}
assertEquals(StringUtils.isEmpty(socket.getResponseMessage()), false,
"Client did not receive response from server");
assertEquals(socket.getResponseMessage(), testMessage.toUpperCase(),
"Received response in not matching");
String response = socket.getResponseMessage();
socket.setResponseMessage(null);
return response;
} else {
throw new APIManagerIntegrationTestException("Unable to create client connection");
}
Expand Down
Loading