Skip to content

Commit d5c3676

Browse files
Add confirm cookie authenticator example
1 parent 42feaf8 commit d5c3676

File tree

2 files changed

+185
-0
lines changed

2 files changed

+185
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package com.github.thomasdarimont.keycloak.custom.auth.confirmcookie;
2+
3+
import com.google.auto.service.AutoService;
4+
import jakarta.ws.rs.core.Response;
5+
import lombok.extern.jbosslog.JBossLog;
6+
import org.keycloak.Config;
7+
import org.keycloak.authentication.AuthenticationFlowContext;
8+
import org.keycloak.authentication.Authenticator;
9+
import org.keycloak.authentication.AuthenticatorFactory;
10+
import org.keycloak.authentication.authenticators.browser.CookieAuthenticator;
11+
import org.keycloak.models.AuthenticationExecutionModel;
12+
import org.keycloak.models.KeycloakSession;
13+
import org.keycloak.models.KeycloakSessionFactory;
14+
import org.keycloak.models.RealmModel;
15+
import org.keycloak.models.UserModel;
16+
import org.keycloak.provider.ProviderConfigProperty;
17+
import org.keycloak.provider.ProviderConfigurationBuilder;
18+
import org.keycloak.provider.ServerInfoAwareProviderFactory;
19+
import org.keycloak.services.managers.AuthenticationManager;
20+
21+
import java.util.List;
22+
import java.util.Map;
23+
24+
@JBossLog
25+
public class ConfirmCookieAuthenticator extends CookieAuthenticator {
26+
27+
static final ConfirmCookieAuthenticator INSTANCE = new ConfirmCookieAuthenticator();
28+
29+
@Override
30+
public void authenticate(AuthenticationFlowContext context) {
31+
AuthenticationManager.AuthResult authResult = AuthenticationManager.authenticateIdentityCookie(context.getSession(),
32+
context.getRealm(), true);
33+
if (authResult == null) {
34+
context.attempted();
35+
return;
36+
}
37+
38+
Response response = context.form() //
39+
.createForm("login-confirm-cookie-form.ftl");
40+
context.challenge(response);
41+
}
42+
43+
@Override
44+
public void action(AuthenticationFlowContext context) {
45+
super.authenticate(context);
46+
}
47+
48+
@Override
49+
public boolean requiresUser() {
50+
return false;
51+
}
52+
53+
@Override
54+
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
55+
return false;
56+
}
57+
58+
@Override
59+
public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
60+
61+
}
62+
63+
@Override
64+
public void close() {
65+
66+
}
67+
68+
@AutoService(AuthenticatorFactory.class)
69+
public static class Factory implements AuthenticatorFactory, ServerInfoAwareProviderFactory {
70+
71+
@Override
72+
public String getId() {
73+
return "acme-auth-confirm-cookie";
74+
}
75+
76+
@Override
77+
public Authenticator create(KeycloakSession session) {
78+
return INSTANCE;
79+
}
80+
81+
@Override
82+
public String getDisplayType() {
83+
return "Acme: Confirm Cookie Authenticator";
84+
}
85+
86+
@Override
87+
public String getHelpText() {
88+
return "Shows a form asking to confirm cookie";
89+
}
90+
91+
@Override
92+
public String getReferenceCategory() {
93+
return "hello";
94+
}
95+
96+
@Override
97+
public boolean isConfigurable() {
98+
return true;
99+
}
100+
101+
@Override
102+
public List<ProviderConfigProperty> getConfigProperties() {
103+
104+
List<ProviderConfigProperty> properties = ProviderConfigurationBuilder.create() //
105+
.property().name("message").label("Message")
106+
.helpText("Message text").type(ProviderConfigProperty.STRING_TYPE)
107+
.defaultValue("hello").add()
108+
109+
.build();
110+
return properties;
111+
}
112+
113+
@Override
114+
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
115+
return REQUIREMENT_CHOICES;
116+
}
117+
118+
@Override
119+
public boolean isUserSetupAllowed() {
120+
return false;
121+
}
122+
123+
@Override
124+
public void postInit(KeycloakSessionFactory factory) {
125+
// called after factory is found
126+
}
127+
128+
@Override
129+
public void init(Config.Scope config) {
130+
}
131+
132+
133+
@Override
134+
public void close() {
135+
136+
}
137+
138+
@Override
139+
public Map<String, String> getOperationalInfo() {
140+
return Map.of("info", "infoValue");
141+
}
142+
}
143+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<#import "template.ftl" as layout>
2+
<@layout.registrationLayout displayInfo=true displayMessage=!messagesPerField.existsError('code') showAnotherWayIfPresent=false; section>
3+
<#if section = "header">
4+
Confirm Cookie: ${realm.displayName}
5+
<#elseif section = "form">
6+
7+
<h1>Confirm Cookie</h1>
8+
9+
<form id="kc-confirm-cookie-login-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
10+
11+
<div class="${properties.kcFormGroupClass!} ${properties.kcFormSettingClass!}">
12+
<#-- <div id="kc-form-options" class="${properties.kcFormOptionsClass!}">-->
13+
<#-- <div class="${properties.kcFormOptionsWrapperClass!}">-->
14+
<#-- <span><a href="${url.loginUrl}">${kcSanitize(msg("backToLogin"))?no_esc}</a></span>-->
15+
<#-- </div>-->
16+
<#-- </div>-->
17+
18+
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
19+
<div class="${properties.kcFormButtonsWrapperClass!}">
20+
<input name="proceed"
21+
class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"
22+
type="submit" value="Continue"/>
23+
24+
<#-- <input name="switchUser"-->
25+
<#-- class="${properties.kcButtonClass!} ${properties.kcButtonSecondaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}"-->
26+
<#-- type="submit" value="Switch User"-->
27+
<#-- formnovalidate="formnovalidate"/>-->
28+
29+
<a id="reset-login" href="${url.loginRestartFlowUrl}" aria-label="${msg("restartLoginTooltip")}" class="${properties.kcButtonClass!} ${properties.kcButtonSecondaryClass!} ${properties.kcButtonBlockClass!} ${properties.kcButtonLargeClass!}">
30+
Switch User
31+
<div class="kc-login-tooltip">
32+
<span class="kc-tooltip-text">Switch User</span>
33+
</div>
34+
</a>
35+
</div>
36+
</div>
37+
</div>
38+
</form>
39+
<#elseif section = "info" >
40+
Confirm Cookie Instruction
41+
</#if>
42+
</@layout.registrationLayout>

0 commit comments

Comments
 (0)