REST API for registration - java

We want to implement a public RESTful API integrated in our software (written in java) that might be used by various clients to build small e-commerce apps (e.g. for Android or iPhone). This API includes getting a list of products, categories, shopping cart support, etc.
We need to provide an API that will allow user registration and couple of other sensitive functions. How should we protect this API against spam and bruteforcing? In the standard product we use reCAPTCHA. Any alternative for the REST counterpart?

First, think of separation of concerns. What is the purpose of REST API?
A REST API should do offer a service to the client. Client sends a request via REST protocol, and gets a response for its request. In code, this looks something like:
#GET
public Response getClientInfo(#QueryParam("clientId") Integer clientId) {
ClientDTO clientDTO = database.getClientInfo(clientId);
return ResponseWrapper.wrap(clientDTO);
}
Now, you want your REST method doing ONLY this and nothing else. Otherwise, you would put block-bruteforce-and-spam-logic in your REST method and you would get a mess of the code that is not extensible, hard to version, etc. If you want to change your, e.g. blacklisting policy you would have to change each and every REST method, and it's bulky. If you want to check the calls before the make it to REST methods, then take a look at Filters. Every request and response pass through a chain of filters and could be check for misuse of the server.
I don't know what is your technology stack is, but I would suggest looking into these:
JBoss AS7.
DeltaSpike (enables you powerful Interceptors that will check user rights and execution rights before the execution of the REST method).
for example:
#LoggedInUser
#GET
public Response getClientInfo(...) {
...
}
This security annotation #LoggedInUser (which, by the way, you define) will give sign to an Interceptor to check this security constraint, e.g.
#Secures (built in annotation)
#LoggedInUser
public boolean hasRight(Identity identity) {
return identity.isLoggedIn(); //or if he is in certain group of users
}
Context and Dependency Injection context (used in DeltaSpike).
JBoss Filters (a filter chain where you can create your own filter that, for example, checks if some IP is trying to send multiple calls within a very short period ~ 10 lines of code).
An example of the Filter
#Startup
#ApplicationScoped
#Filter(around= "org.jboss.seam.web.ajax4jsfFilter")
public class IPTrackerFilter extends AbstractFilter {
//IPTracker is your #ApplicationScoped bean that remembers all IP addresses accessing the application.
#Inject
private IPTracker fIPTracker;
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
if (!(req instanceof HttpServletRequest)) {
chain.doFilter(req, res);
return;
}
final String ipAddress= ((HttpServletRequest)req).getRemoteAddr();
if (fIPTracker.isBlackListed(ipAddress)) {
//implement error message here
sendErrorMessage(response);
return;
} else {
//all good, continue
chain.doFilter(req, res);
}
}
}
PS. I gave you the link for DeltaSpike, for others is really easy to find. Also, if you find DeltaSpike to obscure, try with JBoss Seam Security Framework.

Related

How can i achieve req id for tracing using springboot microservices?

The ask is:
Whenever a client calls API's, i want to tag it with a unique identifier or use one supplied by the client (usually in a query param) and pass it across components until that request is fulfilled sucessfully or fails. The goal is to get a holistic picture of how a request was handled by different components and what happened at each component and quickly identify issues.
How can i achieve this using springboot microservices. please help me.
Spring Cloud Sleuth is what you are looking for: https://cloud.spring.io/spring-cloud-sleuth/reference/html/
Spring Cloud Sleuth’s solution is to inject span and trace IDs into log entries. A trace ID is a unique identifier that an entire request flow will share. IA span is more local and is defined for each request received for each request sent event. They define particular interaction points.
The initial span, or root span, is generated when a client request is received from outside the distributed system. This request lacks trace and span information. The root span becomes the trace ID for the rest of the request flow through the system / systems.
The diagram below shows how Sleuth span and trace generation would work through a hypothetical service network.
All you need to do in your code is to add the dependency spring-cloud-starter-sleuth and Spring will automatically instrument the following communication channels:
requests over messaging technologies like Apache Kafka or RabbitMQ
HTTP headers received at Spring MVC controllers
requests made with the RestTemplate
If you want to start simple you could define a filter (e.g. by extending OncePerRequestFilter) that generates/extracts a request ID. You can also put it into Logback's MDC so that it is included in every logging statement that is issued from the thread executing the request (if configured):
#Component
public class RequestIdFilter extends OncePerRequestFilter {
private final ThreadLocal<String> requestId = new ThreadLocal<>();
public Optional<String> getCurrentRequestId() {
return Optional.ofNullable(requestId.get());
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
try {
requestId.set(UUID.randomUUID().toString()); // or extract from request
MDC.put("requestId", requestId.get());
chain.doFilter(request, response);
} finally {
requestId.remove();
}
}
}

