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

Add OAuth2redirectTest #1310

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
50afb3d
Test setup
christiangoerdes Oct 17, 2024
7e27c12
implemented simple test (WIP!).
christiangoerdes Oct 17, 2024
cbd9013
test extension (WIP)
christiangoerdes Oct 17, 2024
7ae6c3c
Add OAuth2 redirect test cases and update dependencies
t-burch Oct 23, 2024
354e296
Add URL decoding and response validation in OAuth2RedirectTest
christiangoerdes Oct 23, 2024
de57f31
Merge branch 'master' into OAuth2redirectTest
christiangoerdes Oct 24, 2024
ed0ee30
Improve OAuth2 redirect test functionality and enhance code clarity
t-burch Oct 24, 2024
7b42879
Merge remote-tracking branch 'origin/OAuth2redirectTest' into OAuth2r…
t-burch Oct 24, 2024
4cbea77
Implement OAuth2 flow enhancements and logging configuration
christiangoerdes Oct 24, 2024
a9ff3bd
WIP:
christiangoerdes Oct 24, 2024
8aa3071
.
t-burch Oct 30, 2024
81bf870
switched to relative path
christiangoerdes Oct 30, 2024
3f3c2ec
New consentfile
t-burch Oct 30, 2024
89b2d40
Finished OAuth2RedirectTest
christiangoerdes Oct 30, 2024
cee573f
refactoring
christiangoerdes Oct 30, 2024
f015128
Revert LogHelper tmp changes
christiangoerdes Oct 30, 2024
31f79e8
refactoring and code optimization
christiangoerdes Oct 30, 2024
64152a5
Merge branch 'master' into OAuth2redirectTest
rrayst Oct 31, 2024
a02fed0
Merge branch 'master' into OAuth2redirectTest
t-burch Nov 4, 2024
a96fc71
Merge branch 'master' into OAuth2redirectTest
t-burch Nov 6, 2024
6e4ace7
added check that URL survives encoding
rrayst Nov 7, 2024
ce7e28a
removed unnecessary file
rrayst Nov 7, 2024
b158620
First prototype of request continuation instead of redirection after …
t-burch Nov 8, 2024
55dbc3a
Add redirect handling in OAuth2CallbackRequestHandler and update OAut…
t-burch Nov 11, 2024
62d9808
Implement OAuth2 redirect handling in the doRedirect method
t-burch Nov 11, 2024
e68f5c7
Merge branch 'master' into OAuth2redirectTest
t-burch Nov 11, 2024
afcf054
Call the handler in OAuth2CallbackRequestHandler to process redirecti…
t-burch Nov 11, 2024
998fa57
Refactor OAuth2 redirect test to streamline steps for GET and POST re…
t-burch Nov 11, 2024
e71e139
Add assertion to verify URL encoding in OAuth2RedirectTest
t-burch Nov 11, 2024
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 @@ -165,6 +165,8 @@ private void parseSrc(InputStream resolve) throws IOException {

// without checks
tokenEndpoint = (String) json.get("token_endpoint");
if (tokenEndpoint == null)
throw new RuntimeException("No token_endpoint could be detected.");
userInfoEndpoint = (String) json.get("userinfo_endpoint");
authorizationEndpoint = (String) json.get("authorization_endpoint");
revocationEndpoint = (String) json.get("revocation_endpoint");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import com.predic8.membrane.core.interceptor.oauth2client.*;
import com.predic8.membrane.core.interceptor.oauth2client.rf.token.*;
import com.predic8.membrane.core.interceptor.session.*;
import com.predic8.membrane.core.transport.http.HttpClient;
import com.predic8.membrane.core.util.*;
import org.apache.http.impl.client.DefaultHttpClient;
import org.slf4j.*;

import java.math.*;
Expand All @@ -38,6 +40,7 @@
import static com.predic8.membrane.core.interceptor.oauth2client.rf.JsonUtils.isJson;
import static com.predic8.membrane.core.interceptor.oauth2client.rf.StateManager.*;
import static com.predic8.membrane.core.interceptor.oauth2client.temp.OAuth2Constants.*;
import static java.util.List.of;

public class OAuth2CallbackRequestHandler {
private static final Logger log = LoggerFactory.getLogger(OAuth2CallbackRequestHandler.class);
Expand Down Expand Up @@ -196,16 +199,20 @@ private Map<String, Object> exchangeCodeForToken(String tokenEndpoint, String pu
});
}

