Skip to content

Commit

Permalink
Event listener for temporary admin account logging
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Zaoral <[email protected]>
  • Loading branch information
Pepo48 committed Aug 9, 2024
1 parent d6bae4b commit e617ef4
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -767,10 +767,12 @@ export default class RealmSettingsPage extends CommonPage {
}

shouldRemoveAllEventListeners() {
cy.get(".pf-v5-c-chip__actions").first().click();
cy.get(".pf-v5-c-chip__actions").first().click();
cy.get(".pf-v5-c-chip__actions").click();
cy.findByTestId(this.#eventListenersSaveBtn).click();
cy.get(this.#eventListenersDrpDwn).should("not.have.text", "jboss-logging");
cy.get(this.#eventListenersDrpDwn).should("not.have.text", "temp-admin-account");

Check failure on line 775 in js/apps/admin-ui/cypress/support/pages/admin-ui/manage/realm_settings/RealmSettingsPage.ts

View workflow job for this annotation

GitHub Actions / Admin UI

Replace `"not.have.text",·"temp-admin-account"` with `⏎······"not.have.text",⏎······"temp-admin-account",⏎····`
cy.get(this.#eventListenersDrpDwn).should("not.have.text", "email");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.keycloak.events.log;

import org.jboss.logging.Logger;
import org.keycloak.events.Event;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.EventType;
import org.keycloak.events.admin.AdminEvent;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.UserModel;

import static org.keycloak.services.managers.ApplianceBootstrap.TEMP_ADMIN_ATTR_NAME;

public class TemporaryAdminAccountEventListenerProvider implements EventListenerProvider {

private static final Logger log = Logger.getLogger(TemporaryAdminAccountEventListenerProvider.class);

private final KeycloakSession session;
private final RealmProvider realmModel;

public TemporaryAdminAccountEventListenerProvider(KeycloakSession session) {
this.session = session;
this.realmModel = session.realms();
}

@Override
public void onEvent(Event event) {
RealmModel realm = this.realmModel.getRealm(event.getRealmId());
UserModel user = this.session.users().getUserById(realm, event.getUserId());
ClientModel client = this.session.clients().getClientByClientId(realm, event.getClientId());

if (EventType.LOGIN.equals(event.getType()) && Boolean.parseBoolean(user.getFirstAttribute(TEMP_ADMIN_ATTR_NAME))) {
log.warn(user.getUsername() + " is a temporary admin user account. To harden security, create a permanent account and delete the temporary one.");
}

if (EventType.CLIENT_LOGIN.equals(event.getType()) && Boolean.parseBoolean(client.getAttribute(TEMP_ADMIN_ATTR_NAME))) {
log.warn(client.getClientId() + " is a temporary admin service account. To harden security, create a permanent account and delete the temporary one.");
}
}

@Override
public void onEvent(AdminEvent adminEvent, boolean b) {
}

@Override
public void close() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.keycloak.events.log;

import org.keycloak.Config;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.events.EventListenerProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;

public class TemporaryAdminAccountEventListenerProviderFactory implements EventListenerProviderFactory {

public static final String ID = "temp-admin-account";

@Override
public EventListenerProvider create(KeycloakSession keycloakSession) {
return new TemporaryAdminAccountEventListenerProvider(keycloakSession);
}

@Override
public void init(Config.Scope scope) {

}

@Override
public void postInit(KeycloakSessionFactory keycloakSessionFactory) {

}

@Override
public void close() {

}

@Override
public String getId() {
return ID;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.keycloak.utils.ReservedCharValidator;
import org.keycloak.utils.StringUtil;

Expand Down Expand Up @@ -261,7 +263,7 @@ protected void setupRealmDefaults(RealmModel realm) {
realm.setOTPPolicy(OTPPolicy.DEFAULT_POLICY);
realm.setLoginWithEmailAllowed(true);

realm.setEventsListeners(Collections.singleton("jboss-logging"));
realm.setEventsListeners(Set.of("jboss-logging", "temp-admin-account"));
}

public boolean removeRealm(RealmModel realm) {
Expand Down Expand Up @@ -644,7 +646,7 @@ protected void rollbackImpl() {
}

private String determineDefaultRoleName(RealmRepresentation rep) {
String defaultRoleName = Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + rep.getRealm().toLowerCase();
String defaultRoleName = Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + rep.getRealm().toLowerCase();
if (! hasRealmRole(rep, defaultRoleName)) {
return defaultRoleName;
} else {
Expand Down Expand Up @@ -778,7 +780,7 @@ public void setupClientServiceAccountsAndAuthorizationOnImport(RealmRepresentati
ClientModel clientModel = Optional.ofNullable(client.getId())
.map(realmModel::getClientById)
.orElseGet(() -> realmModel.getClientByClientId(client.getClientId()));

if (clientModel == null) {
throw new RuntimeException("Cannot find provided client by dir import.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@
#

org.keycloak.events.email.EmailEventListenerProviderFactory
org.keycloak.events.log.JBossLoggingEventListenerProviderFactory
org.keycloak.events.log.JBossLoggingEventListenerProviderFactory
org.keycloak.events.log.TemporaryAdminAccountEventListenerProviderFactory
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ public void defaultEventConfigTest() {
assertFalse(configRep.isEventsEnabled());

List<String> eventListeners = configRep.getEventsListeners();
assertEquals(1, eventListeners.size());
assertEquals("jboss-logging", eventListeners.get(0));
assertEquals(2, eventListeners.size());
assertTrue(eventListeners.containsAll(Arrays.asList("jboss-logging", "temp-admin-account")));
}

@Test
Expand Down

0 comments on commit e617ef4

Please sign in to comment.