Vanity/Fancy/Rewrite URL implementation that does not suck - java

I have got a website, with really badly implemented Vanity URL module and really high loads at certain periods of time. Due to some bugs in the url module, the system needs to be restarted every so often. So, I want to rewrite a bloody module to make it nice and less buggy...
Is there are a good pattern to implementing Vanity URL system ?
What is the best approach when dealing with Vanity URL's for high performance ?
What is the best library to look at the sources ?
Cheers.
Ako

I'm not sure about the specific implementation details of your application, but as a general sketch I would write a Filter mapped to the space of URL of interest (perhaps /*).
Such Filter would check if the URL is a fancy one, and in that case would forward the request to the appropiate resource (either a URL dispatcher or a named one). You will need to save the filterConfig.getServletContext() passed in init(FilterConfig) in order to create the request dispatchers. If the URL is not fancy, the filter would invoke chain.doFilter(req, resp), then serving a non-mapped resource.
public class ExceptionFilter implements Filter {
private ServletContext servletContext;
public void destroy() {}
public void doFilter(ServletRequest req,
ServletResponse resp,
FilterChain chain)
throws IOException, ServletException {
String mapping = getMappingFor((HttpServletRequest)req);
if(mapping!=null) servletContext.getRequestDispatcher(mapping).forward(req,resp);
else chain.doFilter(req, resp);
}
public void init(FilterConfig filterConfig) throws ServletException {
this.servletContext = filterConfig.getServletContext();
}
private String getMappingFor(HttpServletRequest req) {...}
How getMappingFor is implemented, depends on the application, but it would probably open a connection to a database and ask whether URL /foo/bar is mapped, returning the mapped URL or nullif there is no mapping. If the mappings are known not to change, you may cache those mappings already retrieved.
You may go with more detailed implementations, such as setting some request attributes depending on the given URL or information from the database, and then forwarding the request to some servlet that knows what to do.

Related

Simple REST endpoints authentication

I am learning how secure my endpoints, but everything i searched for contains pretty complicated examples, that didn't really answerd my question, and for now, just for the sake of this example project, i was looking for something simple.
My current solution is to make endpoints return like this:
return authenticate(request.headers) ? cityService.getCity() : utils.unauthenticatedResponse();
Where authenticate(request.headers) checks for token in header.
The thing i want to improve is to have that authenticate method run before every request to my endpoints (aside from login and register), so i can just return cityService.getCity(), and i won't have to make that check every time.
Will appreciate every answers, but please make it easy yo understand, since i am just a beginner.
Since you need to run the authenticate method before every request, you need to implement a Filter. It's pretty straightforward and you can get the steps and template to implement a filter here.
Every request to an endpoint will first pass through the filter (this is configurable), where you can have the authenticate method and then allow it further accordingly.
For starters, you can implement a filter like below:
#Component
public class AuthFilter implements Filter {
#Override
public void doFilter
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if(authenticate(req.getHeaders)){
chain.doFilter(request, response);
} else {
//else logic, ie throw some exception in case authenticate returns false
}
}
}
The advantages that this provides are :
You can implement multiple filters
You can provide Order/priority to filters
You can configure which endpoints need to pass through the filter and which ones do not.
You can use ContainerRequestFilter (if you are using Spring/Tomcat)
Every request coming to the server will go through this filter, so you can implement your code in it.

capturing relevant user requests using filter/interceptors

I am capturing URLs requested for my website. I need to see what all pages were requested from my website.
To achieve this I created a basic filter, and started logging page requests from there.
Now, this filter catches all the requests specific to a page.
For e.g. abc.com/page1, abc.com/resources/myjs.js, etc.
My problem is that for each page request, subsequent resources(js,css) are requested too. I want to capture only the relevant requests.
Right now, I check for patterns like /resources to ignore such requests, but I am looking for a more clean approach.
Also, will interceptors be more useful here?
I have seen filter patterns as well. But those are not useful, since I would have to create patterns for my filter.
If you want to capture the urls accessed from your website, you can configure spring boot to generate access logs in following way until you don't want more advance information:
server.tomcat.accesslog.directory=/logs/ #absolute directory path for log files\
server.tomcat.accesslog.enabled=false #Enable access log.
server.tomcat.accesslog.pattern=any_pattern # log string format pattern for access logs.
To perform any operation based on any request pattern, you can go ahead with filters.
I'm using filters for such requirements in following way:
public class CustomFilter extends OncePerRequestFilter{
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String url = request.getRequestURI();
if (url.startsWith("/resources/")) {
//your business logic
}
filterChain.doFilter(request,response);
}
}

