CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-eclipse-jetty--jetty-security

Security framework for Eclipse Jetty providing authentication, authorization, and user identity management.

Pending
Overview
Eval results
Files

security-framework.mddocs/

Security Framework

The core security framework provides the foundational interfaces and handlers for authentication and authorization in Jetty applications.

Core Interfaces

SecurityHandler

The SecurityHandler is the central component that orchestrates security for web applications.

public abstract class SecurityHandler extends Handler.Abstract {
    
    // Identity and authentication services
    public IdentityService getIdentityService();
    public void setIdentityService(IdentityService identityService);
    
    public LoginService getLoginService();
    public void setLoginService(LoginService loginService);
    
    public Authenticator getAuthenticator();
    public void setAuthenticator(Authenticator authenticator);
    
    public Authenticator.Factory getAuthenticatorFactory();
    public void setAuthenticatorFactory(Authenticator.Factory authenticatorFactory);
    
    // Realm configuration
    public String getRealmName();
    public void setRealmName(String realmName);
    
    public String getAuthenticationType();
    public void setAuthenticationType(String authenticationType);
    
    // Parameter management
    public String getParameter(String key);
    public String setParameter(String key, String value);
    
    // Session configuration
    public boolean isSessionRenewedOnAuthentication();
    public void setSessionRenewedOnAuthentication(boolean renew);
    
    public int getSessionMaxInactiveIntervalOnAuthentication();
    public void setSessionMaxInactiveIntervalOnAuthentication(int seconds);
    
    // Abstract method for constraint resolution
    protected abstract Constraint getConstraint(String pathInContext, Request request);
    
    // Static utility
    public static SecurityHandler getCurrentSecurityHandler();
}

PathMapped SecurityHandler

The concrete implementation using path mappings for constraints:

public static class PathMapped extends SecurityHandler {
    // Path-based constraint mapping
    public void put(String pathSpec, Constraint constraint);
    public Constraint get(String pathSpec);
    public boolean remove(String pathSpec);
    
    // Bulk operations
    public void putAll(Map<String, Constraint> constraints);
    public void clear();
    
    @Override
    protected Constraint getConstraint(String pathInContext, Request request) {
        // Implementation resolves constraint based on path mapping
    }
}

Constraint System

Constraint Interface

Defines security requirements for resources:

public interface Constraint {
    
    // Basic properties
    String getName();
    Transport getTransport();
    Authorization getAuthorization();
    Set<String> getRoles();
    
    // Authorization levels
    enum Authorization {
        FORBIDDEN,      // Access denied to all
        ALLOWED,        // Access allowed to all
        ANY_USER,       // Any authenticated user
        KNOWN_ROLE,     // User must have at least one role
        SPECIFIC_ROLE,  // User must have specific role(s)
        INHERIT         // Inherit from parent constraint
    }
    
    // Transport requirements
    enum Transport {
        SECURE,         // HTTPS required
        ANY,           // HTTP or HTTPS
        INHERIT        // Inherit from parent constraint
    }
    
    // Factory methods
    static Constraint from(String... roles);
    static Constraint from(String name, Transport transport);
    static Constraint from(String name, Authorization authorization, String... roles);
    static Constraint combine(Constraint leastSpecific, Constraint mostSpecific);
}

Predefined Constraints

public class ConstraintExamples {
    
    public void demonstrateConstraints() {
        // Allow all access
        Constraint allowAll = Constraint.ALLOWED;
        
        // Deny all access
        Constraint denyAll = Constraint.FORBIDDEN;
        
        // Require any authenticated user
        Constraint anyUser = Constraint.ANY_USER;
        
        // Require specific roles
        Constraint adminOnly = Constraint.from("admin");
        Constraint userOrMod = Constraint.from("user", "moderator");
        
        // Require HTTPS transport
        Constraint secureOnly = Constraint.SECURE_TRANSPORT;
        
        // Combined constraints
        Constraint secureAdmin = Constraint.from("SecureAdmin", 
            Constraint.Transport.SECURE, "admin");
    }
}

Authentication State

AuthenticationState Interface

Represents the current authentication status of a request:

public interface AuthenticationState {
    
    // Static utility methods
    static AuthenticationState getAuthenticationState(Request request);
    static void setAuthenticationState(Request request, AuthenticationState authenticationState);
    
    static Principal getUserPrincipal(Request request);
    static Succeeded authenticate(Request request);
    static Succeeded authenticate(Request request, Response response, Callback callback);
    
    static Succeeded login(String username, String password, Request request, Response response);
    static boolean logout(Request request, Response response);
    
