mirror of
https://github.com/ysoftdevs/oauth-playground-server.git
synced 2026-03-24 10:01:57 +01:00
fix verification url generation, rewrite DAG test
This commit is contained in:
@@ -13,6 +13,7 @@ import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
@@ -46,6 +47,8 @@ public class OAuthResource {
|
||||
UsersRepo usersRepo;
|
||||
@Inject
|
||||
SessionsRepo sessionsRepo;
|
||||
@Inject
|
||||
UriInfo uriInfo;
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
@@ -102,7 +105,9 @@ public class OAuthResource {
|
||||
return new DeviceResponse(
|
||||
sessionsRepo.generateAuthorizationCode(sessionId),
|
||||
sessionsRepo.generateUserCode(sessionId),
|
||||
"http://verificationuri/device-login",
|
||||
uriInfo.getBaseUriBuilder()
|
||||
.path(OAuthResource.class)
|
||||
.path(OAuthResource.class, "enterDeviceCode").build(),
|
||||
10,
|
||||
180
|
||||
);
|
||||
|
||||
@@ -2,10 +2,12 @@ package com.ysoft.geecon.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public record DeviceResponse(
|
||||
@JsonProperty("device_code") String deviceCode,
|
||||
@JsonProperty("user_code") String userCode,
|
||||
@JsonProperty("verification_uri") String verificationUri,
|
||||
@JsonProperty("verification_uri") URI verificationUri,
|
||||
@JsonProperty("interval") long interval,
|
||||
@JsonProperty("expires_in") long expiresIn
|
||||
) {
|
||||
|
||||
@@ -3,84 +3,67 @@ package com.ysoft.geecon;
|
||||
import com.ysoft.geecon.dto.DeviceResponse;
|
||||
import com.ysoft.geecon.dto.OAuthClient;
|
||||
import com.ysoft.geecon.dto.User;
|
||||
import com.ysoft.geecon.helpers.ConsentScreen;
|
||||
import com.ysoft.geecon.helpers.DeviceAuthorizationGrantFlow;
|
||||
import com.ysoft.geecon.helpers.DeviceCodeScreen;
|
||||
import com.ysoft.geecon.helpers.LoginScreen;
|
||||
import com.ysoft.geecon.repo.ClientsRepo;
|
||||
import com.ysoft.geecon.repo.UsersRepo;
|
||||
import io.quarkus.test.common.http.TestHTTPResource;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.HttpStatusException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@QuarkusTest
|
||||
public class DeviceAuthGrantTest {
|
||||
|
||||
public static final OAuthClient CLIENT = new OAuthClient("deviceclient", "", null, null);
|
||||
@Inject
|
||||
ClientsRepo clientsRepo;
|
||||
@Inject
|
||||
UsersRepo usersRepo;
|
||||
|
||||
@TestHTTPResource("auth/device")
|
||||
String deviceUri;
|
||||
|
||||
@TestHTTPResource("auth/device-login")
|
||||
URI deviceLoginUri;
|
||||
|
||||
@BeforeEach
|
||||
void beforeAll() {
|
||||
clientsRepo.register(CLIENT);
|
||||
usersRepo.register(new User("bob", "password"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void deviceAuthGrant_invalidCode() {
|
||||
given().formParam("code", "somecode").
|
||||
when().post("/auth/device-login").
|
||||
then().statusCode(404);
|
||||
public void deviceAuthGrant_invalidCode() throws IOException {
|
||||
DeviceCodeScreen deviceCodeScreen = new DeviceCodeScreen(deviceLoginUri);
|
||||
|
||||
HttpStatusException exception = assertThrows(HttpStatusException.class, () -> deviceCodeScreen.enterCode("somecode"));
|
||||
assertThat(exception.getStatusCode(), is(404));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deviceAuthGrant() {
|
||||
clientsRepo.register(new OAuthClient("myclient", "", null, null));
|
||||
usersRepo.register(new User("bob", "password"));
|
||||
public void deviceAuthGrant() throws IOException {
|
||||
DeviceAuthorizationGrantFlow flow = new DeviceAuthorizationGrantFlow(deviceUri, CLIENT);
|
||||
DeviceResponse deviceResponse = flow.start();
|
||||
|
||||
DeviceResponse deviceResponse = given().
|
||||
formParam("client_id", "myclient").
|
||||
when().post("/auth/device")
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(JSON)
|
||||
.body("device_code", is(notNullValue()))
|
||||
.body("user_code", is(notNullValue()))
|
||||
.body("verification_uri", is(notNullValue()))
|
||||
.body("interval", is(notNullValue()))
|
||||
.body("expires_in", is(notNullValue()))
|
||||
.extract().body().as(DeviceResponse.class);
|
||||
DeviceCodeScreen deviceCodeScreen = new DeviceCodeScreen(deviceResponse.verificationUri());
|
||||
LoginScreen loginScreen = deviceCodeScreen.enterCode(deviceResponse.userCode());
|
||||
|
||||
String deviceLogin = given().formParam("code", deviceResponse.userCode()).
|
||||
when().post("/auth/device-login").
|
||||
then().statusCode(200)
|
||||
.extract().body().asString();
|
||||
ConsentScreen consentScreen = loginScreen.submitCorrect("bob", "password");
|
||||
consentScreen.submit();
|
||||
|
||||
String sessionId = Jsoup.parse(deviceLogin).getElementsByAttributeValue("name", "sessionId").first().attr("value");
|
||||
|
||||
given().
|
||||
formParam("sessionId", sessionId).
|
||||
formParam("username", "bob").
|
||||
formParam("password", "password").
|
||||
when().
|
||||
post("auth")
|
||||
.then().statusCode(200);
|
||||
|
||||
given().
|
||||
formParam("sessionId", sessionId).
|
||||
when().
|
||||
post("auth/consent")
|
||||
.then().statusCode(200);
|
||||
|
||||
given().
|
||||
formParam("grant_type", "urn:ietf:params:oauth:grant-type:device_code").
|
||||
formParam("client_id", "myclient").
|
||||
formParam("device_code", deviceResponse.deviceCode()).
|
||||
when().
|
||||
post("/auth/token")
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(JSON)
|
||||
.body("token_type", is(notNullValue()))
|
||||
.body("expires_in", is(notNullValue()))
|
||||
.body("access_token", is(notNullValue()))
|
||||
.body("refresh_token", is(notNullValue()));
|
||||
flow.exchangeDeviceCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.ysoft.geecon.helpers;
|
||||
|
||||
import com.ysoft.geecon.dto.AccessTokenResponse;
|
||||
import com.ysoft.geecon.dto.DeviceResponse;
|
||||
import com.ysoft.geecon.dto.OAuthClient;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
|
||||
public class DeviceAuthorizationGrantFlow {
|
||||
private final String deviceUrl;
|
||||
private final OAuthClient client;
|
||||
private DeviceResponse deviceResponse;
|
||||
|
||||
public DeviceAuthorizationGrantFlow(String deviceUrl, OAuthClient client) {
|
||||
this.deviceUrl = deviceUrl;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public DeviceResponse start() throws IOException {
|
||||
deviceResponse = given().
|
||||
formParam("client_id", client.clientId()).
|
||||
when().post(deviceUrl)
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(JSON)
|
||||
.body("device_code", is(notNullValue()))
|
||||
.body("user_code", is(notNullValue()))
|
||||
.body("verification_uri", is(notNullValue()))
|
||||
.body("interval", is(notNullValue()))
|
||||
.body("expires_in", is(notNullValue()))
|
||||
.extract().body().as(DeviceResponse.class);
|
||||
|
||||
return deviceResponse;
|
||||
}
|
||||
|
||||
public AccessTokenResponse exchangeDeviceCode() {
|
||||
return given()
|
||||
.formParam("grant_type", "urn:ietf:params:oauth:grant-type:device_code")
|
||||
.formParam("client_id", client.clientId())
|
||||
.formParam("device_code", deviceResponse.deviceCode())
|
||||
.when()
|
||||
.post("/auth/token")
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(JSON)
|
||||
.body("token_type", is(notNullValue()))
|
||||
.body("expires_in", is(notNullValue()))
|
||||
.body("access_token", is(notNullValue()))
|
||||
.body("refresh_token", is(notNullValue()))
|
||||
.extract().as(AccessTokenResponse.class);
|
||||
}
|
||||
}
|
||||
23
src/test/java/com/ysoft/geecon/helpers/DeviceCodeScreen.java
Normal file
23
src/test/java/com/ysoft/geecon/helpers/DeviceCodeScreen.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package com.ysoft.geecon.helpers;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.FormElement;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
public class DeviceCodeScreen {
|
||||
|
||||
private final FormElement form;
|
||||
|
||||
public DeviceCodeScreen(URI verificationUrl) throws IOException {
|
||||
this.form = Jsoup.connect(verificationUrl.toString()).get().expectForm("form");
|
||||
}
|
||||
|
||||
public LoginScreen enterCode(String code) throws IOException {
|
||||
form.getElementsByAttributeValue("name", "code").val(code);
|
||||
Document login = form.submit().post();
|
||||
return new LoginScreen(login);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ public class LoginScreen {
|
||||
|
||||
public LoginScreen(Document doc) {
|
||||
this.form = doc.expectForm("form");
|
||||
;
|
||||
}
|
||||
|
||||
public Document submit(String username, String password) throws IOException {
|
||||
|
||||
Reference in New Issue
Block a user