From d95ed268b29d44d8c58dcffec117f19176caa1d0 Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Sat, 20 Jun 2015 17:37:17 +0200 Subject: [PATCH] #107 - Added example for Spring Security Integration in MongoDB. Initial project and with example for dynamic data filtering based on current security context information. Relies on DATAMONGO-1244 to be resolved. Original pull request: #108. --- mongodb/pom.xml | 1 + mongodb/security/README.md | 18 ++++ mongodb/security/pom.xml | 39 ++++++++ .../people/ApplicationConfiguration.java | 41 +++++++++ .../springdata/mongodb/people/Person.java | 35 ++++++++ .../mongodb/people/PersonRepository.java | 34 +++++++ .../PersonRepositoryIntegrationTest.java | 90 +++++++++++++++++++ .../mongodb/people/package-info.java | 5 ++ 8 files changed, 263 insertions(+) create mode 100644 mongodb/security/README.md create mode 100644 mongodb/security/pom.xml create mode 100644 mongodb/security/src/main/java/example/springdata/mongodb/people/ApplicationConfiguration.java create mode 100644 mongodb/security/src/main/java/example/springdata/mongodb/people/Person.java create mode 100644 mongodb/security/src/main/java/example/springdata/mongodb/people/PersonRepository.java create mode 100644 mongodb/security/src/test/java/example/springdata/mongodb/people/PersonRepositoryIntegrationTest.java create mode 100644 mongodb/security/src/test/java/example/springdata/mongodb/people/package-info.java diff --git a/mongodb/pom.xml b/mongodb/pom.xml index 9ff92986..6f4523a8 100644 --- a/mongodb/pom.xml +++ b/mongodb/pom.xml @@ -21,6 +21,7 @@ example text-search java8 + security util geo-json diff --git a/mongodb/security/README.md b/mongodb/security/README.md new file mode 100644 index 00000000..cd0f58a9 --- /dev/null +++ b/mongodb/security/README.md @@ -0,0 +1,18 @@ +# Spring Data MongoDB - Spring Security integration. + +This project contains samples of the Spring Security integration in Spring Data (MongoDB). + +## Support for SpEL Expression based filtering + +```java +public interface PersonRepository extends CrudRepository { + + @Override + List findAll(); + + //Custom Query method with filtering based on Spring Security context information + @Query("{id: ?#{ hasRole('ROLE_ADMIN') ? {$exists:true} : principal.id}}") + List findAllForCurrentUserById(); +} +``` + diff --git a/mongodb/security/pom.xml b/mongodb/security/pom.xml new file mode 100644 index 00000000..cdde3c39 --- /dev/null +++ b/mongodb/security/pom.xml @@ -0,0 +1,39 @@ + + 4.0.0 + + + org.springframework.data.examples + spring-data-mongodb-examples + 1.0.0.BUILD-SNAPSHOT + + + spring-data-mongodb-security + Spring Data MongoDB - Spring Security Integration + + + + ${project.groupId} + spring-data-mongodb-utils + ${project.version} + test + + + + org.springframework.data + spring-data-mongodb + 1.8.0.DATAMONGO-1244-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.security + spring-security-data + + + + diff --git a/mongodb/security/src/main/java/example/springdata/mongodb/people/ApplicationConfiguration.java b/mongodb/security/src/main/java/example/springdata/mongodb/people/ApplicationConfiguration.java new file mode 100644 index 00000000..636ee011 --- /dev/null +++ b/mongodb/security/src/main/java/example/springdata/mongodb/people/ApplicationConfiguration.java @@ -0,0 +1,41 @@ +/* + * Copyright 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. + * 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 example.springdata.mongodb.people; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.data.mongodb.core.mapping.event.LoggingEventListener; +import org.springframework.data.repository.query.spi.EvaluationContextExtension; +import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; + +/** + * Simple configuration that registers a {@link LoggingEventListener} to demonstrate mapping behaviour when Java 8 + * Streams are used. + * + * @author Thomas Darimont + */ +@SpringBootApplication +class ApplicationConfiguration { + + public @Bean LoggingEventListener mongoEventListener() { + return new LoggingEventListener(); + } + + @Bean + public EvaluationContextExtension securityExtension() { + return new SecurityEvaluationContextExtension(); + } +} diff --git a/mongodb/security/src/main/java/example/springdata/mongodb/people/Person.java b/mongodb/security/src/main/java/example/springdata/mongodb/people/Person.java new file mode 100644 index 00000000..65003db0 --- /dev/null +++ b/mongodb/security/src/main/java/example/springdata/mongodb/people/Person.java @@ -0,0 +1,35 @@ +/* + * Copyright 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. + * 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 example.springdata.mongodb.people; + +import lombok.Data; +import lombok.RequiredArgsConstructor; + +import org.springframework.data.annotation.Id; + +/** + * An entity to represent a Person. + * + * @author Thomas Darimont + */ +@Data +@RequiredArgsConstructor +public class Person { + + private @Id String id; + private final String firstname; + private final String lastname; +} diff --git a/mongodb/security/src/main/java/example/springdata/mongodb/people/PersonRepository.java b/mongodb/security/src/main/java/example/springdata/mongodb/people/PersonRepository.java new file mode 100644 index 00000000..167f837d --- /dev/null +++ b/mongodb/security/src/main/java/example/springdata/mongodb/people/PersonRepository.java @@ -0,0 +1,34 @@ +/* + * Copyright 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. + * 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 example.springdata.mongodb.people; + +import java.util.List; + +import org.springframework.data.mongodb.repository.Query; +import org.springframework.data.repository.CrudRepository; + +/** + * Repository interface to manage {@link Person} instances. + * + * @author Thomas Darimont + */ +public interface PersonRepository extends CrudRepository { + + List findAll(); + + @Query("{id: ?#{ hasRole('ROLE_ADMIN') ? {$exists:true} : principal.id}}") + List findAllForCurrentUserById(); +} diff --git a/mongodb/security/src/test/java/example/springdata/mongodb/people/PersonRepositoryIntegrationTest.java b/mongodb/security/src/test/java/example/springdata/mongodb/people/PersonRepositoryIntegrationTest.java new file mode 100644 index 00000000..fdeb7c9d --- /dev/null +++ b/mongodb/security/src/test/java/example/springdata/mongodb/people/PersonRepositoryIntegrationTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 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. + * 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 example.springdata.mongodb.people; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; + +import java.util.Collections; +import java.util.List; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import example.springdata.mongodb.util.RequiresMongoDB; + +/** + * Integration test for {@link PersonRepository}. + * + * @author Thomas Darimont + * @authot Oliver Gierke + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = ApplicationConfiguration.class) +public class PersonRepositoryIntegrationTest { + + @ClassRule public static RequiresMongoDB mongodbAvailable = RequiresMongoDB.anyVersion(); + + @Autowired PersonRepository repository; + @Autowired MongoOperations operations; + + Person dave, oliver, carter, admin; + + @Before + public void setUp() { + + repository.deleteAll(); + + admin = repository.save(new Person("Admin", "Boss")); + dave = repository.save(new Person("Dave", "Matthews")); + oliver = repository.save(new Person("Oliver August", "Matthews")); + carter = repository.save(new Person("Carter", "Beauford")); + } + + @Test + public void nonAdminCallingShouldReturnOnlyItSelfAsPerson() throws Exception { + + SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(dave, "x")); + + List persons = repository.findAllForCurrentUserById(); + + assertThat(persons, hasSize(1)); + assertThat(persons, contains(dave)); + } + + @Test + public void adminCallingShouldReturnAllUsers() throws Exception { + + UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(admin, "x", + Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN"))); + SecurityContextHolder.getContext().setAuthentication(auth); + + List persons = repository.findAllForCurrentUserById(); + + assertThat(persons, hasSize(4)); + assertThat(persons, containsInAnyOrder(admin, dave, carter, oliver)); + } +} diff --git a/mongodb/security/src/test/java/example/springdata/mongodb/people/package-info.java b/mongodb/security/src/test/java/example/springdata/mongodb/people/package-info.java new file mode 100644 index 00000000..e4c4d5e2 --- /dev/null +++ b/mongodb/security/src/test/java/example/springdata/mongodb/people/package-info.java @@ -0,0 +1,5 @@ +/** + * Package showing usage of Spring Data MongoDB Repositories with Java 8. + */ +package example.springdata.mongodb.people; +