Skip to content

Commit

Permalink
Add cucumber test for visibility feature
Browse files Browse the repository at this point in the history
  • Loading branch information
sgayangi committed Oct 30, 2023
1 parent ca9ce96 commit eabfc02
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 18 deletions.
18 changes: 18 additions & 0 deletions helm-charts/templates/postgres/initdb-conf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -403,5 +403,23 @@ data:
PRIMARY KEY (CONSUMER_KEY)
);
-- End of Non Prod IDP table --
-- Insert Backoffice Internal Data --
INSERT INTO api(uuid, api_name, api_version, context, status, organization, artifact)
VALUES ('01ed75e2-b30b-18c8-wwf2-25da7edd2231', 'Backoffice Test API', '1.0.0', 'test',
'CREATED', 'a3b58ccf-6ecc-4557-b5bb-0a35cce38256',
'{"id": "01ed75e2-b30b-18c8-wwf2-25da7edd2231", "status": "CREATED", "apiName": "Backoffice Test API", "context": "test", "version": "1.0.0",
"visibility": "PUBLIC", "providerName": "admin", "accessControl": "RESTRICTED", "visibleGroups": null, "accessControlGroups": ["group1"]}');
INSERT INTO api_artifact(organization, api_uuid, api_definition, media_type)
VALUES ('a3b58ccf-6ecc-4557-b5bb-0a35cce38256', '01ed75e2-b30b-18c8-wwf2-25da7edd2231',
'\x7b226f70656e617069223a22332e302e30222c22696e666f223a7b227469746c65223a2253616d706c6520415049222c226465736372697074696f6e223a224f7074696f6e616c206d756c74696c696e65206f722073696e676c652d6c696e65206465736372697074696f6e20696e205b436f6d6d6f6e4d61726b5d28687474703a2f2f636f6d6d6f6e6d61726b2e6f72672f68656c702f29206f722048544d4c2e222c2276657273696f6e223a22302e312e39227d2c2273657276657273223a5b7b2275726c223a22687474703a2f2f6170692e6578616d706c652e636f6d2f7631222c226465736372697074696f6e223a224f7074696f6e616c20736572766572206465736372697074696f6e2c20652e672e204d61696e202870726f64756374696f6e2920736572766572227d2c7b2275726c223a22687474703a2f2f73746167696e672d6170692e6578616d706c652e636f6d222c226465736372697074696f6e223a224f7074696f6e616c20736572766572206465736372697074696f6e2c20652e672e20496e7465726e616c2073746167696e672073657276657220666f722074657374696e67227d5d2c227061746873223a7b222f7573657273223a7b22676574223a7b2273756d6d617279223a2252657475726e732061206c697374206f662075736572732e222c226465736372697074696f6e223a224f7074696f6e616c20657874656e646564206465736372697074696f6e20696e20436f6d6d6f6e4d61726b206f722048544d4c2e222c22726573706f6e736573223a7b22323030223a7b226465736372697074696f6e223a2241204a534f4e206172726179206f662075736572206e616d6573222c22636f6e74656e74223a7b226170706c69636174696f6e2f6a736f6e223a7b22736368656d61223a7b2274797065223a226172726179222c226974656d73223a7b2274797065223a22737472696e67227d7d7d7d7d7d7d7d7d7d',
'HTTP');
INSERT INTO api_lc_event (api_uuid,previous_state,new_state,user_uuid,organization,event_date)
VALUES ('01ed75e2-b30b-18c8-wwf2-25da7edd2231', null, 'CREATED', 'apkuser', 'a3b58ccf-6ecc-4557-b5bb-0a35cce38256',
CURRENT_TIMESTAMP AT TIME ZONE 'UTC');
-- End of Insert Backoffice Internal Data --
commit;
{{ end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.wso2.apk.integration.api;

import java.util.HashMap;
import java.util.Map;
import io.cucumber.java.en.When;

import org.apache.http.HttpResponse;
import org.wso2.apk.integration.utils.Constants;
import org.wso2.apk.integration.utils.Utils;
import org.wso2.apk.integration.utils.clients.SimpleHTTPClient;

public class BackOfficeSteps {

private final SharedContext sharedContext;

public BackOfficeSteps(SharedContext sharedContext) {

this.sharedContext = sharedContext;
}

@When("I make the GET APIs call to the backoffice")
public void make_a_deployment_request() throws Exception {
Map<String, String> headers = new HashMap<>();
headers.put(Constants.REQUEST_HEADERS.AUTHORIZATION, "Bearer " + sharedContext.getAccessToken());
headers.put(Constants.REQUEST_HEADERS.HOST, Constants.DEFAULT_API_HOST);

HttpResponse response = sharedContext.getHttpClient().doGet(Utils.getBackOfficeAPIURL(),
headers);

sharedContext.setResponse(response);
sharedContext.setResponseBody(SimpleHTTPClient.responseEntityBodyToString(sharedContext.getResponse()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,22 @@ public void systemIsReady() {

@Then("the response body should contain {string}")
public void theResponseBodyShouldContain(String expectedText) throws IOException {
Assert.assertTrue(sharedContext.getResponseBody().contains(expectedText), "Actual response body: " + sharedContext.getResponseBody());
Assert.assertTrue(sharedContext.getResponseBody().contains(expectedText),
"Actual response body: " + sharedContext.getResponseBody());
}

@Then("the response body should not contain {string}")
public void theResponseBodyShouldNotContain(String expectedText) throws IOException {
Assert.assertFalse(sharedContext.getResponseBody().contains(expectedText), "Actual response body: " + sharedContext.getResponseBody());
Assert.assertFalse(sharedContext.getResponseBody().contains(expectedText),
"Actual response body: " + sharedContext.getResponseBody());
}

@Then("the response body should contain")
public void theResponseBodyShouldContain(DataTable dataTable) throws IOException {
List<String> responseBodyLines = dataTable.asList(String.class);
for (String line : responseBodyLines) {
Assert.assertTrue(sharedContext.getResponseBody().contains(line), "Actual response body: " + sharedContext.getResponseBody());
Assert.assertTrue(sharedContext.getResponseBody().contains(line),
"Actual response body: " + sharedContext.getResponseBody());
}
}

Expand Down Expand Up @@ -140,7 +144,8 @@ public void sendHttpRequest(String httpMethod, String url, String body) throws I

// It will send request using a new thread and forget about the response
@Then("I send {string} async request to {string} with body {string}")
public void sendAsyncHttpRequest(String httpMethod, String url, String body) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
public void sendAsyncHttpRequest(String httpMethod, String url, String body)
throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
if (sharedContext.getResponse() instanceof CloseableHttpResponse) {
((CloseableHttpResponse) sharedContext.getResponse()).close();
}
Expand Down Expand Up @@ -220,7 +225,7 @@ public void waitForNextMinute() throws InterruptedException {
if (secondsToWait > MAX_WAIT_FOR_NEXT_MINUTE_IN_SECONDS) {
return;
}
Thread.sleep((secondsToWait+1) * 1000);
Thread.sleep((secondsToWait + 1) * 1000);
logger.info("Current time: " + LocalDateTime.now());
}

Expand All @@ -229,7 +234,7 @@ public void waitForNextMinuteStrictly() throws InterruptedException {
LocalDateTime now = LocalDateTime.now();
LocalDateTime nextMinute = now.plusMinutes(1).withSecond(0).withNano(0);
long secondsToWait = now.until(nextMinute, ChronoUnit.SECONDS);
Thread.sleep((secondsToWait+1) * 1000);
Thread.sleep((secondsToWait + 1) * 1000);
logger.info("Current time: " + LocalDateTime.now());
}

Expand Down Expand Up @@ -259,8 +264,9 @@ public void containsHeader(String key, String value) {
return; // Any value is acceptable
}
String actualValue = header.getValue();
Assert.assertEquals(value, actualValue,"Header with key found but value mismatched.");
Assert.assertEquals(value, actualValue, "Header with key found but value mismatched.");
}

@Then("the response headers not contains key {string}")
public void notContainsHeader(String key) {
key = Utils.resolveVariables(key, sharedContext.getValueStore());
Expand All @@ -269,11 +275,12 @@ public void notContainsHeader(String key) {
Assert.fail("Response is null.");
}
Header header = response.getFirstHeader(key);
Assert.assertNull(header,"header contains in response headers");
Assert.assertNull(header, "header contains in response headers");
}

@Then("the {string} jwt should validate from JWKS {string} and contain")
public void decode_header_and_validate(String header,String jwksEndpoint, DataTable dataTable) throws MalformedURLException {
public void decode_header_and_validate(String header, String jwksEndpoint, DataTable dataTable)
throws MalformedURLException {
List<Map<String, String>> claims = dataTable.asMaps(String.class, String.class);
JsonObject jsonResponse = (JsonObject) JsonParser.parseString(sharedContext.getResponseBody());
String headerValue = jsonResponse.get("headers").getAsJsonObject().get(header).getAsString();
Expand Down Expand Up @@ -308,7 +315,7 @@ public void decode_header_and_validate(String header,String jwksEndpoint, DataTa
Assert.assertEquals(claim.get("value"), claim1.toString(), "Actual " +
"decoded JWT body: " + claimsSet);
}
} catch (BadJOSEException | JOSEException|ParseException e) {
} catch (BadJOSEException | JOSEException | ParseException e) {
logger.error("JWT Signature verification fail", e);
Assert.fail("JWT Signature verification fail");
}
Expand All @@ -319,9 +326,11 @@ public void iHaveValidSubscription() throws Exception {

Map<String, String> headers = new HashMap<>();
headers.put(Constants.REQUEST_HEADERS.HOST, Constants.DEFAULT_IDP_HOST);
headers.put(Constants.REQUEST_HEADERS.AUTHORIZATION, "Basic NDVmMWM1YzgtYTkyZS0xMWVkLWFmYTEtMDI0MmFjMTIwMDAyOjRmYmQ2MmVjLWE5MmUtMTFlZC1hZmExLTAyNDJhYzEyMDAwMg==");
headers.put(Constants.REQUEST_HEADERS.AUTHORIZATION,
"Basic NDVmMWM1YzgtYTkyZS0xMWVkLWFmYTEtMDI0MmFjMTIwMDAyOjRmYmQ2MmVjLWE5MmUtMTFlZC1hZmExLTAyNDJhYzEyMDAwMg==");

HttpResponse httpResponse = httpClient.doPost(Utils.getTokenEndpointURL(), headers, "grant_type=client_credentials&scope=" + Constants.API_CREATE_SCOPE,
HttpResponse httpResponse = httpClient.doPost(Utils.getTokenEndpointURL(), headers,
"grant_type=client_credentials&scope=" + Constants.API_CREATE_SCOPE,
Constants.CONTENT_TYPES.APPLICATION_X_WWW_FORM_URLENCODED);
sharedContext.setAccessToken(Utils.extractToken(httpResponse));
sharedContext.addStoreValue("accessToken", sharedContext.getAccessToken());
Expand All @@ -332,9 +341,11 @@ public void iHaveValidSubscriptionWithAPICreateScope() throws Exception {

Map<String, String> headers = new HashMap<>();
headers.put(Constants.REQUEST_HEADERS.HOST, Constants.DEFAULT_IDP_HOST);
headers.put(Constants.REQUEST_HEADERS.AUTHORIZATION, "Basic NDVmMWM1YzgtYTkyZS0xMWVkLWFmYTEtMDI0MmFjMTIwMDAyOjRmYmQ2MmVjLWE5MmUtMTFlZC1hZmExLTAyNDJhYzEyMDAwMg==");
headers.put(Constants.REQUEST_HEADERS.AUTHORIZATION,
"Basic NDVmMWM1YzgtYTkyZS0xMWVkLWFmYTEtMDI0MmFjMTIwMDAyOjRmYmQ2MmVjLWE5MmUtMTFlZC1hZmExLTAyNDJhYzEyMDAwMg==");

HttpResponse httpResponse = httpClient.doPost(Utils.getTokenEndpointURL(), headers, "grant_type=client_credentials",
HttpResponse httpResponse = httpClient.doPost(Utils.getTokenEndpointURL(), headers,
"grant_type=client_credentials",
Constants.CONTENT_TYPES.APPLICATION_X_WWW_FORM_URLENCODED);
sharedContext.setAccessToken(Utils.extractToken(httpResponse));
sharedContext.addStoreValue("accessToken", sharedContext.getAccessToken());
Expand All @@ -353,9 +364,28 @@ public void iHaveValidSubscriptionWithScope(DataTable dataTable) throws Exceptio
headers.put(Constants.REQUEST_HEADERS.AUTHORIZATION, Constants.SUBSCRIPTION_BASIC_AUTH_TOKEN);

HttpResponse httpResponse = httpClient.doPost(Utils.getTokenEndpointURL(), headers,
"grant_type=client_credentials&scope=" + scopes,
Constants.CONTENT_TYPES.APPLICATION_X_WWW_FORM_URLENCODED);
"grant_type=client_credentials&scope=" + scopes,
Constants.CONTENT_TYPES.APPLICATION_X_WWW_FORM_URLENCODED);
sharedContext.setAccessToken(Utils.extractToken(httpResponse));
sharedContext.addStoreValue(Constants.ACCESS_TOKEN, sharedContext.getAccessToken());
}

@Given("I have a valid subscription with groups")
public void iHaveValidSubscriptionWithGroups(DataTable dataTable) throws Exception {
List<List<String>> rows = dataTable.asLists(String.class);
String groups = Constants.EMPTY_STRING;
for (List<String> row : rows) {
String group = row.get(0);
groups += group + Constants.SPACE_STRING;
}
Map<String, String> headers = new HashMap<>();
headers.put(Constants.REQUEST_HEADERS.HOST, Constants.DEFAULT_IDP_HOST);
headers.put(Constants.REQUEST_HEADERS.AUTHORIZATION, Constants.SUBSCRIPTION_BASIC_AUTH_TOKEN);

HttpResponse httpResponse = httpClient.doPost(Utils.getTokenEndpointURL(), headers,
"grant_type=client_credentials&scope=" + Constants.API_VIEW_SCOPE + "&groups=" + groups,
Constants.CONTENT_TYPES.APPLICATION_X_WWW_FORM_URLENCODED);
sharedContext.setAccessToken(Utils.extractToken(httpResponse));
sharedContext.addStoreValue("accessToken", sharedContext.getAccessToken());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ public class Constants {
public static final String DEFAULT_TOKEN_EP = "oauth2/token";
public static final String DEFAULT_API_CONFIGURATOR = "api/configurator/1.0.0/";
public static final String DEFAULT_API_DEPLOYER = "api/deployer/1.0.0/";
public static final String DEFAULT_BACKOFFICE = "/api/backoffice/1.0.0/";
public static final String ACCESS_TOKEN = "accessToken";
public static final String EMPTY_STRING = "";
public static final String API_CREATE_SCOPE = "apk:api_create";
public static final String API_VIEW_SCOPE = "apk:api_view";
public static final String SPACE_STRING = " ";
public static final String SUBSCRIPTION_BASIC_AUTH_TOKEN =
"Basic NDVmMWM1YzgtYTkyZS0xMWVkLWFmYTEtMDI0MmFjMTIwMDAyOjRmYmQ2MmVjLWE5MmUtMTFlZC1hZmExLTAyNDJhYzEyMDAwMg==";
public static final String SUBSCRIPTION_BASIC_AUTH_TOKEN = "Basic NDVmMWM1YzgtYTkyZS0xMWVkLWFmYTEtMDI0MmFjMTIwMDAyOjRmYmQ2MmVjLWE5MmUtMTFlZC1hZmExLTAyNDJhYzEyMDAwMg==";

public class REQUEST_HEADERS {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ public static String getAPIDeployerURL() {
+ Constants.DEFAULT_API_DEPLOYER + "apis/deploy";
}

public static String getBackOfficeAPIURL() {

return "https://" + Constants.DEFAULT_API_HOST + ":" + Constants.DEFAULT_GW_PORT + "/"
+ Constants.DEFAULT_BACKOFFICE + "apis";
}

public static String getAPIUnDeployerURL() {

return "https://" + Constants.DEFAULT_API_HOST + ":" + Constants.DEFAULT_GW_PORT + "/"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Feature: API Visibility and Access Control
Scenario: View APIs with a groups claim and API view scope in the access token
Given The system is ready
And I have a valid subscription with groups
| group1 |
When I make the GET APIs call to the backoffice
Then the response status code should be 200
And the response body should contain "\"count\":1"

Scenario: View APIs without a groups claim in the access token
Given The system is ready
And I have a valid subscription with scopes
| apk:api_view |
When I make the GET APIs call to the backoffice
Then the response status code should be 200
And the response body should contain "\"count\":0"

0 comments on commit eabfc02

Please sign in to comment.