Skip to content
Snippets Groups Projects
Commit 0751e444 authored by Roland Werner's avatar Roland Werner
Browse files

Hebung auf Quarkus

parent 6666db3a
No related branches found
No related tags found
No related merge requests found
Showing
with 81 additions and 96 deletions
......@@ -27,35 +27,6 @@ Die Datei `bayernid-plugin-[VERSION].jar` aus dem Verzeichnis `target` (existier
Siehe Dokument `KeyCloak-Konfiguration.pdf`
## Mapper und Authenticators
Die folgenden Mapper werden durch das Plugin ergänzt:
- **CUSTOM Current-Timestamp mapper**: Setzt den aktuellen Timestamp (Unix Epoch) in Sekunden. Sollte als "force" (immer updaten) konfiguriert werden.
Damit weiß man später, wann der letzte Login des Users erfolgte.
- **Custom effective scopes mapper**: Wird benötigt, damit die angeforderten Scopes beim SSO (Wechsel zwischen zwei Clients) mit betrachtet werden
können. Führt dazu, dass kein SSO zugelassen wird, wenn bei einem Wechsel zwischen zwei Clients nicht alle benötigten Scopes im User vorliegen.
- **CUSTOM UUID generator**: Setzt eine randomisiert generierte UUID. Sollte als "import" (nur bei der ersten Anlage des Datensatzes) verwendet werden,
um eine interne ID zu setzen.
- **Custom ID Template Importer**: Erweiterung des ID Template Importers. Zusätzlich kann auch auf die bPK (die ja anders als die bPK2 noch per BASE64
ausgepackt und ausgeschnitten werden muss) zugegriffen werden. Außerdem wird der String ID_MISSING_DO_NOT_USE gesetzt, falls kein Wert ermittelt werden kann.
- **CUSTOM Attribute-with-Scope Importer**: Erweiterung des Attribute Importers. Es kann zusätzlich noch ein Scope definiert werden. Nur wenn dieser Scope
beim Zugriff auf den Client angefordert wird (explizit oder implizit), wird das entsprechende Attribut bei der BayernID angefordert. Außerdem kann
per "Required Attribute" festgelegt werden, ob das Attribut zwingend bei der BayernID angefragt wird (führt zu einem Fehler, wenn es nicht vorliegt).
- **CUSTOM Attribute-with-Mapping Importer**: Erweiterung des Attribut Importers. Es kann ein Mapping angegeben werden, so dass ein eingehender Wert
auf einen anderen Wert umgeschrieben werden kann.
- **Custom Username Template Importer**: Erweiterung des Username Template Importers. Zusätzlich kann auch auf die bPK (die ja anders als die bPK2 noch per BASE64
ausgepackt und ausgeschnitten werden muss) zugegriffen werden. Außerdem wird der String ID_MISSING_DO_NOT_USE gesetzt, falls kein Wert ermittelt werden kann.
Die folgenden Authenticators werden durch das Plugin ergänzt:
- **Require Attribute**: Forciert, dass ein User nach dem Login in einem Attribut einen bestimmten Wert hat. Der Wert kann entweder in Form einer Liste
angegeben werden oder per RegEx. Zusätzlich kann noch gefordert werden, dass im aktuellen Client ein gleichnamiger Scope mindestens optional zugeordnet
ist. Damit kann man bspw. erreichen, dass in einem Client nur bestimmte IDPs zugelassen sind.
- **CUSTOM Identity Provider Redirector**: Eine Erweiterung des Identity Provider Redirectors. Ein IDP-Hint kann damit auch in einem SAML-Request
mitgegeben werden (im Extensions-Bereich). Außerdem erfolgt eine direkte Weiterleitung zum externen IDP, wenn aufgrund versch. Filterungen nur
einer zur Auswahl steht.
- **CUSTOM Require Effective Scopes**: Wird im Zusammenspiel mit dem o.g. "Custom effective scopes mapper" genutzt, damit beim SSO (Wechsel zwischen zwei
Clients) geprüft wird, ob alle angeforderten Scopes im User auch vorliegen.
## Testen
Je nachdem, ob das Plugin per SAML2-Client oder OIDC-Client aufgerufen wird, verhält es sich unterschiedlich
......
......@@ -5,20 +5,26 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<!-- <keycloak.version>9.0.3</keycloak.version>-->
<keycloak.version>15.0.2</keycloak.version>
<keycloak.version>22.0.5</keycloak.version>
<jboss-logging.version>3.3.1.Final</jboss-logging.version>
<!-- Plugins -->
<wildfly.version>2.0.0.Final</wildfly.version>
<scm.plugin.version>1.11.2</scm.plugin.version>
<java.version>17</java.version>
</properties>
<scm>
<connection>scm:git:https://git.muenchen.de/ccse/rh-sso-plugins/bayernid-plugin/public.git</connection>
<developerConnection>scm:git:https://git.muenchen.de/ccse/rh-sso-plugins/bayernid-plugin/public.git</developerConnection>
</scm>
<artifactId>bayernid-plugin</artifactId>
<groupId>de.muenchen.keycloak</groupId>
<version>1.0.2</version>
<version>1.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
......
......@@ -6,7 +6,7 @@ import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.Authenticator;
import org.keycloak.models.*;
import javax.ws.rs.core.Response;
import jakarta.ws.rs.core.Response;
import java.util.List;
import java.util.Map;
import java.util.Set;
......
......@@ -21,7 +21,7 @@ import org.keycloak.Config;
import org.keycloak.OAuth2Constants;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.authentication.DisplayTypeAuthenticatorFactory;
//import org.keycloak.authentication.DisplayTypeAuthenticatorFactory;
import org.keycloak.authentication.authenticators.AttemptedAuthenticator;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.KeycloakSession;
......@@ -31,7 +31,7 @@ import org.keycloak.provider.ProviderConfigProperty;
import java.util.Arrays;
import java.util.List;
public class RequireEffectiveScopesAuthenticatorFactory implements AuthenticatorFactory, DisplayTypeAuthenticatorFactory {
public class RequireEffectiveScopesAuthenticatorFactory implements AuthenticatorFactory {
public static final String PROVIDER_ID = "require-effective-scopes";
static final String ATTRIBUTE = "attribute";
static final String CUSTOM_ERROR = "customError";
......@@ -43,12 +43,12 @@ public class RequireEffectiveScopesAuthenticatorFactory implements Authenticator
return SINGLETON;
}
@Override
public Authenticator createDisplay(KeycloakSession session, String displayType) {
if (displayType == null) return SINGLETON;
if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) return null;
return AttemptedAuthenticator.SINGLETON; // ignore this authenticator
}
// @Override
// public Authenticator createDisplay(KeycloakSession session, String displayType) {
// if (displayType == null) return SINGLETON;
// if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) return null;
// return AttemptedAuthenticator.SINGLETON; // ignore this authenticator
// }
@Override
public void init(Config.Scope config) {
......
......@@ -6,7 +6,7 @@ import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.Authenticator;
import org.keycloak.models.*;
import javax.ws.rs.core.Response;
import jakarta.ws.rs.core.Response;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
......
......@@ -18,11 +18,8 @@
package de.muenchen.keycloak.custom.authentication.authenticators.afterbroker;
import org.keycloak.Config;
import org.keycloak.OAuth2Constants;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.authentication.DisplayTypeAuthenticatorFactory;
import org.keycloak.authentication.authenticators.AttemptedAuthenticator;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
......@@ -31,7 +28,7 @@ import org.keycloak.provider.ProviderConfigProperty;
import java.util.Arrays;
import java.util.List;
public class RequireAttributeAuthenticatorFactory implements AuthenticatorFactory, DisplayTypeAuthenticatorFactory {
public class RequireAttributeAuthenticatorFactory implements AuthenticatorFactory {
public static final String PROVIDER_ID = "require-attribute";
public static final String REG_EXP = "regExp";
static final String ATTRIBUTE = "attribute";
......@@ -46,12 +43,12 @@ public class RequireAttributeAuthenticatorFactory implements AuthenticatorFactor
return SINGLETON;
}
@Override
public Authenticator createDisplay(KeycloakSession session, String displayType) {
if (displayType == null) return SINGLETON;
if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) return null;
return AttemptedAuthenticator.SINGLETON; // ignore this authenticator
}
// @Override
// public Authenticator createDisplay(KeycloakSession session, String displayType) {
// if (displayType == null) return SINGLETON;
// if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) return null;
// return AttemptedAuthenticator.SINGLETON; // ignore this authenticator
// }
@Override
public void init(Config.Scope config) {
......@@ -111,7 +108,10 @@ public class RequireAttributeAuthenticatorFactory implements AuthenticatorFactor
attribute.setHelpText("Required attribute name that a user needs to have to proceed with the authentication. ");
ProviderConfigProperty attributeValue = new ProviderConfigProperty();
attributeValue.setType(ProviderConfigProperty.MULTIVALUED_STRING_TYPE);
// attributeValue.setType(ProviderConfigProperty.MULTIVALUED_STRING_TYPE);
//Multi-Valued-String scheint im Keycloak22 und Keycloak24 nicht zu funktionieren.
//Stattdessen als Workaround normaler String, die Werte werden mit ## abgetrennt
attributeValue.setType(ProviderConfigProperty.STRING_TYPE);
attributeValue.setName(ATTRIBUTE_VALUES);
attributeValue.setLabel("Attribute value(s)");
attributeValue.setHelpText("Required attribute value(s) that the attribute needs to have to proceed with the authentication.");
......
......@@ -12,8 +12,8 @@ import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.services.Urls;
import org.keycloak.services.managers.ClientSessionCode;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import java.net.URI;
import java.util.List;
import java.util.Objects;
......
......@@ -26,12 +26,12 @@ public class CustomIdentityProviderAuthenticatorFactory extends IdentityProvider
return new CustomIdentityProviderAuthenticator();
}
@Override
public Authenticator createDisplay(KeycloakSession session, String displayType) {
if (displayType == null) return new CustomIdentityProviderAuthenticator();
if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) return null;
return AttemptedAuthenticator.SINGLETON; // ignore this authenticator
}
// @Override
// public Authenticator createDisplay(KeycloakSession session, String displayType) {
// if (displayType == null) return new CustomIdentityProviderAuthenticator();
// if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) return null;
// return AttemptedAuthenticator.SINGLETON; // ignore this authenticator
// }
@Override
public String getId() {
......
......@@ -86,17 +86,12 @@ public class PreprocessorHelper {
List<String> requestedScopes = AuthNoteHelper.getRequestedScopesAsList(clientSession);
if (requestedScopes != null) {
effectiveScopes.addAll(requestedScopes);
} else {
//bei SAML: nur falls keine Scopes und keine Attribute im Request angefordert sind, sind die
//default scopes "effective" (da diese normalerweise alle Attribute umfassen --> rückwärts-kompatible Lösung)
if (AuthNoteHelper.getRequestedAttributes(clientSession) == null ||
!AuthNoteHelper.getRequestedAttributes(clientSession).isEmpty()) {
effectiveScopes.addAll(
ScopesHelper.stripScopes(defaultClientScopes.keySet())
);
}
}
//und alle default Scopes sind "effective"
effectiveScopes.addAll(
ScopesHelper.stripScopes(defaultClientScopes.keySet())
);
}
return effectiveScopes;
......
......@@ -75,6 +75,7 @@ public class CustomUserAttributeWithMappingMapper extends UserAttributeMapper {
applyMapping(mapperModel, user);
}
//Version Keycloak 22
private void applyMapping(final IdentityProviderMapperModel mapperModel, final UserModel user) {
if (user == null || mapperModel == null) {
return;
......@@ -92,4 +93,27 @@ public class CustomUserAttributeWithMappingMapper extends UserAttributeMapper {
user.setSingleAttribute(attribute, newAttributeValue);
}
}
//Version Keycloak 24
// private void applyMapping(final IdentityProviderMapperModel mapperModel, final UserModel user) {
// if (user == null || mapperModel == null) {
// return;
// }
// final String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE);
// final String attributeValue = user.getFirstAttribute(attribute);
//
// logger.debug("Checking attribute " + attribute + ", found value " + attributeValue);
//
// final Map<String, List<String>> mapping = mapperModel.getConfigMap(MAPPING);
//
// if (attributeValue != null && mapping != null && mapping.containsKey(attributeValue)) {
// final List<String> newAttributeValueList = mapping.get(attributeValue);
// if (newAttributeValueList == null || newAttributeValueList.size() > 1) {
// logger.info("Liste für " + attributeValue + " ist nicht 1.");
// }
// final String newAttributeValue = newAttributeValueList.get(0);
// logger.info("Setting " + attribute + " to " + newAttributeValue + " (mapping from " + attributeValue + ")");
// user.setSingleAttribute(attribute, newAttributeValue);
// }
// }
}
......@@ -7,14 +7,11 @@ import org.keycloak.forms.login.freemarker.FreeMarkerLoginFormsProvider;
import org.keycloak.forms.login.freemarker.model.IdentityProviderBean;
import org.keycloak.models.KeycloakSession;
import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.theme.FreeMarkerUtil;
import org.keycloak.theme.Theme;
import javax.ws.rs.core.UriBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import jakarta.ws.rs.core.UriBuilder;
import java.util.*;
/**
* siehe https://stackoverflow.com/questions/44072608/keycloak-access-cookie-and-or-url-query-params-inside-freemarker-template
......@@ -25,39 +22,35 @@ public class CustomFreeMarkerLoginFormsProvider extends FreeMarkerLoginFormsProv
public static final String SOCIAL = "social";
public static final String PUBLIC = "public";
public static final String DEMO = "demo";
public static final String A61 = "A61";
public CustomFreeMarkerLoginFormsProvider(final KeycloakSession session, final FreeMarkerUtil freeMarker) {
super(session, freeMarker);
public CustomFreeMarkerLoginFormsProvider(final KeycloakSession session) {
super(session);
}
@Override
protected void createCommonAttributes(final Theme theme, final Locale locale, final Properties messagesBundle, final UriBuilder baseUriBuilder, final LoginFormsPages page) {
super.createCommonAttributes(theme, locale, messagesBundle, baseUriBuilder, page);
//die folgenden Prüfungen nur im Realm "public" durchführen (um Nebenwirkungen in anderen Realms zu minimieren)
//die folgenden Prüfungen nur im Realm "public" (und aus historischen Gründen alternativ "demo" und "A61") durchführen (um Nebenwirkungen in anderen Realms zu minimieren)
if (session == null || session.getContext() == null || session.getContext().getRealm() == null ||
!session.getContext().getRealm().getName().trim().equalsIgnoreCase(PUBLIC)) {
!Arrays.asList(PUBLIC, DEMO, A61).contains(session.getContext().getRealm().getName().trim())) {
return;
}
AuthenticationSessionModel authenticationSession = session.getContext().getAuthenticationSession();
final String authLevel = IdentityProviderHelper.findAuthLevel(authenticationSession);
logger.debug("Requested authLevel found on Scopes " + authLevel);
logger.info("Requested authLevel found on Scopes " + authLevel);
String requestedAttributeSet = IdentityProviderHelper.findRequestedAttributeSet(authenticationSession);
logger.info("RequestedAttributeSet found " + requestedAttributeSet);
IdentityProviderBean ipb = (IdentityProviderBean) this.attributes.get(SOCIAL);
if (authLevel != null) {
this.attributes.put("authlevel", authLevel);
logger.debug("Setting authlevel " + authLevel + " as attribute for login-Template");
} else {
this.attributes.put("authlevel", "nicht gesetzt");
logger.debug("Setting authlevel to nicht-gesetzt as attribute for login-Template");
}
if (ipb == null) {
//Kein Attribut "social" gefunden - dadurch auch keine IdentityProvider konfiguriert
return;
......
......@@ -22,23 +22,20 @@ import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.forms.login.LoginFormsProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.theme.FreeMarkerUtil;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class CustomFreeMarkerLoginFormsProviderFactory implements LoginFormsProviderFactory {
private FreeMarkerUtil freeMarker;
@Override
public LoginFormsProvider create(KeycloakSession session) {
return new CustomFreeMarkerLoginFormsProvider(session, freeMarker);
return new CustomFreeMarkerLoginFormsProvider(session);
}
@Override
public void init(Config.Scope config) {
freeMarker = new FreeMarkerUtil();
}
@Override
......@@ -47,7 +44,6 @@ public class CustomFreeMarkerLoginFormsProviderFactory implements LoginFormsProv
}
@Override
public void close() {
freeMarker = null;
}
@Override
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment

Consent

On this website, we use the web analytics service Matomo to analyze and review the use of our website. Through the collected statistics, we can improve our offerings and make them more appealing for you. Here, you can decide whether to allow us to process your data and set corresponding cookies for these purposes, in addition to technically necessary cookies. Further information on data protection—especially regarding "cookies" and "Matomo"—can be found in our privacy policy. You can withdraw your consent at any time.