Skip to content

Commit

Permalink
Complete access and refresh token implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
fizzy-fifs committed Aug 29, 2023
1 parent cdade4d commit 0152f47
Show file tree
Hide file tree
Showing 19 changed files with 158 additions and 176 deletions.
31 changes: 14 additions & 17 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.3</version>
<version>3.0.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
Expand All @@ -14,7 +14,7 @@
<name>holiday-planner</name>
<description>Holiday Planner</description>
<properties>
<java.version>16</java.version>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
Expand All @@ -26,6 +26,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.3</version>
</dependency>

<dependency>
Expand All @@ -52,21 +53,23 @@
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-security -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-security</artifactId>
<version>1.7.0</version>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>

<dependency>
Expand Down Expand Up @@ -129,12 +132,6 @@
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>3.3.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver-legacy -->
<dependency>
<groupId>org.mongodb</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.example.holidayplanner;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication()
@EnableScheduling
@EnableMongoRepositories
@OpenAPIDefinition
public class HolidayPlannerApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.example.holidayplanner.availableDates;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -15,7 +15,7 @@

@RestController
@RequestMapping("/api/v1.0/availabledates")
@Api(tags = "Available Dates")
@Tag(name = "Available Dates")
@SecurityRequirement(name = "holidayPlannerSecurity")
public class AvailableDatesController {

Expand All @@ -28,7 +28,7 @@ public AvailableDatesController(AvailableDatesService availableDatesService) {


@PostMapping(path = "/findmultiplebyid")
@ApiOperation(value = "Find multiple available dates by id")
@Operation(summary = "Find multiple available dates by id")
public ResponseEntity findMultipleById(@RequestBody List<String> availableDatesIds) throws JsonProcessingException {
return availableDatesService.findMultipleById(availableDatesIds);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.example.holidayplanner.budget;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -15,7 +15,7 @@

@RestController
@RequestMapping("/api/v1.0/budgets")
@Api(tags = "Budgets")
@Tag(name = "Budgets")
@SecurityRequirement(name = "holidayPlannerSecurity")
public class BudgetController {

Expand All @@ -27,7 +27,7 @@ public BudgetController(BudgetService budgetService) {
}

@PostMapping(path = "/findmultiplebyid")
@ApiOperation(value = "Find multiple budgets by id")
@Operation(summary = "Find multiple budgets by id")
public ResponseEntity findMultipleById(@RequestBody List<String> budgetIds) throws JsonProcessingException {
return budgetService.findMultipleById(budgetIds);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.example.holidayplanner.config;

import com.example.holidayplanner.config.jwt.JwtRequestFilter;
import org.apache.catalina.filters.CorsFilter;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -15,6 +15,9 @@
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import static org.springframework.security.config.Customizer.withDefaults;

Expand All @@ -27,35 +30,21 @@ public class SecurityConfigurer {
@Autowired
private JwtRequestFilter jwtRequestFilter;

// @Override
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(myUserDetailsService);
// }

@Bean
public SecurityFilterChain configure (HttpSecurity http) throws Exception {
return http.cors(withDefaults())
.csrf((csrf) -> csrf.disable())
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/api/v1.0/users/newuser", "/api/v1.0/users/login", "/", "/csrf", "/v3/api-docs",
.requestMatchers("/api/v1.0/users/newuser", "/api/v1.0/users/login", "/", "/csrf",
"/swagger-resources/configuration/ui", "/configuration/ui",
"/swagger-resources", "/swagger-resources/configuration/security",
"/configuration/security", "/swagger-ui/**", "/v2/api-docs/**", "/webjars/**", "/swagger-ui.html").permitAll())
"/swagger-resources/**", "/swagger-resources/configuration/security",
"/configuration/security", "configuration/**", "/swagger-ui/**", "/v3/api-docs/**", "/webjars/**", "/swagger-ui.html").permitAll()
.anyRequest().authenticated())
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore( jwtRequestFilter, UsernamePasswordAuthenticationFilter.class )
.addFilterBefore(corsFilter(), SessionManagementFilter.class).build();
}

// @Override
// public void configure(WebSecurity web) throws Exception {
// web.ignoring().antMatchers("/api/v1.0/users/newuser");
// web.ignoring().antMatchers("/api/v1.0/users/login");
// web.ignoring().antMatchers("/", "/csrf", "/v3/api-docs",
// "/swagger-resources/configuration/ui", "/configuration/ui",
// "/swagger-resources", "/swagger-resources/configuration/security",
// "/configuration/security", "/swagger-ui/**", "/v2/api-docs/**", "/webjars/**", "/swagger-ui.html");
// }

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
Expand All @@ -68,7 +57,12 @@ public AuthenticationManager authenticationManagerBean(final AuthenticationConfi

@Bean
CorsFilter corsFilter() {
CorsFilter corsFilter = new CorsFilter();
CorsFilter corsFilter = new CorsFilter(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
return null;
}
});
return corsFilter;
}
}
78 changes: 19 additions & 59 deletions src/main/java/com/example/holidayplanner/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -1,71 +1,31 @@
package com.example.holidayplanner.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Configuration
@EnableSwagger2
public class SwaggerConfig implements WebMvcConfigurer {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.securityContexts(Arrays.asList(securityContext()))
.securitySchemes(Arrays.asList(apiKey()))
.pathMapping("/")
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.tags(new Tag("User", "All User Endpoints"), new Tag("Group", "All Group Endpoints"), new Tag("Holiday", "All Holiday Endpoints"))

.directModelSubstitute(LocalDate.class, String.class)
.genericModelSubstitutes(ResponseEntity.class)
;
}

ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Holiday Planner")
.version("1.0.0")
.description("Swagger page for the Holiday Planner Monolith")
.build()
;
}

