You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2022/04/25 12:07:46 UTC

[incubator-streampipes] branch dev updated: [STREAMPIPES-534] Add support for authenticated extension services

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

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


The following commit(s) were added to refs/heads/dev by this push:
     new 3fd875939 [STREAMPIPES-534] Add support for authenticated extension services
3fd875939 is described below

commit 3fd8759399b51d7753d893d2ccf348107fc40e2b
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Mon Apr 25 14:07:36 2022 +0200

    [STREAMPIPES-534] Add support for authenticated extension services
---
 pom.xml                                            |  5 ++
 .../streampipes/backend/WebSecurityConfig.java     |  3 +-
 .../apache/streampipes/commons/constants/Envs.java |  1 +
 streampipes-connect-container-worker/pom.xml       |  7 ++
 .../extensions/ExtensionsModelSubmitter.java       |  3 +-
 .../org/apache/streampipes/model}/UserInfo.java    |  2 +-
 .../impl/admin/GeneralConfigurationResource.java   |  2 +-
 .../streampipes/security/jwt/JwtTokenUtils.java    |  5 ++
 .../streampipes/security/jwt/KeyGenerator.java     |  3 +-
 .../security/jwt/PublicKeyResolver.java            | 30 ++++---
 streampipes-service-base/pom.xml                   |  4 +
 .../service/base/rest/BaseResourceConfig.java      |  2 +
 .../security}/UnauthorizedRequestEntryPoint.java   |  4 +-
 .../extensions/base}/WebSecurityConfig.java        | 83 +++++++++++--------
 .../base/security/TokenAuthenticationFilter.java   | 92 ++++++++++++++++++++++
 .../base/security/UnauthenticatedInterfaces.java   | 24 +++---
 .../user/management/util/UserInfoUtil.java         |  2 +-
 .../src/lib/model/gen/streampipes-model-client.ts  | 23 +-----
 .../src/lib/model/gen/streampipes-model.ts         | 29 ++++++-
 19 files changed, 234 insertions(+), 90 deletions(-)

diff --git a/pom.xml b/pom.xml
index b43ff174d..e35c0f417 100644
--- a/pom.xml
+++ b/pom.xml
@@ -389,6 +389,11 @@ IoT data streams.
 					<artifactId>jaxb-api</artifactId>
 					<version>2.3.1</version>
 				</dependency>
+				<dependency>
+					<groupId>net.minidev</groupId>
+					<artifactId>json-smart</artifactId>
+					<version>1.3.3</version>
+				</dependency>
 				<dependency>
 					<groupId>org.apache.httpcomponents</groupId>
 					<artifactId>fluent-hc</artifactId>
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java
index e882c8ceb..b33d9b07e 100644
--- a/streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java
+++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java
@@ -19,6 +19,7 @@
 package org.apache.streampipes.backend;
 
 import org.apache.streampipes.rest.filter.TokenAuthenticationFilter;
+import org.apache.streampipes.service.base.security.UnauthorizedRequestEntryPoint;
 import org.apache.streampipes.user.management.service.SpUserDetailsService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
@@ -40,7 +41,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
   private final UserDetailsService userDetailsService;
