CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-vaadin--vaadin

Comprehensive Java web application development framework that enables server-side Java development with modern web UI components and automatic client-server communication.

Overview
Eval results
Files

security.mddocs/

Security

Vaadin provides comprehensive security features including authentication, authorization, CSRF protection, and integration with popular security frameworks like Spring Security. The platform includes both declarative and programmatic security approaches.

Core Imports

// Security annotations
import com.vaadin.flow.server.auth.AnonymousAllowed;
import com.vaadin.flow.server.auth.PermitAll;
import com.vaadin.flow.server.auth.DenyAll;
import com.vaadin.flow.server.auth.RolesAllowed;

// Login components
import com.vaadin.flow.component.login.LoginForm;
import com.vaadin.flow.component.login.LoginOverlay;
import com.vaadin.flow.component.login.AbstractLogin.LoginEvent;
import com.vaadin.flow.component.login.AbstractLogin.ForgotPasswordEvent;
import com.vaadin.flow.component.login.LoginI18n;

// Navigation guards and observers
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeLeaveObserver;
import com.vaadin.flow.router.BeforeLeaveEvent;

// Session and security context
import com.vaadin.flow.server.VaadinSession;
import com.vaadin.flow.server.VaadinService;
import com.vaadin.flow.server.VaadinRequest;
import com.vaadin.flow.component.UI;

// Component events
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.shared.Registration;

// Spring Security integration
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

// Spring Security configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

// Method-level security
import org.springframework.security.access.prepost.PreAuthorize;

// Spring framework
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

// Servlet configuration
import com.vaadin.flow.server.VaadinServlet;
import com.vaadin.flow.server.VaadinServletConfiguration;
import javax.servlet.annotation.WebServlet;
import javax.servlet.ServletException;

// Standard Java types
import java.security.Principal;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;

// Logging
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// Core components
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.grid.Grid;

// Route annotations
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.PageTitle;

Authentication Annotations

Core Security Annotations

Built-in annotations for declarative access control.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnonymousAllowed {
    // Allows access to anonymous (unauthenticated) users
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PermitAll {
    // Allows access to all authenticated users
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DenyAll {
    // Denies access to all users
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RolesAllowed {
    String[] value();  // Specifies allowed roles
}

Authentication Integration

SecurityContext Access

Access current authentication information.

// Spring Security integration
public class SecurityService {

    public UserDetails getAuthenticatedUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            Object principal = authentication.getPrincipal();
            if (principal instanceof UserDetails) {
                return (UserDetails) principal;
            }
        }
        return null;
    }

    public boolean isAuthenticated() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication != null &&
               authentication.isAuthenticated() &&
               !(authentication instanceof AnonymousAuthenticationToken);
    }

    public boolean hasRole(String role) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            return authentication.getAuthorities().stream()
                    .anyMatch(authority -> authority.getAuthority().equals("ROLE_" + role));
        }
        return false;
    }

    public void logout() {
        SecurityContextHolder.clearContext();
        VaadinSession.getCurrent().getSession().invalidate();
        UI.getCurrent().navigate("");
    }
}

Login Components

Built-in login form components with customization options.

public class LoginForm extends Component {
    public LoginForm();

    // Event handling
    public Registration addLoginListener(ComponentEventListener<LoginEvent> listener);
    public Registration addForgotPasswordListener(ComponentEventListener<ForgotPasswordEvent> listener);

    // Configuration
    public void setError(boolean error);
    public boolean isError();
    public void setEnabled(boolean enabled);
    public boolean isEnabled();

    // Internationalization
    public void setI18n(LoginI18n i18n);
    public LoginI18n getI18n();

    // Actions
    public void setAction(String action);
    public String getAction();
    public void setForgotPasswordButtonVisible(boolean forgotPasswordButtonVisible);
    public boolean isForgotPasswordButtonVisible();
}

public class LoginOverlay extends LoginForm {
    public LoginOverlay();

    // Overlay control
    public void setOpened(boolean opened);
    public boolean isOpened();

    // Title and description
    public void setTitle(String title);
    public String getTitle();
    public void setDescription(String description);
    public String getDescription();
}

// Login events
public class LoginEvent extends ComponentEvent<LoginForm> {
    public LoginEvent(LoginForm source, boolean fromClient, String username, String password);

    public String getUsername();
    public String getPassword();
}

public class ForgotPasswordEvent extends ComponentEvent<LoginForm> {
    public ForgotPasswordEvent(LoginForm source, boolean fromClient, String username);

    public String getUsername();
}

// Internationalization
public class LoginI18n {
    public Header getHeader();
    public void setHeader(Header header);
    public Form getForm();
    public void setForm(Form form);
    public ErrorMessage getErrorMessage();
    public void setErrorMessage(ErrorMessage errorMessage);

