Add the ability to define multiple authentication services
This commit is contained in:
@@ -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 (?, ?, ?, ?, ?, ?, ?)";
|
String query = "insert into players values (?, ?, ?, ?, ?, ?, ?)";
|
||||||
try(PreparedStatement prep_query = this.statement.getConnection().prepareStatement(query)){
|
try(PreparedStatement prep_query = this.statement.getConnection().prepareStatement(query)){
|
||||||
prep_query.setString(1, uuid);
|
prep_query.setString(1, uuid);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import javax.naming.directory.Attributes;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class LdapUser {
|
public class User {
|
||||||
public String firstName;
|
public String firstName;
|
||||||
public String lastName;
|
public String lastName;
|
||||||
public String email;
|
public String email;
|
||||||
@@ -13,7 +13,16 @@ public class LdapUser {
|
|||||||
public int gid;
|
public int gid;
|
||||||
public String ldapName;
|
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"));
|
firstName = trimAttribute(attributes.get("givenname"));
|
||||||
lastName = trimAttribute(attributes.get("sn"));
|
lastName = trimAttribute(attributes.get("sn"));
|
||||||
email = trimAttribute(attributes.get("mail"));
|
email = trimAttribute(attributes.get("mail"));
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.Context;
|
||||||
import javax.naming.NamingEnumeration;
|
import javax.naming.NamingEnumeration;
|
||||||
@@ -16,7 +19,7 @@ public class Ldap {
|
|||||||
private static final String LDAP_URL = "ldap://juri:389";
|
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 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
|
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 {
|
try {
|
||||||
// 1. Bind as admin/service account
|
// 1. Bind as admin/service account
|
||||||
@@ -75,7 +78,7 @@ public class Ldap {
|
|||||||
|
|
||||||
new InitialDirContext(authEnv).close(); // bind attempt
|
new InitialDirContext(authEnv).close(); // bind attempt
|
||||||
|
|
||||||
return new LdapUser(result.getAttributes()); // success
|
return new user(result.getAttributes()); // success
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package de.sebastianvonhelmersen;
|
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 net.kyori.adventure.text.Component;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
@@ -23,11 +26,13 @@ import java.util.logging.Level;
|
|||||||
public class fetmcplugin extends JavaPlugin implements Listener {
|
public class fetmcplugin extends JavaPlugin implements Listener {
|
||||||
private Database db;
|
private Database db;
|
||||||
private Map<UUID, AuthInfos> allInfos = HashMap.newHashMap(0);
|
private Map<UUID, AuthInfos> allInfos = HashMap.newHashMap(0);
|
||||||
|
private Authenticator authenticator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
// Make sure the plugin's data folder exists
|
// Make sure the plugin's data folder exists
|
||||||
File dataFolder = this.getDataFolder();
|
File dataFolder = this.getDataFolder();
|
||||||
|
this.authenticator = new FetSite("MyokpBxpqxw9Eo8IduwH9IFSnBy4qII6");
|
||||||
|
|
||||||
if (!dataFolder.exists()) {
|
if (!dataFolder.exists()) {
|
||||||
dataFolder.mkdirs();
|
dataFolder.mkdirs();
|
||||||
@@ -145,10 +150,10 @@ public class fetmcplugin extends JavaPlugin implements Listener {
|
|||||||
Component.text("§eBitte gib das Password deines FET Accounts ein!"));
|
Component.text("§eBitte gib das Password deines FET Accounts ein!"));
|
||||||
break;
|
break;
|
||||||
case AUTH_WAITING_PASSWORD:
|
case AUTH_WAITING_PASSWORD:
|
||||||
LdapUser user = checkLdap(info.getUsername(), message.trim());
|
boolean valid = validate(info.getUsername(), message.trim());
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
event.getRecipients().clear();
|
event.getRecipients().clear();
|
||||||
if(user != null) {
|
if(valid) {
|
||||||
allInfos.remove(uuid);
|
allInfos.remove(uuid);
|
||||||
this.db.addPlayer(uuid.toString(), event.getPlayer().getName(), user);
|
this.db.addPlayer(uuid.toString(), event.getPlayer().getName(), user);
|
||||||
Bukkit.getScheduler().runTask(this, () -> {
|
Bukkit.getScheduler().runTask(this, () -> {
|
||||||
@@ -177,11 +182,16 @@ public class fetmcplugin extends JavaPlugin implements Listener {
|
|||||||
return;
|
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);
|
getLogger().log(Level.INFO, "Checking LDAP for user " + username);
|
||||||
return Ldap.authenticate(username, password);
|
return authenticator.authenticate(username, token);
|
||||||
//return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user