This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-core.git
The following commit(s) were added to refs/heads/master by this push:
new 3354e1a SLING-10164 : Add basic metrics to SlingAuthenticator (#7)
3354e1a is described below
commit 3354e1ace2c68a3555e251668cdb4a29a4eb4c4a
Author: anchela <[email protected]>
AuthorDate: Fri Mar 19 07:20:04 2021 +0100
SLING-10164 : Add basic metrics to SlingAuthenticator (#7)
* SLING-10164 : Add basic metrics to SlingAuthenticator (initial proposal
with minimal testing)
* SLING-10164 : Add basic metrics to SlingAuthenticator (review findings)
Co-authored-by: angela <[email protected]>
---
pom.xml | 17 ++++
.../auth/core/impl/SlingAuthenticationMetrics.java | 52 +++++++++++++
.../sling/auth/core/impl/SlingAuthenticator.java | 35 +++++++--
.../core/impl/SlingAuthenticationMetricsTest.java | 87 +++++++++++++++++++++
.../auth/core/impl/SlingAuthenticatorOsgiTest.java | 91 ++++++++++++++++++++++
5 files changed, 274 insertions(+), 8 deletions(-)
diff --git a/pom.xml b/pom.xml
index fbb407f..dfbfab8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -124,6 +124,17 @@
<version>1.4</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.metrics</artifactId>
+ <version>1.2.8</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jetbrains</groupId>
+ <artifactId>annotations</artifactId>
+ <version>18.0.0</version>
+ <scope>provided</scope>
+ </dependency>
<!-- Test Dependencies -->
<dependency>
@@ -152,5 +163,11 @@
<version>15.0</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+ <version>3.0.0</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git
a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticationMetrics.java
b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticationMetrics.java
new file mode 100644
index 0000000..17a24bf
--- /dev/null
+++
b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticationMetrics.java
@@ -0,0 +1,52 @@
+/*
+ * 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.sling.auth.core.impl;
+
+import org.apache.sling.commons.metrics.Meter;
+import org.apache.sling.commons.metrics.MetricsService;
+import org.apache.sling.commons.metrics.Timer;
+import org.jetbrains.annotations.NotNull;
+
+class SlingAuthenticationMetrics {
+
+ static final String AUTHENTICATE_TIMER_NAME =
"sling.auth.core.authenticate.timer";
+ static final String AUTHENTICATE_SUCCESS_METER_NAME =
"sling.auth.core.authenticate.success";
+ static final String AUTHENTICATE_FAILED_METER_NAME =
"sling.auth.core.authenticate.failed";
+
+ private final Timer authenticateTimer;
+ private final Meter authenticateSuccess;
+ private final Meter authenticateFailed;
+
+ SlingAuthenticationMetrics(@NotNull MetricsService metricsService) {
+ authenticateTimer = metricsService.timer(AUTHENTICATE_TIMER_NAME);
+ authenticateSuccess =
metricsService.meter(AUTHENTICATE_SUCCESS_METER_NAME);
+ authenticateFailed =
metricsService.meter(AUTHENTICATE_FAILED_METER_NAME);
+ }
+
+ @NotNull
+ Timer.Context authenticationTimerContext() {
+ return authenticateTimer.time();
+ }
+
+ void authenticateCompleted(boolean success) {
+ if (success) {
+ authenticateSuccess.mark();
+ } else {
+ authenticateFailed.mark();
+ }
+ }
+}
\ No newline at end of file
diff --git
a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
index a14393a..5d1a329 100644
--- a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
+++ b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
@@ -60,6 +60,8 @@ import org.apache.sling.auth.core.spi.AuthenticationHandler;
import org.apache.sling.auth.core.spi.AuthenticationInfo;
import org.apache.sling.auth.core.spi.AuthenticationInfoPostProcessor;
import org.apache.sling.auth.core.spi.DefaultAuthenticationFeedbackHandler;
+import org.apache.sling.commons.metrics.MetricsService;
+import org.apache.sling.commons.metrics.Timer;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
@@ -333,6 +335,10 @@ public class SlingAuthenticator implements Authenticator,
@Reference(policy=ReferencePolicy.DYNAMIC, cardinality =
ReferenceCardinality.OPTIONAL)
private volatile EventAdmin eventAdmin;
+ @Reference
+ private MetricsService metricsService;
+ private SlingAuthenticationMetrics metrics;
+
// ---------- SCR integration
@Activate
@@ -363,6 +369,8 @@ public class SlingAuthenticator implements Authenticator,
bundleContext, authHandlerCache);
authInfoPostProcessorTracker = new ServiceTracker(bundleContext,
AuthenticationInfoPostProcessor.class, null);
authInfoPostProcessorTracker.open();
+
+ metrics = new SlingAuthenticationMetrics(metricsService);
}
@Modified
@@ -457,6 +465,11 @@ public class SlingAuthenticator implements Authenticator,
webConsolePlugin.unregister();
webConsolePlugin = null;
}
+
+ metricsService = null;
+ if (metrics != null) {
+ metrics = null;
+ }
}
// --------- AuthenticationSupport interface
@@ -492,15 +505,21 @@ public class SlingAuthenticator implements Authenticator,
request.removeAttribute(REQUEST_ATTRIBUTE_RESOLVER);
}
- boolean process = doHandleSecurity(request, response);
- if (process && expectAuthenticationHandler(request)) {
- log.warn("handleSecurity: AuthenticationHandler did not block
request; access denied");
- request.removeAttribute(AuthenticationHandler.FAILURE_REASON);
- request.removeAttribute(AuthenticationHandler.FAILURE_REASON_CODE);
- AuthUtil.sendInvalid(request, response);
- return false;
+ Timer.Context ctx = metrics.authenticationTimerContext();
+ boolean process = false;
+ try {
+ process = doHandleSecurity(request, response);
+ if (process && expectAuthenticationHandler(request)) {
+ log.warn("handleSecurity: AuthenticationHandler did not block
request; access denied");
+ request.removeAttribute(AuthenticationHandler.FAILURE_REASON);
+
request.removeAttribute(AuthenticationHandler.FAILURE_REASON_CODE);
+ AuthUtil.sendInvalid(request, response);
+ process = false;
+ }
+ } finally {
+ ctx.stop();
+ metrics.authenticateCompleted(process);
}
-
return process;
}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticationMetricsTest.java
b/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticationMetricsTest.java
new file mode 100644
index 0000000..d184194
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticationMetricsTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.sling.auth.core.impl;
+
+import org.apache.sling.commons.metrics.Meter;
+import org.apache.sling.commons.metrics.MetricsService;
+import org.apache.sling.commons.metrics.Timer;
+import org.junit.Before;
+import org.junit.Test;
+
+import static
org.apache.sling.auth.core.impl.SlingAuthenticationMetrics.AUTHENTICATE_FAILED_METER_NAME;
+import static
org.apache.sling.auth.core.impl.SlingAuthenticationMetrics.AUTHENTICATE_SUCCESS_METER_NAME;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class SlingAuthenticationMetricsTest {
+
+ private Meter successMeter = mock(Meter.class);
+ private Meter failedMeter = mock(Meter.class);
+ private Timer.Context ctx = mock(Timer.Context.class);
+ private Timer timer = mock(Timer.class);
+ private final MetricsService metricsService = mock(MetricsService.class);
+
+ private SlingAuthenticationMetrics metrics;
+
+ @Before
+ public void before() {
+ when(timer.time()).thenReturn(ctx);
+
when(metricsService.meter(AUTHENTICATE_SUCCESS_METER_NAME)).thenReturn(successMeter);
+
when(metricsService.meter(AUTHENTICATE_FAILED_METER_NAME)).thenReturn(failedMeter);
+ when(metricsService.timer(anyString())).thenReturn(timer);
+
+ metrics = new SlingAuthenticationMetrics(metricsService);
+
+ verify(metricsService).timer(anyString());
+ verify(metricsService, times(2)).meter(anyString());
+ }
+
+ @Test
+ public void testAuthenticationCompletedSuccess() {
+ metrics.authenticateCompleted(true);
+ verify(successMeter, times(1)).mark();
+ verify(failedMeter, never()).mark();
+ verifyNoMoreInteractions(successMeter, failedMeter);
+ verifyNoInteractions(timer, ctx);
+ }
+
+ @Test
+ public void testAuthenticationCompletedFailed() {
+ metrics.authenticateCompleted(false);
+ verify(failedMeter, times(1)).mark();
+ verify(successMeter, never()).mark();
+ verifyNoMoreInteractions(successMeter, failedMeter);
+ verifyNoInteractions(timer, ctx);
+ }
+
+ @Test
+ public void testAuthenticationTimerContext() {
+ Timer.Context timerContext = metrics.authenticationTimerContext();
+ timerContext.stop();
+
+ verify(timer).time();
+ verify(ctx).stop();
+ verifyNoMoreInteractions(timer, ctx);
+ verifyNoInteractions(successMeter, failedMeter);
+ }
+}
\ No newline at end of file
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorOsgiTest.java
b/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorOsgiTest.java
new file mode 100644
index 0000000..588337e
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorOsgiTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.sling.auth.core.impl;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.auth.core.spi.AuthenticationInfo;
+import org.apache.sling.commons.metrics.Meter;
+import org.apache.sling.commons.metrics.MetricsService;
+import org.apache.sling.commons.metrics.Timer;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import static
org.apache.sling.auth.core.impl.SlingAuthenticationMetrics.AUTHENTICATE_FAILED_METER_NAME;
+import static
org.apache.sling.auth.core.impl.SlingAuthenticationMetrics.AUTHENTICATE_SUCCESS_METER_NAME;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+public class SlingAuthenticatorOsgiTest {
+
+ @Rule
+ public final OsgiContext context = new OsgiContext();
+
+ private Meter successMeter = mock(Meter.class);
+ private Meter failedMeter = mock(Meter.class);
+ private Timer.Context ctx = mock(Timer.Context.class);
+ private Timer timer = mock(Timer.class);
+ private final MetricsService metricsService = mock(MetricsService.class);
+
+ private final SlingAuthenticator authenticator = new SlingAuthenticator();
+
+ @Before
+ public void before() throws Exception {
+ ResourceResolver rr = mock(ResourceResolver.class);
+ ResourceResolverFactory resourceResolverFactory =
mock(ResourceResolverFactory.class);
+
when(resourceResolverFactory.getResourceResolver(any(AuthenticationInfo.class))).thenReturn(rr);
+
+ when(timer.time()).thenReturn(ctx);
+
when(metricsService.meter(AUTHENTICATE_SUCCESS_METER_NAME)).thenReturn(successMeter);
+
when(metricsService.meter(AUTHENTICATE_FAILED_METER_NAME)).thenReturn(failedMeter);
+ when(metricsService.timer(anyString())).thenReturn(timer);
+
+ context.registerService(ResourceResolverFactory.class,
resourceResolverFactory);
+ context.registerService(MetricsService.class, metricsService);
+ context.registerInjectActivateService(authenticator);
+ }
+
+ @Test
+ public void testHandleSecurity() {
+ HttpServletRequest req = mock(HttpServletRequest.class);
+ when(req.getServletPath()).thenReturn("/");
+ when(req.getServerName()).thenReturn("localhost");
+ when(req.getServerPort()).thenReturn(80);
+ when(req.getScheme()).thenReturn("http");
+ when(req.getRequestURI()).thenReturn("http://localhost:80/");
+
+ HttpServletResponse resp = mock(HttpServletResponse.class);
+ authenticator.handleSecurity(req, resp);
+
+ verify(timer).time();
+ verify(ctx).stop();
+ verify(successMeter).mark();
+ verifyNoMoreInteractions(timer, successMeter, ctx);
+ verifyNoInteractions((failedMeter));
+ }
+
+}
\ No newline at end of file