From 8f4c790b461797ab1172aa9ff2e50546a69c71e6 Mon Sep 17 00:00:00 2001 From: Andrei Stoica <andrei.stoica@endava.com> Date: Thu, 21 Jun 2018 11:44:22 +0300 Subject: [PATCH] [Authentication] Added basic http authenticatio non all endpoints --- pom.xml | 9 +++ .../samples/petclinic/model/Role.java | 38 ++++++++++ .../samples/petclinic/model/User.java | 74 +++++++++++++++++++ .../petclinic/repository/UserRepository.java | 9 +++ .../jdbc/JdbcUserRepositoryImpl.java | 68 +++++++++++++++++ .../repository/jpa/JpaUserRepositoryImpl.java | 27 +++++++ .../SpringDataUserRepository.java | 11 +++ .../petclinic/rest/OwnerRestController.java | 7 ++ .../petclinic/rest/PetRestController.java | 7 ++ .../petclinic/rest/PetTypeRestController.java | 19 +++-- .../rest/SpecialtyRestController.java | 19 +++-- .../petclinic/rest/UserRestController.java | 58 +++++++++++++++ .../petclinic/rest/VetRestController.java | 23 +++--- .../petclinic/rest/VisitRestController.java | 19 +++-- .../security/BasicAuthenticationAdapter.java | 39 ++++++++++ .../samples/petclinic/security/Roles.java | 11 +++ .../petclinic/service/UserService.java | 8 ++ .../petclinic/service/UserServiceImpl.java | 36 +++++++++ src/main/resources/db/hsqldb/initDB.sql | 18 +++++ src/main/resources/db/hsqldb/populateDB.sql | 6 ++ src/main/resources/db/mysql/initDB.sql | 17 +++++ src/main/resources/db/mysql/populateDB.sql | 6 ++ src/main/resources/db/postgresql/initDB.sql | 18 +++++ .../resources/db/postgresql/populateDB.sql | 6 ++ .../rest/OwnerRestControllerTests.java | 15 +++- .../rest/PetRestControllerTests.java | 13 +++- .../rest/PetTypeRestControllerTests.java | 45 ++++++++++- .../rest/SpecialtyRestControllerTests.java | 13 +++- .../rest/UserRestControllerTests.java | 74 +++++++++++++++++++ .../rest/VetRestControllerTests.java | 13 +++- .../rest/VisitRestControllerTests.java | 13 +++- .../AbstractClinicServiceTests.java | 65 ++++++++-------- .../ApplicationTestConfig.java | 4 +- .../ClinicServiceJdbcTests.java | 2 +- .../ClinicServiceJpaTests.java | 2 +- .../ClinicServiceSpringDataJpaTests.java | 2 +- .../userService/AbstractUserServiceTests.java | 36 +++++++++ .../userService/UserServiceJdbcTests.java | 13 ++++ .../userService/UserServiceJpaTests.java | 13 ++++ .../UserServiceSpringDataJpaTests.java | 13 ++++ 40 files changed, 814 insertions(+), 75 deletions(-) create mode 100644 src/main/java/org/springframework/samples/petclinic/model/Role.java create mode 100644 src/main/java/org/springframework/samples/petclinic/model/User.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/UserRepository.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcUserRepositoryImpl.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaUserRepositoryImpl.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/springdatajpa/SpringDataUserRepository.java create mode 100644 src/main/java/org/springframework/samples/petclinic/rest/UserRestController.java create mode 100644 src/main/java/org/springframework/samples/petclinic/security/BasicAuthenticationAdapter.java create mode 100644 src/main/java/org/springframework/samples/petclinic/security/Roles.java create mode 100644 src/main/java/org/springframework/samples/petclinic/service/UserService.java create mode 100644 src/main/java/org/springframework/samples/petclinic/service/UserServiceImpl.java create mode 100644 src/test/java/org/springframework/samples/petclinic/rest/UserRestControllerTests.java rename src/test/java/org/springframework/samples/petclinic/service/{ => clinicService}/AbstractClinicServiceTests.java (98%) rename src/test/java/org/springframework/samples/petclinic/service/{ => clinicService}/ApplicationTestConfig.java (77%) rename src/test/java/org/springframework/samples/petclinic/service/{ => clinicService}/ClinicServiceJdbcTests.java (94%) rename src/test/java/org/springframework/samples/petclinic/service/{ => clinicService}/ClinicServiceJpaTests.java (89%) rename src/test/java/org/springframework/samples/petclinic/service/{ => clinicService}/ClinicServiceSpringDataJpaTests.java (89%) create mode 100644 src/test/java/org/springframework/samples/petclinic/service/userService/AbstractUserServiceTests.java create mode 100644 src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceJdbcTests.java create mode 100644 src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceJpaTests.java create mode 100644 src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceSpringDataJpaTests.java diff --git a/pom.xml b/pom.xml index d53bf80d..0fc0b3f9 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,10 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> @@ -102,6 +106,11 @@ <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> diff --git a/src/main/java/org/springframework/samples/petclinic/model/Role.java b/src/main/java/org/springframework/samples/petclinic/model/Role.java new file mode 100644 index 00000000..3147d730 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/model/Role.java @@ -0,0 +1,38 @@ +package org.springframework.samples.petclinic.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +@Entity +@Table(name = "roles" ,uniqueConstraints = @UniqueConstraint(columnNames = {"username", "role"})) +public class Role extends BaseEntity { + + @ManyToOne + @JoinColumn(name = "username") + private User user; + + @Column( name = "role") + private String name; + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/model/User.java b/src/main/java/org/springframework/samples/petclinic/model/User.java new file mode 100644 index 00000000..1bfe90a4 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/model/User.java @@ -0,0 +1,74 @@ +package org.springframework.samples.petclinic.model; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +@Entity +@Table(name = "users") +public class User { + + @Id + @Column(name = "username") + private String username; + + @Column(name = "password") + private String password; + + @Column(name = "enabled") + private Boolean enabled; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.EAGER) + private Set<Role> roles; + + 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 Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Set<Role> getRoles() { + return roles; + } + + public void setRoles(Set<Role> roles) { + this.roles = roles; + } + + @JsonIgnore + public void addRole(String roleName) { + if(this.roles == null) { + this.roles = new HashSet<>(); + } + Role role = new Role(); + role.setName(roleName); + this.roles.add(role); + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/UserRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/UserRepository.java new file mode 100644 index 00000000..3e9b45ba --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/UserRepository.java @@ -0,0 +1,9 @@ +package org.springframework.samples.petclinic.repository; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.model.User; + +public interface UserRepository { + + void save(User user) throws DataAccessException; +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcUserRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcUserRepositoryImpl.java new file mode 100644 index 00000000..7fc51ecb --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcUserRepositoryImpl.java @@ -0,0 +1,68 @@ +package org.springframework.samples.petclinic.repository.jdbc; + +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.samples.petclinic.model.Role; +import org.springframework.samples.petclinic.model.User; +import org.springframework.samples.petclinic.repository.UserRepository; +import org.springframework.stereotype.Repository; + +@Repository +@Profile("jdbc") +public class JdbcUserRepositoryImpl implements UserRepository { + + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + private SimpleJdbcInsert insertUser; + + @Autowired + public JdbcUserRepositoryImpl(DataSource dataSource) { + this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); + this.insertUser = new SimpleJdbcInsert(dataSource).withTableName("users"); + } + + @Override + public void save(User user) throws DataAccessException { + + BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(user); + + try { + getByUsername(user.getUsername()); + this.namedParameterJdbcTemplate.update("UPDATE users SET password=:password, enabled=:enabled WHERE username=:username", parameterSource); + } catch (EmptyResultDataAccessException e) { + this.insertUser.execute(parameterSource); + } finally { + updateUserRoles(user); + } + } + + private User getByUsername(String username) { + + Map<String, Object> params = new HashMap<>(); + params.put("username", username); + return this.namedParameterJdbcTemplate.queryForObject("SELECT * FROM users WHERE username=:username", + params, BeanPropertyRowMapper.newInstance(User.class)); + } + + private void updateUserRoles(User user) { + Map<String, Object> params = new HashMap<>(); + params.put("username", user.getUsername()); + this.namedParameterJdbcTemplate.update("DELETE FROM roles WHERE username=:username", params); + for (Role role : user.getRoles()) { + params.put("role", role.getName()); + if (role.getName() != null) { + this.namedParameterJdbcTemplate.update("INSERT INTO roles(username, role) VALUES (:username, :role)", params); + } + } + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaUserRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaUserRepositoryImpl.java new file mode 100644 index 00000000..d73a7e9f --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaUserRepositoryImpl.java @@ -0,0 +1,27 @@ +package org.springframework.samples.petclinic.repository.jpa; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +import org.springframework.context.annotation.Profile; +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.model.User; +import org.springframework.samples.petclinic.repository.UserRepository; +import org.springframework.stereotype.Repository; + +@Repository +@Profile("jpa") +public class JpaUserRepositoryImpl implements UserRepository { + + @PersistenceContext + private EntityManager em; + + @Override + public void save(User user) throws DataAccessException { + if (this.em.find(User.class, user.getUsername()) == null) { + this.em.persist(user); + } else { + this.em.merge(user); + } + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/springdatajpa/SpringDataUserRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/springdatajpa/SpringDataUserRepository.java new file mode 100644 index 00000000..4219df45 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/springdatajpa/SpringDataUserRepository.java @@ -0,0 +1,11 @@ +package org.springframework.samples.petclinic.repository.springdatajpa; + +import org.springframework.context.annotation.Profile; +import org.springframework.data.repository.Repository; +import org.springframework.samples.petclinic.model.User; +import org.springframework.samples.petclinic.repository.UserRepository; + +@Profile("spring-data-jpa") +public interface SpringDataUserRepository extends UserRepository, Repository<User, Integer> { + +} diff --git a/src/main/java/org/springframework/samples/petclinic/rest/OwnerRestController.java b/src/main/java/org/springframework/samples/petclinic/rest/OwnerRestController.java index e3b3aadb..ff60a276 100644 --- a/src/main/java/org/springframework/samples/petclinic/rest/OwnerRestController.java +++ b/src/main/java/org/springframework/samples/petclinic/rest/OwnerRestController.java @@ -28,6 +28,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; @@ -50,6 +51,7 @@ public class OwnerRestController { @Autowired private ClinicService clinicService; + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/*/lastname/{lastName}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Collection<Owner>> getOwnersList(@PathVariable("lastName") String ownerLastName) { if (ownerLastName == null) { @@ -62,6 +64,7 @@ public class OwnerRestController { return new ResponseEntity<Collection<Owner>>(owners, HttpStatus.OK); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Collection<Owner>> getOwners() { Collection<Owner> owners = this.clinicService.findAllOwners(); @@ -71,6 +74,7 @@ public class OwnerRestController { return new ResponseEntity<Collection<Owner>>(owners, HttpStatus.OK); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/{ownerId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Owner> getOwner(@PathVariable("ownerId") int ownerId) { Owner owner = null; @@ -81,6 +85,7 @@ public class OwnerRestController { return new ResponseEntity<Owner>(owner, HttpStatus.OK); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Owner> addOwner(@RequestBody @Valid Owner owner, BindingResult bindingResult, UriComponentsBuilder ucBuilder) { @@ -96,6 +101,7 @@ public class OwnerRestController { return new ResponseEntity<Owner>(owner, headers, HttpStatus.CREATED); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/{ownerId}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Owner> updateOwner(@PathVariable("ownerId") int ownerId, @RequestBody @Valid Owner owner, BindingResult bindingResult, UriComponentsBuilder ucBuilder) { @@ -119,6 +125,7 @@ public class OwnerRestController { return new ResponseEntity<Owner>(currentOwner, HttpStatus.NO_CONTENT); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/{ownerId}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @Transactional public ResponseEntity<Void> deleteOwner(@PathVariable("ownerId") int ownerId) { diff --git a/src/main/java/org/springframework/samples/petclinic/rest/PetRestController.java b/src/main/java/org/springframework/samples/petclinic/rest/PetRestController.java index 6759cdcf..79d971d6 100644 --- a/src/main/java/org/springframework/samples/petclinic/rest/PetRestController.java +++ b/src/main/java/org/springframework/samples/petclinic/rest/PetRestController.java @@ -29,6 +29,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; @@ -51,6 +52,7 @@ public class PetRestController { @Autowired private ClinicService clinicService; + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/{petId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Pet> getPet(@PathVariable("petId") int petId){ Pet pet = this.clinicService.findPetById(petId); @@ -60,6 +62,7 @@ public class PetRestController { return new ResponseEntity<Pet>(pet, HttpStatus.OK); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Collection<Pet>> getPets(){ Collection<Pet> pets = this.clinicService.findAllPets(); @@ -69,11 +72,13 @@ public class PetRestController { return new ResponseEntity<Collection<Pet>>(pets, HttpStatus.OK); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/pettypes", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Collection<PetType>> getPetTypes(){ return new ResponseEntity<Collection<PetType>>(this.clinicService.findPetTypes(), HttpStatus.OK); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Pet> addPet(@RequestBody @Valid Pet pet, BindingResult bindingResult, UriComponentsBuilder ucBuilder){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -88,6 +93,7 @@ public class PetRestController { return new ResponseEntity<Pet>(pet, headers, HttpStatus.CREATED); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/{petId}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Pet> updatePet(@PathVariable("petId") int petId, @RequestBody @Valid Pet pet, BindingResult bindingResult){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -109,6 +115,7 @@ public class PetRestController { return new ResponseEntity<Pet>(currentPet, HttpStatus.NO_CONTENT); } + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/{petId}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @Transactional public ResponseEntity<Void> deletePet(@PathVariable("petId") int petId){ diff --git a/src/main/java/org/springframework/samples/petclinic/rest/PetTypeRestController.java b/src/main/java/org/springframework/samples/petclinic/rest/PetTypeRestController.java index 239397c1..e16f51e8 100644 --- a/src/main/java/org/springframework/samples/petclinic/rest/PetTypeRestController.java +++ b/src/main/java/org/springframework/samples/petclinic/rest/PetTypeRestController.java @@ -29,6 +29,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; @@ -42,10 +43,11 @@ import org.springframework.web.util.UriComponentsBuilder; @CrossOrigin(exposedHeaders = "errors, content-type") @RequestMapping("api/pettypes") public class PetTypeRestController { - + @Autowired private ClinicService clinicService; - + + @PreAuthorize( "hasAnyRole(@roles.OWNER_ADMIN, @roles.VET_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Collection<PetType>> getAllPetTypes(){ Collection<PetType> petTypes = new ArrayList<PetType>(); @@ -55,7 +57,8 @@ public class PetTypeRestController { } return new ResponseEntity<Collection<PetType>>(petTypes, HttpStatus.OK); } - + + @PreAuthorize( "hasAnyRole(@roles.OWNER_ADMIN, @roles.VET_ADMIN)" ) @RequestMapping(value = "/{petTypeId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<PetType> getPetType(@PathVariable("petTypeId") int petTypeId){ PetType petType = this.clinicService.findPetTypeById(petTypeId); @@ -64,8 +67,8 @@ public class PetTypeRestController { } return new ResponseEntity<PetType>(petType, HttpStatus.OK); } - - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<PetType> addPetType(@RequestBody @Valid PetType petType, BindingResult bindingResult, UriComponentsBuilder ucBuilder){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -79,7 +82,8 @@ public class PetTypeRestController { headers.setLocation(ucBuilder.path("/api/pettypes/{id}").buildAndExpand(petType.getId()).toUri()); return new ResponseEntity<PetType>(petType, headers, HttpStatus.CREATED); } - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "/{petTypeId}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<PetType> updatePetType(@PathVariable("petTypeId") int petTypeId, @RequestBody @Valid PetType petType, BindingResult bindingResult){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -97,7 +101,8 @@ public class PetTypeRestController { this.clinicService.savePetType(currentPetType); return new ResponseEntity<PetType>(currentPetType, HttpStatus.NO_CONTENT); } - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "/{petTypeId}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @Transactional public ResponseEntity<Void> deletePetType(@PathVariable("petTypeId") int petTypeId){ diff --git a/src/main/java/org/springframework/samples/petclinic/rest/SpecialtyRestController.java b/src/main/java/org/springframework/samples/petclinic/rest/SpecialtyRestController.java index 4ee88292..eb63b706 100644 --- a/src/main/java/org/springframework/samples/petclinic/rest/SpecialtyRestController.java +++ b/src/main/java/org/springframework/samples/petclinic/rest/SpecialtyRestController.java @@ -29,6 +29,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.samples.petclinic.model.Specialty; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; @@ -47,10 +48,11 @@ import org.springframework.web.util.UriComponentsBuilder; @CrossOrigin(exposedHeaders = "errors, content-type") @RequestMapping("api/specialties") public class SpecialtyRestController { - + @Autowired private ClinicService clinicService; - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Collection<Specialty>> getAllSpecialtys(){ Collection<Specialty> specialties = new ArrayList<Specialty>(); @@ -60,7 +62,8 @@ public class SpecialtyRestController { } return new ResponseEntity<Collection<Specialty>>(specialties, HttpStatus.OK); } - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "/{specialtyId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Specialty> getSpecialty(@PathVariable("specialtyId") int specialtyId){ Specialty specialty = this.clinicService.findSpecialtyById(specialtyId); @@ -69,8 +72,8 @@ public class SpecialtyRestController { } return new ResponseEntity<Specialty>(specialty, HttpStatus.OK); } - - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Specialty> addSpecialty(@RequestBody @Valid Specialty specialty, BindingResult bindingResult, UriComponentsBuilder ucBuilder){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -84,7 +87,8 @@ public class SpecialtyRestController { headers.setLocation(ucBuilder.path("/api/specialtys/{id}").buildAndExpand(specialty.getId()).toUri()); return new ResponseEntity<Specialty>(specialty, headers, HttpStatus.CREATED); } - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "/{specialtyId}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Specialty> updateSpecialty(@PathVariable("specialtyId") int specialtyId, @RequestBody @Valid Specialty specialty, BindingResult bindingResult){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -102,7 +106,8 @@ public class SpecialtyRestController { this.clinicService.saveSpecialty(currentSpecialty); return new ResponseEntity<Specialty>(currentSpecialty, HttpStatus.NO_CONTENT); } - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "/{specialtyId}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @Transactional public ResponseEntity<Void> deleteSpecialty(@PathVariable("specialtyId") int specialtyId){ diff --git a/src/main/java/org/springframework/samples/petclinic/rest/UserRestController.java b/src/main/java/org/springframework/samples/petclinic/rest/UserRestController.java new file mode 100644 index 00000000..7abb07cb --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/rest/UserRestController.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016-2017 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.samples.petclinic.rest; + +import javax.validation.Valid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.samples.petclinic.model.User; +import org.springframework.samples.petclinic.service.UserService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@CrossOrigin(exposedHeaders = "errors, content-type") +@RequestMapping("api/users") +public class UserRestController { + + @Autowired + private UserService userService; + + @PreAuthorize( "hasRole(@roles.ADMIN)" ) + @RequestMapping(value = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public ResponseEntity<User> addOwner(@RequestBody @Valid User user, BindingResult bindingResult) throws Exception { + BindingErrorsResponse errors = new BindingErrorsResponse(); + HttpHeaders headers = new HttpHeaders(); + if (bindingResult.hasErrors() || (user == null)) { + errors.addAllErrors(bindingResult); + headers.add("errors", errors.toJSON()); + return new ResponseEntity<User>(user, headers, HttpStatus.BAD_REQUEST); + } + + this.userService.saveUser(user); + return new ResponseEntity<User>(user, headers, HttpStatus.CREATED); + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/rest/VetRestController.java b/src/main/java/org/springframework/samples/petclinic/rest/VetRestController.java index b2fd3ee2..c666976e 100644 --- a/src/main/java/org/springframework/samples/petclinic/rest/VetRestController.java +++ b/src/main/java/org/springframework/samples/petclinic/rest/VetRestController.java @@ -29,6 +29,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.samples.petclinic.model.Specialty; import org.springframework.samples.petclinic.model.Vet; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; @@ -47,10 +48,11 @@ import org.springframework.web.util.UriComponentsBuilder; @CrossOrigin(exposedHeaders = "errors, content-type") @RequestMapping("api/vets") public class VetRestController { - + @Autowired private ClinicService clinicService; - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Collection<Vet>> getAllVets(){ Collection<Vet> vets = new ArrayList<Vet>(); @@ -60,7 +62,8 @@ public class VetRestController { } return new ResponseEntity<Collection<Vet>>(vets, HttpStatus.OK); } - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "/{vetId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Vet> getVet(@PathVariable("vetId") int vetId){ Vet vet = this.clinicService.findVetById(vetId); @@ -69,8 +72,8 @@ public class VetRestController { } return new ResponseEntity<Vet>(vet, HttpStatus.OK); } - - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Vet> addVet(@RequestBody @Valid Vet vet, BindingResult bindingResult, UriComponentsBuilder ucBuilder){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -84,7 +87,8 @@ public class VetRestController { headers.setLocation(ucBuilder.path("/api/vets/{id}").buildAndExpand(vet.getId()).toUri()); return new ResponseEntity<Vet>(vet, headers, HttpStatus.CREATED); } - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "/{vetId}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Vet> updateVet(@PathVariable("vetId") int vetId, @RequestBody @Valid Vet vet, BindingResult bindingResult){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -107,7 +111,8 @@ public class VetRestController { this.clinicService.saveVet(currentVet); return new ResponseEntity<Vet>(currentVet, HttpStatus.NO_CONTENT); } - + + @PreAuthorize( "hasRole(@roles.VET_ADMIN)" ) @RequestMapping(value = "/{vetId}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @Transactional public ResponseEntity<Void> deleteVet(@PathVariable("vetId") int vetId){ @@ -118,7 +123,7 @@ public class VetRestController { this.clinicService.deleteVet(vet); return new ResponseEntity<Void>(HttpStatus.NO_CONTENT); } - - + + } diff --git a/src/main/java/org/springframework/samples/petclinic/rest/VisitRestController.java b/src/main/java/org/springframework/samples/petclinic/rest/VisitRestController.java index dfbbee35..ba1638e6 100644 --- a/src/main/java/org/springframework/samples/petclinic/rest/VisitRestController.java +++ b/src/main/java/org/springframework/samples/petclinic/rest/VisitRestController.java @@ -29,6 +29,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.samples.petclinic.model.Visit; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PathVariable; @@ -47,10 +48,11 @@ import org.springframework.web.util.UriComponentsBuilder; @CrossOrigin(exposedHeaders = "errors, content-type") @RequestMapping("api/visits") public class VisitRestController { - + @Autowired private ClinicService clinicService; - + + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Collection<Visit>> getAllVisits(){ Collection<Visit> visits = new ArrayList<Visit>(); @@ -60,7 +62,8 @@ public class VisitRestController { } return new ResponseEntity<Collection<Visit>>(visits, HttpStatus.OK); } - + + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/{visitId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Visit> getVisit(@PathVariable("visitId") int visitId){ Visit visit = this.clinicService.findVisitById(visitId); @@ -69,8 +72,8 @@ public class VisitRestController { } return new ResponseEntity<Visit>(visit, HttpStatus.OK); } - - + + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Visit> addVisit(@RequestBody @Valid Visit visit, BindingResult bindingResult, UriComponentsBuilder ucBuilder){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -84,7 +87,8 @@ public class VisitRestController { headers.setLocation(ucBuilder.path("/api/visits/{id}").buildAndExpand(visit.getId()).toUri()); return new ResponseEntity<Visit>(visit, headers, HttpStatus.CREATED); } - + + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/{visitId}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity<Visit> updateVisit(@PathVariable("visitId") int visitId, @RequestBody @Valid Visit visit, BindingResult bindingResult){ BindingErrorsResponse errors = new BindingErrorsResponse(); @@ -104,7 +108,8 @@ public class VisitRestController { this.clinicService.saveVisit(currentVisit); return new ResponseEntity<Visit>(currentVisit, HttpStatus.NO_CONTENT); } - + + @PreAuthorize( "hasRole(@roles.OWNER_ADMIN)" ) @RequestMapping(value = "/{visitId}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @Transactional public ResponseEntity<Void> deleteVisit(@PathVariable("visitId") int visitId){ diff --git a/src/main/java/org/springframework/samples/petclinic/security/BasicAuthenticationAdapter.java b/src/main/java/org/springframework/samples/petclinic/security/BasicAuthenticationAdapter.java new file mode 100644 index 00000000..98140f08 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/security/BasicAuthenticationAdapter.java @@ -0,0 +1,39 @@ +package org.springframework.samples.petclinic.security; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +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.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class BasicAuthenticationAdapter extends WebSecurityConfigurerAdapter { + + @Autowired + private DataSource dataSource; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/securityNone").permitAll() + .anyRequest().authenticated() + .and() + .httpBasic().and() + .csrf().disable(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth + .jdbcAuthentication() + .dataSource(dataSource) + .usersByUsernameQuery("select username,password,enabled from users where username=?") + .authoritiesByUsernameQuery("select username,role from roles where username=?"); + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/security/Roles.java b/src/main/java/org/springframework/samples/petclinic/security/Roles.java new file mode 100644 index 00000000..d60f0497 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/security/Roles.java @@ -0,0 +1,11 @@ +package org.springframework.samples.petclinic.security; + +import org.springframework.stereotype.Component; + +@Component +public class Roles { + + public final String OWNER_ADMIN = "ROLE_OWNER_ADMIN"; + public final String VET_ADMIN = "ROLE_VET_ADMIN"; + public final String ADMIN = "ROLE_ADMIN"; +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/UserService.java b/src/main/java/org/springframework/samples/petclinic/service/UserService.java new file mode 100644 index 00000000..e637e5ec --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/UserService.java @@ -0,0 +1,8 @@ +package org.springframework.samples.petclinic.service; + +import org.springframework.samples.petclinic.model.User; + +public interface UserService { + + void saveUser(User user) throws Exception; +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/UserServiceImpl.java b/src/main/java/org/springframework/samples/petclinic/service/UserServiceImpl.java new file mode 100644 index 00000000..1075640a --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/UserServiceImpl.java @@ -0,0 +1,36 @@ +package org.springframework.samples.petclinic.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.model.User; +import org.springframework.samples.petclinic.model.Role; +import org.springframework.samples.petclinic.repository.UserRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private UserRepository userRepository; + + @Override + @Transactional + public void saveUser(User user) throws Exception { + + if(user.getRoles() == null || user.getRoles().isEmpty()) { + throw new Exception("User must have at least a role set!"); + } + + for (Role role : user.getRoles()) { + if(!role.getName().startsWith("ROLE_")) { + role.setName("ROLE_" + role.getName()); + } + + if(role.getUser() == null) { + role.setUser(user); + } + } + + userRepository.save(user); + } +} diff --git a/src/main/resources/db/hsqldb/initDB.sql b/src/main/resources/db/hsqldb/initDB.sql index f3c6947b..d14ecf3c 100644 --- a/src/main/resources/db/hsqldb/initDB.sql +++ b/src/main/resources/db/hsqldb/initDB.sql @@ -5,6 +5,8 @@ DROP TABLE visits IF EXISTS; DROP TABLE pets IF EXISTS; DROP TABLE types IF EXISTS; DROP TABLE owners IF EXISTS; +DROP TABLE roles IF EXISTS; +DROP TABLE users IF EXISTS; CREATE TABLE vets ( @@ -62,3 +64,19 @@ CREATE TABLE visits ( ); ALTER TABLE visits ADD CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets (id); CREATE INDEX visits_pet_id ON visits (pet_id); + +CREATE TABLE users ( + username VARCHAR(20) NOT NULL , + password VARCHAR(20) NOT NULL , + enabled BOOLEAN DEFAULT TRUE NOT NULL , + PRIMARY KEY (username) +); + +CREATE TABLE roles ( + id INTEGER IDENTITY PRIMARY KEY, + username VARCHAR(20) NOT NULL, + role VARCHAR(20) NOT NULL +); +ALTER TABLE roles ADD CONSTRAINT fk_username FOREIGN KEY (username) REFERENCES users (username); +CREATE INDEX fk_username_idx ON roles (username); + diff --git a/src/main/resources/db/hsqldb/populateDB.sql b/src/main/resources/db/hsqldb/populateDB.sql index 16dda3e8..01a0f404 100644 --- a/src/main/resources/db/hsqldb/populateDB.sql +++ b/src/main/resources/db/hsqldb/populateDB.sql @@ -51,3 +51,9 @@ INSERT INTO visits VALUES (1, 7, '2013-01-01', 'rabies shot'); INSERT INTO visits VALUES (2, 8, '2013-01-02', 'rabies shot'); INSERT INTO visits VALUES (3, 8, '2013-01-03', 'neutered'); INSERT INTO visits VALUES (4, 7, '2013-01-04', 'spayed'); + +INSERT INTO users(username,password,enabled) VALUES ('admin','admin', true); + +INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_OWNER_ADMIN'); +INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_VET_ADMIN'); +INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN'); diff --git a/src/main/resources/db/mysql/initDB.sql b/src/main/resources/db/mysql/initDB.sql index 6a982598..b7ab4c82 100644 --- a/src/main/resources/db/mysql/initDB.sql +++ b/src/main/resources/db/mysql/initDB.sql @@ -63,3 +63,20 @@ CREATE TABLE IF NOT EXISTS visits ( description VARCHAR(255), FOREIGN KEY (pet_id) REFERENCES pets(id) ) engine=InnoDB; + +CREATE TABLE IF NOT EXISTS users ( + username VARCHAR(20) NOT NULL , + password VARCHAR(20) NOT NULL , + enabled TINYINT NOT NULL DEFAULT 1 , + PRIMARY KEY (username) +) engine=InnoDB; + +CREATE TABLE IF NOT EXISTS roles ( + id int(11) NOT NULL AUTO_INCREMENT, + username varchar(20) NOT NULL, + role varchar(20) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY uni_username_role (role,username), + KEY fk_username_idx (username), + CONSTRAINT fk_username FOREIGN KEY (username) REFERENCES users (username) +) engine=InnoDB; diff --git a/src/main/resources/db/mysql/populateDB.sql b/src/main/resources/db/mysql/populateDB.sql index 3f1dcf8e..48a35469 100644 --- a/src/main/resources/db/mysql/populateDB.sql +++ b/src/main/resources/db/mysql/populateDB.sql @@ -51,3 +51,9 @@ INSERT IGNORE INTO visits VALUES (1, 7, '2010-03-04', 'rabies shot'); INSERT IGNORE INTO visits VALUES (2, 8, '2011-03-04', 'rabies shot'); INSERT IGNORE INTO visits VALUES (3, 8, '2009-06-04', 'neutered'); INSERT IGNORE INTO visits VALUES (4, 7, '2008-09-04', 'spayed'); + +INSERT IGNORE INTO users(username,password,enabled) VALUES ('admin','admin', true); + +INSERT IGNORE INTO roles (username, role) VALUES ('admin', 'ROLE_OWNER_ADMIN'); +INSERT IGNORE INTO roles (username, role) VALUES ('admin', 'ROLE_VET_ADMIN'); +INSERT IGNORE INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN'); diff --git a/src/main/resources/db/postgresql/initDB.sql b/src/main/resources/db/postgresql/initDB.sql index 8fa482a3..49f997b7 100644 --- a/src/main/resources/db/postgresql/initDB.sql +++ b/src/main/resources/db/postgresql/initDB.sql @@ -82,3 +82,21 @@ CREATE TABLE IF NOT EXISTS visits ( ); ALTER SEQUENCE visits_id_seq RESTART WITH 100; + +CREATE TABLE IF NOT EXISTS users ( + username VARCHAR(20) NOT NULL , + password VARCHAR(20) NOT NULL , + enabled boolean NOT NULL DEFAULT true , + CONSTRAINT pk_users PRIMARY KEY (username) +); + +CREATE TABLE IF NOT EXISTS roles ( + id SERIAL, + username varchar(20) NOT NULL, + role varchar(20) NOT NULL, + CONSTRAINT pk_roles PRIMARY KEY (id), + FOREIGN KEY (username) REFERENCES users (username) +); + +ALTER TABLE roles ADD CONSTRAINT uni_username_role UNIQUE (role,username); +ALTER SEQUENCE roles_id_seq RESTART WITH 100; diff --git a/src/main/resources/db/postgresql/populateDB.sql b/src/main/resources/db/postgresql/populateDB.sql index 0f7a94dc..2c429485 100644 --- a/src/main/resources/db/postgresql/populateDB.sql +++ b/src/main/resources/db/postgresql/populateDB.sql @@ -51,3 +51,9 @@ INSERT INTO visits VALUES (1, 7, '2010-03-04', 'rabies shot') ON CONFLICT DO NOT INSERT INTO visits VALUES (2, 8, '2011-03-04', 'rabies shot') ON CONFLICT DO NOTHING; INSERT INTO visits VALUES (3, 8, '2009-06-04', 'neutered') ON CONFLICT DO NOTHING; INSERT INTO visits VALUES (4, 7, '2008-09-04', 'spayed') ON CONFLICT DO NOTHING; + +INSERT INTO users(username,password,enabled) VALUES ('admin','admin', true) ON CONFLICT DO NOTHING; + +INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_OWNER_ADMIN') ON CONFLICT DO NOTHING; +INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_VET_ADMIN') ON CONFLICT DO NOTHING; +INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN') ON CONFLICT DO NOTHING; diff --git a/src/test/java/org/springframework/samples/petclinic/rest/OwnerRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/OwnerRestControllerTests.java index d5224274..75d8f5f8 100644 --- a/src/test/java/org/springframework/samples/petclinic/rest/OwnerRestControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/rest/OwnerRestControllerTests.java @@ -36,8 +36,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.samples.petclinic.model.Owner; -import org.springframework.samples.petclinic.service.ApplicationTestConfig; +import org.springframework.samples.petclinic.service.clinicService.ApplicationTestConfig; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -115,6 +116,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetOwnerSuccess() throws Exception { given(this.clinicService.findOwnerById(1)).willReturn(owners.get(0)); this.mockMvc.perform(get("/api/owners/1") @@ -126,6 +128,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetOwnerNotFound() throws Exception { given(this.clinicService.findOwnerById(-1)).willReturn(null); this.mockMvc.perform(get("/api/owners/-1") @@ -134,6 +137,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetOwnersListSuccess() throws Exception { owners.remove(0); owners.remove(1); @@ -149,6 +153,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetOwnersListNotFound() throws Exception { owners.clear(); given(this.clinicService.findOwnerByLastName("0")).willReturn(owners); @@ -158,6 +163,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetAllOwnersSuccess() throws Exception { owners.remove(0); owners.remove(1); @@ -173,6 +179,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetAllOwnersNotFound() throws Exception { owners.clear(); given(this.clinicService.findAllOwners()).willReturn(owners); @@ -182,6 +189,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testCreateOwnerSuccess() throws Exception { Owner newOwner = owners.get(0); newOwner.setId(999); @@ -193,6 +201,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testCreateOwnerError() throws Exception { Owner newOwner = owners.get(0); newOwner.setId(null); @@ -205,6 +214,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testUpdateOwnerSuccess() throws Exception { given(this.clinicService.findOwnerById(1)).willReturn(owners.get(0)); Owner newOwner = owners.get(0); @@ -226,6 +236,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testUpdateOwnerError() throws Exception { Owner newOwner = owners.get(0); newOwner.setFirstName(""); @@ -237,6 +248,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testDeleteOwnerSuccess() throws Exception { Owner newOwner = owners.get(0); ObjectMapper mapper = new ObjectMapper(); @@ -248,6 +260,7 @@ public class OwnerRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testDeleteOwnerError() throws Exception { Owner newOwner = owners.get(0); ObjectMapper mapper = new ObjectMapper(); diff --git a/src/test/java/org/springframework/samples/petclinic/rest/PetRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/PetRestControllerTests.java index 178d7178..1a421170 100644 --- a/src/test/java/org/springframework/samples/petclinic/rest/PetRestControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/rest/PetRestControllerTests.java @@ -39,8 +39,9 @@ import org.springframework.http.MediaType; import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.model.PetType; -import org.springframework.samples.petclinic.service.ApplicationTestConfig; +import org.springframework.samples.petclinic.service.clinicService.ApplicationTestConfig; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -109,6 +110,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetPetSuccess() throws Exception { given(this.clinicService.findPetById(3)).willReturn(pets.get(0)); this.mockMvc.perform(get("/api/pets/3") @@ -120,6 +122,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetPetNotFound() throws Exception { given(this.clinicService.findPetById(-1)).willReturn(null); this.mockMvc.perform(get("/api/pets/-1") @@ -128,6 +131,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetAllPetsSuccess() throws Exception { given(this.clinicService.findAllPets()).willReturn(pets); this.mockMvc.perform(get("/api/pets/") @@ -141,6 +145,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetAllPetsNotFound() throws Exception { pets.clear(); given(this.clinicService.findAllPets()).willReturn(pets); @@ -150,6 +155,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testCreatePetSuccess() throws Exception { Pet newPet = pets.get(0); newPet.setId(999); @@ -161,6 +167,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testCreatePetError() throws Exception { Pet newPet = pets.get(0); newPet.setId(null); @@ -173,6 +180,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testUpdatePetSuccess() throws Exception { given(this.clinicService.findPetById(3)).willReturn(pets.get(0)); Pet newPet = pets.get(0); @@ -194,6 +202,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testUpdatePetError() throws Exception { Pet newPet = pets.get(0); newPet.setName(""); @@ -205,6 +214,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testDeletePetSuccess() throws Exception { Pet newPet = pets.get(0); ObjectMapper mapper = new ObjectMapper(); @@ -216,6 +226,7 @@ public class PetRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testDeletePetError() throws Exception { Pet newPet = pets.get(0); ObjectMapper mapper = new ObjectMapper(); diff --git a/src/test/java/org/springframework/samples/petclinic/rest/PetTypeRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/PetTypeRestControllerTests.java index 4b11bf33..e0a3c7cb 100644 --- a/src/test/java/org/springframework/samples/petclinic/rest/PetTypeRestControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/rest/PetTypeRestControllerTests.java @@ -36,8 +36,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.samples.petclinic.model.PetType; -import org.springframework.samples.petclinic.service.ApplicationTestConfig; +import org.springframework.samples.petclinic.service.clinicService.ApplicationTestConfig; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -97,7 +98,8 @@ public class PetTypeRestControllerTests { } @Test - public void testGetPetTypeSuccess() throws Exception { + @WithMockUser(roles="OWNER_ADMIN") + public void testGetPetTypeSuccessAsOwnerAdmin() throws Exception { given(this.clinicService.findPetTypeById(1)).willReturn(petTypes.get(0)); this.mockMvc.perform(get("/api/pettypes/1") .accept(MediaType.APPLICATION_JSON_VALUE)) @@ -108,6 +110,19 @@ public class PetTypeRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") + public void testGetPetTypeSuccessAsVetAdmin() throws Exception { + given(this.clinicService.findPetTypeById(1)).willReturn(petTypes.get(0)); + this.mockMvc.perform(get("/api/pettypes/1") + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isOk()) + .andExpect(content().contentType("application/json;charset=UTF-8")) + .andExpect(jsonPath("$.id").value(1)) + .andExpect(jsonPath("$.name").value("cat")); + } + + @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetPetTypeNotFound() throws Exception { given(this.clinicService.findPetTypeById(-1)).willReturn(null); this.mockMvc.perform(get("/api/pettypes/-1") @@ -116,7 +131,8 @@ public class PetTypeRestControllerTests { } @Test - public void testGetAllPetTypesSuccess() throws Exception { + @WithMockUser(roles="OWNER_ADMIN") + public void testGetAllPetTypesSuccessAsOwnerAdmin() throws Exception { petTypes.remove(0); petTypes.remove(1); given(this.clinicService.findAllPetTypes()).willReturn(petTypes); @@ -131,6 +147,23 @@ public class PetTypeRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") + public void testGetAllPetTypesSuccessAsVetAdmin() throws Exception { + petTypes.remove(0); + petTypes.remove(1); + given(this.clinicService.findAllPetTypes()).willReturn(petTypes); + this.mockMvc.perform(get("/api/pettypes/") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType("application/json;charset=UTF-8")) + .andExpect(jsonPath("$.[0].id").value(2)) + .andExpect(jsonPath("$.[0].name").value("dog")) + .andExpect(jsonPath("$.[1].id").value(4)) + .andExpect(jsonPath("$.[1].name").value("snake")); + } + + @Test + @WithMockUser(roles="VET_ADMIN") public void testGetAllPetTypesNotFound() throws Exception { petTypes.clear(); given(this.clinicService.findAllPetTypes()).willReturn(petTypes); @@ -140,6 +173,7 @@ public class PetTypeRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testCreatePetTypeSuccess() throws Exception { PetType newPetType = petTypes.get(0); newPetType.setId(999); @@ -151,6 +185,7 @@ public class PetTypeRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testCreatePetTypeError() throws Exception { PetType newPetType = petTypes.get(0); newPetType.setId(null); @@ -163,6 +198,7 @@ public class PetTypeRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testUpdatePetTypeSuccess() throws Exception { given(this.clinicService.findPetTypeById(2)).willReturn(petTypes.get(1)); PetType newPetType = petTypes.get(1); @@ -183,6 +219,7 @@ public class PetTypeRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testUpdatePetTypeError() throws Exception { PetType newPetType = petTypes.get(0); newPetType.setName(""); @@ -194,6 +231,7 @@ public class PetTypeRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testDeletePetTypeSuccess() throws Exception { PetType newPetType = petTypes.get(0); ObjectMapper mapper = new ObjectMapper(); @@ -205,6 +243,7 @@ public class PetTypeRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testDeletePetTypeError() throws Exception { PetType newPetType = petTypes.get(0); ObjectMapper mapper = new ObjectMapper(); diff --git a/src/test/java/org/springframework/samples/petclinic/rest/SpecialtyRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/SpecialtyRestControllerTests.java index 4b0c5272..1f99c1cc 100644 --- a/src/test/java/org/springframework/samples/petclinic/rest/SpecialtyRestControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/rest/SpecialtyRestControllerTests.java @@ -36,8 +36,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.samples.petclinic.model.Specialty; -import org.springframework.samples.petclinic.service.ApplicationTestConfig; +import org.springframework.samples.petclinic.service.clinicService.ApplicationTestConfig; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -92,6 +93,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testGetSpecialtySuccess() throws Exception { given(this.clinicService.findSpecialtyById(1)).willReturn(specialties.get(0)); this.mockMvc.perform(get("/api/specialties/1") @@ -103,6 +105,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testGetSpecialtyNotFound() throws Exception { given(this.clinicService.findSpecialtyById(-1)).willReturn(null); this.mockMvc.perform(get("/api/specialties/-1") @@ -111,6 +114,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testGetAllSpecialtysSuccess() throws Exception { specialties.remove(0); given(this.clinicService.findAllSpecialties()).willReturn(specialties); @@ -125,6 +129,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testGetAllSpecialtysNotFound() throws Exception { specialties.clear(); given(this.clinicService.findAllSpecialties()).willReturn(specialties); @@ -134,6 +139,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testCreateSpecialtySuccess() throws Exception { Specialty newSpecialty = specialties.get(0); newSpecialty.setId(999); @@ -145,6 +151,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testCreateSpecialtyError() throws Exception { Specialty newSpecialty = specialties.get(0); newSpecialty.setId(null); @@ -157,6 +164,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testUpdateSpecialtySuccess() throws Exception { given(this.clinicService.findSpecialtyById(2)).willReturn(specialties.get(1)); Specialty newSpecialty = specialties.get(1); @@ -177,6 +185,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testUpdateSpecialtyError() throws Exception { Specialty newSpecialty = specialties.get(0); newSpecialty.setName(""); @@ -188,6 +197,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testDeleteSpecialtySuccess() throws Exception { Specialty newSpecialty = specialties.get(0); ObjectMapper mapper = new ObjectMapper(); @@ -199,6 +209,7 @@ public class SpecialtyRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testDeleteSpecialtyError() throws Exception { Specialty newSpecialty = specialties.get(0); ObjectMapper mapper = new ObjectMapper(); diff --git a/src/test/java/org/springframework/samples/petclinic/rest/UserRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/UserRestControllerTests.java new file mode 100644 index 00000000..c1667640 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/rest/UserRestControllerTests.java @@ -0,0 +1,74 @@ +package org.springframework.samples.petclinic.rest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.samples.petclinic.model.User; +import org.springframework.samples.petclinic.service.clinicService.ApplicationTestConfig; +import org.springframework.samples.petclinic.service.UserService; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@SpringBootTest +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ApplicationTestConfig.class) +@WebAppConfiguration +public class UserRestControllerTests { + + @Mock + private UserService userService; + + @Autowired + private UserRestController userRestController; + + private MockMvc mockMvc; + + @Before + public void initVets() { + this.mockMvc = MockMvcBuilders.standaloneSetup(userRestController) + .setControllerAdvice(new ExceptionControllerAdvice()).build(); + } + + @Test + @WithMockUser(roles="ADMIN") + public void testCreateUserSuccess() throws Exception { + User user = new User(); + user.setUsername("username"); + user.setPassword("password"); + user.setEnabled(true); + user.addRole( "OWNER_ADMIN" ); + ObjectMapper mapper = new ObjectMapper(); + String newVetAsJSON = mapper.writeValueAsString(user); + this.mockMvc.perform(post("/api/users/") + .content(newVetAsJSON).accept(MediaType.APPLICATION_JSON_VALUE).contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isCreated()); + } + + @Test + @WithMockUser(roles="ADMIN") + public void testCreateUserError() throws Exception { + User user = new User(); + user.setUsername("username"); + user.setPassword("password"); + user.setEnabled(true); + ObjectMapper mapper = new ObjectMapper(); + String newVetAsJSON = mapper.writeValueAsString(user); + this.mockMvc.perform(post("/api/users/") + .content(newVetAsJSON).accept(MediaType.APPLICATION_JSON_VALUE).contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isBadRequest()); + } +} diff --git a/src/test/java/org/springframework/samples/petclinic/rest/VetRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/VetRestControllerTests.java index a1adbea6..9358b6da 100644 --- a/src/test/java/org/springframework/samples/petclinic/rest/VetRestControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/rest/VetRestControllerTests.java @@ -36,8 +36,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.samples.petclinic.model.Vet; -import org.springframework.samples.petclinic.service.ApplicationTestConfig; +import org.springframework.samples.petclinic.service.clinicService.ApplicationTestConfig; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -95,6 +96,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testGetVetSuccess() throws Exception { given(this.clinicService.findVetById(1)).willReturn(vets.get(0)); this.mockMvc.perform(get("/api/vets/1") @@ -106,6 +108,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testGetVetNotFound() throws Exception { given(this.clinicService.findVetById(-1)).willReturn(null); this.mockMvc.perform(get("/api/vets/-1") @@ -114,6 +117,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testGetAllVetsSuccess() throws Exception { given(this.clinicService.findAllVets()).willReturn(vets); this.mockMvc.perform(get("/api/vets/") @@ -127,6 +131,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testGetAllVetsNotFound() throws Exception { vets.clear(); given(this.clinicService.findAllVets()).willReturn(vets); @@ -136,6 +141,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testCreateVetSuccess() throws Exception { Vet newVet = vets.get(0); newVet.setId(999); @@ -147,6 +153,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testCreateVetError() throws Exception { Vet newVet = vets.get(0); newVet.setId(null); @@ -159,6 +166,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testUpdateVetSuccess() throws Exception { given(this.clinicService.findVetById(1)).willReturn(vets.get(0)); Vet newVet = vets.get(0); @@ -180,6 +188,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testUpdateVetError() throws Exception { Vet newVet = vets.get(0); newVet.setFirstName(""); @@ -191,6 +200,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testDeleteVetSuccess() throws Exception { Vet newVet = vets.get(0); ObjectMapper mapper = new ObjectMapper(); @@ -202,6 +212,7 @@ public class VetRestControllerTests { } @Test + @WithMockUser(roles="VET_ADMIN") public void testDeleteVetError() throws Exception { Vet newVet = vets.get(0); ObjectMapper mapper = new ObjectMapper(); diff --git a/src/test/java/org/springframework/samples/petclinic/rest/VisitRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/VisitRestControllerTests.java index 5d4dc5ee..1d0c1b2a 100644 --- a/src/test/java/org/springframework/samples/petclinic/rest/VisitRestControllerTests.java +++ b/src/test/java/org/springframework/samples/petclinic/rest/VisitRestControllerTests.java @@ -41,8 +41,9 @@ import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.model.Visit; -import org.springframework.samples.petclinic.service.ApplicationTestConfig; +import org.springframework.samples.petclinic.service.clinicService.ApplicationTestConfig; import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -118,6 +119,7 @@ public class VisitRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetVisitSuccess() throws Exception { given(this.clinicService.findVisitById(2)).willReturn(visits.get(0)); this.mockMvc.perform(get("/api/visits/2") @@ -129,6 +131,7 @@ public class VisitRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetVisitNotFound() throws Exception { given(this.clinicService.findVisitById(-1)).willReturn(null); this.mockMvc.perform(get("/api/visits/-1") @@ -137,6 +140,7 @@ public class VisitRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetAllVisitsSuccess() throws Exception { given(this.clinicService.findAllVisits()).willReturn(visits); this.mockMvc.perform(get("/api/visits/") @@ -150,6 +154,7 @@ public class VisitRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testGetAllVisitsNotFound() throws Exception { visits.clear(); given(this.clinicService.findAllVisits()).willReturn(visits); @@ -159,6 +164,7 @@ public class VisitRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testCreateVisitSuccess() throws Exception { Visit newVisit = visits.get(0); newVisit.setId(999); @@ -171,6 +177,7 @@ public class VisitRestControllerTests { } @Test(expected = IOException.class) + @WithMockUser(roles="OWNER_ADMIN") public void testCreateVisitError() throws Exception { Visit newVisit = visits.get(0); newVisit.setId(null); @@ -183,6 +190,7 @@ public class VisitRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testUpdateVisitSuccess() throws Exception { given(this.clinicService.findVisitById(2)).willReturn(visits.get(0)); Visit newVisit = visits.get(0); @@ -203,6 +211,7 @@ public class VisitRestControllerTests { } @Test(expected = IOException.class) + @WithMockUser(roles="OWNER_ADMIN") public void testUpdateVisitError() throws Exception { Visit newVisit = visits.get(0); newVisit.setPet(null); @@ -214,6 +223,7 @@ public class VisitRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testDeleteVisitSuccess() throws Exception { Visit newVisit = visits.get(0); ObjectMapper mapper = new ObjectMapper(); @@ -225,6 +235,7 @@ public class VisitRestControllerTests { } @Test + @WithMockUser(roles="OWNER_ADMIN") public void testDeleteVisitError() throws Exception { Visit newVisit = visits.get(0); ObjectMapper mapper = new ObjectMapper(); diff --git a/src/test/java/org/springframework/samples/petclinic/service/AbstractClinicServiceTests.java b/src/test/java/org/springframework/samples/petclinic/service/clinicService/AbstractClinicServiceTests.java similarity index 98% rename from src/test/java/org/springframework/samples/petclinic/service/AbstractClinicServiceTests.java rename to src/test/java/org/springframework/samples/petclinic/service/clinicService/AbstractClinicServiceTests.java index d2625ad9..50655895 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/AbstractClinicServiceTests.java +++ b/src/test/java/org/springframework/samples/petclinic/service/clinicService/AbstractClinicServiceTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.service; +package org.springframework.samples.petclinic.service.clinicService; import static org.assertj.core.api.Assertions.assertThat; @@ -30,6 +30,7 @@ import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.model.Specialty; import org.springframework.samples.petclinic.model.Vet; import org.springframework.samples.petclinic.model.Visit; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.samples.petclinic.util.EntityUtils; import org.springframework.test.context.ContextConfiguration; import org.springframework.transaction.annotation.Transactional; @@ -58,7 +59,7 @@ public abstract class AbstractClinicServiceTests { @Autowired protected ClinicService clinicService; - + @Before public void init() { MockitoAnnotations.initMocks(this); @@ -207,7 +208,7 @@ public abstract class AbstractClinicServiceTests { assertThat(visitArr[0].getDate()).isNotNull(); assertThat(visitArr[0].getPet().getId()).isEqualTo(7); } - + @Test public void shouldFindAllPets(){ Collection<Pet> pets = this.clinicService.findAllPets(); @@ -216,7 +217,7 @@ public abstract class AbstractClinicServiceTests { Pet pet3 = EntityUtils.getById(pets, Pet.class, 3); assertThat(pet3.getName()).isEqualTo("Rosy"); } - + @Test @Transactional public void shouldDeletePet(){ @@ -229,14 +230,14 @@ public abstract class AbstractClinicServiceTests { } assertThat(pet).isNull(); } - + @Test public void shouldFindVisitDyId(){ Visit visit = this.clinicService.findVisitById(1); assertThat(visit.getId()).isEqualTo(1); assertThat(visit.getPet().getName()).isEqualTo("Samantha"); } - + @Test public void shouldFindAllVisits(){ Collection<Visit> visits = this.clinicService.findAllVisits(); @@ -245,28 +246,28 @@ public abstract class AbstractClinicServiceTests { Visit visit3 = EntityUtils.getById(visits, Visit.class, 3); assertThat(visit3.getPet().getName()).isEqualTo("Max"); } - + @Test @Transactional public void shouldInsertVisit() { Collection<Visit> visits = this.clinicService.findAllVisits(); int found = visits.size(); - + Pet pet = this.clinicService.findPetById(1); Visit visit = new Visit(); visit.setPet(pet); visit.setDate(new Date()); visit.setDescription("new visit"); - - + + this.clinicService.saveVisit(visit); assertThat(visit.getId().longValue()).isNotEqualTo(0); visits = this.clinicService.findAllVisits(); assertThat(visits.size()).isEqualTo(found + 1); } - + @Test @Transactional public void shouldUpdateVisit(){ @@ -278,7 +279,7 @@ public abstract class AbstractClinicServiceTests { visit = this.clinicService.findVisitById(1); assertThat(visit.getDescription()).isEqualTo(newDesc); } - + @Test @Transactional public void shouldDeleteVisit(){ @@ -291,14 +292,14 @@ public abstract class AbstractClinicServiceTests { } assertThat(visit).isNull(); } - + @Test public void shouldFindVetDyId(){ Vet vet = this.clinicService.findVetById(1); assertThat(vet.getFirstName()).isEqualTo("James"); assertThat(vet.getLastName()).isEqualTo("Carter"); } - + @Test @Transactional public void shouldInsertVet() { @@ -308,14 +309,14 @@ public abstract class AbstractClinicServiceTests { Vet vet = new Vet(); vet.setFirstName("John"); vet.setLastName("Dow"); - + this.clinicService.saveVet(vet); assertThat(vet.getId().longValue()).isNotEqualTo(0); vets = this.clinicService.findAllVets(); assertThat(vets.size()).isEqualTo(found + 1); } - + @Test @Transactional public void shouldUpdateVet(){ @@ -327,7 +328,7 @@ public abstract class AbstractClinicServiceTests { vet = this.clinicService.findVetById(1); assertThat(vet.getLastName()).isEqualTo(newLastName); } - + @Test @Transactional public void shouldDeleteVet(){ @@ -340,7 +341,7 @@ public abstract class AbstractClinicServiceTests { } assertThat(vet).isNull(); } - + @Test public void shouldFindAllOwners(){ Collection<Owner> owners = this.clinicService.findAllOwners(); @@ -349,7 +350,7 @@ public abstract class AbstractClinicServiceTests { Owner owner3 = EntityUtils.getById(owners, Owner.class, 3); assertThat(owner3.getFirstName()).isEqualTo("Eduardo"); } - + @Test @Transactional public void shouldDeleteOwner(){ @@ -362,13 +363,13 @@ public abstract class AbstractClinicServiceTests { } assertThat(owner).isNull(); } - + @Test public void shouldFindPetTypeById(){ PetType petType = this.clinicService.findPetTypeById(1); assertThat(petType.getName()).isEqualTo("cat"); } - + @Test public void shouldFindAllPetTypes(){ Collection<PetType> petTypes = this.clinicService.findAllPetTypes(); @@ -377,7 +378,7 @@ public abstract class AbstractClinicServiceTests { PetType petType3 = EntityUtils.getById(petTypes, PetType.class, 3); assertThat(petType3.getName()).isEqualTo("lizard"); } - + @Test @Transactional public void shouldInsertPetType() { @@ -386,14 +387,14 @@ public abstract class AbstractClinicServiceTests { PetType petType = new PetType(); petType.setName("tiger"); - + this.clinicService.savePetType(petType); assertThat(petType.getId().longValue()).isNotEqualTo(0); petTypes = this.clinicService.findAllPetTypes(); assertThat(petTypes.size()).isEqualTo(found + 1); } - + @Test @Transactional public void shouldUpdatePetType(){ @@ -405,7 +406,7 @@ public abstract class AbstractClinicServiceTests { petType = this.clinicService.findPetTypeById(1); assertThat(petType.getName()).isEqualTo(newLastName); } - + @Test @Transactional public void shouldDeletePetType(){ @@ -418,13 +419,13 @@ public abstract class AbstractClinicServiceTests { } assertThat(petType).isNull(); } - + @Test public void shouldFindSpecialtyById(){ Specialty specialty = this.clinicService.findSpecialtyById(1); assertThat(specialty.getName()).isEqualTo("radiology"); } - + @Test public void shouldFindAllSpecialtys(){ Collection<Specialty> specialties = this.clinicService.findAllSpecialties(); @@ -433,7 +434,7 @@ public abstract class AbstractClinicServiceTests { Specialty specialty3 = EntityUtils.getById(specialties, Specialty.class, 3); assertThat(specialty3.getName()).isEqualTo("dentistry"); } - + @Test @Transactional public void shouldInsertSpecialty() { @@ -442,14 +443,14 @@ public abstract class AbstractClinicServiceTests { Specialty specialty = new Specialty(); specialty.setName("dermatologist"); - + this.clinicService.saveSpecialty(specialty); assertThat(specialty.getId().longValue()).isNotEqualTo(0); specialties = this.clinicService.findAllSpecialties(); assertThat(specialties.size()).isEqualTo(found + 1); } - + @Test @Transactional public void shouldUpdateSpecialty(){ @@ -461,7 +462,7 @@ public abstract class AbstractClinicServiceTests { specialty = this.clinicService.findSpecialtyById(1); assertThat(specialty.getName()).isEqualTo(newLastName); } - + @Test @Transactional public void shouldDeleteSpecialty(){ @@ -474,7 +475,7 @@ public abstract class AbstractClinicServiceTests { } assertThat(specialty).isNull(); } - + } diff --git a/src/test/java/org/springframework/samples/petclinic/service/ApplicationTestConfig.java b/src/test/java/org/springframework/samples/petclinic/service/clinicService/ApplicationTestConfig.java similarity index 77% rename from src/test/java/org/springframework/samples/petclinic/service/ApplicationTestConfig.java rename to src/test/java/org/springframework/samples/petclinic/service/clinicService/ApplicationTestConfig.java index ac3898b3..a2014552 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/ApplicationTestConfig.java +++ b/src/test/java/org/springframework/samples/petclinic/service/clinicService/ApplicationTestConfig.java @@ -1,11 +1,11 @@ -package org.springframework.samples.petclinic.service; +package org.springframework.samples.petclinic.service.clinicService; import org.mockito.MockitoAnnotations; import org.springframework.boot.test.context.TestConfiguration; @TestConfiguration public class ApplicationTestConfig { - + public ApplicationTestConfig(){ MockitoAnnotations.initMocks(this); } diff --git a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceJdbcTests.java b/src/test/java/org/springframework/samples/petclinic/service/clinicService/ClinicServiceJdbcTests.java similarity index 94% rename from src/test/java/org/springframework/samples/petclinic/service/ClinicServiceJdbcTests.java rename to src/test/java/org/springframework/samples/petclinic/service/clinicService/ClinicServiceJdbcTests.java index c7735bfe..5c3ea711 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceJdbcTests.java +++ b/src/test/java/org/springframework/samples/petclinic/service/clinicService/ClinicServiceJdbcTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.samples.petclinic.service; +package org.springframework.samples.petclinic.service.clinicService; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceJpaTests.java b/src/test/java/org/springframework/samples/petclinic/service/clinicService/ClinicServiceJpaTests.java similarity index 89% rename from src/test/java/org/springframework/samples/petclinic/service/ClinicServiceJpaTests.java rename to src/test/java/org/springframework/samples/petclinic/service/clinicService/ClinicServiceJpaTests.java index 7cb6ab6e..d0ada35b 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceJpaTests.java +++ b/src/test/java/org/springframework/samples/petclinic/service/clinicService/ClinicServiceJpaTests.java @@ -1,4 +1,4 @@ -package org.springframework.samples.petclinic.service; +package org.springframework.samples.petclinic.service.clinicService; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceSpringDataJpaTests.java b/src/test/java/org/springframework/samples/petclinic/service/clinicService/ClinicServiceSpringDataJpaTests.java similarity index 89% rename from src/test/java/org/springframework/samples/petclinic/service/ClinicServiceSpringDataJpaTests.java rename to src/test/java/org/springframework/samples/petclinic/service/clinicService/ClinicServiceSpringDataJpaTests.java index 041e8971..d3f27fbf 100644 --- a/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceSpringDataJpaTests.java +++ b/src/test/java/org/springframework/samples/petclinic/service/clinicService/ClinicServiceSpringDataJpaTests.java @@ -1,4 +1,4 @@ -package org.springframework.samples.petclinic.service; +package org.springframework.samples.petclinic.service.clinicService; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/org/springframework/samples/petclinic/service/userService/AbstractUserServiceTests.java b/src/test/java/org/springframework/samples/petclinic/service/userService/AbstractUserServiceTests.java new file mode 100644 index 00000000..ef82d68d --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/service/userService/AbstractUserServiceTests.java @@ -0,0 +1,36 @@ +package org.springframework.samples.petclinic.service.userService; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.model.User; +import org.springframework.samples.petclinic.service.UserService; + +public abstract class AbstractUserServiceTests { + + @Autowired + private UserService userService; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void shouldAddUser() throws Exception { + User user = new User(); + user.setUsername("username"); + user.setPassword("password"); + user.setEnabled(true); + user.addRole("OWNER_ADMIN"); + + userService.saveUser(user); + assertThat(user.getRoles().parallelStream().allMatch(role -> role.getName().startsWith("ROLE_")), is(true)); + assertThat(user.getRoles().parallelStream().allMatch(role -> role.getUser() != null), is(true)); + } +} diff --git a/src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceJdbcTests.java b/src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceJdbcTests.java new file mode 100644 index 00000000..790a1ff7 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceJdbcTests.java @@ -0,0 +1,13 @@ +package org.springframework.samples.petclinic.service.userService; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@SpringBootTest +@RunWith(SpringJUnit4ClassRunner.class) +@ActiveProfiles("jdbc, hsqldb") +public class UserServiceJdbcTests extends AbstractUserServiceTests { + +} diff --git a/src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceJpaTests.java b/src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceJpaTests.java new file mode 100644 index 00000000..370c6675 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceJpaTests.java @@ -0,0 +1,13 @@ +package org.springframework.samples.petclinic.service.userService; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@SpringBootTest +@RunWith(SpringJUnit4ClassRunner.class) +@ActiveProfiles("jpa, hsqldb") +public class UserServiceJpaTests extends AbstractUserServiceTests { + +} diff --git a/src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceSpringDataJpaTests.java b/src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceSpringDataJpaTests.java new file mode 100644 index 00000000..09d13146 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/service/userService/UserServiceSpringDataJpaTests.java @@ -0,0 +1,13 @@ +package org.springframework.samples.petclinic.service.userService; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@SpringBootTest +@RunWith(SpringJUnit4ClassRunner.class) +@ActiveProfiles("spring-data-jpa, hsqldb") +public class UserServiceSpringDataJpaTests extends AbstractUserServiceTests { + +} -- GitLab