Add sources for Jax-RS filters

This commit is contained in:
Chris Smowton
2021-08-12 14:52:23 +01:00
parent 0ebbb333ba
commit f1c3a11103
12 changed files with 1187 additions and 20 deletions

View File

@@ -544,11 +544,17 @@ private class UriInfoModel extends SummaryModelCsv {
override predicate row(string row) {
row =
[
"javax.ws.rs.core;UriInfo;true;getAbsolutePath;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;UriInfo;true;getAbsolutePathBuilder;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;UriInfo;true;getPath;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;UriInfo;true;getPathParameters;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;UriInfo;true;getPathSegments;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;UriInfo;true;getQueryParameters;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;UriInfo;true;getRequestUri;;;Argument[-1];ReturnValue;taint",
"javax.ws.rs.core;UriInfo;true;getRequestUriBuilder;;;Argument[-1];ReturnValue;taint",
"jakarta.ws.rs.core;UriInfo;true;getAbsolutePath;;;Argument[-1];ReturnValue;taint",
"jakarta.ws.rs.core;UriInfo;true;getAbsolutePathBuilder;;;Argument[-1];ReturnValue;taint",
"jakarta.ws.rs.core;UriInfo;true;getPath;;;Argument[-1];ReturnValue;taint",
"jakarta.ws.rs.core;UriInfo;true;getPathParameters;;;Argument[-1];ReturnValue;taint",
"jakarta.ws.rs.core;UriInfo;true;getPathSegments;;;Argument[-1];ReturnValue;taint",
"jakarta.ws.rs.core;UriInfo;true;getQueryParameters;;;Argument[-1];ReturnValue;taint",
@@ -955,3 +961,17 @@ private class VulnerableEntity extends XssSinkBarrier {
).getArgument(0)
}
}
/**
* Model sources stemming from `ContainerRequestContext`.
*/
private class ContainerRequestContextModel extends SourceModelCsv {
override predicate row(string s) {
s =
["javax", "jakarta"] + ".ws.rs.container;ContainerRequestContext;true;" +
[
"getAcceptableLanguages", "getAcceptableMediaTypes", "getCookies", "getEntityStream",
"getHeaders", "getHeaderString", "getUriInfo"
] + ";;;ReturnValue;remote"
}
}

View File

@@ -0,0 +1,17 @@
import jakarta.ws.rs.container.ContainerRequestContext;
public class JakartaContainerRequestContextSources {
void sink(Object o) {}
void test(ContainerRequestContext context) throws Exception {
sink(context.getAcceptableLanguages()); // $ hasValueFlow
sink(context.getAcceptableMediaTypes().get(0).getType()); // $ hasTaintFlow
sink(context.getCookies().get("someKey").getValue()); // $ hasTaintFlow
byte[] buf = new byte[1024];
context.getEntityStream().read(buf);
sink(buf); // $ hasTaintFlow
sink(context.getHeaders().getFirst("someKey")); // $ hasTaintFlow
sink(context.getHeaderString("someKey")); // $ hasValueFlow
sink(context.getUriInfo().getPath()); // $ hasTaintFlow
}
}

View File

@@ -57,11 +57,11 @@ public class JakartaRsFlow {
static PathSegment taint(PathSegment ps) { return ps; }
static UriInfo taint(UriInfo ui) { return ui; }
static Map taint(Map m) { return m; }
static Link taint(Link l) { return l; }
static Class taint(Class c) { return c; }
private static class UriSource {
@@ -196,12 +196,16 @@ public class JakartaRsFlow {
sink(taint(ps2).getPath()); // $ hasTaintFlow
}
void testUriInfo(UriInfo ui1, UriInfo ui2, UriInfo ui3, UriInfo ui4, UriInfo ui5) {
sink(taint(ui1).getPathParameters()); // $ hasTaintFlow
sink(taint(ui2).getPathSegments()); // $ hasTaintFlow
sink(taint(ui2).getQueryParameters()); // $ hasTaintFlow
sink(taint(ui2).getRequestUri()); // $ hasTaintFlow
sink(taint(ui2).getRequestUriBuilder()); // $ hasTaintFlow
void testUriInfo(UriInfo ui) {
ui = taint(ui);
sink(ui.getPathParameters()); // $ hasTaintFlow
sink(ui.getPathSegments()); // $ hasTaintFlow
sink(ui.getQueryParameters()); // $ hasTaintFlow
sink(ui.getRequestUri()); // $ hasTaintFlow
sink(ui.getRequestUriBuilder()); // $ hasTaintFlow
sink(ui.getQueryParameters().getFirst("someKey")); // $ hasTaintFlow
sink(ui.getRequestUri()); // $ hasTaintFlow
sink(ui.getRequestUriBuilder().build()); // $ hasTaintFlow
}
void testCookie() {
@@ -341,7 +345,7 @@ public class JakartaRsFlow {
sink(UriBuilder.fromPath(taint()).buildFromEncodedMap(new HashMap<String, String>())); // $ hasTaintFlow
sink(UriBuilder.fromPath("").buildFromMap(taint(new HashMap<String, String>()), false)); // $ hasTaintFlow
sink(UriBuilder.fromPath(taint()).buildFromMap(new HashMap<String, String>(), true)); // $ hasTaintFlow
sink(UriBuilder.fromPath(taint()).clone()); // $ hasTaintFlow
sink(UriBuilder.fromPath("").fragment(taint())); // $ hasTaintFlow
sink(UriBuilder.fromPath(taint()).fragment("")); // $ hasTaintFlow

View File

@@ -0,0 +1,17 @@
import javax.ws.rs.container.ContainerRequestContext;
public class JaxRsContainerRequestContextSources {
void sink(Object o) {}
void test(ContainerRequestContext context) throws Exception {
sink(context.getAcceptableLanguages()); // $ hasValueFlow
sink(context.getAcceptableMediaTypes().get(0).getType()); // $ hasTaintFlow
sink(context.getCookies().get("someKey").getValue()); // $ hasTaintFlow
byte[] buf = new byte[1024];
context.getEntityStream().read(buf);
sink(buf); // $ hasTaintFlow
sink(context.getHeaders().getFirst("someKey")); // $ hasTaintFlow
sink(context.getHeaderString("someKey")); // $ hasValueFlow
sink(context.getUriInfo().getPath()); // $ hasTaintFlow
}
}

View File

@@ -57,11 +57,11 @@ public class JaxRsFlow {
static PathSegment taint(PathSegment ps) { return ps; }
static UriInfo taint(UriInfo ui) { return ui; }
static Map taint(Map m) { return m; }
static Link taint(Link l) { return l; }
static Class taint(Class c) { return c; }
private static class UriSource {
@@ -192,12 +192,16 @@ public class JaxRsFlow {
sink(taint(ps2).getPath()); // $ hasTaintFlow
}
void testUriInfo(UriInfo ui1, UriInfo ui2, UriInfo ui3, UriInfo ui4, UriInfo ui5) {
sink(taint(ui1).getPathParameters()); // $ hasTaintFlow
sink(taint(ui2).getPathSegments()); // $ hasTaintFlow
sink(taint(ui2).getQueryParameters()); // $ hasTaintFlow
sink(taint(ui2).getRequestUri()); // $ hasTaintFlow
sink(taint(ui2).getRequestUriBuilder()); // $ hasTaintFlow
void testUriInfo(UriInfo ui) {
ui = taint(ui);
sink(ui.getPathParameters()); // $ hasTaintFlow
sink(ui.getPathSegments()); // $ hasTaintFlow
sink(ui.getQueryParameters()); // $ hasTaintFlow
sink(ui.getRequestUri()); // $ hasTaintFlow
sink(ui.getRequestUriBuilder()); // $ hasTaintFlow
sink(ui.getQueryParameters().getFirst("someKey")); // $ hasTaintFlow
sink(ui.getRequestUri()); // $ hasTaintFlow
sink(ui.getRequestUriBuilder().build()); // $ hasTaintFlow
}
void testCookie() {
@@ -337,7 +341,7 @@ public class JaxRsFlow {
sink(UriBuilder.fromPath(taint()).buildFromEncodedMap(new HashMap<String, String>())); // $ hasTaintFlow
sink(UriBuilder.fromPath("").buildFromMap(taint(new HashMap<String, String>()), false)); // $ hasTaintFlow
sink(UriBuilder.fromPath(taint()).buildFromMap(new HashMap<String, String>(), true)); // $ hasTaintFlow
sink(UriBuilder.fromPath(taint()).clone()); // $ hasTaintFlow
sink(UriBuilder.fromPath("").fragment(taint())); // $ hasTaintFlow
sink(UriBuilder.fromPath(taint()).fragment("")); // $ hasTaintFlow

View File

@@ -1,5 +1,6 @@
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineExpectationsTest
class TaintFlowConf extends TaintTracking::Configuration {
@@ -7,6 +8,8 @@ class TaintFlowConf extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node n) {
n.asExpr().(MethodAccess).getMethod().hasName("taint")
or
n instanceof RemoteFlowSource
}
override predicate isSink(DataFlow::Node n) {
@@ -21,6 +24,8 @@ class ValueFlowConf extends DataFlow::Configuration {
override predicate isSource(DataFlow::Node n) {
n.asExpr().(MethodAccess).getMethod().hasName("taint")
or
n instanceof RemoteFlowSource
}
override predicate isSink(DataFlow::Node n) {

View File

@@ -0,0 +1,336 @@
/*
* Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package javax.ws.rs.container;
import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
/**
* Container request filter context.
*
* A mutable class that provides request-specific information for the filter, such as request URI, message headers,
* message entity or request-scoped properties. The exposed setters allow modification of the exposed request-specific
* information.
*
* @author Marek Potociar
* @since 2.0
*/
public interface ContainerRequestContext {
/**
* Returns the property with the given name registered in the current request/response exchange context, or {@code null}
* if there is no property by that name.
* <p>
* A property allows a JAX-RS filters and interceptors to exchange additional custom information not already provided by
* this interface.
* </p>
* <p>
* A list of supported properties can be retrieved using {@link #getPropertyNames()}. Custom property names should
* follow the same convention as package names.
* </p>
* <p>
* In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes
* available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of
* properties of the associated {@code ServletRequest}.
* </p>
*
* @param name a {@code String} specifying the name of the property.
* @return an {@code Object} containing the value of the property, or {@code null} if no property exists matching the
* given name.
* @see #getPropertyNames()
*/
public Object getProperty(String name);
/**
* Returns {@code true} if the property with the given name is registered in the current request/response exchange
* context, or {@code false} if there is no property by that name.
* <p>
* Use the {@link #getProperty} method with a property name to get the value of a property.
* </p>
*
* @param name a {@code String} specifying the name of the property.
* @return {@code true} if this property is registered in the context, or {@code false} if no property exists matching
* the given name.
* @see #getPropertyNames()
*/
public default boolean hasProperty(String name) {
return getProperty(name) != null;
}
/**
* Returns an immutable {@link java.util.Collection collection} containing the property names available within the
* context of the current request/response exchange context.
* <p>
* Use the {@link #getProperty} method with a property name to get the value of a property.
* </p>
* <p>
* In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes
* available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of
* properties of the associated {@code ServletRequest}.
* </p>
*
* @return an immutable {@link java.util.Collection collection} of property names.
* @see #getProperty
*/
public Collection<String> getPropertyNames();
/**
* Binds an object to a given property name in the current request/response exchange context. If the name specified is
* already used for a property, this method will replace the value of the property with the new value.
* <p>
* A property allows a JAX-RS filters and interceptors to exchange additional custom information not already provided by
* this interface.
* </p>
* <p>
* A list of supported properties can be retrieved using {@link #getPropertyNames()}. Custom property names should
* follow the same convention as package names.
* </p>
* <p>
* If a {@code null} value is passed, the effect is the same as calling the {@link #removeProperty(String)} method.
* </p>
* <p>
* In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes
* available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of
* properties of the associated {@code ServletRequest}.
* </p>
*
* @param name a {@code String} specifying the name of the property.
* @param object an {@code Object} representing the property to be bound.
*/
public void setProperty(String name, Object object);
/**
* Removes a property with the given name from the current request/response exchange context. After removal, subsequent
* calls to {@link #getProperty} to retrieve the property value will return {@code null}.
* <p>
* In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes
* available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of
* properties of the associated {@code ServletRequest}.
* </p>
*
* @param name a {@code String} specifying the name of the property to be removed.
*/
public void removeProperty(String name);
/**
* Get request URI information.
*
* The returned object contains "live" view of the request URI information in a sense that any changes made to the
* request URI using one of the {@code setRequestUri(...)} methods will be reflected in the previously returned
* {@link UriInfo} instance.
*
* @return request URI information.
*/
public UriInfo getUriInfo();
/**
* Set a new request URI using the current base URI of the application to resolve the application-specific request URI
* part.
* <p>
* Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke
* the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown.
* </p>
*
* @param requestUri new URI of the request.
* @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request
* filter.
* @see #setRequestUri(java.net.URI, java.net.URI)
*/
public void setRequestUri(URI requestUri);
/**
* Set a new request URI using a new base URI to resolve the application-specific request URI part.
* <p>
* Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke
* the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown.
* </p>
*
* @param baseUri base URI that will be used to resolve the application-specific part of the request URI.
* @param requestUri new URI of the request.
* @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request
* filter.
* @see #setRequestUri(java.net.URI)
*/
public void setRequestUri(URI baseUri, URI requestUri);
/**
* Get the injectable request information.
*
* @return injectable request information.
*/
public Request getRequest();
/**
* Get the request method.
*
* @return the request method.
* @see javax.ws.rs.HttpMethod
*/
public String getMethod();
/**
* Set the request method.
* <p>
* Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke
* the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown.
* </p>
*
* @param method new request method.
* @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request
* filter.
* @see javax.ws.rs.HttpMethod
*/
public void setMethod(String method);
/**
* Get the mutable request headers multivalued map.
*
* @return mutable multivalued map of request headers.
* @see #getHeaderString(String)
*/
public MultivaluedMap<String, String> getHeaders();
/**
* Get a message header as a single string value.
*
* @param name the message header.
* @return the message header value. If the message header is not present then {@code null} is returned. If the message
* header is present but has no value then the empty string is returned. If the message header is present more than once
* then the values of joined together and separated by a ',' character.
* @see #getHeaders()
*/
public String getHeaderString(String name);
/**
* Get message date.
*
* @return the message date, otherwise {@code null} if not present.
*/
public Date getDate();
/**
* Get the language of the entity.
*
* @return the language of the entity or {@code null} if not specified
*/
public Locale getLanguage();
/**
* Get Content-Length value.
*
* @return Content-Length as integer if present and valid number. In other cases returns {@code -1}.
*/
public int getLength();
/**
* Get the media type of the entity.
*
* @return the media type or {@code null} if not specified (e.g. there's no request entity).
*/
public MediaType getMediaType();
/**
* Get a list of media types that are acceptable for the response.
*
* @return a read-only list of requested response media types sorted according to their q-value, with highest preference
* first.
*/
public List<MediaType> getAcceptableMediaTypes();
/**
* Get a list of languages that are acceptable for the response.
*
* @return a read-only list of acceptable languages sorted according to their q-value, with highest preference first.
*/
public List<Locale> getAcceptableLanguages();
/**
* Get any cookies that accompanied the request.
*
* @return a read-only map of cookie name (String) to {@link Cookie}.
*/
public Map<String, Cookie> getCookies();
/**
* Check if there is a non-empty entity input stream available in the request message.
*
* The method returns {@code true} if the entity is present, returns {@code false} otherwise.
*
* @return {@code true} if there is an entity present in the message, {@code false} otherwise.
*/
public boolean hasEntity();
/**
* Get the entity input stream. The JAX-RS runtime is responsible for closing the input stream.
*
* @return entity input stream.
*/
public InputStream getEntityStream();
/**
* Set a new entity input stream. The JAX-RS runtime is responsible for closing the input stream.
*
* @param input new entity input stream.
* @throws IllegalStateException in case the method is invoked from a response filter.
*/
public void setEntityStream(InputStream input);
/**
* Get the injectable security context information for the current request.
*
* The {@link SecurityContext#getUserPrincipal()} must return {@code null} if the current request has not been
* authenticated.
*
* @return injectable request security context information.
*/
public SecurityContext getSecurityContext();
/**
* Set a new injectable security context information for the current request.
*
* The {@link SecurityContext#getUserPrincipal()} must return {@code null} if the current request has not been
* authenticated.
*
* @param context new injectable request security context information.
* @throws IllegalStateException in case the method is invoked from a response filter.
*/
public void setSecurityContext(SecurityContext context);
/**
* Abort the filter chain with a response.
*
* This method breaks the filter chain processing and returns the provided response back to the client. The provided
* response goes through the chain of applicable response filters.
*
* @param response response to be sent back to the client.
* @throws IllegalStateException in case the method is invoked from a response filter.
*/
public void abortWith(Response response);
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package javax.ws.rs.core;
import java.util.Date;
import java.util.List;
import javax.ws.rs.core.Response.ResponseBuilder;
/**
* An injectable helper for request processing, all methods throw an {@link IllegalStateException} if called outside the
* scope of a request (e.g. from a provider constructor).
*
* Precondition processing (see the {@code evaluatePreconditions} methods) can result in either a {@code null} return
* value to indicate that preconditions have been met and that the request should continue, or a non-{@code null} return
* value to indicate that preconditions were not met. In the event that preconditions were not met, the returned
* {@code ResponseBuilder} instance will have an appropriate status and will also include a {@code Vary} header if the
* {@link #selectVariant(List)} method was called prior to to calling {@code evaluatePreconditions}. It is the
* responsibility of the caller to check the status and add additional metadata if required. E.g., see
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5">HTTP/1.1, section 10.3.5</a> for details
* of the headers that are expected to accompany a {@code 304 Not Modified} response.
*
* @author Paul Sandoz
* @author Marc Hadley
* @author Marek Potociar
* @since 1.0
*/
public interface Request {
/**
* Get the request method, e.g. GET, POST, etc.
*
* @return the request method.
* @see javax.ws.rs.HttpMethod
*/
public String getMethod();
/**
* Select the representation variant that best matches the request. Returns {@code null} in case there is no matching
* variant in the list.
* <p>
* More explicit variants are chosen ahead of less explicit ones. A vary header is computed from the supplied list and
* automatically added to the response.
* </p>
*
* @param variants a list of Variant that describe all of the available representation variants.
* @return the variant that best matches the request or {@code null} if there's no match.
* @throws java.lang.IllegalArgumentException if variants is empty or {@code null}.
* @throws java.lang.IllegalStateException if called outside the scope of a request.
* @see Variant.VariantListBuilder
*/
public Variant selectVariant(List<Variant> variants);
/**
* Evaluate request preconditions based on the passed in value.
*
* @param eTag an ETag for the current state of the resource
* @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the
* preconditions are not met. A returned {@code ResponseBuilder} will include an ETag header set with the value of eTag,
* provided none of the precondition evaluation has failed, in which case the ETag header would not be included and the
* status code of the returned {@code ResponseBuilder} would be set to {@link Response.Status#PRECONDITION_FAILED}.
* @throws java.lang.IllegalArgumentException if eTag is {@code null}.
* @throws java.lang.IllegalStateException if called outside the scope of a request.
*/
public ResponseBuilder evaluatePreconditions(EntityTag eTag);
/**
* Evaluate request preconditions based on the passed in value.
*
* @param lastModified a date that specifies the modification date of the resource
* @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the
* preconditions are not met.
* @throws java.lang.IllegalArgumentException if lastModified is {@code null}.
* @throws java.lang.IllegalStateException if called outside the scope of a request.
*/
public ResponseBuilder evaluatePreconditions(Date lastModified);
/**
* Evaluate request preconditions based on the passed in value.
*
* @param lastModified a date that specifies the modification date of the resource
* @param eTag an ETag for the current state of the resource
* @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the
* preconditions are not met. A returned {@code ResponseBuilder} will include an ETag header set with the value of eTag,
* provided none of the precondition evaluation has failed, in which case the ETag header would not be included and the
* status code of the returned {@code ResponseBuilder} would be set to {@link Response.Status#PRECONDITION_FAILED}.
* @throws java.lang.IllegalArgumentException if lastModified or eTag is {@code null}.
* @throws java.lang.IllegalStateException if called outside the scope of a request.
*/
public ResponseBuilder evaluatePreconditions(Date lastModified, EntityTag eTag);
/**
* Evaluate request preconditions for a resource that does not currently exist. The primary use of this method is to
* support the <a href="https://tools.ietf.org/html/rfc7232#section-3.1"> If-Match: *</a> and
* <a href="https://tools.ietf.org/html/rfc7232#section-3.2"> If-None-Match: *</a> preconditions.
*
* <p>
* Note that precondition <code>If-None-Match: <i>something</i></code> will never be
* considered to have been met, and it is the application's responsibility to enforce any additional method-specific
* semantics. E.g. a {@code PUT} on a resource that does not exist might succeed whereas a {@code GET} on a resource
* that does not exist would likely result in a 404 response. It would be the responsibility of the application to
* generate the 404 response.
* </p>
*
* @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the
* preconditions are not met.
* @throws IllegalStateException if called outside the scope of a request.
* @since 1.1
*/
public ResponseBuilder evaluatePreconditions();
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package javax.ws.rs.core;
import java.security.Principal;
/**
* An injectable interface that provides access to security related information.
*
* @author Paul Sandoz
* @author Marc Hadley
* @see Context
* @since 1.0
*/
public interface SecurityContext {
/**
* String identifier for Basic authentication. Value "BASIC"
*/
public static final String BASIC_AUTH = "BASIC";
/**
* String identifier for Client Certificate authentication. Value "CLIENT_CERT"
*/
public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";
/**
* String identifier for Digest authentication. Value "DIGEST"
*/
public static final String DIGEST_AUTH = "DIGEST";
/**
* String identifier for Form authentication. Value "FORM"
*/
public static final String FORM_AUTH = "FORM";
/**
* Returns a <code>java.security.Principal</code> object containing the name of the current authenticated user. If the
* user has not been authenticated, the method returns null.
*
* @return a <code>java.security.Principal</code> containing the name of the user making this request; null if the user
* has not been authenticated
* @throws java.lang.IllegalStateException if called outside the scope of a request
*/
public Principal getUserPrincipal();
/**
* Returns a boolean indicating whether the authenticated user is included in the specified logical "role". If the user
* has not been authenticated, the method returns <code>false</code>.
*
* @param role a <code>String</code> specifying the name of the role
* @return a <code>boolean</code> indicating whether the user making the request belongs to a given role;
* <code>false</code> if the user has not been authenticated
* @throws java.lang.IllegalStateException if called outside the scope of a request
*/
public boolean isUserInRole(String role);
/**
* Returns a boolean indicating whether this request was made using a secure channel, such as HTTPS.
*
* @return <code>true</code> if the request was made using a secure channel, <code>false</code> otherwise
* @throws java.lang.IllegalStateException if called outside the scope of a request
*/
public boolean isSecure();
/**
* Returns the string value of the authentication scheme used to protect the resource. If the resource is not
* authenticated, null is returned.
*
* Values are the same as the CGI variable AUTH_TYPE
*
* @return one of the static members BASIC_AUTH, FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH (suitable for == comparison)
* or the container-specific string indicating the authentication scheme, or null if the request was not authenticated.
* @throws java.lang.IllegalStateException if called outside the scope of a request
*/
public String getAuthenticationScheme();
}

View File

@@ -0,0 +1,336 @@
/*
* Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package jakarta.ws.rs.container;
import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import jakarta.ws.rs.core.Cookie;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Request;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.UriInfo;
/**
* Container request filter context.
*
* A mutable class that provides request-specific information for the filter, such as request URI, message headers,
* message entity or request-scoped properties. The exposed setters allow modification of the exposed request-specific
* information.
*
* @author Marek Potociar
* @since 2.0
*/
public interface ContainerRequestContext {
/**
* Returns the property with the given name registered in the current request/response exchange context, or {@code null}
* if there is no property by that name.
* <p>
* A property allows a JAX-RS filters and interceptors to exchange additional custom information not already provided by
* this interface.
* </p>
* <p>
* A list of supported properties can be retrieved using {@link #getPropertyNames()}. Custom property names should
* follow the same convention as package names.
* </p>
* <p>
* In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes
* available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of
* properties of the associated {@code ServletRequest}.
* </p>
*
* @param name a {@code String} specifying the name of the property.
* @return an {@code Object} containing the value of the property, or {@code null} if no property exists matching the
* given name.
* @see #getPropertyNames()
*/
public Object getProperty(String name);
/**
* Returns {@code true} if the property with the given name is registered in the current request/response exchange
* context, or {@code false} if there is no property by that name.
* <p>
* Use the {@link #getProperty} method with a property name to get the value of a property.
* </p>
*
* @param name a {@code String} specifying the name of the property.
* @return {@code true} if this property is registered in the context, or {@code false} if no property exists matching
* the given name.
* @see #getPropertyNames()
*/
public default boolean hasProperty(String name) {
return getProperty(name) != null;
}
/**
* Returns an immutable {@link java.util.Collection collection} containing the property names available within the
* context of the current request/response exchange context.
* <p>
* Use the {@link #getProperty} method with a property name to get the value of a property.
* </p>
* <p>
* In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes
* available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of
* properties of the associated {@code ServletRequest}.
* </p>
*
* @return an immutable {@link java.util.Collection collection} of property names.
* @see #getProperty
*/
public Collection<String> getPropertyNames();
/**
* Binds an object to a given property name in the current request/response exchange context. If the name specified is
* already used for a property, this method will replace the value of the property with the new value.
* <p>
* A property allows a JAX-RS filters and interceptors to exchange additional custom information not already provided by
* this interface.
* </p>
* <p>
* A list of supported properties can be retrieved using {@link #getPropertyNames()}. Custom property names should
* follow the same convention as package names.
* </p>
* <p>
* If a {@code null} value is passed, the effect is the same as calling the {@link #removeProperty(String)} method.
* </p>
* <p>
* In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes
* available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of
* properties of the associated {@code ServletRequest}.
* </p>
*
* @param name a {@code String} specifying the name of the property.
* @param object an {@code Object} representing the property to be bound.
*/
public void setProperty(String name, Object object);
/**
* Removes a property with the given name from the current request/response exchange context. After removal, subsequent
* calls to {@link #getProperty} to retrieve the property value will return {@code null}.
* <p>
* In a Servlet container, the properties are synchronized with the {@code ServletRequest} and expose all the attributes
* available in the {@code ServletRequest}. Any modifications of the properties are also reflected in the set of
* properties of the associated {@code ServletRequest}.
* </p>
*
* @param name a {@code String} specifying the name of the property to be removed.
*/
public void removeProperty(String name);
/**
* Get request URI information.
*
* The returned object contains "live" view of the request URI information in a sense that any changes made to the
* request URI using one of the {@code setRequestUri(...)} methods will be reflected in the previously returned
* {@link UriInfo} instance.
*
* @return request URI information.
*/
public UriInfo getUriInfo();
/**
* Set a new request URI using the current base URI of the application to resolve the application-specific request URI
* part.
* <p>
* Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke
* the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown.
* </p>
*
* @param requestUri new URI of the request.
* @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request
* filter.
* @see #setRequestUri(java.net.URI, java.net.URI)
*/
public void setRequestUri(URI requestUri);
/**
* Set a new request URI using a new base URI to resolve the application-specific request URI part.
* <p>
* Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke
* the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown.
* </p>
*
* @param baseUri base URI that will be used to resolve the application-specific part of the request URI.
* @param requestUri new URI of the request.
* @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request
* filter.
* @see #setRequestUri(java.net.URI)
*/
public void setRequestUri(URI baseUri, URI requestUri);
/**
* Get the injectable request information.
*
* @return injectable request information.
*/
public Request getRequest();
/**
* Get the request method.
*
* @return the request method.
* @see jakarta.ws.rs.HttpMethod
*/
public String getMethod();
/**
* Set the request method.
* <p>
* Note that the method is usable only in pre-matching filters, prior to the resource matching occurs. Trying to invoke
* the method in a filter bound to a resource method results in an {@link IllegalStateException} being thrown.
* </p>
*
* @param method new request method.
* @throws IllegalStateException in case the method is not invoked from a {@link PreMatching pre-matching} request
* filter.
* @see jakarta.ws.rs.HttpMethod
*/
public void setMethod(String method);
/**
* Get the mutable request headers multivalued map.
*
* @return mutable multivalued map of request headers.
* @see #getHeaderString(String)
*/
public MultivaluedMap<String, String> getHeaders();
/**
* Get a message header as a single string value.
*
* @param name the message header.
* @return the message header value. If the message header is not present then {@code null} is returned. If the message
* header is present but has no value then the empty string is returned. If the message header is present more than once
* then the values of joined together and separated by a ',' character.
* @see #getHeaders()
*/
public String getHeaderString(String name);
/**
* Get message date.
*
* @return the message date, otherwise {@code null} if not present.
*/
public Date getDate();
/**
* Get the language of the entity.
*
* @return the language of the entity or {@code null} if not specified
*/
public Locale getLanguage();
/**
* Get Content-Length value.
*
* @return Content-Length as integer if present and valid number. In other cases returns {@code -1}.
*/
public int getLength();
/**
* Get the media type of the entity.
*
* @return the media type or {@code null} if not specified (e.g. there's no request entity).
*/
public MediaType getMediaType();
/**
* Get a list of media types that are acceptable for the response.
*
* @return a read-only list of requested response media types sorted according to their q-value, with highest preference
* first.
*/
public List<MediaType> getAcceptableMediaTypes();
/**
* Get a list of languages that are acceptable for the response.
*
* @return a read-only list of acceptable languages sorted according to their q-value, with highest preference first.
*/
public List<Locale> getAcceptableLanguages();
/**
* Get any cookies that accompanied the request.
*
* @return a read-only map of cookie name (String) to {@link Cookie}.
*/
public Map<String, Cookie> getCookies();
/**
* Check if there is a non-empty entity input stream available in the request message.
*
* The method returns {@code true} if the entity is present, returns {@code false} otherwise.
*
* @return {@code true} if there is an entity present in the message, {@code false} otherwise.
*/
public boolean hasEntity();
/**
* Get the entity input stream. The JAX-RS runtime is responsible for closing the input stream.
*
* @return entity input stream.
*/
public InputStream getEntityStream();
/**
* Set a new entity input stream. The JAX-RS runtime is responsible for closing the input stream.
*
* @param input new entity input stream.
* @throws IllegalStateException in case the method is invoked from a response filter.
*/
public void setEntityStream(InputStream input);
/**
* Get the injectable security context information for the current request.
*
* The {@link SecurityContext#getUserPrincipal()} must return {@code null} if the current request has not been
* authenticated.
*
* @return injectable request security context information.
*/
public SecurityContext getSecurityContext();
/**
* Set a new injectable security context information for the current request.
*
* The {@link SecurityContext#getUserPrincipal()} must return {@code null} if the current request has not been
* authenticated.
*
* @param context new injectable request security context information.
* @throws IllegalStateException in case the method is invoked from a response filter.
*/
public void setSecurityContext(SecurityContext context);
/**
* Abort the filter chain with a response.
*
* This method breaks the filter chain processing and returns the provided response back to the client. The provided
* response goes through the chain of applicable response filters.
*
* @param response response to be sent back to the client.
* @throws IllegalStateException in case the method is invoked from a response filter.
*/
public void abortWith(Response response);
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package jakarta.ws.rs.core;
import java.util.Date;
import java.util.List;
import jakarta.ws.rs.core.Response.ResponseBuilder;
/**
* An injectable helper for request processing, all methods throw an {@link IllegalStateException} if called outside the
* scope of a request (e.g. from a provider constructor).
*
* Precondition processing (see the {@code evaluatePreconditions} methods) can result in either a {@code null} return
* value to indicate that preconditions have been met and that the request should continue, or a non-{@code null} return
* value to indicate that preconditions were not met. In the event that preconditions were not met, the returned
* {@code ResponseBuilder} instance will have an appropriate status and will also include a {@code Vary} header if the
* {@link #selectVariant(List)} method was called prior to to calling {@code evaluatePreconditions}. It is the
* responsibility of the caller to check the status and add additional metadata if required. E.g., see
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5">HTTP/1.1, section 10.3.5</a> for details
* of the headers that are expected to accompany a {@code 304 Not Modified} response.
*
* @author Paul Sandoz
* @author Marc Hadley
* @author Marek Potociar
* @since 1.0
*/
public interface Request {
/**
* Get the request method, e.g. GET, POST, etc.
*
* @return the request method.
* @see jakarta.ws.rs.HttpMethod
*/
public String getMethod();
/**
* Select the representation variant that best matches the request. Returns {@code null} in case there is no matching
* variant in the list.
* <p>
* More explicit variants are chosen ahead of less explicit ones. A vary header is computed from the supplied list and
* automatically added to the response.
* </p>
*
* @param variants a list of Variant that describe all of the available representation variants.
* @return the variant that best matches the request or {@code null} if there's no match.
* @throws java.lang.IllegalArgumentException if variants is empty or {@code null}.
* @throws java.lang.IllegalStateException if called outside the scope of a request.
* @see Variant.VariantListBuilder
*/
public Variant selectVariant(List<Variant> variants);
/**
* Evaluate request preconditions based on the passed in value.
*
* @param eTag an ETag for the current state of the resource
* @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the
* preconditions are not met. A returned {@code ResponseBuilder} will include an ETag header set with the value of eTag,
* provided none of the precondition evaluation has failed, in which case the ETag header would not be included and the
* status code of the returned {@code ResponseBuilder} would be set to {@link Response.Status#PRECONDITION_FAILED}.
* @throws java.lang.IllegalArgumentException if eTag is {@code null}.
* @throws java.lang.IllegalStateException if called outside the scope of a request.
*/
public ResponseBuilder evaluatePreconditions(EntityTag eTag);
/**
* Evaluate request preconditions based on the passed in value.
*
* @param lastModified a date that specifies the modification date of the resource
* @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the
* preconditions are not met.
* @throws java.lang.IllegalArgumentException if lastModified is {@code null}.
* @throws java.lang.IllegalStateException if called outside the scope of a request.
*/
public ResponseBuilder evaluatePreconditions(Date lastModified);
/**
* Evaluate request preconditions based on the passed in value.
*
* @param lastModified a date that specifies the modification date of the resource
* @param eTag an ETag for the current state of the resource
* @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the
* preconditions are not met. A returned {@code ResponseBuilder} will include an ETag header set with the value of eTag,
* provided none of the precondition evaluation has failed, in which case the ETag header would not be included and the
* status code of the returned {@code ResponseBuilder} would be set to {@link Response.Status#PRECONDITION_FAILED}.
* @throws java.lang.IllegalArgumentException if lastModified or eTag is {@code null}.
* @throws java.lang.IllegalStateException if called outside the scope of a request.
*/
public ResponseBuilder evaluatePreconditions(Date lastModified, EntityTag eTag);
/**
* Evaluate request preconditions for a resource that does not currently exist. The primary use of this method is to
* support the <a href="https://tools.ietf.org/html/rfc7232#section-3.1"> If-Match: *</a> and
* <a href="https://tools.ietf.org/html/rfc7232#section-3.2"> If-None-Match: *</a> preconditions.
*
* <p>
* Note that precondition <code>If-None-Match: <i>something</i></code> will never be
* considered to have been met, and it is the application's responsibility to enforce any additional method-specific
* semantics. E.g. a {@code PUT} on a resource that does not exist might succeed whereas a {@code GET} on a resource
* that does not exist would likely result in a 404 response. It would be the responsibility of the application to
* generate the 404 response.
* </p>
*
* @return {@code null} if the preconditions are met or a {@code ResponseBuilder} set with the appropriate status if the
* preconditions are not met.
* @throws IllegalStateException if called outside the scope of a request.
* @since 1.1
*/
public ResponseBuilder evaluatePreconditions();
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package jakarta.ws.rs.core;
import java.security.Principal;
/**
* An injectable interface that provides access to security related information.
*
* @author Paul Sandoz
* @author Marc Hadley
* @see Context
* @since 1.0
*/
public interface SecurityContext {
/**
* String identifier for Basic authentication. Value "BASIC"
*/
public static final String BASIC_AUTH = "BASIC";
/**
* String identifier for Client Certificate authentication. Value "CLIENT_CERT"
*/
public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";
/**
* String identifier for Digest authentication. Value "DIGEST"
*/
public static final String DIGEST_AUTH = "DIGEST";
/**
* String identifier for Form authentication. Value "FORM"
*/
public static final String FORM_AUTH = "FORM";
/**
* Returns a <code>java.security.Principal</code> object containing the name of the current authenticated user. If the
* user has not been authenticated, the method returns null.
*
* @return a <code>java.security.Principal</code> containing the name of the user making this request; null if the user
* has not been authenticated
* @throws java.lang.IllegalStateException if called outside the scope of a request
*/
public Principal getUserPrincipal();
/**
* Returns a boolean indicating whether the authenticated user is included in the specified logical "role". If the user
* has not been authenticated, the method returns <code>false</code>.
*
* @param role a <code>String</code> specifying the name of the role
* @return a <code>boolean</code> indicating whether the user making the request belongs to a given role;
* <code>false</code> if the user has not been authenticated
* @throws java.lang.IllegalStateException if called outside the scope of a request
*/
public boolean isUserInRole(String role);
/**
* Returns a boolean indicating whether this request was made using a secure channel, such as HTTPS.
*
* @return <code>true</code> if the request was made using a secure channel, <code>false</code> otherwise
* @throws java.lang.IllegalStateException if called outside the scope of a request
*/
public boolean isSecure();
/**
* Returns the string value of the authentication scheme used to protect the resource. If the resource is not
* authenticated, null is returned.
*
* Values are the same as the CGI variable AUTH_TYPE
*
* @return one of the static members BASIC_AUTH, FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH (suitable for == comparison)
* or the container-specific string indicating the authentication scheme, or null if the request was not authenticated.
* @throws java.lang.IllegalStateException if called outside the scope of a request
*/
public String getAuthenticationScheme();
}