KEYCLOAK-3321 OIDC requests without 'nonce' claim should be rejected unless using the code flow. Started responseType tests
This commit is contained in:
parent
6a797a61a9
commit
e0a59baaf2
15 changed files with 419 additions and 55 deletions
|
@ -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";
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue