001/* 002 * Copyright © 2025 CUI-OpenSource-Software (info@cuioss.de) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package de.cuioss.http.security.pipeline; 017 018import de.cuioss.http.security.config.SecurityConfiguration; 019import de.cuioss.http.security.core.HttpSecurityValidator; 020import de.cuioss.http.security.core.ValidationType; 021import de.cuioss.http.security.monitoring.SecurityEventCounter; 022import de.cuioss.http.security.validation.*; 023import lombok.EqualsAndHashCode; 024import lombok.Getter; 025import lombok.ToString; 026 027import java.util.List; 028import java.util.Objects; 029 030/** 031 * Sequential validation pipeline specifically for URL parameter components. 032 * 033 * <h3>Validation Sequence</h3> 034 * <ol> 035 * <li><strong>Length Validation</strong> - Enforces maximum parameter length limits</li> 036 * <li><strong>Character Validation</strong> - Validates RFC 3986 query characters</li> 037 * <li><strong>Decoding</strong> - URL decodes with security checks</li> 038 * <li><strong>Normalization</strong> - Parameter normalization and security checks</li> 039 * <li><strong>Pattern Matching</strong> - Detects injection attacks and suspicious patterns</li> 040 * </ol> 041 * 042 * <h3>Design Principles</h3> 043 * <ul> 044 * <li><strong>Sequential Execution</strong> - Each stage processes the output of the previous stage</li> 045 * <li><strong>Early Termination</strong> - Pipeline stops on first security violation</li> 046 * <li><strong>Security First</strong> - Validates before any transformation</li> 047 * <li><strong>Immutable</strong> - Thread-safe pipeline instance</li> 048 * </ul> 049 * 050 * <h3>Usage Example</h3> 051 * <pre> 052 * SecurityConfiguration config = SecurityConfiguration.defaults(); 053 * SecurityEventCounter counter = new SecurityEventCounter(); 054 * 055 * URLParameterValidationPipeline pipeline = new URLParameterValidationPipeline(config, counter); 056 * 057 * try { 058 * String safeParam = pipeline.validate("user_id=123"); 059 * // Use safeParam for processing 060 * } catch (UrlSecurityException e) { 061 * // Handle security violation 062 * log.warn("Parameter validation failed: {}", e.getMessage()); 063 * } 064 * </pre> 065 * 066 * Implements: Task P2 from HTTP verification specification 067 * 068 * @since 1.0 069 */ 070@EqualsAndHashCode(callSuper = false, of = {}) 071@ToString(callSuper = true) 072@Getter 073@SuppressWarnings("ClassCanBeRecord") 074public final class URLParameterValidationPipeline extends AbstractValidationPipeline { 075 076 private static final ValidationType VALIDATION_TYPE = ValidationType.PARAMETER_VALUE; 077 078 /** 079 * Creates a new URL parameter validation pipeline with the specified configuration. 080 * 081 * @param config The security configuration to use 082 * @param eventCounter The counter for tracking security events 083 * @throws NullPointerException if config or eventCounter is null 084 */ 085 public URLParameterValidationPipeline(SecurityConfiguration config, 086 SecurityEventCounter eventCounter) { 087 super(createStages(config), Objects.requireNonNull(eventCounter, "EventCounter must not be null")); 088 } 089 090 private static List<HttpSecurityValidator> createStages(SecurityConfiguration config) { 091 Objects.requireNonNull(config, "Config must not be null"); 092 // Create validation stages in the correct order for URL parameters 093 return List.of( 094 new LengthValidationStage(config, ValidationType.PARAMETER_VALUE), 095 new CharacterValidationStage(config, ValidationType.PARAMETER_VALUE), 096 new DecodingStage(config, ValidationType.PARAMETER_VALUE), 097 new NormalizationStage(config, ValidationType.PARAMETER_VALUE), 098 new PatternMatchingStage(config, ValidationType.PARAMETER_VALUE) 099 ); 100 } 101 102 @Override 103 public ValidationType getValidationType() { 104 return VALIDATION_TYPE; 105 } 106}