    // Nested state interfaces
    interface Succeeded extends AuthenticationState {
        UserIdentity getUserIdentity();
        String getAuthenticationType();
    }
    
    interface ResponseSent extends AuthenticationState {
        // Marker interface for responses that were sent
    }
    
    interface Deferred extends AuthenticationState {
        AuthenticationState authenticate(Request request, Response response, Callback callback);
    }
}

Authentication State Constants

public class AuthenticationStates {
    
    public void handleAuthenticationStates(AuthenticationState state) {
        
        // Challenge was sent to client
        if (state == AuthenticationState.CHALLENGE) {
            // Client needs to provide credentials
        }
        
        // Failure response was sent
        else if (state == AuthenticationState.SEND_FAILURE) {
            // Authentication failed, error sent
        }
        
        // Success response was sent
        else if (state == AuthenticationState.SEND_SUCCESS) {
            // Authentication succeeded, response sent
        }
        
        // Successful authentication
        else if (state instanceof AuthenticationState.Succeeded) {
            AuthenticationState.Succeeded success = (AuthenticationState.Succeeded) state;
            UserIdentity user = success.getUserIdentity();
            String authType = success.getAuthenticationType();
        }
        
        // Deferred authentication
        else if (state instanceof AuthenticationState.Deferred) {
            AuthenticationState.Deferred deferred = (AuthenticationState.Deferred) state;
            // Authentication will be handled later
        }
    }
}

Authenticator Interface

Core Authenticator Methods

public interface Authenticator {
    
    // Authentication type constants
    String BASIC_AUTH = "BASIC";
    String FORM_AUTH = "FORM";
    String DIGEST_AUTH = "DIGEST";
    String CERT_AUTH = "CLIENT_CERT";
    String CERT_AUTH2 = "CLIENT-CERT";
    String SPNEGO_AUTH = "SPNEGO";
    String NEGOTIATE_AUTH = "NEGOTIATE";
    String OPENID_AUTH = "OPENID";
    
    // Configuration and identification
    void setConfiguration(Configuration configuration);
    String getAuthenticationType();
    
    // Request preparation and validation
    default Request prepareRequest(Request request, AuthenticationState authenticationState) {
        return request;
    }
    
    default Constraint.Authorization getConstraintAuthentication(String pathInContext, 
            Constraint.Authorization existing, Function<Boolean, Session> getSession) {
        return existing == null ? Constraint.Authorization.ALLOWED : existing;
    }
    
    AuthenticationState validateRequest(Request request, Response response, Callback callback) 
            throws ServerAuthException;
    
    // Nested configuration interface
    interface Configuration {
        String getRealmName();
        String getParameter(String key);
        LoginService getLoginService();
        IdentityService getIdentityService();
    }
    
    // Factory interface
    interface Factory {
        Authenticator getAuthenticator(Server server, Context context, Configuration configuration);
    }
}

DefaultAuthenticatorFactory

Default implementation of the Authenticator.Factory interface that creates authenticators based on configuration:

public class DefaultAuthenticatorFactory implements Authenticator.Factory {
    
    @Override
    public Authenticator getAuthenticator(Server server, Context context, Configuration configuration);
}

The DefaultAuthenticatorFactory creates authenticators based on the configured authentication type:

  • BASICBasicAuthenticator
  • DIGESTDigestAuthenticator
  • FORMFormAuthenticator
  • CLIENT-CERTSslClientCertAuthenticator (requires single SslContextFactory)
  • SPNEGO/NEGOTIATESPNEGOAuthenticator

LoginAuthenticator instances are wrapped with DeferredAuthenticationState for non-mandatory authentication scenarios.

ServerAuthException

Exception class for server-side authentication and authorization failures:

public class ServerAuthException extends GeneralSecurityException {
    
    // Constructors
    public ServerAuthException();
    public ServerAuthException(String message);
    public ServerAuthException(String message, Throwable cause);
    public ServerAuthException(Throwable cause);
}

Thrown by authenticators during request validation when authentication or authorization fails.

Practical Examples

Basic Security Setup

public class BasicSecuritySetup {
    
