diff --git a/starter_code/pom.xml b/starter_code/pom.xml
index 608bb212f..17ba6c997 100644
--- a/starter_code/pom.xml
+++ b/starter_code/pom.xml
@@ -27,11 +27,17 @@
org.springframework.boot
- spring-boot-starter-web
+ spring-boot-starter-security
org.springframework.boot
- spring-boot-starter-tomcat
+ spring-boot-starter-web
+
+
+
+ com.auth0
+ java-jwt
+ 3.10.3
@@ -44,11 +50,18 @@
spring-boot-starter-test
test
-
- org.codehaus.mojo
- tomcat-maven-plugin
- 1.1
+ org.springframework.security
+ spring-security-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+ org.springframework.security
+ spring-security-config
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..7fdcc332f 100644
--- a/starter_code/src/main/java/com/example/demo/SareetaApplication.java
+++ b/starter_code/src/main/java/com/example/demo/SareetaApplication.java
@@ -3,13 +3,19 @@
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 {
-
+ @Bean
+ public BCryptPasswordEncoder bCryptPasswordEncoder(){
+ return new BCryptPasswordEncoder();
+ }
public static void main(String[] args) {
SpringApplication.run(SareetaApplication.class, args);
}
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..44893c62a 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,9 @@
package com.example.demo.controllers;
-import java.util.Optional;
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;
@@ -28,6 +27,9 @@ public class UserController {
@Autowired
private CartRepository cartRepository;
+ @Autowired
+ private BCryptPasswordEncoder bCryptPasswordEncoder;
+
@GetMapping("/id/{id}")
public ResponseEntity findById(@PathVariable Long id) {
return ResponseEntity.of(userRepository.findById(id));
@@ -38,7 +40,7 @@ public ResponseEntity findByUserName(@PathVariable String username) {
User user = userRepository.findByUsername(username);
return user == null ? ResponseEntity.notFound().build() : ResponseEntity.ok(user);
}
-
+
@PostMapping("/create")
public ResponseEntity createUser(@RequestBody CreateUserRequest createUserRequest) {
User user = new User();
@@ -46,6 +48,11 @@ public ResponseEntity createUser(@RequestBody CreateUserRequest createUser
Cart cart = new Cart();
cartRepository.save(cart);
user.setCart(cart);
+ if(createUserRequest.getPassword().length()<7 ||
+ !createUserRequest.getPassword().equals(createUserRequest.getConfirmPassword())){
+ return ResponseEntity.badRequest().build();
+ }
+ user.setPassword(bCryptPasswordEncoder.encode(createUserRequest.getPassword()));
userRepository.save(user);
return ResponseEntity.ok(user);
}
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..462d51cae 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,12 +26,23 @@ public class User {
@Column(nullable = false, unique = true)
@JsonProperty
private String username;
-
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "cart_id", referencedColumnName = "id")
@JsonIgnore
private Cart cart;
-
+ @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
+ @Column(nullable = false)
+ private String password;
+ public String getPassword(){
+ return password;
+ }
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public User() {
+ }
+
public Cart getCart() {
return cart;
}
@@ -55,7 +66,6 @@ public String getUsername() {
public void setUsername(String username) {
this.username = username;
}
-
-
-
+
+
}
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..5911f9e41 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,19 @@ public String getUsername() {
public void setUsername(String username) {
this.username = username;
}
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public void setConfirmPassword(String confirmPassword) {
+ this.confirmPassword = confirmPassword;
+ }
+ public String getPassword() {
+ return password;
+ }
+
+ public String getConfirmPassword() {
+ return 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..978c7b42a
--- /dev/null
+++ b/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationFilter.java
@@ -0,0 +1,83 @@
+package com.example.demo.security;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.auth0.jwt.algorithms.Algorithm;
+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 com.auth0.jwt.JWT;
+import com.example.demo.model.persistence.User;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+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 com.auth0.jwt.JWT;
+import com.example.demo.model.persistence.User;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
+
+public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
+
+ private AuthenticationManager authenticationManager;
+
+ public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
+ this.authenticationManager = authenticationManager;
+ }
+
+ @Override
+ public Authentication attemptAuthentication(HttpServletRequest req,
+ HttpServletResponse res) throws AuthenticationException {
+ try {
+ User credentials = new ObjectMapper()
+ .readValue(req.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 req,
+ HttpServletResponse res,
+ FilterChain chain,
+ Authentication auth) throws IOException, ServletException {
+
+ String token = JWT.create()
+ .withSubject(((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername())
+ .withExpiresAt(new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME))
+ .sign(HMAC512(SecurityConstants.SECRET.getBytes()));
+ res.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
+ }
+}
diff --git a/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationVerficationFilter.java b/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationVerficationFilter.java
new file mode 100644
index 000000000..3d85ab18c
--- /dev/null
+++ b/starter_code/src/main/java/com/example/demo/security/JWTAuthenticationVerficationFilter.java
@@ -0,0 +1,58 @@
+package com.example.demo.security;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+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 com.auth0.jwt.JWT;
+
+import static com.auth0.jwt.algorithms.Algorithm.HMAC512;
+
+@Component
+public class JWTAuthenticationVerficationFilter extends BasicAuthenticationFilter {
+
+ public JWTAuthenticationVerficationFilter(AuthenticationManager authManager) {
+ super(authManager);
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
+ throws IOException, ServletException {
+ String header = req.getHeader(SecurityConstants.HEADER_STRING);
+
+ if (header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
+ chain.doFilter(req, res);
+ return;
+ }
+
+ UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ chain.doFilter(req, res);
+ }
+
+ private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest req) {
+ String token = req.getHeader(SecurityConstants.HEADER_STRING);
+ if (token != null) {
+ String user = JWT.require(HMAC512(SecurityConstants.SECRET.getBytes())).build()
+ .verify(token.replace(SecurityConstants.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/SecurityConstants.java b/starter_code/src/main/java/com/example/demo/security/SecurityConstants.java
new file mode 100644
index 000000000..3f7cb5455
--- /dev/null
+++ b/starter_code/src/main/java/com/example/demo/security/SecurityConstants.java
@@ -0,0 +1,10 @@
+package com.example.demo.security;
+
+public class SecurityConstants {
+
+ public static final String SECRET = "oursecretkey";
+ 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/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..984331456
--- /dev/null
+++ b/starter_code/src/main/java/com/example/demo/security/UserDetailsServiceImpl.java
@@ -0,0 +1,28 @@
+package com.example.demo.security;
+
+import java.util.Collections;
+
+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 com.example.demo.model.persistence.User;
+import com.example.demo.model.persistence.repositories.UserRepository;
+
+@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..da0e7f3da
--- /dev/null
+++ b/starter_code/src/main/java/com/example/demo/security/WebSecurityConfiguration.java
@@ -0,0 +1,46 @@
+package com.example.demo.security;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.HttpMethod;
+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;
+
+@EnableWebSecurity
+public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ private UserDetailsServiceImpl userDetailsService;
+ private 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, SecurityConstants.SIGN_UP_URL).permitAll()
+ .anyRequest().authenticated()
+ .and()
+ .addFilter(new JWTAuthenticationFilter(authenticationManager()))
+ .addFilter(new JWTAuthenticationVerficationFilter(authenticationManager()))
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+ }
+
+ @Override
+ @Bean
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+ @Override
+ public void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
+ }
+}
diff --git a/starter_code/target/classes/com/example/demo/SareetaApplication.class b/starter_code/target/classes/com/example/demo/SareetaApplication.class
index 388a4f339..50d02e8d7 100644
Binary files a/starter_code/target/classes/com/example/demo/SareetaApplication.class and b/starter_code/target/classes/com/example/demo/SareetaApplication.class differ
diff --git a/starter_code/target/classes/com/example/demo/controllers/CartController.class b/starter_code/target/classes/com/example/demo/controllers/CartController.class
index 2626d1e2e..141ade405 100644
Binary files a/starter_code/target/classes/com/example/demo/controllers/CartController.class and b/starter_code/target/classes/com/example/demo/controllers/CartController.class differ
diff --git a/starter_code/target/classes/com/example/demo/controllers/ItemController.class b/starter_code/target/classes/com/example/demo/controllers/ItemController.class
index 52ac532e6..82e4a5b36 100644
Binary files a/starter_code/target/classes/com/example/demo/controllers/ItemController.class and b/starter_code/target/classes/com/example/demo/controllers/ItemController.class differ
diff --git a/starter_code/target/classes/com/example/demo/controllers/OrderController.class b/starter_code/target/classes/com/example/demo/controllers/OrderController.class
index e8501d299..1a61b3f7e 100644
Binary files a/starter_code/target/classes/com/example/demo/controllers/OrderController.class and b/starter_code/target/classes/com/example/demo/controllers/OrderController.class differ
diff --git a/starter_code/target/classes/com/example/demo/controllers/UserController.class b/starter_code/target/classes/com/example/demo/controllers/UserController.class
index 04bb6840f..3dabda79b 100644
Binary files a/starter_code/target/classes/com/example/demo/controllers/UserController.class and b/starter_code/target/classes/com/example/demo/controllers/UserController.class differ
diff --git a/starter_code/target/classes/com/example/demo/model/persistence/Item.class b/starter_code/target/classes/com/example/demo/model/persistence/Item.class
index 5bce916c6..3b71089e1 100644
Binary files a/starter_code/target/classes/com/example/demo/model/persistence/Item.class and b/starter_code/target/classes/com/example/demo/model/persistence/Item.class differ
diff --git a/starter_code/target/classes/com/example/demo/model/persistence/User.class b/starter_code/target/classes/com/example/demo/model/persistence/User.class
index b4fe72542..328dedc01 100644
Binary files a/starter_code/target/classes/com/example/demo/model/persistence/User.class and b/starter_code/target/classes/com/example/demo/model/persistence/User.class differ
diff --git a/starter_code/target/classes/com/example/demo/model/persistence/repositories/CartRepository.class b/starter_code/target/classes/com/example/demo/model/persistence/repositories/CartRepository.class
index 528fcb014..07321a06e 100644
Binary files a/starter_code/target/classes/com/example/demo/model/persistence/repositories/CartRepository.class and b/starter_code/target/classes/com/example/demo/model/persistence/repositories/CartRepository.class differ
diff --git a/starter_code/target/classes/com/example/demo/model/persistence/repositories/ItemRepository.class b/starter_code/target/classes/com/example/demo/model/persistence/repositories/ItemRepository.class
index fcdea8cef..41c95fcb9 100644
Binary files a/starter_code/target/classes/com/example/demo/model/persistence/repositories/ItemRepository.class and b/starter_code/target/classes/com/example/demo/model/persistence/repositories/ItemRepository.class differ
diff --git a/starter_code/target/classes/com/example/demo/model/persistence/repositories/OrderRepository.class b/starter_code/target/classes/com/example/demo/model/persistence/repositories/OrderRepository.class
index e47ebf196..ad5b636c6 100644
Binary files a/starter_code/target/classes/com/example/demo/model/persistence/repositories/OrderRepository.class and b/starter_code/target/classes/com/example/demo/model/persistence/repositories/OrderRepository.class differ
diff --git a/starter_code/target/classes/com/example/demo/model/persistence/repositories/UserRepository.class b/starter_code/target/classes/com/example/demo/model/persistence/repositories/UserRepository.class
index 54313b79f..bcaa1059e 100644
Binary files a/starter_code/target/classes/com/example/demo/model/persistence/repositories/UserRepository.class and b/starter_code/target/classes/com/example/demo/model/persistence/repositories/UserRepository.class differ
diff --git a/starter_code/target/classes/com/example/demo/model/requests/CreateUserRequest.class b/starter_code/target/classes/com/example/demo/model/requests/CreateUserRequest.class
index 2a2337627..99994e1e9 100644
Binary files a/starter_code/target/classes/com/example/demo/model/requests/CreateUserRequest.class and b/starter_code/target/classes/com/example/demo/model/requests/CreateUserRequest.class differ