Forked from thomasdarimont/LoginStatsRecordingRequiredActionProvider.java
Created
October 8, 2020 19:50
-
-
Save pimtel/104a0eef3e4ef18189757c043a4addaf to your computer and use it in GitHub Desktop.
Keycloak RequiredAction for recording user information on login
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# manual installation via jboss-cli | |
# idm login recording action | |
module add --name=de.tdlabs.idm.keycloak.idm-keycloak-ext-login-action \ | |
--resources=/tmp/idm-keycloak-ext-login-action.jar \ | |
--dependencies=org.keycloak.keycloak-common,org.keycloak.keycloak-core,org.keycloak.keycloak-server-spi,org.jboss.logging |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"providers": [ | |
"classpath:${jboss.home.dir}/providers/*", | |
"module:de.tdlabs.idm.keycloak.idm-keycloak-ext-login-action" | |
], | |
"admin": { | |
"realm": "master" | |
}, | |
"eventsStore": { | |
"provider": "jpa", | |
"jpa": { | |
"exclude-events": [ "REFRESH_TOKEN" ] | |
} | |
}, | |
"realm": { | |
"provider": "jpa" | |
}, | |
"user": { | |
"provider": "jpa" | |
}, | |
"userCache": { | |
"default" : { | |
"enabled": true | |
} | |
}, | |
"userSessionPersister": { | |
"provider": "jpa" | |
}, | |
"timer": { | |
"provider": "basic" | |
}, | |
"theme": { | |
"staticMaxAge": 2592000, | |
"cacheTemplates": true, | |
"cacheThemes": true, | |
"folder": { | |
"dir": "${jboss.home.dir}/themes" | |
} | |
}, | |
"scheduled": { | |
"interval": 900 | |
}, | |
"connectionsHttpClient": { | |
"default": {} | |
}, | |
"connectionsJpa": { | |
"default": { | |
"dataSource": "java:jboss/datasources/KeycloakDS", | |
"databaseSchema": "update" | |
} | |
}, | |
"realmCache": { | |
"provider": "default", | |
"default" : { | |
"enabled": true | |
} | |
}, | |
"connectionsInfinispan": { | |
"provider": "default", | |
"default": { | |
"cacheContainer" : "java:comp/env/infinispan/Keycloak" | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package de.tdlabs.idm.keycloak.ext.authentication; | |
import static java.time.LocalDateTime.now; | |
import static java.util.Arrays.asList; | |
import java.util.List; | |
import org.jboss.logging.Logger; | |
import org.keycloak.Config.Scope; | |
import org.keycloak.authentication.RequiredActionContext; | |
import org.keycloak.authentication.RequiredActionFactory; | |
import org.keycloak.authentication.RequiredActionProvider; | |
import org.keycloak.models.KeycloakSession; | |
import org.keycloak.models.KeycloakSessionFactory; | |
import org.keycloak.models.UserModel; | |
public class LoginStatsRecordingRequiredActionProvider implements RequiredActionProvider, RequiredActionFactory { | |
private static final Logger LOG = Logger.getLogger(LoginStatsRecordingRequiredActionProvider.class); | |
private static final String PROVIDER_ID = "login_stats_action"; | |
private static final String RECORD_LOGIN_STATISTICS_ACTION = "Record Login Statistics Action"; | |
private static final String LOGIN_LOGIN_COUNT = "login.login-count"; | |
private static final String LOGIN_FIRST_LOGIN_DATE = "login.first-login-date"; | |
private static final String LOGIN_RECENT_LOGIN_DATE = "login.recent-login-date"; | |
private static final String ONE = "1"; | |
private static final LoginStatsRecordingRequiredActionProvider INSTANCE = new LoginStatsRecordingRequiredActionProvider(); | |
@Override | |
public void close() { | |
// NOOP | |
} | |
@Override | |
public void evaluateTriggers(RequiredActionContext context) { | |
UserModel user = context.getUser(); | |
try { | |
recordFirstLogin(user); | |
} catch (Exception ex) { | |
LOG.warnv(ex,"Couldn't record first login <{0}>", this); | |
} | |
try { | |
recordRecentLogin(user); | |
} catch (Exception ex) { | |
LOG.warnv(ex, "Couldn't record recent login <{0}>", this); | |
} | |
try { | |
recordLoginCount(user); | |
} catch (Exception ex) { | |
LOG.warnv(ex, "Couldn't record login count <{0}>", this); | |
} | |
} | |
private void recordLoginCount(UserModel user) { | |
List<String> list = user.getAttribute(LOGIN_LOGIN_COUNT); | |
if (list == null || list.isEmpty()) { | |
list = asList(ONE); | |
} else { | |
list = asList(String.valueOf(Long.parseLong(list.get(0)) + 1)); | |
} | |
user.setAttribute(LOGIN_LOGIN_COUNT, list); | |
} | |
private void recordRecentLogin(UserModel user) { | |
user.setAttribute(LOGIN_RECENT_LOGIN_DATE, asList(now().toString())); | |
} | |
private void recordFirstLogin(UserModel user) { | |
List<String> list = user.getAttribute(LOGIN_FIRST_LOGIN_DATE); | |
if (list == null || list.isEmpty()) { | |
user.setAttribute(LOGIN_FIRST_LOGIN_DATE, asList(now().toString())); | |
} | |
} | |
@Override | |
public void requiredActionChallenge(RequiredActionContext context) { | |
// NOOP | |
} | |
@Override | |
public void processAction(RequiredActionContext context) { | |
context.success(); | |
} | |
@Override | |
public RequiredActionProvider create(KeycloakSession session) { | |
return INSTANCE; | |
} | |
@Override | |
public void init(Scope config) { | |
LOG.infov("Creating IdM Keycloak extension <{0}>", this); | |
// NOOP | |
} | |
@Override | |
public void postInit(KeycloakSessionFactory factory) { | |
// NOOP | |
} | |
@Override | |
public String getId() { | |
return PROVIDER_ID; | |
} | |
@Override | |
public String getDisplayText() { | |
return RECORD_LOGIN_STATISTICS_ACTION; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" ?> | |
<module xmlns="urn:jboss:module:1.1" name="de.eurodata.idm.keycloak.idm-keycloak-ext-login-action"> | |
<!-- copy to $KEYCLOAK_HOME/modules/de/tdlabs/idm/keycloak/idm-keycloak-ext-login-action/main/ together with the jar --> | |
<!-- add module reference in provider section of keycloak-server.json under $KEYCLOAK_HOME/standalone/configuration --> | |
<resources> | |
<resource-root path="idm-keycloak-ext-login-action-1.0.0.BUILD-SNAPSHOT.jar"/> | |
</resources> | |
<dependencies> | |
<module name="org.keycloak.keycloak-common"/> | |
<module name="org.keycloak.keycloak-core"/> | |
<module name="org.keycloak.keycloak-server-spi"/> | |
<module name="org.jboss.logging"/> | |
</dependencies> | |
</module> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# place this under src/main/resources/META-INF/services | |
de.tdlabs.idm.keycloak.ext.authentication.LoginStatsRecordingRequiredActionProvider |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>de.tdlabs.idm</groupId> | |
<artifactId>idm-keycloak-ext-login-action</artifactId> | |
<version>1.0.0.BUILD-SNAPSHOT</version> | |
<properties> | |
<keycloak.version>1.9.4.Final</keycloak.version> | |
<lombok.version>1.16.8</lombok.version> | |
<maven.compiler.source>1.8</maven.compiler.source> | |
<maven.compiler.target>1.8</maven.compiler.target> | |
<project.build.sourceEncoding>ISO-8859-1</project.build.sourceEncoding> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.projectlombok</groupId> | |
<artifactId>lombok</artifactId> | |
<version>${lombok.version}</version> | |
<scope>provided</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.keycloak</groupId> | |
<artifactId>keycloak-server-spi</artifactId> | |
<version>${keycloak.version}</version> | |
<scope>provided</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.keycloak</groupId> | |
<artifactId>keycloak-services</artifactId> | |
<version>${keycloak.version}</version> | |
<scope>provided</scope> | |
</dependency> | |
</dependencies> | |
</project> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment