001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.csp; 018 019import java.net.URI; 020import java.net.URISyntaxException; 021import java.util.List; 022 023import org.apache.wicket.util.string.Strings; 024 025/** 026 * An enum holding the possible CSP Directives. Via the 027 * {@link #checkValueForDirective(CSPRenderable, List)}-method, new values are verified before being 028 * added to the list of values for a directive. 029 * 030 * @see <a href="https://www.w3.org/TR/CSP2/">https://www.w3.org/TR/CSP2</a> 031 * @see <a href= 032 * "https://developer.mozilla.org/en-US/docs/Web/Security/CSP">https://developer.mozilla.org/en-US/docs/Web/Security/CSP</a> 033 */ 034public enum CSPDirective 035{ 036 DEFAULT_SRC("default-src"), 037 SCRIPT_SRC("script-src"), 038 STYLE_SRC("style-src"), 039 IMG_SRC("img-src"), 040 CONNECT_SRC("connect-src"), 041 FONT_SRC("font-src"), 042 OBJECT_SRC("object-src"), 043 MANIFEST_SRC("manifest-src"), 044 MEDIA_SRC("media-src"), 045 CHILD_SRC("child-src"), 046 WORKER_SRC("worker-src"), 047 FRAME_ANCESTORS("frame-ancestors"), 048 BASE_URI("base-uri"), 049 /** 050 * This directive was deprecated in CSP 2, but no longer in 3. Wicket will automatically add a 051 * {@code frame-src} directive when {@code child-src} is added. 052 */ 053 FRAME_SRC("frame-src"), 054 FORM_ACTION("form-action"), 055 SANDBOX("sandbox") 056 { 057 /** 058 * Only allow {@link CSPDirectiveSandboxValue} for the {@code 'sandbox'} directive and block 059 * conflicting options. 060 */ 061 @Override 062 public void checkValueForDirective(CSPRenderable value, 063 List<CSPRenderable> existingDirectiveValues) 064 { 065 if (!existingDirectiveValues.isEmpty()) 066 { 067 if (CSPDirectiveSandboxValue.EMPTY.equals(value)) 068 { 069 throw new IllegalArgumentException( 070 "A sandbox directive can't contain an empty string if it already contains " 071 + "other values: " + existingDirectiveValues); 072 } 073 if (existingDirectiveValues.contains(CSPDirectiveSandboxValue.EMPTY)) 074 { 075 throw new IllegalArgumentException( 076 "A sandbox directive can't contain other values if it already contains an " 077 + "empty string, can't add " + value); 078 } 079 } 080 081 if (!(value instanceof CSPDirectiveSandboxValue)) 082 { 083 throw new IllegalArgumentException( 084 "A sandbox directive can only contain values from CSPDirectiveSandboxValue or " 085 + "be empty, can't add " + value); 086 } 087 } 088 }, 089 REPORT_URI("report-uri") 090 { 091 /** 092 * Only allow URI, and only one. 093 */ 094 @Override 095 public void checkValueForDirective(CSPRenderable value, 096 List<CSPRenderable> existingDirectiveValues) 097 { 098 if (!existingDirectiveValues.isEmpty()) 099 { 100 throw new IllegalArgumentException( 101 "A report-uri directive can only contain one URI, it already contains " 102 + existingDirectiveValues); 103 } 104 if (value instanceof RelativeURICSPValue) 105 { 106 return; 107 } 108 if (!(value instanceof FixedCSPValue)) 109 { 110 throw new IllegalArgumentException( 111 "A report-uri directive can only contain an URI, not " + value); 112 } 113 try 114 { 115 new URI(value.toString()); 116 } 117 catch (URISyntaxException urise) 118 { 119 throw new IllegalArgumentException("Illegal URI for report-uri directive", urise); 120 } 121 } 122 }; 123 124 private String value; 125 126 CSPDirective(String value) 127 { 128 this.value = value; 129 } 130 131 public String getValue() 132 { 133 return value; 134 } 135 136 /** 137 * Check if {@code value} can be added to the list of other values. By default, it checks for 138 * conflicts with wildcards and none and it checks if values are valid uris. 139 * 140 * @param value 141 * The value to add. 142 * @param existingDirectiveValues 143 * The other values. 144 * @throws IllegalArgumentException 145 * if the given value is invalid. 146 */ 147 public void checkValueForDirective(CSPRenderable value, 148 List<CSPRenderable> existingDirectiveValues) 149 { 150 if (!existingDirectiveValues.isEmpty()) 151 { 152 if (CSPDirectiveSrcValue.WILDCARD.equals(value) 153 || CSPDirectiveSrcValue.NONE.equals(value)) 154 { 155 throw new IllegalArgumentException( 156 "A -src directive can't contain an * or a 'none' if it already contains other " 157 + "values: " + existingDirectiveValues); 158 } 159 if (existingDirectiveValues.contains(CSPDirectiveSrcValue.WILDCARD) 160 || existingDirectiveValues.contains(CSPDirectiveSrcValue.NONE)) 161 { 162 throw new IllegalArgumentException( 163 "A -src directive can't contain other values if it already contains an * or " 164 + "a 'none', can't add " + value); 165 } 166 } 167 168 if (value instanceof CSPDirectiveSandboxValue) 169 { 170 throw new IllegalArgumentException( 171 "A -src directive can't contain any of the sandbox directive values, like " 172 + value); 173 } 174 175 value.checkValidityForSrc(); 176 } 177 178 /** 179 * @return The CSPDirective constant whose value-parameter equals the input-parameter or 180 * {@code null} if none can be found. 181 */ 182 public static CSPDirective fromValue(String value) 183 { 184 if (Strings.isEmpty(value)) 185 { 186 return null; 187 } 188 for (int i = 0; i < values().length; i++) 189 { 190 if (value.equals(values()[i].getValue())) 191 { 192 return values()[i]; 193 } 194 } 195 return null; 196 } 197}