diff --git a/README.md b/README.md index b0a2367..34a713e 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ CSRF is enabled by default and the example jQuery AJAX calls pass the CSRF token An audit event and listener are implmented to allow for recording security events, or any type of event you like, and logging them to a seperate file. You can easily replace the logging listener with your own and store audit events in a database, publish them to a REST API, or anything else. +There is Role and Privilege setup service, which allows you to easily define Roles, associated Privileges, and Role inheritance hierachy in your application.yml. Check out the application.yml for the basic OOTB configuration, and look at the RolePrivilegeSetupService component. You can still create and leverage roles and privileges programatically, but this makes it easy to define and see the associations. + ## How To Get Started diff --git a/src/main/java/com/digitalsanctuary/spring/user/util/WebSecurityConfig.java b/src/main/java/com/digitalsanctuary/spring/user/util/WebSecurityConfig.java index a70936d..e5c2d75 100644 --- a/src/main/java/com/digitalsanctuary/spring/user/util/WebSecurityConfig.java +++ b/src/main/java/com/digitalsanctuary/spring/user/util/WebSecurityConfig.java @@ -2,13 +2,15 @@ import java.util.ArrayList; import java.util.Arrays; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.access.expression.SecurityExpressionHandler; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; @@ -21,13 +23,16 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; - +import org.springframework.security.web.FilterInvocation; +import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; +import org.springframework.security.web.session.HttpSessionEventPublisher; import com.digitalsanctuary.spring.user.service.LoginSuccessService; import com.digitalsanctuary.spring.user.service.LogoutSuccessService; - import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Data @EqualsAndHashCode(callSuper = false) @Configuration @@ -97,6 +102,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private LogoutSuccessService logoutSuccessService; + @Autowired + private RolesAndPrivilegesConfig rolesAndPrivilegesConfig; + @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { @@ -134,20 +142,18 @@ protected void configure(HttpSecurity http) throws Exception { disableCSRFURIs.removeAll(Arrays.asList("", null)); if (DEFAULT_ACTION_DENY.equals(getDefaultAction())) { - http.authorizeRequests().antMatchers(unprotectedURIs.toArray(new String[0])).permitAll().anyRequest() - .authenticated().and().formLogin().loginPage(loginPageURI).loginProcessingUrl(loginActionURI) - .successHandler(loginSuccessService).permitAll().and().logout().logoutUrl(logoutActionURI) - .invalidateHttpSession(true).logoutSuccessHandler(logoutSuccessService).deleteCookies("JSESSIONID") + http.authorizeRequests().antMatchers(unprotectedURIs.toArray(new String[0])).permitAll().anyRequest().authenticated().and().formLogin() + .loginPage(loginPageURI).loginProcessingUrl(loginActionURI).successHandler(loginSuccessService).permitAll().and().logout() + .logoutUrl(logoutActionURI).invalidateHttpSession(true).logoutSuccessHandler(logoutSuccessService).deleteCookies("JSESSIONID") .permitAll(); if (disableCSRFURIs != null && disableCSRFURIs.size() > 0) { http.csrf().ignoringAntMatchers(disableCSRFURIs.toArray(new String[0])); } } else if (DEFAULT_ACTION_ALLOW.equals(getDefaultAction())) { - http.authorizeRequests().antMatchers(protectedURIsArray).authenticated().antMatchers("/**").permitAll() - .and().formLogin().loginPage(loginPageURI).loginProcessingUrl(loginActionURI) - .successHandler(loginSuccessService).successHandler(loginSuccessService).and().logout() - .logoutUrl(logoutActionURI).invalidateHttpSession(true).logoutSuccessHandler(logoutSuccessService) - .deleteCookies("JSESSIONID").permitAll(); + http.authorizeRequests().antMatchers(protectedURIsArray).authenticated().antMatchers("/**").permitAll().and().formLogin() + .loginPage(loginPageURI).loginProcessingUrl(loginActionURI).successHandler(loginSuccessService) + .successHandler(loginSuccessService).and().logout().logoutUrl(logoutActionURI).invalidateHttpSession(true) + .logoutSuccessHandler(logoutSuccessService).deleteCookies("JSESSIONID").permitAll(); if (disableCSRFURIs != null && disableCSRFURIs.size() > 0) { http.csrf().ignoringAntMatchers(disableCSRFURIs.toArray(new String[0])); @@ -178,4 +184,25 @@ public PasswordEncoder encoder() { public SessionRegistry sessionRegistry() { return new SessionRegistryImpl(); } -} \ No newline at end of file + + @Bean + public RoleHierarchy roleHierarchy() { + RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); + roleHierarchy.setHierarchy(rolesAndPrivilegesConfig.getRoleHierarchyString()); + log.debug("WebSecurityConfig.roleHierarchy:" + "roleHierarchy: {}", roleHierarchy.toString()); + return roleHierarchy; + } + + @Bean + public SecurityExpressionHandler webExpressionHandler() { + DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler(); + defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy()); + return defaultWebSecurityExpressionHandler; + } + + @Bean + public HttpSessionEventPublisher httpSessionEventPublisher() { + return new HttpSessionEventPublisher(); + } + +}