diff --git a/shoppingcart/pom.xml b/shoppingcart/pom.xml index 1a2d4e3a..7e16c495 100644 --- a/shoppingcart/pom.xml +++ b/shoppingcart/pom.xml @@ -35,6 +35,20 @@ runtime true + + 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 + com.h2database 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..d16b0d98 --- /dev/null +++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/AuthorizationServerConfig.java @@ -0,0 +1,56 @@ +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 { + + private static final String CLIENT_ID = System.getenv("OAUTHCLIENTID"); + private static final String CLIENT_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 passwordEncoder; + + @Override + public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { + endpoints.tokenStore(tokenStore) + .authenticationManager(authenticationManager); + endpoints.pathMapping("/oauth/token","/login"); + } + + @Override + public void configure(ClientDetailsServiceConfigurer clients) throws Exception { + clients.inMemory() + .withClient(CLIENT_ID) + .secret(passwordEncoder.encode(CLIENT_SECRET)) + .authorizedGrantTypes(GRANT_TYPE_PASSWORD,AUTHORIZATION_CODE) + .scopes(SCOPE_READ,SCOPE_TRUST,SCOPE_WRITE) + .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS); + + + } +} 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..47f7b876 --- /dev/null +++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/ResourceServerConfig.java @@ -0,0 +1,45 @@ +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/**", + "/swagger-resources/**", + "/swagger-resource/**", + "/swagger-ui.html", + "/v2/api-docs", + "/webjars/**", + "/createnewuser") + .permitAll() + .antMatchers("/roles/**","/products/**","/users/**") + .hasAnyRole("ADMIN") + .antMatchers("/carts/**") + .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/SecurityServiceConfig.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/SecurityServiceConfig.java new file mode 100644 index 00000000..8daaf6b0 --- /dev/null +++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/SecurityServiceConfig.java @@ -0,0 +1,46 @@ +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 SecurityServiceConfig extends WebSecurityConfigurerAdapter { + + @Override + @Bean + public AuthenticationManager authenticationManagerBean()throws Exception{ + return super.authenticationManagerBean(); + } + @Bean + public TokenStore tokenStore(){ + return new InMemoryTokenStore(); + } + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } + @Autowired + private UserDetailsService securityUserDetails; + + + @Autowired + public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(securityUserDetails) + .passwordEncoder(passwordEncoder()); + } +} diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/SimpleCorsFilter.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/SimpleCorsFilter.java new file mode 100644 index 00000000..bdb19bf4 --- /dev/null +++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/config/SimpleCorsFilter.java @@ -0,0 +1,52 @@ +package com.lambdaschool.shoppingcart.config; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpMethod; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +@Order(Ordered.HIGHEST_PRECEDENCE) +public class SimpleCorsFilter implements Filter { + @Override + public void doFilter( + ServletRequest servletRequest, + ServletResponse servletResponse, + FilterChain filterChain) + throws + IOException, + ServletException + { + // Convert our request and response to Http ones. If they are not Http ones, an exception would be thrown + // that would handled by our exception handler! + HttpServletResponse response = (HttpServletResponse) servletResponse; + HttpServletRequest request = (HttpServletRequest) servletRequest; + // white list domains that can access this API. * says let everyone access it. To restrict access use something like + // response.setHeader("Access-Control-Allow-Origin", + // "https://lambdaschool.com/"); + response.setHeader("Access-Control-Allow-Origin", + "*"); + // white list http methods that can be used with this API. * says lets them all work! To restrict access use something like + // response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE"); + response.setHeader("Access-Control-Allow-Methods", + "*"); + // while list access headers that can be used with this API. * says lets them all work! To restrict access use something like + // response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, content-type, access_token"); + response.setHeader("Access-Control-Allow-Headers", + "*"); + // maximum seconds results can be cached + response.setHeader("Access-Control-Max-Age", + "3600"); + if (HttpMethod.OPTIONS.name() + .equalsIgnoreCase(request.getMethod())) + { + response.setStatus(HttpServletResponse.SC_OK); + } else + { + filterChain.doFilter(servletRequest, + servletResponse); + } + } +} diff --git a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/controllers/CartController.java b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/controllers/CartController.java index bd0d26e7..cb4e4317 100644 --- a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/controllers/CartController.java +++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/controllers/CartController.java @@ -5,8 +5,11 @@ import com.lambdaschool.shoppingcart.services.CartItemService; import com.lambdaschool.shoppingcart.services.UserService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.web.bind.annotation.*; @RestController @@ -16,21 +19,24 @@ public class CartController @Autowired private CartItemService cartItemService; + @Autowired private UserService userService; - @GetMapping(value = "/user/{userid}", + @GetMapping(value = "/user/products", produces = {"application/json"}) - public ResponseEntity listCartItemsByUserId( - @PathVariable - long userid) + public ResponseEntity listCartItemsByUserId() { - User u = userService.findUserById(userid); - return new ResponseEntity<>(u, + String uname = SecurityContextHolder.getContext().getAuthentication().getName(); + + User user = userService.findByName(uname); + + + return new ResponseEntity<>(user, HttpStatus.OK); } - @PutMapping(value = "/add/user/{userid}/product/{productid}", + @PutMapping(value = "/add/user/product/{productid}", produces = {"application/json"}) public ResponseEntity addToCart( @PathVariable @@ -45,7 +51,7 @@ public ResponseEntity addToCart( HttpStatus.OK); } - @DeleteMapping(value = "/remove/user/{userid}/product/{productid}", + @DeleteMapping(value = "/remove/user/product/{productid}", produces = {"application/json"}) public ResponseEntity removeFromCart( @PathVariable 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..c554b561 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,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; @@ -51,13 +52,13 @@ public ResponseEntity listAllUsers() * @return JSON object of the user you seek * @see UserService#findUserById(long) UserService.findUserById(long) */ - @GetMapping(value = "/user/{userId}", + @GetMapping(value = "/user" produces = "application/json") - public ResponseEntity getUserById( - @PathVariable - Long userId) + public ResponseEntity getUserById() { - User u = userService.findUserById(userId); + String uname = SecurityContextHolder.getContext().getAuthentication().getName(); + + User u = userService.findByName(uname); return new ResponseEntity<>(u, HttpStatus.OK); } @@ -148,7 +149,7 @@ public ResponseEntity addNewUser( * @return status of OK * @see UserService#save(User) UserService.save(User) */ - @PutMapping(value = "/user/{userid}", + @PutMapping(value = "/user", consumes = "application/json") public ResponseEntity updateFullUser( @Valid 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..27a2b4aa 100644 --- a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/models/User.java +++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/models/User.java @@ -1,12 +1,14 @@ package com.lambdaschool.shoppingcart.models; +import com.fasterxml.jackson.annotation.JsonIgnore; 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.HashSet; -import java.util.Set; +import java.util.*; /** * The entity allowing interaction with the users table @@ -122,12 +124,17 @@ public String getUsername() { return username; } + public void setPassword(String password) + { + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + this.password = passwordEncoder.encode(password); + } + + public void setPasswordNoEncrypt(String password) + { + this.password = password; + } - /** - * setter for username - * - * @param username the new username (String) converted to lowercase - */ public void setUsername(String username) { this.username = username.toLowerCase(); @@ -168,10 +175,6 @@ public String getPassword() * * @param password the new password (String) for the user */ - public void setPassword(String password) - { - this.password = password; - } /** * Getter for user role combinations @@ -212,4 +215,14 @@ public void setCarts(Set carts) { this.carts = carts; } + + @JsonIgnore + public List getAuthority(){ + List rtnList = new ArrayList<>(); + for (UserRoles ur: this.roles){ + String myRole = "ROLE_" + ur.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..91f093d0 --- /dev/null +++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/SecurityUserServiceImpl.java @@ -0,0 +1,36 @@ +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 javax.transaction.Transactional; +import java.util.Locale; + +@Transactional +@Service(value = "securityUserDetails") +public class SecurityUserServiceImpl implements UserDetailsService { + + @Autowired + private UserRepository userrepos; + + @Transactional + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + User user = userrepos.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..6d482a78 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; @@ -11,18 +13,24 @@ */ @Component public class UserAuditing - implements AuditorAware -{ + implements AuditorAware { /** * The current user * * @return Optional(String) of current user */ @Override - public Optional getCurrentAuditor() - { + public Optional getCurrentAuditor() { String uname; - uname = "SYSTEM"; + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + uname = "SYSTEM"; + }else{ + uname = authentication.getName(); + + + } return Optional.of(uname); + } -} +} \ No newline at end of file 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 d84fad84..03564a32 100755 --- a/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserServiceImpl.java +++ b/shoppingcart/src/main/java/com/lambdaschool/shoppingcart/services/UserServiceImpl.java @@ -101,7 +101,7 @@ public User save(User user) newUser.setUsername(user.getUsername() .toLowerCase()); - newUser.setPassword(user.getPassword()); + newUser.setPasswordNoEncrypt(user.getPassword()); newUser.setPrimaryemail(user.getPrimaryemail() .toLowerCase()); @@ -141,7 +141,7 @@ public User update( if (user.getPassword() != null) { - currentUser.setPassword(user.getPassword()); + currentUser.setPasswordNoEncrypt(user.getPassword()); } if (user.getPrimaryemail() != null) diff --git a/shoppingcart/src/main/resources/data.sql b/shoppingcart/src/main/resources/data.sql index a1159b8b..d372b3a0 100644 --- a/shoppingcart/src/main/resources/data.sql +++ b/shoppingcart/src/main/resources/data.sql @@ -18,9 +18,9 @@ INSERT INTO ROLES(ROLEID, NAME, CREATEDBY, CREATEDDATE, LASTMODIFIEDBY, LASTMODI (2, 'USER', 'SYSTEM', CURRENT_TIMESTAMP, 'SYSTEM', CURRENT_TIMESTAMP); INSERT INTO USERS(USERID, USERNAME, PRIMARYEMAIL, PASSWORD, COMMENTS, CREATEDBY, CREATEDDATE, LASTMODIFIEDBY, LASTMODIFIEDDATE) - VALUES (1, 'barnbarn', 'barnbarn@host.local', 'LambdaLlama', '', 'SYSTEM', CURRENT_TIMESTAMP, 'SYSTEM', CURRENT_TIMESTAMP), - (2, 'cinnamon', 'cinnamon@host.local', 'LambdaLlama', '', 'SYSTEM', CURRENT_TIMESTAMP, 'SYSTEM', CURRENT_TIMESTAMP), - (3, 'stumps', 'stumps@host.local', 'LambdaLlama', '', 'SYSTEM', CURRENT_TIMESTAMP, 'SYSTEM', CURRENT_TIMESTAMP); + VALUES (1, 'barnbarn', 'barnbarn@host.local','$2y$12$xbqvAmGbfuOlUEE3Y3P2y.arKWqMFyyCNZegUu25VYzjv785auV7K', '', 'SYSTEM', CURRENT_TIMESTAMP, 'SYSTEM', CURRENT_TIMESTAMP), + (2, 'cinnamon', 'cinnamon@host.local', '$2y$12$xbqvAmGbfuOlUEE3Y3P2y.arKWqMFyyCNZegUu25VYzjv785auV7K', '', 'SYSTEM', CURRENT_TIMESTAMP, 'SYSTEM', CURRENT_TIMESTAMP), + (3, 'stumps', 'stumps@host.local', '$2y$12$xbqvAmGbfuOlUEE3Y3P2y.arKWqMFyyCNZegUu25VYzjv785auV7K', '', 'SYSTEM', CURRENT_TIMESTAMP, 'SYSTEM', CURRENT_TIMESTAMP); INSERT INTO USERROLES(ROLEID, USERID, CREATEDBY, CREATEDDATE, LASTMODIFIEDBY, LASTMODIFIEDDATE) VALUES (1, 1, 'SYSTEM', CURRENT_TIMESTAMP, 'SYSTEM', CURRENT_TIMESTAMP),