Dateien nach "sourcecode/src/main/java/de/gmp/keycloak" hochladen
This commit is contained in:
parent
706ac46d59
commit
8bf3b758d7
150
sourcecode/src/main/java/de/gmp/keycloak/IpAuthenticator.java
Normal file
150
sourcecode/src/main/java/de/gmp/keycloak/IpAuthenticator.java
Normal file
@ -0,0 +1,150 @@
|
||||
package de.gmp.keycloak;
|
||||
|
||||
import jakarta.ws.rs.core.MultivaluedMap;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.keycloak.authentication.AuthenticationFlowContext;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.apache.commons.net.util.SubnetUtils;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import org.keycloak.authentication.AuthenticationFlowError;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
|
||||
// import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
// import org.keycloak.storage.UserStorageManager;
|
||||
// import org.keycloak.credential.CredentialModel;
|
||||
// import org.keycloak.storage.UserStorageManager;
|
||||
// import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
// import org.keycloak.models.UserCredentialModel;
|
||||
// import org.keycloak.credential.UserCredentialStore;
|
||||
// import org.keycloak.authentication.AuthenticationProcessor;
|
||||
// import org.keycloak.authentication.AuthenticationFlowError;
|
||||
// import org.keycloak.authentication.CredentialValidator;
|
||||
// import org.keycloak.credential.CredentialProvider;
|
||||
// import org.keycloak.models.KeycloakSession;
|
||||
// import org.keycloak.models.RealmModel;
|
||||
// import org.keycloak.models.UserCredentialModel;
|
||||
// import org.keycloak.models.UserModel;
|
||||
// import org.keycloak.models.utils.FormMessage;
|
||||
// import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
// import java.util.List;
|
||||
|
||||
|
||||
public class IpAuthenticator implements Authenticator {
|
||||
|
||||
@Override
|
||||
public void authenticate(AuthenticationFlowContext context) {
|
||||
// SCHRITT 1: Prüfen, ob der Benutzer den IP-Login überspringen will.
|
||||
String skip = context.getHttpRequest().getUri().getQueryParameters().getFirst("skip_ip_login");
|
||||
if ("true".equals(skip)) {
|
||||
context.attempted();
|
||||
return;
|
||||
}
|
||||
|
||||
// SCHRITT 2: IP-Prüfung wie gehabt
|
||||
UserModel user = findUserByIp(context);
|
||||
if (user != null) {
|
||||
// Benutzer gefunden -> Zeige unsere spezielle Login-Seite an.
|
||||
Response challenge = context.form()
|
||||
.setAttribute("user", user)
|
||||
.createForm("ip-login-page.ftl");
|
||||
context.challenge(challenge);
|
||||
} else {
|
||||
// Kein passender Benutzer gefunden -> Fahre mit dem normalen Flow fort.
|
||||
context.attempted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(AuthenticationFlowContext context) {
|
||||
UserModel user = findUserByIp(context);
|
||||
if (user != null) {
|
||||
context.setUser(user);
|
||||
context.success();
|
||||
} else {
|
||||
// Sicherheitshalber, falls die IP sich zwischenzeitlich ändert.
|
||||
context.failure(AuthenticationFlowError.UNKNOWN_USER);
|
||||
}
|
||||
}
|
||||
|
||||
private UserModel findUserByIp(AuthenticationFlowContext context) {
|
||||
RealmModel realm = context.getRealm();
|
||||
KeycloakSession session = context.getSession();
|
||||
String clientIp = context.getConnection().getRemoteAddr();
|
||||
|
||||
try (Stream<UserModel> userStream = session.users().searchForUserByUserAttributeStream(realm, "ipLogin", "1")) {
|
||||
Optional<UserModel> matchingUser = userStream.filter(user -> {
|
||||
Optional<String> ipChecker = user.getAttributeStream("ipAddresses").filter(ipBlock -> {
|
||||
String[] ipBlocks = ipBlock.split(",");
|
||||
for (String ipOrCidr : ipBlocks) {
|
||||
//System.out.println(ipOrCidr);
|
||||
if (isIpMatch(clientIp, ipOrCidr.trim())) {
|
||||
//System.out.println(clientIp + " match!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}).findFirst();
|
||||
if (ipChecker.isPresent()) {
|
||||
//System.out.println("Check: "+ipChecker);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}).findFirst();
|
||||
|
||||
if (matchingUser.isPresent()) {
|
||||
// Speichere den gefundenen Benutzer für den nächsten Schritt (action)
|
||||
UserModel user = matchingUser.get();
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isIpMatch(String ip, String ipOrCidr) {
|
||||
try {
|
||||
if (ipOrCidr.contains("-")) { // Mehrere IPs nach Schreibweise 192.168.1.1-192.168.1.5
|
||||
String[] parts = ipOrCidr.split("-");
|
||||
String startIp = parts[0].trim();
|
||||
String endIp = parts[1].trim();
|
||||
try {
|
||||
long ipToCheckLong = ipToLong(ip);
|
||||
long startIpLong = ipToLong(startIp);
|
||||
long endIpLong = ipToLong(endIp);
|
||||
return ipToCheckLong >= startIpLong && ipToCheckLong <= endIpLong;
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
} else { // Davon ausgehend, dass es sich nur um eine Adresse handelt
|
||||
return ipOrCidr.equals(ip);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static long ipToLong(String ip) throws UnknownHostException {
|
||||
InetAddress inetAddress = InetAddress.getByName(ip);
|
||||
byte[] ipBytes = inetAddress.getAddress();
|
||||
long result = 0;
|
||||
for (byte b : ipBytes) {
|
||||
result = (result << 8) | (b & 0xFF);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Leere Methoden
|
||||
@Override public boolean requiresUser() { return false; }
|
||||
@Override public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) { return true; }
|
||||
@Override public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {}
|
||||
@Override public void close() {}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
package de.gmp.keycloak;
|
||||
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.authentication.AuthenticatorFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
// import org.keycloak.models.UserModel;
|
||||
// import org.keycloak.models.RealmModel;
|
||||
|
||||
public class IpAuthenticatorFactory implements AuthenticatorFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "ip-authenticator";
|
||||
|
||||
private static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
|
||||
AuthenticationExecutionModel.Requirement.ALTERNATIVE,
|
||||
AuthenticationExecutionModel.Requirement.DISABLED
|
||||
};
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Login per IP";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator create(KeycloakSession session) {
|
||||
return new IpAuthenticator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) { }
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) { }
|
||||
|
||||
@Override
|
||||
public void close() { }
|
||||
|
||||
@Override
|
||||
public boolean isConfigurable() { return false; }
|
||||
|
||||
@Override
|
||||
public boolean isUserSetupAllowed() { return false; }
|
||||
|
||||
@Override
|
||||
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
|
||||
return new AuthenticationExecutionModel.Requirement[]{
|
||||
AuthenticationExecutionModel.Requirement.ALTERNATIVE,
|
||||
AuthenticationExecutionModel.Requirement.DISABLED
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReferenceCategory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Fügt eine 'Login mit 1 Klick'-Option hinzu, wenn die IP-Adresse bei den Attributen eines Benutzers gefunden wurde.";
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user