Security konfiguriert.

master
Markus Kreth 2 years ago
parent d9333851cf
commit 406331d33e
  1. 6
      pom.xml
  2. 8
      src/main/java/de/kreth/invoice/config/KeycloakConfigResolverLocal.java
  3. 4
      src/main/java/de/kreth/invoice/config/SecurityUtils.java
  4. 98
      src/main/java/de/kreth/invoice/config/UiSecurityConfig.java
  5. 2
      src/main/java/de/kreth/invoice/views/View.java
  6. 304
      src/main/java/de/kreth/invoice/views/user/UserDetailsDialog.java

@ -116,7 +116,6 @@
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
<!-- <version>4.0.1</version> -->
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -163,6 +162,11 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>com.vaadin</groupId> <groupId>com.vaadin</groupId>
<artifactId>vaadin-testbench</artifactId> <artifactId>vaadin-testbench</artifactId>

@ -8,9 +8,9 @@ import org.springframework.context.annotation.Configuration;
@Configuration @Configuration
public class KeycloakConfigResolverLocal { public class KeycloakConfigResolverLocal {
@Bean @Bean
public KeycloakConfigResolver keyCloakConfigResolver() { public KeycloakConfigResolver keyCloakConfigResolver() {
return new KeycloakSpringBootConfigResolver(); return new KeycloakSpringBootConfigResolver();
} }
} }

