diff --git a/CHANGELOG.md b/CHANGELOG.md index c5cfdffaa..69e40e4d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ make sure to check and update your HELM settings. * Fixed a typo in the helm variable rewriteTarget. * Fixed security queries running as normal user, resulting in too narrow access. * Improved the memory efficiency of the DataArray resultFormat. +* Added checks for maximum username and password lengths. ## Release version 2.2.0 diff --git a/FROST-Server.Auth.Basic/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/basic/BasicAuthFilter.java b/FROST-Server.Auth.Basic/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/basic/BasicAuthFilter.java index f21e5d0ca..caa463b80 100644 --- a/FROST-Server.Auth.Basic/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/basic/BasicAuthFilter.java +++ b/FROST-Server.Auth.Basic/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/basic/BasicAuthFilter.java @@ -40,10 +40,14 @@ import static de.fraunhofer.iosb.ilt.frostserver.auth.basic.BasicAuthProvider.TAG_HTTP_ROLE_PATCH; import static de.fraunhofer.iosb.ilt.frostserver.auth.basic.BasicAuthProvider.TAG_HTTP_ROLE_POST; import static de.fraunhofer.iosb.ilt.frostserver.auth.basic.BasicAuthProvider.TAG_HTTP_ROLE_PUT; +import static de.fraunhofer.iosb.ilt.frostserver.auth.basic.BasicAuthProvider.TAG_MAX_PASSWORD_LENGTH; +import static de.fraunhofer.iosb.ilt.frostserver.auth.basic.BasicAuthProvider.TAG_MAX_USERNAME_LENGTH; import static de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings.TAG_AUTHENTICATE_ONLY; import static de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings.TAG_AUTH_ALLOW_ANON_READ; import static de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings.TAG_AUTH_ROLE_ADMIN; import static de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings.TAG_CORE_SETTINGS; +import static de.fraunhofer.iosb.ilt.frostserver.util.user.UserData.MAX_PASSWORD_LENGTH; +import static de.fraunhofer.iosb.ilt.frostserver.util.user.UserData.MAX_USERNAME_LENGTH; import de.fraunhofer.iosb.ilt.frostserver.settings.ConfigDefaults; import de.fraunhofer.iosb.ilt.frostserver.settings.ConfigUtils; @@ -86,6 +90,8 @@ public class BasicAuthFilter implements Filter { private boolean allowAnonymous; private boolean authenticateOnly; + private int maxPassLength = MAX_PASSWORD_LENGTH; + private int maxNameLength = MAX_USERNAME_LENGTH; private final Map methodCheckers = new EnumMap<>(HttpMethod.class); private DatabaseHandler databaseHandler; @@ -121,6 +127,9 @@ public void init(FilterConfig filterConfig) throws ServletException { String realmName = authSettings.get(TAG_AUTH_REALM_NAME, BasicAuthProvider.class); authHeaderValue = "Basic realm=\"" + realmName + "\", charset=\"UTF-8\""; + maxPassLength = authSettings.getInt(TAG_MAX_PASSWORD_LENGTH, BasicAuthProvider.class); + maxNameLength = authSettings.getInt(TAG_MAX_USERNAME_LENGTH, BasicAuthProvider.class); + final AuthChecker allAllowed = (userData, response) -> true; methodCheckers.put(HttpMethod.OPTIONS, allAllowed); methodCheckers.put(HttpMethod.HEAD, allAllowed); @@ -152,7 +161,7 @@ private UserData findCredentials(HttpServletRequest request) { } String[] split = userPassDecoded.split(":", 2); - final UserData userData = new UserData(split[0], split[1]); + final UserData userData = new UserData(split[0], maxNameLength, split[1], maxPassLength); if (databaseHandler.isValidUser(userData)) { return userData; } else { diff --git a/FROST-Server.Auth.Basic/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/basic/BasicAuthProvider.java b/FROST-Server.Auth.Basic/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/basic/BasicAuthProvider.java index 52c3e0f2b..c87e9f84f 100644 --- a/FROST-Server.Auth.Basic/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/basic/BasicAuthProvider.java +++ b/FROST-Server.Auth.Basic/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/basic/BasicAuthProvider.java @@ -18,6 +18,8 @@ package de.fraunhofer.iosb.ilt.frostserver.auth.basic; import static de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings.TAG_AUTH_ROLE_ADMIN; +import static de.fraunhofer.iosb.ilt.frostserver.util.user.UserData.MAX_PASSWORD_LENGTH; +import static de.fraunhofer.iosb.ilt.frostserver.util.user.UserData.MAX_USERNAME_LENGTH; import de.fraunhofer.iosb.ilt.frostserver.settings.ConfigDefaults; import de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings; @@ -53,6 +55,12 @@ public class BasicAuthProvider implements AuthProvider, LiquibaseUser, ConfigDef @DefaultValueInt(10) public static final String TAG_MAX_CLIENTS_PER_USER = "maxClientsPerUser"; + @DefaultValueInt(MAX_PASSWORD_LENGTH) + public static final String TAG_MAX_PASSWORD_LENGTH = "maxPasswordLength"; + + @DefaultValueInt(MAX_USERNAME_LENGTH) + public static final String TAG_MAX_USERNAME_LENGTH = "maxUsernameLength"; + @DefaultValue("FROST-Server") public static final String TAG_AUTH_REALM_NAME = "realmName"; @@ -70,6 +78,8 @@ public class BasicAuthProvider implements AuthProvider, LiquibaseUser, ConfigDef private CoreSettings coreSettings; private String roleAdmin; private int maxClientsPerUser; + private int maxPassLength = MAX_PASSWORD_LENGTH; + private int maxNameLength = MAX_USERNAME_LENGTH; private final Map clientidToUserinfo = new ConcurrentHashMap<>(); private final Map usernameToUserinfo = new ConcurrentHashMap<>(); @@ -81,6 +91,8 @@ public void init(CoreSettings coreSettings) { final Settings authSettings = coreSettings.getAuthSettings(); roleAdmin = authSettings.get(TAG_AUTH_ROLE_ADMIN, CoreSettings.class); maxClientsPerUser = authSettings.getInt(TAG_MAX_CLIENTS_PER_USER, getClass()); + maxPassLength = authSettings.getInt(TAG_MAX_PASSWORD_LENGTH, getClass()); + maxNameLength = authSettings.getInt(TAG_MAX_USERNAME_LENGTH, getClass()); } @Override @@ -90,7 +102,7 @@ public void addFilter(Object context, CoreSettings coreSettings) { @Override public boolean isValidUser(String clientId, String userName, String password) { - final UserData userData = new UserData(userName, password); + final UserData userData = new UserData(userName, maxNameLength, password, maxPassLength); final boolean validUser = DatabaseHandler.getInstance(coreSettings) .isValidUser(userData); if (!validUser) { diff --git a/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakAuthProvider.java b/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakAuthProvider.java index fc854d00c..3c43984bc 100644 --- a/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakAuthProvider.java +++ b/FROST-Server.Auth.Keycloak/src/main/java/de/fraunhofer/iosb/ilt/frostserver/auth/keycloak/KeycloakAuthProvider.java @@ -18,6 +18,8 @@ package de.fraunhofer.iosb.ilt.frostserver.auth.keycloak; import static de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings.TAG_AUTH_ROLE_ADMIN; +import static de.fraunhofer.iosb.ilt.frostserver.util.user.UserData.MAX_PASSWORD_LENGTH; +import static de.fraunhofer.iosb.ilt.frostserver.util.user.UserData.MAX_USERNAME_LENGTH; import de.fraunhofer.iosb.ilt.frostserver.settings.ConfigDefaults; import de.fraunhofer.iosb.ilt.frostserver.settings.CoreSettings; @@ -89,6 +91,12 @@ public class KeycloakAuthProvider implements AuthProvider, LiquibaseUser, Config @DefaultValue("USER_NAME") public static final String TAG_USERNAME_COLUMN = "usernameColumn"; + @DefaultValueInt(MAX_PASSWORD_LENGTH) + public static final String TAG_MAX_PASSWORD_LENGTH = "maxPasswordLength"; + + @DefaultValueInt(MAX_USERNAME_LENGTH) + public static final String TAG_MAX_USERNAME_LENGTH = "maxUsernameLength"; + /** * The logger for this class. */ @@ -107,6 +115,8 @@ public class KeycloakAuthProvider implements AuthProvider, LiquibaseUser, Config private int maxClientsPerUser; private boolean registerUserLocally; private DatabaseHandler databaseHandler; + private int maxPassLength = MAX_PASSWORD_LENGTH; + private int maxNameLength = MAX_USERNAME_LENGTH; private final Map clientidToUserinfo = new ConcurrentHashMap<>(); private final Map usernameToUserinfo = new ConcurrentHashMap<>(); @@ -125,6 +135,8 @@ public void init(CoreSettings coreSettings) { final Settings authSettings = coreSettings.getAuthSettings(); roleAdmin = authSettings.get(TAG_AUTH_ROLE_ADMIN, CoreSettings.class); maxClientsPerUser = authSettings.getInt(TAG_MAX_CLIENTS_PER_USER, getClass()); + maxPassLength = authSettings.getInt(TAG_MAX_PASSWORD_LENGTH, getClass()); + maxNameLength = authSettings.getInt(TAG_MAX_USERNAME_LENGTH, getClass()); registerUserLocally = authSettings.getBoolean(TAG_REGISTER_USER_LOCALLY, KeycloakAuthProvider.class); if (registerUserLocally) { DatabaseHandler.init(coreSettings); @@ -148,7 +160,7 @@ public boolean isValidUser(String clientId, String username, String password) { loginModule = new DirectAccessGrantsLoginModuleFrost(coreSettings); } - final UserData userData = new UserData(username, password); + final UserData userData = new UserData(username, maxNameLength, password, maxPassLength); clientMapCleanup(); final boolean validUser = checkLogin(loginModule, userData, clientId); diff --git a/FROST-Server.Util/src/main/java/de/fraunhofer/iosb/ilt/frostserver/util/user/UserData.java b/FROST-Server.Util/src/main/java/de/fraunhofer/iosb/ilt/frostserver/util/user/UserData.java index 96eda385d..2c3e53175 100644 --- a/FROST-Server.Util/src/main/java/de/fraunhofer/iosb/ilt/frostserver/util/user/UserData.java +++ b/FROST-Server.Util/src/main/java/de/fraunhofer/iosb/ilt/frostserver/util/user/UserData.java @@ -19,17 +19,51 @@ import java.util.LinkedHashSet; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A wrapper for userName, userPass and userRoles. */ public class UserData { + private static final Logger LOGGER = LoggerFactory.getLogger(UserData.class); + public static final int MAX_PASSWORD_LENGTH = 128; + public static final int MAX_USERNAME_LENGTH = 128; + public final String userName; public final String userPass; public final Set roles = new LinkedHashSet<>(); + /** + * Create a new UserData with the standard maximum username and password + * lengths. + * + * @param userName the user name to use. + * @param userPass the password to use. + */ public UserData(String userName, String userPass) { + this(userName, MAX_USERNAME_LENGTH, userPass, MAX_PASSWORD_LENGTH); + } + + /** + * Create a new UserData with the given maximum username and password + * lengths. + * + * @param userName the user name to use. + * @param maxNameLength the maximum length of the username to check for. + * @param userPass the password to use. + * @param maxPassLength the maximum length of the password to check for. + */ + public UserData(String userName, int maxNameLength, String userPass, int maxPassLength) { + if (userName != null && userName.length() > maxNameLength) { + LOGGER.error("Password too long, aborting."); + throw new IllegalArgumentException("Password too long."); + } + if (userPass != null && userPass.length() > maxPassLength) { + LOGGER.error("Password too long, aborting."); + throw new IllegalArgumentException("Password too long."); + } this.userName = userName; this.userPass = userPass; }