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

Reply via email to