    public SecurityHandler createBasicSecurity() {
        SecurityHandler.PathMapped security = new SecurityHandler.PathMapped();
        
        // Configure realm
        security.setRealmName("MyApplication");
        
        // Set up login service
        HashLoginService loginService = new HashLoginService();
        loginService.setName("MyApplication");
        loginService.setConfig(Resource.newResource("users.properties"));
        security.setLoginService(loginService);
        
        // Configure authenticator
        BasicAuthenticator authenticator = new BasicAuthenticator();
        security.setAuthenticator(authenticator);
        
        // Define constraints
        security.put("/public/*", Constraint.ALLOWED);
        security.put("/users/*", Constraint.ANY_USER);
        security.put("/admin/*", Constraint.from("admin"));
        security.put("/api/secure/*", Constraint.from("SecureAPI", 
            Constraint.Transport.SECURE, "api-user"));
        
        return security;
    }
}

Advanced Security Configuration

public class AdvancedSecurityConfig {
    
    public void configureAdvancedSecurity(SecurityHandler security) {
        
        // Identity service for thread association
        DefaultIdentityService identityService = new DefaultIdentityService();
        security.setIdentityService(identityService);
        
        // Session security settings
        security.setSessionRenewedOnAuthentication(true);
        security.setSessionMaxInactiveIntervalOnAuthentication(1800); // 30 minutes
        
        // Custom authenticator factory
        security.setAuthenticatorFactory(new DefaultAuthenticatorFactory());
        
        // Parameters for authenticators
        security.setParameter("charset", "UTF-8");
        security.setParameter("realmName", "SecureRealm");
        
        // Complex constraint combinations
        setupComplexConstraints((SecurityHandler.PathMapped) security);
    }
    
    private void setupComplexConstraints(SecurityHandler.PathMapped security) {
        
        // Public resources - no authentication required
        security.put("/css/*", Constraint.ALLOWED);
        security.put("/js/*", Constraint.ALLOWED);
        security.put("/images/*", Constraint.ALLOWED);
        security.put("/favicon.ico", Constraint.ALLOWED);
        
        // API endpoints with role-based access
        security.put("/api/public/*", Constraint.ALLOWED);
        security.put("/api/users/*", Constraint.ANY_USER);
        security.put("/api/admin/*", Constraint.from("admin", "super-admin"));
        
        // Secure administrative areas requiring HTTPS
        security.put("/admin/*", Constraint.from("AdminArea", 
            Constraint.Transport.SECURE, "admin"));
        security.put("/config/*", Constraint.from("ConfigArea", 
            Constraint.Transport.SECURE, "super-admin"));
        
        // User-specific areas
        security.put("/user/*", Constraint.from("user", "premium-user"));
        security.put("/premium/*", Constraint.from("premium-user"));
    }
}

Custom Constraint Implementation

public class CustomConstraintExample {
    
    public static class TimeBasedConstraint implements Constraint {
        private final Constraint base;
        private final int startHour;
        private final int endHour;
        
        public TimeBasedConstraint(Constraint base, int startHour, int endHour) {
            this.base = base;
            this.startHour = startHour;
            this.endHour = endHour;
        }
        
        @Override
        public String getName() {
            return "TimeBased-" + base.getName();
        }
        
        @Override
        public Transport getTransport() {
            return base.getTransport();
        }
        
        @Override
        public Authorization getAuthorization() {
            int hour = LocalTime.now().getHour();
            if (hour >= startHour && hour < endHour) {
                return base.getAuthorization();
            }
            return Authorization.FORBIDDEN;
        }
        
        @Override
        public Set<String> getRoles() {
            return base.getRoles();
        }
    }
    
    public void useTimeBasedConstraints(SecurityHandler.PathMapped security) {
        // Business hours only access (9 AM to 6 PM)
        Constraint businessHours = new TimeBasedConstraint(
            Constraint.from("business-user"), 9, 18);
        security.put("/business/*", businessHours);
        
        // After-hours admin access
        Constraint afterHours = new TimeBasedConstraint(
            Constraint.from("admin"), 18, 9);
        security.put("/maintenance/*", afterHours);
    }
}

SecurityHandler Extension

public class CustomSecurityHandler extends SecurityHandler {
    private final Map<String, Constraint> dynamicConstraints = new ConcurrentHashMap<>();
    
    @Override
    protected Constraint getConstraint(String pathInContext, Request request) {
        
        // Check dynamic constraints first
        Constraint dynamic = dynamicConstraints.get(pathInContext);
        if (dynamic != null) {
            return dynamic;
        }
        
        // Check user-specific constraints
        UserIdentity user = getCurrentUser(request);
        if (user != null && user.isUserInRole("super-admin")) {
            return Constraint.ALLOWED; // Super admins bypass all constraints
        }
        
        // Default to forbidden for unknown paths
        return Constraint.FORBIDDEN;
    }
    
