diff --git a/pom.xml b/pom.xml index 1dde8b56b..60be53522 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,11 @@ org.springframework.security spring-security-taglibs + + org.springframework.boot + spring-boot-starter-security + 2.4.4 + diff --git a/src/main/java/org/springframework/cheapy/configuration/ExceptionHandlerConfiguration.java b/src/main/java/org/springframework/cheapy/configuration/ExceptionHandlerConfiguration.java new file mode 100644 index 000000000..e578e2a7e --- /dev/null +++ b/src/main/java/org/springframework/cheapy/configuration/ExceptionHandlerConfiguration.java @@ -0,0 +1,28 @@ +package org.springframework.cheapy.configuration; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import javax.servlet.http.HttpServletRequest; + +/** + * This advice is necessary because MockMvc is not a real servlet environment, therefore it does not redirect error + * responses to [ErrorController], which produces validation response. So we need to fake it in tests. + * It's not ideal, but at least we can use classic MockMvc tests for testing error response + document it. + */ +@ControllerAdvice +public class ExceptionHandlerConfiguration +{ + @Autowired + private BasicErrorController errorController; + // add any exceptions/validations/binding problems + + @ExceptionHandler(Exception.class) + public String defaultErrorHandler(HttpServletRequest request, Exception ex) { + request.setAttribute("javax.servlet.error.request_uri", request.getPathInfo()); + request.setAttribute("javax.servlet.error.status_code", 400); + request.setAttribute("exeption", ex); + return "exception"; + } +} \ No newline at end of file diff --git a/src/main/java/org/springframework/cheapy/configuration/SecurityConfiguration.java b/src/main/java/org/springframework/cheapy/configuration/SecurityConfiguration.java new file mode 100644 index 000000000..46e1b8600 --- /dev/null +++ b/src/main/java/org/springframework/cheapy/configuration/SecurityConfiguration.java @@ -0,0 +1,72 @@ + +package org.springframework.cheapy.configuration; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +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.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +/* + * 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. + */ + +/** + * @author japarejo + */ +@Configuration +@EnableWebSecurity +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + + @Autowired + DataSource dataSource; + + + @Override + protected void configure(final HttpSecurity http) throws Exception { + + http.authorizeRequests().antMatchers("/resources/**", "/webjars/**", "/h2-console/**").permitAll() + .antMatchers(HttpMethod.GET, "/", "/oups").permitAll() + .antMatchers("/users/new").permitAll() + .antMatchers("/usuarios/new").permitAll() + .antMatchers("/admin/**").hasAnyAuthority("admin") + .antMatchers("/owners/**").hasAnyAuthority("owner", "admin") + .antMatchers("/vets/**").authenticated().anyRequest().denyAll() + .and().formLogin() + /* .loginPage("/login") */ + .failureUrl("/login-error").and().logout().logoutSuccessUrl("/"); + + // Configuración para que funcione la consola de administración + // de la BD H2 (deshabilitar las cabeceras de protección contra + // ataques de tipo csrf y habilitar los framesets si su contenido + // se sirve desde esta misma página. + http.csrf().ignoringAntMatchers("/h2-console/**"); + http.headers().frameOptions().sameOrigin(); + } + + @Override + + public void configure(final AuthenticationManagerBuilder auth) throws Exception { + auth.jdbcAuthentication().dataSource(this.dataSource) + //[login de admin,owner y vet] .usersByUsernameQuery("select username,password,enabled " + "from users " + "where username = ?") + .usersByUsernameQuery("select nombre_usuario,contra,enabled from usuarios where nombre_usuario=?").authoritiesByUsernameQuery("select username, authority " + "from authorities " + "where username = ?") //[login de tallerespaco] + .passwordEncoder(this.passwordEncoder()); + + } + + @Bean + public PasswordEncoder passwordEncoder() { + PasswordEncoder encoder = NoOpPasswordEncoder.getInstance(); + return encoder; + } + +} diff --git a/src/main/java/org/springframework/cheapy/model/Client.java b/src/main/java/org/springframework/cheapy/model/Client.java index 06268c32a..37ba216fa 100644 --- a/src/main/java/org/springframework/cheapy/model/Client.java +++ b/src/main/java/org/springframework/cheapy/model/Client.java @@ -1,94 +1,93 @@ -package org.springframework.cheapy.model; - -import java.util.Set; - -import javax.persistence.Entity; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.Digits; -import javax.validation.constraints.NotEmpty; - -@Entity -@Table(name = "clients") -public class Client extends User { - - @NotEmpty - private String address; - - @NotEmpty - private String timetable; - - @NotEmpty - @Digits(fraction = 0, integer = 10) - private String telephone; - - @NotEmpty - private String description; - - @NotEmpty - private String code; - - @NotEmpty - private String food; - - @OneToMany - private Set foodOffers; - - @OneToMany - private Set nuOffers; - - @OneToMany - private Set speedOffers; - - @OneToMany - private Set timeOffers; - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public String getTimetable() { - return timetable; - } - - public void setTimetable(String timetable) { - this.timetable = timetable; - } - - public String getTelephone() { - return telephone; - } - - public void setTelephone(String telephone) { - this.telephone = telephone; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getFood() { - return food; - } - - public void setFood(String food) { - this.food = food; - } - +package org.springframework.cheapy.model; + +import java.util.Set; + +import javax.persistence.Entity; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.validation.constraints.Digits; +import javax.validation.constraints.NotEmpty; + +@Entity +@Table(name = "clients") +public class Client extends User { + + @NotEmpty + private String address; + + @NotEmpty + private String timetable; + + @NotEmpty + @Digits(fraction = 0, integer = 10) + private String telephone; + + @NotEmpty + private String description; + + @NotEmpty + private String code; + + @NotEmpty + private String food; + + @OneToMany + private Set foodOffers; + + @OneToMany + private Set nuOffers; + + @OneToMany + private Set speedOffers; + + @OneToMany + private Set timeOffers; + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getTimetable() { + return timetable; + } + + public void setTimetable(String timetable) { + this.timetable = timetable; + } + + public String getTelephone() { + return telephone; + } + + public void setTelephone(String telephone) { + this.telephone = telephone; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getFood() { + return food; + } + + public void setFood(String food) { + this.food = food; + } } \ No newline at end of file diff --git a/src/main/java/org/springframework/cheapy/model/User.java b/src/main/java/org/springframework/cheapy/model/User.java index 9420b0deb..a0db78bf9 100644 --- a/src/main/java/org/springframework/cheapy/model/User.java +++ b/src/main/java/org/springframework/cheapy/model/User.java @@ -1,58 +1,57 @@ -package org.springframework.cheapy.model; - -import javax.persistence.Id; -import javax.persistence.MappedSuperclass; -import javax.persistence.OneToOne; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; - - -@MappedSuperclass -public class User extends BaseEntity { - - @NotBlank - String username; - - @NotBlank - String password; - - @Email - @NotBlank - String email; - - @OneToOne - Authorities authority; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Authorities getAuthority() { - return authority; - } - - public void setAuthority(Authorities authority) { - this.authority = authority; - } - -} +package org.springframework.cheapy.model; + +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import javax.persistence.OneToOne; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; + + +@MappedSuperclass +public class User extends BaseEntity { + + @NotBlank + String username; + + @NotBlank + String password; + + @Email + @NotBlank + String email; + + @OneToOne + Authorities authority; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Authorities getAuthority() { + return authority; + } + + public void setAuthority(Authorities authority) { + this.authority = authority; + } +} diff --git a/src/main/java/org/springframework/cheapy/repository/AuthoritiesRepository.java b/src/main/java/org/springframework/cheapy/repository/AuthoritiesRepository.java new file mode 100644 index 000000000..0a0647e96 --- /dev/null +++ b/src/main/java/org/springframework/cheapy/repository/AuthoritiesRepository.java @@ -0,0 +1,13 @@ +package org.springframework.cheapy.repository; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.cheapy.model.Authorities; +import org.springframework.cheapy.model.User; + + + +public interface AuthoritiesRepository extends CrudRepository{ + + Authorities findByUser(User user); + +} diff --git a/src/main/java/org/springframework/cheapy/repository/UserRepository.java b/src/main/java/org/springframework/cheapy/repository/UserRepository.java new file mode 100644 index 000000000..a109afcb6 --- /dev/null +++ b/src/main/java/org/springframework/cheapy/repository/UserRepository.java @@ -0,0 +1,11 @@ + +package org.springframework.cheapy.repository; + +import org.springframework.data.repository.CrudRepository; +import org.springframework.cheapy.model.User; + +public interface UserRepository extends CrudRepository { + + User findByUsername(String currentPrincipalName); + +} diff --git a/src/main/java/org/springframework/cheapy/service/AuthoritiesService.java b/src/main/java/org/springframework/cheapy/service/AuthoritiesService.java new file mode 100644 index 000000000..092a08ad5 --- /dev/null +++ b/src/main/java/org/springframework/cheapy/service/AuthoritiesService.java @@ -0,0 +1,71 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cheapy.service; + + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.cheapy.model.Authorities; +import org.springframework.cheapy.model.User; +import org.springframework.cheapy.repository.AuthoritiesRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * Mostly used as a facade for all Petclinic controllers Also a placeholder + * for @Transactional and @Cacheable annotations + * + * @author Michael Isvy + */ +@Service +public class AuthoritiesService { + + private AuthoritiesRepository authoritiesRepository; + private UserService userService; + + @Autowired + public AuthoritiesService(AuthoritiesRepository authoritiesRepository,UserService userService) { + this.authoritiesRepository = authoritiesRepository; + this.userService = userService; + } + + @Transactional + public Authorities findAuthoritiyByUser(User user) { + return this.authoritiesRepository.findByUser(user); + } + + @Transactional + public void saveAuthorities(Authorities authorities) throws DataAccessException { + authoritiesRepository.save(authorities); + } + + @Transactional + public void saveAuthorities(String username, String role) throws DataAccessException { + Authorities authority = new Authorities(); + Optional user = userService.findUser(username); + if(user.isPresent()) { + authority.setUser(user.get()); + authority.setAuthority(role); + //user.get().getAuthorities().add(authority); + authoritiesRepository.save(authority); + }else + throw new DataAccessException("User '"+username+"' not found!") {}; + } + + +} diff --git a/src/main/java/org/springframework/cheapy/service/UserService.java b/src/main/java/org/springframework/cheapy/service/UserService.java new file mode 100644 index 000000000..895aae516 --- /dev/null +++ b/src/main/java/org/springframework/cheapy/service/UserService.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.cheapy.service; + + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.cheapy.model.User; +import org.springframework.cheapy.repository.UserRepository; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +/** + * Mostly used as a facade for all Petclinic controllers Also a placeholder + * for @Transactional and @Cacheable annotations + * + * @author Michael Isvy + */ + +@Service +public class UserService { + + private UserRepository userRepository; + + @Autowired + public UserService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Transactional + public void saveUser(User user) throws DataAccessException { + userRepository.save(user); + } + + public Optional findUser(String username) { + return userRepository.findById(username); + } + + @Transactional + public User getCurrentUser() throws DataAccessException { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String currentPrincipalName = authentication.getName(); //Obtiene el nombre del ususario actual + return this.userRepository.findByUsername(currentPrincipalName); //Obtiene el usuario con ese nombre + } +} diff --git a/src/main/java/org/springframework/cheapy/web/UserController.java b/src/main/java/org/springframework/cheapy/web/UserController.java new file mode 100644 index 000000000..97e921a75 --- /dev/null +++ b/src/main/java/org/springframework/cheapy/web/UserController.java @@ -0,0 +1,154 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cheapy.web; + +import javax.persistence.EntityNotFoundException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cheapy.model.Authorities; +import org.springframework.cheapy.model.User; +import org.springframework.cheapy.service.AuthoritiesService; +import org.springframework.cheapy.service.UserService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; + +/** + * @author Juergen Hoeller + * @author Ken Krebs + * @author Arjen Poutsma + * @author Michael Isvy + */ +@Controller +public class UserController { + + private UserService userService; + + private AuthoritiesService authoritiesService; + +// @Autowired +// public UserController (UserService userService, AuthoritiesService authoritiesService, +// ClienteService clienteService, FarmaceuticoService farmaceuticoService, ProveedorService proveedorService) { +// this.userService = userService; +// this.authoritiesService = authoritiesService; +// this.clienteService = clienteService; +// this.farmaceuticoService = farmaceuticoService; +// this.proveedorService = proveedorService; +// } +// +// @InitBinder +// public void setAllowedFields(final WebDataBinder dataBinder) { +// dataBinder.setDisallowedFields("id"); +// } +// +// @GetMapping("users") +// private String showUserDetails(ModelMap model) { +// User user = this.userService.getCurrentUser(); +// Authorities authority = this.authoritiesService.findAuthoritiyByUser(user); +// +// if(authority.getAuthority().equals("cliente")) { +// Cliente cliente = this.clienteService.findClienteUser(user); +// model.addAttribute("cliente", cliente); +// }else if(authority.getAuthority().equals("proveedor")) { +// Proveedor proveedor = this.proveedorService.findProveedorUser(user); +// model.addAttribute("proveedor", proveedor); +// }else if(authority.getAuthority().equals("farmaceutico")) { +// Farmaceutico farmaceutico = this.farmaceuticoService.findFarmaceuticoByUser(user); +// model.addAttribute("farmaceutico", farmaceutico); +// } +// +// log.info("El usuario '" + user.getUsername() + "' ha mostrado su informacion personal"); +// return "users/userDetails"; +// } +// +// @GetMapping("/users/new") +// public String newUser(ModelMap model) { +// Cliente cliente = new Cliente(); +// model.addAttribute("cliente", cliente); +// model.addAttribute("dni", new String()); +// return "users/userRegister"; +// } +// +// @PostMapping("/users/new") +// public String creationUser(@ModelAttribute("cliente") Cliente cliente, final BindingResult result, ModelMap model) { +// if (result.hasErrors()) { +// return "users/userRegister"; +// } else if(cliente.getUser() == null) { +// try { +// cliente = this.clienteService.clienteDni(cliente.getDni()); +// }catch(EntityNotFoundException ex) { +// result.rejectValue("dni", "clienteNotFound"); +// return "users/userRegister"; +// } +// cliente.setUser(new User()); +// model.addAttribute("cliente", cliente); +// return "users/userRegister"; +// }else { +// this.userService.saveUser(cliente.getUser()); +// this.authoritiesService.saveAuthorities(cliente.getUser().getUsername(), "cliente"); +// this.clienteService.saveCliente(cliente); +// log.info("El cliente con dni '" + cliente.getDni() + "' se ha registrado como usuario"); +// return "redirect:../"; +// } +// } +// +// @GetMapping("/users/password") +// public String initChangePassword(ModelMap model) { +// User currentUser = this.userService.getCurrentUser(); +// UserValidate user = new UserValidate(currentUser.getUsername(), ""); +// model.addAttribute("user", user); +// return "users/passwordEdit"; +// } +// +// @PostMapping("/users/password") +// public String changePassword(@ModelAttribute("user") UserValidate user, final BindingResult result, ModelMap model) { +// if(result.hasErrors()) { +// return "users/passwordEdit"; +// }else { +// User CurrentUser = this.userService.getCurrentUser(); +// if(CurrentUser.getPassword().equals(user.getPassword()) && user.getNewPassword().equals(user.getValidPassword())) { +// if(!user.getNewPassword().isEmpty()) { +// CurrentUser.setPassword(user.getNewPassword()); +// this.userService.saveUser(CurrentUser); +// log.info("El usuario '" + CurrentUser.getUsername() + "' ha cambiado satisfactoriamente su contraseña"); +// return "redirect:../"; +// }else { +// FieldError err = new FieldError("PassException", "newPassword", "Introduce una nueva contraseña"); +// result.addError(err); +// log.warn("El usuario '" + CurrentUser.getUsername() + "' ha tenido un error 'PassException'"); +// return "users/passwordEdit"; +// } +// }else if(!CurrentUser.getPassword().equals(user.getPassword())){ +// FieldError err = new FieldError("PassException", "password", "Contraseña incorrecta"); +// result.addError(err); +// log.warn("El usuario '" + CurrentUser.getUsername() + "' ha tenido un error 'PassException'"); +// return "users/passwordEdit"; +// }else { +// FieldError err = new FieldError("PassException", "newPassword", "Las contraseñas no coinciden"); +// result.addError(err); +// log.warn("El usuario '" + CurrentUser.getUsername() + "' ha tenido un error 'PassException'"); +// return "users/passwordEdit"; +// } +// } +// } +} diff --git a/src/main/webapp/WEB-INF/tags/menu.tag b/src/main/webapp/WEB-INF/tags/menu.tag index 6cda27bee..2d0eeff56 100644 --- a/src/main/webapp/WEB-INF/tags/menu.tag +++ b/src/main/webapp/WEB-INF/tags/menu.tag @@ -50,8 +50,6 @@ - -