Check the network tab. If it is related to spring security then most probably some endpoint that is called by vaadin is secured.
Check for Response Codes 401 and 403
I am sorry, I think I can’t help you with the Json-Error.
But I think the other problem is caused by the first one. After the error, the connection to the server might be broken, and so no more business logic is triggered in the backend.
You should try to disable spring security. Is the problem then gone?
I just wanted to give you my working security config… then i got it:
I DO have the same issue! What I did was explicit forcing authentication on my spring controllers, while
permitAll on the rest.
The reason for that was exactly what you describe.
My SecurityConfig is as follows:
@Configuration
@Profile("multi-user")
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ServerSecurityConfig extends WebSecurityConfigurerAdapter implements InitializingBean {
@Autowired
HofficeUserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/files/**", "/fahrtkosten/**","/app/**","/rechnungen/**",
"/worklog/**","/stammdaten/**","/archive/**","/fahrten/**","/stats/**")
.authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(authPointEntry()).and()
.authorizeRequests().anyRequest().permitAll(); //App security handled by Vaadin
}
@Bean
public LoginUrlAuthenticationEntryPoint authPointEntry(){
return new CustomAuthPointEntry("/login");
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
// Vaadin Flow static resources
"/VAADIN/**",
// the standard favicon URI
"/favicon.ico",
// web application manifest
"/manifest.json",
// icons and images
"/icons/**",
"/images/**",
// (development mode) static resources
"/frontend/**",
// (development mode) webjars
"/webjars/**",
// (production mode) static resources
"/frontend-es5/**", "/frontend-es6/**");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider createDaoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
@Bean
public RememberMeAuthenticationProvider tokenAuthenticationProvider() {
return new RememberMeAuthenticationProvider(Constants.REMEMBER_ME_TOKEN_KEY);
}
@Bean
public AuditorAware<String> auditorAware() {
return new AuditorAwareImpl();
}
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
@Override
/*
* Make async threads run with the same context
* This is requires by the OCR processor to save the content
* */
public void afterPropertiesSet() {
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
There MUST be some path missing in the ignoring-part.
But I did not figure out which one so far.
My Security-Logic is the following:
If you have a valid Spring-Session the you may enter.
Otherwise you will be redirected to a token-login-page, that tries to read a RememberMeToken from the local-storage on client side.
If this is successfull you get logged in and redirected to where you wanted to go, otherwise you will be redirected to the login view.
I need the RememberMeToken to be in the localstorage, because if I put the App on the IOS Home Screen, then the cookies are not kept between multiple accessed to the app.
Olli Tietäväinen:
You are possibly executing that JavaScript snippet too early, e.g. in the constructor of a component. In that case, the element you’re trying to find wouldn’t exist yet, hence the error. Try moving the executeJavaScript call to an onAttach method instead.
Danko Pavlinovic:
Hi,
Someone posted this solution with ironform (can’t remember who and where exactly), and it’s working for me.
This is just Login view class. Rest of the implementation (WebSecurityConfigurerAdapter implementation, SecurityUtils…) is the same as in Bakery starter project.
@Route("login")
@Theme(value = Lumo.class, variant = Lumo.DARK)
@HtmlImport("frontend://bower_components/iron-form/iron-form.html")
public class Login extends VerticalLayout implements PageConfigurator, AfterNavigationObserver{
public Login() {
TextField userNameTextField = new TextField();
userNameTextField.getElement().setAttribute("name", "username");
PasswordField passwordField = new PasswordField();
passwordField.getElement().setAttribute("name", "password");
Button submitButton = new Button("Login");
submitButton.setId("submitbutton");
submitButton.setVisible(true);
UI.getCurrent().getPage().executeJavaScript("document.getElementById('submitbutton').addEventListener('click', () => document.getElementById('ironform').submit());");
NativeButton submitButtonNative = new NativeButton("Login (native)");
submitButton.getElement().setAttribute("type", "submit");
FormLayout formLayout = new FormLayout();
formLayout.add( userNameTextField, passwordField,submitButton,submitButtonNative);
Element formElement = new Element("form");
formElement.setAttribute("method", "post");
formElement.setAttribute("action", "login");
formElement.appendChild(formLayout.getElement());
Element ironForm = new Element("iron-form");
ironForm.setAttribute("id", "ironform");
ironForm.setAttribute("allow-redirect", true);
ironForm.appendChild(formElement);
getElement().appendChild(ironForm);
setClassName("login");
}
@Override
public void configurePage(InitialPageSettings settings) {
// Force login page to use Shady DOM to avoid problems with browsers and
// password managers not supporting shadow DOM
settings.addInlineWithContents(InitialPageSettings.Position.PREPEND,
"window.customElements=window.customElements||{};" +
"window.customElements.forcePolyfill=true;" +
"window.ShadyDOM={force:true};", InitialPageSettings.WrapMode.JAVASCRIPT);
}
@Override
public void afterNavigation(AfterNavigationEvent event) {
boolean error = event.getLocation().getQueryParameters().getParameters().containsKey("error");
}
public interface Model extends TemplateModel {
void setError(boolean error);
}
}
Is there an easy way to accomplish this without using Thymeleaf, Polymer elements or HTML imports?
Here is my working LoginView class (you can even leave out the LocaleChangeObserver which is used here to re-translate the form if user changes locale):
It is still work in progress and I would like to collect some feedback before extending it. As it is based on Vaadin 12 it does not contain an example with the new login component, yet.