    public static class Header {
        public String getTitle();
        public void setTitle(String title);
        public String getDescription();
        public void setDescription(String description);
    }

    public static class Form {
        public String getTitle();
        public void setTitle(String title);
        public String getUsername();
        public void setUsername(String username);
        public String getPassword();
        public void setPassword(String password);
        public String getSubmit();
        public void setSubmit(String submit);
        public String getForgotPassword();
        public void setForgotPassword(String forgotPassword);
    }

    public static class ErrorMessage {
        public String getTitle();
        public void setTitle(String title);
        public String getMessage();
        public void setMessage(String message);
    }
}

Authorization and Access Control

Navigation Guards

Implement authorization at the navigation level.

public interface BeforeEnterObserver {
    void beforeEnter(BeforeEnterEvent event);
}

// Example navigation guard
@Component
public class AuthenticationGuard implements BeforeEnterObserver {

    @Autowired
    private SecurityService securityService;

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        if (!securityService.isAuthenticated()) {
            // Redirect to login if not authenticated
            event.rerouteTo(LoginView.class);
        }
    }
}

// Role-based navigation guard
public class RoleBasedGuard implements BeforeEnterObserver {

    private final String requiredRole;

    public RoleBasedGuard(String requiredRole) {
        this.requiredRole = requiredRole;
    }

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        if (!hasRequiredRole()) {
            event.rerouteTo(AccessDeniedView.class);
        }
    }

    private boolean hasRequiredRole() {
        // Check if current user has required role
        return SecurityContextHolder.getContext().getAuthentication()
                .getAuthorities().stream()
                .anyMatch(auth -> auth.getAuthority().equals("ROLE_" + requiredRole));
    }
}

Programmatic Security

Programmatic access control within views and components.

public class SecurityUtils {

    public static boolean isUserLoggedIn() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication != null &&
               authentication.isAuthenticated() &&
               !(authentication instanceof AnonymousAuthenticationToken);
    }

    public static boolean hasRole(String role) {
        return SecurityContextHolder.getContext().getAuthentication()
                .getAuthorities().stream()
                .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ROLE_" + role));
    }

    public static boolean hasAnyRole(String... roles) {
        return Arrays.stream(roles).anyMatch(SecurityUtils::hasRole);
    }

    public static String getCurrentUsername() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            return authentication.getName();
        }
        return null;
    }

    public static Optional<Object> getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            return Optional.ofNullable(authentication.getPrincipal());
        }
        return Optional.empty();
    }
}

CSRF Protection

CSRF Token Handling

Built-in CSRF protection with token management.

public class CSRFTokenService {

    // CSRF tokens are automatically handled by Vaadin
    // Manual token access for custom scenarios

    public String getCSRFToken() {
        VaadinSession session = VaadinSession.getCurrent();
        if (session != null) {
            String token = (String) session.getAttribute("csrf-token");
            if (token == null) {
                token = generateCSRFToken();
                session.setAttribute("csrf-token", token);
            }
            return token;
        }
        return null;
    }

    public boolean validateCSRFToken(String token) {
        String sessionToken = getCSRFToken();
        return sessionToken != null && sessionToken.equals(token);
    }

    private String generateCSRFToken() {
        return UUID.randomUUID().toString();
    }
}

Session Security

Session Management

Secure session handling and management.

public class SessionSecurityService {

    public void invalidateSession() {
        VaadinSession vaadinSession = VaadinSession.getCurrent();
        if (vaadinSession != null) {
            // Clear security context
            SecurityContextHolder.clearContext();

            // Invalidate session
            vaadinSession.close();

            // Redirect to login
            UI.getCurrent().getPage().setLocation("/login");
        }
    }

    public void refreshSession() {
        VaadinSession session = VaadinSession.getCurrent();
        if (session != null) {
            // Force session regeneration for security
            session.lock();
            try {
                // Migrate session data if needed
                Object userData = session.getAttribute("user-data");
                session.close();

                // Create new session
                VaadinSession newSession = VaadinSession.getCurrent();
                if (userData != null) {
                    newSession.setAttribute("user-data", userData);
                }
            } finally {
                session.unlock();
            }
        }
    }

    public void setSessionTimeout(int timeoutInSeconds) {
        VaadinSession session = VaadinSession.getCurrent();
        if (session != null) {
            session.getSession().setMaxInactiveInterval(timeoutInSeconds);
        }
    }

    public boolean isSessionExpired() {
        VaadinSession session = VaadinSession.getCurrent();
        return session == null || session.isClosed();
    }
}

