-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/user accounts #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f4fd0f5
1bd8fcd
c28b037
84401bf
2ce5d02
208bf9d
100f1f5
1f0a820
889e03f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| package org.example.devroadmapskilltracker.config; | ||
|
|
||
| import org.example.devroadmapskilltracker.skill.Skill; | ||
| import org.example.devroadmapskilltracker.skill.SkillRepository; | ||
| import org.example.devroadmapskilltracker.skill.SkillStatus; | ||
| import org.example.devroadmapskilltracker.user.User; | ||
| import org.example.devroadmapskilltracker.user.UserRepository; | ||
| import org.springframework.boot.CommandLineRunner; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import org.slf4j.LoggerFactory; | ||
| import org.slf4j.Logger; | ||
| import org.springframework.context.annotation.Profile; | ||
| import org.springframework.security.crypto.password.PasswordEncoder; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Configuration | ||
| public class DataInitializer { | ||
|
|
||
| private static final Logger logger = LoggerFactory.getLogger(DataInitializer.class); | ||
| private final PasswordEncoder passwordEncoder; | ||
|
|
||
| public DataInitializer(PasswordEncoder passwordEncoder) { | ||
| this.passwordEncoder = passwordEncoder; | ||
| } | ||
|
|
||
| @Bean | ||
| @Profile("!prod") | ||
| CommandLineRunner initDatabase(SkillRepository skillRepository, UserRepository userRepository) { | ||
| return args -> { | ||
|
|
||
| if (userRepository.count() == 0) { | ||
| logger.info("No skill found. Generating test user and skills..."); | ||
|
|
||
| User testUser = new User(); | ||
| testUser.setFullName("Test Developer"); | ||
| testUser.setUsername("test"); | ||
| testUser.setPassword(passwordEncoder.encode("secret")); | ||
|
|
||
| User savedUser = userRepository.save(testUser); | ||
|
|
||
| skillRepository.saveAll(List.of( | ||
| // BACKLOG | ||
| new Skill("Docker", "Learn containerization and how to manage images.","DevOps", SkillStatus.BACKLOG, savedUser), | ||
| new Skill("TypeScript", "Strongly typed JavaScript for better scaling.","Frontend", SkillStatus.BACKLOG,savedUser), | ||
|
|
||
| // IN PROGRESS | ||
| new Skill("Spring Boot", "Building robust backend services with Java.","Backend", SkillStatus.IN_PROGRESS,savedUser), | ||
| new Skill("Thymeleaf", "Server-side template engine for modern web apps.","Web", SkillStatus.IN_PROGRESS, savedUser), | ||
| new Skill("CSS Grid", "Mastering complex layouts with grid systems.","Design", SkillStatus.IN_PROGRESS, savedUser), | ||
|
|
||
| // MASTERED | ||
| new Skill("Java Fundamentals", "Core syntax, OOP, and collections.", "Backend", SkillStatus.MASTERED, savedUser), | ||
| new Skill("REST APIs", "Designing and implementing scalable endpoints." ,"Backend", SkillStatus.MASTERED,savedUser) | ||
|
|
||
| )); | ||
|
|
||
| logger.info("🚀Test data has been loaded!"); | ||
| } | ||
| }; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| package org.example.devroadmapskilltracker.config; | ||
|
|
||
| import org.example.devroadmapskilltracker.user.UserRepository; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||
| import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | ||
| import org.springframework.security.core.userdetails.User; | ||
| import org.springframework.security.core.userdetails.UserDetailsService; | ||
| import org.springframework.security.core.userdetails.UsernameNotFoundException; | ||
| import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||
| import org.springframework.security.crypto.password.PasswordEncoder; | ||
| import org.springframework.security.web.SecurityFilterChain; | ||
|
|
||
| @Configuration | ||
| @EnableWebSecurity | ||
| public class SecurityConfig { | ||
|
|
||
| private final UserRepository userRepository; | ||
|
|
||
| public SecurityConfig(UserRepository userRepository) { | ||
| this.userRepository = userRepository; | ||
| } | ||
|
|
||
| @Bean | ||
| public SecurityFilterChain securityFilterChain(HttpSecurity http) { | ||
| http.csrf(csrf -> csrf.disable()) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Re-enable CSRF protection for form-based authentication. Disabling CSRF protection exposes all state-changing operations (skill create/update/delete, account changes) to cross-site request forgery. Since this application uses Thymeleaf with 🔒 Proposed fix to re-enable CSRF protection- http.csrf(csrf -> csrf.disable())
- .authorizeHttpRequests(auth -> auth
+ http
+ .authorizeHttpRequests(auth -> authEnsure all Thymeleaf forms use <!-- Use this -->
<form th:action="@{/skills}" method="post">
<!-- Instead of this -->
<form action="/skills" method="post">🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| .authorizeHttpRequests(auth -> auth | ||
| .requestMatchers("/login", "/static/**", "/css/**", "/assets/**").permitAll() | ||
| .requestMatchers("/signup","/createAccount").permitAll() | ||
| .anyRequest().authenticated()) | ||
|
|
||
| .formLogin(form -> form | ||
| .loginPage("/login") | ||
| .defaultSuccessUrl("/skills") | ||
| .permitAll()) | ||
| .logout(logout -> logout | ||
| .logoutUrl("/logout") | ||
| .logoutSuccessUrl("/login?logout") | ||
| .permitAll()); | ||
|
|
||
|
|
||
| return http.build(); | ||
| } | ||
|
|
||
| @Bean | ||
| public UserDetailsService userDetailsService() { | ||
| return username -> userRepository.findByUsername(username) | ||
| .map(user -> User | ||
| .withUsername(user.getUsername()) | ||
| .password(user.getPassword()) | ||
| .roles("USER") | ||
| .build()) | ||
| .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username)); | ||
| } | ||
|
|
||
|
|
||
| @Bean | ||
| public PasswordEncoder passwordEncoder() { | ||
| return new BCryptPasswordEncoder(); | ||
| } | ||
| } | ||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
Test credentials documented in README.
Documenting the
test/secretcredentials is convenient for development, but ensure this seeded account is removed or disabled before any production deployment. Consider noting that these credentials are for local development only.🤖 Prompt for AI Agents