diff --git a/pom.xml b/pom.xml index d53bf80d88b7cc97a493ee90c09ee624438f4f50..0fc0b3f978b42663ab71b3fd65892b665df6c170 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/readme.md b/readme.md index 0a645e7fcd52cd5dd4e49b3d86a1141201e8db8f..98e7babf1d28f0aae65cdb1bfb90b4a27ff61df3 100644 --- a/readme.md +++ b/readme.md @@ -80,6 +80,35 @@ You may also start a Postgres database with docker: docker run --name postgres-petclinic -e POSTGRES_PASSWORD=petclinic -e POSTGRES_DB=petclinic -p 5432:5432 -d postgres:9.6.0 ``` +## Security configuration +In its default configuration, Petclinic doesn't have authentication and authorization enabled. + +### Basic Authentication +In order to use the basic authentication functionality, turn in on from the application.properties file +``` +basic.authentication.enabled=true +``` +This will secure all APIs and in order to access them, basic authentication is required. +Apart from authentication, APIs also require authorization. This is done via roles that a user can have. +The existing roles are listed below with the corresponding permissions +* OWNER_ADMIN -> OwnerController, PetController, PetTypeController (getAllPetTypes and getPetType), VisitController +* VET_ADMIN -> PetTypeController, SpecialityController, VetController +* ADMIN -> UserController + +There is an existing user with the username admin and password admin that has access to all APIs. + In order to add a new user, please use the following API: +``` +POST /api/users +{ + "username": "secondAdmin", + "password": "password", + "enabled": true, + "roles": [ + { "name" : "OWNER_ADMIN" } + ] +} +``` + ## Working with Petclinic in Eclipse/STS ### prerequisites 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 0000000000000000000000000000000000000000..8dd19a10274326357bbb66817d04eb7801136d0b --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/model/Role.java @@ -0,0 +1,39 @@ +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") + @JsonIgnore + 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 0000000000000000000000000000000000000000..1bfe90a418ad20516409bd4d3bc00637f43d0fbe --- /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 0000000000000000000000000000000000000000..3e9b45ba7372250ce88a3d935ce3d8d960359892 --- /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 0000000000000000000000000000000000000000..7fc51ecbd97a5be5549fbecea60cbf68fd56c73f --- /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 0000000000000000000000000000000000000000..d73a7e9fbe69b20dd096f3596a6128ef052574c9 --- /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 0000000000000000000000000000000000000000..4219df459fa5f8c83126ef5513d67871deda5e45 --- /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 e3b3aadb54dd26f4c800e59442dce6aa526e7118..ff60a276910b999c0af1daf39454b113c25e4c64 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 6759cdcf050754ebd187c798eda495ca5fa82435..79d971d66a4c1885133384f70e8caa451de9e5ac 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 239397c1eedb490283e11d8893538f9f857f08d1..e16f51e81c5b5cac4ec27374873e2091d9af9336 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 4ee8829204a1322c51982f284a50ca6f0007dc6e..eb63b7064b43140a50c90d513e3275aa264a1147 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 0000000000000000000000000000000000000000..7abb07cb959a3fa0904ec1c85b0636513c9b47f5 --- /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 b2fd3ee2b1f83de84945faaa40c1b0a99a1bc4f4..c666976e56a477fad5f868af7cecef04b2dfc15c 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 dfbbee35c1625badff550d1d0fc40b25abe209fe..ba1638e6f86bae1958e59d9e201b4ed7e0287ef9 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 0000000000000000000000000000000000000000..b9c9dfb09fbd3acea2c91dc91ba263f071dd0572 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/security/BasicAuthenticationAdapter.java @@ -0,0 +1,41 @@ +package org.springframework.samples.petclinic.security; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +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) +@ConditionalOnProperty( "basic.authentication.enabled" ) +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 0000000000000000000000000000000000000000..d60f04972284faeaf0259966ae220fc3061bc9d8 --- /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 0000000000000000000000000000000000000000..e637e5ecf5bb89ec0be2b58a1ea60e3caf4a0c8c --- /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 0000000000000000000000000000000000000000..1075640a1017fc0a62911070354bb45a6fe87033 --- /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/application.properties b/src/main/resources/application.properties index 13904f040be640ef652547e0f850d236e1b46134..77f1022a6db6dfcb1f3f690d8e2bbeaf881b1211 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -30,3 +30,8 @@ logging.level.org.springframework=INFO #logging.level.org.hibernate.SQL=DEBUG #logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE + +# enable the desired authentication type +# by default the authentication is disabled +security.ignored=/** +basic.authentication.enabled=false diff --git a/src/main/resources/db/hsqldb/initDB.sql b/src/main/resources/db/hsqldb/initDB.sql index f3c6947b7db1408f9f5d68b2d5c69a736b21df66..d14ecf3c29f78b85d34aa72d0bbe4503f2361b90 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 16dda3e8485cd38ddb915f4360d9fff7c213d40b..01a0f404cda03db7f52149519c2e110658f80346 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 6a982598373c3d641bea6d33bcfa8e9f417629e4..b7ab4c82d8f417cb651fdb250b0cc9a85844915c 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 3f1dcf8ea161c9ab2baa54e2b2a2ac55bf381458..48a354697ceee8f0489d0a2c291632fd01b4e9a3 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 8fa482a364685579d1831af1c91d1e74ba0c9aae..49f997b76d5a983bc45d2e2ff5fe114a925f0266 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 0f7a94dc7258b0aa750e88414ebe6a5213d9f98f..2c429485a28796d49457020f7d4298b7ee7be4a2 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 d52242742c3afa1cbbb51e92d5f7103cdabb4203..75d8f5f8b149feee863993e5b111c8b20ddb56f3 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 178d7178db6f77e49fe52c14e81873a833d38d50..1a421170ab6cf182dd8b601551853bba1c8c7d5f 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 4b11bf3330627d97702bb8626251cdac3b498e96..e0a3c7cb0d2865c0f7ca85a4a05ea2b4a25274e6 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 4b0c527225cc14b189494a9c276f80f1f8b2fe45..1f99c1cccda0fe6dc39c216b4e469098a701e833 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 0000000000000000000000000000000000000000..c16676407ec4a00a3967d6f473c1f527b34a6c8b --- /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 a1adbea6bb513a7425ec45c55db7d5fe2e42aced..9358b6daf6aded04b881854361a5195723952c00 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 5d4dc5eef2d2897e7ef37642b09f75c3146c5cb4..1d0c1b2aac444dde05e1d6dd2aa14077353a3793 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 d2625ad9c41bb83ded13a94643ebf2db725e00fc..50655895842775ddecc1877a3c36d30ca354fba3 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 ac3898b3447f849ffa77f444cf215ce75c2c31e1..a20145521a53f7b61ae29abb0020181f54ac5db1 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 c7735bfea4357d78e89a148459c235b3ce5a47b7..5c3ea71158d1463426ba35af4a6674abe3ef00bd 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 7cb6ab6e440df746a896bdc4cecffb99a84280f3..d0ada35b7cccafd1695ef4834beeee8185a71e37 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 041e8971e936894da2bc51ef8f2317f675255a08..d3f27fbfbce68dc3972d8dd292c72495a36000ba 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 0000000000000000000000000000000000000000..ef82d68d70a1f468245347171e74d53339347b87 --- /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 0000000000000000000000000000000000000000..790a1ff7f89c1feb2ebab6f7cd71eeecc2a64924 --- /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 0000000000000000000000000000000000000000..370c6675715cccc3cac55cd07d04be66a9f1bb4b --- /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 0000000000000000000000000000000000000000..09d13146cfcbf08fd00b1be60b13c1ec824f2029 --- /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 { + +}