diff --git a/pom.xml b/pom.xml index 462d94c..93ab052 100644 --- a/pom.xml +++ b/pom.xml @@ -116,7 +116,6 @@ javax.servlet javax.servlet-api - provided @@ -163,6 +162,11 @@ spring-boot-starter-test test + + org.springframework.security + spring-security-test + test + com.vaadin vaadin-testbench diff --git a/src/main/java/de/kreth/invoice/config/KeycloakConfigResolverLocal.java b/src/main/java/de/kreth/invoice/config/KeycloakConfigResolverLocal.java index 9c980d7..2b87d11 100644 --- a/src/main/java/de/kreth/invoice/config/KeycloakConfigResolverLocal.java +++ b/src/main/java/de/kreth/invoice/config/KeycloakConfigResolverLocal.java @@ -8,9 +8,9 @@ import org.springframework.context.annotation.Configuration; @Configuration public class KeycloakConfigResolverLocal { - @Bean - public KeycloakConfigResolver keyCloakConfigResolver() { - return new KeycloakSpringBootConfigResolver(); - } + @Bean + public KeycloakConfigResolver keyCloakConfigResolver() { + return new KeycloakSpringBootConfigResolver(); + } } diff --git a/src/main/java/de/kreth/invoice/config/SecurityUtils.java b/src/main/java/de/kreth/invoice/config/SecurityUtils.java index 2d0b94d..a3183ce 100644 --- a/src/main/java/de/kreth/invoice/config/SecurityUtils.java +++ b/src/main/java/de/kreth/invoice/config/SecurityUtils.java @@ -11,6 +11,10 @@ import org.springframework.security.core.context.SecurityContextHolder; import com.vaadin.flow.shared.ApplicationConstants; public class SecurityUtils { + + private SecurityUtils() { + } + /** * Tests if the request is an internal framework request. The test consists of * checking if the request parameter is present and if its value is consistent diff --git a/src/main/java/de/kreth/invoice/config/UiSecurityConfig.java b/src/main/java/de/kreth/invoice/config/UiSecurityConfig.java index 08e8805..e9280e8 100644 --- a/src/main/java/de/kreth/invoice/config/UiSecurityConfig.java +++ b/src/main/java/de/kreth/invoice/config/UiSecurityConfig.java @@ -22,60 +22,58 @@ import org.springframework.security.web.authentication.session.SessionAuthentica @KeycloakConfiguration public class UiSecurityConfig extends KeycloakWebSecurityConfigurerAdapter { - @Autowired - private KeycloakClientRequestFactory factory; + @Autowired + private KeycloakClientRequestFactory factory; - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) { - KeycloakAuthenticationProvider keyCloakAuthProvider = keycloakAuthenticationProvider(); - keyCloakAuthProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); - auth.authenticationProvider(keyCloakAuthProvider); - } + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) { + KeycloakAuthenticationProvider keyCloakAuthProvider = keycloakAuthenticationProvider(); + keyCloakAuthProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); + auth.authenticationProvider(keyCloakAuthProvider); + } - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public KeycloakRestTemplate restTemplate() { - return new KeycloakRestTemplate(factory); - } + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public KeycloakRestTemplate restTemplate() { + return new KeycloakRestTemplate(factory); + } - @Bean - @Override - protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { - return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); - } + @Bean + @Override + protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { + return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); + } - @Override - public void configure(HttpSecurity http) throws Exception { - super.configure(http); - http.cors().disable() - .csrf().disable() - .anonymous().disable() - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and() - .authorizeRequests().requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll() - .anyRequest().hasAnyRole("ROLE_trainer", "ROLE_admin"); - } + @Override + public void configure(HttpSecurity http) throws Exception { + super.configure(http); + http.cors().disable().csrf().disable().anonymous().disable().sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().authorizeRequests() + .requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll().anyRequest() + .hasAnyRole("admin", "INVOICE_USER"); + } - @Override - public void configure(WebSecurity web) throws Exception { - web.ignoring().antMatchers( - // Vaadin Flow static resources // - "/VAADIN/**", - // the standard favicon URI - "/favicon.ico", - // the robots exclusion standard - "/robots.txt", - // web application manifest // - "/manifest.webmanifest", "/sw.js", "/offline-page.html", - // (development mode) static resources // - "/frontend/**", - // (development mode) webjars // - "/webjars/**", - // (production mode) static resources // - "/frontend-es5/**", "/frontend-es6/**"); - } + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring().antMatchers( + // Vaadin Flow static resources // + "/VAADIN/**", + // the standard favicon URI + "/favicon.ico", + // the robots exclusion standard + "/robots.txt", + // web application manifest // + "/manifest.webmanifest", "/sw.js", "/offline-page.html", + // (development mode) static resources // + "/frontend/**", + // (development mode) webjars // + "/webjars/**", + // (production mode) static resources // + "/frontend-es5/**", "/frontend-es6/**"); + } - @Bean - public static KeycloakConfigResolver keycloakConfigResolver() { - return new KeycloakSpringBootConfigResolver(); - } + @Bean + public static KeycloakConfigResolver keycloakConfigResolver() { + return new KeycloakSpringBootConfigResolver(); + } } diff --git a/src/main/java/de/kreth/invoice/views/View.java b/src/main/java/de/kreth/invoice/views/View.java index 9b3890e..8c0441e 100644 --- a/src/main/java/de/kreth/invoice/views/View.java +++ b/src/main/java/de/kreth/invoice/views/View.java @@ -5,7 +5,6 @@ import java.util.Iterator; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import com.vaadin.flow.component.ClickEvent; import com.vaadin.flow.component.Text; @@ -42,7 +41,6 @@ import de.kreth.invoice.views.user.UserDetailsDialog; @PageTitle("") @Route(value = "") -@PreAuthorize("hasRole('INVOICE_USER')") public class View extends VerticalLayout implements BeforeEnterObserver { private static final long serialVersionUID = 1L; diff --git a/src/main/java/de/kreth/invoice/views/user/UserDetailsDialog.java b/src/main/java/de/kreth/invoice/views/user/UserDetailsDialog.java index 8eff28a..d9d50ab 100644 --- a/src/main/java/de/kreth/invoice/views/user/UserDetailsDialog.java +++ b/src/main/java/de/kreth/invoice/views/user/UserDetailsDialog.java @@ -33,44 +33,44 @@ import de.kreth.invoice.report.Signature; public class UserDetailsDialog extends Dialog { - private static final long serialVersionUID = -6255487997073609068L; + private static final long serialVersionUID = -6255487997073609068L; - private Logger logger = LoggerFactory.getLogger(getClass()); + private Logger logger = LoggerFactory.getLogger(getClass()); - private final Binder bankBinder = new Binder<>(); - private final Binder adressBinder = new Binder<>(); + private final Binder bankBinder = new Binder<>(); + private final Binder adressBinder = new Binder<>(); // private final TextField loginName; - private final TextField prename; + private final TextField prename; - private final TextField surname; + private final TextField surname; - private final TextField bankName; + private final TextField bankName; - private final TextField iban; + private final TextField iban; - private final TextField bic; + private final TextField bic; - private final TextField adress1; + private final TextField adress1; - private final TextField adress2; + private final TextField adress2; - private final TextField zipCode; + private final TextField zipCode; - private final TextField city; + private final TextField city; - private final Button okButton; + private final Button okButton; - private final Image signatureImage; - private final Upload upload; + private final Image signatureImage; + private final Upload upload; - private User user; + private User user; - private boolean isValidAndClosedWithOk = false; + private boolean isValidAndClosedWithOk = false; - public UserDetailsDialog(// UserBankRepository bankRepository, UserAdressRepository adressRepository - ) { + public UserDetailsDialog(// UserBankRepository bankRepository, UserAdressRepository adressRepository + ) { // this.bankRepository = bankRepository; // this.adressRepository = adressRepository; @@ -78,151 +78,145 @@ public class UserDetailsDialog extends Dialog { // loginName.setLabel("Login Name"); // loginName.setEnabled(false); - prename = new TextField(); - prename.setLabel("Vorname"); - prename.setEnabled(false); - - surname = new TextField(); - surname.setLabel("Nachname"); - surname.setEnabled(false); - - bankName = new TextField(); - bankName.setLabel("Name der Bank"); - bankBinder.forField(bankName) - .asRequired("Der BankName darf nicht leer sein.") - .bind(UserBank::getBankName, UserBank::setBankName); - - iban = new TextField(); - iban.setLabel("IBAN"); - bankBinder.forField(iban) - .asRequired("Die IBAN darf nicht leer sein.") - .bind(UserBank::getIban, UserBank::setIban); - - bic = new TextField(); - bic.setLabel("BIC"); - bankBinder.forField(bic).bind(UserBank::getBic, UserBank::setBic); - - adress1 = new TextField(); - adress1.setLabel("Straße"); - adressBinder.forField(adress1) - .asRequired("Die Straße muss angegeben sein.") - .bind(UserAdress::getAdress1, UserAdress::setAdress1); - - adress2 = new TextField(); - adress2.setLabel("Adresszusatz"); - adressBinder.forField(adress2) - .bind(UserAdress::getAdress2, UserAdress::setAdress2); - - zipCode = new TextField(); - zipCode.setLabel("Postleitzahl"); - adressBinder.forField(zipCode) - .asRequired("Die Postleitzahl muss angegeben sein.") - .bind(UserAdress::getZip, UserAdress::setZip); - - city = new TextField(); - city.setLabel("Ort"); - adressBinder.forField(city) - .asRequired("Der Ort muss angegeben sein.") - .bind(UserAdress::getCity, UserAdress::setCity); - - signatureImage = new Image(); - signatureImage.setAlt("Keine Unterschrift konfiguriert"); - - upload = new Upload(this::receiveUpload); - upload.addFinishedListener(ev -> updateSignatureImage()); - - VerticalLayout layout = new VerticalLayout(); - layout.add(prename, surname); - layout.add(new Hr()); - layout.add(bankName, iban, bic); - layout.add(new Hr()); - HorizontalLayout cityLayout = new HorizontalLayout(); - cityLayout.add(zipCode, city); - - layout.add(adress1, adress2, cityLayout, new FormLayout(signatureImage, upload)); - - okButton = new Button("OK", ev -> { - BinderValidationStatus bankValidation = bankBinder.validate(); - BinderValidationStatus adressValidation = adressBinder.validate(); - - if (bankValidation.isOk() && adressValidation.isOk()) { - user.setBank(bankBinder.getBean()); - user.setAdress(adressBinder.getBean()); - isValidAndClosedWithOk = true; - close(); - } - }); - - Button cancel = new Button("Abbrechen", ev -> close()); - - HorizontalLayout buttons = new HorizontalLayout(); - buttons.add(okButton, cancel); - layout.add(buttons); - - add(layout); - } - - private OutputStream receiveUpload(String filename, String mimeType) { - - Signature signature = new Signature(user); - try { - return signature.createOutputStream(filename); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } + prename = new TextField(); + prename.setLabel("Vorname"); + prename.setEnabled(false); + + surname = new TextField(); + surname.setLabel("Nachname"); + surname.setEnabled(false); + + bankName = new TextField(); + bankName.setLabel("Name der Bank"); + bankBinder.forField(bankName).asRequired("Der BankName darf nicht leer sein.").bind(UserBank::getBankName, + UserBank::setBankName); + + iban = new TextField(); + iban.setLabel("IBAN"); + bankBinder.forField(iban).asRequired("Die IBAN darf nicht leer sein.").bind(UserBank::getIban, + UserBank::setIban); + + bic = new TextField(); + bic.setLabel("BIC"); + bankBinder.forField(bic).bind(UserBank::getBic, UserBank::setBic); + + adress1 = new TextField(); + adress1.setLabel("Straße"); + adressBinder.forField(adress1).asRequired("Die Straße muss angegeben sein.").bind(UserAdress::getAdress1, + UserAdress::setAdress1); + + adress2 = new TextField(); + adress2.setLabel("Adresszusatz"); + adressBinder.forField(adress2).bind(UserAdress::getAdress2, UserAdress::setAdress2); + + zipCode = new TextField(); + zipCode.setLabel("Postleitzahl"); + adressBinder.forField(zipCode).asRequired("Die Postleitzahl muss angegeben sein.").bind(UserAdress::getZip, + UserAdress::setZip); + + city = new TextField(); + city.setLabel("Ort"); + adressBinder.forField(city).asRequired("Der Ort muss angegeben sein.").bind(UserAdress::getCity, + UserAdress::setCity); + + signatureImage = new Image(); + signatureImage.setAlt("Keine Unterschrift konfiguriert"); + + upload = new Upload(this::receiveUpload); + upload.addFinishedListener(ev -> updateSignatureImage()); + + VerticalLayout layout = new VerticalLayout(); + layout.add(prename, surname); + layout.add(new Hr()); + layout.add(bankName, iban, bic); + layout.add(new Hr()); + HorizontalLayout cityLayout = new HorizontalLayout(); + cityLayout.add(zipCode, city); + + layout.add(adress1, adress2, cityLayout, new FormLayout(signatureImage, upload)); + + okButton = new Button("OK", ev -> { + BinderValidationStatus bankValidation = bankBinder.validate(); + BinderValidationStatus adressValidation = adressBinder.validate(); + + if (bankValidation.isOk() && adressValidation.isOk()) { + user.setBank(bankBinder.getBean()); + user.setAdress(adressBinder.getBean()); + isValidAndClosedWithOk = true; + close(); + } + }); - public void setUser(User user) { + Button cancel = new Button("Abbrechen", ev -> close()); - this.user = Objects.requireNonNull(user); + HorizontalLayout buttons = new HorizontalLayout(); + buttons.add(okButton, cancel); + layout.add(buttons); - this.prename.setValue(user.getGivenName()); - this.surname.setValue(user.getFamilyName()); - bankBinder.setBean(user.getBank().clone()); - adressBinder.setBean(user.getAdress().clone()); - updateSignatureImage(); - } + add(layout); + } - public boolean isValidAndClosedWithOk() { - return isValidAndClosedWithOk; - } + private OutputStream receiveUpload(String filename, String mimeType) { - private void updateSignatureImage() { - if (user != null && user.getId() != null) { - upload.setUploadButton(null); - Signature signature = new Signature(user); - if (signature.isSignatureImageExists()) { - File signatureUrl = signature.getSignatureUrl(); - logger.info("Showing signature: {}", signatureUrl); + Signature signature = new Signature(user); + try { + return signature.createOutputStream(filename); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } - StreamResource resource = new StreamResource("Unterschrift", new InputStreamFactory() { + public void setUser(User user) { - private static final long serialVersionUID = 1L; + this.user = Objects.requireNonNull(user); - @Override - public InputStream createInputStream() { - try { - return new FileInputStream(signatureUrl); - } catch (FileNotFoundException e) { - throw new UncheckedIOException(e); + this.prename.setValue(user.getGivenName()); + this.surname.setValue(user.getFamilyName()); + bankBinder.setBean(user.getBank().clone()); + adressBinder.setBean(user.getAdress().clone()); + updateSignatureImage(); + } + + public boolean isValidAndClosedWithOk() { + return isValidAndClosedWithOk; + } + + private void updateSignatureImage() { + if (user != null && user.getId() != null) { + upload.setUploadButton(null); + Signature signature = new Signature(user); + if (signature.isSignatureImageExists()) { + File signatureUrl = signature.getSignatureUrl(); + logger.info("Showing signature: {}", signatureUrl); + + StreamResource resource = new StreamResource("Unterschrift", new InputStreamFactory() { + + private static final long serialVersionUID = 1L; + + @Override + public InputStream createInputStream() { + try { + return new FileInputStream(signatureUrl); + } catch (FileNotFoundException e) { + throw new UncheckedIOException(e); + } + } + }); + signatureImage.setWidth("192px"); + signatureImage.setHeight("62px"); + signatureImage.setSrc(resource); } - } - }); - signatureImage.setWidth("192px"); - signatureImage.setHeight("62px"); - signatureImage.setSrc(resource); - } - } else { - signatureImage.setWidth(null); - signatureImage.setHeight(null); - upload.setVisible(false); - signatureImage.setAlt( - "Eine Unterschrift kann konfiguriert werden, nachdem die Benutzerdaten gespeichert wurden."); + } else { + signatureImage.setWidth(null); + signatureImage.setHeight(null); + upload.setVisible(false); + signatureImage.setAlt( + "Eine Unterschrift kann konfiguriert werden, nachdem die Benutzerdaten gespeichert wurden."); + } } - } - public User getUser() { - return user; - } + public User getUser() { + return user; + } }