I am trying to retrieve the Subject that is currently executing a Privileged Action under the JAAS framework, in order to be able to extract its principals. Basically, I need to verify at run-time that the Privileged Action is indeed executed by the principal that has the right to do so.
Or, to put it differently: is it possible to get the current LoginContext at run-time as some kind of system property (and not by creating a new one)? This would easily allow extracting the Subject.
Are you sure you need the LoginContext?
If you just need the Subject (with all attached Principals), you can do
Subject activeSubject = Subject.getSubject(AccessController.getContext());
I think you need to manage such a mechanism yourself. For instance if this is a web application where you authenticate once and then associate the authentication with a session. You store the LoginContext in the session. One trick to make it available in other parts of the code would be to make a thread local wrapper that you set/unset at the start/end of every thread invocation (such as a request).
public class LoginContextHolder {
private static ThreadLocal<LoginContext> ctx = new ThreadLocal<LoginContext>();
public static void set(LoginContext lc) {
ctx.set(lc);
}
public static LoginContext get() {
return ctx.get();
}
}
public class LoginContextFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
LoginContext ctx = null;
HttpSession sess = (HttpSession)((HttpRequest)request).getSession(false);
if (sess != null) {
ctx = (LoginContext)sess.getAttribute("ctx");
}
try {
LoginContextHolder.set(ctx);
chain.doFilter(request, response);
} finally {
LoginContextHolder.set(null);
}
}
}
Related
I'm working on an application that's using a OncePerRequestFilter to do some custom log-like behavior using the incoming web request. This behavior uses both the HttpServletRequest & HttpServletResponse. Additionally, the filter uses both ContentCachingRequestWrapper & ContentCachingResponseWrapper to access the request/response bodies.
It's been decided that we only want to do this behavior when methods in particular Spring controllers have been called, since it's not something we want to do for other controllers/actuator endpoints/etc. Is there a way to tell whether the incoming request will be (or was) mapped to a controller?
public class ExampleFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Can I tell here whether this will be mapping to an endpoint in
// ExampleController or NestedExampleController?
ContentCachingRequestWrapper requestToUse = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper responseToUse = new ContentCachingResponseWrapper(response);
try {
filterChain.doFilter(requestToUse, responseToUse);
// Can I tell here whether this was mapped to an endpoint in
// ExampleController or OtherExampleController?
} finally {
responseToUse.copyBodyToResponse(); // Write the cached body back to the real response
}
}
}
#RestController
#RequestMapping("/example")
public class ExampleController {
#GetMapping("/{id}")
public Example retrieveExample() {
return getValue(); // Retrieve the value
}
// ...
}
#RestController
#RequestMapping("/example/{id}/nested")
public class NestedExampleController {
#GetMapping("/{nestedId}")
public NestedExample retrieveNestedExample() {
return getValue(); // Retrieve the value
}
// ...
}
I've dug around the Spring MVC/Boot internals a bit, and I'm not sure if there's a way to easily do this. As an alternative, I can do some manual URL pattern matching, which probably won't necessarily exactly match up to the methods in the controllers, but may get me close enough to be an acceptable solution.
To summarize: is there a way in a web filter to tell whether the incoming request will be mapped to a controller (prior to executing the filter chain) or whether it was mapped to a controller (after executing the filter chain)?
What you want is basically a cross-cutting concern that targets a specific part of your application - in this case, logging.
This is one of the most common use-cases for aspect-oriented programming, for which Spring has built-in support using AspectJ-style pointcuts.
You will need:
To enable AOP within your Spring configuration on a configuration class, as follows:
#Configuration
#EnableAspectJAutoProxy
public class AopConfiguration {
}
Define an aspect, e.g. as follows:
#Aspect
public class LoggingAspect {
Logger log = ...; // define logger
// Matches all executions in com.example.ExampleController,
// with any return value, using any parameters
#Pointcut("execution(* com.example.ExampleController.*(..))")
public void controllerExecutionPointcut() {}
#Around("controllerExecutionPointcut()")
public Object aroundTargetControllerInvocation(ProceedingJoinPoint pjp) {
log.debug("About to invoke method: {}", pjp.getSignature().getName());
try {
return pjp.proceed();
} catch (Throwable t) {
// note that getArgs() returns an Object[],
// so you may want to map it to a more readable format
log.debug("Encountered exception while invoking method with args {}", pjp.getArgs());
throw t;
}
log.debug("Sucessfully finished invocation");
}
}
See e.g. this guide to learn more about pointcut expressions.
Another common use-case for this is timing your method calls, although for that something like Micrometer (and the Micrometer adapter for Spring) using #Timed would probably be better.
You may also wish to read through the reference documentation, which devotes quite a lot of information on how AOP in Spring works.
Note: as will almost all other Spring proxying mechanisms, invocations from within the target object will not be proxied, i.e. this.otherControllerMethod() will not be subject to interception by the above advice. Similarly, private methods also cannot be intercepted. See section 5.4.3 of the reference documentation for more information.
As a last note, if performance is of great importance, you should check out AspectJ compile-time or load-time weaving, which gets rid of some of the overhead introduced by Spring's proxying mechanism (which is what Spring AOP uses under the hood). This will most likely not be necessary in your case, but is good to keep in mind.
Edit for comment:
Thanks! One caveat with this approach is that it does not give me access to the HttpServletRequest or HttpServletResponse, which is something I'm making use of. I can see where this would be helpful if that wasn't something I needed. I see that I wasn't explicit about that requirement in my question, so I'll update accordingly.
Indeed, that is unfortunately not directly possible with this approach. If you really need the request, then the HandlerInterceptor approach mentioned by #DarrenForsythe is another possible to go. If all you're going for is logging though, I see no reason why you absolutely need the request - unless you wish to extract specific headers and log those.
In that case, IMO, a OncePerRequestFilter as you originally tried would be far better, as you can control for which requests the filter gets applied (using shouldNotFilter(HttpServletRequest request) and matching on the URL).
After some additional poking around and some trial and error, I discovered that the controller is accessible through the RequestMappingHandlerMapping bean. When the request can be handled by a controller, this will map the request to a HandlerMethod for the controller's request handling method.
public class ExampleFilter extends OncePerRequestFilter {
private RequestMappingHandlerMapping requestMappingHandlerMapping;
#Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
Object handler = getHandlerBean(request);
boolean isHandledController = handler instanceof ExampleController
|| handler instanceof NestedEampleController;
if (!isHandledController) {
filterChain.doFilter(request, response);
return;
}
// ...
}
private Object getHandlerBean(HttpServletRequest request) {
try {
HandlerExecutionChain handlerChain = requestMappingHandlerMapping.getHandler(request);
if (handlerChain != null) {
Object handler = handlerChain.getHandler();
if (handler instanceof HandlerMethod) {
return ((HandlerMethod) handler).getBean();
}
}
return null;
} catch (Exception e) {
return null;
}
}
#Override
protected void initFilterBean() {
WebApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
requestMappingHandlerMapping = appContext.getBean(RequestMappingHandlerMapping.class);
}
}
To be extra thorough and truly mimic Spring's handler logic, the DispatcherServlet logic could be used/mimicked instead of directly referencing RequestMappingHandlerMapping. This will consult all handlers, not just the RequestMappingHandlerMapping.
public class ExampleFilter extends OncePerRequestFilter {
private DispatcherServlet dispatcherServlet;
#Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
Object handler = getHandlerBean(request);
boolean isHandledController = handler instanceof ExampleController
|| handler instanceof NestedEampleController;
if (!isHandledController) {
filterChain.doFilter(request, response);
return;
}
// ...
}
private Object getHandlerBean(HttpServletRequest request) {
try {
HandlerExecutionChain handlerChain = getHandler(request);
if (handlerChain != null) {
Object handler = handlerChain.getHandler();
if (handler instanceof HandlerMethod) {
return ((HandlerMethod) handler).getBean();
}
}
return null;
} catch (Exception e) {
return null;
}
}
/**
* Duplicates the protected "getHandler" method logic from DispatcherServlet.
*/
private HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
List<HandlerMapping> handlerMappings = dispatcherServlet.getHandlerMappings();
if (handlerMappings != null) {
for (HandlerMapping mapping : handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
#Override
protected void initFilterBean() {
WebApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
dispatcherServlet = appContext.getBean(DispatcherServlet.class);
}
}
I'm not sure if there is a more idiomatic approach, and it definitely feels like it's jumping through some hoops and digging into the Spring internals a bit too much. But it does appear to work, at least on spring-web 5.2.7.RELEASE.
I'm trying to make unexisting pages under my domain go to a 404 page. I need to distinguish 404 pages from the other pages. However, I do not know how to do this. And the thing below is not working.
#Component(service = Filter.class,
property = {
"service.ranking=" + Integer.MIN_VALUE})
#SlingServletFilter(scope = {SlingServletFilterScope.REQUEST},
pattern = "/content/foo/.*",
resourceTypes = "cq:Page",
extensions = {"html"},
methods = {"GET"})
public class NotFoundFilter implements Filter {
private static final String DEFAULT_METHOD = "GET";
#Reference
private UrlOperationsManager urlOperationsManager;
#Reference
private RequestResponseFactory requestResponseFactory;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (!(request instanceof SlingHttpServletRequest) ||
!(response instanceof SlingHttpServletResponse)) {
chain.doFilter(request, response);
return;
}
SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response;
//this condition here is not working since slingResponse has no getStatusCode method.
if(slingResponse.getStatusCode() == 404) {
//do something
}
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
}
You could work around this by implementing your own HttpServletResponseWrapper to save the value and access it later. The Sling implementation is marginally different (at least as far as this particular mechanic is concerned) from the generic Servlet API, which is covered in depth in How can I get the HTTP status code out of a ServletResponse in a ServletFilter?
However, if your intention is to serve a particular error document for a given status code, I'd approach it differently. Assuming you use a Dispatcher, you could have the web server take care of it.
The official AEM project archetype comes with a few simple examples that you could enable if you use Apache. The details will depend on your site structure but the gist is that it's possible to provide a similar configuration using the ErrorDocument directive to point to a cached error page relative to the document root, usually making it use content-editable error pages.
Some errors, especially HTTP 5** family could be a bit more tricky that way in that they usually happen when there's something wrong with AEM itself so it's prudent to make sure a fully static version is always available.
Based on this question I'd like to create a server endpoint instance based on the negotiated subprotocol to handle various protocol messages differently. Unfortunately ServerEndpointConfig.Configurator.getEndpointInstance [docs] wouldn't let me access any relevant session data to get the negotiated subprotol so I could instantiate different classes.
public static class ServerEndpointConfigurator extends
ServerEndpointConfig.Configurator {
public ServerEndpointConfigurator()
{
}
#Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
// useful to work with session data in endpoint instance but not at getEndpointInstance
HttpSession httpSession = (HttpSession) request.getHttpSession();
config.getUserProperties().put(HttpSession.class.getName(), httpSession);
}
#Override
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
// TODO get negotiated subprotocol and instantiate endpoint using switch case or factory
return (T) new WebSocketControllerA();
// or return (T) new WebSocketControllerB();
// or return (T) new WebSocketControllerC();
// ...
}
}
Any idea how to solve this problem or are there any widely accepted practices how to handle different subprotocols? I am having a hard time finding example implementations or advanced documentation about subprotocol handling on the web.
Is this what you are looking for?
#ServerEndpoint("/ws")
public class MyWebSocket {
#OnOpen
public void onOpen(Session session) {
session.getNegotiatedSubprotocol();
}
I am developing a shopping cart using servlets, have two servlets :
1. ShopingCart.java
2. TotalAmount.java
In ShopingCart.java i have created sessions and synchronise them using
synchronized(session) // lock session protect this from multiple threads
{
TotalAmount cart = (TotalAmount)session.getAttribute("Cart");
if(cart == null) // new sesssion, just create a cart
{
cart = new TotalAmount();
session.setAttribute("Cart", cart);
}
// I have to call cart.display();
and my display method in TotalAmount.java contains (request,response) as parameters.
so, how can i pass the request and response to display method?
yes, i need request and response parameters in display method to save some variable data in session in TotalAmount.java
Please Help..
I can pass the request and response to display method of TotalAmount.java by calling
Display(request,response);
As I already have the object of TotalAmount in ShopingCart.java
As per Java EE specification, servlet are independents and the only official way to interact with one is via their service(ServletRequest req, ServletResponse res) or doXXX method.
If you want to call a specific method of another servlet you have 2 broad solutions :
make the objects know each other by dependancy injection (Java EE CDI, Spring framework, etc.) - clean and neat provided you have one DI mechanism
manually register them via static method - say you want to access Servlet2 from Servlet1
class Servlet1 implement HttpServlet {
private static Servlet2 servlet2 = null;
public static void setServlet2(Servlet2 servlet2) {
this.servlet2 = servlet2;
}
// ... other code
servlet2.display(...);
// ...
}
class Servlet2 implements HttpServlet {
#Override
public void init(ServletConfig config) {
Servlet1.setServlet2(this);
// ... other init code eventually
}
// ...
}
It should work but is not very nice because of the static misuse.
forward to the other servlet and pass a request attribute to indicate that a special action is requested (assuming Servlet2 is named "Servlet2" in web.xml)
in Servlet1 :
request.setAttribute("DISPLAY", true);
request.getServletContext().getNamedDispatcher("Servlet2").forward(req, resp);
in Servlet2 :
public void service(ServletRequest req, ServletResponse resp) {
if (req.getAttribute("DISPLAY") != null) {
display(req, resp);
}
else {
super.service(req, resp); // or directly your code
}
}
Still a nice solution because attribute will not be set in a direct call (of course, you can use req.getRequestDispatcher("/Servlet2URL") instead of getServletContext().getNamedDispatcher("Servlet2"))
Servlets runs in several threads, so my question is:
If I have a lot of servlets which call some utility class (DbUtils, for example
Connection c = DbUtils.getConnection();
//....some action with db here
should I assume additional actions for synchronization inside DbUtils?
Actually I'd like to inherit HttpServlet into something like DatabaseInvokerServlet:
public abstract class DatabaseInvokerServlet extends HttpServlet
with methods:
public abstract void getResultSets(Connection connection) throws SQLException;
private AbstractUser currentUser;
private HttpServletRequest request;
private HttpServletResponse response;
protected void processData() {}
protected void afterRequestProcessed() throws ServletException, IOException {}
protected void beforeRequestProcessed() throws ServletException, IOException {}
protected void execute() {
Connection c = null;
try {
c = DbUtils.getConnection();
getResultSets(c);
processData();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (c != null) {
c.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public HttpServletRequest getRequest() {
return request;
}
public HttpServletResponse getResponse() {
return response;
}
public AbstractUser getCurrentUser() {
return currentUser;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
this.request = request;
this.response = response;
this.currentUser = (AbstractUser) request.getSession().getAttribute("currentUser");
}
Then I'd just inherit my DatabaseInvokerServlet to new servlets to do custom stuff. The reason is not to copy-paste database invoke block with try-catch-finally in a lot of places.
But as I can see such approach won't work because of synchronization issues. Am I right?
If the DbUtils creates the connection in the same thread, like as:
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
Then it's threadsafe.
But if the connection is a class variable, like as:
private static Connection connection = DriverManager.getConnection(url, username, password);
public static Connection getConnection() throws SQLException {
return connection;
}
Then it is definitely not threadsafe because the same connection will be shared among all threads. Also when it's closed in a thread, all subsequent threads won't be able to use the connection because it's not open anymore. Also when it's never closed, the DB will timeout the connection sooner or later, usually after a few hours, and your application won't work anymore because the connection is not open anymore.
As to the servlet,
public abstract class DatabaseInvokerServlet extends HttpServlet {
private AbstractUser currentUser;
private HttpServletRequest request;
private HttpServletResponse response;
// ...
}
it's definitely not threadsafe. You're assigning the current user, request and response as instance variables. From each servlet class, there is only one instance during the application's lifetime. This instance is shared among all visitors/sessions throughout the entire application's lifetime. Each HTTP request operates in a separate thread and uses the same instance.
Imagine two simultaneous visitors: visitor A will set the current user, request and response. The DB process however takes a long time. Before the response of visitor A has returned, visitor B calls the same servlet and thus the current user, request and response will be overriden. Then, the query of visitor A finishes and wants to write to the response, it is instead writing to the response of visitor B! Visitor B sees the result of the query of visitor A and visitor A sees nothing on his screen!
You should never assign request/session-specific data as instance variable of the servlet. You should keep them method (thread) local.
public abstract class DatabaseInvokerServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AbstractUser currentUser = request.getSession().getAttribute("user");
// Keep the variables in the method block!
// Do not assign them as instance variable!
}
}
As to the complete picture, this approach is clumsy. The database access layer should have nothing to do with servlets. It should operate in its own standalone classes which you could just construct/invoke in every other Java class, any servlet class, or a normal application with main(), or whatever. You should not have any single line of java.sql.* imports in your servlet classes (expect of maybe SQLException if it is not abstracted away). You should not have any single line of javax.servlet.* imports in your database classes.
See also:
Servlet instantiation and (session) variables
Basic DAO tutorial
If the utility class has state (example: class or instance variables) most probably yes.
If I guess right the DBUtils is returning new instance for each call of getConnection(). And as the DBUtils class is a utility class so it shouldn't be maintaining any state. In this scenario no you dont need any addition efforts for synchronization.
Servlets runs in several threads.
The J2EE spec says there is only one instance per servlet class running in one web container for non single thread servlet.
Servlet 2.3 specs
A servlet container may send
concurrent requests through the
service method of the servlet. To
handle the requests the developer of
the servlet must make adequate
provisions for concurrent processing
with multiple threads in the service
method.
Synchronisation in servlet.
Never have an member variable in a servlet, it is not thread safe.