@ -11,6 +11,10 @@ import org.springframework.security.core.context.SecurityContextHolder;
import com.vaadin.flow.shared.ApplicationConstants; import com.vaadin.flow.shared.ApplicationConstants;
public class SecurityUtils { public class SecurityUtils {
private SecurityUtils() {
}
/** /**
* Tests if the request is an internal framework request. The test consists of * 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 * checking if the request parameter is present and if its value is consistent

@ -22,60 +22,58 @@ import org.springframework.security.web.authentication.session.SessionAuthentica
@KeycloakConfiguration @KeycloakConfiguration
public class UiSecurityConfig extends KeycloakWebSecurityConfigurerAdapter { public class UiSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired @Autowired
private KeycloakClientRequestFactory factory; private KeycloakClientRequestFactory factory;
@Autowired @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) { public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keyCloakAuthProvider = keycloakAuthenticationProvider(); KeycloakAuthenticationProvider keyCloakAuthProvider = keycloakAuthenticationProvider();
keyCloakAuthProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); keyCloakAuthProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keyCloakAuthProvider); auth.authenticationProvider(keyCloakAuthProvider);
} }
@Bean @Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public KeycloakRestTemplate restTemplate() { public KeycloakRestTemplate restTemplate() {
return new KeycloakRestTemplate(factory); return new KeycloakRestTemplate(factory);
} }
@Bean @Bean
@Override @Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
} }
@Override @Override
public void configure(HttpSecurity http) throws Exception { public void configure(HttpSecurity http) throws Exception {
super.configure(http); super.configure(http);
http.cors().disable() http.cors().disable().csrf().disable().anonymous().disable().sessionManagement()
.csrf().disable() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().authorizeRequests()
.anonymous().disable() .requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll().anyRequest()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and() .hasAnyRole("admin", "INVOICE_USER");
.authorizeRequests().requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll() }
.anyRequest().hasAnyRole("ROLE_trainer", "ROLE_admin");
}
@Override @Override
public void configure(WebSecurity web) throws Exception { public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers( web.ignoring().antMatchers(
// Vaadin Flow static resources // // Vaadin Flow static resources //
"/VAADIN/**", "/VAADIN/**",
// the standard favicon URI // the standard favicon URI
"/favicon.ico", "/favicon.ico",
// the robots exclusion standard // the robots exclusion standard
"/robots.txt", "/robots.txt",
// web application manifest // // web application manifest //
"/manifest.webmanifest", "/sw.js", "/offline-page.html", "/manifest.webmanifest", "/sw.js", "/offline-page.html",
// (development mode) static resources // // (development mode) static resources //
"/frontend/**", "/frontend/**",
// (development mode) webjars // // (development mode) webjars //
"/webjars/**", "/webjars/**",
// (production mode) static resources // // (production mode) static resources //
"/frontend-es5/**", "/frontend-es6/**"); "/frontend-es5/**", "/frontend-es6/**");
} }
@Bean @Bean
public static KeycloakConfigResolver keycloakConfigResolver() { public static KeycloakConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver(); return new KeycloakSpringBootConfigResolver();
} }
} }

@ -5,7 +5,6 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; 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.ClickEvent;
import com.vaadin.flow.component.Text; import com.vaadin.flow.component.Text;
@ -42,7 +41,6 @@ import de.kreth.invoice.views.user.UserDetailsDialog;
@PageTitle("") @PageTitle("")
@Route(value = "") @Route(value = "")
@PreAuthorize("hasRole('INVOICE_USER')")
public class View extends VerticalLayout implements BeforeEnterObserver { public class View extends VerticalLayout implements BeforeEnterObserver {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

@ -33,44 +33,44 @@ import de.kreth.invoice.report.Signature;
public class UserDetailsDialog extends Dialog { 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<UserBank> bankBinder = new Binder<>(); private final Binder<UserBank> bankBinder = new Binder<>();
private final Binder<UserAdress> adressBinder = new Binder<>(); private final Binder<UserAdress> adressBinder = new Binder<>();
// private final TextField loginName; // 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 Image signatureImage;
private final Upload upload; 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.bankRepository = bankRepository;
// this.adressRepository = adressRepository; // this.adressRepository = adressRepository;
@ -78,151 +78,145 @@ public class UserDetailsDialog extends Dialog {
// loginName.setLabel("Login Name"); // loginName.setLabel("Login Name");
// loginName.setEnabled(false); // loginName.setEnabled(false);
prename = new TextField(); prename = new TextField();
prename.setLabel("Vorname"); prename.setLabel("Vorname");
prename.setEnabled(false); prename.setEnabled(false);
surname = new TextField(); surname = new TextField();
surname.setLabel("Nachname"); surname.setLabel("Nachname");
surname.setEnabled(false); surname.setEnabled(false);
bankName = new TextField(); bankName = new TextField();
bankName.setLabel("Name der Bank"); bankName.setLabel("Name der Bank");
bankBinder.forField(bankName) bankBinder.forField(bankName).asRequired("Der BankName darf nicht leer sein.").bind(UserBank::getBankName,
.asRequired("Der BankName darf nicht leer sein.") UserBank::setBankName);
.bind(UserBank::getBankName, UserBank::setBankName);
iban = new TextField();
iban = new TextField(); iban.setLabel("IBAN");
iban.setLabel("IBAN"); bankBinder.forField(iban).asRequired("Die IBAN darf nicht leer sein.").bind(UserBank::getIban,
bankBinder.forField(iban) UserBank::setIban);
.asRequired("Die IBAN darf nicht leer sein.")
.bind(UserBank::getIban, UserBank::setIban); bic = new TextField();
bic.setLabel("BIC");
bic = new TextField(); bankBinder.forField(bic).bind(UserBank::getBic, UserBank::setBic);
bic.setLabel("BIC");
bankBinder.forField(bic).bind(UserBank::getBic, UserBank::setBic); adress1 = new TextField();
adress1.setLabel("Straße");
adress1 = new TextField(); adressBinder.forField(adress1).asRequired("Die Straße muss angegeben sein.").bind(UserAdress::getAdress1,
adress1.setLabel("Straße"); UserAdress::setAdress1);
adressBinder.forField(adress1)
.asRequired("Die Straße muss angegeben sein.") adress2 = new TextField();
.bind(UserAdress::getAdress1, UserAdress::setAdress1); adress2.setLabel("Adresszusatz");
adressBinder.forField(adress2).bind(UserAdress::getAdress2, UserAdress::setAdress2);
adress2 = new TextField();
adress2.setLabel("Adresszusatz"); zipCode = new TextField();
adressBinder.forField(adress2) zipCode.setLabel("Postleitzahl");
.bind(UserAdress::getAdress2, UserAdress::setAdress2); adressBinder.forField(zipCode).asRequired("Die Postleitzahl muss angegeben sein.").bind(UserAdress::getZip,
UserAdress::setZip);
zipCode = new TextField();
zipCode.setLabel("Postleitzahl"); city = new TextField();
adressBinder.forField(zipCode) city.setLabel("Ort");
.asRequired("Die Postleitzahl muss angegeben sein.") adressBinder.forField(city).asRequired("Der Ort muss angegeben sein.").bind(UserAdress::getCity,
.bind(UserAdress::getZip, UserAdress::setZip); UserAdress::setCity);
city = new TextField(); signatureImage = new Image();
city.setLabel("Ort"); signatureImage.setAlt("Keine Unterschrift konfiguriert");
adressBinder.forField(city)
.asRequired("Der Ort muss angegeben sein.") upload = new Upload(this::receiveUpload);
.bind(UserAdress::getCity, UserAdress::setCity); upload.addFinishedListener(ev -> updateSignatureImage());
signatureImage = new Image(); VerticalLayout layout = new VerticalLayout();
signatureImage.setAlt("Keine Unterschrift konfiguriert"); layout.add(prename, surname);
layout.add(new Hr());
upload = new Upload(this::receiveUpload); layout.add(bankName, iban, bic);
upload.addFinishedListener(ev -> updateSignatureImage()); layout.add(new Hr());
HorizontalLayout cityLayout = new HorizontalLayout();
VerticalLayout layout = new VerticalLayout(); cityLayout.add(zipCode, city);
layout.add(prename, surname);
layout.add(new Hr()); layout.add(adress1, adress2, cityLayout, new FormLayout(signatureImage, upload));
layout.add(bankName, iban, bic);
layout.add(new Hr()); okButton = new Button("OK", ev -> {
HorizontalLayout cityLayout = new HorizontalLayout(); BinderValidationStatus<UserBank> bankValidation = bankBinder.validate();
cityLayout.add(zipCode, city); BinderValidationStatus<UserAdress> adressValidation = adressBinder.validate();
layout.add(adress1, adress2, cityLayout, new FormLayout(signatureImage, upload)); if (bankValidation.isOk() && adressValidation.isOk()) {
user.setBank(bankBinder.getBean());
okButton = new Button("OK", ev -> { user.setAdress(adressBinder.getBean());
BinderValidationStatus<UserBank> bankValidation = bankBinder.validate(); isValidAndClosedWithOk = true;
BinderValidationStatus<UserAdress> adressValidation = adressBinder.validate(); close();
}
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);
}
}
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()); add(layout);
this.surname.setValue(user.getFamilyName()); }
bankBinder.setBean(user.getBank().clone());
adressBinder.setBean(user.getAdress().clone());
updateSignatureImage();
}
public boolean isValidAndClosedWithOk() { private OutputStream receiveUpload(String filename, String mimeType) {
return isValidAndClosedWithOk;
}
private void updateSignatureImage() { Signature signature = new Signature(user);
if (user != null && user.getId() != null) { try {
upload.setUploadButton(null); return signature.createOutputStream(filename);
Signature signature = new Signature(user); } catch (IOException e) {
if (signature.isSignatureImageExists()) { throw new UncheckedIOException(e);
File signatureUrl = signature.getSignatureUrl(); }
logger.info("Showing signature: {}", signatureUrl); }
StreamResource resource = new StreamResource("Unterschrift", new InputStreamFactory() { public void setUser(User user) {
private static final long serialVersionUID = 1L; this.user = Objects.requireNonNull(user);
@Override this.prename.setValue(user.getGivenName());
public InputStream createInputStream() { this.surname.setValue(user.getFamilyName());
try { bankBinder.setBean(user.getBank().clone());
return new FileInputStream(signatureUrl); adressBinder.setBean(user.getAdress().clone());
} catch (FileNotFoundException e) { updateSignatureImage();
throw new UncheckedIOException(e); }
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);
} }
} } else {
}); signatureImage.setWidth(null);
signatureImage.setWidth("192px"); signatureImage.setHeight(null);
signatureImage.setHeight("62px"); upload.setVisible(false);
signatureImage.setSrc(resource); 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() { public User getUser() {
return user; return user;
} }
} }

Loading…
Cancel
Save