Add the ability to define multiple authentication services

This commit is contained in:
sebivh
2025-10-17 13:56:15 +02:00
parent 1fc848287e
commit a0157292cc
6 changed files with 97 additions and 12 deletions

View File

@@ -46,7 +46,7 @@ public class Database {
}
}
public void addPlayer(String uuid, String mcusername, LdapUser user) {
public void addPlayer(String uuid, String mcusername, user user) {
String query = "insert into players values (?, ?, ?, ?, ?, ?, ?)";
try(PreparedStatement prep_query = this.statement.getConnection().prepareStatement(query)){
prep_query.setString(1, uuid);

View File

@@ -5,7 +5,7 @@ import javax.naming.directory.Attributes;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LdapUser {
public class User {
public String firstName;
public String lastName;
public String email;
@@ -13,7 +13,16 @@ public class LdapUser {
public int gid;
public String ldapName;
public LdapUser(Attributes attributes) {
public User(String firstName, String lastName, String email, int uid, int gid, String ldapName) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.uid = uid;
this.gid = gid;
this.ldapName = ldapName;
}
public User(Attributes attributes) {
firstName = trimAttribute(attributes.get("givenname"));
lastName = trimAttribute(attributes.get("sn"));
email = trimAttribute(attributes.get("mail"));

View File

@@ -0,0 +1,8 @@
package de.sebastianvonhelmersen.authentication;
import de.sebastianvonhelmersen.User;
public interface Authenticator {
public boolean authenticate(String username, String token);
public User getUser(String username);
}

View File

@@ -0,0 +1,55 @@
package de.sebastianvonhelmersen.authentication;
import de.sebastianvonhelmersen.User;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
public class FetSite implements Authenticator {
private final byte[] masterPassword;
private final MessageDigest digest;
public FetSite(String masterPassword) {
this.masterPassword = masterPassword.getBytes(StandardCharsets.UTF_8);
// Setup hashing Class
try {
this.digest = MessageDigest.getInstance("SHA-256");
}
catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/*
Token: base64(hash(<username>) XOR <masterpasswd>)
*/
public boolean authenticate(String username, String token) {
byte[] byteToken = token.getBytes(StandardCharsets.UTF_8);
// Hash username to make comparison
byte[] userNameHash = digest.digest(username.getBytes(StandardCharsets.UTF_8));
// Decode token
// Ensure both have the same length
int length = Math.min(byteToken.length, userNameHash.length);
byte[] result = new byte[length];
// XOR each byte
for (int i = 0; i < length; i++) {
result[i] = (byte) (byteToken[i] ^ this.masterPassword[i]);
}
byte[] dec_token = Base64.getDecoder().decode(result);
// Compare hash and decoded token
return Arrays.equals(dec_token, userNameHash);
}
public User getUser(String username) {
return new User("", "", "", 0, 0, username);
}
}

View File

@@ -1,4 +1,7 @@
package de.sebastianvonhelmersen;
package de.sebastianvonhelmersen.authentication;
import de.sebastianvonhelmersen.User;
import de.sebastianvonhelmersen.user;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
@@ -16,7 +19,7 @@ public class Ldap {
private static final String LDAP_URL = "ldap://juri:389";
private static final String BASE_DN = "dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at";
private static final String ADMIN_DN = "cn=admin,dc=fet,dc=htu,dc=tuwien,dc=ac,dc=at"; // service account
public static LdapUser authenticate(String username, String password) {
public static User authenticate(String username, String password) {
try {
// 1. Bind as admin/service account
@@ -75,7 +78,7 @@ public class Ldap {
new InitialDirContext(authEnv).close(); // bind attempt
return new LdapUser(result.getAttributes()); // success
return new user(result.getAttributes()); // success
} catch (Exception e) {
e.printStackTrace();

View File

@@ -1,5 +1,8 @@
package de.sebastianvonhelmersen;
import de.sebastianvonhelmersen.authentication.Authenticator;
import de.sebastianvonhelmersen.authentication.FetSite;
import de.sebastianvonhelmersen.authentication.Ldap;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
@@ -23,11 +26,13 @@ import java.util.logging.Level;
public class fetmcplugin extends JavaPlugin implements Listener {
private Database db;
private Map<UUID, AuthInfos> allInfos = HashMap.newHashMap(0);
private Authenticator authenticator;
@Override
public void onEnable() {
// Make sure the plugin's data folder exists
File dataFolder = this.getDataFolder();
this.authenticator = new FetSite("MyokpBxpqxw9Eo8IduwH9IFSnBy4qII6");
if (!dataFolder.exists()) {
dataFolder.mkdirs();
@@ -145,10 +150,10 @@ public class fetmcplugin extends JavaPlugin implements Listener {
Component.text("§eBitte gib das Password deines FET Accounts ein!"));
break;
case AUTH_WAITING_PASSWORD:
LdapUser user = checkLdap(info.getUsername(), message.trim());
boolean valid = validate(info.getUsername(), message.trim());
event.setCancelled(true);
event.getRecipients().clear();
if(user != null) {
if(valid) {
allInfos.remove(uuid);
this.db.addPlayer(uuid.toString(), event.getPlayer().getName(), user);
Bukkit.getScheduler().runTask(this, () -> {
@@ -177,11 +182,16 @@ public class fetmcplugin extends JavaPlugin implements Listener {
return;
}
private LdapUser checkLdap(String username, String password) {
/*
* This function uses the defined Authenticator instance to authenticate the User against their
* provided username - token combination
* @param username the username used to authenticate the player with the provider
* @param token some sort of authentication methon. Can be Password, AppPassword or some other form of token the
* provider takes to authenticate the user
*/
private boolean validate(String username, String token) {
getLogger().log(Level.INFO, "Checking LDAP for user " + username);
return Ldap.authenticate(username, password);
//return true;
return authenticator.authenticate(username, token);
}
}