Skip to content

Commit

Permalink
Merge branch 'igniterealtime:main' into OF-2559_mina-to-netty
Browse files Browse the repository at this point in the history
  • Loading branch information
viv authored Jul 25, 2023
2 parents ca54c54 + 9fea45d commit 50b87a2
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 212 deletions.
4 changes: 4 additions & 0 deletions i18n/src/main/resources/openfire_i18n.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1715,6 +1715,10 @@ system_property.adminConsole.forwarded.for.header=The HTTP header name for 'forw
system_property.adminConsole.forwarded.server.header=The HTTP header name for 'forwarded server'.
system_property.adminConsole.forwarded.host.header=The HTTP header name for 'forwarded hosts'.
system_property.adminConsole.forwarded.host.name=Sets a forced valued for the host header.
system_property.adminConsole.maxAttemptsPerIP=Maximum number of Admin Console login attempts per IP address that can be performed in a given time frame.
system_property.adminConsole.perIPAttemptResetInterval=Time frame before Admin Console login attempts per IP address are reset.
system_property.adminConsole.maxAttemptsPerUsername=Maximum number of Admin Console login attempts per username that can be performed in a given time frame.
system_property.adminConsole.perUsernameAttemptResetInterval=Time frame before Admin Console login attempts per username are reset.
system_property.xmpp.muc.muclumbus.v1-0.enabled=Determine is the multi-user chat "muclumbus" (v1.0) search feature is enabled.
system_property.xmpp.muc.join.presence=Setting the presence send of participants joining in MUC rooms.
system_property.xmpp.muc.join.self-presence-timeout=Maximum duration to wait for presence to be broadcast while joining a MUC room.
Expand Down
4 changes: 4 additions & 0 deletions i18n/src/main/resources/openfire_i18n_nl.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,10 @@ system_property.adminConsole.forwarded.for.header=De naam van de HTTP header voo
system_property.adminConsole.forwarded.server.header=De naam van de HTTP header voor 'forwarded server'.
system_property.adminConsole.forwarded.host.header=De naam van de HTTP header voor 'forwarded hosts'.
system_property.adminConsole.forwarded.host.name=Zet een gefoceerde waarde voor de host header.
system_property.adminConsole.maxAttemptsPerIP=Maximaal aantal inlogpoginging voor de beheerconsole, per IP, in een bepaald tijdsbestek.
system_property.adminConsole.perIPAttemptResetInterval=Tijdsbestek waarna inlogpogingen voor de beheerconsole, per IP, worden gereset.
system_property.adminConsole.maxAttemptsPerUsername=Maximaal aantal inlogpoginging voor de beheerconsole, per gebruikersnaam, in een bepaald tijdsbestek.
system_property.adminConsole.perUsernameAttemptResetInterval=Tijdsbestek waarna inlogpogingen voor de beheerconsole, per gebruikersnaam, worden gereset.
system_property.xmpp.muc.muclumbus.v1-0.enabled=Definieert of de multi-user chat "muclumbus" (v1.0) zoekfunctionaliteit wordt geactiveerd.
system_property.xmpp.muc.join.presence=Wissel statusinformatie uit als een nieuwe participant een MUC ruimte binnentreedt.
system_property.xmpp.muc.join.self-presence-timeout=Maximale wachttijd voor omgeroepen status informatie tijdens het binnentreden van een MUC ruimte.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2009 Jive Software, 2022 Ignite Realtime Foundation. All rights reserved.
* Copyright (C) 2004-2009 Jive Software, 2022-2023 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,12 +17,13 @@
package org.jivesoftware.admin;

import org.jivesoftware.openfire.security.SecurityAuditManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.SystemProperty;
import org.jivesoftware.util.TaskEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -52,14 +53,38 @@ public static LoginLimitManager getInstance() {
}

// Max number of attempts per ip address that can be performed in given time frame
private long maxAttemptsPerIP;
public static final SystemProperty<Long> MAX_ATTEMPTS_PER_IP = SystemProperty.Builder.ofType(Long.class)
.setKey("adminConsole.maxAttemptsPerIP")
.setDynamic(true)
.setDefaultValue(10L)
.setMinValue(1L)
.build();

// Time frame before attempts per ip addresses are reset
private Duration millisecondsBetweenPerIP;
public static final SystemProperty<Duration> PER_IP_ATTEMPT_RESET_INTERVAL = SystemProperty.Builder.ofType(Duration.class)
.setKey("adminConsole.perIPAttemptResetInterval")
.setDynamic(false)
.setChronoUnit(ChronoUnit.MILLIS)
.setDefaultValue(Duration.ofMinutes(15))
.setMinValue(Duration.ofMillis(1))
.build();

