Skip to content

Commit ee3c74c

Browse files
committed
add conditional attribute
1 parent db248cf commit ee3c74c

File tree

3 files changed

+163
-1
lines changed

3 files changed

+163
-1
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.instipod.keycloakauthenticators;
2+
3+
import com.instipod.keycloakauthenticators.utils.AuthenticatorUtils;
4+
import org.jboss.logging.Logger;
5+
import org.keycloak.authentication.AuthenticationFlowContext;
6+
import org.keycloak.models.AuthenticatorConfigModel;
7+
import org.keycloak.models.KeycloakSession;
8+
import org.keycloak.models.RealmModel;
9+
import org.keycloak.models.UserModel;
10+
11+
import java.util.List;
12+
13+
public class ConditionalAttributeAuthenticator implements org.keycloak.authentication.authenticators.conditional.ConditionalAuthenticator {
14+
public static final ConditionalAttributeAuthenticator SINGLETON = new ConditionalAttributeAuthenticator();
15+
private static Logger logger = Logger.getLogger(ConditionalAttributeAuthenticator.class);
16+
17+
@Override
18+
public boolean matchCondition(AuthenticationFlowContext context) {
19+
AuthenticatorConfigModel authConfig = context.getAuthenticatorConfig();
20+
21+
if (authConfig!=null && authConfig.getConfig()!=null) {
22+
//evaluate
23+
boolean not = AuthenticatorUtils.getConfigBoolean(context, ConditionalAttributeAuthenticatorFactory.CONDITIONAL_NOT);
24+
String attributeName = authConfig.getConfig().get(ConditionalAttributeAuthenticatorFactory.CONDITIONAL_ATTRIBUTE_NAME);
25+
String attributeValue = authConfig.getConfig().get(ConditionalAttributeAuthenticatorFactory.CONDITIONAL_ATTRIBUTE_VALUE);
26+
attributeName = AuthenticatorUtils.variableReplace(context, attributeName);
27+
attributeValue = AuthenticatorUtils.variableReplace(context, attributeValue);
28+
29+
List<String> values = context.getUser().getAttribute(attributeName);
30+
boolean hasAttribute = values.contains(attributeValue);
31+
32+
boolean check;
33+
if (not) {
34+
//does not have attribute
35+
check = !(hasAttribute);
36+
} else {
37+
//has attribute
38+
check = hasAttribute;
39+
}
40+
41+
return check;
42+
} else {
43+
logger.error("No config data found for this authenticator!");
44+
}
45+
46+
return false;
47+
}
48+
49+
@Override
50+
public void action(AuthenticationFlowContext context) {
51+
// Not used
52+
}
53+
54+
@Override
55+
public boolean requiresUser() {
56+
return true;
57+
}
58+
59+
@Override
60+
public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
61+
// Not used
62+
}
63+
64+
@Override
65+
public void close() {
66+
// Does nothing
67+
}
68+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package com.instipod.keycloakauthenticators;
2+
3+
import org.keycloak.Config.Scope;
4+
import org.keycloak.authentication.authenticators.conditional.ConditionalAuthenticator;
5+
import org.keycloak.models.AuthenticationExecutionModel.Requirement;
6+
import org.keycloak.models.KeycloakSessionFactory;
7+
import org.keycloak.provider.ProviderConfigProperty;
8+
import org.keycloak.provider.ProviderConfigurationBuilder;
9+
10+
import java.util.Collections;
11+
import java.util.List;
12+
13+
public class ConditionalAttributeAuthenticatorFactory implements org.keycloak.authentication.authenticators.conditional.ConditionalAuthenticatorFactory {
14+
public static final String PROVIDER_ID = "conditional-attribute";
15+
protected static final String CONDITIONAL_ATTRIBUTE_NAME = "condAttributeName";
16+
protected static final String CONDITIONAL_ATTRIBUTE_VALUE = "condAttributeValue";
17+
protected static final String CONDITIONAL_NOT = "condNot";
18+
19+
private static List<ProviderConfigProperty> commonConfig;
20+
21+
static {
22+
commonConfig = Collections.unmodifiableList(ProviderConfigurationBuilder.create()
23+
.property().name(CONDITIONAL_ATTRIBUTE_NAME).label("User Attribute Name").helpText("Attribute name to check (supports variables)").type(ProviderConfigProperty.STRING_TYPE).add()
24+
.property().name(CONDITIONAL_ATTRIBUTE_VALUE).label("User Attribute Value").helpText("Attribute value (supports variables)").type(ProviderConfigProperty.STRING_TYPE).add()
25+
.property().name(CONDITIONAL_NOT).label("Not").helpText("If we should match on NOT having this attribute").type(ProviderConfigProperty.BOOLEAN_TYPE).add()
26+
.build()
27+
);
28+
}
29+
30+
@Override
31+
public void init(Scope config) {
32+
// no-op
33+
}
34+
35+
@Override
36+
public void postInit(KeycloakSessionFactory factory) {
37+
// no-op
38+
}
39+
40+
@Override
41+
public void close() {
42+
// no-op
43+
}
44+
45+
@Override
46+
public String getId() {
47+
return PROVIDER_ID;
48+
}
49+
50+
@Override
51+
public String getDisplayType() {
52+
return "Condition - Attribute";
53+
}
54+
55+
@Override
56+
public String getReferenceCategory() {
57+
return "condition";
58+
}
59+
60+
@Override
61+
public boolean isConfigurable() {
62+
return true;
63+
}
64+
65+
private static final Requirement[] REQUIREMENT_CHOICES = {
66+
Requirement.REQUIRED, Requirement.DISABLED
67+
};
68+
69+
@Override
70+
public Requirement[] getRequirementChoices() {
71+
return REQUIREMENT_CHOICES;
72+
}
73+
74+
@Override
75+
public boolean isUserSetupAllowed() {
76+
return false;
77+
}
78+
79+
@Override
80+
public String getHelpText() {
81+
return "Flow is executed only if user has specified attribute.";
82+
}
83+
84+
@Override
85+
public List<ProviderConfigProperty> getConfigProperties() {
86+
return commonConfig;
87+
}
88+
89+
@Override
90+
public ConditionalAuthenticator getSingleton() {
91+
return ConditionalAttributeAuthenticator.SINGLETON;
92+
}
93+
}

src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ com.instipod.keycloakauthenticators.ConditionalRoleEnhancedAuthenticatorFactory
1010
com.instipod.keycloakauthenticators.ConditionalClientRoleAuthenticatorFactory
1111
com.instipod.keycloakauthenticators.SuccessAuthenticatorFactory
1212
com.instipod.keycloakauthenticators.SplashMessageAuthenticatorFactory
13-
com.instipod.keycloakauthenticators.MagicLinkFormAuthenticatorFactory
13+
com.instipod.keycloakauthenticators.MagicLinkFormAuthenticatorFactory
14+
com.instipod.keycloakauthenticators.ConditionalAttributeAuthenticatorFactory

0 commit comments

Comments
 (0)