diff --git a/starter_code/pom.xml b/starter_code/pom.xml index 4b807f2e4..c4721937d 100644 --- a/starter_code/pom.xml +++ b/starter_code/pom.xml @@ -1,6 +1,6 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework.boot @@ -8,16 +8,16 @@ 2.1.5.RELEASE - com.example - auth-course + com.udacity + ecommerce war - 0.0.1-SNAPSHOT - auth-course - Demo project for Spring Boot + 0.0.1 + ecommerce + Starter code for eCommerce project with Spring Boot 1.8 - 3.1.1 + 3.6.3 @@ -33,7 +33,6 @@ org.springframework.boot spring-boot-starter-tomcat - com.h2database h2 @@ -46,10 +45,29 @@ - org.apache.tomcat.maven + org.codehaus.mojo tomcat-maven-plugin - 2.2 - pom + 1.1 + + + org.springframework.boot + spring-boot-starter-security + + + com.auth0 + java-jwt + 3.4.0 + + + + org.slf4j + slf4j-log4j12 + 1.7.25 + test + + + org.projectlombok + lombok @@ -60,8 +78,47 @@ spring-boot-maven-plugin - org.apache.maven.plugins - maven-compiler-plugin + org.apache.maven.plugins + maven-compiler-plugin + + + + org.jacoco + jacoco-maven-plugin + 0.8.6 + + + + prepare-agent + + + + generate-code-coverage-report + test + + report + + + + + + org.codehaus.mojo + cobertura-maven-plugin + 2.7 + + + xml + + + + + + package + + cobertura + + + diff --git a/starter_code/src/main/java/com/example/demo/SareetaApplication.java b/starter_code/src/main/java/com/example/demo/SareetaApplication.java index f161f699d..6021acca3 100644 --- a/starter_code/src/main/java/com/example/demo/SareetaApplication.java +++ b/starter_code/src/main/java/com/example/demo/SareetaApplication.java @@ -3,15 +3,23 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.context.annotation.Bean; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @EnableJpaRepositories("com.example.demo.model.persistence.repositories") @EntityScan("com.example.demo.model.persistence") -@SpringBootApplication +@SpringBootApplication(exclude = {SecurityAutoConfiguration.class}) public class SareetaApplication { public static void main(String[] args) { SpringApplication.run(SareetaApplication.class, args); } + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() { + return new BCryptPasswordEncoder(); + } + } diff --git a/starter_code/src/main/java/com/example/demo/controllers/CartController.java b/starter_code/src/main/java/com/example/demo/controllers/CartController.java index 6f72169f8..78a4a4e0f 100644 --- a/starter_code/src/main/java/com/example/demo/controllers/CartController.java +++ b/starter_code/src/main/java/com/example/demo/controllers/CartController.java @@ -3,6 +3,9 @@ import java.util.Optional; import java.util.stream.IntStream; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -21,8 +24,10 @@ @RestController @RequestMapping("/api/cart") +@Slf4j public class CartController { - + + private static final Logger log = LoggerFactory.getLogger(CartController.class); @Autowired private UserRepository userRepository; @@ -36,16 +41,19 @@ public class CartController { public ResponseEntity addTocart(@RequestBody ModifyCartRequest request) { User user = userRepository.findByUsername(request.getUsername()); if(user == null) { + log.error("User is not found for creating cart request: user = {}", request.getUsername()); return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); } Optional item = itemRepository.findById(request.getItemId()); if(!item.isPresent()) { + log.error("Item id is not found for creating cart request: item id = {}", request.getItemId()); return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); } Cart cart = user.getCart(); IntStream.range(0, request.getQuantity()) .forEach(i -> cart.addItem(item.get())); cartRepository.save(cart); + log.info("cart is added: cart = {}", cart); return ResponseEntity.ok(cart); } @@ -53,16 +61,19 @@ public ResponseEntity addTocart(@RequestBody ModifyCartRequest request) { public ResponseEntity removeFromcart(@RequestBody ModifyCartRequest request) { User user = userRepository.findByUsername(request.getUsername()); if(user == null) { + log.error("User is not found for removing cart request: user = {}", request.getUsername()); return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); } Optional item = itemRepository.findById(request.getItemId()); if(!item.isPresent()) { + log.error("Item id is not found for removing cart request: item id = {}", request.getItemId()); return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); } Cart cart = user.getCart(); IntStream.range(0, request.getQuantity()) .forEach(i -> cart.removeItem(item.get())); cartRepository.save(cart); + log.info("Cart is removed: cart = {}", cart); return ResponseEntity.ok(cart); } diff --git a/starter_code/src/main/java/com/example/demo/controllers/ItemController.java b/starter_code/src/main/java/com/example/demo/controllers/ItemController.java index e990c0abc..2b033ec73 100644 --- a/starter_code/src/main/java/com/example/demo/controllers/ItemController.java +++ b/starter_code/src/main/java/com/example/demo/controllers/ItemController.java @@ -2,20 +2,23 @@ import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import com.example.demo.model.persistence.Item; import com.example.demo.model.persistence.repositories.ItemRepository; @RestController @RequestMapping("/api/item") +@Slf4j public class ItemController { + private static final Logger log = LoggerFactory.getLogger(ItemController.class); + @Autowired private ItemRepository itemRepository; @@ -23,18 +26,37 @@ public class ItemController { public ResponseEntity> getItems() { return ResponseEntity.ok(itemRepository.findAll()); } + + @PostMapping("/create") + public ResponseEntity createItem(@RequestBody Item item) { + if (item != null && item.getName() != null) { + itemRepository.save(item); + log.info("create Item successfully: item = {}", item); + return ResponseEntity.ok(item); + } + log.error("Item data is error: item = {}", item); + return ResponseEntity.badRequest().body(null); + } @GetMapping("/{id}") public ResponseEntity getItemById(@PathVariable Long id) { + if (!itemRepository.findById(id).isPresent()) { + log.error("Item can not be found by Id {}", id); + return ResponseEntity.notFound().build(); + } + log.info("Item can be found by Id {}", id); return ResponseEntity.of(itemRepository.findById(id)); } @GetMapping("/name/{name}") public ResponseEntity> getItemsByName(@PathVariable String name) { List items = itemRepository.findByName(name); - return items == null || items.isEmpty() ? ResponseEntity.notFound().build() - : ResponseEntity.ok(items); - + if (items == null || items.isEmpty()) { + log.error("Item can not be found by name {}", name); + return ResponseEntity.notFound().build(); + } + log.info("Item can be found by name {}", name); + return ResponseEntity.ok(items); } } diff --git a/starter_code/src/main/java/com/example/demo/controllers/OrderController.java b/starter_code/src/main/java/com/example/demo/controllers/OrderController.java index 79b8b288c..09929c6b1 100644 --- a/starter_code/src/main/java/com/example/demo/controllers/OrderController.java +++ b/starter_code/src/main/java/com/example/demo/controllers/OrderController.java @@ -2,6 +2,9 @@ import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -19,33 +22,48 @@ @RestController @RequestMapping("/api/order") +@Slf4j public class OrderController { - - - @Autowired - private UserRepository userRepository; - - @Autowired - private OrderRepository orderRepository; - - - @PostMapping("/submit/{username}") - public ResponseEntity submit(@PathVariable String username) { - User user = userRepository.findByUsername(username); - if(user == null) { - return ResponseEntity.notFound().build(); - } - UserOrder order = UserOrder.createFromCart(user.getCart()); - orderRepository.save(order); - return ResponseEntity.ok(order); - } - - @GetMapping("/history/{username}") - public ResponseEntity> getOrdersForUser(@PathVariable String username) { - User user = userRepository.findByUsername(username); - if(user == null) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(orderRepository.findByUser(user)); - } + + + private static final Logger log = LoggerFactory.getLogger(OrderController.class); + @Autowired + private UserRepository userRepository; + + @Autowired + private OrderRepository orderRepository; + + + @PostMapping("/submit/{username}") + public ResponseEntity submit(@PathVariable String username) { + try { + User user = userRepository.findByUsername(username); + if (user == null) { + log.error("User must be registered before submitting an order"); + return ResponseEntity.notFound().build(); + } + UserOrder order = UserOrder.createFromCart(user.getCart()); + orderRepository.save(order); + log.info("create order successfully: {}", order); + return ResponseEntity.ok(order); + } catch (RuntimeException e) { + log.error("There is an error when trying to creating an order"); + return ResponseEntity.notFound().build(); + } + } + + @GetMapping("/history/{username}") + public ResponseEntity> getOrdersForUser(@PathVariable String username) { + try { + User user = userRepository.findByUsername(username); + if (user == null) { + log.error("Order not found!"); + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(orderRepository.findByUser(user)); + } catch (RuntimeException e) { + log.error("There is an error when trying to find an order by username: {}", username); + return ResponseEntity.notFound().build(); + } + } } diff --git a/starter_code/src/main/java/com/example/demo/controllers/UserController.java b/starter_code/src/main/java/com/example/demo/controllers/UserController.java index 87e8089df..b18fd8568 100644 --- a/starter_code/src/main/java/com/example/demo/controllers/UserController.java +++ b/starter_code/src/main/java/com/example/demo/controllers/UserController.java @@ -1,10 +1,13 @@ package com.example.demo.controllers; -import java.util.Optional; +import java.util.Objects; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -18,36 +21,87 @@ import com.example.demo.model.persistence.repositories.UserRepository; import com.example.demo.model.requests.CreateUserRequest; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; + @RestController @RequestMapping("/api/user") +@Slf4j public class UserController { - + + private static final Logger log = LoggerFactory.getLogger(UserController.class); @Autowired private UserRepository userRepository; @Autowired private CartRepository cartRepository; + @Autowired + private BCryptPasswordEncoder bCryptPasswordEncoder; + @GetMapping("/id/{id}") public ResponseEntity findById(@PathVariable Long id) { + log.info("Get user by id: {}", id); return ResponseEntity.of(userRepository.findById(id)); } @GetMapping("/{username}") public ResponseEntity findByUserName(@PathVariable String username) { - User user = userRepository.findByUsername(username); - return user == null ? ResponseEntity.notFound().build() : ResponseEntity.ok(user); + try { + log.error("Find user by username: {}", username); + User user = userRepository.findByUsername(username); + return user == null ? ResponseEntity.notFound().build() : ResponseEntity.ok(user); + } catch (RuntimeException e) { + log.error("There is an error when trying to find user by name: {}", username); + return ResponseEntity.notFound().build(); + } } @PostMapping("/create") public ResponseEntity createUser(@RequestBody CreateUserRequest createUserRequest) { User user = new User(); - user.setUsername(createUserRequest.getUsername()); - Cart cart = new Cart(); - cartRepository.save(cart); - user.setCart(cart); - userRepository.save(user); + try { + boolean isUserInfoError = isCreateUserInfoError(createUserRequest); + boolean isPasswordInvalid = isPasswordTooShort(createUserRequest); + boolean isPasswordConfirmNotMatch = isPasswordConfirmNotMatch(createUserRequest); + if (!isUserInfoError) { + if (isPasswordInvalid) { + log.error("Password must include more than 7 characters: password = {}", createUserRequest.getPassword()); + return ResponseEntity.badRequest().body(user); + } else if (isPasswordConfirmNotMatch) { + log.error("Confirm password is not match: password = {}", createUserRequest.getConfirmPassword()); + return ResponseEntity.badRequest().body(user); + } + } else { + log.error("Username Or Password is missing: user = {}", createUserRequest); + return ResponseEntity.badRequest().body(user); + } + user.setUsername(createUserRequest.getUsername()); + user.setPassword(createUserRequest.getPassword()); + Cart cart = new Cart(); + cartRepository.save(cart); + user.setCart(cart); + userRepository.save(user); + log.info("create user successfully: user = {}", createUserRequest); + } catch (RuntimeException e) { + log.error("There is an error when trying to create user: user = {}", createUserRequest); + return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(user); + } return ResponseEntity.ok(user); } + + private boolean isCreateUserInfoError(CreateUserRequest createUserRequest) { + return Objects.isNull(createUserRequest.getPassword()) + || Objects.isNull(createUserRequest.getUsername()) + || createUserRequest.getPassword().isEmpty() + || createUserRequest.getUsername().isEmpty(); + } + + private boolean isPasswordTooShort(CreateUserRequest createUserRequest) { + return createUserRequest.getPassword().length() < 7; + } + + private boolean isPasswordConfirmNotMatch(CreateUserRequest createUserRequest) { + return !createUserRequest.getPassword().contentEquals(createUserRequest.getConfirmPassword()); + } } diff --git a/starter_code/src/main/java/com/example/demo/model/persistence/User.java b/starter_code/src/main/java/com/example/demo/model/persistence/User.java index ab85ccc60..fbd7b0010 100644 --- a/starter_code/src/main/java/com/example/demo/model/persistence/User.java +++ b/starter_code/src/main/java/com/example/demo/model/persistence/User.java @@ -26,6 +26,10 @@ public class User { @Column(nullable = false, unique = true) @JsonProperty private String username; + + @Column(nullable = false, unique = true) + @JsonProperty + private String password; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "cart_id", referencedColumnName = "id") @@ -55,7 +59,12 @@ public String getUsername() { public void setUsername(String username) { this.username = username; } - - - + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } } diff --git a/starter_code/src/main/java/com/example/demo/model/requests/CreateUserRequest.java b/starter_code/src/main/java/com/example/demo/model/requests/CreateUserRequest.java index a92d0bbb6..5997237bf 100644 --- a/starter_code/src/main/java/com/example/demo/model/requests/CreateUserRequest.java +++ b/starter_code/src/main/java/com/example/demo/model/requests/CreateUserRequest.java @@ -7,6 +7,12 @@ public class CreateUserRequest { @JsonProperty private String username; + @JsonProperty + private String password; + + @JsonProperty + private String confirmPassword; + public String getUsername() { return username; } @@ -14,4 +20,20 @@ public String getUsername() { public void setUsername(String username) { this.username = username; } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getConfirmPassword() { + return confirmPassword; + } + + public void setConfirmPassword(String confirmPassword) { + this.confirmPassword = confirmPassword; + } } diff --git a/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationFilter.java b/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationFilter.java new file mode 100644 index 000000000..f6986c555 --- /dev/null +++ b/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationFilter.java @@ -0,0 +1,55 @@ +package com.example.demo.security; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.example.demo.model.persistence.User; +import com.example.demo.utils.AppConfig; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; + +public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter { + + private final AuthenticationManager authenticationManager; + + public JWTAuthenticationFilter(AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { + try { + User credentials = new ObjectMapper() + .readValue(request.getInputStream(), User.class); + return authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken( + credentials.getUsername(), + credentials.getPassword(), + new ArrayList<>() + ) + ); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { + String token = JWT.create() + .withSubject(((org.springframework.security.core.userdetails.User) authResult.getPrincipal()).getUsername()) + .withExpiresAt(new Date(System.currentTimeMillis() + AppConfig.EXPIRATION_TIME)) + .sign(Algorithm.HMAC512(AppConfig.SECRET.getBytes())); + response.addHeader(AppConfig.HEADER_STRING, AppConfig.TOKEN_PREFIX + token); + } +} diff --git a/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationVerificationFilter.java b/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationVerificationFilter.java new file mode 100644 index 000000000..2534bbf3c --- /dev/null +++ b/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationVerificationFilter.java @@ -0,0 +1,52 @@ +package com.example.demo.security; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.example.demo.utils.AppConfig; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; + +@Component +public class JWTAuthenticationVerificationFilter extends BasicAuthenticationFilter { + + public JWTAuthenticationVerificationFilter(AuthenticationManager authenticationManager) { + super(authenticationManager); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { + String header = request.getHeader(AppConfig.HEADER_STRING); + if (header == null || !header.startsWith(AppConfig.TOKEN_PREFIX)) { + chain.doFilter(request, response); + return; + } + + UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(request); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + chain.doFilter(request, response); + } + + private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) { + String token = request.getHeader(AppConfig.HEADER_STRING); + if (token != null) { + String user = JWT.require(Algorithm.HMAC512(AppConfig.SECRET.getBytes())).build() + .verify(token.replace(AppConfig.TOKEN_PREFIX, "")) + .getSubject(); + if (user != null) { + return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>()); + } + return null; + } + return null; + } +} diff --git a/starter_code/src/main/java/com/example/demo/security/UserDetailsServiceImpl.java b/starter_code/src/main/java/com/example/demo/security/UserDetailsServiceImpl.java new file mode 100644 index 000000000..320524244 --- /dev/null +++ b/starter_code/src/main/java/com/example/demo/security/UserDetailsServiceImpl.java @@ -0,0 +1,27 @@ +package com.example.demo.security; + +import com.example.demo.model.persistence.User; +import com.example.demo.model.persistence.repositories.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +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 java.util.Collections; + +@Service +public class UserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private UserRepository userRepository; + + @Override + public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { + User user = userRepository.findByUsername(userName); + if (user == null) { + throw new UsernameNotFoundException(userName); + } + return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), Collections.emptyList()); + } +} diff --git a/starter_code/src/main/java/com/example/demo/security/WebSecurityConfiguration.java b/starter_code/src/main/java/com/example/demo/security/WebSecurityConfiguration.java new file mode 100644 index 000000000..594b3a6d2 --- /dev/null +++ b/starter_code/src/main/java/com/example/demo/security/WebSecurityConfiguration.java @@ -0,0 +1,54 @@ +package com.example.demo.security; + +import com.example.demo.utils.AppConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +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.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; + +@EnableWebSecurity +public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { + + private final UserDetailsServiceImpl userDetailsService; + + private final BCryptPasswordEncoder bCryptPasswordEncoder; + + public WebSecurityConfiguration(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) { + this.userDetailsService = userDetailsService; + this.bCryptPasswordEncoder = bCryptPasswordEncoder; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.cors().and().csrf().disable().authorizeRequests() + .antMatchers(HttpMethod.POST, AppConfig.SIGN_UP_URL).permitAll() + .anyRequest().authenticated() + .and() + .addFilter(new JWTAuthenticationFilter(authenticationManager())) + .addFilter(new JWTAuthenticationVerificationFilter(authenticationManager())) + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .exceptionHandling() + .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)); + } + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.parentAuthenticationManager(authenticationManagerBean()) + .userDetailsService(userDetailsService) + .passwordEncoder(bCryptPasswordEncoder); + } +} diff --git a/starter_code/src/main/java/com/example/demo/utils/AppConfig.java b/starter_code/src/main/java/com/example/demo/utils/AppConfig.java new file mode 100644 index 000000000..48d28a1a7 --- /dev/null +++ b/starter_code/src/main/java/com/example/demo/utils/AppConfig.java @@ -0,0 +1,9 @@ +package com.example.demo.utils; + +public class AppConfig { + public static final String SECRET = "mysecretkey"; + public static final long EXPIRATION_TIME = 864_000_000; // 10 days + public static final String TOKEN_PREFIX = "Bearer "; + public static final String HEADER_STRING = "Authorization"; + public static final String SIGN_UP_URL = "/api/user/create"; +} diff --git a/starter_code/src/main/resources/application.properties b/starter_code/src/main/resources/application.properties deleted file mode 100644 index ed303a7d4..000000000 --- a/starter_code/src/main/resources/application.properties +++ /dev/null @@ -1,6 +0,0 @@ -spring.datasource.driver-class-name=org.h2.Driver -spring.datasource.url=jdbc:h2:mem:bootapp;DB_CLOSE_DELAY=-1 -spring.datasource.username=sa -spring.datasource.password= -spring.jpa.hibernate.ddl-auto=update -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect \ No newline at end of file diff --git a/starter_code/src/main/resources/application.yml b/starter_code/src/main/resources/application.yml new file mode 100644 index 000000000..a9e687340 --- /dev/null +++ b/starter_code/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:bootapp;DB_CLOSE_DELAY=-1 + username: sa + password: "" + jpa: + hibernate: + ddl-auto: update + properties: + hibernate: + dialect: org.hibernate.dialect.H2Dialect + +logging: + level: + org: + slf4j: + Logger: TRACE + file: myLog.csv