From 1c90f0c073264b178f79f122865f2d37a0a2da16 Mon Sep 17 00:00:00 2001 From: Nelson Date: Wed, 13 Nov 2019 22:08:18 +0000 Subject: [PATCH 1/5] 3 --- pom.xml | 6 +++ .../security/ApplicationSecurityConfig.java | 51 ++++++++++++++++++- .../security/ApplicationUserPermission.java | 18 +++++++ .../demo/security/ApplicationUserRole.java | 23 +++++++++ .../example/demo/security/PasswordConfig.java | 15 ++++++ 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/demo/security/ApplicationUserPermission.java create mode 100644 src/main/java/com/example/demo/security/ApplicationUserRole.java create mode 100644 src/main/java/com/example/demo/security/PasswordConfig.java diff --git a/pom.xml b/pom.xml index 186e802..57fa585 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,12 @@ spring-boot-starter-security + + com.google.guava + guava + 28.1-jre + + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java index f653c63..4d561ee 100644 --- a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java +++ b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java @@ -1,24 +1,71 @@ package com.example.demo.security; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +import static com.example.demo.security.ApplicationUserRole.*; + @Configuration @EnableWebSecurity public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter { + private final PasswordEncoder passwordEncoder; + + @Autowired + public ApplicationSecurityConfig(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() - .antMatchers("/", "index", "/css/*", "/js/*") - .permitAll() + .antMatchers("/", "index", "/css/*", "/js/*").permitAll() + .antMatchers("/api/**").hasRole(STUDENT.name()) .anyRequest() .authenticated() .and() .httpBasic(); } + @Override + @Bean + protected UserDetailsService userDetailsService() { + UserDetails annaSmithUser = User.builder() + .username("annasmith") + .password(passwordEncoder.encode("password")) + .roles(STUDENT.name()) // ROLE_STUDENT + .build(); + + UserDetails lindaUser = User.builder() + .username("linda") + .password(passwordEncoder.encode("password123")) + .roles(ADMIN.name()) // ROLE_ADMIN + .build(); + + UserDetails tomUser = User.builder() + .username("tom") + .password(passwordEncoder.encode("password123")) + .roles(ADMINTRAINEE.name()) // ROLE_ADMINTRAINEE + .build(); + + return new InMemoryUserDetailsManager( + annaSmithUser, + lindaUser, + tomUser + ); + + } } diff --git a/src/main/java/com/example/demo/security/ApplicationUserPermission.java b/src/main/java/com/example/demo/security/ApplicationUserPermission.java new file mode 100644 index 0000000..3f6102b --- /dev/null +++ b/src/main/java/com/example/demo/security/ApplicationUserPermission.java @@ -0,0 +1,18 @@ +package com.example.demo.security; + +public enum ApplicationUserPermission { + STUDENT_READ("student:read"), + STUDENT_WRITE("student:write"), + COURSE_READ("course:read"), + COURSE_WRITE("course:write"); + + private final String permission; + + ApplicationUserPermission(String permission) { + this.permission = permission; + } + + public String getPermission() { + return permission; + } +} diff --git a/src/main/java/com/example/demo/security/ApplicationUserRole.java b/src/main/java/com/example/demo/security/ApplicationUserRole.java new file mode 100644 index 0000000..cb43e93 --- /dev/null +++ b/src/main/java/com/example/demo/security/ApplicationUserRole.java @@ -0,0 +1,23 @@ +package com.example.demo.security; + +import com.google.common.collect.Sets; + +import java.util.Set; + +import static com.example.demo.security.ApplicationUserPermission.*; + +public enum ApplicationUserRole { + STUDENT(Sets.newHashSet()), + ADMIN(Sets.newHashSet(COURSE_READ, COURSE_WRITE, STUDENT_READ, STUDENT_WRITE)), + ADMINTRAINEE(Sets.newHashSet(COURSE_READ, STUDENT_READ)); + + private final Set permissions; + + ApplicationUserRole(Set permissions) { + this.permissions = permissions; + } + + public Set getPermissions() { + return permissions; + } +} diff --git a/src/main/java/com/example/demo/security/PasswordConfig.java b/src/main/java/com/example/demo/security/PasswordConfig.java new file mode 100644 index 0000000..0d9273b --- /dev/null +++ b/src/main/java/com/example/demo/security/PasswordConfig.java @@ -0,0 +1,15 @@ +package com.example.demo.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(10); + } +} From a15c19a50a39e1afbf9b00a9d9a5510d6400cd67 Mon Sep 17 00:00:00 2001 From: Nelson Date: Fri, 15 Nov 2019 22:21:44 +0000 Subject: [PATCH 2/5] 4 --- .../security/ApplicationSecurityConfig.java | 18 +++++-- .../demo/security/ApplicationUserRole.java | 11 +++++ .../com/example/demo/student/Student.java | 8 ++++ .../student/StudentManagementController.java | 48 +++++++++++++++++++ 4 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/example/demo/student/StudentManagementController.java diff --git a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java index 4d561ee..b9a665c 100644 --- a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java +++ b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java @@ -3,11 +3,10 @@ import org.springframework.beans.factory.annotation.Autowired; 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.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; @@ -19,6 +18,7 @@ @Configuration @EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter { private final PasswordEncoder passwordEncoder; @@ -31,9 +31,14 @@ public ApplicationSecurityConfig(PasswordEncoder passwordEncoder) { @Override protected void configure(HttpSecurity http) throws Exception { http + .csrf().disable() // TODO: I will teach this in detail in the next section .authorizeRequests() .antMatchers("/", "index", "/css/*", "/js/*").permitAll() .antMatchers("/api/**").hasRole(STUDENT.name()) +// .antMatchers(HttpMethod.DELETE, "/management/api/**").hasAuthority(COURSE_WRITE.getPermission()) +// .antMatchers(HttpMethod.POST, "/management/api/**").hasAuthority(COURSE_WRITE.getPermission()) +// .antMatchers(HttpMethod.PUT, "/management/api/**").hasAuthority(COURSE_WRITE.getPermission()) +// .antMatchers("/management/api/**").hasAnyRole(ADMIN.name(), ADMINTRAINEE.name()) .anyRequest() .authenticated() .and() @@ -46,19 +51,22 @@ protected UserDetailsService userDetailsService() { UserDetails annaSmithUser = User.builder() .username("annasmith") .password(passwordEncoder.encode("password")) - .roles(STUDENT.name()) // ROLE_STUDENT +// .roles(STUDENT.name()) // ROLE_STUDENT + .authorities(STUDENT.getGrantedAuthorities()) .build(); UserDetails lindaUser = User.builder() .username("linda") .password(passwordEncoder.encode("password123")) - .roles(ADMIN.name()) // ROLE_ADMIN +// .roles(ADMIN.name()) // ROLE_ADMIN + .authorities(ADMIN.getGrantedAuthorities()) .build(); UserDetails tomUser = User.builder() .username("tom") .password(passwordEncoder.encode("password123")) - .roles(ADMINTRAINEE.name()) // ROLE_ADMINTRAINEE +// .roles(ADMINTRAINEE.name()) // ROLE_ADMINTRAINEE + .authorities(ADMINTRAINEE.getGrantedAuthorities()) .build(); return new InMemoryUserDetailsManager( diff --git a/src/main/java/com/example/demo/security/ApplicationUserRole.java b/src/main/java/com/example/demo/security/ApplicationUserRole.java index cb43e93..4d40004 100644 --- a/src/main/java/com/example/demo/security/ApplicationUserRole.java +++ b/src/main/java/com/example/demo/security/ApplicationUserRole.java @@ -1,8 +1,11 @@ package com.example.demo.security; import com.google.common.collect.Sets; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import java.util.Set; +import java.util.stream.Collectors; import static com.example.demo.security.ApplicationUserPermission.*; @@ -20,4 +23,12 @@ public enum ApplicationUserRole { public Set getPermissions() { return permissions; } + + public Set getGrantedAuthorities() { + Set permissions = getPermissions().stream() + .map(permission -> new SimpleGrantedAuthority(permission.getPermission())) + .collect(Collectors.toSet()); + permissions.add(new SimpleGrantedAuthority("ROLE_" + this.name())); + return permissions; + } } diff --git a/src/main/java/com/example/demo/student/Student.java b/src/main/java/com/example/demo/student/Student.java index cd3cee3..35b1c9a 100644 --- a/src/main/java/com/example/demo/student/Student.java +++ b/src/main/java/com/example/demo/student/Student.java @@ -18,4 +18,12 @@ public Integer getStudentId() { public String getStudentName() { return studentName; } + + @Override + public String toString() { + return "Student{" + + "studentId=" + studentId + + ", studentName='" + studentName + '\'' + + '}'; + } } diff --git a/src/main/java/com/example/demo/student/StudentManagementController.java b/src/main/java/com/example/demo/student/StudentManagementController.java new file mode 100644 index 0000000..a832520 --- /dev/null +++ b/src/main/java/com/example/demo/student/StudentManagementController.java @@ -0,0 +1,48 @@ +package com.example.demo.student; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; + +@RestController +@RequestMapping("management/api/v1/students") +public class StudentManagementController { + + private static final List STUDENTS = Arrays.asList( + new Student(1, "James Bond"), + new Student(2, "Maria Jones"), + new Student(3, "Anna Smith") + ); + +// hasRole('ROLE_') hasAnyRole('ROLE_') hasAuthority('permission') hasAnyAuthority('permission') + + @GetMapping + @PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_ADMINTRAINEE')") + public List getAllStudents() { + System.out.println("getAllStudents"); + return STUDENTS; + } + + @PostMapping + @PreAuthorize("hasAuthority('student:write')") + public void registerNewStudent(@RequestBody Student student) { + System.out.println("registerNewStudent"); + System.out.println(student); + } + + @DeleteMapping(path = "{studentId}") + @PreAuthorize("hasAuthority('student:write')") + public void deleteStudent(@PathVariable("studentId") Integer studentId) { + System.out.println("deleteStudent"); + System.out.println(studentId); + } + + @PutMapping(path = "{studentId}") + @PreAuthorize("hasAuthority('student:write')") + public void updateStudent(@PathVariable("studentId") Integer studentId, @RequestBody Student student) { + System.out.println("updateStudent"); + System.out.println(String.format("%s %s", studentId, student)); + } +} From 473da3edef59d1a2c10c933ca2cebc4ba020591c Mon Sep 17 00:00:00 2001 From: Nelson Date: Sat, 16 Nov 2019 15:45:32 +0000 Subject: [PATCH 3/5] 5 --- .../example/demo/security/ApplicationSecurityConfig.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java index b9a665c..4d8b993 100644 --- a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java +++ b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java @@ -12,6 +12,7 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import static com.example.demo.security.ApplicationUserRole.*; @@ -31,14 +32,11 @@ public ApplicationSecurityConfig(PasswordEncoder passwordEncoder) { @Override protected void configure(HttpSecurity http) throws Exception { http - .csrf().disable() // TODO: I will teach this in detail in the next section + .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) + .and() .authorizeRequests() .antMatchers("/", "index", "/css/*", "/js/*").permitAll() .antMatchers("/api/**").hasRole(STUDENT.name()) -// .antMatchers(HttpMethod.DELETE, "/management/api/**").hasAuthority(COURSE_WRITE.getPermission()) -// .antMatchers(HttpMethod.POST, "/management/api/**").hasAuthority(COURSE_WRITE.getPermission()) -// .antMatchers(HttpMethod.PUT, "/management/api/**").hasAuthority(COURSE_WRITE.getPermission()) -// .antMatchers("/management/api/**").hasAnyRole(ADMIN.name(), ADMINTRAINEE.name()) .anyRequest() .authenticated() .and() From b1170caf1ecc327bb343e6b8d4e8f1c8c2eb431f Mon Sep 17 00:00:00 2001 From: Nelson Date: Sun, 17 Nov 2019 23:24:01 +0000 Subject: [PATCH 4/5] 6 --- pom.xml | 5 +++ .../demo/contoller/TemplateController.java | 20 ++++++++++ .../security/ApplicationSecurityConfig.java | 37 ++++++++++++++--- src/main/resources/templates/courses.html | 22 ++++++++++ src/main/resources/templates/login.html | 40 +++++++++++++++++++ 5 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/example/demo/contoller/TemplateController.java create mode 100644 src/main/resources/templates/courses.html create mode 100644 src/main/resources/templates/login.html diff --git a/pom.xml b/pom.xml index 57fa585..7a301ea 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,11 @@ spring-boot-starter-security + + org.springframework.boot + spring-boot-starter-thymeleaf + + com.google.guava guava diff --git a/src/main/java/com/example/demo/contoller/TemplateController.java b/src/main/java/com/example/demo/contoller/TemplateController.java new file mode 100644 index 0000000..c54f1bd --- /dev/null +++ b/src/main/java/com/example/demo/contoller/TemplateController.java @@ -0,0 +1,20 @@ +package com.example.demo.contoller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/") +public class TemplateController { + + @GetMapping("login") + public String getLogin() { + return "login"; + } + + @GetMapping("courses") + public String getCourses() { + return "courses"; + } +} diff --git a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java index 4d8b993..d33896e 100644 --- a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java +++ b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java @@ -12,7 +12,14 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.util.matcher.AndRequestMatcher; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +import javax.servlet.http.Cookie; +import java.net.CookieStore; +import java.util.concurrent.TimeUnit; import static com.example.demo.security.ApplicationUserRole.*; @@ -32,15 +39,32 @@ public ApplicationSecurityConfig(PasswordEncoder passwordEncoder) { @Override protected void configure(HttpSecurity http) throws Exception { http - .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) - .and() + .csrf().disable() .authorizeRequests() .antMatchers("/", "index", "/css/*", "/js/*").permitAll() .antMatchers("/api/**").hasRole(STUDENT.name()) .anyRequest() .authenticated() .and() - .httpBasic(); + .formLogin() + .loginPage("/login") + .permitAll() + .defaultSuccessUrl("/courses", true) + .passwordParameter("password") + .usernameParameter("username") + .and() + .rememberMe() + .tokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(21)) + .key("somethingverysecured") + .rememberMeParameter("remember-me") + .and() + .logout() + .logoutUrl("/logout") + .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET")) // https://docs.spring.io/spring-security/site/docs/4.2.12.RELEASE/apidocs/org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.html + .clearAuthentication(true) + .invalidateHttpSession(true) + .deleteCookies("JSESSIONID", "remember-me") + .logoutSuccessUrl("/login"); } @Override @@ -49,21 +73,18 @@ protected UserDetailsService userDetailsService() { UserDetails annaSmithUser = User.builder() .username("annasmith") .password(passwordEncoder.encode("password")) -// .roles(STUDENT.name()) // ROLE_STUDENT .authorities(STUDENT.getGrantedAuthorities()) .build(); UserDetails lindaUser = User.builder() .username("linda") .password(passwordEncoder.encode("password123")) -// .roles(ADMIN.name()) // ROLE_ADMIN .authorities(ADMIN.getGrantedAuthorities()) .build(); UserDetails tomUser = User.builder() .username("tom") .password(passwordEncoder.encode("password123")) -// .roles(ADMINTRAINEE.name()) // ROLE_ADMINTRAINEE .authorities(ADMINTRAINEE.getGrantedAuthorities()) .build(); @@ -74,4 +95,8 @@ protected UserDetailsService userDetailsService() { ); } + + public static void main(String[] args) { + System.out.println(TimeUnit.DAYS.toSeconds(1)); + } } diff --git a/src/main/resources/templates/courses.html b/src/main/resources/templates/courses.html new file mode 100644 index 0000000..2c7b919 --- /dev/null +++ b/src/main/resources/templates/courses.html @@ -0,0 +1,22 @@ + + + + + + + Amigoscode login + + + + +

Courses

+
+

Spring Boot Security

+ +
+ + + diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..2d7b41c --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,40 @@ + + + + + + + Amigoscode login + + + + + +
+ +
+ + \ No newline at end of file From c4798536b805b0092f42265c7f62292151d8d87d Mon Sep 17 00:00:00 2001 From: crystalclearaspen Date: Fri, 10 Jun 2022 12:33:40 -0600 Subject: [PATCH 5/5] added authentication package --- pom.xml | 2 +- .../example/demo/auth/ApplicationUser.java | 70 +++++++++++++++++++ .../example/demo/auth/ApplicationUserDAO.java | 9 +++ .../demo/auth/ApplicationUserService.java | 25 +++++++ .../auth/FakeApplicationUserDaoService.java | 62 ++++++++++++++++ .../security/ApplicationSecurityConfig.java | 41 +++++------ src/main/resources/application.properties | 1 + src/main/resources/templates/courses.html | 2 +- 8 files changed, 185 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/example/demo/auth/ApplicationUser.java create mode 100644 src/main/java/com/example/demo/auth/ApplicationUserDAO.java create mode 100644 src/main/java/com/example/demo/auth/ApplicationUserService.java create mode 100644 src/main/java/com/example/demo/auth/FakeApplicationUserDaoService.java diff --git a/pom.xml b/pom.xml index 7a301ea..50a5262 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ Demo project for Spring Boot - 11 + 1.8 diff --git a/src/main/java/com/example/demo/auth/ApplicationUser.java b/src/main/java/com/example/demo/auth/ApplicationUser.java new file mode 100644 index 0000000..edc395d --- /dev/null +++ b/src/main/java/com/example/demo/auth/ApplicationUser.java @@ -0,0 +1,70 @@ +package com.example.demo.auth; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public class ApplicationUser implements UserDetails { + + private final Set grantedAuthorities; + private final String password; + private final String username; + private final boolean isAccountNonExpired; + private final boolean isAccountNonLocked; + private final boolean isCredentialsNonExpired; + private final boolean isEnabled; + + public ApplicationUser(String username, + String password, + Set grantedAuthorities, + boolean isAccountNonExpired, + boolean isAccountNonLocked, + boolean isCredentialsNonExpired, + boolean isEnabled) { + this.grantedAuthorities = grantedAuthorities; + this.password = password; + this.username = username; + this.isAccountNonExpired = isAccountNonExpired; + this.isAccountNonLocked = isAccountNonLocked; + this.isCredentialsNonExpired = isCredentialsNonExpired; + this.isEnabled = isEnabled; + } + + @Override + public Collection getAuthorities() { + return grantedAuthorities; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public boolean isAccountNonExpired() { + return isAccountNonExpired; + } + + @Override + public boolean isAccountNonLocked() { + return isAccountNonLocked; + } + + @Override + public boolean isCredentialsNonExpired() { + return isCredentialsNonExpired; + } + + @Override + public boolean isEnabled() { + return isEnabled; + } +} diff --git a/src/main/java/com/example/demo/auth/ApplicationUserDAO.java b/src/main/java/com/example/demo/auth/ApplicationUserDAO.java new file mode 100644 index 0000000..a277a62 --- /dev/null +++ b/src/main/java/com/example/demo/auth/ApplicationUserDAO.java @@ -0,0 +1,9 @@ +package com.example.demo.auth; + +import java.util.Optional; + +public interface ApplicationUserDAO { + + Optional selectApplicationUserByUsername(String username); + +} diff --git a/src/main/java/com/example/demo/auth/ApplicationUserService.java b/src/main/java/com/example/demo/auth/ApplicationUserService.java new file mode 100644 index 0000000..b439f62 --- /dev/null +++ b/src/main/java/com/example/demo/auth/ApplicationUserService.java @@ -0,0 +1,25 @@ +package com.example.demo.auth; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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 ApplicationUserService implements UserDetailsService { + + private final ApplicationUserDAO applicationUserDAO; + + @Autowired + public ApplicationUserService(@Qualifier("fake") ApplicationUserDAO applicationUserDAO){ + this.applicationUserDAO = applicationUserDAO; + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + return applicationUserDAO.selectApplicationUserByUsername(username) + .orElseThrow(() -> new UsernameNotFoundException(String.format("Username %s not found", username))); + } +} diff --git a/src/main/java/com/example/demo/auth/FakeApplicationUserDaoService.java b/src/main/java/com/example/demo/auth/FakeApplicationUserDaoService.java new file mode 100644 index 0000000..8193bf8 --- /dev/null +++ b/src/main/java/com/example/demo/auth/FakeApplicationUserDaoService.java @@ -0,0 +1,62 @@ +package com.example.demo.auth; + +import com.example.demo.security.ApplicationUserRole; +import com.google.common.collect.Lists; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository("fake") +public class FakeApplicationUserDaoService implements ApplicationUserDAO { + + private final PasswordEncoder passwordEncoder; + + @Autowired + public FakeApplicationUserDaoService(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + @Override + public Optional selectApplicationUserByUsername(String username) { + return getApplicationUsers() + .stream() + .filter(applicationUser -> username.equals(applicationUser.getUsername())) + .findFirst(); + } + + private List getApplicationUsers() { + List applicationUsers = Lists.newArrayList( + new ApplicationUser( + "annasmith", + passwordEncoder.encode("pass"), + ApplicationUserRole.STUDENT.getGrantedAuthorities(), + true, + true, + true, + true + ), + new ApplicationUser( + "linda", + passwordEncoder.encode("pass"), + ApplicationUserRole.ADMIN.getGrantedAuthorities(), + true, + true, + true, + true + ), + new ApplicationUser( + "tom", + passwordEncoder.encode("pass"), + ApplicationUserRole.ADMINTRAINEE.getGrantedAuthorities(), + true, + true, + true, + true + ) + ); + return applicationUsers; + } +} diff --git a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java index d33896e..b316ebf 100644 --- a/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java +++ b/src/main/java/com/example/demo/security/ApplicationSecurityConfig.java @@ -1,8 +1,11 @@ package com.example.demo.security; +import com.example.demo.auth.ApplicationUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +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.configuration.EnableWebSecurity; @@ -30,9 +33,11 @@ public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter { private final PasswordEncoder passwordEncoder; + private final ApplicationUserService applicationUserService; @Autowired - public ApplicationSecurityConfig(PasswordEncoder passwordEncoder) { + public ApplicationSecurityConfig(PasswordEncoder passwordEncoder, ApplicationUserService applicationUserService) { + this.applicationUserService = applicationUserService; this.passwordEncoder = passwordEncoder; } @@ -68,33 +73,19 @@ protected void configure(HttpSecurity http) throws Exception { } @Override - @Bean - protected UserDetailsService userDetailsService() { - UserDetails annaSmithUser = User.builder() - .username("annasmith") - .password(passwordEncoder.encode("password")) - .authorities(STUDENT.getGrantedAuthorities()) - .build(); - - UserDetails lindaUser = User.builder() - .username("linda") - .password(passwordEncoder.encode("password123")) - .authorities(ADMIN.getGrantedAuthorities()) - .build(); + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(daoAuthenticationProvider()); + } - UserDetails tomUser = User.builder() - .username("tom") - .password(passwordEncoder.encode("password123")) - .authorities(ADMINTRAINEE.getGrantedAuthorities()) - .build(); + @Bean + public DaoAuthenticationProvider daoAuthenticationProvider() { + DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setPasswordEncoder(passwordEncoder); + provider.setUserDetailsService(applicationUserService); + return provider; + } - return new InMemoryUserDetailsManager( - annaSmithUser, - lindaUser, - tomUser - ); - } public static void main(String[] args) { System.out.println(TimeUnit.DAYS.toSeconds(1)); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b13789..164f752 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,2 @@ +server.port=8085 diff --git a/src/main/resources/templates/courses.html b/src/main/resources/templates/courses.html index 2c7b919..1649526 100644 --- a/src/main/resources/templates/courses.html +++ b/src/main/resources/templates/courses.html @@ -10,8 +10,8 @@ -

Courses

+

Courses

Spring Boot Security