Change ServletRequest server name programmatically

I need to change the serverName of the ServletRequest object in my Grails controller. I'm having trouble figuring out how to do this since the serverName is a read-only property.
The most correct thing to do is probably to set up a clever filter or redirect which "fixes" your request URL before your servlet even gets involved. I know nothing about how to do that; you should ask on serverfault.com if you want to do that.
In java, you can fake it by creating your own subclass of HttpServletRequestWrapper which provides setServerName() and overrides getServerName() while delegating all other methods to the superclass. You can then provide a filter which creates an instance of your request and sends that one down the chain.
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
YourHttpServletRequest yourRequest =
new YourHttpServletRequest(request, newServerName);
chain.doFilter(yourRequest, response);
}
If I understand this correctly, CORS filter might help
I've used http://software.dzhuvinov.com/cors-filter.html in my previous project.
But you can also lookup on github for example https://github.com/eBay/cors-filter

JavaEE Webapp Custom authorization from outside a Servlet

I'm having a JavaEE Website running on a cloud-platform.
Now I want to use two types of authentications:
Is from an SSO-System, which is well integrated in the platfrom and works very nicely.
Is the problematic part: I want to authorize a user from 1) for the time of a session, and give him access to a more restricted resource.
Some details
I get the user and his data from 1).
The user first has to ask for permission to 2), which can be denyed or granted. A user gets authorization from a service, which is outside of the scope of his servlet.
For this purpose I pass a User-POJO (with the session of this user as a member) to a service.
If the service grants the rights to this user, it will set an attribute to the user session:
userSession.setAttribute("auth", "granted");
To restrict access to that resource I use a Filter:
#WebFilter("/supersecret/*")
public class NiceFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession();
// check
if (session.getAttribute("auth") != "granted")
// redirect to login
else
chain.doFilter(req, res);
}
//...
While this is currently working, I feel that my solution is very sloppy.
Altering the user-session outside the scope of a servlet seems to be bad practice.
Adding an attribute to the session for security-purposes is probably not a good idea?
I'd rather want to use standard JavaEE-mechanisms, but most of them are already used for auth-method 1), like declaring login-config in the web.xml.
Any ideas for a more robust solution to this problem?
Thanks in advance :)

How to define default welcome page in an equinox OSGI server?

We are using OSGI Equinox "org.eclipse.equinox.http.registry.resources" extension to define resources accessible in our different JAR in our OSGI Equinox server. Most of them are just to point to static HTML content so there's no Servlet implementation. I was wondering what was the easiest way to define the default page for a sub folder (defining the "Welcome" file usually defined in a web.xml in standard Servlet packaging). Basically, I define a resource at /mynewresource and would link the user to be directed to index.html when he enters instead of getting a server error.
If you just want to have a default behavior of going to index.html on your resource, you can create that simple filter:
public class WelcomFilter implements javax.servlet.Filter {
/** {#inheritDoc} */
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/** {#inheritDoc} */
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
HttpServletRequest r = (HttpServletRequest) request;
if ("/".equals(r.getPathInfo())) {
r.getRequestDispatcher("index.html").forward(request, response);
} else {
chain.doFilter(request, response);
}
} else {
chain.doFilter(request, response);
}
}
/** {#inheritDoc} */
#Override
public void destroy() {
}
}
You have two choices: you can register this filter once at the root (/) but keep in mind that any request with no path info will get redirected to index.html or you can register it for the sub-domain where you want it. In any case, you need to use the equinox http filter extension.
<extension
point="org.eclipse.equinox.http.registry.filters">
<filter
alias="/mydomain"
class="com.abc.filters.WelcomeFilter">
</filter>
</extension>
There is no standardised way yet to define a default (or welcome) page in an OSGi server.
Coincidentally, I faced the same and decided to add this functionality to the Amdatu-Web project. Aside allowing non-Java resources to be served through the web, it now also allows you to define a default page like:
X-Web-Resource-Default-Page: index.html
or a default page for a specific directory:
X-Web-Resource-Default-Page: /path=index.html
The default page(s) will be served in case no file is requested.
It is not entirely done yet, as it needs some reviewing and I need to update the documentation and examples a bit on the Amdatu website. But, you can already take a look at the code (especially the demo project in the BitBucket project) to get an idea of how it should work.
Filters didn't work for me (using Kura/Equinox) however, using a custom HttpContext implementation I was able to add the required logic in getResources.

Categories

Resources