From cf87a481c8203446e43106ff3a7ef29e0115ede7 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Fri, 4 Feb 2022 20:19:18 +0100
Subject: [PATCH] Added authentication for the container service, nice

Former-commit-id: c169229365ad73990e4d2e69a364d4f052237058
---
 fda-authentication-service/report/pom.xml     | 40 +------------
 .../endpoints/AuthenticationEndpoint.java     | 21 ++++++-
 .../at/tuwien/endpoints/UserEndpoint.java     |  2 +-
 .../java/at/tuwien/auth/AuthTokenFilter.java  |  4 --
 .../main/java/at/tuwien/auth/JwtUtils.java    |  3 +-
 .../at/tuwien/config/WebSecurityConfig.java   |  4 +-
 .../java/at/tuwien/mapper/UserMapper.java     | 56 +++++++++++++++++-
 .../tuwien/service/AuthenticationService.java |  4 +-
 .../java/at/tuwien/service/UserService.java   |  3 +-
 .../impl/AuthenticationServiceImpl.java       | 33 ++++-------
 .../service/impl/UserDetailsServiceImpl.java  | 14 ++++-
 .../tuwien/service/impl/UserServiceImpl.java  |  3 +-
 .../tuwien/endpoints/ContainerEndpoint.java   |  4 +-
 .../at/tuwien/endpoints/ImageEndpoint.java    |  4 +-
 .../src/main/resources/application-docker.yml |  2 +-
 .../src/main/resources/application.yml        |  2 +-
 .../java/at/tuwien/auth/AuthTokenFilter.java  | 13 +++--
 .../java/at/tuwien/config/GatewayConfig.java  | 22 +++++++
 .../at/tuwien/config/WebSecurityConfig.java   | 16 ++++-
 .../gateway/AuthenticationServiceGateway.java | 14 +++++
 .../AuthenticationServiceGatewayImpl.java     | 36 ++++++++++++
 .../java/at/tuwien/mapper/ImageMapper.java    |  2 -
 .../java/at/tuwien/mapper/UserMapper.java     | 18 ++++++
 .../api/{user => auth}/JwtResponseDto.java    |  2 +-
 .../api/{user => auth}/LoginRequestDto.java   |  2 +-
 .../api/{user => auth}/SignupRequestDto.java  |  2 +-
 .../tuwien/api/user/GrantedAuthorityDto.java  | 19 ++++++
 .../at/tuwien/api/user/UserDetailsDto.java    | 58 +++++++++++++++++++
 .../main/java/at/tuwien/api/user/UserDto.java | 44 ++------------
 .../java/at/tuwien/entities/user/User.java    |  1 +
 fda-ui/components/dialogs/CreateDB.vue        |  6 +-
 31 files changed, 316 insertions(+), 138 deletions(-)
 create mode 100644 fda-container-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
 create mode 100644 fda-container-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java
 create mode 100644 fda-container-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java
 create mode 100644 fda-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
 rename fda-metadata-db/api/src/main/java/at/tuwien/api/{user => auth}/JwtResponseDto.java (96%)
 rename fda-metadata-db/api/src/main/java/at/tuwien/api/{user => auth}/LoginRequestDto.java (93%)
 rename fda-metadata-db/api/src/main/java/at/tuwien/api/{user => auth}/SignupRequestDto.java (95%)
 create mode 100644 fda-metadata-db/api/src/main/java/at/tuwien/api/user/GrantedAuthorityDto.java
 create mode 100644 fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java

diff --git a/fda-authentication-service/report/pom.xml b/fda-authentication-service/report/pom.xml
index 30e855d217..d75342985b 100644
--- a/fda-authentication-service/report/pom.xml
+++ b/fda-authentication-service/report/pom.xml
@@ -9,48 +9,12 @@
         <version>0.0.1-SNAPSHOT</version>
     </parent>
 
-    <artifactId>report</artifactId>
+    <artifactId>api</artifactId>
     <version>0.0.1-SNAPSHOT</version>
-    <name>fda-authentication-service-report</name>
+    <name>fda-authentication-service-api</name>
     <description>
         This module is only intended for the pipeline coverage report. See the detailed report in the
         respective modules
     </description>
 
