Improvements to authorization

main
tim holloway 2 months ago
parent ec17e0d72a
commit 21d4f58574
  1. 17
      src/main/java/com/mousetech/gourmetj/AdminMainBean.java
  2. 4
      src/main/java/com/mousetech/gourmetj/JSFUtils.java
  3. 4
      src/main/java/com/mousetech/gourmetj/RecipeDetailBean.java
  4. 5
      src/main/java/com/mousetech/gourmetj/SpringPrimeFacesApplication.java
  5. 50
      src/main/java/com/mousetech/gourmetj/SpringSecurityConfig.java
  6. 2
      src/main/java/com/mousetech/gourmetj/UserSession.java
  7. 2
      src/main/resources/META-INF/resources/WEB-INF/faces-config.xml
  8. 12
      src/main/resources/META-INF/resources/error/error404.html
  9. 12
      src/main/resources/META-INF/resources/error/error404.jsp
  10. 14
      src/main/resources/META-INF/resources/error/viewExpired.html
  11. 13
      src/main/resources/META-INF/resources/index.html
  12. 55
      src/main/resources/META-INF/resources/login.xhtml
  13. 17
      src/main/resources/META-INF/resources/main.xhtml
  14. 14
      src/main/resources/application.yml

@ -12,27 +12,22 @@ import com.mousetech.gourmetj.persistence.model.Recipe;
import com.mousetech.gourmetj.persistence.service.RecipeService;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.event.AjaxBehaviorEvent;
import jakarta.faces.model.DataModel;
import jakarta.faces.model.ListDataModel;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
/**
* Main control panel backing bean.
*
* The rare and fabled RequestScope, which is otherwise
* useless 90% of the time. Here we maintain no session
* state. so we can better support the session timeout
* for editing functions.
*
* @author timh
* @since Jun 28, 2012
*/
@Named
@RequestScoped
@ViewScoped
public class AdminMainBean implements Serializable {
/**
@ -49,9 +44,6 @@ public class AdminMainBean implements Serializable {
private static final Logger log =
LoggerFactory.getLogger(AdminMainBean.class);
/** Cookie delimiter */
private static final String CKDLM = ",";
/**
* Persistency service for Recipes.
*/
@ -289,4 +281,9 @@ public class AdminMainBean implements Serializable {
// items.
return "recipeDetails?faces-redirect=true";
}
public String doLogout() {
JSFUtils.logout();
return null;
}
}

@ -164,5 +164,9 @@ public class JSFUtils {
log.warn("Session did not exist.");
}
}
public static HttpSession getSession(boolean create) {
return (HttpSession) getExternalContext().getSession(create);
}
}

