User Tools
Writing /app/www/public/data/meta/toolsandtechnologies/spring-security.meta failed
toolsandtechnologies:spring-security
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| toolsandtechnologies:spring-security [2017/08/04 12:12] – mzubal | toolsandtechnologies:spring-security [2021/06/25 10:09] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Spring Security ====== | ||
| + | The spring-security is a project, which solves Authentication/ | ||
| + | |||
| + | ===== Use in Errigal projects ===== | ||
| + | At the time of writing this, the most ' | ||
| + | |||
| + | ===== Setting up authentication ===== | ||
| + | The authentication (and all the other security things) are set-up in the [[https:// | ||
| + | <code groovy> | ||
| + | @Override | ||
| + | protected void configure(AuthenticationManagerBuilder auth) throws Exception { | ||
| + | if (casEnabled) { | ||
| + | auth.authenticationProvider(casAuthenticationProvider()) | ||
| + | } else { | ||
| + | auth.authenticationProvider(localAuthenticationProvider()) | ||
| + | } | ||
| + | } | ||
| + | |||
| + | AuthenticationProvider localAuthenticationProvider() { | ||
| + | DaoAuthenticationProvider provider = new DaoAuthenticationProvider() | ||
| + | provider.setUserDetailsService(authenticationUserDetailsService) | ||
| + | provider.setPasswordEncoder(passwordEncoder) | ||
| + | return provider | ||
| + | } | ||
| + | |||
| + | AuthenticationProvider casAuthenticationProvider() { | ||
| + | CasAuthenticationProvider provider = new CasAuthenticationProvider() | ||
| + | provider.setAuthenticationUserDetailsService(authenticationUserDetailsService) | ||
| + | provider.setServiceProperties(serviceProperties()) | ||
| + | provider.setTicketValidator(new Cas20ServiceTicketValidator(urlPrefix)) | ||
| + | provider.setKey(' | ||
| + | return provider | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Securing Resources ===== | ||
| + | Once the authentication is set-up, we can start enforcing certain authorisations for our code. There are several ways of doing that. | ||
| + | |||
| + | ==== Securing URLs ==== | ||
| + | This can be done in the already mentioned [[https:// | ||
| + | <code groovy> | ||
| + | @Override | ||
| + | protected void configure(HttpSecurity http) throws Exception { | ||
| + | if (casEnabled) { | ||
| + | http.exceptionHandling() | ||
| + | .authenticationEntryPoint(casAuthenticationEntryPoint()).and().addFilter(casAuthenticationFilter()) | ||
| + | .addFilterBefore(singleSignOutFilter(), | ||
| + | .addFilterBefore(requestCasGlobalLogoutFilter(), | ||
| + | } else { | ||
| + | http.httpBasic() | ||
| + | } | ||
| + | |||
| + | http.authorizeRequests().anyRequest().fullyAuthenticated().and().httpBasic() | ||
| + | |||
| + | http.logout() | ||
| + | .logoutUrl('/ | ||
| + | .logoutSuccessUrl('/' | ||
| + | .invalidateHttpSession(true) | ||
| + | .deleteCookies(' | ||
| + | |||
| + | http.csrf().disable() | ||
| + | } | ||
| + | </ | ||
| + | This sample is pretty simple, but you can use more complex/ | ||
| + | <code groovy> | ||
| + | http.authorizeRequests() | ||
| + | .antMatchers("/ | ||
| + | .antMatchers("/ | ||
| + | .antMatchers("/ | ||
| + | .anyRequest().authenticated() | ||
| + | .and() | ||
| + | </ | ||
| + | |||
| + | ==== Programatically ==== | ||
| + | The most straightforward way is to programatically get the context of the currently logged in user in a following way. The important part is the first 2 lines in the filter method. They get the current logged in user ([[https:// | ||
| + | <code groovy> | ||
| + | @Transactional | ||
| + | abstract class CompanyBasedPermission< | ||
| + | |||
| + | boolean authorize(T domain) { | ||
| + | filter(domain) | ||
| + | } | ||
| + | |||
| + | boolean filter(T domain) { | ||
| + | Authentication authentication = SecurityContextHolder.getContext().getAuthentication() | ||
| + | UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal() | ||
| + | if (userPrincipal.hasUnlimitedAccess()) { | ||
| + | return true | ||
| + | } else { | ||
| + | Company company = userPrincipal.company | ||
| + | if (company == null) { | ||
| + | return false | ||
| + | } else { | ||
| + | return resolveCompanyPermission(domain, | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | abstract boolean resolveCompanyPermission(T domain, Company companyFromCurrentUser) | ||
| + | | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Using Annotations ==== | ||
| + | This is a very convenient and declarative way of defining authorisation and is preferred to be used for simple rules. It has to be explicitly enabled in [[https:// | ||
| + | <code groovy> | ||
| + | @Configuration | ||
| + | @EnableWebSecurity | ||
| + | @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) | ||
| + | class SecurityConfiguration extends WebSecurityConfigurerAdapter { | ||
| + | ... | ||
| + | </ | ||
| + | |||
| + | Then you can use various annotations as can be seen on following example: | ||
| + | <code groovy> | ||
| + | @RepositoryRestResource(collectionResourceRel = ' | ||
| + | interface DistributionRepository extends PagingAndSortingRepository< | ||
| + | |||
| + | Distribution findByName(String name) | ||
| + | |||
| + | // have to implement the filtering logic in query as the paging doesn' | ||
| + | @Override | ||
| + | @Query(" | ||
| + | Page< | ||
| + | |||
| + | @Override | ||
| + | @PostAuthorize(" | ||
| + | Distribution findOne(Long aLong) | ||
| + | |||
| + | @PostFilter(" | ||
| + | @Query(" | ||
| + | List< | ||
| + | |||
| + | @Override | ||
| + | @Secured([' | ||
| + | def <S extends Distribution> | ||
| + | |||
| + | @Secured([' | ||
| + | void delete(Long aLong) | ||
| + | |||
| + | } | ||
| + | </ | ||
| + | |||
| + | === @Secured === | ||
| + | The last method (// | ||
| + | |||
| + | === @PostFilter === | ||
| + | The // | ||
| + | |||
| + | === @PostAuthorize === | ||
| + | The //findOne// method uses the @PostAuthorize annotation. It's behaviour is very similar to @PostFilter, | ||
| + | |||
| + | === Using user context in @Query === | ||
| + | All of the previous methods mean that the data has to be somehow present in the application to authorise it. This might not be very feasible for large data sets or in case you want to use some limit or paging of the data from DB. For these cases the current user's context can be also used in the query to DB. | ||
| + | This is done in the //findAll// method, which actually uses the current UserPrincipal in order to do the filtering on the DB level. This is possible due to use of [[http:// | ||
| + | |||
| + | === @PreAuthorize / @PreFilter === | ||
| + | There are also other annotation, which can be used in a very similar manner, but instead of filtering/ | ||
| + | |||
| + | |||
| + | |||
| + | |||