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.juneau.rest.server; 018 019import static java.lang.annotation.ElementType.*; 020import static java.lang.annotation.RetentionPolicy.*; 021 022import java.lang.annotation.*; 023 024/** 025 * Declares that a REST operation changes state, so that binding it to an HTTP method defined as safe becomes a 026 * startup failure instead of a silent mistake. 027 * 028 * <h5 class='section'>The mistake this exists to catch</h5> 029 * <p> 030 * RFC 9110 defines {@code GET}, {@code HEAD}, {@code OPTIONS} and {@code TRACE} as <i>safe</i>: a client, a proxy, 031 * a crawler or a browser prefetcher may issue them freely, repeat them, and follow them without asking, precisely 032 * because they are defined not to change anything. Everything downstream of a request is built on that promise 033 * — caches store the response, link prefetchers fire the request before the user clicks, and every CSRF 034 * defence in existence, including {@link org.apache.juneau.rest.server.filter.LoopbackBoundary}, applies its checks 035 * only to the methods that are <i>not</i> safe. 036 * <p> 037 * So a handler that mutates state behind {@code GET} does not merely misuse a verb. It sits behind whichever of 038 * those checks the application relies on, having quietly opted out of all of them — not by disabling 039 * anything, but by being classified as harmless. Nothing about it looks wrong at the call site, and nothing 040 * reports it at runtime, because from the boundary's point of view a {@code GET} arriving without a CSRF token is 041 * an ordinary read. 042 * <p> 043 * That is the failure mode this annotation exists to convert into a boot error: 044 * <p class='bjava'> 045 * <jc>// Fails at startup: this mutates, and @RestOp with no method= and a name that starts with none of 046 * // get/put/post/delete resolves to GET.</jc> 047 * <ja>@Mutating</ja> 048 * <ja>@RestOp</ja> 049 * <jk>public</jk> Result <jsm>armRelease</jsm>(...) {...} 050 * </p> 051 * <p> 052 * The {@code @RestOp} case above is worth singling out, because the developer never typed {@code GET} anywhere: 053 * with no {@code method=} and a Java method name whose prefix is not one of {@code get}/{@code put}/{@code post}/ 054 * {@code delete}, the resolved method <b>defaults to {@code GET}</b>. A mutating operation therefore lands on a 055 * safe method through nobody's decision. The check resolves the method the same way dispatch does, so it sees the 056 * inferred {@code GET} rather than the absent annotation. 057 * 058 * <h5 class='section'>Why this is declared and not detected</h5> 059 * <p> 060 * The obvious alternative is for the framework to work out for itself which handlers mutate, and it was rejected 061 * because no sound version of it exists. "Mutates" is a claim about effects on state the <i>application</i> cares 062 * about, and that has no syntactic signature: 063 * <p class='bjava'> 064 * <jv>runner</jv>.run(List.<jsm>of</jsm>(<js>"svn"</js>, <js>"commit"</js>, <jv>path</jv>)); <jc>// mutates the world</jc> 065 * <jv>runner</jv>.run(List.<jsm>of</jsm>(<js>"svn"</js>, <js>"info"</js>, <jv>path</jv>)); <jc>// mutates nothing</jc> 066 * </p> 067 * <p> 068 * Those are the same call to the same method with the same argument type, and telling them apart requires knowing 069 * what {@code svn} does. No analysis of the Java program can supply that. Any analysis strong enough to see 070 * through the indirection real applications use — an interface for the process runner, a supplier for the 071 * credential, a method reference for the callback, an HTTP client whose URL is chosen at runtime — is a 072 * whole-program points-to analysis, and it would still be wrong on the two lines above. 073 * <p> 074 * A naming heuristic ({@code set*}, {@code save*}, {@code delete*}) fails in both directions 075 * — {@code getOrCreateSession} mutates, {@code applyFilter} does not — and has a worse property than 076 * being unreliable: it would make renaming a Java method change the application's security posture. 077 * <p> 078 * Inspecting the signature fares no better. A mutating operation need take nothing but a {@code @Path}: deleting 079 * a record by id, or validating a stored credential and caching the verdict, both mutate while taking no body at 080 * all. 081 * <p> 082 * The decisive argument is about the cost of being wrong. This check's failure mode is <b>the application does 083 * not start</b>. A check that can refuse to start an application it merely suspects will be switched off, and a 084 * check that has been switched off protects nothing — including against the real contradictions it would 085 * have caught. So the rule here is one a machine can evaluate with certainty: the developer stated that this 086 * operation mutates, and the operation is bound to a method defined as safe. Those cannot both be intended, and 087 * no inference is involved in noticing it. 088 * 089 * <h5 class='section'>What this does not catch</h5> 090 * <p> 091 * <b>An operation that mutates and says nothing is invisible to this check.</b> The check finds contradictions, 092 * not omissions, and a developer who does not reach for the annotation gets no protection from it. That limit is 093 * inherent in the previous section: the alternative to a declaration that can be forgotten is an inference that 094 * can be wrong, and at a gate that stops the application from booting, wrong is worse. 095 * <p> 096 * What makes the limit acceptable is that the annotation is <b>strictly additive</b>. It can only ever cause a 097 * boot failure; it never relaxes a runtime check. Its opposite, {@link RestOp#read() @RestOp(read=true)}, is 098 * accepted only on custom methods and cannot declare a {@code POST}, {@code PUT}, {@code PATCH} or {@code DELETE} 099 * safe. An operation that omits it is therefore treated exactly as it would be if this 100 * annotation did not exist — the boundary still classifies by HTTP method, still treats an unknown method as 101 * state-changing, and still applies every write check to every non-safe method. Adopting the annotation can move 102 * an application from "wrong and silent" to "refuses to start"; it cannot move one from "protected" to 103 * "unprotected". 104 * <p> 105 * For the same reason this is <b>method-level only</b>. A class-level form meaning "everything here mutates" 106 * would be convenient and would immediately produce false failures on the page-rendering {@code GET} that nearly 107 * every such resource also has — reintroducing exactly the false-positive problem that ruled out inference. 108 * 109 * <h5 class='section'>When it runs</h5> 110 * <p> 111 * When the resource's operation table is assembled: at startup under {@link Rest#eagerInit()}, and otherwise on 112 * the first request to that resource. In both cases it runs <b>before any operation on that resource can be 113 * dispatched</b>, so a contradiction cannot be reached by a request. An application wanting the failure at boot 114 * literally should set {@code eagerInit}. 115 * <p> 116 * The check is unconditional and needs no wiring. It is not part of any filter, because HTTP method safety is not 117 * a property of a security filter — it is a property of the resource, which the filter then depends on. An 118 * application with no {@code @Mutating} anywhere is unaffected. 119 * 120 * <h5 class='section'>Example:</h5> 121 * <p class='bjava'> 122 * <jc>// Correct: declared mutating, bound to a method that is not safe. Boots, and the boundary's write 123 * // checks apply to it because POST is not in the safe set.</jc> 124 * <ja>@Mutating</ja> 125 * <ja>@RestPost</ja>(<js>"/{version}/arm"</js>) 126 * <jk>public</jk> ArmResult <jsm>arm</jsm>(<ja>@Path</ja>(<js>"version"</js>) String <jv>version</jv>, <ja>@Content</ja> ArmRequest <jv>body</jv>) {...} 127 * </p> 128 * 129 * <h5 class='section'>See Also:</h5><ul> 130 * <li class='jc'>{@link org.apache.juneau.rest.server.filter.LoopbackBoundary} 131 * <li class='jm'>{@link MethodSafety#check(java.util.List)} 132 * </ul> 133 * 134 * @since 10.0.0 135 */ 136@Target(METHOD) 137@Retention(RUNTIME) 138@Inherited 139public @interface Mutating { 140 141 /** 142 * Optional note describing what this operation changes. 143 * 144 * <p> 145 * Included in the startup failure message when this operation is bound to a safe method, so the error can say 146 * what is at stake rather than only which method is wrong. Has no other effect. 147 * 148 * @return The description of what this operation changes. 149 */ 150 String value() default ""; 151}