Details
diff --git a/events/api/src/main/java/org/keycloak/events/Details.java b/events/api/src/main/java/org/keycloak/events/Details.java
index 1a9c479..4a0a1ad 100755
--- a/events/api/src/main/java/org/keycloak/events/Details.java
+++ b/events/api/src/main/java/org/keycloak/events/Details.java
@@ -27,4 +27,9 @@ public interface Details {
String CLIENT_SESSION_STATE = "client_session_state";
String CLIENT_SESSION_HOST = "client_session_host";
+ String CONSENT = "consent";
+ String CONSENT_VALUE_NO_CONSENT_REQUIRED = "no_consent_required"; // No consent is required by client
+ String CONSENT_VALUE_CONSENT_GRANTED = "consent_granted"; // Consent granted by user
+ String CONSENT_VALUE_PERSISTED_CONSENT = "persistent_consent"; // Persistent consent used (was already granted by user before)
+
}
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index e76ab3a..f200130 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -465,7 +465,6 @@ public class AuthenticationManager {
}
if (client.isConsentRequired()) {
- accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT);
UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
@@ -496,11 +495,18 @@ public class AuthenticationManager {
// Skip grant screen if everything was already approved by this user
if (realmRoles.size() > 0 || resourceRoles.size() > 0 || protocolMappers.size() > 0) {
+ accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT);
+
return session.getProvider(LoginFormsProvider.class)
.setClientSessionCode(accessCode.getCode())
.setAccessRequest(realmRoles, resourceRoles, protocolMappers)
.createOAuthGrant(clientSession);
+ } else {
+ String consentDetail = (grantedConsent != null) ? Details.CONSENT_VALUE_PERSISTED_CONSENT : Details.CONSENT_VALUE_NO_CONSENT_REQUIRED;
+ event.detail(Details.CONSENT, consentDetail);
}
+ } else {
+ event.detail(Details.CONSENT, Details.CONSENT_VALUE_NO_CONSENT_REQUIRED);
}
event.success();
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index c2571d9..08a05c9 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -316,7 +316,7 @@ public class LoginActionsService {
return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
}
if (!client.isEnabled()) {
- event.error(Errors.CLIENT_NOT_FOUND);
+ event.error(Errors.CLIENT_DISABLED);
return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
}
@@ -443,7 +443,7 @@ public class LoginActionsService {
return ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
}
if (!client.isEnabled()) {
- event.error(Errors.CLIENT_NOT_FOUND);
+ event.error(Errors.CLIENT_DISABLED);
return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
}
@@ -741,6 +741,7 @@ public class LoginActionsService {
}
user.updateConsent(grantedConsent);
+ event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED);
event.success();
return authManager.redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, clientConnection);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index 0f1eba1..4fafbb3 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -242,7 +242,9 @@ public class AccountTest {
Assert.assertEquals("Invalid username or password.", loginPage.getError());
- events.expectLogin().session((String) null).error("invalid_user_credentials").assertEvent();
+ events.expectLogin().session((String) null).error("invalid_user_credentials")
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
loginPage.open();
loginPage.login("test-user@localhost", "new-password");
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
index ce80527..21e5190 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -113,7 +113,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
}
public ExpectedEvent expectRequiredAction(EventType event) {
- return expectLogin().event(event).session(isUUID());
+ return expectLogin().event(event).removeDetail(Details.CONSENT).session(isUUID());
}
public ExpectedEvent expectLogin() {
@@ -123,6 +123,7 @@ public class AssertEvents implements TestRule, EventListenerProviderFactory {
.detail(Details.RESPONSE_TYPE, "code")
.detail(Details.AUTH_METHOD, "form")
.detail(Details.REDIRECT_URI, DEFAULT_REDIRECT_URI)
+ .detail(Details.CONSENT, Details.CONSENT_VALUE_NO_CONSENT_REQUIRED)
.session(isUUID());
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
index 644fff3..03da92f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
@@ -127,7 +127,10 @@ public class LoginTest {
Assert.assertEquals("Invalid username or password.", loginPage.getError());
- events.expectLogin().user(userId).session((String) null).error("invalid_user_credentials").detail(Details.USERNAME, "login-test").assertEvent();
+ events.expectLogin().user(userId).session((String) null).error("invalid_user_credentials")
+ .detail(Details.USERNAME, "login-test")
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
}
@Test
@@ -147,7 +150,10 @@ public class LoginTest {
Assert.assertEquals("Invalid username or password.", loginPage.getError());
- events.expectLogin().user(userId).session((String) null).error("invalid_user_credentials").detail(Details.USERNAME, "login-test").assertEvent();
+ events.expectLogin().user(userId).session((String) null).error("invalid_user_credentials")
+ .detail(Details.USERNAME, "login-test")
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
} finally {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
@Override
@@ -175,7 +181,10 @@ public class LoginTest {
Assert.assertEquals("Account is disabled, contact admin.", loginPage.getError());
- events.expectLogin().user(userId).session((String) null).error("user_disabled").detail(Details.USERNAME, "login-test").assertEvent();
+ events.expectLogin().user(userId).session((String) null).error("user_disabled")
+ .detail(Details.USERNAME, "login-test")
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
} finally {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
@Override
@@ -195,7 +204,10 @@ public class LoginTest {
Assert.assertEquals("Invalid username or password.", loginPage.getError());
- events.expectLogin().user((String) null).session((String) null).error("user_not_found").detail(Details.USERNAME, "invalid").assertEvent();
+ events.expectLogin().user((String) null).session((String) null).error("user_not_found")
+ .detail(Details.USERNAME, "invalid")
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
}
@Test
@@ -413,7 +425,10 @@ public class LoginTest {
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
Assert.assertEquals("access_denied", oauth.getCurrentQuery().get(OAuth2Constants.ERROR));
- events.expectLogin().error("rejected_by_user").user((String) null).session((String) null).removeDetail(Details.USERNAME).assertEvent();
+ events.expectLogin().error("rejected_by_user").user((String) null).session((String) null)
+ .removeDetail(Details.USERNAME)
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
}
// KEYCLOAK-1037
@@ -427,7 +442,10 @@ public class LoginTest {
loginPage.assertCurrent();
Assert.assertEquals("Login timeout. Please login again.", loginPage.getError());
- events.expectLogin().user((String) null).session((String) null).error("expired_code").clearDetails().detail(Details.CODE_ID, AssertEvents.isCodeId()).assertEvent();
+ events.expectLogin().user((String) null).session((String) null).error("expired_code").clearDetails()
+ .detail(Details.CODE_ID, AssertEvents.isCodeId())
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
} finally {
Time.setOffset(0);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
index 45795da..8eea530 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
@@ -114,7 +114,9 @@ public class LoginTotpTest {
loginPage.assertCurrent();
Assert.assertEquals("Invalid username or password.", loginPage.getError());
- events.expectLogin().error("invalid_user_credentials").session((String) null).assertEvent();
+ events.expectLogin().error("invalid_user_credentials").session((String) null)
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
}
@Test
@@ -140,7 +142,9 @@ public class LoginTotpTest {
Assert.assertEquals("Invalid username or password.", loginPage.getError());
- events.expectLogin().error("invalid_user_credentials").session((String) null).assertEvent();
+ events.expectLogin().error("invalid_user_credentials").session((String) null)
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
}
@Test
@@ -159,7 +163,8 @@ public class LoginTotpTest {
Assert.assertEquals("Invalid username or password.", loginPage.getError());
AssertEvents.ExpectedEvent expectedEvent = events.expectLogin().error("invalid_user_credentials")
- .session((String) null);
+ .session((String) null)
+ .removeDetail(Details.CONSENT);
expectedEvent.assertEvent();
} finally {
Time.setOffset(0);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
index 0a70da0..784318f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
@@ -141,6 +141,7 @@ public class AuthorizationCodeTest {
events.expectLogin().error("rejected_by_user").user((String) null).session((String) null)
.removeDetail(Details.USERNAME)
+ .removeDetail(Details.CONSENT)
.detail(Details.REDIRECT_URI, "http://localhost:8081/auth/realms/test/protocol/openid-connect/oauth/oob")
.assertEvent().getDetails().get(Details.CODE_ID);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
index 939231f..bfff4bd 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
@@ -36,7 +36,6 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.managers.RealmManager;
@@ -51,7 +50,6 @@ import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
-import java.io.IOException;
import java.util.Map;
import static org.junit.Assert.assertEquals;
@@ -104,7 +102,10 @@ public class OAuthGrantTest {
Assert.assertTrue(oauth.getCurrentQuery().containsKey(OAuth2Constants.CODE));
- Event loginEvent = events.expectLogin().client("third-party").assertEvent();
+ Event loginEvent = events.expectLogin()
+ .client("third-party")
+ .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+ .assertEvent();
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
String sessionId = loginEvent.getSessionId();
@@ -147,7 +148,11 @@ public class OAuthGrantTest {
Assert.assertTrue(oauth.getCurrentQuery().containsKey(OAuth2Constants.ERROR));
assertEquals("access_denied", oauth.getCurrentQuery().get(OAuth2Constants.ERROR));
- events.expectLogin().client("third-party").error("rejected_by_user").assertEvent();
+ events.expectLogin()
+ .client("third-party")
+ .error("rejected_by_user")
+ .removeDetail(Details.CONSENT)
+ .assertEvent();
}
@Test
@@ -159,7 +164,10 @@ public class OAuthGrantTest {
grantPage.assertCurrent();
grantPage.accept();
- events.expectLogin().client("third-party").assertEvent();
+ events.expectLogin()
+ .client("third-party")
+ .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+ .assertEvent();
// Assert permissions granted on Account mgmt. applications page
accountAppsPage.open();
@@ -172,7 +180,11 @@ public class OAuthGrantTest {
// Open login form and assert grantPage not shown
oauth.openLoginForm();
appPage.assertCurrent();
- events.expectLogin().detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).client("third-party").assertEvent();
+ events.expectLogin()
+ .detail(Details.AUTH_METHOD, "sso")
+ .detail(Details.CONSENT, Details.CONSENT_VALUE_PERSISTED_CONSENT)
+ .removeDetail(Details.USERNAME)
+ .client("third-party").assertEvent();
// Revoke grant in account mgmt.
accountAppsPage.open();
@@ -219,7 +231,10 @@ public class OAuthGrantTest {
// Confirm grant page
grantPage.assertCurrent();
grantPage.accept();
- events.expectLogin().client("third-party").assertEvent();
+ events.expectLogin()
+ .client("third-party")
+ .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+ .assertEvent();
// Assert new role and protocol mapper not in account mgmt.
accountAppsPage.open();
@@ -235,7 +250,10 @@ public class OAuthGrantTest {
Assert.assertTrue(driver.getPageSource().contains("new-role"));
Assert.assertTrue(driver.getPageSource().contains(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME));
grantPage.accept();
- events.expectLogin().client("third-party").assertEvent();
+ events.expectLogin()
+ .client("third-party")
+ .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+ .assertEvent();
// Go to account mgmt. Everything is granted now
accountAppsPage.open();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
index 59ba8aa..23d2e5e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
@@ -93,6 +93,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
.detail(Details.USERNAME, login)
.removeDetail(Details.CODE_ID)
.removeDetail(Details.REDIRECT_URI)
+ .removeDetail(Details.CONSENT)
.assertEvent();
assertEquals(accessToken.getSessionState(), refreshToken.getSessionState());
@@ -128,6 +129,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
.removeDetail(Details.CODE_ID)
.removeDetail(Details.REDIRECT_URI)
+ .removeDetail(Details.CONSENT)
.assertEvent();
HttpResponse logoutResponse = oauth.doLogout(response.getRefreshToken(), "secret");
@@ -180,6 +182,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
.detail(Details.RESPONSE_TYPE, "token")
.removeDetail(Details.CODE_ID)
.removeDetail(Details.REDIRECT_URI)
+ .removeDetail(Details.CONSENT)
.error(Errors.INVALID_USER_CREDENTIALS)
.assertEvent();
}
@@ -203,6 +206,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
.detail(Details.USERNAME, "invalid")
.removeDetail(Details.CODE_ID)
.removeDetail(Details.REDIRECT_URI)
+ .removeDetail(Details.CONSENT)
.error(Errors.INVALID_USER_CREDENTIALS)
.assertEvent();
}