-  private StreamPipesPasswordEncoder passwordEncoder;
+  private final StreamPipesPasswordEncoder passwordEncoder;
 
   public WebSecurityConfig(StreamPipesPasswordEncoder passwordEncoder) {
     this.passwordEncoder = passwordEncoder;
diff --git a/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
index 954d3d953..217f649fd 100644
--- a/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
+++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
@@ -32,6 +32,7 @@ public enum Envs {
   SP_INITIAL_SERVICE_USER("SP_INITIAL_SERVICE_USER"),
   SP_INITIAL_SERVICE_USER_SECRET("SP_INITIAL_SERVICE_USER_SECRET"),
   SP_SETUP_INSTALL_PIPELINE_ELEMENTS("SP_SETUP_INSTALL_PIPELINE_ELEMENTS"),
+  SP_EXT_AUTH_MODE("SP_EXT_AUTH_MODE"),
   SP_CLIENT_USER("SP_CLIENT_USER"),
   SP_CLIENT_SECRET("SP_CLIENT_SECRET"),
   SP_ENCRYPTION_PASSCODE("SP_ENCRYPTION_PASSCODE"),
diff --git a/streampipes-connect-container-worker/pom.xml b/streampipes-connect-container-worker/pom.xml
index 6b6b20700..dc1e74b88 100644
--- a/streampipes-connect-container-worker/pom.xml
+++ b/streampipes-connect-container-worker/pom.xml
@@ -66,6 +66,13 @@
         </dependency>
         <!-- External dependencies -->
 
+
+        <!-- Dependency convergence -->
+        <dependency>
+            <groupId>net.minidev</groupId>
+            <artifactId>json-smart</artifactId>
+        </dependency>
+
         <!-- Test dependencies -->
         <dependency>
             <groupId>com.github.tomakehurst</groupId>
diff --git a/streampipes-container-extensions/src/main/java/org/apache/streampipes/container/extensions/ExtensionsModelSubmitter.java b/streampipes-container-extensions/src/main/java/org/apache/streampipes/container/extensions/ExtensionsModelSubmitter.java
index 63b8d1570..d0e97de0a 100644
--- a/streampipes-container-extensions/src/main/java/org/apache/streampipes/container/extensions/ExtensionsModelSubmitter.java
+++ b/streampipes-container-extensions/src/main/java/org/apache/streampipes/container/extensions/ExtensionsModelSubmitter.java
@@ -24,6 +24,7 @@ import org.apache.streampipes.container.model.SpServiceDefinition;
 import org.apache.streampipes.container.standalone.init.PipelineElementServiceShutdownHandler;
 import org.apache.streampipes.container.standalone.init.PipelineElementServiceTagProvider;
 import org.apache.streampipes.service.extensions.base.StreamPipesExtensionsServiceBase;
+import org.apache.streampipes.service.extensions.base.WebSecurityConfig;
 import org.apache.streampipes.svcdiscovery.api.model.SpServiceTag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,7 +37,7 @@ import java.util.List;
 
 @Configuration
 @EnableAutoConfiguration
-@Import({ ExtensionsResourceConfig.class })
+@Import({ ExtensionsResourceConfig.class, WebSecurityConfig.class})
 public abstract class ExtensionsModelSubmitter extends StreamPipesExtensionsServiceBase {
 
     private static final Logger LOG =
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java b/streampipes-model/src/main/java/org/apache/streampipes/model/UserInfo.java
similarity index 97%
rename from streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java
rename to streampipes-model/src/main/java/org/apache/streampipes/model/UserInfo.java
index 4295f8497..9a8b200ae 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/UserInfo.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  *
  */
-package org.apache.streampipes.model.client.user;
+package org.apache.streampipes.model;
 
 
 import org.apache.streampipes.model.shared.annotation.TsModel;
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/GeneralConfigurationResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/GeneralConfigurationResource.java
index ad41cc80d..91cd5ab9d 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/GeneralConfigurationResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/GeneralConfigurationResource.java
@@ -78,7 +78,7 @@ public class GeneralConfigurationResource extends AbstractAuthGuardedRestResourc
     return Response.ok(multiPartEntity).build();
   }
 
-  private String exportKeyAsPem(Key key, String keyType) throws Exception {
+  private String exportKeyAsPem(Key key, String keyType) {
     StringWriter sw = new StringWriter();
 
     sw.write("-----BEGIN " + keyType + " KEY-----\n");
diff --git a/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/JwtTokenUtils.java b/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/JwtTokenUtils.java
index 6163c61d1..1ea45ce8f 100644
--- a/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/JwtTokenUtils.java
+++ b/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/JwtTokenUtils.java
@@ -37,6 +37,11 @@ public class JwtTokenUtils {
     return jwtParser(resolver).parseClaimsJws(token).getBody().getSubject();
   }
 
+  public static Claims getClaimsFromToken(String token,
+                                          SigningKeyResolver resolver) {
+    return jwtParser(resolver).parseClaimsJws(token).getBody();
+  }
+
   public static JwtParser jwtParser(String tokenSecret) {
     return Jwts.parserBuilder()
             .setSigningKey(tokenSecret.getBytes(StandardCharsets.UTF_8))
diff --git a/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/KeyGenerator.java b/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/KeyGenerator.java
index b62087147..bbd3f64ad 100644
--- a/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/KeyGenerator.java
+++ b/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/KeyGenerator.java
@@ -54,8 +54,7 @@ public class KeyGenerator {
       try {
         return makeKeyForRsa(pkContent);
       } catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) {
-        e.printStackTrace();
-        LOG.warn("Could not properly create the provided key, defaulting to an HMAC token, which will almost certainly lead to problems");
+        LOG.error("Could not properly create the provided key, defaulting to an HMAC token, which will almost certainly lead to problems");
         return makeKeyForSecret(tokenSecret);
       }
     } else {
diff --git a/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java b/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/PublicKeyResolver.java
similarity index 56%
copy from streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java
copy to streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/PublicKeyResolver.java
index 2233be263..96c07e8ae 100644
--- a/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java
+++ b/streampipes-security-jwt/src/main/java/org/apache/streampipes/security/jwt/PublicKeyResolver.java
@@ -15,20 +15,30 @@
  * limitations under the License.
  *
  */
-package org.apache.streampipes.service.base.rest;
 
-import org.glassfish.jersey.server.ResourceConfig;
+package org.apache.streampipes.security.jwt;
 
-import java.util.List;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwsHeader;
+import io.jsonwebtoken.SigningKeyResolver;
 
-public abstract class BaseResourceConfig extends ResourceConfig {
+import java.io.IOException;
+import java.security.Key;
 
-  public BaseResourceConfig() {
-    getClassesToRegister()
-            .forEach(set -> set.forEach(this::register));
-    register(ServiceHealthResource.class);
-  }
+public class PublicKeyResolver implements SigningKeyResolver {
 
-  public abstract List<List<Class<?>>> getClassesToRegister();
+  @Override
+  public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) {
+    try {
+      return new KeyGenerator().makeKeyForSecret(jwsHeader.getAlgorithm(), "");
+    } catch (IOException e) {
+      e.printStackTrace();
+      return null;
+    }
+  }
 
+  @Override
+  public Key resolveSigningKey(JwsHeader jwsHeader, String s) {
+    return null;
+  }
 }
diff --git a/streampipes-service-base/pom.xml b/streampipes-service-base/pom.xml
index fe03bad89..41e0ddfc5 100644
--- a/streampipes-service-base/pom.xml
+++ b/streampipes-service-base/pom.xml
@@ -67,6 +67,10 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-undertow</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-oauth2-client</artifactId>
+        </dependency>
 
         <!--dependency convergence-->
         <dependency>
diff --git a/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java b/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java
index 2233be263..7e5d1d77d 100644
--- a/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java
+++ b/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java
@@ -18,12 +18,14 @@
 package org.apache.streampipes.service.base.rest;
 
 import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.servlet.ServletProperties;
 
 import java.util.List;
 
 public abstract class BaseResourceConfig extends ResourceConfig {
 
   public BaseResourceConfig() {
+    property(ServletProperties.FILTER_FORWARD_ON_404, true);
     getClassesToRegister()
             .forEach(set -> set.forEach(this::register));
     register(ServiceHealthResource.class);
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/UnauthorizedRequestEntryPoint.java b/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/security/UnauthorizedRequestEntryPoint.java
similarity index 92%
rename from streampipes-backend/src/main/java/org/apache/streampipes/backend/UnauthorizedRequestEntryPoint.java
rename to streampipes-service-base/src/main/java/org/apache/streampipes/service/base/security/UnauthorizedRequestEntryPoint.java
index 181c178e3..91528c8ee 100644
--- a/streampipes-backend/src/main/java/org/apache/streampipes/backend/UnauthorizedRequestEntryPoint.java
+++ b/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/security/UnauthorizedRequestEntryPoint.java
@@ -16,7 +16,7 @@
  *
  */
 
-package org.apache.streampipes.backend;
+package org.apache.streampipes.service.base.security;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,7 +33,7 @@ public class UnauthorizedRequestEntryPoint implements AuthenticationEntryPoint {
 
 	@Override
 	public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
-		LOG.error("Unauthorized request - {}", e.getMessage());
+		LOG.error("Unauthorized request to {}", httpServletRequest.getPathInfo());
 
 		httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getLocalizedMessage());
 	}
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java b/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/WebSecurityConfig.java
similarity index 50%
copy from streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java
copy to streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/WebSecurityConfig.java
index e882c8ceb..ada8748ea 100644
--- a/streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java
+++ b/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/WebSecurityConfig.java
@@ -16,15 +16,16 @@
  *
  */
 
-package org.apache.streampipes.backend;
+package org.apache.streampipes.service.extensions.base;
 
-import org.apache.streampipes.rest.filter.TokenAuthenticationFilter;
-import org.apache.streampipes.user.management.service.SpUserDetailsService;
+import org.apache.streampipes.commons.constants.Envs;
+import org.apache.streampipes.service.base.security.UnauthorizedRequestEntryPoint;
+import org.apache.streampipes.service.extensions.base.security.TokenAuthenticationFilter;
+import org.apache.streampipes.service.extensions.base.security.UnauthenticatedInterfaces;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.config.BeanIds;
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -39,38 +40,56 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
 @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
-  private final UserDetailsService userDetailsService;
-  private StreamPipesPasswordEncoder passwordEncoder;
+  private static final Logger LOG = LoggerFactory.getLogger(WebSecurityConfigurerAdapter.class);
+
+  public WebSecurityConfig() {
 
-  public WebSecurityConfig(StreamPipesPasswordEncoder passwordEncoder) {
-    this.passwordEncoder = passwordEncoder;
-    this.userDetailsService = new SpUserDetailsService();
   }
 
   @Autowired
   public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
-    auth.userDetailsService(userDetailsService).passwordEncoder(this.passwordEncoder.passwordEncoder());
+    auth.userDetailsService(userDetailsService());
   }
 
   @Override
   protected void configure(HttpSecurity http) throws Exception {
 
-    http
-            .cors()
-            .and()
-            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
-            .and()
-            .csrf().disable()
-            .formLogin().disable()
-            .httpBasic().disable()
-            .exceptionHandling()
-            .authenticationEntryPoint(new UnauthorizedRequestEntryPoint())
-            .and()
-            .authorizeRequests()
-            .antMatchers(UnauthenticatedInterfaces.get().toArray(new String[0])).permitAll()
-            .anyRequest()
-            .authenticated().and()
-            .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
+    if (isAnonymousAccess()) {
+      http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+        .and()
+        .csrf().disable()
+        .formLogin().disable()
+        .httpBasic().disable().authorizeRequests().antMatchers("/**").permitAll();
+    } else {
+      http
+        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+        .and()
+        .csrf().disable()
+        .formLogin().disable()
+        .httpBasic().disable()
+        .exceptionHandling()
+        .authenticationEntryPoint(new UnauthorizedRequestEntryPoint())
+        .and()
+        .authorizeRequests()
+        .antMatchers(UnauthenticatedInterfaces.get().toArray(new String[0])).permitAll()
+        .anyRequest().authenticated().and().addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
+    }
+  }
+
+  private boolean isAnonymousAccess() {
+    if (Envs.SP_EXT_AUTH_MODE.exists() && Envs.SP_EXT_AUTH_MODE.getValue().equals("AUTH")) {
+      if (Envs.SP_JWT_PUBLIC_KEY_LOC.exists()) {
+        LOG.info("Configured service for authenticated access mode");
+        return false;
+      } else {
+        LOG.warn("No env variable {} provided, which is required for authenticated access. Defaulting to anonymous access.",
+                Envs.SP_JWT_PUBLIC_KEY_LOC.getEnvVariableName());
+        return true;
+      }
+    } else {
+      LOG.info("Configured anonymous access for this service, consider providing an authentication option.");
+      return true;
+    }
   }
 
   public TokenAuthenticationFilter tokenAuthenticationFilter() {
@@ -79,13 +98,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
   @Override
   public UserDetailsService userDetailsService() {
-    return userDetailsService;
-  }
-
-  @Bean(BeanIds.AUTHENTICATION_MANAGER)
-  @Override
-  public AuthenticationManager authenticationManagerBean() throws Exception {
-    return super.authenticationManagerBean();
+    return username -> null;
   }
 
 }
diff --git a/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/security/TokenAuthenticationFilter.java b/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/security/TokenAuthenticationFilter.java
new file mode 100644
index 000000000..3b50f1c87
--- /dev/null
+++ b/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/security/TokenAuthenticationFilter.java
@@ -0,0 +1,92 @@
+/*
+ * 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.streampipes.service.extensions.base.security;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import io.jsonwebtoken.Claims;
+import org.apache.streampipes.commons.constants.HttpConstants;
+import org.apache.streampipes.model.UserInfo;
+import org.apache.streampipes.security.jwt.JwtTokenUtils;
+import org.apache.streampipes.security.jwt.JwtTokenValidator;
+import org.apache.streampipes.security.jwt.PublicKeyResolver;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+public class TokenAuthenticationFilter extends OncePerRequestFilter {
+
+
+  public TokenAuthenticationFilter() {
+  }
+
+  @Override
+  protected void doFilterInternal(HttpServletRequest request,
+                                  HttpServletResponse response,
+                                  FilterChain filterChain) throws ServletException, IOException {
+    try {
+      String jwt = getJwtFromRequest(request);
+      if (StringUtils.hasText(jwt) && JwtTokenValidator.validateJwtToken(jwt, new PublicKeyResolver())) {
+        Claims claims = JwtTokenUtils.getClaimsFromToken(jwt, new PublicKeyResolver());
+        applySuccessfulAuth(request, claims);
+      }
+    } catch (Exception ex) {
+      logger.error("Could not set user authentication in security context", ex);
+    }
+
+    filterChain.doFilter(request, response);
+  }
+
+  private String getJwtFromRequest(HttpServletRequest request) {
+    String bearerToken = request.getHeader(HttpConstants.AUTHORIZATION);
+    if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(HttpConstants.BEARER)) {
+      return bearerToken.substring(7);
+    }
+    return null;
+  }
+
+  private void applySuccessfulAuth(HttpServletRequest request,
+                                   Claims claims) throws JsonProcessingException {
+    UserInfo userInfo = parseUserInfo((Map<String, Object>) claims.get("user"));
+    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userInfo, null, null);
+    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+  }
+
+  private UserInfo parseUserInfo(Map<String, Object> user) {
+    UserInfo userInfo = new UserInfo();
+    userInfo.setUsername(user.get("username").toString());
+    userInfo.setDisplayName(user.get("displayName").toString());
+    userInfo.setRoles(new HashSet<>((List<String>) user.get("roles")));
+
+    return userInfo;
+  }
+}
diff --git a/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java b/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/security/UnauthenticatedInterfaces.java
similarity index 66%
copy from streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java
copy to streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/security/UnauthenticatedInterfaces.java
index 2233be263..86e443ae4 100644
--- a/streampipes-service-base/src/main/java/org/apache/streampipes/service/base/rest/BaseResourceConfig.java
+++ b/streampipes-service-extensions-base/src/main/java/org/apache/streampipes/service/extensions/base/security/UnauthenticatedInterfaces.java
@@ -15,20 +15,24 @@
  * limitations under the License.
  *
  */
-package org.apache.streampipes.service.base.rest;
 
-import org.glassfish.jersey.server.ResourceConfig;
 
-import java.util.List;
+package org.apache.streampipes.service.extensions.base.security;
 
-public abstract class BaseResourceConfig extends ResourceConfig {
+import java.util.Arrays;
+import java.util.Collection;
 
-  public BaseResourceConfig() {
-    getClassesToRegister()
-            .forEach(set -> set.forEach(this::register));
-    register(ServiceHealthResource.class);
-  }
 
-  public abstract List<List<Class<?>>> getClassesToRegister();
+public class UnauthenticatedInterfaces {
 
+  public static Collection<String> get() {
+    return Arrays.asList(
+      "/svchealth/*",
+      "/",
+      "/sec/**",
+      "/sepa/**",
+      "/stream/**",
+      "/api/v1/worker/**"
+    );
+  }
 }
diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/UserInfoUtil.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/UserInfoUtil.java
index 2cc2df172..2b4cd7d94 100644
--- a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/UserInfoUtil.java
+++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/util/UserInfoUtil.java
@@ -19,7 +19,7 @@
 package org.apache.streampipes.user.management.util;
 
 import org.apache.streampipes.model.client.user.UserAccount;
-import org.apache.streampipes.model.client.user.UserInfo;
+import org.apache.streampipes.model.UserInfo;
 
 import java.util.Set;
 
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
index 279322215..ab4b1019b 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
@@ -18,7 +18,7 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 2.27.744 on 2022-03-11 16:37:33.
+// Generated using typescript-generator version 2.27.744 on 2022-04-25 13:56:53.
 
 export class ExtensionsServiceEndpointItem {
     appId: string;
@@ -246,27 +246,6 @@ export class UserApiToken {
     }
 }
 
-export class UserInfo {
-    darkMode: boolean;
-    displayName: string;
-    roles: string[];
-    showTutorial: boolean;
-    username: string;
-
-    static fromData(data: UserInfo, target?: UserInfo): UserInfo {
-        if (!data) {
-            return data;
-        }
-        const instance = target || new UserInfo();
-        instance.username = data.username;
-        instance.displayName = data.displayName;
-        instance.roles = __getCopyArrayFn(__identity<string>())(data.roles);
-        instance.showTutorial = data.showTutorial;
-        instance.darkMode = data.darkMode;
-        return instance;
-    }
-}
-
 export type PrincipalType = "USER_ACCOUNT" | "SERVICE_ACCOUNT" | "GROUP";
 
 export type Privilege = "PRIVILEGE_READ_PIPELINE" | "PRIVILEGE_WRITE_PIPELINE" | "PRIVILEGE_DELETE_PIPELINE" | "PRIVILEGE_READ_ADAPTER" | "PRIVILEGE_WRITE_ADAPTER" | "PRIVILEGE_DELETE_ADAPTER" | "PRIVILEGE_READ_PIPELINE_ELEMENT" | "PRIVILEGE_WRITE_PIPELINE_ELEMENT" | "PRIVILEGE_DELETE_PIPELINE_ELEMENT" | "PRIVILEGE_READ_DASHBOARD" | "PRIVILEGE_WRITE_DASHBOARD" | "PRIVILEGE_DELETE_DASHBOARD" | "PRIVILEGE_READ_DASHBOARD_WIDGET" | "PRIVILEGE_WRITE_DASHBOARD_WIDGET" | "PRIVILEGE_DELETE_DASHB [...]
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
index 18a564910..393aa4c56 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
@@ -18,7 +18,7 @@
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 2.27.744 on 2022-03-11 16:37:20.
+// Generated using typescript-generator version 2.27.744 on 2022-04-25 13:56:39.
 
 export class AbstractStreamPipesEntity {
     "@class": "org.apache.streampipes.model.base.AbstractStreamPipesEntity" | "org.apache.streampipes.model.base.NamedStreamPipesEntity" | "org.apache.streampipes.model.connect.adapter.AdapterDescription" | "org.apache.streampipes.model.connect.adapter.AdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.GenericAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.AdapterStre [...]
@@ -151,8 +151,8 @@ export class NamedStreamPipesEntity extends AbstractStreamPipesEntity {
         instance.applicationLinks = __getCopyArrayFn(ApplicationLink.fromData)(data.applicationLinks);
         instance.internallyManaged = data.internallyManaged;
         instance.connectedTo = __getCopyArrayFn(__identity<string>())(data.connectedTo);
-        instance.dom = data.dom;
         instance.uri = data.uri;
+        instance.dom = data.dom;
         instance._rev = data._rev;
         return instance;
     }
@@ -192,8 +192,8 @@ export class AdapterDescription extends NamedStreamPipesEntity {
         instance.selectedEndpointUrl = data.selectedEndpointUrl;
         instance.correspondingServiceGroup = data.correspondingServiceGroup;
         instance.correspondingDataStreamElementId = data.correspondingDataStreamElementId;
-        instance.streamRules = __getCopyArrayFn(__identity<any>())(data.streamRules);
         instance.valueRules = __getCopyArrayFn(__identity<any>())(data.valueRules);
+        instance.streamRules = __getCopyArrayFn(__identity<any>())(data.streamRules);
         instance.schemaRules = __getCopyArrayFn(__identity<any>())(data.schemaRules);
         return instance;
     }
@@ -2500,8 +2500,8 @@ export class PipelineTemplateDescription extends NamedStreamPipesEntity {
         const instance = target || new PipelineTemplateDescription();
         super.fromData(data, instance);
         instance.boundTo = __getCopyArrayFn(BoundPipelineElement.fromData)(data.boundTo);
-        instance.pipelineTemplateDescription = data.pipelineTemplateDescription;
         instance.pipelineTemplateName = data.pipelineTemplateName;
+        instance.pipelineTemplateDescription = data.pipelineTemplateDescription;
         instance.pipelineTemplateId = data.pipelineTemplateId;
         return instance;
     }
@@ -3165,6 +3165,27 @@ export class UserDefinedOutputStrategy extends OutputStrategy {
     }
 }
 
+export class UserInfo {
+    darkMode: boolean;
+    displayName: string;
+    roles: string[];
+    showTutorial: boolean;
+    username: string;
+
+    static fromData(data: UserInfo, target?: UserInfo): UserInfo {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new UserInfo();
+        instance.username = data.username;
+        instance.displayName = data.displayName;
+        instance.roles = __getCopyArrayFn(__identity<string>())(data.roles);
+        instance.showTutorial = data.showTutorial;
+        instance.darkMode = data.darkMode;
+        return instance;
+    }
+}
+
 export class VisualizablePipeline {
     pipelineId: string;
     pipelineName: string;