Skip to content

Commit

Permalink
fix: basic implicit flow test
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc committed Oct 10, 2024
1 parent 541e2e4 commit e1025ec
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 0 deletions.
3 changes: 3 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,6 @@ core_config_version: 0
# (OPTIONAL | Default: oauth_provider_public_service_url) If specified, the core uses this URL to parse responses from
# the oauth provider when the oauth provider's internal address differs from the known public provider address.
# oauth_provider_url_configured_in_oauth_provider:

# (Optional | Default: null) string value. The encryption key used for saving OAuth client secret on the database.
# oauth_client_secret_encryption_key:
3 changes: 3 additions & 0 deletions devConfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,6 @@ disable_telemetry: true
# (OPTIONAL | Default: oauth_provider_public_service_url) If specified, the core uses this URL to parse responses from
# the oauth provider when the oauth provider's internal address differs from the known public provider address.
# oauth_provider_url_configured_in_oauth_provider:

# (Optional | Default: null) string value. The encryption key used for saving OAuth client secret on the database.
# oauth_client_secret_encryption_key:
84 changes: 84 additions & 0 deletions src/test/java/io/supertokens/test/oauth/api/OAuthAPIHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
*
* This software is licensed under the Apache License, Version 2.0 (the
* "License") as published by the Apache Software Foundation.
*
* 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 io.supertokens.test.oauth.api;

import java.util.Map;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import com.google.gson.JsonObject;

import io.supertokens.Main;
import io.supertokens.test.httpRequest.HttpRequestForTesting;
import io.supertokens.webserver.WebserverAPI;

public class OAuthAPIHelper {
// TODO WIP
public static JsonObject createClient(Main main, JsonObject createClientBody) throws Exception {
JsonObject response = HttpRequestForTesting.sendJsonPOSTRequest(main, "",
"http://localhost:3567/recipe/oauth/clients", createClientBody, 1000, 1000, null,
WebserverAPI.getLatestCDIVersion().get(), "");
return response;
}

public static JsonObject auth(Main main, JsonObject authBody) throws Exception {
JsonObject response = HttpRequestForTesting.sendJsonPOSTRequest(main, "",
"http://localhost:3567/recipe/oauth/auth", authBody, 1000, 1000, null,
WebserverAPI.getLatestCDIVersion().get(), "");
return response;
}

public static JsonObject acceptLoginRequest(Main main, Map<String, String> queryParams, JsonObject acceptLoginChallengeBody) throws Exception {
String url = "http://localhost:3567/recipe/oauth/auth/requests/login/accept";
if (queryParams != null && !queryParams.isEmpty()) {
StringBuilder queryString = new StringBuilder("?");
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
if (queryString.length() > 1) {
queryString.append("&");
}
String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.toString());
queryString.append(entry.getKey()).append("=").append(encodedValue);
}
url += queryString.toString();
}

JsonObject response = HttpRequestForTesting.sendJsonPUTRequest(main, "",
url, acceptLoginChallengeBody, 1000, 1000, null,
WebserverAPI.getLatestCDIVersion().get(), "");
return response;
}

public static JsonObject acceptConsentRequest(Main main, Map<String, String> queryParams, JsonObject acceptConsentChallengeBody) throws Exception {
String url = "http://localhost:3567/recipe/oauth/auth/requests/consent/accept";
if (queryParams != null && !queryParams.isEmpty()) {
StringBuilder queryString = new StringBuilder("?");
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
if (queryString.length() > 1) {
queryString.append("&");
}
String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.toString());
queryString.append(entry.getKey()).append("=").append(encodedValue);
}
url += queryString.toString();
}

JsonObject response = HttpRequestForTesting.sendJsonPUTRequest(main, "",
url, acceptConsentChallengeBody, 1000, 1000, null,
WebserverAPI.getLatestCDIVersion().get(), "");
return response;
}
}
209 changes: 209 additions & 0 deletions src/test/java/io/supertokens/test/oauth/api/TestImplicitFlow.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved.
*
* This software is licensed under the Apache License, Version 2.0 (the
* "License") as published by the Apache Software Foundation.
*
* 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 io.supertokens.test.oauth.api;

import io.supertokens.ProcessState;
import io.supertokens.featureflag.EE_FEATURES;
import io.supertokens.featureflag.FeatureFlag;
import io.supertokens.featureflag.FeatureFlagTestContent;
import io.supertokens.pluginInterface.STORAGE_TYPE;
import io.supertokens.storageLayer.StorageLayer;
import io.supertokens.test.TestingProcessManager;
import io.supertokens.test.Utils;
import io.supertokens.test.totp.TotpLicenseTest;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;

import static org.junit.Assert.assertNotNull;