-    <properties>
-        <jacoco.version>0.8.7</jacoco.version>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>at.tuwien</groupId>
-            <artifactId>rest-service</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>at.tuwien</groupId>
-            <artifactId>services</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.jacoco</groupId>
-                <artifactId>jacoco-maven-plugin</artifactId>
-                <version>${jacoco.version}</version>
-                <executions>
-                    <execution>
-                        <id>report-aggregate</id>
-                        <phase>verify</phase>
-                        <goals>
-                            <goal>report-aggregate</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-
 </project>
\ No newline at end of file
diff --git a/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/AuthenticationEndpoint.java b/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/AuthenticationEndpoint.java
index d0f8f1c8a9..97a1d24af9 100644
--- a/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/AuthenticationEndpoint.java
+++ b/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/AuthenticationEndpoint.java
@@ -1,7 +1,9 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.user.JwtResponseDto;
-import at.tuwien.api.user.LoginRequestDto;
+import at.tuwien.api.auth.JwtResponseDto;
+import at.tuwien.api.auth.LoginRequestDto;
+import at.tuwien.api.user.UserDto;
+import at.tuwien.mapper.UserMapper;
 import at.tuwien.service.AuthenticationService;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
@@ -12,6 +14,7 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
+import java.security.Principal;
 
 @Log4j2
 @RestController
