diff --git a/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/CustomFilter.java b/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/CustomFilter.java deleted file mode 100644 index 1bf6c9e94b17d9c78ccad1e41cd34e5090ec4dcd..0000000000000000000000000000000000000000 --- a/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/CustomFilter.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.latlon.xplanbox.security.authentication; - -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 CustomFilter extends GenericFilterBean { - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) - throws IOException, ServletException { - chain.doFilter(request, response); - } - -} \ No newline at end of file diff --git a/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/PropertiesFileUserDetailsManager.java b/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/PropertiesFileUserDetailsManager.java new file mode 100644 index 0000000000000000000000000000000000000000..7721fac23399fc423cb17bcbaf44b3557512bf66 --- /dev/null +++ b/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/PropertiesFileUserDetailsManager.java @@ -0,0 +1,79 @@ +package de.latlon.xplanbox.security.authentication; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.UserDetailsManager; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Map; +import java.util.Properties; +import java.util.stream.Collectors; + +/** + * {@link UserDetailsManager} managing user details from properties file + * + * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> + * @since 7.1 + */ +public class PropertiesFileUserDetailsManager implements UserDetailsManager { + + private static final Logger LOG = LoggerFactory.getLogger(PropertiesFileUserDetailsManager.class); + + private final Map<String, String> usersAndEncryptedPasswords; + + public PropertiesFileUserDetailsManager(String userPropertiesFile, PasswordEncoder passwordEncoder) + throws SecurityConfigurationException { + try (FileInputStream inputStream = new FileInputStream(userPropertiesFile)) { + Properties users = new Properties(); + users.load(inputStream); + this.usersAndEncryptedPasswords = users.entrySet() + .stream() + .collect(Collectors.toMap(entry -> (String) entry.getKey(), + entry -> passwordEncoder.encode((String) entry.getValue()))); + } + catch (IOException e) { + LOG.error("Properties file with users could not be read. ", e); + throw new SecurityConfigurationException(e); + } + } + + @Override + public void createUser(UserDetails user) { + throw new UnsupportedOperationException(); + } + + @Override + public void updateUser(UserDetails user) { + throw new UnsupportedOperationException(); + } + + @Override + public void deleteUser(String username) { + throw new UnsupportedOperationException(); + } + + @Override + public void changePassword(String oldPassword, String newPassword) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean userExists(String username) { + return usersAndEncryptedPasswords.containsKey(username); + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + if (!userExists(username)) { + throw new UsernameNotFoundException(username); + } + String password = this.usersAndEncryptedPasswords.get(username); + return User.withUsername(username).password(password).roles("USER_ROLE").build(); + } + +} diff --git a/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/SecurityConfigurationException.java b/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/SecurityConfigurationException.java new file mode 100644 index 0000000000000000000000000000000000000000..b7b9da4d2bdae0711729905f024a1dfae7c134ec --- /dev/null +++ b/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/SecurityConfigurationException.java @@ -0,0 +1,15 @@ +package de.latlon.xplanbox.security.authentication; + +/** + * Indicates a misconfiguration in the security module. + * + * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> + * @since 7.1 + */ +public class SecurityConfigurationException extends Exception { + + public SecurityConfigurationException(Throwable e) { + super(e); + } + +} diff --git a/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/UnauthorizedAuthenticationEntryPoint.java b/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/UnauthorizedAuthenticationEntryPoint.java index c52d40df4bf1458d66c44b6a8eabdd9bb1126888..e5a67f1037dbd9477310b076da36b8cb22130193 100644 --- a/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/UnauthorizedAuthenticationEntryPoint.java +++ b/xplan-security/src/main/java/de/latlon/xplanbox/security/authentication/UnauthorizedAuthenticationEntryPoint.java @@ -9,6 +9,10 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.Serializable; +/** + * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> + * @since 7.1 + */ @Component public class UnauthorizedAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { diff --git a/xplan-security/src/main/java/de/latlon/xplanbox/security/config/SecurityContext.java b/xplan-security/src/main/java/de/latlon/xplanbox/security/config/SecurityContext.java index 1c60347717fa47bbbdc96180e9d5d57ec4bfefb0..d6fa393d75a831b404bd7a3a40fcad29b9c5b26a 100644 --- a/xplan-security/src/main/java/de/latlon/xplanbox/security/config/SecurityContext.java +++ b/xplan-security/src/main/java/de/latlon/xplanbox/security/config/SecurityContext.java @@ -1,23 +1,29 @@ package de.latlon.xplanbox.security.config; +import de.latlon.xplanbox.security.authentication.PropertiesFileUserDetailsManager; +import de.latlon.xplanbox.security.authentication.SecurityConfigurationException; import de.latlon.xplanbox.security.authentication.UnauthorizedAuthenticationEntryPoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; 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.UserDetails; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; +/** + * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a> + * @since 7.1 + */ @EnableWebSecurity @Configuration +@Profile("enableSecurity") @ComponentScan(basePackages = { "de.latlon.xplanbox.security" }) public class SecurityContext { @@ -39,12 +45,10 @@ public class SecurityContext { } @Bean - public InMemoryUserDetailsManager userDetailsService() { - UserDetails user = User.withUsername("user") - .password(passwordEncoder().encode("password")) - .roles("USER_ROLE") - .build(); - return new InMemoryUserDetailsManager(user); + public PropertiesFileUserDetailsManager userDetailsService( + @Value("#{environment.XPLAN_SECURITY_USER_PROPERTIES_FILE}") String userPropertiesFile, + PasswordEncoder passwordEncoder) throws SecurityConfigurationException { + return new PropertiesFileUserDetailsManager(userPropertiesFile, passwordEncoder); } @Bean