Skip to content

Commit fbe70b1

Browse files
authored
Add script authenticators (#1)
* Add user-enabled-authenticator * Use OpenJDK 21 and bump version * Add CSM Authenticator and Authorization Authenticator * Include version in jar name * Make name shorter * Replace getAttribute with getFirstAttribute
1 parent 3316bf3 commit fbe70b1

File tree

7 files changed

+87
-8
lines changed

7 files changed

+87
-8
lines changed

META-INF/keycloak-scripts.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
{
2-
"authenticators": [],
2+
"authenticators": [
3+
{
4+
"name": "User Enabled Authenticator",
5+
"fileName": "user-enabled-authenticator.js",
6+
"description": "Allow only enabled users"
7+
},
8+
{
9+
"name": "CSM Authenticator",
10+
"fileName": "csm-authenticator.js",
11+
"description": "CSM EmployeeStatus Authenticator"
12+
},
13+
{
14+
"name": "Authorization Authenticator",
15+
"fileName": "authz-authenticator.js",
16+
"description": "Authorization Authenticator"
17+
}
18+
],
319
"policies": [],
420
"mappers": [],
521
"saml-mappers": [

authz-authenticator.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
2+
3+
function authenticate(context) {
4+
5+
if (!authenticationSession.getClient()) {
6+
context.failure(AuthenticationFlowError.CLIENT_NOT_FOUND);
7+
return;
8+
}
9+
var client = authenticationSession.getClient().getClientId();
10+
LOG.info(script.name + " evalute authorization for user=" + user.username + " client=" + client);
11+
/*
12+
Use employeeStatus verification for service-now which allows some disabled
13+
states to still authenticate.
14+
Also allow class-dev for testing purposes.
15+
*/
16+
if (client && (client.contains("service-now") || client.contains("class-dev"))) {
17+
var allowed = /(REQAPPROVAL|ACTIVE|WEBONLY|RESTRICTED)/;
18+
var employeeStatus = user.getFirstAttribute("employeeStatus");
19+
if (employeeStatus && !allowed.test(employeeStatus)) {
20+
context.failure(AuthenticationFlowError.INVALID_USER);
21+
return;
22+
}
23+
} else {
24+
/*
25+
All other clients will authorize if the user account is not disabled or locked
26+
*/
27+
if (user.getFirstAttribute("nsAccountLock") == "TRUE" || user.getFirstAttribute("loginDisabled") == "TRUE") {
28+
context.failure(AuthenticationFlowError.INVALID_USER);
29+
return;
30+
}
31+
}
32+
33+
context.success();
34+
}

build/Dockerfile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
FROM rockylinux:8
2-
RUN dnf -y install java-17-openjdk-devel maven && yum clean all && rm -rf /var/cache/yum/*
3-
RUN alternatives --set java $(alternatives --display java | grep 'family java-17-openjdk' | cut -d' ' -f1)
4-
RUN alternatives --set javac $(alternatives --display javac | grep 'family java-17-openjdk' | cut -d' ' -f1)
2+
RUN dnf -y install java-21-openjdk-devel maven && yum clean all && rm -rf /var/cache/yum/*
3+
RUN alternatives --set java $(alternatives --display java | grep 'family java-21-openjdk' | cut -d' ' -f1)
4+
RUN alternatives --set javac $(alternatives --display javac | grep 'family java-21-openjdk' | cut -d' ' -f1)
55
RUN mkdir /build
6+
ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk

build/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,5 @@ From root of repo:
1212

1313
```
1414
docker run --rm -it -v $(pwd):/build -w /build \
15-
-e JAVA_HOME=/usr/lib/jvm/java-17-openjdk \
1615
osc-keycloak-scripts-build:latest mvn clean package
1716
```

csm-authenticator.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
2+
3+
function authenticate(context) {
4+
5+
LOG.info(script.name + " --> trace auth for: " + user.username);
6+
7+
const allowed = /(REQAPPROVAL|ACTIVE|WEBONLY|RESTRICTED)/;
8+
if (user.getFirstAttribute("employeeStatus") && allowed.test(user.getFirstAttribute("employeeStatus"))) {
9+
context.success();
10+
} else {
11+
context.failure(AuthenticationFlowError.INVALID_USER);
12+
return;
13+
}
14+
15+
context.success();
16+
}

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

77
<groupId>edu.osc</groupId>
88
<artifactId>osc-keycloak-scripts</artifactId>
9-
<version>1.0.0</version>
9+
<version>1.1.0</version>
1010
<packaging>jar</packaging>
1111

1212
<properties>
1313
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14-
<java.version>17.0.0</java.version>
14+
<java.version>21.0.0</java.version>
1515
</properties>
1616

1717
<dependencies>
@@ -23,7 +23,7 @@
2323
</dependencies>
2424

2525
<build>
26-
<finalName>osc-keycloak-scripts</finalName>
26+
<finalName>osc-keycloak-scripts-${project.version}</finalName>
2727
<resources>
2828
<resource>
2929
<directory>.</directory>

user-enabled-authenticator.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
AuthenticationFlowError = Java.type("org.keycloak.authentication.AuthenticationFlowError");
2+
3+
function authenticate(context) {
4+
5+
LOG.info(script.name + " --> trace auth for: " + user.username);
6+
7+
if (user.getFirstAttribute("nsAccountLock") == "TRUE" || user.getFirstAttribute("loginDisabled") == "TRUE") {
8+
context.failure(AuthenticationFlowError.INVALID_USER);
9+
return;
10+
}
11+
12+
context.success();
13+
}

0 commit comments

Comments
 (0)