Content Security Policy

CSP Configuration

Content Security Policy configuration for enhanced security.

@WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
@VaadinServletConfiguration(ui = MyUI.class)
public class MyUIServlet extends VaadinServlet {

    @Override
    protected void servletInitialized() throws ServletException {
        super.servletInitialized();

        // Configure CSP headers
        getService().addSessionInitListener(event -> {
            event.getSource().addBootstrapListener(response -> {
                response.setHeader("Content-Security-Policy",
                    "default-src 'self'; " +
                    "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " +
                    "style-src 'self' 'unsafe-inline'; " +
                    "img-src 'self' data: https:; " +
                    "connect-src 'self' ws: wss:; " +
                    "font-src 'self'; " +
                    "object-src 'none'; " +
                    "media-src 'self'; " +
                    "frame-src 'none';"
                );
            });
        });
    }
}

Input Validation and Sanitization

Data Validation

Server-side validation for security and data integrity.

public class SecurityValidator {

    private static final Pattern SQL_INJECTION_PATTERN =
        Pattern.compile("('.+--)|(--.+)|('.+#)|(#.+)|(\\b(select|insert|update|delete|drop|create|alter|exec|execute|union|script)\\b)",
                       Pattern.CASE_INSENSITIVE);

    private static final Pattern XSS_PATTERN =
        Pattern.compile("<\\s*script\\s*.*?>|<\\s*\\/\\s*script\\s*>|javascript:|vbscript:|onload=|onerror=|onmouseover=",
                       Pattern.CASE_INSENSITIVE);

    public static boolean containsSQLInjection(String input) {
        if (input == null) return false;
        return SQL_INJECTION_PATTERN.matcher(input).find();
    }

    public static boolean containsXSS(String input) {
        if (input == null) return false;
        return XSS_PATTERN.matcher(input).find();
    }

    public static String sanitizeInput(String input) {
        if (input == null) return null;

        // Remove potentially dangerous characters
        String sanitized = input.replaceAll("[<>\"'%;()&+]", "");

        // Limit length
        if (sanitized.length() > 1000) {
            sanitized = sanitized.substring(0, 1000);
        }

        return sanitized.trim();
    }

    public static boolean isValidEmail(String email) {
        return email != null &&
               email.matches("^[A-Za-z0-9+_.-]+@([A-Za-z0-9.-]+\\.[A-Za-z]{2,})$") &&
               email.length() <= 254;
    }

    public static boolean isValidUsername(String username) {
        return username != null &&
               username.matches("^[a-zA-Z0-9_.-]{3,50}$");
    }
}

Security Event Handling

Security Events

Handle security-related events and logging.

public class SecurityEventService {

    private static final Logger logger = LoggerFactory.getLogger(SecurityEventService.class);

    public void logSuccessfulLogin(String username, String ipAddress) {
        logger.info("Successful login - User: {}, IP: {}", username, ipAddress);
        // Store in audit log
    }

    public void logFailedLogin(String username, String ipAddress) {
        logger.warn("Failed login attempt - User: {}, IP: {}", username, ipAddress);
        // Implement brute force protection
    }

    public void logLogout(String username) {
        logger.info("User logout - User: {}", username);
    }

    public void logSecurityViolation(String username, String violation, String details) {
        logger.error("Security violation - User: {}, Violation: {}, Details: {}",
                    username, violation, details);
        // Alert security team
    }

    public void logAccessDenied(String username, String resource) {
        logger.warn("Access denied - User: {}, Resource: {}", username, resource);
    }
}

Secure Configuration

Security Configuration

