'state' is optional

This commit is contained in:
Dusan Jakub
2023-10-11 16:17:47 +02:00
parent d7d2b94dea
commit 48ab035574
4 changed files with 41 additions and 8 deletions

View File

@@ -10,7 +10,6 @@ import com.ysoft.geecon.repo.SessionsRepo;
import com.ysoft.geecon.repo.UsersRepo;
import io.quarkus.qute.CheckedTemplate;
import io.quarkus.qute.TemplateInstance;
import io.quarkus.runtime.util.StringUtil;
import io.quarkus.security.webauthn.WebAuthnLoginResponse;
import io.quarkus.security.webauthn.WebAuthnRegisterResponse;
import io.quarkus.security.webauthn.WebAuthnSecurity;
@@ -153,9 +152,11 @@ public class OAuthResource {
var responseTypes = session.params().getResponseTypes();
UriBuilder uri = UriBuilder.fromUri(redirectUri)
.fragment("")
.queryParam("state", session.params().getState());
.fragment("");
if (StringUtils.isNotBlank(session.params().getState())) {
uri.queryParam("state", session.params().getState());
}
if (responseTypes.contains(AuthParams.ResponseType.code)) {
uri.queryParam("code", sessionsRepo.generateAuthorizationCode(sessionId));
}
@@ -263,9 +264,10 @@ public class OAuthResource {
// must NOT redirect to invalid redirect URI
throw new OAuthUserVisibleException(ErrorResponse.Error.invalid_request, "Invalid redirect URI");
}
if (StringUtil.isNullOrEmpty(params.getState())) {
throw new OAuthRedirectException(params, ErrorResponse.Error.invalid_request, "Missing state");
}
// state is optional
// if (StringUtil.isNullOrEmpty(params.getState())) {
// throw new OAuthRedirectException(params, ErrorResponse.Error.invalid_request, "Missing state");
// }
if (!params.validateResponseType()) {
throw new OAuthRedirectException(params, ErrorResponse.Error.unsupported_response_type,
"Unsupported response type");

View File

@@ -3,6 +3,7 @@ package com.ysoft.geecon.error;
import com.ysoft.geecon.dto.AuthParams;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import org.apache.commons.lang3.StringUtils;
public class OAuthRedirectException extends OAuthApiException {
private final AuthParams authParams;
@@ -19,9 +20,11 @@ public class OAuthRedirectException extends OAuthApiException {
public Response getResponse() {
UriBuilder uri = UriBuilder.fromUri(authParams.getRedirectUri())
.fragment("")
.queryParam("state", authParams.getState())
.queryParam("error", response.error())
.queryParam("error_description", response.description());
if (StringUtils.isNotBlank(authParams.getState())) {
uri.queryParam("state", authParams.getState());
}
return Response.seeOther(uri.build()).build();
}
}

View File

@@ -59,6 +59,26 @@ public class AuthCodeGrantTest {
assertThat(accessTokenResponse.accessToken(), is(notNullValue()));
}
@Test
public void authCodeGrant_stateIsOptional() throws IOException {
AuthorizationCodeFlow flow = new AuthorizationCodeFlow(authUrl, CLIENT)
.state(null)
.scope("scope1 scope2");
LoginScreen loginScreen = flow.start().expectLogin();
ConsentScreen consentScreen = loginScreen.submit("bob", "password").expectSuccess();
assertThat(consentScreen.getScopes(), is(List.of("scope1", "scope2")));
Document submit = consentScreen.submit();
flow.expectSuccessfulRedirect(submit.connection().response());
assertThat(flow.getCode(), is(notNullValue()));
assertThat(flow.getAccessToken(), is(nullValue()));
AccessTokenResponse accessTokenResponse = flow.exchangeCode().expectTokens();
assertThat(accessTokenResponse.accessToken(), is(notNullValue()));
}
@Test
public void badCredentials() throws IOException {
AuthorizationCodeFlow flow = new AuthorizationCodeFlow(authUrl, CLIENT)

View File

@@ -37,7 +37,11 @@ public class AuthorizationCodeFlow {
query = new HashMap<>();
query.put("client_id", client.clientId());
query.put("redirect_uri", client.redirectUris().get(0));
query.put("state", state);
}
public AuthorizationCodeFlow state(String state) {
this.state = state;
return this;
}
public AuthorizationCodeFlow param(String key, String value) {
@@ -46,6 +50,10 @@ public class AuthorizationCodeFlow {
}
public Result start() throws IOException {
if (state != null) {
query.put("state", state);
}
Document document = Jsoup.connect(authUrl)
.followRedirects(false)
.data(query)