FINERACT-1984: OAuth2.1
This commit is contained in:
committed by
Arnold Gálovics
parent
0c0d8592bb
commit
fa9c7b9364
@@ -35,6 +35,9 @@ configurations {
|
||||
}
|
||||
dependencies {
|
||||
driver 'com.mysql:mysql-connector-j'
|
||||
testImplementation 'org.seleniumhq.selenium:selenium-java:4.21.0'
|
||||
testImplementation 'io.github.bonigarcia:webdrivermanager:5.5.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
|
||||
}
|
||||
|
||||
cargo {
|
||||
@@ -57,7 +60,7 @@ cargo {
|
||||
startStopTimeout = 240000
|
||||
sharedClasspath = configurations.driver
|
||||
containerProperties {
|
||||
def jvmArgs = '--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Dfineract.security.basicauth.enabled=false -Dfineract.security.oauth.enabled=true -Dfineract.security.2fa.enabled=false '
|
||||
def jvmArgs = '--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Dfineract.security.basicauth.enabled=false -Dfineract.security.oauth2.enabled=true -Dfineract.security.2fa.enabled=false '
|
||||
if (project.hasProperty('dbType')) {
|
||||
if ('postgresql'.equalsIgnoreCase(dbType)) {
|
||||
jvmArgs += '-Dspring.datasource.hikari.driverClassName=org.postgresql.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:postgresql://localhost:5432/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=postgres -Dfineract.tenant.host=localhost -Dfineract.tenant.port=5432 -Dfineract.tenant.username=root -Dfineract.tenant.password=postgres'
|
||||
|
||||
+90
-43
@@ -20,9 +20,11 @@ package org.apache.fineract.oauth2tests;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
@@ -31,10 +33,21 @@ import io.restassured.path.json.JsonPath;
|
||||
import io.restassured.response.Response;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import jakarta.mail.MessagingException;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.chrome.ChromeDriver;
|
||||
import org.openqa.selenium.chrome.ChromeOptions;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
public class OAuth2AuthenticationTest {
|
||||
|
||||
@@ -75,49 +88,22 @@ public class OAuth2AuthenticationTest {
|
||||
|
||||
@Test
|
||||
public void testAccessWithoutAuthentication() {
|
||||
performServerGet(requestSpec, responseSpec401, "/fineract-provider/api/v1/offices/1?" + TENANT_IDENTIFIER, "");
|
||||
performServerGet(requestSpec, responseSpec401, "/fineract-provider/api/v1/offices/1?" + TENANT_IDENTIFIER, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOAuth2Login() throws IOException, MessagingException {
|
||||
public void testGetOAuth2UserDetails() throws IOException, InterruptedException {
|
||||
performServerGet(requestSpec, responseSpec401, "/fineract-provider/api/v1/offices/1?" + TENANT_IDENTIFIER, null);
|
||||
|
||||
performServerGet(requestSpec, responseSpec401, "/fineract-provider/api/v1/offices/1?" + TENANT_IDENTIFIER, "");
|
||||
|
||||
String accessToken = performServerPost(requestFormSpec, responseSpec, "http://localhost:9000/auth/realms/fineract/token",
|
||||
"grant_type=client_credentials&client_id=community-app&client_secret=123123", "access_token");
|
||||
assertNotNull(accessToken);
|
||||
|
||||
String bearerToken = performServerPost(requestFormSpec, responseSpec, "http://localhost:9000/auth/realms/fineract/token",
|
||||
"grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + accessToken
|
||||
+ "&client_id=community-app&scope=fineract",
|
||||
"access_token");
|
||||
assertNotNull(bearerToken);
|
||||
String token = loginAndClaimToken(
|
||||
"https://localhost:8443/fineract-provider/oauth2/authorize" + "?response_type=code&client_id=frontend-client"
|
||||
+ "&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fcallback&scope=read&state=xyz"
|
||||
+ "&code_challenge=zudG_xkz8WrPPMq2MwmFP-NRvNapCL0OD-xYWRapTsU" + "&code_challenge_method=S256",
|
||||
requestFormSpec);
|
||||
|
||||
RequestSpecification requestSpecWithToken = new RequestSpecBuilder() //
|
||||
.setContentType(ContentType.JSON) //
|
||||
.addHeader("Authorization", "Bearer " + bearerToken) //
|
||||
.build();
|
||||
|
||||
performServerGet(requestSpecWithToken, responseSpec, "/fineract-provider/api/v1/offices/1?" + TENANT_IDENTIFIER, "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOAuth2UserDetails() {
|
||||
performServerGet(requestSpec, responseSpec401, "/fineract-provider/api/v1/offices/1?" + TENANT_IDENTIFIER, "");
|
||||
|
||||
String accessToken = performServerPost(requestFormSpec, responseSpec, "http://localhost:9000/auth/realms/fineract/token",
|
||||
"grant_type=client_credentials&client_id=community-app&client_secret=123123", "access_token");
|
||||
assertNotNull(accessToken);
|
||||
|
||||
String bearerToken = performServerPost(requestFormSpec, responseSpec, "http://localhost:9000/auth/realms/fineract/token",
|
||||
"grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + accessToken
|
||||
+ "&client_id=community-app&scope=fineract",
|
||||
"access_token");
|
||||
assertNotNull(bearerToken);
|
||||
|
||||
RequestSpecification requestSpecWithToken = new RequestSpecBuilder() //
|
||||
.setContentType(ContentType.JSON) //
|
||||
.addHeader("Authorization", "Bearer " + bearerToken) //
|
||||
.addHeader("Authorization", "Bearer " + token) //
|
||||
.build();
|
||||
|
||||
Boolean authenticationCheck = performServerGet(requestSpecWithToken, responseSpec,
|
||||
@@ -149,11 +135,73 @@ public class OAuth2AuthenticationTest {
|
||||
} catch (Exception e) {
|
||||
Thread.sleep(3000);
|
||||
}
|
||||
attempt++;
|
||||
} while (attempt < max_attempts);
|
||||
|
||||
fail(HEALTH_URL + " returned " + response.prettyPrint());
|
||||
}
|
||||
|
||||
public String loginAndClaimToken(String url, RequestSpecification requestSpec) throws IOException {
|
||||
CompletableFuture<String> futureToken = new CompletableFuture<>();
|
||||
HttpServer server = HttpServer.create(new InetSocketAddress(3000), 0);
|
||||
server.createContext("/callback", exchange -> {
|
||||
try {
|
||||
String token = claimTokenOnCallback(requestSpec, exchange);
|
||||
futureToken.complete(token); // complete future with value
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
} catch (Exception e) {
|
||||
futureToken.completeExceptionally(e); // propagate exception
|
||||
} finally {
|
||||
exchange.close();
|
||||
}
|
||||
});
|
||||
server.start();
|
||||
WebDriver driver = getWebDriver();
|
||||
try {
|
||||
driver.get(url);
|
||||
driver.findElement(By.name("username")).sendKeys("mifos");
|
||||
driver.findElement(By.name("password")).sendKeys("password");
|
||||
driver.findElement(By.name("tenantId")).sendKeys("default");
|
||||
driver.findElement(By.cssSelector("button[type='submit'], input[type='submit']")).click();
|
||||
return futureToken.get(5, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
driver.quit();
|
||||
server.stop(0);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static WebDriver getWebDriver() {
|
||||
ChromeOptions options = new ChromeOptions();
|
||||
options.addArguments("--headless"); // run in headless mode
|
||||
options.addArguments("--no-sandbox");
|
||||
options.addArguments("--disable-dev-shm-usage");
|
||||
options.addArguments("--ignore-certificate-errors");
|
||||
return new ChromeDriver(options);
|
||||
}
|
||||
|
||||
private String claimTokenOnCallback(RequestSpecification requestSpec, HttpExchange exchange) {
|
||||
String query = exchange.getRequestURI().getQuery();
|
||||
String code = null;
|
||||
if (query != null) {
|
||||
for (String param : Splitter.on("&").split(query)) {
|
||||
List<String> keyValue = Splitter.on("=").splitToList(param);
|
||||
if (keyValue.size() == 2) {
|
||||
String key = keyValue.getFirst();
|
||||
if ("code".equals(key)) {
|
||||
code = URLDecoder.decode(keyValue.getLast(), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, String> formParams = Map.of("grant_type", "authorization_code", "code", code, "redirect_uri",
|
||||
"http://localhost:3000/callback", "client_id", "frontend-client", "code_verifier",
|
||||
"gyQBFpozcvcosvPt7m9Q1A4SqSf1yJtPIERruioHLjQ");
|
||||
return performServerPost(requestSpec, responseSpec, "/fineract-provider/oauth2/token", formParams, "access_token");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T performServerGet(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||
final String getURL, final String jsonAttributeToGetBack) {
|
||||
@@ -164,11 +212,10 @@ public class OAuth2AuthenticationTest {
|
||||
return (T) JsonPath.from(json).get(jsonAttributeToGetBack);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T performServerPost(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||
final String putURL, final String formBody, final String jsonAttributeToGetBack) {
|
||||
final String json = given().spec(requestSpec).body(formBody).expect().spec(responseSpec).log().ifError().when().post(putURL)
|
||||
.andReturn().asString();
|
||||
return (T) JsonPath.from(json).get(jsonAttributeToGetBack);
|
||||
final String putURL, final Map<String, String> formBody, final String jsonAttributeToGetBack) {
|
||||
final String response = given().spec(requestSpec).header("Content-Type", "application/x-www-form-urlencoded").formParams(formBody)
|
||||
.expect().spec(responseSpec).log().ifError().when().post(putURL).andReturn().asString();
|
||||
return (T) JsonPath.from(response).get(jsonAttributeToGetBack);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user