Index: oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/authentication/external/ExternalLoginTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/authentication/external/ExternalLoginTest.java (revision 1883635) +++ oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/authentication/external/ExternalLoginTest.java (date 1605708800547) @@ -16,39 +16,35 @@ */ package org.apache.jackrabbit.oak.benchmark.authentication.external; -import static javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL; -import static javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT; -import static org.junit.Assert.assertEquals; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import javax.jcr.LoginException; -import javax.jcr.Session; -import javax.jcr.SimpleCredentials; -import javax.security.auth.login.AppConfigurationEntry; -import javax.security.auth.login.Configuration; - +import com.google.common.collect.ImmutableMap; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate; import org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule; import org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl; import org.apache.jackrabbit.oak.spi.security.authentication.AuthenticationConfiguration; import org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule; -import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStats; -import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStatsCollector; import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef; import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModule; import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.jetbrains.annotations.NotNull; -import com.google.common.collect.ImmutableMap; +import javax.jcr.LoginException; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL; +import static javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT; +import static org.junit.Assert.assertEquals; /** * Login against the {@link ExternalLoginModule} with a randomly selected user. @@ -63,19 +59,19 @@ private final int numberOfUsers; private final int numberOfGroups; private final Reporter reporter; - private final LoginModuleStats lmStats; + StatisticsProvider statisticsProvider; private final List auto; private Set uniques; private AtomicLong err; public ExternalLoginTest(int numberOfUsers, int numberOfGroups, long expTime, boolean dynamicMembership, - @NotNull List autoMembership, boolean report, StatisticsProvider statsProvider) { + @NotNull List autoMembership, boolean report, @NotNull StatisticsProvider statsProvider) { super(numberOfUsers, numberOfGroups, expTime, dynamicMembership, autoMembership); this.numberOfUsers = numberOfUsers; this.numberOfGroups = numberOfGroups; this.reporter = new Reporter(report); - this.lmStats = new LoginModuleStats(statsProvider); + this.statisticsProvider = statsProvider; this.auto = autoMembership; } @@ -87,9 +83,7 @@ err = new AtomicLong(); AuthenticationConfiguration authenticationConfiguration = getSecurityProvider() .getConfiguration(AuthenticationConfiguration.class); - if (authenticationConfiguration instanceof LoginModuleStatsCollector) { - ((LoginModuleStatsCollector) authenticationConfiguration).setLoginModuleMonitor(lmStats); - } + authenticationConfiguration.getMonitors(statisticsProvider); } @Override Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/AuthenticationConfigurationImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/AuthenticationConfigurationImpl.java (revision 1883635) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/AuthenticationConfigurationImpl.java (date 1605709043834) @@ -16,7 +16,9 @@ */ package org.apache.jackrabbit.oak.security.authentication; +import java.util.Collections; import java.util.Map; + import org.apache.jackrabbit.oak.api.ContentRepository; import org.apache.jackrabbit.oak.spi.security.ConfigurationBase; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; @@ -25,9 +27,11 @@ import org.apache.jackrabbit.oak.spi.security.authentication.AuthenticationConfiguration; import org.apache.jackrabbit.oak.spi.security.authentication.LoginContextProvider; import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleMonitor; -import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStatsCollector; +import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStats; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardAware; +import org.apache.jackrabbit.oak.stats.Monitor; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.jetbrains.annotations.NotNull; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -51,7 +55,7 @@ */ @Component(service = {AuthenticationConfiguration.class, SecurityConfiguration.class}) @Designate(ocd = AuthenticationConfigurationImpl.Configuration.class) -public class AuthenticationConfigurationImpl extends ConfigurationBase implements AuthenticationConfiguration, LoginModuleStatsCollector { +public class AuthenticationConfigurationImpl extends ConfigurationBase implements AuthenticationConfiguration { @ObjectClassDefinition(name = "Apache Jackrabbit Oak AuthenticationConfiguration") @interface Configuration { @@ -106,6 +110,13 @@ return NAME; } + @NotNull + @Override + public Iterable> getMonitors(@NotNull StatisticsProvider statisticsProvider) { + lmMonitor = new LoginModuleStats(statisticsProvider); + return Collections.singleton(lmMonitor); + } + //----------------------------------------< AuthenticationConfiguration >--- /** * Create a {@code LoginContextProvider} using standard @@ -144,9 +155,4 @@ } return new LoginContextProviderImpl(appName, getParameters(), contentRepository, provider, whiteboard, lmMonitor); } - - @Override - public void setLoginModuleMonitor(@NotNull LoginModuleMonitor lmMonitor) { - this.lmMonitor = lmMonitor; - } } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistration.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistration.java (revision 1883635) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistration.java (date 1605004989936) @@ -16,18 +16,8 @@ */ package org.apache.jackrabbit.oak.security.internal; -import java.io.Closeable; -import java.security.Principal; -import java.util.Collection; -import java.util.Collections; -import java.util.Dictionary; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; - +import com.google.common.collect.Iterables; +import com.google.common.io.Closer; import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager; import org.apache.jackrabbit.oak.commons.PropertiesUtil; import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard; @@ -45,9 +35,6 @@ import org.apache.jackrabbit.oak.spi.security.SecurityProvider; import org.apache.jackrabbit.oak.spi.security.authentication.AuthenticationConfiguration; import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleMBean; -import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleMonitor; -import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStats; -import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStatsCollector; import org.apache.jackrabbit.oak.spi.security.authentication.token.CompositeTokenConfiguration; import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration; import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; @@ -65,6 +52,7 @@ import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableActionProvider; import org.apache.jackrabbit.oak.spi.whiteboard.Registration; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; +import org.apache.jackrabbit.oak.stats.Monitor; import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -86,14 +74,22 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.io.Closer; - import javax.jcr.security.AccessControlManager; +import java.security.Principal; +import java.util.Collection; +import java.util.Collections; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; import static com.google.common.collect.Lists.newArrayList; -import static org.apache.jackrabbit.oak.spi.security.RegistrationConstants.OAK_SECURITY_NAME; import static org.apache.jackrabbit.oak.commons.IOUtils.closeQuietly; import static org.apache.jackrabbit.oak.spi.security.ConfigurationParameters.EMPTY; +import static org.apache.jackrabbit.oak.spi.security.RegistrationConstants.OAK_SECURITY_NAME; import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean; @Component(immediate=true) @@ -518,9 +514,10 @@ properties.put("type", "default"); Whiteboard whiteboard = new OsgiWhiteboard(context); + SecurityProvider securityProvider = createSecurityProvider(whiteboard); ServiceRegistration registration = context.registerService( SecurityProvider.class.getName(), - createSecurityProvider(whiteboard), + securityProvider, properties ); @@ -530,16 +527,15 @@ } closer = Closer.create(); - if (authenticationConfiguration instanceof LoginModuleStatsCollector) { - LoginModuleStats lmMonitor = new LoginModuleStats(statisticsProvider); - ((LoginModuleStatsCollector) authenticationConfiguration).setLoginModuleMonitor(lmMonitor); + Iterable>> monitors = Iterables.transform(securityProvider.getConfigurations(), sc -> sc.getMonitors(statisticsProvider)); + for (Monitor monitor : Iterables.concat(monitors)) { + Registration reg = whiteboard.register(monitor.getMonitorClass(), monitor, monitor.getMonitorProperties()); + closer.register(reg::unregister); - Registration mon = whiteboard.register(LoginModuleMonitor.class, lmMonitor, Collections.emptyMap()); - closer.register((Closeable) mon::unregister); - - Registration mbean = registerMBean(whiteboard, LoginModuleMBean.class, lmMonitor, LoginModuleMBean.TYPE, - "LoginModule statistics"); - closer.register((Closeable) mbean::unregister); + if (monitor instanceof LoginModuleMBean) { + Registration mbean = registerMBean(whiteboard, LoginModuleMBean.class, (LoginModuleMBean) monitor, LoginModuleMBean.TYPE, LoginModuleMBean.NAME); + closer.register(mbean::unregister); + } } log.info("SecurityProvider instance registered"); Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/AuthenticationConfigurationImplTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/AuthenticationConfigurationImplTest.java (revision 1883635) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/AuthenticationConfigurationImplTest.java (date 1605707807307) @@ -16,15 +16,19 @@ */ package org.apache.jackrabbit.oak.security.authentication; +import com.google.common.collect.Iterables; import org.apache.jackrabbit.oak.api.ContentRepository; import org.apache.jackrabbit.oak.security.internal.SecurityProviderBuilder; import org.apache.jackrabbit.oak.spi.security.SecurityProvider; import org.apache.jackrabbit.oak.spi.security.authentication.AuthenticationConfiguration; import org.apache.jackrabbit.oak.spi.security.authentication.LoginContextProvider; import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleMonitor; +import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStats; import org.apache.jackrabbit.oak.spi.whiteboard.DefaultWhiteboard; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardAware; +import org.apache.jackrabbit.oak.stats.Monitor; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.junit.Test; import org.mockito.Mockito; @@ -89,15 +93,17 @@ } @Test - public void testSetLoginModuleMonitor() throws Exception { + public void testGetMonitors() throws Exception { Field f = AuthenticationConfigurationImpl.class.getDeclaredField("lmMonitor"); f.setAccessible(true); - assertSame(LoginModuleMonitor.NOOP, f.get(authConfiguration)); - LoginModuleMonitor monitor = mock(LoginModuleMonitor.class); - authConfiguration.setLoginModuleMonitor(monitor); + StatisticsProvider statisticsProvider = StatisticsProvider.NOOP; + Iterable> monitors = authConfiguration.getMonitors(statisticsProvider); + assertEquals(1, Iterables.size(monitors)); - assertSame(monitor, f.get(authConfiguration)); + Monitor m = monitors.iterator().next(); + assertTrue(m instanceof LoginModuleStats); + assertTrue(f.get(authConfiguration) instanceof LoginModuleStats); } } \ No newline at end of file Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistrationTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistrationTest.java (revision 1883635) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistrationTest.java (date 1605792414327) @@ -51,6 +51,7 @@ import org.apache.jackrabbit.oak.spi.security.authentication.AuthenticationConfiguration; import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleMBean; import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleMonitor; +import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStats; import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStatsCollector; import org.apache.jackrabbit.oak.spi.security.authentication.token.CompositeTokenConfiguration; import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration; @@ -69,6 +70,8 @@ import org.apache.jackrabbit.oak.spi.security.user.UserConstants; import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableActionProvider; import org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider; +import org.apache.jackrabbit.oak.stats.Monitor; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.apache.sling.testing.mock.osgi.junit.OsgiContext; import org.jetbrains.annotations.NotNull; import org.junit.Rule; @@ -81,6 +84,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.Collection; +import java.util.Collections; import java.util.Hashtable; import java.util.List; import java.util.Map; @@ -315,6 +319,7 @@ // register AuthenticationConfiguration to trigger MBean registration AuthenticationConfigurationImpl mockAc = mock(AuthenticationConfigurationImpl.class); + when(mockAc.getMonitors(any(StatisticsProvider.class))).thenReturn(Collections.singleton(new LoginModuleStats(StatisticsProvider.NOOP))); registration.bindAuthenticationConfiguration(mockAc); // register required service @@ -491,7 +496,8 @@ // trigger maybeRegister registration.bindAuthorizationConfiguration(mockConfiguration(AuthorizationConfiguration.class), ConfigurationParameters.of(OAK_SECURITY_NAME, "authorizationId")); - verify(((LoginModuleStatsCollector) ac), times(1)).setLoginModuleMonitor(any(LoginModuleMonitor.class)); + verify(((LoginModuleStatsCollector) ac), never()).setLoginModuleMonitor(any(LoginModuleMonitor.class)); + verify(ac, times(1)).getMonitors(any(StatisticsProvider.class)); } @Test @@ -1082,5 +1088,33 @@ verify(filter1, never()).stop(acMgr, ImmutableSet.of(EveryonePrincipal.getInstance())); verify(filter2, times(1)).stop(acMgr, ImmutableSet.of(EveryonePrincipal.getInstance())); + } + + @Test + public void testRegisterWithMonitors() { + registration.activate(context.bundleContext(), configWithRequiredServiceIds("customAuthorizationConfig")); + assertNull(context.getService(SecurityProvider.class)); + + AuthorizationConfiguration mockConfiguration = mockConfiguration(AuthorizationConfiguration.class); + when(mockConfiguration.getMonitors(any(StatisticsProvider.class))).thenReturn(ImmutableList.of(new TestMonitor())); + + registration.bindAuthorizationConfiguration(mockConfiguration, Collections.singletonMap(SERVICE_PID, "customAuthorizationConfig")); + SecurityProvider service = context.getService(SecurityProvider.class); + assertNotNull(service); + + verify(mockConfiguration, times(1)).getMonitors(any(StatisticsProvider.class)); + } + + private static final class TestMonitor implements Monitor { + + @Override + public @NotNull Class getMonitorClass() { + return TestMonitor.class; + } + + @Override + public @NotNull Map getMonitorProperties() { + return Collections.emptyMap(); + } } } Index: oak-core-spi/src/main/java/org/apache/jackrabbit/oak/stats/Monitor.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core-spi/src/main/java/org/apache/jackrabbit/oak/stats/Monitor.java (date 1605781696714) +++ oak-core-spi/src/main/java/org/apache/jackrabbit/oak/stats/Monitor.java (date 1605781696714) @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.jackrabbit.oak.stats; + +import org.jetbrains.annotations.NotNull; +import org.osgi.annotation.versioning.ProviderType; + +import java.util.Map; + +/** + * Marker interface for monitors that are to be registered with a {@link org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard}. + */ +@ProviderType +public interface Monitor { + + /** + * @return The type to be passed to {@link org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard#register(Class, Object, Map)} + */ + @NotNull + Class getMonitorClass(); + + /** + * @return The properties to be passed to {@link org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard#register(Class, Object, Map)} + */ + @NotNull + Map getMonitorProperties(); +} Index: oak-core-spi/src/main/java/org/apache/jackrabbit/oak/stats/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core-spi/src/main/java/org/apache/jackrabbit/oak/stats/package-info.java (revision 1883635) +++ oak-core-spi/src/main/java/org/apache/jackrabbit/oak/stats/package-info.java (date 1601991888237) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.1.0") +@Version("1.2.0") package org.apache.jackrabbit.oak.stats; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/token/package-info.java (date 1601993672014) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.6.1") +@Version("1.7.0") package org.apache.jackrabbit.oak.spi.security.authentication.token; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleMBean.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleMBean.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleMBean.java (date 1605005040230) @@ -25,6 +25,8 @@ String TYPE = "LoginModuleStats"; + String NAME = "LoginModule statistics"; + long getLoginErrors(); CompositeData getLoginErrorsHistory(); Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleMonitor.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleMonitor.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleMonitor.java (date 1605708835075) @@ -16,10 +16,15 @@ */ package org.apache.jackrabbit.oak.spi.security.authentication; +import org.apache.jackrabbit.oak.stats.Monitor; +import org.jetbrains.annotations.NotNull; import org.osgi.annotation.versioning.ProviderType; +import java.util.Collections; +import java.util.Map; + @ProviderType -public interface LoginModuleMonitor { +public interface LoginModuleMonitor extends Monitor { LoginModuleMonitor NOOP = new LoginModuleMonitor() { @@ -36,4 +41,13 @@ */ void loginError(); + @Override + default @NotNull Class getMonitorClass() { + return LoginModuleMonitor.class; + } + + @Override + default @NotNull Map getMonitorProperties() { + return Collections.emptyMap(); + } } Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleStatsCollector.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleStatsCollector.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleStatsCollector.java (date 1605782457307) @@ -16,9 +16,14 @@ */ package org.apache.jackrabbit.oak.spi.security.authentication; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.jetbrains.annotations.NotNull; import org.osgi.annotation.versioning.ProviderType; +/** + * @deprecated Since Oak 1.38.0 in favor of {@link org.apache.jackrabbit.oak.spi.security.SecurityConfiguration#getMonitors(StatisticsProvider)} + */ +@Deprecated @ProviderType public interface LoginModuleStatsCollector { Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/package-info.java (date 1601992909559) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.4.0") +@Version("1.5.0") package org.apache.jackrabbit.oak.spi.security.authentication; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/package-info.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/package-info.java (date 1601992909555) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.1.1") +@Version("1.2.0") package org.apache.jackrabbit.oak.spi.security.authorization; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/package-info.java (date 1601992909552) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("2.0.0") +@Version("2.1.0") package org.apache.jackrabbit.oak.spi.security.principal; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java (date 1601992868012) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.3.0") +@Version("1.4.0") package org.apache.jackrabbit.oak.spi.security.privilege; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/user/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/user/package-info.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/user/package-info.java (date 1601992878557) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("2.3.1") +@Version("2.4.0") package org.apache.jackrabbit.oak.spi.security.user; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java (date 1605709043838) @@ -44,6 +44,8 @@ import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer; import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer; import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter; +import org.apache.jackrabbit.oak.stats.Monitor; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.osgi.annotation.versioning.ProviderType; @@ -264,6 +266,13 @@ return ctx; } + @NotNull + @Override + public Iterable> getMonitors(@NotNull StatisticsProvider statisticsProvider) { + return Iterables.concat( + Iterables.transform(getConfigurations(), securityConfiguration -> securityConfiguration.getMonitors(statisticsProvider))); + } + private static final class Ranking { private Map m = new ConcurrentHashMap<>(); Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/package-info.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/package-info.java (date 1601992856498) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("2.2.1") +@Version("2.3.0") package org.apache.jackrabbit.oak.spi.security; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java (revision 1883635) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/SecurityConfiguration.java (date 1605708955130) @@ -21,6 +21,8 @@ import java.util.List; import java.util.Set; +import org.apache.jackrabbit.oak.stats.Monitor; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.jetbrains.annotations.NotNull; import org.osgi.annotation.versioning.ProviderType; import org.apache.jackrabbit.oak.spi.commit.CommitHook; @@ -120,6 +122,11 @@ @NotNull Context getContext(); + @NotNull + default Iterable> getMonitors(@NotNull StatisticsProvider statisticsProvider) { + return Collections.emptySet(); + } + /** * Default implementation that provides empty initializers, validators, * commit hooks and parameters. Index: oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleMonitorTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleMonitorTest.java (date 1605703268095) +++ oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleMonitorTest.java (date 1605703268095) @@ -0,0 +1,40 @@ +package org.apache.jackrabbit.oak.spi.security.authentication; + +import org.junit.Test; +import org.mockito.Answers; + +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.withSettings; + +public class LoginModuleMonitorTest { + + private final LoginModuleMonitor noop = spy(LoginModuleMonitor.NOOP); + private final LoginModuleMonitor monitor = mock(LoginModuleMonitor.class, withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS)); + + @Test + public void testLoginError() { + noop.loginError(); + verifyNoInteractions(monitor); + reset(noop, monitor); + + monitor.loginError(); + verifyNoInteractions(noop); + } + + @Test + public void testGetMonitorClass() { + assertSame(LoginModuleMonitor.class, noop.getMonitorClass()); + assertSame(LoginModuleMonitor.class, monitor.getMonitorClass()); + } + + @Test + public void testGetMonitorProperties() { + assertTrue(noop.getMonitorProperties().isEmpty()); + assertTrue(monitor.getMonitorProperties().isEmpty()); + } +} Index: oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleStatsTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleStatsTest.java (revision 1883635) +++ oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/LoginModuleStatsTest.java (date 1605697858443) @@ -29,7 +29,7 @@ public class LoginModuleStatsTest { @Test - public void testLoginError() throws Exception { + public void testLoginError() { ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); StatisticsProvider sp = new DefaultStatisticsProvider(executor); Index: oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java (revision 1883635) +++ oak-security-spi/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java (date 1605709043826) @@ -21,6 +21,7 @@ import java.util.Set; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import org.apache.jackrabbit.oak.plugins.tree.RootProvider; import org.apache.jackrabbit.oak.plugins.tree.TreeProvider; import org.apache.jackrabbit.oak.spi.commit.CommitHook; @@ -31,7 +32,11 @@ import org.apache.jackrabbit.oak.spi.lifecycle.CompositeWorkspaceInitializer; import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer; import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer; +import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleMonitor; +import org.apache.jackrabbit.oak.spi.security.authentication.LoginModuleStats; import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter; +import org.apache.jackrabbit.oak.stats.Monitor; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Before; @@ -384,4 +389,27 @@ assertEquals(ImmutableSet.copyOf(ConfigurationParameters.of(params, params2).keySet()), ImmutableSet.copyOf(compositeParams.keySet())); assertEquals("valueA2", compositeParams.getConfigValue("a", "def")); } + + @Test + public void testGetMonitors() { + StatisticsProvider statisticsProvider = StatisticsProvider.NOOP; + assertTrue(Iterables.isEmpty(compositeConfiguration.getMonitors(statisticsProvider))); + + addConfiguration(new SecurityConfiguration.Default()); + assertTrue(Iterables.isEmpty(compositeConfiguration.getMonitors(statisticsProvider))); + + Monitor monitor = new LoginModuleStats(statisticsProvider); + SecurityConfiguration withMonitors = new SecurityConfiguration.Default() { + @NotNull + @Override + public Iterable> getMonitors(@NotNull StatisticsProvider statisticsProvider) { + return ImmutableList.of(monitor); + } + }; + addConfiguration(withMonitors); + + Iterable> monitors = compositeConfiguration.getMonitors(statisticsProvider); + assertEquals(1, Iterables.size(monitors)); + assertSame(monitor, monitors.iterator().next()); + } }