Web implementation of the Gourmet Recipe Manager
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

141 lines
4.3 KiB

package com.mousetech.gourmetj;
import java.io.File;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.util.Arrays;
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.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.UserDetailsManagerConfigurer;
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.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig {
//extends WebSecurityConfigurerAdapter {
/* Logger */
private static final Logger log =
LoggerFactory.getLogger(SpringSecurityConfig.class);
@Value("${gourmet.password.file}")
private String passwordFile;
/**
* Load in config file with in-memory credentials.
* For practical use, this should probably be
* replace with JdbcUserDetailsManager and credentials in
* the recipe database.
*
* @param auth Builder for the authenticator
* @throws Exception
*/
@Autowired
public void configureGlobal(
AuthenticationManagerBuilder auth) throws Exception {
File pwFile = new File(passwordFile);
if (!pwFile.canRead()) {
String msg =
"Password file '" + pwFile.getAbsolutePath()
+ "' could not be found or read.";
log.error(msg);
throw new RuntimeException(msg);
}
LineNumberReader rdr =
new LineNumberReader(new FileReader(pwFile));
String pwLine;
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>
authenticator =
auth.inMemoryAuthentication();
while ((pwLine = rdr.readLine()) != null) {
pwLine = pwLine.trim();
if ((pwLine.length() == 0)
|| (pwLine.charAt(0) == '#')) {
continue;
}
String[] creds = parseCreds(pwLine);
UserDetailsManagerConfigurer<AuthenticationManagerBuilder,
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>
.UserDetailsBuilder bar =
authenticator.withUser(creds[0])
.password("{noop}" + creds[1]);
int credlen = creds.length;
for (int i = 2; i < credlen; i++) {
bar.roles(creds[i]);
}
}
rdr.close();
}
/**
* Parse CSV credential/roles line. Element 1 is userid,
* element 2 is password, following element(s) are role(s)
*
* @param pwLine
* @return Credentials array following CSV values, trimmed
*/
private String[] parseCreds(String pwLine) {
String[] creds = pwLine.split(",");
String[] ocreds = Arrays.stream(creds).map(e -> e.trim())
.toArray(String[]::new);
return ocreds;
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.formLogin(login -> login.loginPage("/login.jsf")
.permitAll()
.failureUrl("/login.jsf?error=true"))
.logout(logout -> logout
.logoutSuccessUrl("/login.jsf"))
.httpBasic(Customizer.withDefaults())
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated());
return http.build();
}
/**
* Replaces old antMatchers for determining secured URLs.
* @return customizer
*/
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers(
"/jakarta.faces.resource/**",
"/",
"/index.html",
// "/login",
// "/login.jsf", // Leave them for the authenticator!
// "/login.xhtml",
"/main.jsf",
"/main.xhtml",
"/img/**",
"/error/**",
"/RES_NOT_FOUND",
"/recipeDetails.jsf",
"/recipeDetails.xhtml",
"/shoppingList.jsf",
"/recipePrint.jsf");
}
}