KEYCLOAK-13682 NPE when refreshing token after enabling consent

This commit is contained in:
Martin Kanis 2020-04-29 14:14:28 +02:00 committed by Stian Thorgersen
parent a878bec60f
commit aa309b96a8
2 changed files with 52 additions and 1 deletions

View file

@ -570,7 +570,7 @@ public class TokenManager {
continue; continue;
} }
if (!grantedConsent.getGrantedClientScopes().contains(requestedScope)) { if (grantedConsent == null || !grantedConsent.getGrantedClientScopes().contains(requestedScope)) {
logger.debugf("Client '%s' no longer has requested consent from user '%s' for client scope '%s'", logger.debugf("Client '%s' no longer has requested consent from user '%s' for client scope '%s'",
client.getClientId(), user.getUsername(), requestedScope.getName()); client.getClientId(), user.getUsername(), requestedScope.getName());
return false; return false;

View file

@ -20,18 +20,26 @@ package org.keycloak.testsuite.admin;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.UserResource; import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource; import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation; import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.ConsentPage; import org.keycloak.testsuite.pages.ConsentPage;
import org.keycloak.testsuite.pages.ErrorPage; import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
@ -41,11 +49,15 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.keycloak.testsuite.AbstractTestRealmKeycloakTest.TEST_REALM_NAME;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient; import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
import static org.keycloak.testsuite.admin.ApiUtil.findClientByClientId; import static org.keycloak.testsuite.admin.ApiUtil.findClientByClientId;
import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword; import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
import org.keycloak.testsuite.util.OAuthClient.AccessTokenResponse;
import org.keycloak.testsuite.util.OAuthClient.AuthorizationEndpointResponse;
/** /**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a> * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
@ -149,6 +161,8 @@ public class ConsentsTest extends AbstractKeycloakTest {
return IDP_OIDC_ALIAS; return IDP_OIDC_ALIAS;
} }
@Rule
public AssertEvents events = new AssertEvents(this);
@Page @Page
protected LoginPage accountLoginPage; protected LoginPage accountLoginPage;
@ -156,6 +170,9 @@ public class ConsentsTest extends AbstractKeycloakTest {
@Page @Page
protected ConsentPage consentPage; protected ConsentPage consentPage;
@Page
protected AppPage appPage;
@Page @Page
protected ErrorPage errorPage; protected ErrorPage errorPage;
@ -163,9 +180,11 @@ public class ConsentsTest extends AbstractKeycloakTest {
public void addTestRealms(List<RealmRepresentation> testRealms) { public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation providerRealm = createProviderRealm(); RealmRepresentation providerRealm = createProviderRealm();
RealmRepresentation consumerRealm = createConsumerRealm(); RealmRepresentation consumerRealm = createConsumerRealm();
RealmRepresentation realmRepresentation = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
testRealms.add(providerRealm); testRealms.add(providerRealm);
testRealms.add(consumerRealm); testRealms.add(consumerRealm);
testRealms.add(realmRepresentation);
} }
@Before @Before
@ -347,6 +366,38 @@ public class ConsentsTest extends AbstractKeycloakTest {
accountPage.assertCurrent(); accountPage.assertCurrent();
} }
@Test
public void clientConsentRequiredAfterLogin() {
oauth.realm(TEST_REALM_NAME).clientId("test-app");
AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(response.getCode(), "password");
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
EventRepresentation loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
String sessionId = loginEvent.getSessionId();
ClientRepresentation clientRepresentation = adminClient.realm(TEST_REALM_NAME).clients().findByClientId("test-app").get(0);
try {
clientRepresentation.setConsentRequired(true);
adminClient.realm(TEST_REALM_NAME).clients().get(clientRepresentation.getId()).update(clientRepresentation);
events.clear();
// try to refresh the token
// this fails as client no longer has requested consent from user
AccessTokenResponse refreshTokenResponse = oauth.doRefreshTokenRequest(accessTokenResponse.getRefreshToken(), "password");
Assert.assertEquals(OAuthErrorException.INVALID_SCOPE, refreshTokenResponse.getError());
Assert.assertEquals("Client no longer has requested consent from user", refreshTokenResponse.getErrorDescription());
events.expectRefresh(accessTokenResponse.getRefreshToken(), sessionId).clearDetails().error(Errors.INVALID_TOKEN).assertEvent();
} finally {
clientRepresentation.setConsentRequired(false);
adminClient.realm(TEST_REALM_NAME).clients().get(clientRepresentation.getId()).update(clientRepresentation);
}
}
private String getAccountUrl(String realmName) { private String getAccountUrl(String realmName) {
return getAuthRoot() + "/auth/realms/" + realmName + "/account"; return getAuthRoot() + "/auth/realms/" + realmName + "/account";
} }