keycloak-uncached

Merge pull request #3114 from mposolda/master KEYCLOAK-3321

8/5/2016 11:45:56 AM

Changes

Details

diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java
index 188d759..2a7d37b 100644
--- a/core/src/main/java/org/keycloak/OAuth2Constants.java
+++ b/core/src/main/java/org/keycloak/OAuth2Constants.java
@@ -42,6 +42,10 @@ public interface OAuth2Constants {
 
     String RESPONSE_TYPE = "response_type";
 
+    String ACCESS_TOKEN = "access_token";
+
+    String ID_TOKEN = "id_token";
+
     String REFRESH_TOKEN = "refresh_token";
 
     String AUTHORIZATION_CODE = "authorization_code";
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index 95aa9a6..b08d3d8 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -340,6 +340,12 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
             return redirectErrorToClient(parsedResponseMode, OAuthErrorException.REQUEST_URI_NOT_SUPPORTED, null);
         }
 
+        if (parsedResponseType.isImplicitOrHybridFlow() && nonce == null) {
+            logger.missingParameter(OIDCLoginProtocol.NONCE_PARAM);
+            event.error(Errors.INVALID_REQUEST);
+            return redirectErrorToClient(parsedResponseMode, OAuthErrorException.INVALID_REQUEST, "Missing parameter: nonce");
+        }
+
         return null;
     }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index 3105122..8271cc7 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -171,11 +171,11 @@ public class OIDCLoginProtocol implements LoginProtocol {
                     .build();
 
             if (responseType.hasResponseType(OIDCResponseType.ID_TOKEN)) {
-                redirectUri.addParam("id_token", res.getIdToken());
+                redirectUri.addParam(OAuth2Constants.ID_TOKEN, res.getIdToken());
             }
 
             if (responseType.hasResponseType(OIDCResponseType.TOKEN)) {
-                redirectUri.addParam("access_token", res.getToken());
+                redirectUri.addParam(OAuth2Constants.ACCESS_TOKEN, res.getToken());
                 redirectUri.addParam("token_type", res.getTokenType());
                 redirectUri.addParam("session_state", res.getSessionState());
                 redirectUri.addParam("expires_in", String.valueOf(res.getExpiresIn()));
diff --git a/testsuite/integration/src/test/resources/log4j.properties b/testsuite/integration/src/test/resources/log4j.properties
index 327102e..5d5369c 100755
--- a/testsuite/integration/src/test/resources/log4j.properties
+++ b/testsuite/integration/src/test/resources/log4j.properties
@@ -56,6 +56,9 @@ log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=${
 # Enable to view hibernate statistics
 log4j.logger.org.keycloak.connections.jpa.HibernateStatsReporter=debug
 
+# Enable to view ldap logging
+# log4j.logger.org.keycloak.federation.ldap=trace
+
 # Enable to view kerberos/spnego logging
 # log4j.logger.org.keycloak.federation.kerberos=trace
 
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 8c7b290..1d632c1 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
@@ -41,6 +41,7 @@ import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
 import org.keycloak.protocol.oidc.representations.JSONWebKeySet;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.IDToken;
 import org.keycloak.representations.RefreshToken;
@@ -120,7 +121,7 @@ public class OAuthClient {
         maxAge = null;
     }
 
-    public AuthorizationCodeResponse doLogin(String username, String password) {
+    public AuthorizationEndpointResponse doLogin(String username, String password) {
         openLoginForm();
         String src = driver.getPageSource();
         try {
@@ -132,7 +133,7 @@ public class OAuthClient {
             throw t;
         }
 
-        return new AuthorizationCodeResponse(this);
+        return new AuthorizationEndpointResponse(this);
     }
 
     public void doLoginGrant(String username, String password) {
@@ -637,7 +638,7 @@ public class OAuthClient {
         return realm;
     }
 
-    public static class AuthorizationCodeResponse {
+    public static class AuthorizationEndpointResponse {
 
         private boolean isRedirected;
         private String code;
@@ -645,11 +646,25 @@ public class OAuthClient {
         private String error;
         private String errorDescription;
 
-        public AuthorizationCodeResponse(OAuthClient client) {
-            this(client, false);
+        // Just during OIDC implicit or hybrid flow
+        private String accessToken;
+        private String idToken;
+
+        public AuthorizationEndpointResponse(OAuthClient client) {
+            boolean fragment;
+            try {
+                fragment = client.responseType != null && OIDCResponseType.parse(client.responseType).isImplicitOrHybridFlow();
+            } catch (IllegalArgumentException iae) {
+                fragment = false;
+            }
+            init (client, fragment);
+        }
+
+        public AuthorizationEndpointResponse(OAuthClient client, boolean fragment) {
+            init(client, fragment);
         }
 
-        public AuthorizationCodeResponse(OAuthClient client, boolean fragment) {
+        private void init(OAuthClient client, boolean fragment) {
             isRedirected = client.getCurrentRequest().equals(client.getRedirectUri());
             Map<String, String> params = fragment ? client.getCurrentFragment() : client.getCurrentQuery();
 
@@ -657,6 +672,8 @@ public class OAuthClient {
             state = params.get(OAuth2Constants.STATE);
             error = params.get(OAuth2Constants.ERROR);
             errorDescription = params.get(OAuth2Constants.ERROR_DESCRIPTION);
+            accessToken = params.get(OAuth2Constants.ACCESS_TOKEN);
+            idToken = params.get(OAuth2Constants.ID_TOKEN);
         }
 
         public boolean isRedirected() {
@@ -678,6 +695,14 @@ public class OAuthClient {
         public String getErrorDescription() {
             return errorDescription;
         }
+
+        public String getAccessToken() {
+            return accessToken;
+        }
+
+        public String getIdToken() {
+            return idToken;
+        }
     }
 
     public static class AccessTokenResponse {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
index 4e2bdd9..ee06750 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -129,7 +129,7 @@ public class ClientTest extends AbstractAdminTest {
         OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("password", "test-user@localhost", "password");
         assertEquals(200, response.getStatusCode());
 
-        OAuthClient.AuthorizationCodeResponse codeResponse = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse codeResponse = oauth.doLogin("test-user@localhost", "password");
 
         OAuthClient.AccessTokenResponse response2 = oauth.doAccessTokenRequest(codeResponse.getCode(), "password");
         assertEquals(200, response2.getStatusCode());
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 ece81d8..cf69f74 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
@@ -78,7 +78,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
     public void authorizationRequest() throws IOException {
         oauth.state("OpenIdConnect.AuthenticationProperties=2302984sdlk");
 
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertTrue(response.isRedirected());
         Assert.assertNotNull(response.getCode());
@@ -116,7 +116,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
 
         oauth.state("mystate");
 
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertTrue(response.isRedirected());
         Assert.assertNotNull(response.getCode());
@@ -131,7 +131,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
     public void authorizationRequestNoState() throws IOException {
         oauth.state(null);
 
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertTrue(response.isRedirected());
         Assert.assertNotNull(response.getCode());
@@ -150,7 +150,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
         UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
         driver.navigate().to(b.build().toURL());
 
-        OAuthClient.AuthorizationCodeResponse errorResponse = new OAuthClient.AuthorizationCodeResponse(oauth, true);
+        OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, true);
         Assert.assertTrue(errorResponse.isRedirected());
         Assert.assertEquals(errorResponse.getError(), OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE);
         Assert.assertEquals(errorResponse.getErrorDescription(), "Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.");
@@ -164,7 +164,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
         UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
         driver.navigate().to(b.build().toURL());
 
-        OAuthClient.AuthorizationCodeResponse errorResponse = new OAuthClient.AuthorizationCodeResponse(oauth);
+        OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
         Assert.assertTrue(errorResponse.isRedirected());
         Assert.assertEquals(errorResponse.getError(), OAuthErrorException.INVALID_REQUEST);
 
@@ -177,7 +177,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
         UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
         driver.navigate().to(b.build().toURL());
 
-        OAuthClient.AuthorizationCodeResponse errorResponse = new OAuthClient.AuthorizationCodeResponse(oauth);
+        OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
         Assert.assertTrue(errorResponse.isRedirected());
         Assert.assertEquals(errorResponse.getError(), OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE);
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
index 853b38b..f80e789 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
@@ -154,7 +154,7 @@ public class OAuthRedirectUriTest extends AbstractKeycloakTest {
     @Test
     public void testValid() throws IOException {
         oauth.redirectUri(APP_ROOT + "/auth");
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertNotNull(response.getCode());
         URL url = new URL(driver.getCurrentUrl());
@@ -175,7 +175,7 @@ public class OAuthRedirectUriTest extends AbstractKeycloakTest {
     @Test
     public void testWithParams() throws IOException {
         oauth.redirectUri(APP_ROOT + "/auth?key=value");
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertNotNull(response.getCode());
         URL url = new URL(driver.getCurrentUrl());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
index 2296908..191581e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
@@ -47,7 +47,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 /**
- * Test for supporting advanced parameters of OIDC specs (max_age, nonce, prompt, ...)
+ * Test for supporting advanced parameters of OIDC specs (max_age, prompt, ...)
  *
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
@@ -169,7 +169,7 @@ public class OIDCAdvancedRequestParamsTest extends TestRealmKeycloakTest {
         events.assertEmpty();
 
         // Assert error response was sent because not logged in
-        OAuthClient.AuthorizationCodeResponse resp = new OAuthClient.AuthorizationCodeResponse(oauth);
+        OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
         Assert.assertNull(resp.getCode());
         Assert.assertEquals(OAuthErrorException.LOGIN_REQUIRED, resp.getError());
 
@@ -224,7 +224,7 @@ public class OIDCAdvancedRequestParamsTest extends TestRealmKeycloakTest {
             assertTrue(appPage.isCurrent());
             Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
 
-            OAuthClient.AuthorizationCodeResponse resp = new OAuthClient.AuthorizationCodeResponse(oauth);
+            OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
             Assert.assertNull(resp.getCode());
             Assert.assertEquals(OAuthErrorException.INTERACTION_REQUIRED, resp.getError());
 
@@ -242,7 +242,7 @@ public class OIDCAdvancedRequestParamsTest extends TestRealmKeycloakTest {
             driver.navigate().to(oauth.getLoginFormUrl() + "&prompt=none");
             Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
 
-            resp = new OAuthClient.AuthorizationCodeResponse(oauth);
+            resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
             Assert.assertNotNull(resp.getCode());
             Assert.assertNull(resp.getError());
 
@@ -289,37 +289,6 @@ public class OIDCAdvancedRequestParamsTest extends TestRealmKeycloakTest {
 
     }
 
-
-    // NONCE
-
-    @Test
-    public void nonceNotUsed() {
-        driver.navigate().to(oauth.getLoginFormUrl());
-
-        loginPage.assertCurrent();
-        loginPage.login("test-user@localhost", "password");
-        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
-
-        EventRepresentation loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
-        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
-
-        Assert.assertNull(idToken.getNonce());
-    }
-
-    @Test
-    public void nonceMatches() {
-        driver.navigate().to(oauth.getLoginFormUrl() + "&nonce=abcdef123456");
-
-        loginPage.assertCurrent();
-        loginPage.login("test-user@localhost", "password");
-        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
-
-        EventRepresentation loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
-        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
-
-        Assert.assertEquals("abcdef123456", idToken.getNonce());
-    }
-
     // DISPLAY & OTHERS
 
     @Test
@@ -346,7 +315,7 @@ public class OIDCAdvancedRequestParamsTest extends TestRealmKeycloakTest {
         assertTrue(appPage.isCurrent());
 
         // Assert error response was sent because not logged in
-        OAuthClient.AuthorizationCodeResponse resp = new OAuthClient.AuthorizationCodeResponse(oauth);
+        OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
         Assert.assertNull(resp.getCode());
         Assert.assertEquals(OAuthErrorException.REQUEST_NOT_SUPPORTED, resp.getError());
     }
@@ -359,7 +328,7 @@ public class OIDCAdvancedRequestParamsTest extends TestRealmKeycloakTest {
         assertTrue(appPage.isCurrent());
 
         // Assert error response was sent because not logged in
-        OAuthClient.AuthorizationCodeResponse resp = new OAuthClient.AuthorizationCodeResponse(oauth);
+        OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
         Assert.assertNull(resp.getCode());
         Assert.assertEquals(OAuthErrorException.REQUEST_URI_NOT_SUPPORTED, resp.getError());
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/AbstractOIDCResponseTypeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/AbstractOIDCResponseTypeTest.java
new file mode 100644
index 0000000..047a62d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/AbstractOIDCResponseTypeTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.resptype;
+
+import java.util.List;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Rule;
+import org.keycloak.OAuthErrorException;
+import org.keycloak.events.Details;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.TestRealmKeycloakTest;
+import org.keycloak.testsuite.admin.AbstractAdminTest;
+import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.OAuthGrantPage;
+import org.keycloak.testsuite.util.OAuthClient;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Abstract test for various values of response_type
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class AbstractOIDCResponseTypeTest extends TestRealmKeycloakTest {
+
+    @Rule
+    public AssertEvents events = new AssertEvents(this);
+
+    @Page
+    protected AppPage appPage;
+
+    @Page
+    protected LoginPage loginPage;
+
+    @Page
+    protected AccountUpdateProfilePage profilePage;
+
+    @Page
+    protected OAuthGrantPage grantPage;
+
+    @Override
+    public void configureTestRealm(RealmRepresentation testRealm) {
+    }
+
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation realm = AbstractAdminTest.loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+        testRealms.add(realm);
+    }
+
+
+    protected void nonceMatches() {
+        driver.navigate().to(oauth.getLoginFormUrl() + "&nonce=abcdef123456");
+
+        loginPage.assertCurrent();
+        loginPage.login("test-user@localhost", "password");
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        EventRepresentation loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
+        List<IDToken> idTokens = retrieveIDTokens(loginEvent);
+
+        for (IDToken idToken : idTokens) {
+            Assert.assertEquals("abcdef123456", idToken.getNonce());
+        }
+    }
+
+
+    protected void nonceNotUsed() {
+        driver.navigate().to(oauth.getLoginFormUrl());
+
+        loginPage.assertCurrent();
+        loginPage.login("test-user@localhost", "password");
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        EventRepresentation loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
+
+        List<IDToken> idTokens = retrieveIDTokens(loginEvent);
+        for (IDToken idToken : idTokens) {
+            Assert.assertNull(idToken.getNonce());
+        }
+    }
+
+
+    protected void nonceNotUsedErrorExpected() {
+        driver.navigate().to(oauth.getLoginFormUrl());
+
+        assertFalse(loginPage.isCurrent());
+        assertTrue(appPage.isCurrent());
+
+        // Assert error response was sent because not logged in
+        OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
+        Assert.assertNull(resp.getCode());
+        Assert.assertNull(resp.getIdToken());
+        Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, resp.getError());
+        Assert.assertEquals("Missing parameter: nonce", resp.getErrorDescription());
+    }
+
+    protected abstract List<IDToken> retrieveIDTokens(EventRepresentation loginEvent);
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/OIDCBasicResponseTypeCodeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/OIDCBasicResponseTypeCodeTest.java
new file mode 100644
index 0000000..a8f51fb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/OIDCBasicResponseTypeCodeTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.resptype;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.ClientManager;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * Test for response_type=code
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCBasicResponseTypeCodeTest extends AbstractOIDCResponseTypeTest {
+
+    @Before
+    public void clientConfiguration() {
+        ClientManager.realm(adminClient.realm("test")).clientId("test-app").standardFlow(true).implicitFlow(false);
+
+        oauth.clientId("test-app");
+        oauth.responseType(OIDCResponseType.CODE);
+    }
+
+
+    protected List<IDToken> retrieveIDTokens(EventRepresentation loginEvent) {
+        Assert.assertEquals(OIDCResponseType.CODE, loginEvent.getDetails().get(Details.RESPONSE_TYPE));
+
+        OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, false);
+        Assert.assertNull(authzResponse.getAccessToken());
+        Assert.assertNull(authzResponse.getIdToken());
+
+        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
+
+        return Collections.singletonList(idToken);
+    }
+
+
+    @Test
+    public void nonceNotUsed() {
+        super.nonceNotUsed();
+    }
+
+
+    @Test
+    public void nonceMatches() {
+        super.nonceMatches();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/OIDCHybridResponseTypeCodeIDTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/OIDCHybridResponseTypeCodeIDTokenTest.java
new file mode 100644
index 0000000..ff16927
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/OIDCHybridResponseTypeCodeIDTokenTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.resptype;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.ClientManager;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * Tests with response_type=code id_token
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCHybridResponseTypeCodeIDTokenTest extends AbstractOIDCResponseTypeTest {
+
+    @Before
+    public void clientConfiguration() {
+        ClientManager.realm(adminClient.realm("test")).clientId("test-app").standardFlow(true).implicitFlow(true);
+
+        oauth.clientId("test-app");
+        oauth.responseType(OIDCResponseType.CODE + " " + OIDCResponseType.ID_TOKEN);
+    }
+
+
+    protected List<IDToken> retrieveIDTokens(EventRepresentation loginEvent) {
+        Assert.assertEquals(OIDCResponseType.CODE + " " + OIDCResponseType.ID_TOKEN, loginEvent.getDetails().get(Details.RESPONSE_TYPE));
+
+        // IDToken from the authorization response
+        OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, true);
+        Assert.assertNull(authzResponse.getAccessToken());
+        String idTokenStr = authzResponse.getIdToken();
+        IDToken idToken = oauth.verifyIDToken(idTokenStr);
+
+        // IDToken exchanged for the code
+        IDToken idToken2 = sendTokenRequestAndGetIDToken(loginEvent);
+
+        return Arrays.asList(idToken, idToken2);
+    }
+
+
+    @Test
+    public void nonceNotUsedErrorExpected() {
+        super.nonceNotUsedErrorExpected();
+    }
+
+
+    @Test
+    public void nonceMatches() {
+        super.nonceMatches();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/OIDCImplicitResponseTypeIDTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/OIDCImplicitResponseTypeIDTokenTest.java
new file mode 100644
index 0000000..4bcdc65
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/resptype/OIDCImplicitResponseTypeIDTokenTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.resptype;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.ClientManager;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * Tests with response_type=id_token
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCImplicitResponseTypeIDTokenTest extends AbstractOIDCResponseTypeTest {
+
+    @Before
+    public void clientConfiguration() {
+        ClientManager.realm(adminClient.realm("test")).clientId("test-app").standardFlow(false).implicitFlow(true);
+
+        oauth.clientId("test-app");
+        oauth.responseType(OIDCResponseType.ID_TOKEN);
+    }
+
+
+    protected List<IDToken> retrieveIDTokens(EventRepresentation loginEvent) {
+        Assert.assertEquals(OIDCResponseType.ID_TOKEN, loginEvent.getDetails().get(Details.RESPONSE_TYPE));
+
+        OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, true);
+        Assert.assertNull(authzResponse.getAccessToken());
+        String idTokenStr = authzResponse.getIdToken();
+        IDToken idToken = oauth.verifyIDToken(idTokenStr);
+
+        return Collections.singletonList(idToken);
+    }
+
+
+    @Test
+    public void nonceNotUsedErrorExpected() {
+        super.nonceNotUsedErrorExpected();
+    }
+
+
+    @Test
+    public void nonceMatches() {
+        super.nonceMatches();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
index 0e10c58..040bb4c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
@@ -86,7 +86,7 @@ public abstract class TestRealmKeycloakTest extends AbstractKeycloakTest {
         String sessionId = loginEvent.getSessionId();
         String codeId = loginEvent.getDetails().get(Details.CODE_ID);
 
-        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+        String code = new OAuthClient.AuthorizationEndpointResponse(oauth).getCode();
         OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
 
         Assert.assertEquals(200, response.getStatusCode());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
index 6702ec5..6bc7151 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
@@ -67,6 +67,20 @@ public class ClientManager {
             clientResource.update(app);
         }
 
+        public ClientManagerBuilder standardFlow(Boolean enable) {
+            ClientRepresentation app = clientResource.toRepresentation();
+            app.setStandardFlowEnabled(enable);
+            clientResource.update(app);
+            return this;
+        }
+
+        public ClientManagerBuilder implicitFlow(Boolean enable) {
+            ClientRepresentation app = clientResource.toRepresentation();
+            app.setImplicitFlowEnabled(enable);
+            clientResource.update(app);
+            return this;
+        }
+
         public void fullScopeAllowed(boolean enable) {
             ClientRepresentation app = clientResource.toRepresentation();
             app.setFullScopeAllowed(enable);