diff --git a/2022-02/spring-22/pom.xml b/2022-02/spring-22/pom.xml
new file mode 100644
index 00000000..4de329a6
--- /dev/null
+++ b/2022-02/spring-22/pom.xml
@@ -0,0 +1,53 @@
+
+
+ 4.0.0
+
+ ru.otus
+ spring-framework-22-spring-security-start
+ 1.0-SNAPSHOT
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.3
+
+
+
+ 17
+ 17
+ 17
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/2022-02/spring-22/src/main/java/ru/otus/spring/Main.java b/2022-02/spring-22/src/main/java/ru/otus/spring/Main.java
new file mode 100644
index 00000000..5406a277
--- /dev/null
+++ b/2022-02/spring-22/src/main/java/ru/otus/spring/Main.java
@@ -0,0 +1,12 @@
+package ru.otus.spring;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Main {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Main.class);
+ }
+}
diff --git a/2022-02/spring-22/src/main/java/ru/otus/spring/rest/PagesController.java b/2022-02/spring-22/src/main/java/ru/otus/spring/rest/PagesController.java
new file mode 100644
index 00000000..1bdf754e
--- /dev/null
+++ b/2022-02/spring-22/src/main/java/ru/otus/spring/rest/PagesController.java
@@ -0,0 +1,32 @@
+package ru.otus.spring.rest;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class PagesController {
+
+ @GetMapping("/")
+ public String indexPage() {
+ return "index";
+ }
+
+ @GetMapping("/public")
+ public String publicPage() {
+ return "public";
+ }
+
+ @GetMapping("/authenticated")
+ public String authenticatedPage() {
+ return "authenticated";
+ }
+
+ @GetMapping("/success")
+ public String successPage(){
+ return "success";
+ }
+}
diff --git a/2022-02/spring-22/src/main/java/ru/otus/spring/security/SecurityConfiguration.java b/2022-02/spring-22/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
new file mode 100644
index 00000000..88cba3ba
--- /dev/null
+++ b/2022-02/spring-22/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
@@ -0,0 +1,78 @@
+package ru.otus.spring.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+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;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+
+import java.util.Collection;
+
+@EnableWebSecurity
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ public void configure(WebSecurity web) {
+ web.ignoring()
+ .antMatchers("/")
+ .antMatchers( "/static/**" );
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable()
+ // По умолчанию SecurityContext хранится в сессии. Эта часть вырубает и каждый запросом приходитТ
+// .sessionManagement()
+// .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
+// .and()
+ .authorizeRequests()
+ .antMatchers("/public/").anonymous()
+ .and()
+ .authorizeRequests()
+ .antMatchers("/authenticated").authenticated()
+// .and()
+// .authorizeRequests().antMatchers("/public").authenticated()
+ .and()
+ .formLogin()
+ .and()
+ .anonymous()
+ .principal( "anonymous" )
+ .and()
+ .rememberMe().key( "Some secret" )
+ ;
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+// return new BCryptPasswordEncoder(10);
+ return NoOpPasswordEncoder.getInstance();
+// return new PasswordEncoder() {
+// @Override
+// public String encode(CharSequence charSequence) {
+// return charSequence.toString();
+// }
+//
+// @Override
+// public boolean matches(CharSequence charSequence, String s) {
+// return charSequence.toString().equals(s);
+// }
+// };
+ }
+
+ @Autowired
+ public void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.inMemoryAuthentication()
+ .withUser("admin").password("password").roles("ADMIN")
+ ;
+ }
+}
diff --git a/2022-02/spring-22/src/main/resources/application.yml b/2022-02/spring-22/src/main/resources/application.yml
new file mode 100644
index 00000000..e69de29b
diff --git a/2022-02/spring-22/src/main/resources/templates/authenticated.html b/2022-02/spring-22/src/main/resources/templates/authenticated.html
new file mode 100644
index 00000000..9f8b0d7e
--- /dev/null
+++ b/2022-02/spring-22/src/main/resources/templates/authenticated.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Только для авторизованных
+
+
diff --git a/2022-02/spring-22/src/main/resources/templates/index.html b/2022-02/spring-22/src/main/resources/templates/index.html
new file mode 100644
index 00000000..f4d11090
--- /dev/null
+++ b/2022-02/spring-22/src/main/resources/templates/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+/public
+
+/authenticated
+
+
diff --git a/2022-02/spring-22/src/main/resources/templates/public.html b/2022-02/spring-22/src/main/resources/templates/public.html
new file mode 100644
index 00000000..77188469
--- /dev/null
+++ b/2022-02/spring-22/src/main/resources/templates/public.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Доступен всем
+
+
diff --git a/2022-02/spring-22/src/main/resources/templates/success.html b/2022-02/spring-22/src/main/resources/templates/success.html
new file mode 100644
index 00000000..89db5f22
--- /dev/null
+++ b/2022-02/spring-22/src/main/resources/templates/success.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Вы успешно вошли
+
+
+Вы успешно вошли
+
+
diff --git a/2022-02/spring-23/pom.xml b/2022-02/spring-23/pom.xml
new file mode 100644
index 00000000..873ca89f
--- /dev/null
+++ b/2022-02/spring-23/pom.xml
@@ -0,0 +1,61 @@
+
+
+ 4.0.0
+
+ ru.otus
+ spring-framework-23-auth
+ 1.0-SNAPSHOT
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.0
+
+
+
+ UTF-8
+ UTF-8
+ 17
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+
+
+
+ org.springframework.security
+ spring-security-test
+ ${spring-security.version}
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/2022-02/spring-23/src/main/java/ru/otus/spring/Main.java b/2022-02/spring-23/src/main/java/ru/otus/spring/Main.java
new file mode 100644
index 00000000..5406a277
--- /dev/null
+++ b/2022-02/spring-23/src/main/java/ru/otus/spring/Main.java
@@ -0,0 +1,12 @@
+package ru.otus.spring;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Main {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Main.class);
+ }
+}
diff --git a/2022-02/spring-23/src/main/java/ru/otus/spring/rest/PagesController.java b/2022-02/spring-23/src/main/java/ru/otus/spring/rest/PagesController.java
new file mode 100644
index 00000000..1fa8da0c
--- /dev/null
+++ b/2022-02/spring-23/src/main/java/ru/otus/spring/rest/PagesController.java
@@ -0,0 +1,43 @@
+package ru.otus.spring.rest;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+
+@Controller
+public class PagesController {
+
+ @GetMapping("/")
+ public String indexPage() {
+ return "index";
+ }
+
+ @GetMapping("/public")
+ public String publicPage() {
+// SecurityContext securityContext = SecurityContextHolder.getContext();
+// Authentication authentication = securityContext.getAuthentication();
+// System.out.println(authentication.getPrincipal());
+ return "public";
+ }
+
+ @GetMapping("/authenticated")
+ public String authenticatedPage() {
+ SecurityContext securityContext = SecurityContextHolder.getContext();
+ return "authenticated";
+ }
+
+ @GetMapping("/success")
+ public String successPage() {
+ return "success";
+ }
+
+
+ @GetMapping("/error")
+ public String errorPage() {
+ return "error";
+ }
+}
diff --git a/2022-02/spring-23/src/main/java/ru/otus/spring/security/AnonimusUD.java b/2022-02/spring-23/src/main/java/ru/otus/spring/security/AnonimusUD.java
new file mode 100644
index 00000000..b7a31238
--- /dev/null
+++ b/2022-02/spring-23/src/main/java/ru/otus/spring/security/AnonimusUD.java
@@ -0,0 +1,43 @@
+package ru.otus.spring.security;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+
+public class AnonimusUD implements UserDetails {
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return null;
+ }
+
+ @Override
+ public String getPassword() {
+ return null;
+ }
+
+ @Override
+ public String getUsername() {
+ return "anonymous";
+ }
+
+ @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/2022-02/spring-23/src/main/java/ru/otus/spring/security/SecurityConfiguration.java b/2022-02/spring-23/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
new file mode 100644
index 00000000..05b2f980
--- /dev/null
+++ b/2022-02/spring-23/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
@@ -0,0 +1,51 @@
+package ru.otus.spring.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+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;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@EnableWebSecurity
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ public void configure( WebSecurity web ) {
+ web.ignoring().antMatchers( "/" );
+ }
+
+ @Override
+ public void configure( HttpSecurity http ) throws Exception {
+ http.csrf().disable()
+ // По умолчанию SecurityContext хранится в сессии
+ // Это необходимо, чтобы он нигде не хранился
+ // и данные приходили каждый раз с запросом
+// .sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS )
+// .and()
+ .authorizeRequests().antMatchers( "/public" ).anonymous()
+ .and()
+ .authorizeRequests().antMatchers( "/authenticated", "/success" ).authenticated()
+
+ .and()
+ // Включает Form-based аутентификацию
+ .formLogin()
+ ;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return NoOpPasswordEncoder.getInstance();
+ }
+
+ @Autowired
+ public void configure( AuthenticationManagerBuilder auth ) throws Exception {
+ auth.inMemoryAuthentication()
+ .withUser( "admin" ).password( "password" ).roles( "ADMIN" );
+ }
+}
diff --git a/2022-02/spring-23/src/main/java/ru/otus/spring/security/filter/MyOwnFilter.java b/2022-02/spring-23/src/main/java/ru/otus/spring/security/filter/MyOwnFilter.java
new file mode 100644
index 00000000..010afbaa
--- /dev/null
+++ b/2022-02/spring-23/src/main/java/ru/otus/spring/security/filter/MyOwnFilter.java
@@ -0,0 +1,17 @@
+package ru.otus.spring.security.filter;
+
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.io.IOException;
+
+public class MyOwnFilter extends GenericFilterBean {
+ @Override
+ public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain ) throws IOException, ServletException {
+ servletRequest.getParameterMap().put( "SpecialValue", new String[]{ "My dirty secret" } );
+ filterChain.doFilter( servletRequest, servletResponse );
+ }
+}
diff --git a/2022-02/spring-23/src/main/resources/application.yml b/2022-02/spring-23/src/main/resources/application.yml
new file mode 100644
index 00000000..0151c503
--- /dev/null
+++ b/2022-02/spring-23/src/main/resources/application.yml
@@ -0,0 +1,4 @@
+logging:
+ level:
+ root: error
+ org.springframework: error
\ No newline at end of file
diff --git a/2022-02/spring-23/src/main/resources/templates/authenticated.html b/2022-02/spring-23/src/main/resources/templates/authenticated.html
new file mode 100644
index 00000000..0d2043f0
--- /dev/null
+++ b/2022-02/spring-23/src/main/resources/templates/authenticated.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Только для авторизованных
+
+
+Только для авторизованных
+
+
diff --git a/2022-02/spring-23/src/main/resources/templates/error.html b/2022-02/spring-23/src/main/resources/templates/error.html
new file mode 100644
index 00000000..ba4e50a2
--- /dev/null
+++ b/2022-02/spring-23/src/main/resources/templates/error.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Упс...
+
+
+Что-то пошло не так. Печалька
+
+
diff --git a/2022-02/spring-23/src/main/resources/templates/index.html b/2022-02/spring-23/src/main/resources/templates/index.html
new file mode 100644
index 00000000..f2d1d1ae
--- /dev/null
+++ b/2022-02/spring-23/src/main/resources/templates/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+ Главная страница
+
+
+/public
+
+/authenticated
+
+
diff --git a/2022-02/spring-23/src/main/resources/templates/public.html b/2022-02/spring-23/src/main/resources/templates/public.html
new file mode 100644
index 00000000..b9f93817
--- /dev/null
+++ b/2022-02/spring-23/src/main/resources/templates/public.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Доступен всем
+
+
+Доступен всем
+
+
diff --git a/2022-02/spring-23/src/main/resources/templates/success.html b/2022-02/spring-23/src/main/resources/templates/success.html
new file mode 100644
index 00000000..58414c01
--- /dev/null
+++ b/2022-02/spring-23/src/main/resources/templates/success.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Вы успешно вошли !
+
+
+Вы успешно вошли !
+
+
diff --git a/2022-02/spring-23/src/test/java/ru/otus/spring/rest/PagesControllerTest.java b/2022-02/spring-23/src/test/java/ru/otus/spring/rest/PagesControllerTest.java
new file mode 100644
index 00000000..3f84fa46
--- /dev/null
+++ b/2022-02/spring-23/src/test/java/ru/otus/spring/rest/PagesControllerTest.java
@@ -0,0 +1,32 @@
+package ru.otus.spring.rest;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@ExtendWith(SpringExtension.class)
+@WebMvcTest(PagesController.class)
+public class PagesControllerTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @WithMockUser(
+ username = "admin",
+ authorities = {"ROLE_ADMIN"}
+ )
+ @Test
+ public void testAuthenticatedOnAdmin() throws Exception {
+ mockMvc.perform(get("/authenticated"))
+ .andExpect(status().isOk());
+ }
+}
diff --git a/2022-02/spring-24/pom.xml b/2022-02/spring-24/pom.xml
new file mode 100644
index 00000000..c386ad2d
--- /dev/null
+++ b/2022-02/spring-24/pom.xml
@@ -0,0 +1,47 @@
+
+
+ 4.0.0
+
+ ru.otus
+ spring-framework-24-security-authorization
+ 1.0-SNAPSHOT
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.3
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/2022-02/spring-24/src/main/java/ru/otus/spring/SpringSecurity24Sample.java b/2022-02/spring-24/src/main/java/ru/otus/spring/SpringSecurity24Sample.java
new file mode 100644
index 00000000..ba8fd4fc
--- /dev/null
+++ b/2022-02/spring-24/src/main/java/ru/otus/spring/SpringSecurity24Sample.java
@@ -0,0 +1,17 @@
+package ru.otus.spring;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
+@SpringBootApplication
+public class SpringSecurity24Sample {
+
+ public static void main( String[] args ) {
+ SpringApplication.run( SpringSecurity24Sample.class );
+ }
+
+}
diff --git a/2022-02/spring-24/src/main/java/ru/otus/spring/rest/PagesController.java b/2022-02/spring-24/src/main/java/ru/otus/spring/rest/PagesController.java
new file mode 100644
index 00000000..9ffbf988
--- /dev/null
+++ b/2022-02/spring-24/src/main/java/ru/otus/spring/rest/PagesController.java
@@ -0,0 +1,57 @@
+package ru.otus.spring.rest;
+
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+import ru.otus.spring.service.MyService;
+
+@Controller
+public class PagesController {
+
+ private final MyService myService;
+
+ public PagesController(MyService myService) {
+ this.myService = myService;
+ }
+
+ @GetMapping("/")
+ public String indexPage() {
+ return "index";
+ }
+
+ @GetMapping("/public")
+ public String publicPage( ) {
+ return "public";
+ }
+
+ @GetMapping("/user")
+ public String userPage() {
+// myService.onlyUser();
+ return "user";
+ }
+
+ @GetMapping("/admin")
+// @Secured( "ADMIN" )
+ public String adminPage( ) {
+ myService.onlyUser();
+ //myService.onlyAdmin();
+ return "admin";
+ }
+
+ @GetMapping("/authenticated")
+ public String authenticatedPage() {
+ UserDetails userDetails = (UserDetails) SecurityContextHolder
+ .getContext().getAuthentication().getPrincipal();
+ System.out.println(userDetails.getUsername());
+ return "authenticated";
+ }
+
+ @GetMapping("/success")
+ public String successPage() {
+ return "success";
+ }
+}
diff --git a/2022-02/spring-24/src/main/java/ru/otus/spring/rest/SecurityControllerAdvice.java b/2022-02/spring-24/src/main/java/ru/otus/spring/rest/SecurityControllerAdvice.java
new file mode 100644
index 00000000..267b080d
--- /dev/null
+++ b/2022-02/spring-24/src/main/java/ru/otus/spring/rest/SecurityControllerAdvice.java
@@ -0,0 +1,16 @@
+package ru.otus.spring.rest;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+import java.util.Optional;
+
+@ControllerAdvice
+public class SecurityControllerAdvice {
+ @ExceptionHandler(AccessDeniedException.class)
+ public ResponseEntity accessError(){
+ return ResponseEntity.of( Optional.of( "Неудачник" ));
+ }
+}
diff --git a/2022-02/spring-24/src/main/java/ru/otus/spring/security/SecurityConfiguration.java b/2022-02/spring-24/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
new file mode 100644
index 00000000..3989d010
--- /dev/null
+++ b/2022-02/spring-24/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
@@ -0,0 +1,76 @@
+package ru.otus.spring.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+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;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+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.provisioning.InMemoryUserDetailsManager;
+
+import java.util.Collection;
+
+@EnableWebSecurity
+@Configuration
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+
+ @Override
+ public void configure(WebSecurity web) {
+ web.ignoring().antMatchers("/");
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable()
+ //.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ //.and()
+ .authorizeRequests().antMatchers("/public").permitAll()
+ .and()
+ .authorizeRequests().antMatchers("/authenticated", "/success").authenticated()
+ .and()
+ .authorizeRequests().antMatchers("/user").hasAnyRole( "ADMIN", "USER" )
+
+ .and()
+ .authorizeRequests().antMatchers("/admin").hasRole( "ADMIN" )
+ .and()
+ .formLogin()
+ .and()
+ .logout().logoutUrl("/logout");
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new PasswordEncoder() {
+ @Override
+ public String encode(CharSequence charSequence) {
+ return charSequence.toString();
+ }
+
+ @Override
+ public boolean matches(CharSequence charSequence, String s) {
+ return charSequence.toString().equals(s);
+ }
+ };
+ }
+
+ @Autowired
+ public void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.inMemoryAuthentication()
+ .withUser("admin").password("password").roles("ADMIN")
+ .and()
+ .withUser("user").password("password").roles("USER")
+ .and()
+ .withUser("manager").password("manager").roles("MANAGER", "USER");
+ }
+}
diff --git a/2022-02/spring-24/src/main/java/ru/otus/spring/service/MyService.java b/2022-02/spring-24/src/main/java/ru/otus/spring/service/MyService.java
new file mode 100644
index 00000000..064ad676
--- /dev/null
+++ b/2022-02/spring-24/src/main/java/ru/otus/spring/service/MyService.java
@@ -0,0 +1,16 @@
+package ru.otus.spring.service;
+
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MyService {
+ @PreAuthorize("hasRole('ROLE_USER') && {new java.util.Random().nextInt()%2 == 0}")
+ public String onlyUser() {
+ return "My love";
+ }
+
+ @Secured( "ADMIN" )
+ public void onlyAdmin() {}
+}
diff --git a/2022-02/spring-24/src/main/resources/templates/admin.html b/2022-02/spring-24/src/main/resources/templates/admin.html
new file mode 100644
index 00000000..aa1c9563
--- /dev/null
+++ b/2022-02/spring-24/src/main/resources/templates/admin.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Страница с доступом только админу
+
+
diff --git a/2022-02/spring-24/src/main/resources/templates/authenticated.html b/2022-02/spring-24/src/main/resources/templates/authenticated.html
new file mode 100644
index 00000000..e4756c01
--- /dev/null
+++ b/2022-02/spring-24/src/main/resources/templates/authenticated.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Только для аторизованных
+
+
diff --git a/2022-02/spring-24/src/main/resources/templates/error.html b/2022-02/spring-24/src/main/resources/templates/error.html
new file mode 100644
index 00000000..f28b51df
--- /dev/null
+++ b/2022-02/spring-24/src/main/resources/templates/error.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Вам доступ запрещён!
+
+
diff --git a/2022-02/spring-24/src/main/resources/templates/index.html b/2022-02/spring-24/src/main/resources/templates/index.html
new file mode 100644
index 00000000..d4c54ecd
--- /dev/null
+++ b/2022-02/spring-24/src/main/resources/templates/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+/public
+
+/authenticated
+
+/user
+
+/admin
+
+
diff --git a/2022-02/spring-24/src/main/resources/templates/manager.html b/2022-02/spring-24/src/main/resources/templates/manager.html
new file mode 100644
index 00000000..dd4a77af
--- /dev/null
+++ b/2022-02/spring-24/src/main/resources/templates/manager.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Доступ к MANAGER
+
+
diff --git a/2022-02/spring-24/src/main/resources/templates/public.html b/2022-02/spring-24/src/main/resources/templates/public.html
new file mode 100644
index 00000000..77188469
--- /dev/null
+++ b/2022-02/spring-24/src/main/resources/templates/public.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Доступен всем
+
+
diff --git a/2022-02/spring-24/src/main/resources/templates/success.html b/2022-02/spring-24/src/main/resources/templates/success.html
new file mode 100644
index 00000000..4e2a37cd
--- /dev/null
+++ b/2022-02/spring-24/src/main/resources/templates/success.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Вы успешно вошли !
+
+
diff --git a/2022-02/spring-24/src/main/resources/templates/user.html b/2022-02/spring-24/src/main/resources/templates/user.html
new file mode 100644
index 00000000..a794bc2d
--- /dev/null
+++ b/2022-02/spring-24/src/main/resources/templates/user.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Доступ к USER
+
+
diff --git a/2022-02/spring-25/ACL/pom.xml b/2022-02/spring-25/ACL/pom.xml
new file mode 100644
index 00000000..4939fe4b
--- /dev/null
+++ b/2022-02/spring-25/ACL/pom.xml
@@ -0,0 +1,82 @@
+
+
+ 4.0.0
+
+ ru.otus
+ spring-framework-25-acl
+ 1.0-SNAPSHOT
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.6.RELEASE
+
+
+
+ 2.6.11
+ 2.8.0
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ org.springframework.security
+ spring-security-acl
+
+
+ net.sf.ehcache
+ ehcache-core
+ ${ehcache-core.version}
+ jar
+
+
+ org.springframework
+ spring-context-support
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+
+
+
+ io.springfox
+ springfox-swagger2
+ ${swagger.version}
+
+
+ io.springfox
+ springfox-swagger-ui
+ ${swagger.version}
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/Main.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/Main.java
new file mode 100644
index 00000000..baca49d5
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/Main.java
@@ -0,0 +1,14 @@
+package ru.otus.spring;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+
+@SpringBootApplication
+public class Main {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Main.class);
+ }
+}
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/config/SwaggerConfig.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/config/SwaggerConfig.java
new file mode 100644
index 00000000..92854b5f
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/config/SwaggerConfig.java
@@ -0,0 +1,23 @@
+package ru.otus.spring.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import ru.otus.spring.rest.NoticeMessageController;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+
+ @Bean
+ public Docket productApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .useDefaultResponseMessages(false)
+ .select()
+ .apis(RequestHandlerSelectors.basePackage(NoticeMessageController.class.getPackage().getName()))
+ .build();
+ }
+}
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/model/NoticeMessage.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/model/NoticeMessage.java
new file mode 100644
index 00000000..21457970
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/model/NoticeMessage.java
@@ -0,0 +1,33 @@
+package ru.otus.spring.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "system_message")
+public class NoticeMessage {
+
+ @Id
+ @Column
+ private Integer id;
+ @Column
+ private String content;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+}
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/model/Pack.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/model/Pack.java
new file mode 100644
index 00000000..8498e0cc
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/model/Pack.java
@@ -0,0 +1,4 @@
+package ru.otus.spring.model;
+
+public class Pack {
+}
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/repository/NoticeMessageRepository.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/repository/NoticeMessageRepository.java
new file mode 100644
index 00000000..4588eb21
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/repository/NoticeMessageRepository.java
@@ -0,0 +1,25 @@
+package ru.otus.spring.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.security.access.prepost.PostAuthorize;
+import org.springframework.security.access.prepost.PostFilter;
+import org.springframework.security.access.prepost.PreAuthorize;
+import ru.otus.spring.model.NoticeMessage;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface NoticeMessageRepository extends JpaRepository {
+
+ @PostFilter("hasPermission(filterObject, 'READ')")
+ List findAll();
+
+ @PostAuthorize("hasPermission(returnObject, 'READ')")
+ NoticeMessage getById(Integer id);
+
+ @SuppressWarnings("unchecked")
+ @PreAuthorize("hasPermission(#noticeMessage, 'WRITE')")
+ NoticeMessage save(@Param("noticeMessage") NoticeMessage noticeMessage);
+
+}
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/rest/NoticeMessageController.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/rest/NoticeMessageController.java
new file mode 100644
index 00000000..fbf59c52
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/rest/NoticeMessageController.java
@@ -0,0 +1,35 @@
+package ru.otus.spring.rest;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RestController;
+import ru.otus.spring.model.NoticeMessage;
+import ru.otus.spring.repository.NoticeMessageRepository;
+
+import java.util.List;
+
+@RestController
+public class NoticeMessageController {
+
+ private final NoticeMessageRepository repository;
+
+ public NoticeMessageController(NoticeMessageRepository repository) {
+ this.repository = repository;
+ }
+
+ @GetMapping("/message")
+ public List getAll() {
+ return repository.findAll();
+ }
+
+ @GetMapping("/message/{id}")
+ public NoticeMessage getById(@PathVariable("id") Integer id) {
+ return repository.getById(id);
+ }
+
+ @PutMapping("/message")
+ public NoticeMessage getById(NoticeMessage message) {
+ return repository.save(message);
+ }
+}
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/security/AclConfig.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/security/AclConfig.java
new file mode 100644
index 00000000..36d7376a
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/security/AclConfig.java
@@ -0,0 +1,79 @@
+package ru.otus.spring.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.ehcache.EhCacheFactoryBean;
+import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
+import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
+import org.springframework.security.acls.AclPermissionCacheOptimizer;
+import org.springframework.security.acls.AclPermissionEvaluator;
+import org.springframework.security.acls.domain.*;
+import org.springframework.security.acls.jdbc.BasicLookupStrategy;
+import org.springframework.security.acls.jdbc.JdbcMutableAclService;
+import org.springframework.security.acls.jdbc.LookupStrategy;
+import org.springframework.security.acls.model.PermissionGrantingStrategy;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+import javax.sql.DataSource;
+import java.util.Objects;
+
+@Configuration
+public class AclConfig {
+
+ @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
+ @Autowired
+ private DataSource dataSource;
+
+ @Bean
+ public EhCacheBasedAclCache aclCache() {
+ return new EhCacheBasedAclCache(
+ Objects.requireNonNull(aclEhCacheFactoryBean().getObject()),
+ permissionGrantingStrategy(),
+ aclAuthorizationStrategy()
+ );
+ }
+
+ @Bean
+ public EhCacheFactoryBean aclEhCacheFactoryBean() {
+ EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();
+ ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());
+ ehCacheFactoryBean.setCacheName("aclCache");
+ return ehCacheFactoryBean;
+ }
+
+ @Bean
+ public EhCacheManagerFactoryBean aclCacheManager() {
+ return new EhCacheManagerFactoryBean();
+ }
+
+ @Bean
+ public PermissionGrantingStrategy permissionGrantingStrategy() {
+ return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
+ }
+
+ @Bean
+ public AclAuthorizationStrategy aclAuthorizationStrategy() {
+ return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_EDITOR"));
+ }
+
+ @Bean
+ public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler() {
+ DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
+ AclPermissionEvaluator permissionEvaluator = new AclPermissionEvaluator(aclService());
+ expressionHandler.setPermissionEvaluator(permissionEvaluator);
+ expressionHandler.setPermissionCacheOptimizer(new AclPermissionCacheOptimizer(aclService()));
+ return expressionHandler;
+ }
+
+ @Bean
+ public LookupStrategy lookupStrategy() {
+ return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
+ }
+
+ @Bean
+ public JdbcMutableAclService aclService() {
+ return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
+ }
+}
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/security/AclMethodSecurityConfiguration.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/security/AclMethodSecurityConfiguration.java
new file mode 100644
index 00000000..b66620ba
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/security/AclMethodSecurityConfiguration.java
@@ -0,0 +1,22 @@
+package ru.otus.spring.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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, securedEnabled = true)
+public class AclMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
+
+ @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
+ @Autowired
+ MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler;
+
+ @Override
+ protected MethodSecurityExpressionHandler createExpressionHandler() {
+ return defaultMethodSecurityExpressionHandler;
+ }
+
+}
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/security/SecurityConfiguration.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
new file mode 100644
index 00000000..ecdfd7f1
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
@@ -0,0 +1,60 @@
+package ru.otus.spring.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+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;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@EnableWebSecurity
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ @Override
+ public void configure(WebSecurity web) {
+ web.ignoring().antMatchers("/swagger-ui.html")
+ .antMatchers("/webjars/springfox-swagger-ui/**")
+ .antMatchers("/swagger-resources/**")
+ .antMatchers("/v2/api-docs")
+ .antMatchers("/h2-console/**");
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable()
+ //.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ //.and()
+ .authorizeRequests().antMatchers("/**").permitAll()
+ .and()
+ .formLogin()
+ .and()
+ .logout().logoutUrl("/logout");
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new PasswordEncoder() {
+ @Override
+ public String encode(CharSequence charSequence) {
+ return charSequence.toString();
+ }
+
+ @Override
+ public boolean matches(CharSequence charSequence, String s) {
+ return charSequence.toString().equals(s);
+ }
+ };
+ }
+
+ @Autowired
+ public void configure(AuthenticationManagerBuilder auth) throws Exception {
+ auth.inMemoryAuthentication()
+ .withUser("admin").password("password").roles("EDITOR")
+ .and()
+ .withUser("user").password("password").roles("USER")
+ .and()
+ .withUser("someone").password("password").roles("SOMEONE");
+ }
+}
diff --git a/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/service/NoticeService.java b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/service/NoticeService.java
new file mode 100644
index 00000000..f7f878fc
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/java/ru/otus/spring/service/NoticeService.java
@@ -0,0 +1,42 @@
+package ru.otus.spring.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.acls.domain.BasePermission;
+import org.springframework.security.acls.domain.GrantedAuthoritySid;
+import org.springframework.security.acls.domain.ObjectIdentityImpl;
+import org.springframework.security.acls.domain.PrincipalSid;
+import org.springframework.security.acls.model.MutableAcl;
+import org.springframework.security.acls.model.MutableAclService;
+import org.springframework.security.acls.model.ObjectIdentity;
+import org.springframework.security.acls.model.Sid;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+import ru.otus.spring.model.NoticeMessage;
+import ru.otus.spring.repository.NoticeMessageRepository;
+
+@Service
+public class NoticeService {
+ @Autowired
+ protected MutableAclService mutableAclService;
+
+ @Autowired
+ private NoticeMessageRepository repository;
+
+ public void add( NoticeMessage noticeMessage ) {
+ repository.save( noticeMessage );
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ final Sid owner = new PrincipalSid( authentication );
+ ObjectIdentity oid = new ObjectIdentityImpl( noticeMessage.getClass(), noticeMessage.getId() );
+
+ final Sid admin = new GrantedAuthoritySid("ROLE_EDITOR");
+
+ MutableAcl acl = mutableAclService.createAcl( oid );
+ acl.setOwner( owner );
+ acl.insertAce( acl.getEntries().size(), BasePermission.ADMINISTRATION, admin, true );
+
+ mutableAclService.updateAcl( acl );
+
+
+ }
+}
diff --git a/2022-02/spring-25/ACL/src/main/resources/application.yml b/2022-02/spring-25/ACL/src/main/resources/application.yml
new file mode 100644
index 00000000..9a70d12a
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/resources/application.yml
@@ -0,0 +1,7 @@
+spring:
+ h2:
+ console:
+ enabled: true
+ jpa:
+ hibernate:
+ ddl-auto: none
diff --git a/2022-02/spring-25/ACL/src/main/resources/data.sql b/2022-02/spring-25/ACL/src/main/resources/data.sql
new file mode 100644
index 00000000..9ae11203
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/resources/data.sql
@@ -0,0 +1,28 @@
+INSERT INTO system_message(id,content) VALUES
+(1,'First Level Message'),
+(2,'Second Level Message'),
+(3,'Third Level Message');
+
+
+INSERT INTO acl_sid (id, principal, sid) VALUES
+(1, 1, 'admin'),
+(2, 1, 'user'),
+(3, 0, 'ROLE_EDITOR');
+
+INSERT INTO acl_class (id, class) VALUES
+(1, 'ru.otus.spring.model.NoticeMessage');
+
+INSERT INTO acl_object_identity (id, object_id_class, object_id_identity, parent_object, owner_sid, entries_inheriting) VALUES
+(1, 1, 1, NULL, 3, 0),
+(2, 1, 2, NULL, 3, 0),
+(3, 1, 3, NULL, 3, 0);
+
+INSERT INTO acl_entry (id, acl_object_identity, ace_order, sid, mask,
+ granting, audit_success, audit_failure) VALUES
+(1, 1, 1, 1, 1, 1, 1, 1),
+(2, 1, 2, 1, 2, 1, 1, 1),
+(3, 1, 3, 3, 1, 1, 1, 1),
+(4, 2, 1, 2, 1, 1, 1, 1),
+(5, 2, 2, 3, 1, 1, 1, 1),
+(6, 3, 1, 3, 1, 1, 1, 1),
+(7, 3, 2, 3, 2, 1, 1, 1);
diff --git a/2022-02/spring-25/ACL/src/main/resources/schema.sql b/2022-02/spring-25/ACL/src/main/resources/schema.sql
new file mode 100644
index 00000000..9f740482
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/resources/schema.sql
@@ -0,0 +1,58 @@
+create table IF NOT EXISTS system_message (id integer not null, content varchar(255), primary key (id));
+
+CREATE TABLE IF NOT EXISTS acl_sid (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ principal tinyint(1) NOT NULL,
+ sid varchar(100) NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_uk_1 (sid,principal)
+);
+
+CREATE TABLE IF NOT EXISTS acl_class (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ class varchar(255) NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_uk_2 (class)
+);
+
+CREATE TABLE IF NOT EXISTS acl_entry (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ acl_object_identity bigint(20) NOT NULL,
+ ace_order int(11) NOT NULL,
+ sid bigint(20) NOT NULL,
+ mask int(11) NOT NULL,
+ granting tinyint(1) NOT NULL,
+ audit_success tinyint(1) NOT NULL,
+ audit_failure tinyint(1) NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_uk_4 (acl_object_identity,ace_order)
+);
+
+CREATE TABLE IF NOT EXISTS acl_object_identity (
+ id bigint(20) NOT NULL AUTO_INCREMENT,
+ object_id_class bigint(20) NOT NULL,
+ object_id_identity bigint(20) NOT NULL,
+ parent_object bigint(20) DEFAULT NULL,
+ owner_sid bigint(20) DEFAULT NULL,
+ entries_inheriting tinyint(1) NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE KEY unique_uk_3 (object_id_class,object_id_identity)
+);
+
+ALTER TABLE acl_entry
+ADD FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity(id);
+
+ALTER TABLE acl_entry
+ADD FOREIGN KEY (sid) REFERENCES acl_sid(id);
+
+--
+-- Constraints for table acl_object_identity
+--
+ALTER TABLE acl_object_identity
+ADD FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id);
+
+ALTER TABLE acl_object_identity
+ADD FOREIGN KEY (object_id_class) REFERENCES acl_class (id);
+
+ALTER TABLE acl_object_identity
+ADD FOREIGN KEY (owner_sid) REFERENCES acl_sid (id);
\ No newline at end of file
diff --git a/2022-02/spring-25/ACL/src/main/resources/templates/error.html b/2022-02/spring-25/ACL/src/main/resources/templates/error.html
new file mode 100644
index 00000000..f28b51df
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/resources/templates/error.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Вам доступ запрещён!
+
+
diff --git a/2022-02/spring-25/ACL/src/main/resources/templates/index.html b/2022-02/spring-25/ACL/src/main/resources/templates/index.html
new file mode 100644
index 00000000..79347f42
--- /dev/null
+++ b/2022-02/spring-25/ACL/src/main/resources/templates/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+login
+
+logout
+
+h2-console
+
+/swagger
+
+
diff --git a/2022-02/spring-25/WebFlux/pom.xml b/2022-02/spring-25/WebFlux/pom.xml
new file mode 100644
index 00000000..f3160a4d
--- /dev/null
+++ b/2022-02/spring-25/WebFlux/pom.xml
@@ -0,0 +1,72 @@
+
+
+ 4.0.0
+
+ ru.otus
+ spring-framework-25-webflux
+ 1.0-SNAPSHOT
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.6.RELEASE
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+
+ org.springframework.security
+ spring-security-core
+
+
+ org.springframework.security
+ spring-security-config
+
+
+ org.springframework.security
+ spring-security-web
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-mongodb-reactive
+
+
+
+ de.flapdoodle.embed
+ de.flapdoodle.embed.mongo
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+ spring-milestone
+ http://repo.spring.io/milestone
+
+
+
diff --git a/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/Main.java b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/Main.java
new file mode 100644
index 00000000..490b4b3a
--- /dev/null
+++ b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/Main.java
@@ -0,0 +1,22 @@
+package ru.otus.spring;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions;
+import org.springframework.web.reactive.function.server.ServerResponse;
+
+@SpringBootApplication
+public class Main {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Main.class);
+ }
+
+ @Bean
+ RouterFunction staticResourceRouter() {
+ return RouterFunctions.resources("/**.html", new ClassPathResource("static/"));
+ }
+}
diff --git a/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/data/Person.java b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/data/Person.java
new file mode 100644
index 00000000..067c0b64
--- /dev/null
+++ b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/data/Person.java
@@ -0,0 +1,41 @@
+package ru.otus.spring.data;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document
+public class Person {
+
+ @Id
+ private String id;
+
+ private String name;
+
+ public Person() {
+ }
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public Person(String id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/data/PersonRepository.java b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/data/PersonRepository.java
new file mode 100644
index 00000000..2f1994d3
--- /dev/null
+++ b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/data/PersonRepository.java
@@ -0,0 +1,11 @@
+package ru.otus.spring.data;
+
+import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
+import org.springframework.stereotype.Repository;
+import reactor.core.publisher.Mono;
+
+@Repository
+public interface PersonRepository extends ReactiveMongoRepository {
+
+ Mono findByName(String string);
+}
diff --git a/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/rest/PersonController.java b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/rest/PersonController.java
new file mode 100644
index 00000000..f1d4333c
--- /dev/null
+++ b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/rest/PersonController.java
@@ -0,0 +1,34 @@
+package ru.otus.spring.rest;
+
+import org.springframework.web.bind.annotation.*;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import ru.otus.spring.data.Person;
+import ru.otus.spring.data.PersonRepository;
+
+@RestController
+public class PersonController {
+
+ private final PersonRepository personRepository;
+
+ public PersonController(PersonRepository personRepository) {
+ this.personRepository = personRepository;
+ }
+
+ @GetMapping("/person")
+ public Flux getAll() {
+ return personRepository.findAll();
+ }
+
+ @GetMapping("/person/find")
+ public Mono find(@RequestParam("name") String name) {
+ return personRepository.findByName(name)
+ .cache();
+ }
+
+
+ @PostMapping("/person")
+ public Mono savePerson(@RequestBody Person person) {
+ return personRepository.save(person);
+ }
+}
diff --git a/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/security/SecurityConfiguration.java b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
new file mode 100644
index 00000000..b779f380
--- /dev/null
+++ b/2022-02/spring-25/WebFlux/src/main/java/ru/otus/spring/security/SecurityConfiguration.java
@@ -0,0 +1,49 @@
+package ru.otus.spring.security;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
+import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+import org.springframework.security.config.web.server.ServerHttpSecurity;
+import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
+import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.server.SecurityWebFilterChain;
+
+@Configuration
+@EnableWebFluxSecurity
+@EnableReactiveMethodSecurity
+public class SecurityConfiguration {
+
+ @Bean
+ public SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
+ return http
+ .authorizeExchange()
+ .pathMatchers(HttpMethod.GET, "/authenticated.html").hasRole("USER")
+ // anonymous
+ .anyExchange().permitAll()
+ .and()
+ .httpBasic()
+ .and()
+ .build();
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return NoOpPasswordEncoder.getInstance();
+ }
+
+ @Bean
+ public ReactiveUserDetailsService userDetailsService() {
+ UserDetails user = User
+ .withUsername("user")
+ .password("password")
+ .roles("USER")
+ .build();
+ return new MapReactiveUserDetailsService(user);
+ }
+}
diff --git a/2022-02/spring-25/WebFlux/src/main/resources/static/authenticated.html b/2022-02/spring-25/WebFlux/src/main/resources/static/authenticated.html
new file mode 100644
index 00000000..e4756c01
--- /dev/null
+++ b/2022-02/spring-25/WebFlux/src/main/resources/static/authenticated.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Только для аторизованных
+
+
diff --git a/2022-02/spring-25/WebFlux/src/main/resources/static/index.html b/2022-02/spring-25/WebFlux/src/main/resources/static/index.html
new file mode 100644
index 00000000..a89ba331
--- /dev/null
+++ b/2022-02/spring-25/WebFlux/src/main/resources/static/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+/public.html
+
+/authenticated.html
+
+
diff --git a/2022-02/spring-25/WebFlux/src/main/resources/static/public.html b/2022-02/spring-25/WebFlux/src/main/resources/static/public.html
new file mode 100644
index 00000000..77188469
--- /dev/null
+++ b/2022-02/spring-25/WebFlux/src/main/resources/static/public.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+Доступен всем
+
+