    public void addDynamicConstraint(String path, Constraint constraint) {
        dynamicConstraints.put(path, constraint);
    }
    
    public void removeDynamicConstraint(String path) {
        dynamicConstraints.remove(path);
    }
    
    private UserIdentity getCurrentUser(Request request) {
        AuthenticationState auth = AuthenticationState.getAuthenticationState(request);
        if (auth instanceof AuthenticationState.Succeeded) {
            return ((AuthenticationState.Succeeded) auth).getUserIdentity();
        }
        return null;
    }
}

Error Handling

Security Exceptions

public class SecurityErrorHandling {
    
    public void handleSecurityErrors(SecurityHandler security) {
        
        try {
            // Security operations that might fail
            Constraint constraint = security.getConstraint("/protected", request);
            
        } catch (ServerAuthException e) {
            // Handle authentication/authorization errors
            logger.error("Security error: " + e.getMessage(), e);
            
            // Send appropriate error response
            response.setStatus(HttpStatus.UNAUTHORIZED_401);
            response.getHeaders().put(HttpHeader.WWW_AUTHENTICATE, 
                "Basic realm=\"" + security.getRealmName() + "\"");
        }
    }
    
    public void customErrorHandling(Request request, Response response, Throwable error) {
        
        if (error instanceof ServerAuthException) {
            ServerAuthException authError = (ServerAuthException) error;
            
            // Log security violations
            logger.warn("Authentication failure for user: {} from IP: {}", 
                request.getHeaders().get("X-User"), 
                Request.getRemoteAddr(request));
            
            // Custom error page
            response.setStatus(HttpStatus.FORBIDDEN_403);
            response.getHeaders().put(HttpHeader.CONTENT_TYPE, "text/html");
            
            try {
                response.getWriter().write("<html><body>" +
                    "<h1>Access Denied</h1>" +
                    "<p>You do not have permission to access this resource.</p>" +
                    "</body></html>");
            } catch (IOException e) {
                logger.error("Error writing security error page", e);
            }
        }
    }
}

Best Practices

Security Configuration

public class SecurityBestPractices {
    
    public SecurityHandler createProductionSecurity() {
        SecurityHandler.PathMapped security = new SecurityHandler.PathMapped();
        
        // Always use strong realm names
        security.setRealmName("ProductionApp-" + UUID.randomUUID().toString());
        
        // Enable session renewal on authentication
        security.setSessionRenewedOnAuthentication(true);
        
        // Set reasonable session timeout
        security.setSessionMaxInactiveIntervalOnAuthentication(1800); // 30 minutes
        
        // Secure transport for sensitive operations
        security.put("/login/*", Constraint.from("Login", 
            Constraint.Transport.SECURE));
        security.put("/admin/*", Constraint.from("Admin", 
            Constraint.Transport.SECURE, "admin"));
        security.put("/api/payment/*", Constraint.from("Payment", 
            Constraint.Transport.SECURE, "payment-user"));
        
        return security;
    }
    
    public void secureDefaultsSetup(SecurityHandler security) {
        
        // Deny by default - explicit allow only
        security.put("/*", Constraint.FORBIDDEN);
        
        // Explicitly allow public resources
        security.put("/public/*", Constraint.ALLOWED);
        security.put("/health", Constraint.ALLOWED);
        security.put("/status", Constraint.ALLOWED);
        
        // Authenticated areas
        security.put("/app/*", Constraint.ANY_USER);
        security.put("/user/*", Constraint.ANY_USER);
        
        // Role-based areas
        security.put("/admin/*", Constraint.from("admin"));
        security.put("/reports/*", Constraint.from("admin", "manager"));
    }
}

Utility Classes

Resource

Utility class for configuration resource management:

public abstract class Resource {
    
    // Factory methods for creating resources
    public static Resource newResource(String resource);
    public static Resource newClassPathResource(String name);
    public static Resource newResource(URI uri);
    public static Resource newResource(File file);
    
    // Resource properties
    public abstract boolean exists();
    public abstract boolean isDirectory();
    public abstract String getName();
    public abstract URI getURI();
}

The Resource class provides abstracted access to configuration files, supporting filesystem paths, classpath resources, and URIs. Commonly used for specifying login service configuration files.

The Security Framework provides the foundation for all authentication and authorization in Jetty applications, offering flexible constraint definition, pluggable authenticators, and comprehensive security state management.

Install with Tessl CLI

npx tessl i tessl/maven-org-eclipse-jetty--jetty-security

docs

authentication.md

index.md

jaas.md

login-services.md

security-framework.md

user-identity.md

tile.json