private static void doRedirect(Exchange exc, AbstractExchangeSnapshot originalRequest, Session session) throws JsonProcessingException {
if (originalRequest.getRequest().getMethod().equals("GET")) {
exc.setResponse(Response.redirect(originalRequest.getOriginalRequestUri(), false).build());
} else {
String oa2redirect = new BigInteger(130, new SecureRandom()).toString(32);

session.put(OAuthUtils.oa2redictKeyNameInSession(oa2redirect), new ObjectMapper().writeValueAsString(originalRequest));

String delimiter = originalRequest.getOriginalRequestUri().contains("?") ? "&" : "?";
exc.setResponse(Response.redirect(originalRequest.getOriginalRequestUri() + delimiter + OA2REDIRECT + "=" + oa2redirect, false).build());
private static void doRedirect(Exchange exc, AbstractExchangeSnapshot originalRequest, Session session) throws Exception {
try (HttpClient hc = new HttpClient()) {
Exchange ogExc = (Exchange) originalRequest.toAbstractExchange();
//exc.setResponse(Response.redirect(originalRequest.getOriginalRequestUri(), false).build());
if (originalRequest.getRequest().getMethod().equals("POST")) {
String oa2redirect = new BigInteger(130, new SecureRandom()).toString(32);
session.put(OAuthUtils.oa2redictKeyNameInSession(oa2redirect), new ObjectMapper().writeValueAsString(originalRequest));
String delimiter = ogExc.getOriginalRequestUri().contains("?") ? "&" : "?";

String ogDest = ogExc.getDestinations().get(0);
ogExc.setDestinations(new ArrayList<>(of(ogDest + delimiter + OA2REDIRECT + "=" + oa2redirect)));
}
hc.call(ogExc);
exc.setResponse(ogExc.getResponse());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
import org.jetbrains.annotations.NotNull;

import java.math.BigInteger;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;

import static com.predic8.membrane.core.interceptor.session.SessionManager.SESSION_VALUE_SEPARATOR;
import static java.nio.charset.StandardCharsets.UTF_8;

public class StateManager {

Expand All @@ -39,7 +42,7 @@ public static String getSecurityTokenFromState(String state2) {
if (state2 == null)
throw new RuntimeException("No CSRF token.");

Map<String, String> param = URLParamUtil.parseQueryString(state2, URLParamUtil.DuplicateKeyOrInvalidFormStrategy.ERROR);
Map<String, String> param = URLParamUtil.parseQueryString(URLDecoder.decode(state2, UTF_8), URLParamUtil.DuplicateKeyOrInvalidFormStrategy.ERROR);
rrayst marked this conversation as resolved.
Show resolved Hide resolved

if (!param.containsKey("security_token"))
throw new RuntimeException("No CSRF token.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.predic8.membrane.core.interceptor.RegExReplaceInterceptorTest;
import com.predic8.membrane.core.interceptor.rest.REST2SOAPInterceptorIntegrationTest;
import com.predic8.membrane.core.interceptor.server.WSDLPublisherTest;
import com.predic8.membrane.core.oauth2.OAuth2RedirectTest;
import com.predic8.membrane.core.resolver.ResolverTest;
import com.predic8.membrane.core.rules.ProxySSLTest;
import com.predic8.membrane.core.rules.SOAPProxyIntegrationTest;
Expand Down Expand Up @@ -47,7 +48,8 @@
IllegalCharactersInURLTest.class,
ProxySSLTest.class,
SessionManager.class,
OpenApiRewriteIntegrationTest.class
OpenApiRewriteIntegrationTest.class,
OAuth2RedirectTest.class
})
public class IntegrationTestsWithoutInternet {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package com.predic8.membrane.core.oauth2;

import io.restassured.response.Response;
import org.jetbrains.annotations.NotNull;

import java.util.HashMap;
import java.util.Map;

import static io.restassured.RestAssured.given;
import static org.apache.http.HttpHeaders.LOCATION;
import static org.hamcrest.text.MatchesPattern.matchesPattern;

public class OAuth2AuthFlowClient {

private static final String CLIENT_BASE_URL = "http://localhost:2000";
private static final String CLIENT_URL = CLIENT_BASE_URL + "/a?b=c&d= ";
private static final String AUTH_SERVER_URL = "http://localhost:2002";

Map<String, String> cookies = new HashMap<>();
Map<String, String> memCookies = new HashMap<>();

// @formatter:off
@NotNull Response step1originalRequestGET() {
Response response =
given()
.redirects().follow(false)
.when()
.get(CLIENT_URL)
.then()
.statusCode(307)
.header(LOCATION, matchesPattern(AUTH_SERVER_URL + ".*"))
.extract().response();
memCookies.putAll(response.getCookies());
return response;
}

@NotNull Response step1originalRequestPOST() {
Response response =
given()
.redirects().follow(false)
.when()
.post(CLIENT_URL)
.then()
.statusCode(307)
.header(LOCATION, matchesPattern(AUTH_SERVER_URL + ".*"))
.extract().response();
memCookies.putAll(response.getCookies());
return response;
}

@NotNull String step2sendAuthToOAuth2Server(Response response) {
Response formRedirect =
given()
.redirects().follow(false)
.cookies(cookies)
.urlEncodingEnabled(false)
.when()
.get(response.getHeader(LOCATION))
.then()
.statusCode(307)
.header(LOCATION, matchesPattern("/login.*"))
.extract().response();
cookies.putAll(formRedirect.getCookies());
return formRedirect.getHeader(LOCATION);
}

void step3openLoginPage(String location) {
given()
.redirects().follow(true)
.cookies(cookies)
.when()
.get(AUTH_SERVER_URL + location)
.then()
.statusCode(200)
.extract().response();
}

void step4submitLogin(String location) {
given()
.redirects().follow(false)
.cookies(cookies)
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Accept-Charset", "UTF-8")
.formParam("username", "user")
.formParam("password", "password")
.when()
.post(AUTH_SERVER_URL + location)
.then()
.statusCode(200)
.header(LOCATION, "/")
.extract().response();
}

String step5redirectToConsent() {
return given()
.redirects().follow(false)
.cookies(cookies)
.when()
.get(AUTH_SERVER_URL)
.then()
.statusCode(307)
.header(LOCATION, matchesPattern("/login/consent.*"))
.extract().response().getHeader(LOCATION);
}

void step6openConsentDialog(String location) {
given()
.redirects().follow(false)
.cookies(cookies)
.when()
.get(AUTH_SERVER_URL + location)
.then()
.statusCode(200)
.extract().response();
}

void step7submitConsent(String location) {
given()
.redirects().follow(false)
.cookies(cookies)
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Accept-Charset", "UTF-8")
.formParam("consent", "Accept")
.when()
.post(AUTH_SERVER_URL + location)
.then()
.statusCode(200)
.header(LOCATION, "/")
.extract().response();
}

String step8redirectToClient() {
return given()
.redirects().follow(false)
.cookies(cookies)
.when()
.post(AUTH_SERVER_URL)
.then()
.statusCode(307)
.header(LOCATION, matchesPattern(CLIENT_BASE_URL + ".*"))
.extract().response().getHeader(LOCATION);
}

void step9exchangeCodeForToken(String location) {
given()
.redirects().follow(false)
.cookies(memCookies)
.when()
.post(location)
.then()
.statusCode(200)
.extract().response();
}
// @formatter:on
}
Loading
Loading