diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java index d09bc47bb1..95de1b9b96 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java @@ -125,7 +125,7 @@ public abstract class OIDCRedirectUriBuilder { @Override public OIDCRedirectUriBuilder addParam(String paramName, String paramValue) { - params.put(paramName, Encode.encodeQueryParam(paramValue)); + params.put(paramName, paramValue); return this; } diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java index f75d93c68c..bc63c99f70 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java @@ -17,6 +17,8 @@ package org.keycloak.testsuite.rest; +import org.jboss.resteasy.spi.HttpRequest; +import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.jose.jws.JWSInput; import org.keycloak.jose.jws.JWSInputException; import org.keycloak.models.KeycloakSession; @@ -25,7 +27,6 @@ import org.keycloak.representations.adapters.action.PushNotBeforeAction; import org.keycloak.representations.adapters.action.TestAvailabilityAction; import org.keycloak.services.resource.RealmResourceProvider; import org.keycloak.services.resources.RealmsResource; -import org.keycloak.testsuite.events.EventsListenerProvider; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -34,8 +35,10 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; + import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; @@ -110,6 +113,35 @@ public class TestApplicationResourceProvider implements RealmResourceProvider { return Response.noContent().build(); } + @POST + @Produces(MediaType.TEXT_HTML) + @Path("/{action}") + public String post(@PathParam("action") String action) { + String title = "APP_REQUEST"; + if (action.equals("auth")) { + title = "AUTH_RESPONSE"; + } else if (action.equals("logout")) { + title = "LOGOUT_REQUEST"; + } + + StringBuilder sb = new StringBuilder(); + sb.append("" + title + ""); + + sb.append("Form parameters:
"); + HttpRequest request = ResteasyProviderFactory.getContextData(HttpRequest.class); + MultivaluedMap formParams = request.getDecodedFormParameters(); + for (String paramName : formParams.keySet()) { + sb.append(paramName).append(": ").append("").append(formParams.getFirst(paramName)).append("
"); + } + sb.append("
"); + + UriBuilder base = UriBuilder.fromUri("http://localhost:8180/auth"); + sb.append("account"); + + sb.append(""); + return sb.toString(); + } + @GET @Produces(MediaType.TEXT_HTML) @Path("/{action}") diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java index cbfcc5beba..be9127dc9d 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java @@ -36,9 +36,6 @@ import org.keycloak.admin.client.Keycloak; import org.keycloak.common.VerificationException; import org.keycloak.common.util.PemUtils; import org.keycloak.constants.AdapterConstants; -import org.keycloak.jose.jwk.JWK; -import org.keycloak.jose.jwk.JWKBuilder; -import org.keycloak.jose.jwk.JWKParser; import org.keycloak.jose.jws.JWSInput; import org.keycloak.jose.jws.crypto.RSAProvider; import org.keycloak.protocol.oidc.OIDCLoginProtocol; @@ -99,6 +96,10 @@ public class OAuthClient { private String maxAge; + private String responseType = OAuth2Constants.CODE; + + private String responseMode; + private Map publicKeys = new HashMap<>(); public void init(Keycloak adminClient, WebDriver driver) { @@ -486,7 +487,12 @@ public class OAuthClient { public String getLoginFormUrl() { UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(AUTH_SERVER_ROOT)); - b.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE); + if (responseType != null) { + b.queryParam(OAuth2Constants.RESPONSE_TYPE, responseType); + } + if (responseMode != null) { + b.queryParam(OIDCLoginProtocol.RESPONSE_MODE_PARAM, responseMode); + } if (clientId != null) { b.queryParam(OAuth2Constants.CLIENT_ID, clientId); } @@ -598,6 +604,16 @@ public class OAuthClient { return this; } + public OAuthClient responseType(String responseType) { + this.responseType = responseType; + return this; + } + + public OAuthClient responseMode(String responseMode) { + this.responseMode = responseMode; + return this; + } + public String getRealm() { return realm; } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java index 3fc08b4640..a5082c5217 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java @@ -18,12 +18,14 @@ package org.keycloak.testsuite.oauth; import org.jboss.arquillian.graphene.page.Page; import org.junit.Assert; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.keycloak.OAuth2Constants; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.models.Constants; +import org.keycloak.protocol.oidc.utils.OIDCResponseMode; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AssertEvents; @@ -65,15 +67,21 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest { } + @Before + public void clientConfiguration() { + oauth.responseType(OAuth2Constants.CODE); + oauth.responseMode(null); + } + @Test public void authorizationRequest() throws IOException { - oauth.state("mystate"); + oauth.state("OpenIdConnect.AuthenticationProperties=2302984sdlk"); OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password"); Assert.assertTrue(response.isRedirected()); Assert.assertNotNull(response.getCode()); - assertEquals("mystate", response.getState()); + assertEquals("OpenIdConnect.AuthenticationProperties=2302984sdlk", response.getState()); Assert.assertNull(response.getError()); testingClient.testing().verifyCode("test", response.getCode()); @@ -137,8 +145,8 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest { @Test public void authorizationRequestImplicitFlowDisabled() throws IOException { + oauth.responseType("token id_token"); UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl()); - b.replaceQueryParam(OAuth2Constants.RESPONSE_TYPE, "token id_token"); driver.navigate().to(b.build().toURL()); assertEquals("Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.", errorPage.getError()); events.expectLogin().error(Errors.NOT_ALLOWED).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "token id_token").assertEvent(); @@ -146,13 +154,33 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest { @Test public void authorizationRequestInvalidResponseType() throws IOException { + oauth.responseType("tokenn"); UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl()); - b.replaceQueryParam(OAuth2Constants.RESPONSE_TYPE, "tokenn"); driver.navigate().to(b.build().toURL()); assertEquals("Invalid parameter: response_type", errorPage.getError()); events.expectLogin().error(Errors.INVALID_REQUEST).client((String) null).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "tokenn").assertEvent(); } + // KEYCLOAK-3281 + @Test + public void authorizationRequestFormPostResponseMode() throws IOException { + oauth.responseMode(OIDCResponseMode.FORM_POST.toString().toLowerCase()); + oauth.state("OpenIdConnect.AuthenticationProperties=2302984sdlk"); + oauth.doLoginGrant("test-user@localhost", "password"); + + String sources = driver.getPageSource(); + System.out.println(sources); + + String code = driver.findElement(By.id("code")).getText(); + String state = driver.findElement(By.id("state")).getText(); + + assertEquals("OpenIdConnect.AuthenticationProperties=2302984sdlk", state); + + testingClient.testing().verifyCode("test", code); + String codeId = events.expectLogin().assertEvent().getDetails().get(Details.CODE_ID); + assertCode(codeId, code); + } + private void assertCode(String expectedCodeId, String actualCode) { String code = testingClient.testing().verifyCode("test", actualCode); assertEquals(expectedCodeId, code);