From c6a0d44425b088fadee86f6963fe8aae86d55a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Sokol=C3=ADk?= <434807@mail.muni.cz> Date: Sun, 16 Dec 2018 22:27:41 +0100 Subject: [PATCH 1/2] Main Controller minor modifications --- .../team01/libraryinformationsystem/data/InitializerImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sample-data/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/data/InitializerImpl.java b/sample-data/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/data/InitializerImpl.java index 4610468..151da76 100644 --- a/sample-data/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/data/InitializerImpl.java +++ b/sample-data/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/data/InitializerImpl.java @@ -3,7 +3,6 @@ import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.entity.Book; import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.entity.Customer; -import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.entity.Loan; import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.enums.BookCondition; import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.exceptions.BookNotAvailableException; import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.service.BookService; From dc6f39d0d04e9ccb8ce6afed89dbd60552454636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Sokol=C3=ADk?= <434807@mail.muni.cz> Date: Mon, 17 Dec 2018 22:09:52 +0100 Subject: [PATCH 2/2] Security and other things --- .../dto/CustomerDTO.java | 10 +++ .../entity/Customer.java | 12 +++ rest/pom.xml | 20 ++++- .../Config/Initializer.java | 4 - .../CustomAuthenticationProvider.java | 60 ++++++++++++++ .../RestAuthenticationEntryPoint.java | 26 +++++++ .../RestConfiguration.java | 74 ++++++++++++++++++ .../SecurityConfiguration.java | 78 +++++++++++++++++++ .../controllers/CustomersController.java | 22 ++++++ .../data/InitializerImpl.java | 8 +- 10 files changed, 305 insertions(+), 9 deletions(-) create mode 100644 rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/CustomAuthenticationProvider.java create mode 100644 rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/RestAuthenticationEntryPoint.java create mode 100644 rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/RestConfiguration.java create mode 100644 rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/SecurityConfiguration.java diff --git a/api/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/dto/CustomerDTO.java b/api/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/dto/CustomerDTO.java index 98b4a0a..21da16e 100644 --- a/api/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/dto/CustomerDTO.java +++ b/api/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/dto/CustomerDTO.java @@ -25,6 +25,7 @@ public class CustomerDTO { private List books; @JsonIgnoreProperties("customer") private List loans; + private boolean isAdmin = false; // Getters and Setters @@ -83,6 +84,15 @@ public List getLoans() { public void setLoans(List loans) { this.loans = loans; } + + public boolean isIsAdmin() { + return isAdmin; + } + + public void setIsAdmin(boolean isAdmin) { + this.isAdmin = isAdmin; + } + //HashCode and Equals diff --git a/persistence/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/entity/Customer.java b/persistence/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/entity/Customer.java index b0c94d4..5dbf333 100644 --- a/persistence/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/entity/Customer.java +++ b/persistence/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/entity/Customer.java @@ -42,6 +42,9 @@ public class Customer { @OneToMany(mappedBy = "customer") private List loans; + + @Column(name = "isAdmin", nullable = false) + private boolean isAdmin = false; public Customer(String name, String surname, String login, String password) { this.name = name; @@ -112,6 +115,15 @@ public List getLoans() { public void setLoans(List loans) { this.loans = loans; } + + public boolean isIsAdmin() { + return isAdmin; + } + + public void setIsAdmin(boolean isAdmin) { + this.isAdmin = isAdmin; + } + @Override diff --git a/rest/pom.xml b/rest/pom.xml index 4529d93..bd2c25f 100644 --- a/rest/pom.xml +++ b/rest/pom.xml @@ -69,8 +69,24 @@ com.fasterxml.jackson.core jackson-databind - 2.9.7 - + 2.4.6 + jar + + + org.springframework.security + spring-security-core + 5.1.2.RELEASE + + + org.springframework.security + spring-security-config + 5.1.2.RELEASE + + + org.springframework.security + spring-security-web + 5.1.2.RELEASE + \ No newline at end of file diff --git a/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/Config/Initializer.java b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/Config/Initializer.java index c23edc3..d161d54 100644 --- a/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/Config/Initializer.java +++ b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/Config/Initializer.java @@ -1,12 +1,8 @@ package cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.Config; -import javax.servlet.Filter; import javax.servlet.ServletContext; import javax.servlet.ServletException; -import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.ApiContract; import org.springframework.web.context.request.RequestContextListener; -import org.springframework.web.filter.CharacterEncodingFilter; -import org.springframework.web.filter.ShallowEtagHeaderFilter; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer{ diff --git a/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/CustomAuthenticationProvider.java b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/CustomAuthenticationProvider.java new file mode 100644 index 0000000..0b94cbf --- /dev/null +++ b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/CustomAuthenticationProvider.java @@ -0,0 +1,60 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem; + +import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.dto.CustomerDTO; +import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.facade.CustomerFacade; +import java.util.ArrayList; +import java.util.List; +import javax.inject.Inject; +import org.springframework.stereotype.Component; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +/** + * + * @author Anry + */ +@Component +public class CustomAuthenticationProvider implements AuthenticationProvider { + + @Inject + private CustomerFacade customerFacade; + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + String username = authentication.getName(); + String password = (String) authentication.getCredentials(); + + if (customerFacade.authenticate(username, password)) { + CustomerDTO user = customerFacade.findCustomerByLogin(username); + + List grantedAuths = new ArrayList<>(); + String str; + if(user.isIsAdmin()){ + str = "ADMIN"; + }else{ + str = "USER"; + } + grantedAuths.add(new SimpleGrantedAuthority("ROLE_" + str)); + + return new UsernamePasswordAuthenticationToken(username, password, grantedAuths); + } else { + throw new BadCredentialsException("Invalid password."); + } + } + + @Override + public boolean supports(Class authentication) { + return authentication.equals(UsernamePasswordAuthenticationToken.class); + } + +} \ No newline at end of file diff --git a/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/RestAuthenticationEntryPoint.java b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/RestAuthenticationEntryPoint.java new file mode 100644 index 0000000..dc9f4d7 --- /dev/null +++ b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/RestAuthenticationEntryPoint.java @@ -0,0 +1,26 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +/** + * + * @author Anry + */ +@Component +public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized!"); + } + +} diff --git a/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/RestConfiguration.java b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/RestConfiguration.java new file mode 100644 index 0000000..6124610 --- /dev/null +++ b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/RestConfiguration.java @@ -0,0 +1,74 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.config.SampleDataConfiguration; +import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.config.ServiceConfig; +import cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem.controllers.LoansController; +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.Locale; +import javax.validation.Validator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +/** + * + * @author Anry + */ + +@Configuration +@EnableWebMvc +@Import({ServiceConfig.class, SampleDataConfiguration.class}) +@ComponentScan(basePackageClasses = {LoansController.class}) +public class RestConfiguration extends WebMvcConfigurerAdapter { + + @Override + public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { + configurer.enable(); + } + + @Override + public void configureMessageConverters(List> converters) { + converters.add(customJackson2HttpMessageConverter()); + } + + private MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() { + MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ENGLISH)); + + /*objectMapper.addMixIn(AbilityDTO.class, AbilityDTOMixin.class); + objectMapper.addMixIn(GhostDTO.class, GhostDTOMixin.class); + objectMapper.addMixIn(HouseDTO.class, HouseDTOMixin.class); + objectMapper.addMixIn(PersonDTO.class, PersonDTOMixin.class);*/ + + objectMapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION); + + jsonConverter.setObjectMapper(objectMapper); + return jsonConverter; + } + + @Bean + public Validator validator() { + return new LocalValidatorFactoryBean(); + } + +} \ No newline at end of file diff --git a/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/SecurityConfiguration.java b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/SecurityConfiguration.java new file mode 100644 index 0000000..18bafdf --- /dev/null +++ b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/SecurityConfiguration.java @@ -0,0 +1,78 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package cz.muni.fi.pa165.skupina06.team01.libraryinformationsystem; + +import javax.inject.Inject; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpMethod; + +/** + * + * @author Anry + */ +@Configuration +@EnableWebSecurity +@ComponentScan(basePackageClasses = {CustomAuthenticationProvider.class}) +@Import(RestConfiguration.class) +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Inject + private CustomAuthenticationProvider customAuthenticationProvider; + + @Inject + private RestAuthenticationEntryPoint restAuthenticationEntryPoint; + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(customAuthenticationProvider); + } + + // @Override + protected void configure(HttpSecurity http) throws Exception { + + http.exceptionHandling() + .authenticationEntryPoint(restAuthenticationEntryPoint).and() + .authorizeRequests() + + .antMatchers(HttpMethod.GET, "/rest/house").hasAnyRole("ADMIN", "USER") + .antMatchers(HttpMethod.PUT, "/rest/house").hasRole("ADMIN") + .antMatchers(HttpMethod.POST, "/rest/house").hasAnyRole("ADMIN", "USER") + .antMatchers(HttpMethod.DELETE, "/rest/house").hasRole("ADMIN") + + .antMatchers(HttpMethod.GET, "/rest/house/*").hasRole("ADMIN") + .antMatchers(HttpMethod.PUT, "/rest/house/*").hasRole("ADMIN") + .antMatchers(HttpMethod.POST, "/rest/house/*").hasRole("ADMIN") + .antMatchers(HttpMethod.DELETE, "/rest/house/*").hasRole("ADMIN") + + + .antMatchers(HttpMethod.GET, "/rest/ghost").hasAnyRole("ADMIN", "USER") + .antMatchers(HttpMethod.PUT, "/rest/ghost").hasRole("ADMIN") + .antMatchers(HttpMethod.POST, "/rest/ghost").hasRole("ADMIN") + .antMatchers(HttpMethod.DELETE, "/rest/ghost").hasRole("ADMIN") + + .antMatchers(HttpMethod.GET, "/rest/ability").hasRole("ADMIN") + .antMatchers(HttpMethod.PUT, "/rest/ability").hasRole("ADMIN") + .antMatchers(HttpMethod.POST, "/rest/ability").hasRole("ADMIN") + .antMatchers(HttpMethod.DELETE, "/rest/ability").hasRole("ADMIN") + + .antMatchers(HttpMethod.GET, "/rest/person").hasAnyRole("ADMIN", "USER") + + .antMatchers("/js/**").permitAll() + .antMatchers("/partials/**").permitAll() + .antMatchers("/index.html").permitAll() + + .anyRequest().authenticated().and() + .formLogin().loginPage("/login.html").permitAll().and() + .logout().logoutUrl("/logout.html").logoutSuccessUrl("/index.html?logout").permitAll().and().csrf().disable(); + } + +} diff --git a/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/controllers/CustomersController.java b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/controllers/CustomersController.java index b9d8f74..8eb50cc 100644 --- a/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/controllers/CustomersController.java +++ b/rest/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/controllers/CustomersController.java @@ -68,4 +68,26 @@ public final CustomerDTO getCustomer(@PathVariable("id") long id) throws Excepti } + /** + * + * getting customer according to id + * + * @param id user identifier + * @return CustomerDTO + * @throws ResourceNotFoundException + */ + @RequestMapping(value = "/{login}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + public final boolean isAdmin(@PathVariable("login") String login) throws Exception { + + logger.debug("rest isAdmin({})", login); + + try { + CustomerDTO customerDTO = customerFacade.findCustomerByLogin(login); + return customerDTO.isIsAdmin(); + } catch (Exception ex) { + throw new ResourceNotFoundException(); + } + + } + } diff --git a/sample-data/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/data/InitializerImpl.java b/sample-data/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/data/InitializerImpl.java index a93bae4..e809ab6 100644 --- a/sample-data/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/data/InitializerImpl.java +++ b/sample-data/src/main/java/cz/muni/fi/pa165/skupina06/team01/libraryinformationsystem/data/InitializerImpl.java @@ -47,8 +47,9 @@ void loadBooks(){ } void loadCustomers(){ - createCustomer("Juraj", "Pokazil", "test123", "hunter2"); - createCustomer("Michal", "Opravil", "repairman", "logmein"); + createCustomer("Juraj", "Pokazil", "test123", "hunter2", false); + createCustomer("Michal", "Opravil", "repairman", "logmein", false); + createCustomer("Admin", "Adminič", "admin", "pass", true); } void loadLoans(){ @@ -80,13 +81,14 @@ void createBook(String author, String title, String ISBN, BookCondition conditio bookService.createBook(book); } - void createCustomer(String name, String surname, String login, String password){ + void createCustomer(String name, String surname, String login, String password, boolean isAdmin){ Customer customer = new Customer(); customer.setName(name); customer.setSurname(surname); customer.setLogin(login); customer.setPassword(password); + customer.setIsAdmin(isAdmin); customerService.registerCustomer(customer); }