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