@@ -20,10 +23,12 @@ import javax.validation.Valid;
 @RequestMapping("/api/auth")
 public class AuthenticationEndpoint {
 
+    private final UserMapper userMapper;
     private final AuthenticationService authenticationService;
 
     @Autowired
-    public AuthenticationEndpoint(AuthenticationService authenticationService) {
+    public AuthenticationEndpoint(UserMapper userMapper, AuthenticationService authenticationService) {
+        this.userMapper = userMapper;
         this.authenticationService = authenticationService;
     }
 
@@ -38,4 +43,14 @@ public class AuthenticationEndpoint {
                 .body(response);
     }
 
+    @PutMapping
+    @ApiOperation(value = "Authenticates a token")
+    @ApiResponses({
+            @ApiResponse(code = 201, message = "Successfully authenticated a user.")
+    })
+    public ResponseEntity<UserDto> authenticateUser(Principal principal) {
+        return ResponseEntity.accepted()
+                .body(userMapper.principalToUserDto(principal));
+    }
+
 }
\ No newline at end of file
diff --git a/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java b/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
index cb2d2d5bb5..e60df7e616 100644
--- a/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
+++ b/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java
@@ -1,6 +1,6 @@
 package at.tuwien.endpoints;
 
-import at.tuwien.api.user.SignupRequestDto;
+import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.api.user.UserDto;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.RoleNotFoundException;
diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/fda-authentication-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java
index fdaf70a6a2..76d247bf13 100644
--- a/fda-authentication-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java
+++ b/fda-authentication-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java
@@ -2,12 +2,10 @@ package at.tuwien.auth;
 
 import at.tuwien.service.impl.UserDetailsServiceImpl;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
-import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
 import org.springframework.web.filter.OncePerRequestFilter;
 
@@ -18,13 +16,11 @@ import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 
 @Slf4j
-@Component
 public class AuthTokenFilter extends OncePerRequestFilter {
 
     private final JwtUtils jwtUtils;
     private final UserDetailsServiceImpl userDetailsService;
 
-    @Autowired
     public AuthTokenFilter(JwtUtils jwtUtils, UserDetailsServiceImpl userDetailsService) {
         this.jwtUtils = jwtUtils;
         this.userDetailsService = userDetailsService;
diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/auth/JwtUtils.java b/fda-authentication-service/services/src/main/java/at/tuwien/auth/JwtUtils.java
index c768db7382..601cdfbbb1 100644
--- a/fda-authentication-service/services/src/main/java/at/tuwien/auth/JwtUtils.java
+++ b/fda-authentication-service/services/src/main/java/at/tuwien/auth/JwtUtils.java
@@ -1,5 +1,6 @@
 package at.tuwien.auth;
 
+import at.tuwien.api.user.UserDetailsDto;
 import at.tuwien.api.user.UserDto;
 import com.auth0.jwt.JWT;
 import com.auth0.jwt.algorithms.Algorithm;
@@ -24,7 +25,7 @@ public class JwtUtils {
     private Integer expire;
 
     public String generateJwtToken(Authentication authentication) {
-        final UserDto userPrincipal = (UserDto) authentication.getPrincipal();
+        final UserDetailsDto userPrincipal = (UserDetailsDto) authentication.getPrincipal();
         final Algorithm algorithm = Algorithm.HMAC512(secret);
         return JWT.create()
                 .withSubject(userPrincipal.getUsername())
diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/fda-authentication-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
index 017992fda0..cab319c4f8 100644
--- a/fda-authentication-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
+++ b/fda-authentication-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
@@ -38,7 +38,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     }
 
     @Bean
-    public AuthTokenFilter authenticationJwtTokenFilter() {
+    public AuthTokenFilter authTokenFilter() {
         return new AuthTokenFilter(jwtUtils, userDetailsService);
     }
 
@@ -86,7 +86,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 /* our private endpoints */
                 .anyRequest().authenticated();
         /* add JWT token filter */
-        http.addFilterBefore(authenticationJwtTokenFilter(),
+        http.addFilterBefore(authTokenFilter(),
                 UsernamePasswordAuthenticationFilter.class
         );
     }
diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/mapper/UserMapper.java b/fda-authentication-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
index b630e8f19a..14fedb815b 100644
--- a/fda-authentication-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
+++ b/fda-authentication-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
@@ -1,20 +1,44 @@
 package at.tuwien.mapper;
 
-import at.tuwien.api.user.SignupRequestDto;
+import at.tuwien.api.auth.JwtResponseDto;
+import at.tuwien.api.auth.SignupRequestDto;
+import at.tuwien.api.user.GrantedAuthorityDto;
+import at.tuwien.api.user.UserDetailsDto;
 import at.tuwien.api.user.UserDto;
+import at.tuwien.entities.user.RoleType;
 import at.tuwien.entities.user.User;
 import org.mapstruct.Mapper;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 
-import java.util.List;
+import java.security.Principal;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 @Mapper(componentModel = "spring")
 public interface UserMapper {
 
+    org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserMapper.class);
+
     User signupRequestDtoToUser(SignupRequestDto data);
 
+    UserDetailsDto userToUserDetailsDto(User data);
+
+    default JwtResponseDto principalToJwtResponseDto(Object data) {
+        final UserDetailsDto details = (UserDetailsDto) data;
+        return JwtResponseDto.builder()
+                .id(details.getId())
+                .username(details.getUsername())
+                .email(details.getEmail())
+                .roles(details.getAuthorities()
+                        .stream()
+                        .filter(Objects::nonNull)
+                        .map(GrantedAuthority::getAuthority)
+                        .collect(Collectors.toList()))
+                .build();
+    }
+
     default UserDto userToUserDto(User data) {
         return UserDto.builder()
                 .id(data.getId())
@@ -23,7 +47,33 @@ public interface UserMapper {
                 .password(data.getPassword())
                 .authorities(data.getRoles()
                         .stream()
-                        .map(role -> new SimpleGrantedAuthority(role.name()))
+                        .map(this::roleTypeToGrantedAuthorityDto)
+                        .collect(Collectors.toList()))
+                .build();
+    }
+
+    default GrantedAuthority roleTypeToGrantedAuthority(RoleType data) {
+        return new SimpleGrantedAuthority(data.name());
+    }
+
+    default GrantedAuthorityDto roleTypeToGrantedAuthorityDto(RoleType data) {
+        return GrantedAuthorityDto.builder()
+                .authority(data.name())
+                .build();
+    }
+
+    default GrantedAuthorityDto grantedAuthorityToGrantedAuthority(GrantedAuthority data) {
+        return GrantedAuthorityDto.builder()
+                .authority(data.getAuthority())
+                .build();
+    }
+
+    default UserDto principalToUserDto(Principal principal) {
+        final UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) principal;
+        return UserDto.builder()
+                .authorities(token.getAuthorities()
+                        .stream()
+                        .map(this::grantedAuthorityToGrantedAuthority)
                         .collect(Collectors.toList()))
                 .build();
     }
diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/service/AuthenticationService.java b/fda-authentication-service/services/src/main/java/at/tuwien/service/AuthenticationService.java
index 67b8245620..59483d1ba7 100644
--- a/fda-authentication-service/services/src/main/java/at/tuwien/service/AuthenticationService.java
+++ b/fda-authentication-service/services/src/main/java/at/tuwien/service/AuthenticationService.java
@@ -1,7 +1,7 @@
 package at.tuwien.service;
 
-import at.tuwien.api.user.JwtResponseDto;
-import at.tuwien.api.user.LoginRequestDto;
+import at.tuwien.api.auth.JwtResponseDto;
+import at.tuwien.api.auth.LoginRequestDto;
 
 public interface AuthenticationService {
 
diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/service/UserService.java b/fda-authentication-service/services/src/main/java/at/tuwien/service/UserService.java
index 1149a32f5a..6eac718c15 100644
--- a/fda-authentication-service/services/src/main/java/at/tuwien/service/UserService.java
+++ b/fda-authentication-service/services/src/main/java/at/tuwien/service/UserService.java
@@ -1,7 +1,6 @@
 package at.tuwien.service;
 
-import at.tuwien.api.user.SignupRequestDto;
-import at.tuwien.api.user.UserDto;
+import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.RoleNotFoundException;
 import at.tuwien.exception.UserEmailExistsException;
diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java b/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
index 51f7b31e06..60f334d871 100644
--- a/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
+++ b/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java
@@ -1,55 +1,46 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.user.JwtResponseDto;
-import at.tuwien.api.user.LoginRequestDto;
-import at.tuwien.api.user.UserDto;
+import at.tuwien.api.auth.JwtResponseDto;
+import at.tuwien.api.auth.LoginRequestDto;
 import at.tuwien.auth.JwtUtils;
+import at.tuwien.mapper.UserMapper;
 import at.tuwien.service.AuthenticationService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.List;
-import java.util.stream.Collectors;
 
 @Slf4j
 @Service
 public class AuthenticationServiceImpl implements AuthenticationService {
 
     private final JwtUtils jwtUtils;
+    private final UserMapper userMapper;
     private final AuthenticationManager authenticationManager;
 
     @Autowired
-    public AuthenticationServiceImpl(JwtUtils jwtUtils, AuthenticationManager authenticationManager) {
+    public AuthenticationServiceImpl(JwtUtils jwtUtils, UserMapper userMapper,
+                                     AuthenticationManager authenticationManager) {
         this.jwtUtils = jwtUtils;
+        this.userMapper = userMapper;
         this.authenticationManager = authenticationManager;
     }
 
     @Override
     @Transactional
     public JwtResponseDto authenticate(LoginRequestDto data) {
-        final UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(data.getUsername(), data.getPassword());
+        final UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(data.getUsername(),
+                data.getPassword());
         final Authentication authentication = authenticationManager.authenticate(token);
         SecurityContextHolder.getContext().setAuthentication(authentication);
-        final String jwt = jwtUtils.generateJwtToken(authentication);
-        final UserDto userDetails = (UserDto) authentication.getPrincipal();
-        final List<String> roles = userDetails.getAuthorities().stream()
-                .map(GrantedAuthority::getAuthority)
-                .collect(Collectors.toList());
-        return JwtResponseDto.builder()
-                .id(userDetails.getId())
-                .username(userDetails.getUsername())
-                .email(userDetails.getEmail())
-                .roles(roles)
-                .token(jwt)
-                .build();
+        final JwtResponseDto response = userMapper.principalToJwtResponseDto(authentication.getPrincipal());
+        response.setToken(jwtUtils.generateJwtToken(authentication));
+        return response;
     }
 
 }
diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserDetailsServiceImpl.java b/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserDetailsServiceImpl.java
index 67d8f172f8..bd0887b32e 100644
--- a/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserDetailsServiceImpl.java
+++ b/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserDetailsServiceImpl.java
@@ -1,5 +1,6 @@
 package at.tuwien.service.impl;
 
+import at.tuwien.api.user.UserDetailsDto;
 import at.tuwien.entities.user.User;
 import at.tuwien.mapper.UserMapper;
 import at.tuwien.repositories.UserRepository;
@@ -9,6 +10,9 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.stream.Collectors;
 
 @Slf4j
 @Service
@@ -24,10 +28,18 @@ public class UserDetailsServiceImpl implements UserDetailsService {
     }
 
     @Override
+    @Transactional(readOnly = true)
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
         final User user = userRepository.findByUsername(username)
                 .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
-        return userMapper.userToUserDto(user);
+        log.debug("loaded user {}", user);
+        final UserDetailsDto details = userMapper.userToUserDetailsDto(user);
+        details.setAuthorities(user.getRoles()
+                .stream()
+                .map(userMapper::roleTypeToGrantedAuthority)
+                .collect(Collectors.toList()));
+        log.debug("mapped user {}", details);
+        return details;
     }
 
 }
diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java b/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
index 40cf2f03f2..f7683c2d6b 100644
--- a/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
+++ b/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java
@@ -1,6 +1,6 @@
 package at.tuwien.service.impl;
 
-import at.tuwien.api.user.SignupRequestDto;
+import at.tuwien.api.auth.SignupRequestDto;
 import at.tuwien.entities.user.RoleType;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.RoleNotFoundException;
@@ -79,4 +79,5 @@ public class UserServiceImpl implements UserService {
         log.debug("created user {}", entity);
         return entity;
     }
+
 }
diff --git a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
index 75ebe4aad7..5eec2b16c5 100644
--- a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
+++ b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java
@@ -38,7 +38,7 @@ public class ContainerEndpoint {
     }
 
     @Transactional
-    @GetMapping("/")
+    @GetMapping
     @ApiOperation(value = "List all containers", notes = "Lists the containers in the metadata database.")
     @ApiResponses({
             @ApiResponse(code = 200, message = "All containers are listed."),
@@ -53,7 +53,7 @@ public class ContainerEndpoint {
     }
 
     @Transactional
-    @PostMapping("/")
+    @PostMapping
     @ApiOperation(value = "Creates a new container", notes = "Creates a new container whose image is registered in the metadata database too.")
     @ApiResponses({
             @ApiResponse(code = 201, message = "Successfully created a new container."),
diff --git a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java
index 9ed8adffa5..53eb0de4b1 100644
--- a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java
+++ b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java
@@ -43,7 +43,7 @@ public class ImageEndpoint {
     }
 
     @Transactional
-    @GetMapping("/")
+    @GetMapping
     @ApiOperation(value = "List all images", notes = "Lists the images in the metadata database.")
     @ApiResponses({
             @ApiResponse(code = 200, message = "All images are listed."),
@@ -58,7 +58,7 @@ public class ImageEndpoint {
     }
 
     @Transactional
-    @PostMapping("/")
+    @PostMapping
     @ApiOperation(value = "Creates a new image", notes = "Creates a new image in the metadata database.")
     @ApiResponses({
             @ApiResponse(code = 201, message = "Successfully created a new image."),
diff --git a/fda-container-service/rest-service/src/main/resources/application-docker.yml b/fda-container-service/rest-service/src/main/resources/application-docker.yml
index b18fc742b2..4cebc5d734 100644
--- a/fda-container-service/rest-service/src/main/resources/application-docker.yml
+++ b/fda-container-service/rest-service/src/main/resources/application-docker.yml
@@ -26,4 +26,4 @@ eureka:
   client.serviceUrl.defaultZone: http://fda-discovery-service:9090/eureka/
 fda:
   ready.path: /ready
-  auth.url: http://fda-authentication-service:9097/api/auth
\ No newline at end of file
+  auth.endpoint: http://fda-authentication-service:9097
\ No newline at end of file
diff --git a/fda-container-service/rest-service/src/main/resources/application.yml b/fda-container-service/rest-service/src/main/resources/application.yml
index 98f135bd1e..9d042c907b 100644
--- a/fda-container-service/rest-service/src/main/resources/application.yml
+++ b/fda-container-service/rest-service/src/main/resources/application.yml
@@ -26,4 +26,4 @@ eureka:
   client.serviceUrl.defaultZone: http://localhost:9090/eureka/
 fda:
   ready.path: ./ready
-  auth.url: http://localhost:9097/api/auth
\ No newline at end of file
+  auth.endpoint: http://localhost:9097
\ No newline at end of file
diff --git a/fda-container-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/fda-container-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java
index 2d1d025885..2ece75e3cd 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java
@@ -1,12 +1,12 @@
 package at.tuwien.auth;
 
+import at.tuwien.gateway.AuthenticationServiceGateway;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
-import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
 import org.springframework.web.filter.OncePerRequestFilter;
 
@@ -17,16 +17,21 @@ import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 
 @Slf4j
-@Component
 public class AuthTokenFilter extends OncePerRequestFilter {
 
+    private final AuthenticationServiceGateway authenticationServiceGateway;
+
+    public AuthTokenFilter(AuthenticationServiceGateway authenticationServiceGateway) {
+        this.authenticationServiceGateway = authenticationServiceGateway;
+    }
+
     @Override
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
             throws ServletException, IOException {
         String jwt = parseJwt(request);
+        log.debug("parsed jwt {}", jwt);
         if (jwt != null) {
-
-            final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+            final UserDetails userDetails = authenticationServiceGateway.validate(jwt);
             final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                     userDetails, null, userDetails.getAuthorities());
             authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
diff --git a/fda-container-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/fda-container-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
new file mode 100644
index 0000000000..252235a1eb
--- /dev/null
+++ b/fda-container-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
@@ -0,0 +1,22 @@
+package at.tuwien.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+@Configuration
+public class GatewayConfig {
+
+    @Value("${fda.auth.endpoint}")
+    private String authEndpoint;
+
+    @Bean
+    public RestTemplate restTemplate() {
+        final RestTemplate restTemplate =  new RestTemplate();
+        restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(authEndpoint));
+        return restTemplate;
+    }
+
+}
diff --git a/fda-container-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/fda-container-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
index 5f0bd47720..84aa080940 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java
@@ -1,6 +1,8 @@
 package at.tuwien.config;
 
 import at.tuwien.auth.AuthTokenFilter;
+import at.tuwien.gateway.AuthenticationServiceGateway;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpMethod;
@@ -9,6 +11,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 import org.springframework.web.cors.CorsConfiguration;
 import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
 import org.springframework.web.filter.CorsFilter;
@@ -20,9 +23,16 @@ import javax.servlet.http.HttpServletResponse;
 @EnableGlobalMethodSecurity(prePostEnabled = true)
 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
+    private final AuthenticationServiceGateway authenticationServiceGateway;
+
+    @Autowired
+    public WebSecurityConfig(AuthenticationServiceGateway authenticationServiceGateway) {
+        this.authenticationServiceGateway = authenticationServiceGateway;
+    }
+
     @Bean
     public AuthTokenFilter authTokenFilter() {
-        return new AuthTokenFilter()
+        return new AuthTokenFilter(authenticationServiceGateway);
     }
 
     @Override
@@ -51,6 +61,10 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .antMatchers(HttpMethod.GET, "/api/image/**").permitAll()
                 /* our private endpoints */
                 .anyRequest().authenticated();
+        /* add JWT token filter */
+        http.addFilterBefore(authTokenFilter(),
+                UsernamePasswordAuthenticationFilter.class
+        );
     }
 
     @Bean
diff --git a/fda-container-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java b/fda-container-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java
new file mode 100644
index 0000000000..fc47ce246d
--- /dev/null
+++ b/fda-container-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java
@@ -0,0 +1,14 @@
+package at.tuwien.gateway;
+
+import org.springframework.security.core.userdetails.UserDetails;
+
+public interface AuthenticationServiceGateway {
+
+    /**
+     * Validates a token
+     *
+     * @param token The token
+     * @return User details on success
+     */
+    UserDetails validate(String token);
+}
diff --git a/fda-container-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java b/fda-container-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java
new file mode 100644
index 0000000000..30507c4b6e
--- /dev/null
+++ b/fda-container-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java
@@ -0,0 +1,36 @@
+package at.tuwien.gateway.impl;
+
+import at.tuwien.api.user.UserDto;
+import at.tuwien.gateway.AuthenticationServiceGateway;
+import at.tuwien.mapper.UserMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+@Service
+public class AuthenticationServiceGatewayImpl implements AuthenticationServiceGateway {
+
+    private final UserMapper userMapper;
+    private final RestTemplate restTemplate;
+
+    @Autowired
+    public AuthenticationServiceGatewayImpl(UserMapper userMapper, RestTemplate restTemplate) {
+        this.userMapper = userMapper;
+        this.restTemplate = restTemplate;
+    }
+
+    @Override
+    public UserDetails validate(String token) {
+        final HttpHeaders headers = new HttpHeaders();
+        headers.set("Authorization", "Bearer " + token);
+        final ResponseEntity<UserDto> response = restTemplate.exchange("/api/auth", HttpMethod.PUT,
+                new HttpEntity<>("", headers), UserDto.class);
+        return userMapper.userDtoToUserDetailsDto(response.getBody());
+    }
+
+}
diff --git a/fda-container-service/services/src/main/java/at/tuwien/mapper/ImageMapper.java b/fda-container-service/services/src/main/java/at/tuwien/mapper/ImageMapper.java
index c74b365925..5a41191dc7 100644
--- a/fda-container-service/services/src/main/java/at/tuwien/mapper/ImageMapper.java
+++ b/fda-container-service/services/src/main/java/at/tuwien/mapper/ImageMapper.java
@@ -1,11 +1,9 @@
 package at.tuwien.mapper;
 
 import at.tuwien.api.container.image.ImageBriefDto;
-import at.tuwien.api.container.image.ImageDateDto;
 import at.tuwien.api.container.image.ImageDto;
 import at.tuwien.api.container.image.ImageEnvItemDto;
 import at.tuwien.entities.container.image.ContainerImage;
-import at.tuwien.entities.container.image.ContainerImageDate;
 import at.tuwien.entities.container.image.ContainerImageEnvironmentItem;
 import com.github.dockerjava.api.command.InspectImageResponse;
 import org.mapstruct.Mapper;
diff --git a/fda-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java b/fda-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
new file mode 100644
index 0000000000..f14430e967
--- /dev/null
+++ b/fda-container-service/services/src/main/java/at/tuwien/mapper/UserMapper.java
@@ -0,0 +1,18 @@
+package at.tuwien.mapper;
+
+import at.tuwien.api.user.GrantedAuthorityDto;
+import at.tuwien.api.user.UserDetailsDto;
+import at.tuwien.api.user.UserDto;
+import org.mapstruct.Mapper;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+@Mapper(componentModel = "spring")
+public interface UserMapper {
+
+    UserDetailsDto userDtoToUserDetailsDto(UserDto data);
+
+    default GrantedAuthority grantedAuthorityDtoToGrantedAuthority(GrantedAuthorityDto data) {
+        return new SimpleGrantedAuthority(data.getAuthority());
+    }
+}
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/JwtResponseDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/JwtResponseDto.java
similarity index 96%
rename from fda-metadata-db/api/src/main/java/at/tuwien/api/user/JwtResponseDto.java
rename to fda-metadata-db/api/src/main/java/at/tuwien/api/auth/JwtResponseDto.java
index 1d35f55fd9..48c3f5f2cc 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/JwtResponseDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/JwtResponseDto.java
@@ -1,4 +1,4 @@
-package at.tuwien.api.user;
+package at.tuwien.api.auth;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.*;
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/LoginRequestDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/LoginRequestDto.java
similarity index 93%
rename from fda-metadata-db/api/src/main/java/at/tuwien/api/user/LoginRequestDto.java
rename to fda-metadata-db/api/src/main/java/at/tuwien/api/auth/LoginRequestDto.java
index c3b786d722..8b1ef6cf79 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/LoginRequestDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/LoginRequestDto.java
@@ -1,4 +1,4 @@
-package at.tuwien.api.user;
+package at.tuwien.api.auth;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.*;
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/SignupRequestDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java
similarity index 95%
rename from fda-metadata-db/api/src/main/java/at/tuwien/api/user/SignupRequestDto.java
rename to fda-metadata-db/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java
index 9415e90db6..a117e83a9a 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/SignupRequestDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java
@@ -1,4 +1,4 @@
-package at.tuwien.api.user;
+package at.tuwien.api.auth;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.*;
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/GrantedAuthorityDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/GrantedAuthorityDto.java
new file mode 100644
index 0000000000..eb26ea9125
--- /dev/null
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/GrantedAuthorityDto.java
@@ -0,0 +1,19 @@
+package at.tuwien.api.user;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.*;
+
+@Getter
+@Setter
+@ToString
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class GrantedAuthorityDto {
+
+    @ApiModelProperty(name = "authority name")
+    private String authority;
+
+
+
+}
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java
new file mode 100644
index 0000000000..3a94dcc7b8
--- /dev/null
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java
@@ -0,0 +1,58 @@
+package at.tuwien.api.user;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.*;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Getter
+@Setter
+@ToString
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class UserDetailsDto implements UserDetails {
+
+    @ApiModelProperty(name = "id")
+    private Long id;
+
+    @ApiModelProperty(name = "user authorities")
+    private List<? extends GrantedAuthority> authorities;
+
+    @NotNull
+    @ApiModelProperty(name = "user name")
+    private String username;
+
+    @NotNull
+    @ToString.Exclude
+    @ApiModelProperty(name = "password hash")
+    private String password;
+
+    @NotNull
+    @ApiModelProperty(name = "mail address")
+    private String email;
+
+    @Override
+    public boolean isAccountNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isAccountNonLocked() {
+        return true;
+    }
+
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+}
diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java
index c7a251242e..f6ffb845d8 100644
--- a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java
+++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserDto.java
@@ -3,11 +3,9 @@ package at.tuwien.api.user;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.*;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
 
 import javax.validation.constraints.NotNull;
-import java.util.Collection;
+import java.util.List;
 
 @Getter
 @Setter
@@ -15,19 +13,20 @@ import java.util.Collection;
 @Builder
 @AllArgsConstructor
 @NoArgsConstructor
-public class UserDto implements UserDetails {
+public class UserDto {
 
     @ApiModelProperty(name = "id")
     private Long id;
 
     @ApiModelProperty(name = "user authorities")
-    private Collection<? extends GrantedAuthority> authorities;
+    private List<GrantedAuthorityDto> authorities;
 
     @NotNull
     @ApiModelProperty(name = "user name")
     private String username;
 
     @NotNull
+    @ToString.Exclude
     @JsonIgnore
     @ApiModelProperty(name = "password hash")
     private String password;
@@ -36,39 +35,4 @@ public class UserDto implements UserDetails {
     @ApiModelProperty(name = "mail address")
     private String email;
 
-    @Override
-    public Collection<? extends GrantedAuthority> getAuthorities() {
-        return authorities;
-    }
-
-    @Override
-    public String getPassword() {
-        return this.password;
-    }
-
-    @Override
-    public String getUsername() {
-        return this.username;
-    }
-
-    @Override
-    public boolean isAccountNonExpired() {
-        return true;
-    }
-
-    @Override
-    public boolean isAccountNonLocked() {
-        return true;
-    }
-
-    @Override
-    public boolean isCredentialsNonExpired() {
-        return true;
-    }
-
-    @Override
-    public boolean isEnabled() {
-        return true;
-    }
-
 }
diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java
index acd94b0687..c36f0f4074 100644
--- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java
+++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/user/User.java
@@ -55,6 +55,7 @@ public class User {
     @Column(name = "main_email", unique = true, nullable = false)
     private String email;
 
+    @ToString.Exclude
     @Column(nullable = false)
     private String password;
 
diff --git a/fda-ui/components/dialogs/CreateDB.vue b/fda-ui/components/dialogs/CreateDB.vue
index 1316c5fd64..3172bb337f 100644
--- a/fda-ui/components/dialogs/CreateDB.vue
+++ b/fda-ui/components/dialogs/CreateDB.vue
@@ -104,7 +104,7 @@ export default {
       try {
         this.loading = true
         this.error = false
-        res = await this.$axios.get('/api/image/', {
+        res = await this.$axios.get('/api/image', {
           headers: { Authorization: `Bearer ${this.token}` }
         })
         this.engines = res.data
@@ -129,7 +129,7 @@ export default {
       try {
         this.loading = true
         this.error = false
-        res = await this.$axios.post('/api/container/', {
+        res = await this.$axios.post('/api/container', {
           name: this.database,
           description: this.description,
           repository: this.engine.repository,
@@ -176,7 +176,7 @@ export default {
       this.error = false
       for (let i = 0; i < 5; i++) {
         try {
-          res = await this.$axios.post(`/api/container/${containerId}/database/`, {
+          res = await this.$axios.post(`/api/container/${containerId}/database`, {
             name: this.database,
             description: this.description,
             is_public: this.isPublic
-- 
GitLab