// Max number of attempts per username that can be performed in a given time frame
private long maxAttemptsPerUsername;
public static final SystemProperty<Long> MAX_ATTEMPTS_PER_USERNAME = SystemProperty.Builder.ofType(Long.class)
.setKey("adminConsole.maxAttemptsPerUsername")
.setDynamic(true)
.setDefaultValue(10L)
.setMinValue(1L)
.build();

// Time frame before attempts per username are reset
private Duration millisecondsBetweenPerUsername;
public static final SystemProperty<Duration> PER_USERNAME_ATTEMPT_RESET_INTERVAL = SystemProperty.Builder.ofType(Duration.class)
.setKey("adminConsole.perUsernameAttemptResetInterval")
.setDynamic(false)
.setChronoUnit(ChronoUnit.MILLIS)
.setDefaultValue(Duration.ofMinutes(15))
.setMinValue(Duration.ofMillis(1))
.build();

// Record of attempts per IP address
private Map<String,Long> attemptsPerIP;
Expand All @@ -82,18 +107,10 @@ private LoginLimitManager() {
attemptsPerIP = new ConcurrentHashMap<>();
attemptsPerUsername = new ConcurrentHashMap<>();

// Max number of attempts per ip address that can be performed in given time frame (10 attempts default)
maxAttemptsPerIP = JiveGlobals.getLongProperty("adminConsole.maxAttemptsPerIP", 10);
// Time frame before attempts per ip addresses are reset (15 minutes default)
millisecondsBetweenPerIP = Duration.ofMillis(JiveGlobals.getLongProperty("adminConsole.perIPAttemptResetInterval", 900000));
// Max number of attempts per username that can be performed in a given time frame (10 attempts default)
maxAttemptsPerUsername = JiveGlobals.getLongProperty("adminConsole.maxAttemptsPerUsername", 10);
// Time frame before attempts per ip addresses are reset (15 minutes default)
millisecondsBetweenPerUsername = Duration.ofMillis(JiveGlobals.getLongProperty("adminConsole.perUsernameAttemptResetInterval", 900000));
// Set up per username attempt reset task
taskEngine.scheduleAtFixedRate(new PerUsernameTask(), Duration.ZERO, millisecondsBetweenPerUsername);
taskEngine.scheduleAtFixedRate(new PerUsernameTask(), Duration.ZERO, PER_USERNAME_ATTEMPT_RESET_INTERVAL.getValue());
// Set up per IP attempt reset task
taskEngine.scheduleAtFixedRate(new PerIPAddressTask(), Duration.ZERO, millisecondsBetweenPerIP);
taskEngine.scheduleAtFixedRate(new PerIPAddressTask(), Duration.ZERO, PER_IP_ATTEMPT_RESET_INTERVAL.getValue());
}

