diff --git a/spring-security-custom-permission/.classpath b/spring-security-custom-permission/.classpath
new file mode 100644
index 0000000000..0cad5db2d0
--- /dev/null
+++ b/spring-security-custom-permission/.classpath
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-security-custom-permission/.project b/spring-security-custom-permission/.project
new file mode 100644
index 0000000000..06b5975e98
--- /dev/null
+++ b/spring-security-custom-permission/.project
@@ -0,0 +1,48 @@
+
+
+ spring-security-custom-permission
+
+
+
+
+
+ org.eclipse.wst.jsdt.core.javascriptValidator
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.wst.common.project.facet.core.builder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+ org.springframework.ide.eclipse.core.springbuilder
+
+
+
+
+ org.eclipse.wst.validation.validationbuilder
+
+
+
+
+
+ org.eclipse.jem.workbench.JavaEMFNature
+ org.eclipse.wst.common.modulecore.ModuleCoreNature
+ org.springframework.ide.eclipse.core.springnature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+ org.eclipse.wst.common.project.facet.core.nature
+ org.eclipse.wst.jsdt.core.jsNature
+
+
diff --git a/spring-security-custom-permission/pom.xml b/spring-security-custom-permission/pom.xml
new file mode 100644
index 0000000000..6f460f1751
--- /dev/null
+++ b/spring-security-custom-permission/pom.xml
@@ -0,0 +1,107 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ spring-security-custom-permission
+ 0.0.1-SNAPSHOT
+ war
+
+ spring-security-custom-permission
+ Spring Security custom permission
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.3.3.RELEASE
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+ provided
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+
+ org.thymeleaf.extras
+ thymeleaf-extras-springsecurity4
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+ com.h2database
+ h2
+
+
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.hamcrest
+ hamcrest-core
+ test
+
+
+
+ org.hamcrest
+ hamcrest-library
+ test
+
+
+
+ com.jayway.restassured
+ rest-assured
+ ${rest-assured.version}
+ test
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+ UTF-8
+ 1.8
+ 2.4.0
+
+
+
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/Application.java b/spring-security-custom-permission/src/main/java/org/baeldung/Application.java
new file mode 100644
index 0000000000..a9d6f3b8b1
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/Application.java
@@ -0,0 +1,12 @@
+package org.baeldung;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/config/MethodSecurityConfig.java b/spring-security-custom-permission/src/main/java/org/baeldung/config/MethodSecurityConfig.java
new file mode 100644
index 0000000000..c4624e85e0
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/config/MethodSecurityConfig.java
@@ -0,0 +1,21 @@
+package org.baeldung.config;
+
+import org.baeldung.security.CustomMethodSecurityExpressionHandler;
+import org.baeldung.security.CustomPermissionEvaluator;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
+
+@Configuration
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
+
+ @Override
+ protected MethodSecurityExpressionHandler createExpressionHandler() {
+ // final DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
+ final CustomMethodSecurityExpressionHandler expressionHandler = new CustomMethodSecurityExpressionHandler();
+ expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
+ return expressionHandler;
+ }
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/config/MvcConfig.java b/spring-security-custom-permission/src/main/java/org/baeldung/config/MvcConfig.java
new file mode 100644
index 0000000000..9ade60e54c
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/config/MvcConfig.java
@@ -0,0 +1,42 @@
+package org.baeldung.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
+import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+@Configuration
+@EnableWebMvc
+public class MvcConfig extends WebMvcConfigurerAdapter {
+
+ public MvcConfig() {
+ super();
+ }
+
+ //
+ @Bean
+ public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
+ return new PropertySourcesPlaceholderConfigurer();
+ }
+
+ @Override
+ public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
+ configurer.enable();
+ }
+
+ @Override
+ public void addViewControllers(final ViewControllerRegistry registry) {
+ super.addViewControllers(registry);
+ registry.addViewController("/").setViewName("forward:/index");
+ registry.addViewController("/index");
+ }
+
+ @Override
+ public void addResourceHandlers(final ResourceHandlerRegistry registry) {
+ registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
+ }
+}
\ No newline at end of file
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/config/SecurityConfig.java b/spring-security-custom-permission/src/main/java/org/baeldung/config/SecurityConfig.java
new file mode 100644
index 0000000000..b365744bea
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/config/SecurityConfig.java
@@ -0,0 +1,43 @@
+package org.baeldung.config;
+
+import org.baeldung.security.MyUserDetailsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableWebSecurity
+@ComponentScan("org.baeldung.security")
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Autowired
+ private MyUserDetailsService userDetailsService;
+
+ @Override
+ protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
+ auth.userDetailsService(userDetailsService);
+ }
+
+ @Override
+ public void configure(WebSecurity web) throws Exception {
+ web.ignoring().antMatchers("/resources/**");
+ }
+
+ @Override
+ protected void configure(final HttpSecurity http) throws Exception {
+ // @formatter:off
+ http.authorizeRequests()
+ .antMatchers("/login").permitAll()
+ .antMatchers("/admin").hasRole("ADMIN")
+ .anyRequest().authenticated()
+ .and().formLogin().permitAll()
+ .and().csrf().disable();
+ ;
+ // @formatter:on
+ }
+}
\ No newline at end of file
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/SetupData.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/SetupData.java
new file mode 100644
index 0000000000..fa6d4c42ee
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/SetupData.java
@@ -0,0 +1,89 @@
+package org.baeldung.persistence;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+import javax.annotation.PostConstruct;
+
+import org.baeldung.persistence.dao.OrganizationRepository;
+import org.baeldung.persistence.dao.PrivilegeRepository;
+import org.baeldung.persistence.dao.RoleRepository;
+import org.baeldung.persistence.dao.UserRepository;
+import org.baeldung.persistence.model.Organization;
+import org.baeldung.persistence.model.Privilege;
+import org.baeldung.persistence.model.Role;
+import org.baeldung.persistence.model.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SetupData {
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private RoleRepository roleRepository;
+
+ @Autowired
+ private PrivilegeRepository privilegeRepository;
+
+ @Autowired
+ private OrganizationRepository organizationRepository;
+
+ @PostConstruct
+ public void init() {
+ initPrivileges();
+ initRoles();
+ initOrganizations();
+ initUsers();
+ }
+
+ private void initUsers() {
+ final Role role1 = roleRepository.findByName("USER_ROLE");
+ final Role role2 = roleRepository.findByName("ADMIN_ROLE");
+ //
+ final User user1 = new User();
+ user1.setUsername("john");
+ user1.setPassword("123");
+ user1.setRoles(new HashSet(Arrays.asList(role1)));
+ user1.setOrganization(organizationRepository.findByName("FirstOrg"));
+ userRepository.save(user1);
+ //
+ final User user2 = new User();
+ user2.setUsername("tom");
+ user2.setPassword("111");
+ user2.setRoles(new HashSet(Arrays.asList(role2)));
+ user2.setOrganization(organizationRepository.findByName("SecondOrg"));
+ userRepository.save(user2);
+ }
+
+ private void initOrganizations() {
+ final Organization org1 = new Organization("FirstOrg");
+ organizationRepository.save(org1);
+ //
+ final Organization org2 = new Organization("SecondOrg");
+ organizationRepository.save(org2);
+
+ }
+
+ private void initRoles() {
+ final Privilege privilege1 = privilegeRepository.findByName("FOO_READ_PRIVILEGE");
+ final Privilege privilege2 = privilegeRepository.findByName("FOO_WRITE_PRIVILEGE");
+ //
+ final Role role1 = new Role("USER_ROLE");
+ role1.setPrivileges(new HashSet(Arrays.asList(privilege1)));
+ roleRepository.save(role1);
+ //
+ final Role role2 = new Role("ADMIN_ROLE");
+ role2.setPrivileges(new HashSet(Arrays.asList(privilege1, privilege2)));
+ roleRepository.save(role2);
+ }
+
+ private void initPrivileges() {
+ final Privilege privilege1 = new Privilege("FOO_READ_PRIVILEGE");
+ privilegeRepository.save(privilege1);
+ //
+ final Privilege privilege2 = new Privilege("FOO_WRITE_PRIVILEGE");
+ privilegeRepository.save(privilege2);
+ }
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/OrganizationRepository.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/OrganizationRepository.java
new file mode 100644
index 0000000000..a20d24057b
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/OrganizationRepository.java
@@ -0,0 +1,10 @@
+package org.baeldung.persistence.dao;
+
+import org.baeldung.persistence.model.Organization;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface OrganizationRepository extends JpaRepository {
+
+ public Organization findByName(String name);
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/PrivilegeRepository.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/PrivilegeRepository.java
new file mode 100644
index 0000000000..edf9002c3d
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/PrivilegeRepository.java
@@ -0,0 +1,10 @@
+package org.baeldung.persistence.dao;
+
+import org.baeldung.persistence.model.Privilege;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface PrivilegeRepository extends JpaRepository {
+
+ public Privilege findByName(String name);
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/RoleRepository.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/RoleRepository.java
new file mode 100644
index 0000000000..408720fe9c
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/RoleRepository.java
@@ -0,0 +1,9 @@
+package org.baeldung.persistence.dao;
+
+import org.baeldung.persistence.model.Role;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface RoleRepository extends JpaRepository {
+ public Role findByName(String name);
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/UserRepository.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/UserRepository.java
new file mode 100644
index 0000000000..679dd6c363
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/dao/UserRepository.java
@@ -0,0 +1,10 @@
+package org.baeldung.persistence.dao;
+
+import org.baeldung.persistence.model.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface UserRepository extends JpaRepository {
+
+ User findByUsername(final String username);
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Foo.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Foo.java
new file mode 100644
index 0000000000..29c19cf22e
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Foo.java
@@ -0,0 +1,94 @@
+package org.baeldung.persistence.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Foo {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+
+ @Column(nullable = false)
+ private String name;
+
+ //
+
+ public Foo() {
+ super();
+ }
+
+ public Foo(String name) {
+ super();
+ this.name = name;
+ }
+
+ //
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ //
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Foo [id=").append(id).append(", name=").append(name).append("]");
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((id == null) ? 0 : id.hashCode());
+ result = (prime * result) + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Foo other = (Foo) obj;
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Organization.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Organization.java
new file mode 100644
index 0000000000..645285b5e9
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Organization.java
@@ -0,0 +1,95 @@
+package org.baeldung.persistence.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Organization {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+
+ @Column(nullable = false, unique = true)
+ private String name;
+
+ //
+
+ public Organization() {
+ super();
+ }
+
+ public Organization(String name) {
+ super();
+ this.name = name;
+ }
+
+ //
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ //
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Organization [id=").append(id).append(", name=").append(name).append("]");
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((id == null) ? 0 : id.hashCode());
+ result = (prime * result) + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Organization other = (Organization) obj;
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Privilege.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Privilege.java
new file mode 100644
index 0000000000..ff3ae62c25
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Privilege.java
@@ -0,0 +1,95 @@
+package org.baeldung.persistence.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Privilege {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+
+ @Column(nullable = false, unique = true)
+ private String name;
+
+ //
+
+ public Privilege() {
+ super();
+ }
+
+ public Privilege(String name) {
+ super();
+ this.name = name;
+ }
+
+ //
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ //
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Privilege [id=").append(id).append(", name=").append(name).append("]");
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((id == null) ? 0 : id.hashCode());
+ result = (prime * result) + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Privilege other = (Privilege) obj;
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Role.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Role.java
new file mode 100644
index 0000000000..f4589315b9
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/Role.java
@@ -0,0 +1,121 @@
+package org.baeldung.persistence.model;
+
+import java.util.Set;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+
+@Entity
+public class Role {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+
+ @Column(nullable = false, unique = true)
+ private String name;
+
+ @ManyToMany(fetch = FetchType.EAGER)
+ @JoinTable(name = "roles_privileges", joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "privilege_id", referencedColumnName = "id"))
+ private Set privileges;
+
+ //
+
+ public Role() {
+ super();
+ }
+
+ public Role(String name) {
+ super();
+ this.name = name;
+ }
+
+ //
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getPrivileges() {
+ return privileges;
+ }
+
+ public void setPrivileges(Set privileges) {
+ this.privileges = privileges;
+ }
+
+ //
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Role [id=").append(id).append(", name=").append(name).append(", privileges=").append(privileges).append("]");
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((id == null) ? 0 : id.hashCode());
+ result = (prime * result) + ((name == null) ? 0 : name.hashCode());
+ result = (prime * result) + ((privileges == null) ? 0 : privileges.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Role other = (Role) obj;
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ if (privileges == null) {
+ if (other.privileges != null) {
+ return false;
+ }
+ } else if (!privileges.equals(other.privileges)) {
+ return false;
+ }
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/User.java b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/User.java
new file mode 100644
index 0000000000..995c62d08f
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/persistence/model/User.java
@@ -0,0 +1,198 @@
+package org.baeldung.persistence.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+@Entity
+public class User implements UserDetails {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+
+ @Column(nullable = false, unique = true)
+ private String username;
+
+ private String password;
+
+ @ManyToMany(fetch = FetchType.EAGER)
+ @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
+ private Set roles;
+
+ @ManyToOne(fetch = FetchType.EAGER)
+ @JoinColumn(name = "organization_id", referencedColumnName = "id")
+ private Organization organization;
+
+ //
+
+ public User() {
+ super();
+ }
+
+ //
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ @Override
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ @Override
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public Set getRoles() {
+ return roles;
+ }
+
+ public void setRoles(Set roles) {
+ this.roles = roles;
+ }
+
+ public Organization getOrganization() {
+ return organization;
+ }
+
+ public void setOrganization(Organization organization) {
+ this.organization = organization;
+ }
+
+ //
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("User [id=").append(id).append(", username=").append(username).append(", password=").append(password).append(", roles=").append(roles).append(", organization=").append(organization).append("]");
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + ((id == null) ? 0 : id.hashCode());
+ result = (prime * result) + ((organization == null) ? 0 : organization.hashCode());
+ result = (prime * result) + ((password == null) ? 0 : password.hashCode());
+ result = (prime * result) + ((roles == null) ? 0 : roles.hashCode());
+ result = (prime * result) + ((username == null) ? 0 : username.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final User other = (User) obj;
+ if (id == null) {
+ if (other.id != null) {
+ return false;
+ }
+ } else if (!id.equals(other.id)) {
+ return false;
+ }
+ if (organization == null) {
+ if (other.organization != null) {
+ return false;
+ }
+ } else if (!organization.equals(other.organization)) {
+ return false;
+ }
+ if (password == null) {
+ if (other.password != null) {
+ return false;
+ }
+ } else if (!password.equals(other.password)) {
+ return false;
+ }
+ if (roles == null) {
+ if (other.roles != null) {
+ return false;
+ }
+ } else if (!roles.equals(other.roles)) {
+ return false;
+ }
+ if (username == null) {
+ if (other.username != null) {
+ return false;
+ }
+ } else if (!username.equals(other.username)) {
+ return false;
+ }
+ return true;
+ }
+
+ //
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ final List authorities = new ArrayList();
+ for (final Role role : this.getRoles()) {
+ for (final Privilege privilege : role.getPrivileges()) {
+ authorities.add(new SimpleGrantedAuthority(privilege.getName()));
+ }
+ }
+ return authorities;
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/security/CustomMethodSecurityExpressionHandler.java b/spring-security-custom-permission/src/main/java/org/baeldung/security/CustomMethodSecurityExpressionHandler.java
new file mode 100644
index 0000000000..e040a0b109
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/security/CustomMethodSecurityExpressionHandler.java
@@ -0,0 +1,22 @@
+package org.baeldung.security;
+
+import org.aopalliance.intercept.MethodInvocation;
+import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
+import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
+import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
+import org.springframework.security.core.Authentication;
+
+public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
+ private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+
+ @Override
+ protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
+ // final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
+ final MySecurityExpressionRoot root = new MySecurityExpressionRoot(authentication);
+ root.setPermissionEvaluator(getPermissionEvaluator());
+ root.setTrustResolver(this.trustResolver);
+ root.setRoleHierarchy(getRoleHierarchy());
+ return root;
+ }
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/security/CustomMethodSecurityExpressionRoot.java b/spring-security-custom-permission/src/main/java/org/baeldung/security/CustomMethodSecurityExpressionRoot.java
new file mode 100644
index 0000000000..a3f4644592
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/security/CustomMethodSecurityExpressionRoot.java
@@ -0,0 +1,50 @@
+package org.baeldung.security;
+
+import org.baeldung.persistence.model.User;
+import org.springframework.security.access.expression.SecurityExpressionRoot;
+import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
+import org.springframework.security.core.Authentication;
+
+public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
+
+ private Object filterObject;
+ private Object returnObject;
+
+ public CustomMethodSecurityExpressionRoot(Authentication authentication) {
+ super(authentication);
+ }
+
+ //
+ public boolean isMember(Long OrganizationId) {
+ final User user = (User) this.getPrincipal();
+ return user.getOrganization().getId().longValue() == OrganizationId.longValue();
+ }
+
+ //
+
+ @Override
+ public Object getFilterObject() {
+ return this.filterObject;
+ }
+
+ @Override
+ public Object getReturnObject() {
+ return this.returnObject;
+ }
+
+ @Override
+ public Object getThis() {
+ return this;
+ }
+
+ @Override
+ public void setFilterObject(Object obj) {
+ this.filterObject = obj;
+ }
+
+ @Override
+ public void setReturnObject(Object obj) {
+ this.returnObject = obj;
+ }
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/security/CustomPermissionEvaluator.java b/spring-security-custom-permission/src/main/java/org/baeldung/security/CustomPermissionEvaluator.java
new file mode 100644
index 0000000000..e81f9f8939
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/security/CustomPermissionEvaluator.java
@@ -0,0 +1,47 @@
+package org.baeldung.security;
+
+import java.io.Serializable;
+
+import org.springframework.security.access.PermissionEvaluator;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+
+public class CustomPermissionEvaluator implements PermissionEvaluator {
+
+ @Override
+ public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) {
+ System.out.println(auth);
+ if ((auth == null) || (targetDomainObject == null) || !(permission instanceof String)) {
+ return false;
+ }
+ String targetType = "";
+ if (targetDomainObject instanceof String) {
+ targetType = targetDomainObject.toString().toUpperCase();
+ } else {
+ targetType = targetDomainObject.getClass().getSimpleName().toUpperCase();
+ System.out.println(targetType);
+ }
+ return hasPrivilege(auth, targetType, permission.toString().toUpperCase());
+ }
+
+ @Override
+ public boolean hasPermission(Authentication auth, Serializable targetId, String targetType, Object permission) {
+ if ((auth == null) || (targetType == null) || !(permission instanceof String)) {
+ return false;
+ }
+ return hasPrivilege(auth, targetType.toUpperCase(), permission.toString().toUpperCase());
+ }
+
+ private boolean hasPrivilege(Authentication auth, String targetType, String permission) {
+ for (final GrantedAuthority grantedAuth : auth.getAuthorities()) {
+ System.out.println("here " + grantedAuth);
+ if (grantedAuth.getAuthority().startsWith(targetType)) {
+ if (grantedAuth.getAuthority().contains(permission)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/security/MySecurityExpressionRoot.java b/spring-security-custom-permission/src/main/java/org/baeldung/security/MySecurityExpressionRoot.java
new file mode 100644
index 0000000000..a09d166798
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/security/MySecurityExpressionRoot.java
@@ -0,0 +1,203 @@
+package org.baeldung.security;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.baeldung.persistence.model.User;
+import org.springframework.security.access.PermissionEvaluator;
+import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
+import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+
+public class MySecurityExpressionRoot implements MethodSecurityExpressionOperations {
+ protected final Authentication authentication;
+ private AuthenticationTrustResolver trustResolver;
+ private RoleHierarchy roleHierarchy;
+ private Set roles;
+ private String defaultRolePrefix = "ROLE_";
+
+ public final boolean permitAll = true;
+ public final boolean denyAll = false;
+ private PermissionEvaluator permissionEvaluator;
+ public final String read = "read";
+ public final String write = "write";
+ public final String create = "create";
+ public final String delete = "delete";
+ public final String admin = "administration";
+
+ //
+
+ private Object filterObject;
+ private Object returnObject;
+
+ public MySecurityExpressionRoot(Authentication authentication) {
+ if (authentication == null) {
+ throw new IllegalArgumentException("Authentication object cannot be null");
+ }
+ this.authentication = authentication;
+ }
+
+ @Override
+ public final boolean hasAuthority(String authority) {
+ throw new RuntimeException("method hasAuthority() not allowed");
+ }
+
+ @Override
+ public final boolean hasAnyAuthority(String... authorities) {
+ return hasAnyAuthorityName(null, authorities);
+ }
+
+ @Override
+ public final boolean hasRole(String role) {
+ return hasAnyRole(role);
+ }
+
+ @Override
+ public final boolean hasAnyRole(String... roles) {
+ return hasAnyAuthorityName(defaultRolePrefix, roles);
+ }
+
+ private boolean hasAnyAuthorityName(String prefix, String... roles) {
+ final Set roleSet = getAuthoritySet();
+
+ for (final String role : roles) {
+ final String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
+ if (roleSet.contains(defaultedRole)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public final Authentication getAuthentication() {
+ return authentication;
+ }
+
+ @Override
+ public final boolean permitAll() {
+ return true;
+ }
+
+ @Override
+ public final boolean denyAll() {
+ return false;
+ }
+
+ @Override
+ public final boolean isAnonymous() {
+ return trustResolver.isAnonymous(authentication);
+ }
+
+ @Override
+ public final boolean isAuthenticated() {
+ return !isAnonymous();
+ }
+
+ @Override
+ public final boolean isRememberMe() {
+ return trustResolver.isRememberMe(authentication);
+ }
+
+ @Override
+ public final boolean isFullyAuthenticated() {
+ return !trustResolver.isAnonymous(authentication) && !trustResolver.isRememberMe(authentication);
+ }
+
+ public Object getPrincipal() {
+ return authentication.getPrincipal();
+ }
+
+ public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
+ this.trustResolver = trustResolver;
+ }
+
+ public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
+ this.roleHierarchy = roleHierarchy;
+ }
+
+ public void setDefaultRolePrefix(String defaultRolePrefix) {
+ this.defaultRolePrefix = defaultRolePrefix;
+ }
+
+ private Set getAuthoritySet() {
+ if (roles == null) {
+ roles = new HashSet();
+ Collection extends GrantedAuthority> userAuthorities = authentication.getAuthorities();
+
+ if (roleHierarchy != null) {
+ userAuthorities = roleHierarchy.getReachableGrantedAuthorities(userAuthorities);
+ }
+
+ roles = AuthorityUtils.authorityListToSet(userAuthorities);
+ }
+
+ return roles;
+ }
+
+ @Override
+ public boolean hasPermission(Object target, Object permission) {
+ return permissionEvaluator.hasPermission(authentication, target, permission);
+ }
+
+ @Override
+ public boolean hasPermission(Object targetId, String targetType, Object permission) {
+ return permissionEvaluator.hasPermission(authentication, (Serializable) targetId, targetType, permission);
+ }
+
+ public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) {
+ this.permissionEvaluator = permissionEvaluator;
+ }
+
+ private static String getRoleWithDefaultPrefix(String defaultRolePrefix, String role) {
+ if (role == null) {
+ return role;
+ }
+ if ((defaultRolePrefix == null) || (defaultRolePrefix.length() == 0)) {
+ return role;
+ }
+ if (role.startsWith(defaultRolePrefix)) {
+ return role;
+ }
+ return defaultRolePrefix + role;
+ }
+
+ //
+ public boolean isMember(Long OrganizationId) {
+ final User user = (User) this.getPrincipal();
+ return user.getOrganization().getId().longValue() == OrganizationId.longValue();
+ }
+
+ //
+
+ @Override
+ public Object getFilterObject() {
+ return this.filterObject;
+ }
+
+ @Override
+ public Object getReturnObject() {
+ return this.returnObject;
+ }
+
+ @Override
+ public Object getThis() {
+ return this;
+ }
+
+ @Override
+ public void setFilterObject(Object obj) {
+ this.filterObject = obj;
+ }
+
+ @Override
+ public void setReturnObject(Object obj) {
+ this.returnObject = obj;
+ }
+}
\ No newline at end of file
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/security/MyUserDetailsService.java b/spring-security-custom-permission/src/main/java/org/baeldung/security/MyUserDetailsService.java
new file mode 100644
index 0000000000..19276a906e
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/security/MyUserDetailsService.java
@@ -0,0 +1,31 @@
+package org.baeldung.security;
+
+import org.baeldung.persistence.dao.UserRepository;
+import org.baeldung.persistence.model.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MyUserDetailsService implements UserDetailsService {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ public MyUserDetailsService() {
+ super();
+ }
+
+ // API
+
+ @Override
+ public UserDetails loadUserByUsername(final String username) {
+ final User user = userRepository.findByUsername(username);
+ if (user == null) {
+ throw new UsernameNotFoundException(username);
+ }
+ return user;
+ }
+}
diff --git a/spring-security-custom-permission/src/main/java/org/baeldung/web/MainController.java b/spring-security-custom-permission/src/main/java/org/baeldung/web/MainController.java
new file mode 100644
index 0000000000..7e279907c6
--- /dev/null
+++ b/spring-security-custom-permission/src/main/java/org/baeldung/web/MainController.java
@@ -0,0 +1,57 @@
+package org.baeldung.web;
+
+import org.baeldung.persistence.dao.OrganizationRepository;
+import org.baeldung.persistence.model.Foo;
+import org.baeldung.persistence.model.Organization;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+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.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@Controller
+public class MainController {
+
+ @Autowired
+ private OrganizationRepository organizationRepository;
+
+ @PreAuthorize("hasPermission('Foo', 'read')")
+ @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}")
+ @ResponseBody
+ public Foo findById(@PathVariable final long id) {
+ return new Foo("Sample");
+ }
+
+ @PreAuthorize("hasPermission(#foo, 'write')")
+ @RequestMapping(method = RequestMethod.POST, value = "/foos")
+ @ResponseStatus(HttpStatus.CREATED)
+ @ResponseBody
+ public Foo create(@RequestBody final Foo foo) {
+ return foo;
+ }
+
+ //
+
+ @PreAuthorize("hasAuthority('FOO_READ_PRIVILEGE')")
+ @RequestMapping(method = RequestMethod.GET, value = "/foos")
+ @ResponseBody
+ public Foo findFooByName(@RequestParam final String name) {
+ return new Foo(name);
+ }
+
+ //
+
+ @PreAuthorize("isMember(#id)")
+ @RequestMapping(method = RequestMethod.GET, value = "/organizations/{id}")
+ @ResponseBody
+ public Organization findOrgById(@PathVariable final long id) {
+ return organizationRepository.findOne(id);
+ }
+
+}
diff --git a/spring-security-custom-permission/src/main/resources/application.properties b/spring-security-custom-permission/src/main/resources/application.properties
new file mode 100644
index 0000000000..0b40f62fa9
--- /dev/null
+++ b/spring-security-custom-permission/src/main/resources/application.properties
@@ -0,0 +1,9 @@
+server.port=8081
+spring.datasource.driver-class-name=org.h2.Driver
+spring.datasource.url=jdbc:h2:mem:security_permission;DB_CLOSE_DELAY=-1
+spring.datasource.username=sa
+spring.datasource.password=
+spring.jpa.hibernate.ddl-auto=create-drop
+spring.jpa.database=H2
+spring.jpa.show-sql=false
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/spring-security-custom-permission/src/main/resources/templates/index.html b/spring-security-custom-permission/src/main/resources/templates/index.html
new file mode 100644
index 0000000000..8e7394ad6a
--- /dev/null
+++ b/spring-security-custom-permission/src/main/resources/templates/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+Spring Security Thymeleaf
+
+
+
+
+
+
+ Welcome
+
+
+
\ No newline at end of file
diff --git a/spring-security-custom-permission/src/test/java/org/baeldung/web/LiveTest.java b/spring-security-custom-permission/src/test/java/org/baeldung/web/LiveTest.java
new file mode 100644
index 0000000000..80b1390083
--- /dev/null
+++ b/spring-security-custom-permission/src/test/java/org/baeldung/web/LiveTest.java
@@ -0,0 +1,67 @@
+package org.baeldung.web;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.baeldung.persistence.model.Foo;
+import org.junit.Test;
+import org.springframework.http.MediaType;
+
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.authentication.FormAuthConfig;
+import com.jayway.restassured.response.Response;
+import com.jayway.restassured.specification.RequestSpecification;
+
+public class LiveTest {
+
+ private final FormAuthConfig formAuthConfig = new FormAuthConfig("http://localhost:8081/login", "username", "password");
+
+ @Test
+ public void givenUserWithReadPrivilegeAndHasPermission_whenGetFooById_thenOK() {
+ final Response response = givenAuth("john", "123").get("http://localhost:8081/foos/1");
+ assertEquals(200, response.getStatusCode());
+ assertTrue(response.asString().contains("id"));
+ }
+
+ @Test
+ public void givenUserWithNoWritePrivilegeAndHasPermission_whenPostFoo_thenForbidden() {
+ final Response response = givenAuth("john", "123").contentType(MediaType.APPLICATION_JSON_VALUE).body(new Foo("sample")).post("http://localhost:8081/foos");
+ assertEquals(403, response.getStatusCode());
+ }
+
+ @Test
+ public void givenUserWithWritePrivilegeAndHasPermission_whenPostFoo_thenOk() {
+ final Response response = givenAuth("tom", "111").contentType(MediaType.APPLICATION_JSON_VALUE).body(new Foo("sample")).post("http://localhost:8081/foos");
+ assertEquals(201, response.getStatusCode());
+ assertTrue(response.asString().contains("id"));
+ }
+
+ //
+
+ @Test
+ public void givenUserMemberInOrganization_whenGetOrganization_thenOK() {
+ final Response response = givenAuth("john", "123").get("http://localhost:8081/organizations/1");
+ assertEquals(200, response.getStatusCode());
+ assertTrue(response.asString().contains("id"));
+ }
+
+ @Test
+ public void givenUserMemberNotInOrganization_whenGetOrganization_thenForbidden() {
+ final Response response = givenAuth("john", "123").get("http://localhost:8081/organizations/2");
+ assertEquals(403, response.getStatusCode());
+ }
+
+ //
+
+ @Test
+ public void givenDisabledSecurityExpression_whenGetFooByName_thenError() {
+ final Response response = givenAuth("john", "123").get("http://localhost:8081/foos?name=sample");
+ assertEquals(500, response.getStatusCode());
+ assertTrue(response.asString().contains("method hasAuthority() not allowed"));
+ }
+
+ //
+ private RequestSpecification givenAuth(String username, String password) {
+ return RestAssured.given().auth().form(username, password, formAuthConfig);
+ }
+}
\ No newline at end of file