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}