@ -14,12 +14,10 @@ import jakarta.faces.model.ListDataModel;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.servlet.http.Part;
import jakarta.faces.event.AjaxBehaviorEvent;
import org.apache.commons.lang3.StringUtils;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.file.UploadedFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -980,7 +978,7 @@ public class RecipeDetailBean implements Serializable {
public String editDescription() {
this.setDetailTab(0);
return "detailEdit?faces-redirect=true";
return "detailEdit.xhtml?faces-redirect=true";
}
public String editIngredients() {

@ -21,10 +21,11 @@ import org.springframework.http.HttpStatus;
"com.mousetech.gourmetj.persistence.model" })
public class SpringPrimeFacesApplication {
final String homePage = "/main.jsf?viewExpired=true";
final String errorPage = "/error/error.html";
final String error404Page = "/error/error404.html";
final String error404Page = "/error/error404.jsp";
final String error400Page = "/error/error400.jsp";
final String expiredPage = "/main.xhtml";
final String expiredPage = "/error/viewExpired.xhtml";
public static void main(String[] args) {
SpringApplication.run(SpringPrimeFacesApplication.class,

@ -20,6 +20,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import jakarta.servlet.DispatcherType;
@ -99,24 +100,24 @@ public class SpringSecurityConfig {
return ocreds;
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.cors(AbstractHttpConfigurer::disable)
.formLogin(formLogin ->
formLogin
.loginPage("/login.xhtml")
.permitAll())
.authorizeHttpRequests((authorize)-> authorize
.dispatcherTypeMatchers(DispatcherType.FORWARD, DispatcherType.ERROR).permitAll()
.anyRequest().authenticated()
);
return http.build();
}
@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
@ -124,14 +125,19 @@ public class SpringSecurityConfig {
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers(
"/jakarta.faces.resource/**",
"/index.xhtml",
"/jakarta.faces.resource/**",
"/",
"/index.jsf",
"/login",
"/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");
}

@ -5,10 +5,8 @@ import java.util.ArrayList;
import java.util.List;
import jakarta.enterprise.context.SessionScoped;
import jakarta.faces.model.SelectItem;
import jakarta.inject.Named;
import org.primefaces.PrimeFaces;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ -25,7 +25,7 @@
<navigation-case>
<description>Go Home</description>
<from-outcome>home</from-outcome>
<to-view-id>/main</to-view-id>
<to-view-id>/main.xhtml?faces-redirect=true</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<title>ERROR - Page Not Found</title>
</head>
<body>
<h1>Page Not Found</h1>
<p>This URL is invalid.</p>
<p><a href="/main.jsf">Return to Main Page</a></p>
</body>
</html>

@ -0,0 +1,12 @@
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII" isErrorPage="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ERROR - Page Not Found</title>
</head>
<body>
<h1>Page Not Found</h1>
<p><a href="/main.jsf">Return to Main Page</a></p>
</body>
</html>

@ -1,14 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ERROR - Page Expired</title>
</head>
<body>
<h1>Page Expired</h1>
<p>The page state could not be restored because it was
left idle too long.</p>
<p>
<a href="/main.jsf">Return to Main Page</a>
</p>
</body>
</html>

@ -1,13 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
>
<h:head>Gourmet Recipe Manager</h:head>
<h:body>
<html>
<head><title>Gourmet Recipe Manager</title><head>
<body>
<h1>Gourmet Recipe Manager</h1>
<p>This is an implementation of Thomas Hinkle's
Gourmet Recipe Manager, originally a desktop
@ -20,5 +15,5 @@
<p>This is an open-source application under the
Common Development and Distribution License (CDDL).
</p>
</h:body>
<body>
</html>

@ -1,31 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions">
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions"
>
<h:head>
<title>Login</title>
<h:outputStylesheet name="/css/login.css" />
<title>Login</title>
</h:head>
<h:body>
<h:form prependId="false">
<p:panelGrid columns="1" styleClass="ui-fluid center ui-noborder">
<h2>Please login</h2>
<p:outputLabel value="Login failed!" styleClass="red"
rendered="${!empty param['error']}" />
<p:inputText id="username" placeholder="User name" />
<p:password id="password" placeholder="Password" />
<p:commandButton value="Login" ajax="false" />
</p:panelGrid>
</h:form>
<h:form prependId="false" style="width:100%">
<p:panelGrid columns="3" style="width:100%"
styleClass="ui-fluid center ui-noborder"
>
<h:outputText style="width:33%;" value=" " />
<p:panelGrid columns="1" id="grid1">
<h:outputText>Please login</h:outputText>
<p:outputLabel value="Login failed!"
styleClass="red"
rendered="${!empty param['error']}"
/>
<p:outputLabel for="username">User ID</p:outputLabel>
<p:inputText id="username"
placeholder="User name"
/>
<p:outputLabel for="password">Password</p:outputLabel>
<p:password id="password" placeholder="Password" />
<p:commandButton value="Login" ajax="false" />
</p:panelGrid>
<h:outputText style="width:33%;" value=" " />
</p:panelGrid>
</h:form>
</h:body>
</html>
</html>

@ -20,13 +20,7 @@
listener="#{adminMainBean.ajaxUpdateList}"
/>
</p:autoComplete>
<p:defaultCommand target="find" />
<p:commandButton id="find" value="Find"
icon="ui-icon-search"
action="#{adminMainBean.doFind}"
update=":form2:table1"
/>
<p:outputLabel for="@next" value="Search for " />
<p:outputLabel for="@next" value=" In " />
<p:selectOneMenu id="ctlSearchType"
value="#{cookieBean.searchType}"
>
@ -37,6 +31,12 @@
listener="#{adminMainBean.resetSuggestions}"
/>
</p:selectOneMenu>
<p:defaultCommand target="find" />
<p:commandButton id="find" value="Find"
icon="ui-icon-search"
action="#{adminMainBean.doFind}"
update=":form2:table1"
/>
<p:commandButton id="ctlClear" value="Clear"
icon="ui-icon-close"
update="@form:searchFor :form2:table1"
@ -55,6 +55,9 @@
<h:outputLabel for="slistSize"
value=" Recipes in Shopping List"
/>
<p:commandButton id="logout" value="Logout"
action="#{adminMainBean.doLogout}"
/>
</div>
</h:form>
<h:form id="form2">

@ -21,10 +21,13 @@ spring:
ddl-auto: none
database-platform: org.hibernate.dialect.MySQLDialect
# Tracking-modes prevent URL rewrite jsessionid on Primecases
# resources. Which causes "400" errors on initial main.jsf fetch.
server:
servlet:
session:
timeout: '30m'
tracking-modes: 'cookie'
# Theme here overrides joinfaces theme
# context-parameters:
# primefaces:
@ -38,3 +41,14 @@ gourmet:
joinfaces:
primefaces:
theme: bluesky
faces:
project-stage: Production
facelets-libraries: /tags/tags.taglib.xml
#logging:
# level:
# org.springframework.security: TRACE
# org.apache.catalina: TRACE
# jakarta.faces: TRACE
# com.sun.faces: TRACE
# jakarta.servlet: TRACE
Loading…
Cancel
Save