@Override
public void addViewControllers(final ViewControllerRegistry registry) {
registry.addRedirectViewController("/", "/swagger-ui/#/");
}

private ApiKey apiKey () {
return new ApiKey("Access Token", "Authorization", SecurityScheme.In.HEADER.name());
}

private SecurityContext securityContext() {
return SecurityContext.builder().securityReferences(securityReference()).build();
}

private List<SecurityReference> securityReference() {
AuthorizationScope[] authorizationScope = { new AuthorizationScope("global", "Empty Description")};
return Collections.singletonList(new SecurityReference("Access Token", authorizationScope));
public OpenAPI springShopOpenAPI() {
return new OpenAPI().info(new Info().title("GetAway")
.description("Api documentation for GetAway")
.version("v0.01")
.license(new License()
.name("Apache 2.0").url("http://springdoc.org")
))
.components(new Components().addSecuritySchemes("Api Key", new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.scheme("bearer")
.bearerFormat("jwt")
.in(SecurityScheme.In.HEADER)
.name("Authorization")
)).addSecurityItem(new SecurityRequirement().addList("Api Key"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Date;

@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private MyUserDetailsService myUserDetailsService;

@Autowired
private JwtUtil jwtUtil;
private final JwtUtil jwtUtil;

@Autowired
private final TokenService tokenService;

public JwtRequestFilter(TokenService tokenService) {
public JwtRequestFilter(JwtUtil jwtUtil, TokenService tokenService) {
this.jwtUtil = jwtUtil;
this.tokenService = tokenService;
}

Expand All @@ -38,31 +40,33 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
final String authorizationHeader = request.getHeader("Authorization");

String jwt = null;
String email = null;
// String email = null;

if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
email = jwtUtil.extractEmail(jwt);
// email = jwtUtil.extractEmail(jwt);
}

if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.myUserDetailsService.loadUserByUsername(email);

if (jwt != null && SecurityContextHolder.getContext().getAuthentication() == null) {
Token token = tokenService.findByAccessToken(jwt);

if (!jwtUtil.validateAccessToken(token.getAccessToken(), userDetails) && jwtUtil.validateRefreshToken(token.getRefreshToken(), userDetails)) {
UserDetails userDetails = this.myUserDetailsService.loadUserByUsername(token.getOwner().getEmail());

if (!jwtUtil.validateAccessToken(token.getAccessToken()) && token.getRefreshTokenExpiration().after(new Date())) {
String newAccessToken = jwtUtil.generateToken(userDetails);

String newRefreshToken = jwtUtil.generateRefreshToken(userDetails);

token.setAccessToken(newAccessToken);
token.setAccessTokenExpiration(jwtUtil.extractExpiration(newAccessToken));
token.setRefreshToken(newRefreshToken);
token.setRefreshTokenExpiration(jwtUtil.extractExpiration(newRefreshToken));
tokenService.saveToken(token);

response.setHeader("NewAccessToken", newAccessToken);
}

if (jwtUtil.validateAccessToken(token.getAccessToken(), userDetails)) {
if (jwtUtil.validateAccessToken(token.getAccessToken())) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
Expand Down
Loading

0 comments on commit 0152f47

Please sign in to comment.