mirror of
https://github.com/ysoftdevs/oauth-playground-server.git
synced 2026-03-21 08:39:40 +01:00
test of Auth Code Grant flow
This commit is contained in:
@@ -2,34 +2,28 @@ package com.ysoft.geecon;
|
||||
|
||||
import com.ysoft.geecon.dto.OAuthClient;
|
||||
import com.ysoft.geecon.dto.User;
|
||||
import com.ysoft.geecon.helpers.AuthorizationCodeFlow;
|
||||
import com.ysoft.geecon.helpers.ConsentScreen;
|
||||
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.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.jsoup.Connection;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.FormElement;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
@QuarkusTest
|
||||
public class AuthCodeGrantTest {
|
||||
public static final OAuthClient CLIENT = new OAuthClient("myclient", "", null, "https://myserver:8888/success");
|
||||
@Inject
|
||||
ClientsRepo clientsRepo;
|
||||
@Inject
|
||||
@@ -40,54 +34,26 @@ public class AuthCodeGrantTest {
|
||||
|
||||
@BeforeEach
|
||||
void beforeAll() {
|
||||
clientsRepo.register(new OAuthClient("myclient", "", null, "https://myserver:8888/success"));
|
||||
clientsRepo.register(CLIENT);
|
||||
usersRepo.register(new User("bob", "password"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authCodeGrant() throws IOException {
|
||||
String state = "test state is not random";
|
||||
FormElement login = Jsoup.connect(authUrl)
|
||||
.data("client_id", "myclient")
|
||||
.data("redirect_uri", "https://myserver:8888/success")
|
||||
.data("state", state)
|
||||
.data("scope", "scope1 scope2")
|
||||
.get().forms().get(0);
|
||||
login.getElementsByAttributeValue("name", "username").val("bob");
|
||||
login.getElementsByAttributeValue("name", "password").val("password");
|
||||
AuthorizationCodeFlow flow = new AuthorizationCodeFlow(authUrl, CLIENT);
|
||||
LoginScreen loginScreen = flow.start(Map.of("scope", "scope1 scope2"));
|
||||
|
||||
Document consentsDoc = login.submit().post();
|
||||
FormElement consents = consentsDoc.expectForm("form");
|
||||
ConsentScreen consentScreen = loginScreen.submitCorrect("bob", "password");
|
||||
assertThat(consentScreen.getScopes(), is(List.of("scope1", "scope2")));
|
||||
|
||||
consents.expectFirst("input[name=scope][value=scope1]");
|
||||
consents.expectFirst("input[name=scope][value=scope2]");
|
||||
Document submit = consentScreen.submit();
|
||||
flow.parseAndValidateRedirect(submit.connection().response());
|
||||
|
||||
Document success = consents.submit().followRedirects(false).post();
|
||||
Connection.Response response = success.connection().response();
|
||||
assertThat(response.statusCode(), is(303));
|
||||
assertThat(response.header("location"), startsWith("https://myserver:8888/success"));
|
||||
assertThat(flow.getCode(), is(notNullValue()));
|
||||
assertThat(flow.getToken(), is(nullValue()));
|
||||
flow.exchangeCode();
|
||||
|
||||
URI location = URI.create(Objects.requireNonNull(response.header("location")));
|
||||
Map<String, String> query = URLEncodedUtils.parse(location.getQuery(), Charset.defaultCharset())
|
||||
.stream().collect(Collectors.toMap(NameValuePair::getName, NameValuePair::getValue));
|
||||
|
||||
assertThat(query.get("state"), is(state));
|
||||
assertThat(query.get("code"), is(notNullValue()));
|
||||
|
||||
given()
|
||||
.formParam("grant_type", "authorization_code")
|
||||
.formParam("client_id", "myclient")
|
||||
.formParam("redirect_uri", "https://myserver:8888/success")
|
||||
.formParam("code", query.get("code"))
|
||||
.when()
|
||||
.post("/auth/token")
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(JSON)
|
||||
.body("token_type", is("Bearer"))
|
||||
.body("expires_in", is(notNullValue()))
|
||||
.body("access_token", is(notNullValue()))
|
||||
.body("refresh_token", is(notNullValue()));
|
||||
assertThat(flow.getToken(), is(notNullValue()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.ysoft.geecon.helpers;
|
||||
|
||||
import com.ysoft.geecon.dto.AccessTokenResponse;
|
||||
import com.ysoft.geecon.dto.OAuthClient;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.jsoup.Connection;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static io.restassured.http.ContentType.JSON;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class AuthorizationCodeFlow {
|
||||
private final String authUrl;
|
||||
private final OAuthClient client;
|
||||
private String state = "testStateIsNotRandom";
|
||||
private String code;
|
||||
private String token;
|
||||
private String idToken;
|
||||
|
||||
public AuthorizationCodeFlow(String authUrl, OAuthClient client) {
|
||||
this.authUrl = authUrl;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public LoginScreen start(Map<String, String> additionalData) throws IOException {
|
||||
var data = defaultQuery();
|
||||
if (additionalData != null) {
|
||||
data.putAll(additionalData);
|
||||
}
|
||||
|
||||
Document login = Jsoup.connect(authUrl)
|
||||
.data(data)
|
||||
.get();
|
||||
|
||||
return new LoginScreen(login);
|
||||
}
|
||||
|
||||
private Map<String, String> defaultQuery() {
|
||||
var map = new HashMap<String, String>();
|
||||
map.put("client_id", client.clientId());
|
||||
map.put("redirect_uri", client.redirectUri());
|
||||
map.put("state", state);
|
||||
return map;
|
||||
}
|
||||
|
||||
public void parseAndValidateRedirect(Connection.Response response) {
|
||||
assertThat(response.statusCode(), is(303));
|
||||
assertThat(response.header("location"), startsWith(client.redirectUri()));
|
||||
|
||||
URI location = URI.create(Objects.requireNonNull(response.header("location")));
|
||||
Map<String, String> query = URLEncodedUtils.parse(location.getQuery(), Charset.defaultCharset())
|
||||
.stream().collect(Collectors.toMap(NameValuePair::getName, NameValuePair::getValue));
|
||||
|
||||
assertThat(query.get("state"), is(state));
|
||||
assertThat(query.get("code"), is(notNullValue()));
|
||||
|
||||
code = query.get("code");
|
||||
token = query.get("token");
|
||||
idToken = query.get("id_token");
|
||||
}
|
||||
|
||||
public AccessTokenResponse exchangeCode() {
|
||||
AccessTokenResponse accessTokenResponse = given()
|
||||
.formParam("grant_type", "authorization_code")
|
||||
.formParam("client_id", client.clientId())
|
||||
.formParam("redirect_uri", client.redirectUri())
|
||||
.formParam("code", code)
|
||||
.when()
|
||||
.post("/auth/token")
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(JSON)
|
||||
.body("token_type", is("Bearer"))
|
||||
.body("expires_in", is(notNullValue()))
|
||||
.body("access_token", is(notNullValue()))
|
||||
.body("refresh_token", is(notNullValue()))
|
||||
.extract().body().as(AccessTokenResponse.class);
|
||||
token = accessTokenResponse.accessToken();
|
||||
idToken = accessTokenResponse.idToken();
|
||||
return accessTokenResponse;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getIdToken() {
|
||||
return idToken;
|
||||
}
|
||||
}
|
||||
27
src/test/java/com/ysoft/geecon/helpers/ConsentScreen.java
Normal file
27
src/test/java/com/ysoft/geecon/helpers/ConsentScreen.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.ysoft.geecon.helpers;
|
||||
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.nodes.FormElement;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class ConsentScreen {
|
||||
|
||||
private final FormElement consents;
|
||||
|
||||
public ConsentScreen(Document document) {
|
||||
consents = document.expectForm("form");
|
||||
}
|
||||
|
||||
public List<String> getScopes() {
|
||||
Elements checkboxes = consents.select("input[name=scope]");
|
||||
return checkboxes.stream().map(Element::val).toList();
|
||||
}
|
||||
|
||||
public Document submit() throws IOException {
|
||||
return consents.submit().followRedirects(false).post();
|
||||
}
|
||||
}
|
||||
33
src/test/java/com/ysoft/geecon/helpers/LoginScreen.java
Normal file
33
src/test/java/com/ysoft/geecon/helpers/LoginScreen.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.ysoft.geecon.helpers;
|
||||
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.FormElement;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class LoginScreen {
|
||||
|
||||
private final FormElement form;
|
||||
|
||||
public LoginScreen(Document doc) {
|
||||
this.form = doc.expectForm("form");
|
||||
;
|
||||
}
|
||||
|
||||
public Document submit(String username, String password) throws IOException {
|
||||
form.getElementsByAttributeValue("name", "username").val(username);
|
||||
form.getElementsByAttributeValue("name", "password").val(password);
|
||||
|
||||
return form.submit().post();
|
||||
}
|
||||
|
||||
public ConsentScreen submitCorrect(String username, String password) throws IOException {
|
||||
Document posted = submit(username, password);
|
||||
return new ConsentScreen(posted);
|
||||
}
|
||||
|
||||
public LoginScreen submitWrong(String username, String password) throws IOException {
|
||||
Document posted = submit(username, password);
|
||||
return new LoginScreen(posted);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user