/**
Expand All @@ -104,10 +121,10 @@ private LoginLimitManager() {
* @return True if the login attempt limit has been hit.
*/
public boolean hasHitConnectionLimit(String username, String address) {
if (attemptsPerIP.get(address) != null && attemptsPerIP.get(address) > maxAttemptsPerIP) {
if (attemptsPerIP.get(address) != null && attemptsPerIP.get(address) > MAX_ATTEMPTS_PER_IP.getValue()) {
return true;
}
if (attemptsPerUsername.get(username) != null && attemptsPerUsername.get(username) > maxAttemptsPerUsername) {
if (attemptsPerUsername.get(username) != null && attemptsPerUsername.get(username) > MAX_ATTEMPTS_PER_USERNAME.getValue()) {
return true;
}
// No problem then, no limit hit.
Expand All @@ -130,7 +147,7 @@ public void recordFailedAttempt(String username, String address) {
cnt++;
attemptsPerIP.put(address, cnt);
final StringBuilder sb = new StringBuilder();
if (cnt > maxAttemptsPerIP) {
if (cnt > MAX_ATTEMPTS_PER_IP.getValue()) {
Log.warn("Login attempt limit breached for address "+address);
sb.append("Future login attempts from this address will be temporarily locked out. ");
}
Expand All @@ -141,7 +158,7 @@ public void recordFailedAttempt(String username, String address) {
}
cnt++;
attemptsPerUsername.put(username, cnt);
if (cnt > maxAttemptsPerUsername) {
if (cnt > MAX_ATTEMPTS_PER_USERNAME.getValue()) {
Log.warn("Login attempt limit breached for username "+username);
sb.append("Future login attempts for this user will be temporarily locked out. ");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ private void saveProperty(final HttpServletRequest request, final WebManager web
final boolean oldEncrypt = JiveGlobals.isPropertyEncrypted(key);
final String oldValueToLog = oldEncrypt ? "***********" : JiveGlobals.getProperty(key);
final String value = request.getParameter("value");
final boolean encrypt = ParamUtils.getBooleanAttribute(request, "encrypt");
final boolean encrypt = ParamUtils.getBooleanParameter(request, "encrypt");
final boolean alreadyExists = JiveGlobals.getProperty(key) != null;
JiveGlobals.setProperty(key, value, encrypt);
request.getSession().setAttribute("successMessage",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 IgniteRealtime.org
* Copyright 2016-2023 Ignite Realtime Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -350,68 +350,67 @@ public boolean accept( final Path path ) throws IOException
// plugins always precede their children.
final Deque<List<Path>> dirs = sortPluginDirs( ds, devPlugins );

// Hierarchy processing could be parallel.
final Collection<Callable<Integer>> parallelProcesses = new ArrayList<>();
for ( final List<Path> hierarchy : dirs )
// Before running any plugin, make sure that the admin plugin is loaded. It is a dependency
// of all plugins that attempt to modify the admin panel.
if ( pluginManager.getPlugin( "admin" ) == null )
{
parallelProcesses.add( new Callable<Integer>()
{
pluginManager.loadPlugin( "admin", dirs.getFirst().get( 0 ) );
}

@Override
public Integer call() throws Exception
// Prevent trying to read properties from the database while we're still in setup mode.
if (!XMPPServer.getInstance().isSetupMode())
{
// Hierarchy processing could be parallel.
final Collection<Callable<Integer>> parallelProcesses = new ArrayList<>();
for ( final List<Path> hierarchy : dirs )
{
parallelProcesses.add( new Callable<Integer>()
{
int loaded = 0;
for ( final Path path : hierarchy )

@Override
public Integer call() throws Exception
{
// If the plugin hasn't already been started, start it.
final String canonicalName = PluginMetadataHelper.getCanonicalName( path );
if ( pluginManager.getPlugin( canonicalName ) == null )
int loaded = 0;
for ( final Path path : hierarchy )
{
if ( pluginManager.loadPlugin( canonicalName, path ) )
// If the plugin hasn't already been started, start it.
final String canonicalName = PluginMetadataHelper.getCanonicalName( path );
if ( pluginManager.getPlugin( canonicalName ) == null )
{
loaded++;
if ( pluginManager.loadPlugin( canonicalName, path ) )
{
loaded++;
}
}
}

return loaded;
}
} );
}

return loaded;
// Hierarchies could be processed in parallel. This is likely to be beneficial during the first
// execution of this monitor, as during later executions, most plugins will likely already be loaded.
final int parallelProcessMax = JiveGlobals.getIntProperty("plugins.loading.max-parallel", 4);
final int parallelProcessCount = (pluginManager.isExecuted() ? 1 : parallelProcessMax);
final ThreadFactory threadFactory = new NamedThreadFactory("PluginMonitorExec-", Executors.defaultThreadFactory(), false, Thread.NORM_PRIORITY);
final ExecutorService executorService = Executors.newFixedThreadPool(parallelProcessCount, threadFactory);
try {
// Blocks until ready
final List<Future<Integer>> futures = executorService.invokeAll(parallelProcesses);

// Unless nothing happened, report that we're done loading plugins.
int pluginsLoaded = 0;
for (Future<Integer> future : futures) {
pluginsLoaded += future.get();
}
} );
}

// Before running any plugin, make sure that the admin plugin is loaded. It is a dependency
// of all plugins that attempt to modify the admin panel.
if ( pluginManager.getPlugin( "admin" ) == null )
{
pluginManager.loadPlugin( "admin", dirs.getFirst().get( 0 ) );
}

// Hierarchies could be processed in parallel. This is likely to be beneficial during the first
// execution of this monitor, as during later executions, most plugins will likely already be loaded.
final int parallelProcessMax = JiveGlobals.getIntProperty( "plugins.loading.max-parallel", 4 );
final int parallelProcessCount = ( pluginManager.isExecuted() ? 1 : parallelProcessMax );
final ThreadFactory threadFactory = new NamedThreadFactory("PluginMonitorExec-", Executors.defaultThreadFactory(), false, Thread.NORM_PRIORITY);
final ExecutorService executorService = Executors.newFixedThreadPool( parallelProcessCount, threadFactory );
try
{
// Blocks until ready
final List<Future<Integer>> futures = executorService.invokeAll( parallelProcesses );

// Unless nothing happened, report that we're done loading plugins.
int pluginsLoaded = 0;
for ( Future<Integer> future : futures )
{
pluginsLoaded += future.get();
}
if ( pluginsLoaded > 0 && !XMPPServer.getInstance().isSetupMode() )
{
Log.info( "Finished processing all plugins." );
if (pluginsLoaded > 0) {
Log.info("Finished processing all plugins.");
}
} finally {
executorService.shutdown();
}
}
finally
{
executorService.shutdown();
}

// Trigger event that plugins have been monitored
pluginManager.firePluginsMonitored();
Expand Down
Loading

0 comments on commit 50b87a2

Please sign in to comment.