This is an automated email from the ASF dual-hosted git repository.

bossenti pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new db41c7d35 feat(#2269): Add basic auth to prometheus monitoring 
endpoint (#2270)
db41c7d35 is described below

commit db41c7d3506b9d5cae6363399ed723b07b8ebd42
Author: Dominik Riemer <[email protected]>
AuthorDate: Thu Dec 7 12:30:56 2023 +0100

    feat(#2269): Add basic auth to prometheus monitoring endpoint (#2270)
    
    * feat(#2269): Add basic auth to prometheus monitoring endpoint
    
    * Use constants for auth
    
    * refactor: rename variable
    
    ---------
    
    Co-authored-by: bossenti <[email protected]>
---
 .../commons/constants/HttpConstants.java           |  1 +
 .../security/UnauthorizedRequestEntryPoint.java    |  2 +-
 .../core/filter/TokenAuthenticationFilter.java     | 44 +++++++++++++++++++++-
 3 files changed, 45 insertions(+), 2 deletions(-)

diff --git 
a/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/HttpConstants.java
 
b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/HttpConstants.java
index 63dece4bb..9866f10e8 100644
--- 
a/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/HttpConstants.java
+++ 
b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/HttpConstants.java
@@ -26,5 +26,6 @@ public class HttpConstants {
   public static final String APPLICATION_JSON_TYPE = "application/json";
   public static final String X_API_USER = "X-API-USER";
   public static final String X_API_KEY = "X-API-KEY";
+  public static final String BASIC = "Basic ";
 
 }
diff --git 
a/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/security/UnauthorizedRequestEntryPoint.java
 
b/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/security/UnauthorizedRequestEntryPoint.java
index 144a990dc..94304a6d5 100644
--- 
a/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/security/UnauthorizedRequestEntryPoint.java
+++ 
b/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/security/UnauthorizedRequestEntryPoint.java
@@ -35,7 +35,7 @@ public class UnauthorizedRequestEntryPoint implements 
AuthenticationEntryPoint {
   @Override
   public void commence(HttpServletRequest httpServletRequest, 
HttpServletResponse httpServletResponse,
                        AuthenticationException e) throws IOException {
-    LOG.error("Unauthorized request to {}", httpServletRequest.getPathInfo());
+    LOG.error("Unauthorized request to {}", 
httpServletRequest.getServletPath());
 
     httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, 
e.getLocalizedMessage());
   }
diff --git 
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/filter/TokenAuthenticationFilter.java
 
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/filter/TokenAuthenticationFilter.java
index e389f4afb..ac4c83359 100644
--- 
a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/filter/TokenAuthenticationFilter.java
+++ 
b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/filter/TokenAuthenticationFilter.java
@@ -24,15 +24,18 @@ import 
org.apache.streampipes.model.client.user.ServiceAccount;
 import org.apache.streampipes.model.client.user.UserAccount;
 import org.apache.streampipes.storage.api.IUserStorage;
 import org.apache.streampipes.storage.management.StorageDispatcher;
+import 
org.apache.streampipes.user.management.encryption.SecretEncryptionManager;
 import org.apache.streampipes.user.management.jwt.JwtTokenProvider;
 import org.apache.streampipes.user.management.model.PrincipalUserDetails;
 import org.apache.streampipes.user.management.model.ServiceAccountDetails;
 import org.apache.streampipes.user.management.model.UserAccountDetails;
 import org.apache.streampipes.user.management.service.TokenService;
+import org.apache.streampipes.user.management.util.PasswordUtil;
 import org.apache.streampipes.user.management.util.TokenUtil;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
 import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.context.SecurityContextHolder;
 import 
org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
@@ -45,12 +48,20 @@ import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
 import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Base64;
+import java.util.List;
 
 public class TokenAuthenticationFilter extends OncePerRequestFilter {
 
   private final JwtTokenProvider tokenProvider;
   private final IUserStorage userStorage;
 
+  private final List<String> supportedBasicAuthPaths = List.of(
+      "/actuator/prometheus"
+  );
+
   private static final Logger logger = 
LoggerFactory.getLogger(TokenAuthenticationFilter.class);
 
   public TokenAuthenticationFilter() {
@@ -68,7 +79,7 @@ public class TokenAuthenticationFilter extends 
OncePerRequestFilter {
       if (StringUtils.hasText(jwt) && tokenProvider.validateJwtToken(jwt)) {
         String username = tokenProvider.getUserIdFromToken(jwt);
         applySuccessfulAuth(request, username);
-      } else {
+      } else if (isApiKeyAuth(request)) {
         String apiKey = getApiKeyFromRequest(request);
         String apiUser = getApiUserFromRequest(request);
         if (StringUtils.hasText(apiKey) && StringUtils.hasText(apiUser)) {
@@ -78,6 +89,22 @@ public class TokenAuthenticationFilter extends 
OncePerRequestFilter {
             applySuccessfulAuth(request, apiUser);
           }
         }
+      } else {
+        var authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
+        if (authorizationHeader != null && 
authorizationHeader.startsWith(HttpConstants.BASIC)) {
+          if (supportedBasicAuthPaths.contains(request.getServletPath())) {
+            String base64Credentials = 
authorizationHeader.substring(HttpConstants.BASIC.length()).trim();
+            String credentials = new 
String(Base64.getDecoder().decode(base64Credentials));
+
+            String[] splitCredentials = credentials.split(":");
+            String username = splitCredentials[0];
+            String passphrase = splitCredentials[1];
+            var principal = 
StorageDispatcher.INSTANCE.getNoSqlStore().getUserStorageAPI().getUser(username);
+            if (principal != null && checkCredentials(principal, passphrase)) {
+              applySuccessfulAuth(request, username);
+            }
+          }
+        }
       }
     } catch (Exception ex) {
       logger.error("Could not set user authentication in security context", 
ex);
@@ -86,6 +113,21 @@ public class TokenAuthenticationFilter extends 
OncePerRequestFilter {
     filterChain.doFilter(request, response);
   }
 
+  private boolean checkCredentials(Principal principal, String passphrase)
+      throws NoSuchAlgorithmException, InvalidKeySpecException {
+    if (principal instanceof UserAccount) {
+      return PasswordUtil.validatePassword(passphrase, ((UserAccount) 
principal).getPassword());
+    } else if (principal instanceof ServiceAccount) {
+      return 
passphrase.equals(SecretEncryptionManager.decrypt(((ServiceAccount) 
principal).getClientSecret()));
+    } else {
+      throw new IllegalArgumentException("Unknown user instance");
+    }
+  }
+
+  private boolean isApiKeyAuth(HttpServletRequest request) {
+    return request.getHeader(HttpConstants.X_API_USER) != null && 
request.getHeader(HttpConstants.X_API_KEY) != null;
+  }
+
   private void applySuccessfulAuth(HttpServletRequest request,
                                    String username) {
     Principal user = userStorage.getUser(username);

Reply via email to