From 9bb284fc84fd2d421729e805d220b5d0de157161 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Sat, 1 Aug 2015 21:08:38 +0200 Subject: [PATCH] #119 - Polishing. Changed the update clause to set the the entire principal the reflect a domain object design that's closer to what might be set up if Spring Data auditing is used, too. Made use of Lombok in the domain objects where possible. Reduced visibility of repository interfaces to package scope. Minor test case cleanups. --- .../jpa/security/BusinessObject.java | 92 +++---------------- .../security/BusinessObjectRepository.java | 7 +- .../SecureBusinessObjectRepository.java | 13 +-- .../example/springdata/jpa/security/User.java | 39 +++----- .../security/SecurityIntegrationTests.java | 51 +++++----- 5 files changed, 61 insertions(+), 141 deletions(-) diff --git a/jpa/security/src/main/java/example/springdata/jpa/security/BusinessObject.java b/jpa/security/src/main/java/example/springdata/jpa/security/BusinessObject.java index 8ea013c1..421b8e65 100644 --- a/jpa/security/src/main/java/example/springdata/jpa/security/BusinessObject.java +++ b/jpa/security/src/main/java/example/springdata/jpa/security/BusinessObject.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 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. @@ -15,6 +15,9 @@ */ package example.springdata.jpa.security; +import lombok.Data; +import lombok.Getter; + import java.util.Date; import javax.persistence.Entity; @@ -24,93 +27,28 @@ import javax.persistence.ManyToOne; /** * @author Thomas Darimont + * @author Oliver Gierke */ @Entity +@Data public class BusinessObject { - @Id @GeneratedValue Long id; - String data; + private @Id @GeneratedValue @Getter Long id; + private @ManyToOne User lastModifiedBy; + private Date lastModifiedDate; - @ManyToOne User owner; - - String lastModifiedByUsername; - - Date lastModifiedDate; - - public BusinessObject() {} + private final String data; + private final @ManyToOne User owner; public BusinessObject(String data, User owner) { this.data = data; this.owner = owner; } - - public Long getId() { - return id; - } - public void setId(Long id) { - this.id = id; - } - - public String getData() { - return data; - } - - public void setData(String data) { - this.data = data; - } - - public User getOwner() { - return owner; - } - - public void setOwner(User owner) { - this.owner = owner; - } - - public String getLastModifiedByUsername() { - return lastModifiedByUsername; - } - - public void setLastModifiedByUsername(String lastModifiedByUsername) { - this.lastModifiedByUsername = lastModifiedByUsername; - } - - public Date getLastModifiedDate() { - return lastModifiedDate; - } - - public void setLastModifiedDate(Date lastModifiedDate) { - this.lastModifiedDate = lastModifiedDate; - } - - @Override - public boolean equals(Object o) { - - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - BusinessObject that = (BusinessObject) o; - - if (data != null ? !data.equals(that.data) : that.data != null) - return false; - if (id != null ? !id.equals(that.id) : that.id != null) - return false; - if (owner != null ? !owner.equals(that.owner) : that.owner != null) - return false; - - return true; - } - - @Override - public int hashCode() { - - int result = id != null ? id.hashCode() : 0; - result = 31 * result + (data != null ? data.hashCode() : 0); - result = 31 * result + (owner != null ? owner.hashCode() : 0); - return result; + @SuppressWarnings("unused") + private BusinessObject() { + this.data = null; + this.owner = null; } } diff --git a/jpa/security/src/main/java/example/springdata/jpa/security/BusinessObjectRepository.java b/jpa/security/src/main/java/example/springdata/jpa/security/BusinessObjectRepository.java index a77f81fe..b9767d4c 100644 --- a/jpa/security/src/main/java/example/springdata/jpa/security/BusinessObjectRepository.java +++ b/jpa/security/src/main/java/example/springdata/jpa/security/BusinessObjectRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 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. @@ -21,7 +21,6 @@ import org.springframework.data.repository.CrudRepository; * Repository to manage {@link BusinessObject} instances. * * @author Thomas Darimont + * @author Oliver Gierke */ -public interface BusinessObjectRepository extends CrudRepository { - -} +interface BusinessObjectRepository extends CrudRepository {} diff --git a/jpa/security/src/main/java/example/springdata/jpa/security/SecureBusinessObjectRepository.java b/jpa/security/src/main/java/example/springdata/jpa/security/SecureBusinessObjectRepository.java index 20080c91..20102058 100644 --- a/jpa/security/src/main/java/example/springdata/jpa/security/SecureBusinessObjectRepository.java +++ b/jpa/security/src/main/java/example/springdata/jpa/security/SecureBusinessObjectRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 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. @@ -23,8 +23,9 @@ import org.springframework.data.repository.Repository; /** * @author Thomas Darimont + * @auhtor Oliver Gierke */ -public interface SecureBusinessObjectRepository extends Repository{ +interface SecureBusinessObjectRepository extends Repository { /** * Here we demonstrate the usage of SpEL expression within a custom query. @@ -44,7 +45,7 @@ public interface SecureBusinessObjectRepository extends Repository findBusinessObjectsForCurrentUser(); - + /** * Here we apply a dynamic filter condition in there query depending of the role of the current principal. * @@ -52,11 +53,11 @@ public interface SecureBusinessObjectRepository extends Repository findBusinessObjectsForCurrentUserById(); - + /** - * Here we demonstrate the use of SecurityContext information in dynamic SPEL parameters in a JPAQL update statement. + * Here we demonstrate the use of SecurityContext information in dynamic SpEL parameters in a JPQL update statement. */ @Modifying - @Query("update BusinessObject b set b.data = upper(b.data), b.lastModifiedByUsername = :#{#security.principal.firstname}, b.lastModifiedDate = :#{new java.util.Date()}") + @Query("update BusinessObject b set b.data = upper(b.data), b.lastModifiedBy = :#{#security.principal}, b.lastModifiedDate = :#{new java.util.Date()}") void modifiyDataWithRecordingSecurityContext(); } diff --git a/jpa/security/src/main/java/example/springdata/jpa/security/User.java b/jpa/security/src/main/java/example/springdata/jpa/security/User.java index 1f7fe393..dcd26438 100644 --- a/jpa/security/src/main/java/example/springdata/jpa/security/User.java +++ b/jpa/security/src/main/java/example/springdata/jpa/security/User.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 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. @@ -15,6 +15,10 @@ */ package example.springdata.jpa.security; +import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @@ -23,33 +27,18 @@ import javax.persistence.Id; * @author Thomas Darimont */ @Entity +@Data +@RequiredArgsConstructor public class User { - @Id @GeneratedValue Long id; + private @Id @GeneratedValue @Getter Long id; + private final String firstname, lastname, emailAddress; - String firstname; - String lastname; - String emailAddress; + @SuppressWarnings("unused") + private User() { - public User(String firstname, String lastname, String emailAddress) { - this.firstname = firstname; - this.lastname = lastname; - this.emailAddress = emailAddress; - } - - public Long getId() { - return id; - } - - public String getFirstname() { - return firstname; - } - - public String getLastname() { - return lastname; - } - - public String getEmailAddress() { - return emailAddress; + this.firstname = null; + this.lastname = null; + this.emailAddress = null; } } diff --git a/jpa/security/src/test/java/example/springdata/jpa/security/SecurityIntegrationTests.java b/jpa/security/src/test/java/example/springdata/jpa/security/SecurityIntegrationTests.java index 6b1f8c8a..dc906b72 100644 --- a/jpa/security/src/test/java/example/springdata/jpa/security/SecurityIntegrationTests.java +++ b/jpa/security/src/test/java/example/springdata/jpa/security/SecurityIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2015 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. @@ -50,32 +50,25 @@ public class SecurityIntegrationTests { @Autowired SecureBusinessObjectRepository secureBusinessObjectRepository; @Autowired EntityManager em; - User tom; - User olli; - User admin; - - UsernamePasswordAuthenticationToken olliAuth; - UsernamePasswordAuthenticationToken tomAuth; - UsernamePasswordAuthenticationToken adminAuth; - - BusinessObject object1; - BusinessObject object2; - BusinessObject object3; + User tom, ollie, admin; + UsernamePasswordAuthenticationToken olliAuth, tomAuth, adminAuth; + BusinessObject object1, object2, object3; @Before public void setup() { tom = userRepository.save(new User("thomas", "darimont", "tdarimont@example.org")); - olli = userRepository.save(new User("oliver", "gierke", "ogierke@example.org")); + ollie = userRepository.save(new User("oliver", "gierke", "ogierke@example.org")); admin = userRepository.save(new User("admin", "admin", "admin@example.org")); - object1 = businessObjectRepository.save(new BusinessObject("object1", olli)); - object2 = businessObjectRepository.save(new BusinessObject("object2", olli)); + object1 = businessObjectRepository.save(new BusinessObject("object1", ollie)); + object2 = businessObjectRepository.save(new BusinessObject("object2", ollie)); object3 = businessObjectRepository.save(new BusinessObject("object3", tom)); - - olliAuth = new UsernamePasswordAuthenticationToken(olli, "x"); + + olliAuth = new UsernamePasswordAuthenticationToken(ollie, "x"); tomAuth = new UsernamePasswordAuthenticationToken(tom, "x"); - adminAuth = new UsernamePasswordAuthenticationToken(admin, "x", singleton(new SimpleGrantedAuthority("ROLE_ADMIN"))); + adminAuth = new UsernamePasswordAuthenticationToken(admin, "x", + singleton(new SimpleGrantedAuthority("ROLE_ADMIN"))); } @Test @@ -88,7 +81,7 @@ public class SecurityIntegrationTests { assertThat(businessObjects, hasSize(1)); assertThat(businessObjects, contains(object3)); - SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(olli, "x")); + SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(ollie, "x")); businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUser(); @@ -135,23 +128,23 @@ public class SecurityIntegrationTests { assertThat(businessObjects, hasSize(3)); assertThat(businessObjects, contains(object1, object2, object3)); } - + @Test public void customUpdateStatementShouldAllowToUseSecurityContextInformationViaSpelParameters() { - + SecurityContextHolder.getContext().setAuthentication(adminAuth); - - //Detaching items to get them out of the query cache in order to see the updated values. - em.detach(object1); + + // Detaching items to get them out of the query cache in order to see the updated values. + em.detach(object1); em.detach(object2); em.detach(object3); - + secureBusinessObjectRepository.modifiyDataWithRecordingSecurityContext(); - - for(BusinessObject bo : businessObjectRepository.findAll()) { - + + for (BusinessObject bo : businessObjectRepository.findAll()) { + assertThat(bo.getLastModifiedDate(), is(notNullValue())); - assertThat(bo.getLastModifiedByUsername(), is("admin")); + assertThat(bo.getLastModifiedBy().getFirstname(), is("admin")); } } }