diff --git a/shoppingcart/pom.xml b/shoppingcart/pom.xml
index 1a2d4e3a..46a75631 100644
--- a/shoppingcart/pom.xml
+++ b/shoppingcart/pom.xml
@@ -76,6 +76,24 @@
2.9.2
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+
+ org.springframework.security.oauth
+ spring-security-oauth2
+ 2.3.6.RELEASE
+
+
diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/AuthorizationServerConfig.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/AuthorizationServerConfig.java
new file mode 100644
index 00000000..2aa2e3ae
--- /dev/null
+++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/AuthorizationServerConfig.java
@@ -0,0 +1,59 @@
+package com.lambdaschool.shoppingcart.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
+import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+@Configuration
+@EnableAuthorizationServer
+public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
+
+ static final String CLIENT_ID = System.getenv("OAUTHCLIENTID");
+ static final String CLINET_SECRET = System.getenv("OAUTHCLIENTSECRET");
+ static final String GRANT_TYPE_PASSWORD = "password";
+ static final String AUTHORIZATION_CODE = "authorization_code";
+
+ static final String SCOPE_READ = "read";
+ static final String SCOPE_WRITE = "write";
+ static final String SCOPE_TRUST = "trust";
+
+ static final int ACCESS_TOKEN_VALIDITY_SECONDS = -1;
+
+ @Autowired
+ private TokenStore tokenStore;
+
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
+ @Autowired
+ private PasswordEncoder encoder;
+
+ @Override
+ public void configure(ClientDetailsServiceConfigurer configurer)
+ throws Exception {
+ configurer.inMemory()
+ .withClient(CLIENT_ID)
+ .secret(encoder.encode(CLINET_SECRET))
+ .authorizedGrantTypes(GRANT_TYPE_PASSWORD,
+ AUTHORIZATION_CODE)
+ .scopes(SCOPE_READ,
+ SCOPE_WRITE,
+ SCOPE_TRUST)
+ .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS);
+ }
+
+ @Override
+ public void configure(AuthorizationServerEndpointsConfigurer endpoints)
+ throws Exception {
+ endpoints.tokenStore(tokenStore)
+ .authenticationManager(authenticationManager);
+ endpoints.pathMapping("/oauth/token",
+ "/login");
+ }
+}
diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/ResourceServerConfig.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/ResourceServerConfig.java
new file mode 100644
index 00000000..42f709e9
--- /dev/null
+++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/ResourceServerConfig.java
@@ -0,0 +1,39 @@
+package com.lambdaschool.shoppingcart.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+
+ private static final String RESOURCE_ID = "resource_id";
+
+ @Override
+ public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
+ resources.resourceId(RESOURCE_ID)
+ .stateless(false);
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests()
+ .antMatchers("/", "/h2-console/**", "/createnewuser")
+ .permitAll()
+ .antMatchers("/roles/**", "/products/**")
+ .hasAnyRole("ADMIN")
+ .antMatchers("/logout")
+ .authenticated()
+ .and()
+ .exceptionHandling()
+ .accessDeniedHandler(new OAuth2AccessDeniedHandler());
+
+ http.csrf().disable();
+ http.headers().frameOptions().disable();
+ http.logout().disable();
+ }
+}
diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/SecurityConfig.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/SecurityConfig.java
new file mode 100644
index 00000000..c353a49d
--- /dev/null
+++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/SecurityConfig.java
@@ -0,0 +1,45 @@
+package com.lambdaschool.shoppingcart.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
+
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ @Bean
+ public AuthenticationManager authenticationManagerBean() throws Exception {
+ return super.authenticationManagerBean();
+ }
+
+ @Autowired
+ private UserDetailsService securityUserService;
+
+ @Autowired
+ public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
+ auth.userDetailsService(securityUserService).passwordEncoder(encoder());
+ }
+
+ @Bean
+ public PasswordEncoder encoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Bean
+ public TokenStore tokenStore() {
+ return new InMemoryTokenStore();
+ }
+}
diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/controllers/UserController.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/controllers/UserController.java
index 50737ff4..abbe99fb 100755
--- a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/controllers/UserController.java
+++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/controllers/UserController.java
@@ -6,6 +6,8 @@
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
@@ -70,6 +72,7 @@ public ResponseEntity> getUserById(
* @return JSON object of the user you seek
* @see UserService#findByName(String) UserService.findByName(String)
*/
+ @PreAuthorize(value = "hasAnyRole('ADMIN')")
@GetMapping(value = "/user/name/{userName}",
produces = "application/json")
public ResponseEntity> getUserByName(
@@ -89,6 +92,7 @@ public ResponseEntity> getUserByName(
* @return A JSON list of users you seek
* @see UserService#findByNameContaining(String) UserService.findByNameContaining(String)
*/
+ @PreAuthorize(value = "hasAnyRole('ADMIN')")
@GetMapping(value = "/user/name/like/{userName}",
produces = "application/json")
public ResponseEntity> getUserLikeName(
@@ -111,6 +115,7 @@ public ResponseEntity> getUserLikeName(
* @throws URISyntaxException Exception if something does not work in creating the location header
* @see UserService#save(User) UserService.save(User)
*/
+ @PreAuthorize(value = "hasAnyRole('ADMIN')")
@PostMapping(value = "/user",
consumes = "application/json")
public ResponseEntity> addNewUser(
@@ -148,6 +153,7 @@ public ResponseEntity> addNewUser(
* @return status of OK
* @see UserService#save(User) UserService.save(User)
*/
+ @PreAuthorize(value = "hasAnyRole('ADMIN')")
@PutMapping(value = "/user/{userid}",
consumes = "application/json")
public ResponseEntity> updateFullUser(
@@ -194,6 +200,7 @@ public ResponseEntity> updateUser(
* @param id the primary key of the user you wish to delete
* @return Status of OK
*/
+ @PreAuthorize(value = "hasAnyRole('ADMIN')")
@DeleteMapping(value = "/user/{id}")
public ResponseEntity> deleteUserById(
@PathVariable
@@ -202,4 +209,14 @@ public ResponseEntity> deleteUserById(
userService.delete(id);
return new ResponseEntity<>(HttpStatus.OK);
}
+
+ @GetMapping(value = "/myinfo", produces = "application/json")
+ public ResponseEntity> getCurrentUserInfo(){
+ String uname = SecurityContextHolder.getContext().getAuthentication().getName();
+ User user = userService.findByName(uname);
+
+ return new ResponseEntity<>(user, HttpStatus.OK);
+ }
+
+
}
\ No newline at end of file
diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/models/User.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/models/User.java
index fcc02f61..e0bd9db9 100644
--- a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/models/User.java
+++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/models/User.java
@@ -2,10 +2,14 @@
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import javax.persistence.*;
import javax.validation.constraints.Email;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
/**
@@ -170,6 +174,11 @@ public String getPassword()
*/
public void setPassword(String password)
{
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ this.password = passwordEncoder.encode(password);
+ }
+
+ public void setPasswordNoEncrypt(String password){
this.password = password;
}
@@ -212,4 +221,14 @@ public void setCarts(Set carts)
{
this.carts = carts;
}
+
+ public List getAuthority(){
+ List rtnList = new ArrayList<>();
+
+ for (UserRoles r : this.roles) {
+ String myRole = "ROLE_" + r.getRole().getName().toUpperCase();
+ rtnList.add(new SimpleGrantedAuthority(myRole));
+ }
+ return rtnList;
+ }
}
diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/SecurityUserServiceImpl.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/SecurityUserServiceImpl.java
new file mode 100644
index 00000000..e9bef1c4
--- /dev/null
+++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/SecurityUserServiceImpl.java
@@ -0,0 +1,30 @@
+package com.lambdaschool.shoppingcart.services;
+
+
+import com.lambdaschool.shoppingcart.exceptions.ResourceNotFoundException;
+import com.lambdaschool.shoppingcart.models.User;
+import com.lambdaschool.shoppingcart.repository.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 org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+@Service(value = "securityUserService")
+public class SecurityUserServiceImpl implements UserDetailsService {
+ @Autowired
+ UserRepository userRepository;
+
+ @Transactional
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ User user = userRepository.findByUsername(username.toLowerCase());
+
+ if ( user == null ) {
+ throw new ResourceNotFoundException("Invalid username or password");
+ }
+ return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), user.getAuthority());
+ }
+}
diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserAuditing.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserAuditing.java
index 725dcee1..3b54b165 100644
--- a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserAuditing.java
+++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserAuditing.java
@@ -1,6 +1,8 @@
package com.lambdaschool.shoppingcart.services;
import org.springframework.data.domain.AuditorAware;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import java.util.Optional;
@@ -22,7 +24,15 @@ public class UserAuditing
public Optional getCurrentAuditor()
{
String uname;
+
+ Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+
+ if(auth == null) {
uname = "SYSTEM";
+ } else {
+ uname = auth.getName();
+ }
+
return Optional.of(uname);
}
}
diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserServiceImpl.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserServiceImpl.java
index f88ce29b..80434fb2 100755
--- a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserServiceImpl.java
+++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserServiceImpl.java
@@ -100,7 +100,7 @@ public User save(User user)
newUser.setUsername(user.getUsername()
.toLowerCase());
- newUser.setPassword(user.getPassword());
+ newUser.setPasswordNoEncrypt(user.getPassword());
newUser.setPrimaryemail(user.getPrimaryemail()
.toLowerCase());
@@ -140,7 +140,7 @@ public User update(
if (user.getPassword() != null)
{
- currentUser.setPassword(user.getPassword());
+ currentUser.setPasswordNoEncrypt(user.getPassword());
}
if (user.getPrimaryemail() != null)