Best practices for secure Vaadin application configuration.

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(12);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/login", "/register", "/public/**").permitAll()
                        .requestMatchers("/admin/**").hasRole("ADMIN")
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login")
                        .defaultSuccessUrl("/dashboard")
                        .failureUrl("/login?error=true")
                        .permitAll()
                )
                .logout(logout -> logout
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/login")
                        .invalidateHttpSession(true)
                        .deleteCookies("JSESSIONID")
                        .permitAll()
                )
                .sessionManagement(session -> session
                        .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                        .maximumSessions(1)
                        .maxSessionsPreventsLogin(false)
                )
                .csrf(csrf -> csrf
                        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                )
                .headers(headers -> headers
                        .frameOptions().deny()
                        .contentTypeOptions().and()
                        .httpStrictTransportSecurity(hsts -> hsts
                                .maxAgeInSeconds(31536000)
                                .includeSubdomains(true)
                        )
                )
                .build();
    }
}

Usage Examples

Secured View Implementation

@Route("admin/users")
@PageTitle("User Management")
@RolesAllowed("ADMIN")
public class UserManagementView extends VerticalLayout implements BeforeEnterObserver {

    @Autowired
    private SecurityService securityService;

    @Autowired
    private UserService userService;

    private Grid<User> userGrid;

    public UserManagementView() {
        setupUI();
    }

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        // Additional security check
        if (!securityService.hasRole("ADMIN")) {
            event.rerouteTo(AccessDeniedView.class);
            return;
        }

        // Log access
        String currentUser = securityService.getAuthenticatedUser().getUsername();
        logger.info("Admin access - User: {}, View: UserManagement", currentUser);
    }

    private void setupUI() {
        H1 title = new H1("User Management");

        userGrid = new Grid<>(User.class);
        configureGrid();

        Button addUserButton = new Button("Add User");
        addUserButton.addClickListener(e -> addUser());

        add(title, addUserButton, userGrid);
    }

    private void configureGrid() {
        userGrid.setColumns("username", "email", "role", "lastLogin");
        userGrid.addComponentColumn(user -> createActionButtons(user))
                .setHeader("Actions");

        userGrid.setItems(userService.findAll());
    }

    private Component createActionButtons(User user) {
        Button editButton = new Button("Edit");
        editButton.addClickListener(e -> editUser(user));

        Button deleteButton = new Button("Delete");
        deleteButton.addClickListener(e -> confirmDeleteUser(user));
        deleteButton.getStyle().set("color", "var(--lumo-error-color)");

        return new HorizontalLayout(editButton, deleteButton);
    }
}

Login View with Security

@Route("login")
@PageTitle("Login")
@AnonymousAllowed
public class LoginView extends VerticalLayout {

    @Autowired
    private SecurityEventService securityEventService;

    private LoginForm loginForm;

    public LoginView() {
        setupUI();
    }

    private void setupUI() {
        setSizeFull();
        setJustifyContentMode(JustifyContentMode.CENTER);
        setAlignItems(Alignment.CENTER);

        loginForm = new LoginForm();
        loginForm.setAction("login");
        loginForm.addLoginListener(this::handleLogin);

        // Customize appearance
        LoginI18n i18n = LoginI18n.createDefault();
        i18n.getForm().setTitle("Secure Application");
        i18n.getForm().setUsername("Username");
        i18n.getForm().setPassword("Password");
        i18n.getForm().setSubmit("Sign In");
        loginForm.setI18n(i18n);

        add(loginForm);
    }

    private void handleLogin(LoginEvent event) {
        String username = event.getUsername();
        String ipAddress = getClientIP();

        try {
            // Validate input
            if (!SecurityValidator.isValidUsername(username)) {
                loginForm.setError(true);
                securityEventService.logSecurityViolation(username, "Invalid username format", ipAddress);
                return;
            }

            // Additional security checks can be added here
            securityEventService.logSuccessfulLogin(username, ipAddress);

        } catch (Exception e) {
            loginForm.setError(true);
            securityEventService.logFailedLogin(username, ipAddress);
        }
    }

    private String getClientIP() {
        VaadinRequest request = VaadinService.getCurrentRequest();
        return request != null ? request.getRemoteAddr() : "unknown";
    }
}

Secure Data Access

@Service
public class SecureUserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private SecurityEventService securityEventService;

    @PreAuthorize("hasRole('ADMIN') or authentication.name == #username")
    public User getUserByUsername(String username) {
        // Validate input
        if (!SecurityValidator.isValidUsername(username)) {
            throw new IllegalArgumentException("Invalid username format");
        }

        return userRepository.findByUsername(username);
    }

    @PreAuthorize("hasRole('ADMIN')")
    public List<User> getAllUsers() {
        String currentUser = SecurityContextHolder.getContext()
                .getAuthentication().getName();

        securityEventService.logSecurityViolation(currentUser,
                "Admin access", "Retrieved all users");

        return userRepository.findAll();
    }

    @PreAuthorize("hasRole('ADMIN') or authentication.name == #user.username")
    public User saveUser(User user) {
        // Sanitize input
        user.setEmail(SecurityValidator.sanitizeInput(user.getEmail()));
        user.setUsername(SecurityValidator.sanitizeInput(user.getUsername()));

        // Validate data
        if (!SecurityValidator.isValidEmail(user.getEmail())) {
            throw new IllegalArgumentException("Invalid email format");
        }

        return userRepository.save(user);
    }
}

The security system provides comprehensive protection while maintaining ease of development through declarative annotations and programmatic APIs.

Install with Tessl CLI

npx tessl i tessl/maven-com-vaadin--vaadin

docs

components.md

data-binding.md

data-components.md

index.md

layouts.md

routing.md

security.md

server-communication.md

theming.md

tile.json