How to get a header value in a RestController and pass it to the parent controller

I'm new to spring-boot and quite new to web services.
I would like to implement an authorization process in an (abstract) generic RestController which should get the content of the basic-auth. header from the extending controllers and then perform the authorization.
Something like that:
public class GenericController
{
// Constructor
protected GenericController(String basicAuth) throws MalformedURLException, ProtocolException, IOException
{
// check user can execute action
}
}
#RestController
#RequestMapping( "/users" )
public class UserController extends GenericController
{
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
// Constructor
protected UserController() throws MalformedURLException, ProtocolException, IOException
{
// somehow get the basic auth information from header and pass it to the parent's constructor
basicAuth = ???
super(basicAuth);
}
#GetMapping( "/user/{cn}" )
public String getUser( #PathVariable String cn )
{
logger.error("Start getUser(...): cn=" + cn);
}
How can I do that? (is that even possible?)
ADDED INFORMATION:
My web services are themselves consumers of other web services.
Once the calling user is authorized to "use" my web services I have to forward/set the Basic Authentication into the request for the web services I call.
So, how/where can I "intercept" and get the headers when my services are called?
I would recommend to take a look at Spring Security framework. There are many tutorials showing how to configure it to perform basic authentication, e.g.: here.
The main idea is decoupling authentication / authorization concerns from controllers and business logic code. To implement this filters are used which intercept every request and validate it against different conditions. When implementing stateless REST-service (each request independent from others) it's not so difficult. When handling sessions, logic will become much more complicated. Spring Security implements filter chains, consisting of multiple filters, each performing its own checks.
Spring Security is used very often in spring-based projects and is definitely worth to look at, although it may seem a bit difficult when meeting it for the first time.
You can use HttpServletRequest to get the header from the request.
protected UserController(HttpServletRequest httpServletRequest) throws MalformedURLException, ProtocolException, IOException
{
System.out.println( httpServletRequest.getHeaders("key name"));
// somehow get the basic auth information from header and pass it to the parent's constructor
basicAuth = ???
super(basicAuth);
}

Annotation based api authentication

I have somewhere around 70 of API's of which most of them are secured by following token based approach. There are (let's say 20) open api which do not need any kind of token.
For authentication of secured apis I initially though of implementing it in spring filters and skip this authentication for open api's. Something like below
#Component
class AccountFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) {
if(request.getRequestURI().contains.(list of open apis)) {
chain.doFilter(request, response);
return;
} else {
/*
* logic for token validation
*
}
}
}
But sooner found it becoming tedious. I mean putting if else for 20 apis makes code look cluttered.
Eventually I thought of creating a custom annotation something like #Authenticator and implement the token validation logic there. Put this annotation on RestController methods of secured api's and omit it from open api's.
#RentionPolicy
#Target
#interface Authenticator {
}
#RestController
public class TestController {
#Authenticator
#GetMapping(/api/v1/securedapi)
public void testSecurily() {
}
// Omit #Authenticator from non secured api
#GetMapping(/api/v1/api)
public void test() {
}
}
Unfortunately, I could not find anything which helps me. All I can find is spring security but that is not in my scope as of now.
I know spring supports custom annotations but I could not find anything which fulfils my requirement.
Can any one help me with this?
Also I want to know
If my approach is right? If yes how can i proceed further?
If not how can I achieve this functionality without cluttering my code.

How to start testing a RESTful web service using Java ? [duplicate]

This question already has an answer here:
How to invoke a REST service
(1 answer)
Closed 7 years ago.
I have this web service http://qa-takehome-creyzna.dev.aetion.com:4440 that I would like to test. I have the authentication details (username and password) and the service has the following end points: /login, /user/, /user/{id} and /user/search. For all endpoints other than /login an authorization token needs to be passed as an HTTP Header.
The service exposes a login endpoint ( /login) which takes a POST request with two parameters: username and password. Following a successful login, an authentication token will be returned which must be used to make additional requests to the service. For example,if the request is as following,
{
"username": "admin",
"password": "admin"
}
It may return { "token": "1234-0009-999" } and this token will required for making additional request.
I will need to authenticate the web service, create 10 users and then, retrieve that information to validate the users was created correctly. I would like to develop a test plan and implement in Eclipse. How can I get started ?
A web service is basically an extension of the Java Servlet, where the input is processed a bit more and the output is rarely an HTML page.
Netbeans has an excellent tutorial on how to stand up a web service, and if you follow it, you can have a basic web service running within the hour.
https://netbeans.org/features/java-on-server/web-services.html
Don't be fooled by thinking that you must use one IDE (I like netbeans, but others don't) or another. The fancy GUI tools are just writing plain Java classes that might use other plain Java facilities (like JAXB if using XML, etc).
A web service is not much more than a web server that accepts particular kinds of requests, and responds with particular kinds of responses. In Java, web servers are made easier to use by leveraging Servlets. The internal contents of the Servlet will look like
Unpack the request
Validate the request is complete, report an error response if not
Act on the reqeust
Generate a response in the appropriate format
Send the response back as the reply.
--- Edited in response to request ---
Sorry, It seemed too obvious to me. Let me fill in the gaps. Sorry for glossing over the details.
public class MockHttpServletRequest implements HttpServletRequest {
#Override
public String getAuthType() {
throw new UnsupportedOpertationException("unexpected method use");
}
#Override
public String getContextPath() {
throw new UnsupportedOpertationException("unexpected method use");
}
... repeat for all methods ....
}
public class ItemRequestWithBadEncoding extends MockHttpServletRequest {
#Override
public String getMethod() {
return "GET";
}
#Override
public String getHeader(String name) {
if ("content-type".equals(name)) {
return "text/plain-ish"; // this is not a mime-type
}
throw new IllegalArgumentException(String.format("this mock doesn't support %s", name);
}
... fill out the rest of the required request details ...
}
public class CapturingServletResponse implements HttpServletRespose {
private final ArrayList<Cookie> cookies = new ArrayList<Cookie>();
#Override
public void addCookie(Cookie cookie) {
cookies.add(cookie);
}
public List<Cookie> getCookies() {
return Collections.unmodifiableList(cookies);
}
... override other methods and capture them into per-instance fields
with ability to return unmodifiable references or copies to them ...
}
Now back in the testing framework
#Test
public void testItemFetch() {
try {
MockRequest request= ItemRequestWithBadEncoding();
CapturingServletResponse response = new CapturingServletResponse();
Servlet itemRequestServlet = new ItemRequestServlet();
itemRequestServlet.service(request, response);
Assert.assertEquals("unexpected cookies in response", 0, response.getCookies().size());
... other asssertations ....
} catch (Exception e) {
Assert.assertFail(String.format("unexpected exception: %s", e.getMessage());
}
}
Depending on what items you care about, and how much work you need to put into it, you can then flesh out the needed parts of the capture and perhaps parameterize and refine the way you construct your input handling.
Look into spring frameworks.
They go well with other testing frameworks like Mockito and Junits.
Use something like SpringMVCTest or SpringRestAssured, note RestAssured would let you write integration tests.
Read this and this

Restricting access to localhost for Java Servlet endpoint

In short - I would like to add such service endpoints to my servlet that can only be called from localhost. The restriction should be coded in the servlet itself, i.e it should not depend on Tomcat/Apache to be configured in a certain way. At the same time, there are many other, existing endpoints that should be reachable externally.
Longer description - I am creating an HTTP API that 3rd parties can implement to integrate with my application. I am also supplying a default implementation, bundled together with my app, that customers with simple requirements can use, without having to implement anything.
The endpoints of my default implementation should be reachable only for my app, which happens to be the same servlet as the one supplying the implementation, i.e it runs on the same host. So for security reasons (the API is security related), I want my implementation to be usable only for my app, which in the first round means restricting access to localhost for a set of HTTP endpoints.
At the same time, I don't want to rely on customers setting up their container/proxy properly, but do the restriction in my servlet, so that there are no changes required for existing installations.
So far the only idea I had was to check the requestor's IP addess in a servlet filter - so I am wondering if there is a better, more sophisticated way.
I think you should add Web Filter to your application and check your url in doFilter method. Check request.getRemoteAddr() and endpoint link you can put in urlPattern.
Like this:
#WebFilter(urlPatterns = "/*")
public class RequestDefaultFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (isForbidden(request, response))
return;
else
chain.doFilter(request, response);
}
}
isForbidden implementation is up to you. In response you just send 403 error code for example.
You can check make same check in servlet and send in response 403 error.

Categories