Skip to content

Commit

Permalink
Added cache to basic authentication module
Browse files Browse the repository at this point in the history
  • Loading branch information
hylkevds committed Feb 22, 2024
1 parent 65330a5 commit e1410d1
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ make sure to check and update your HELM settings.
* 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.
* Added cache to basic authentication module to avoid calling crypt for users that are previously authenticated.


## Release version 2.2.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ public class BasicAuthProvider implements AuthProvider, LiquibaseUser, ConfigDef
@DefaultValueInt(MAX_USERNAME_LENGTH)
public static final String TAG_MAX_USERNAME_LENGTH = "maxUsernameLength";

@DefaultValueInt(60_000)
public static final String TAG_USER_CACHE_LIFE_MS = "userCacheLifeMs";

@DefaultValue("FROST-Server")
public static final String TAG_AUTH_REALM_NAME = "realmName";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static de.fraunhofer.iosb.ilt.frostserver.auth.basic.BasicAuthProvider.LIQUIBASE_CHANGELOG_FILENAME;
import static de.fraunhofer.iosb.ilt.frostserver.auth.basic.BasicAuthProvider.TAG_AUTO_UPDATE_DATABASE;
import static de.fraunhofer.iosb.ilt.frostserver.auth.basic.BasicAuthProvider.TAG_PLAIN_TEXT_PASSWORD;
import static de.fraunhofer.iosb.ilt.frostserver.auth.basic.BasicAuthProvider.TAG_USER_CACHE_LIFE_MS;
import static de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.ConnectionUtils.TAG_DB_URL;

import de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.ConnectionUtils;
Expand All @@ -38,6 +39,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.collections4.map.PassiveExpiringMap;
import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.Record1;
Expand Down Expand Up @@ -66,6 +68,8 @@ public class DatabaseHandler {
private final String connectionUrl;
private boolean maybeUpdateDatabase;

private PassiveExpiringMap<UserData, UserData> cache;

public static void init(CoreSettings coreSettings) {
if (INSTANCES.get(coreSettings) == null) {
createInstance(coreSettings);
Expand Down Expand Up @@ -93,6 +97,11 @@ private DatabaseHandler(CoreSettings coreSettings) {
maybeUpdateDatabase = authSettings.getBoolean(TAG_AUTO_UPDATE_DATABASE, BasicAuthProvider.class);
plainTextPassword = authSettings.getBoolean(TAG_PLAIN_TEXT_PASSWORD, BasicAuthProvider.class);
connectionUrl = authSettings.get(TAG_DB_URL, ConnectionUtils.class, false);
int userCacheLifeMs = authSettings.getInt(TAG_USER_CACHE_LIFE_MS, BasicAuthProvider.class);
if (userCacheLifeMs > 0) {
LOGGER.info("Enabling user cache.");
cache = new PassiveExpiringMap<>(userCacheLifeMs);
}
}

public boolean isPlainTextPassword() {
Expand All @@ -113,6 +122,11 @@ private Condition passwordCondition(String passwordOrHash) {
* @return true if the user is value
*/
public boolean isValidUser(UserData userData) {
final UserData cachedData = getFromCache(userData);
if (cachedData != null) {
userData.roles.addAll(cachedData.roles);
return true;
}
maybeUpdateDatabase();
try (final ConnectionWrapper connectionProvider = new ConnectionWrapper(authSettings, connectionUrl)) {
final DSLContext dslContext = DSL.using(connectionProvider.get(), SQLDialect.POSTGRES);
Expand All @@ -128,13 +142,39 @@ public boolean isValidUser(UserData userData) {
.stream()
.filter(Objects::nonNull)
.forEach(userData.roles::add);
return !roles.isEmpty();
boolean valid = !roles.isEmpty();
if (valid) {
addToCache(userData);
}
return valid;
} catch (SQLException | RuntimeException exc) {
LOGGER.error("Failed to check user credentials.", exc);
return false;
}
}

public UserData getFromCache(UserData userData) {
if (cache == null) {
return null;
}
try {
return cache.get(userData);
} catch (RuntimeException ex) {
LOGGER.debug("Failed to check cache.", ex);
return null;
}
}

public void addToCache(UserData userData) {
if (cache != null) {
try {
cache.put(userData, userData);
} catch (RuntimeException exc) {
LOGGER.debug("Failed to fill cache.", exc);
}
}
}

/**
* This method checks if the given user exists with the given password and
* has the given role.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package de.fraunhofer.iosb.ilt.frostserver.util.user;

import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -76,4 +77,30 @@ public boolean isEmpty() {
return userName == null;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final UserData other = (UserData) obj;
if (!Objects.equals(this.userName, other.userName)) {
return false;
}
return Objects.equals(this.userPass, other.userPass);
}

@Override
public int hashCode() {
int hash = 7;
hash = 71 * hash + Objects.hashCode(this.userName);
hash = 71 * hash + Objects.hashCode(this.userPass);
return hash;
}

}

0 comments on commit e1410d1

Please sign in to comment.