KEYCLOAK-3321 OIDC requests without 'nonce' claim should be rejected unless using the code flow. Started responseType tests

This commit is contained in:
mposolda 2016-08-05 13:08:05 +02:00
parent 6a797a61a9
commit e0a59baaf2
15 changed files with 419 additions and 55 deletions

View file

@ -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";

View file

@ -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()));

View file

@ -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;
}

View file

@ -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 AuthorizationCodeResponse(OAuthClient client, boolean fragment) {
public AuthorizationEndpointResponse(OAuthClient client, boolean fragment) {
init(client, 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 {

View file

@ -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());

View file

@ -128,7 +128,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());

View file

@ -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);

View file

@ -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());

View file

@ -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());
}

View file

@ -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);
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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