import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class TestImplicitFlow {
@Rule
public TestRule watchman = Utils.getOnFailure();

@AfterClass
public static void afterTesting() {
Utils.afterTesting();
}

@Before
public void beforeEach() {
Utils.reset();
}

@Test
public void testImplicitGrantFlow() throws Exception {
String[] args = {"../"};

// TODO WIP
TestingProcessManager.TestingProcess process = TestingProcessManager.start(args, false);
Utils.setValueInConfig("oauth_provider_public_service_url", "http://localhost:4444");
Utils.setValueInConfig("oauth_provider_admin_service_url", "http://localhost:4445");
Utils.setValueInConfig("oauth_provider_consent_login_base_url", "http://localhost:3001/auth");
Utils.setValueInConfig("oauth_client_secret_encryption_key", "secret");
process.startProcess();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
return;
}

FeatureFlag.getInstance(process.main)
.setLicenseKeyAndSyncFeatures(TotpLicenseTest.OPAQUE_KEY_WITH_MFA_FEATURE);
FeatureFlagTestContent.getInstance(process.main)
.setKeyValue(FeatureFlagTestContent.ENABLED_FEATURES, new EE_FEATURES[]{EE_FEATURES.OAUTH});

if (StorageLayer.getStorage(process.getProcess()).getType() != STORAGE_TYPE.SQL) {
return;
}

JsonObject clientBody = new JsonObject();
JsonArray grantTypes = new JsonArray();
grantTypes.add(new JsonPrimitive("implicit"));
clientBody.add("grantTypes", grantTypes);
JsonArray responseTypes = new JsonArray();
responseTypes.add(new JsonPrimitive("token"));
responseTypes.add(new JsonPrimitive("id_token"));
clientBody.add("responseTypes", responseTypes);
JsonArray redirectUris = new JsonArray();
redirectUris.add(new JsonPrimitive("http://localhost.com:3000/auth/callback/supertokens"));
clientBody.add("redirectUris", redirectUris);
clientBody.addProperty("scope", "openid profile email");

JsonObject client = OAuthAPIHelper.createClient(process.getProcess(), clientBody);

JsonObject authRequestBody = new JsonObject();
JsonObject params = new JsonObject();
params.addProperty("client_id", client.get("clientId").getAsString());
params.addProperty("redirect_uri", "http://localhost.com:3000/auth/callback/supertokens");
params.addProperty("response_type", "token");
params.addProperty("scope", "openid profile email");
params.addProperty("state", "test12345678");

authRequestBody.add("params", params);

JsonObject authResponse = OAuthAPIHelper.auth(process.getProcess(), authRequestBody);
System.out.println("AuthResponse: " + authResponse);
String cookies = authResponse.get("cookies").getAsJsonArray().get(0).getAsString();
cookies = cookies.split(";")[0];

String redirectTo = authResponse.get("redirectTo").getAsString();
redirectTo = redirectTo.replace("{apiDomain}", "http://localhost:3001/auth");

URL url = new URL(redirectTo);
Map<String, String> queryParams = splitQuery(url);
String loginChallenge = queryParams.get("login_challenge");

Map<String, String> acceptLoginRequestParams = new HashMap<>();
acceptLoginRequestParams.put("loginChallenge", loginChallenge);

JsonObject acceptLoginRequestBody = new JsonObject();
acceptLoginRequestBody.addProperty("subject", "someuserid");
acceptLoginRequestBody.addProperty("remember", true);
acceptLoginRequestBody.addProperty("rememberFor", 3600);

JsonObject acceptLoginRequestResponse = OAuthAPIHelper.acceptLoginRequest(process.getProcess(), acceptLoginRequestParams, acceptLoginRequestBody);
System.out.println("AcceptLoginRequest: " + acceptLoginRequestResponse);

redirectTo = acceptLoginRequestResponse.get("redirectTo").getAsString();
redirectTo = redirectTo.replace("{apiDomain}", "http://localhost:3001/auth");

url = new URL(redirectTo);
queryParams = splitQuery(url);

params = new JsonObject();
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
params.addProperty(entry.getKey(), entry.getValue());
}
authRequestBody.add("params", params);
authRequestBody.addProperty("cookies", cookies);

authResponse = OAuthAPIHelper.auth(process.getProcess(), authRequestBody);
System.out.println(authResponse);

redirectTo = authResponse.get("redirectTo").getAsString();
redirectTo = redirectTo.replace("{apiDomain}", "http://localhost:3001/auth");
cookies = authResponse.get("cookies").getAsJsonArray().get(0).getAsString();
cookies = cookies.split(";")[0];

url = new URL(redirectTo);
queryParams = splitQuery(url);

String consentChallenge = queryParams.get("consent_challenge");

JsonObject acceptConsentRequestBody = new JsonObject();
acceptConsentRequestBody.addProperty("remember", true);
acceptConsentRequestBody.addProperty("rememberFor", 3600);
acceptConsentRequestBody.addProperty("iss", "http://localhost:3001/auth");
acceptConsentRequestBody.addProperty("tId", "public");
acceptConsentRequestBody.addProperty("rsub", "someuser");
acceptConsentRequestBody.addProperty("sessionHandle", "session-handle");
acceptConsentRequestBody.add("initialAccessTokenPayload", new JsonObject());
acceptConsentRequestBody.add("initialIdTokenPayload", new JsonObject());

queryParams = new HashMap<>();
queryParams.put("consentChallenge", consentChallenge);

JsonObject acceptConsentRequestResponse = OAuthAPIHelper.acceptConsentRequest(process.getProcess(), queryParams, acceptConsentRequestBody);
System.out.println("AcceptConsentRequest: " + acceptConsentRequestResponse);

redirectTo = acceptConsentRequestResponse.get("redirectTo").getAsString();
redirectTo = redirectTo.replace("{apiDomain}", "http://localhost:3001/auth");

url = new URL(redirectTo);
queryParams = splitQuery(url);

params = new JsonObject();
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
params.addProperty(entry.getKey(), entry.getValue());
}
authRequestBody.add("params", params);
authRequestBody.addProperty("cookies", cookies);

authResponse = OAuthAPIHelper.auth(process.getProcess(), authRequestBody);
System.out.println(authResponse);

process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

// Helper method to split query parameters
private static Map<String, String> splitQuery(URL url) throws UnsupportedEncodingException {
Map<String, String> queryPairs = new LinkedHashMap<>();
String query = url.getQuery();
String[] pairs = query.split("&");
for (String pair : pairs) {
int idx = pair.indexOf("=");
queryPairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"),
URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
}
return queryPairs;
}
}

0 comments on commit e1025ec

Please sign in to comment.