diff --git a/fda-authentication-service/report/pom.xml b/fda-authentication-service/report/pom.xml index 30e855d217b850a8559b3df28e8fc77e2c5fa0ae..d75342985b65a733018ff3717191747cd26a413c 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 d0f8f1c8a90839fa9a308a553bcee8d4e21aa7b8..97a1d24af9f70d887ec000e2d33f5682fa167f8a 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 cb2d2d5bb5bd308734202bb31b7533867d15c1d2..e60df7e616e347829fed47b36985ae949c1260da 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 fdaf70a6a2dbd8d4f968115aac6e452b4fbb2a07..76d247bf132e83713d226a241c9fc5639642a735 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 c768db7382eb42871c0288c08cf9c3e043d617b5..601cdfbbb193b91038d127b5165e7b0803da6d67 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 017992fda0e7314069d5fff2e461e88cfcd0c321..cab319c4f83130aca499e24ad4566db6c98a6494 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 b630e8f19a35e802619294c4a9ec70f93fae2e9f..14fedb815b6a6a174aacd3cb909e1ccd09ea777b 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 67b8245620d96f975dacda12747ec3ee92287ab8..59483d1ba7d79f6b8237d2a387ebcd5a3a95a4eb 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 1149a32f5a7e252624f7307ffb9fb91a39b10249..6eac718c154a45aaf08a47c01e6f5ff85e62f523 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 51f7b31e0603b3bed9c7228ad98b073e4294aa22..60f334d871d8624bac634dc0665db9680838df68 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 67d8f172f84b6f7530bb705ceb5aa1ab7d03e639..bd0887b32ecda00c663d9440536a26bc2c6dcc1d 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 40cf2f03f2481d0091b29d6c4259b1f0e2688ec0..f7683c2d6b238c4140bd322813814ee23630dae4 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 75ebe4aad776be8595e8c78ff9ee062e0621c7ca..5eec2b16c58e0de6de43737cec4f0c1abea98b03 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 9ed8adffa5b635bd0bedf3b5dde7c70f4d6d82ad..53eb0de4b110ddf4ea40bd540b4efbc27339dd88 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 b18fc742b2c1298fdf50cb17e31d7544382908ba..4cebc5d734d04a151352a86220c9bd1a8e7a6f5b 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 98f135bd1e153208b9a61c9023f2036a6db80c09..9d042c907b7450d66999be0113ca2b115115428d 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 2d1d0258855ba5fa3444a8008e0db5a53594445c..2ece75e3cdda899a18f28e272501bb9d4acbee61 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 0000000000000000000000000000000000000000..252235a1eb97fcee790d7cf270935f06924f007f --- /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 5f0bd4772059fb3410c182bffc929ac069f988aa..84aa080940b6685d609e1f09dd72d1b23a500851 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 0000000000000000000000000000000000000000..fc47ce246da851244cf1630b15f493ded20249d8 --- /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 0000000000000000000000000000000000000000..30507c4b6e662a7e772e85c609fdb5fbc563a99f --- /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 c74b365925b0ccf005f1ccb0fa29da7da7f45c06..5a41191dc76e82cf8df7c56613d43ab476f3afa1 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 0000000000000000000000000000000000000000..f14430e9675c7a152c778df18fc892e3423afdc6 --- /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 1d35f55fd958e940852f0256910f7976e815555f..48c3f5f2cc5f21c4871d1b61ab3fefa80f2ed111 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 c3b786d72201049dac0cf12d35a38757ce9f0f42..8b1ef6cf791cd8f865c38ab8b368f89ddc7817f5 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 9415e90db6240e1619240d75ad41a62eb8091f9f..a117e83a9affb1d77f93586a4f7b66ff281f6af7 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 0000000000000000000000000000000000000000..eb26ea9125f412776e874c36f0ed6efc1f1768b1 --- /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 0000000000000000000000000000000000000000..3a94dcc7b8c1841946da4a061cdb44b4d8440442 --- /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 c7a251242e8a548a708ea0f747ca8d2d20f06501..f6ffb845d80c9169d14d1ce72fe1e067ab3d400f 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 acd94b0687d34c9c9d9f644ebb6b9d7cff2f51c2..c36f0f407432ca881f897469deebaeb947e0489e 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 1316c5fd642e920f302ed1b361c050897212b656..3172bb337f64aac45ee25e3e9169fc324b0fdce9 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