NoClassDefFoundError when calling function from RESTful web service - rest

I'm trying to create a RESTful web service in java that will allow authentication with a Yubikey.
I'm modifying an existing tutorial that I completed while trying to learn about REST.
I'm trying to call the validation function from within the javax.ws.rs.core.Response function but keep getting an error with a package from the imported yubikey jars.
I imported these jars from build path -> libraries --> Add external Jars
Error as follows when I post my form to the RESTful url:
java.lang.NoClassDefFoundError: com/yubico/client/v2/exceptions/YubicoValidationException
package de.vogella.jersey.todo.resources;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import com.yubico.client.v2.exceptions.YubicoValidationException;
import com.yubico.client.v2.exceptions.YubicoValidationFailure;
import de.vogella.jersey.todo.resources.Validate;
#Path("/test")
public class Test {
#POST
public Response testCred(#FormParam("username") String username,
#FormParam("password") String password,
#FormParam("otp") String otp) throws YubicoValidationException, YubicoValidationFailure {
int client_id = 11095;
boolean status;
status = Validate.validate(otp, client_id);
return Response.status(200)
.entity("validation status: : " + status + ", for client " + otp)
.build();
}
}
the validate class is as follows:
package de.vogella.jersey.todo.resources;
import com.yubico.client.v2.YubicoClient;
import com.yubico.client.v2.YubicoResponse;
import com.yubico.client.v2.YubicoResponseStatus;
import com.yubico.client.v2.exceptions.YubicoValidationException;
import com.yubico.client.v2.exceptions.YubicoValidationFailure;
public class Validate {
public static boolean validate(String otp, int client_id) throws YubicoValidationException, YubicoValidationFailure {
YubicoClient client = YubicoClient.getClient(client_id);
YubicoResponse response = client.verify(otp);
if(response != null && response.getStatus() == YubicoResponseStatus.OK) {
return true;
}
return false;
}
}

Related

How to shorten the URL for a Restful service

I have a maven java web application developed using Netbeans. I have figured out to run a parameter based Restful service successfully.
The URL contains three names in separated by slashes before providing the parameter.
http://localhost:8080/chims/api/data/list?name=district_list
Can I have a URL with less slashes like
http://localhost:8080/chims/data?name=district_list
This is the applicatoin config file.
package org.netbeans.rest.application.config;
import javax.ws.rs.core.Application;
#javax.ws.rs.ApplicationPath("api")
public class ApplicationConfig extends Application {
}
This is the service file.
package lk.gov.health.phsp.ws;
import java.util.List;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import lk.gov.health.phsp.bean.AreaApplicationController;
import lk.gov.health.phsp.entity.Area;
import lk.gov.health.phsp.enums.AreaType;
import org.json.JSONArray;
import org.json.JSONObject;
#Path("data")
#RequestScoped
public class ApiResource {
#Context
private UriInfo context;
#Inject
AreaApplicationController areaApplicationController;
/**
* Creates a new instance of GenericResource
*/
public ApiResource() {
}
#GET
#Path("list")
#Produces(MediaType.APPLICATION_JSON)
public String getJson(#QueryParam("name") String name) {
JSONObject jSONObjectOut;
if (name == null || name.trim().equals("")) {
jSONObjectOut = errorMessageInstruction();
} else {
switch (name) {
case "district_list":
jSONObjectOut = districtList();
break;
default:
jSONObjectOut = errorMessage();
}
}
String json = jSONObjectOut.toString();
return json;
}
private JSONObject districtList() {
JSONObject jSONObjectOut = new JSONObject();
JSONArray array = new JSONArray();
List<Area> ds = areaApplicationController.getAllAreas(AreaType.District);
for (Area a : ds) {
JSONObject ja = new JSONObject();
ja.put("district_id", a.getCode());
ja.put("district_name", a.getName());
array.put(ja);
}
jSONObjectOut.put("data", array);
jSONObjectOut.put("status", successMessage());
return jSONObjectOut;
}
private JSONObject successMessage() {
JSONObject jSONObjectOut = new JSONObject();
jSONObjectOut.put("code", 200);
jSONObjectOut.put("type", "success");
return jSONObjectOut;
}
private JSONObject errorMessage() {
JSONObject jSONObjectOut = new JSONObject();
jSONObjectOut.put("code", 400);
jSONObjectOut.put("type", "error");
jSONObjectOut.put("message", "Parameter name is not recognized.");
return jSONObjectOut;
}
private JSONObject errorMessageInstruction() {
JSONObject jSONObjectOut = new JSONObject();
jSONObjectOut.put("code", 400);
jSONObjectOut.put("type", "error");
jSONObjectOut.put("message", "You must provide a value for the parameter name.");
return jSONObjectOut;
}
}
I have not done any changes to the web.xml file. All the tutorials I went through did not give me a clear picture as to how and why I have to change it. Even without changing it, the web service works as expected.
How can I reduce the slashes in the URL?
The first thing you can do is remove the #Path("list"). A GET to /data will automatically go to the getJson method.
The next thing you can do is remove the api. You can do this by changing the "api" to "", "/", or "/*". All three will result in the same "/*". What happens when you do this is that Jersey will now take all requests that come to the server (and the same context). Any other servlets or static content will not be reachable.
To get around this, you can configure Jersey to run as a servlet filter instead of a servlet. Then configure it to forward unknown requests. See this post for how to configure this.

Java transmission of SWA response as a HttpEntity with a large attachment fails (can't chunk multipart)

Please note: This issue has also been posted to the official Apache HttpClient Users mailing list.
Question
How should Java-based servers built on Apache HttpComponents assemble and send large SOAP with attachments (SWA) responses?
Issue details
The Apache HttpClient Java API does not support chunking multipart HttpEntity instances. Clients making SOAP requests to a mock server are failing (specifically, Apache-based Java clients are throwing org.apache.http.NoHttpResponseExceptions) when the attachment in the SWA response is large (>2 MiB). Small attachments are transmitted without throwing any exceptions. HTTP Content-Length header is correct.
Use case
Multithreaded SOAP server capable of transmitting SWA responses of arbitrary content length
Platform
Java 8 64b
Required Libraries
HttpCore v4.4.6 + HttpMime v4.5.3
Error replication
Build the example source with HttpCore v4.4.6 and HttpMime v4.5.3 libraries (HttpMime is part of the HttpClient project).
Run the program with a sufficiently large (>2 MiB) "random.png.gz" binary file.
Send the server an arbitrary HTTP POST request via some third-party client. As it's an Apache-based Java client with precision logging, SoapUI is recommended. NB: the failure to receive the large server-generated multipart result.
Example server source
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.http.ExceptionLogger;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import static org.apache.http.HttpStatus.SC_OK;
import org.apache.http.MethodNotSupportedException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.nio.bootstrap.HttpServer;
import org.apache.http.impl.nio.bootstrap.ServerBootstrap;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
import org.apache.http.nio.protocol.BasicAsyncResponseProducer;
import org.apache.http.nio.protocol.HttpAsyncExchange;
import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
import org.apache.http.protocol.HttpContext;
public class HttpComponentsConciseTest {
/*
* The random.png.gz file must be large (> 2 MiB)
*/
private static final String LARGE_COMPRESSED_FILE_NAME = "random.png.gz";
private static final File LARGE_TEST_GZIP_FILE = new File(LARGE_COMPRESSED_FILE_NAME);
private static final String SOAP_RESPONSE_MESSAGE_XML
= "<soapenv:Envelope "
+ "xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soapenv:Header/>\n"
+ " <soapenv:Body>\n"
+ " <AResponse>\n"
+ " <ResponseFile>" + LARGE_COMPRESSED_FILE_NAME + "</ResponseFile>\n"
+ " </AResponse>\n"
+ " </soapenv:Body>\n"
+ "</soapenv:Envelope>";
private static final int PORT_NUMBER = 8080;
public static void main(String[] args) {
startHttpServer();
}
private static void startHttpServer() {
IOReactorConfig config = IOReactorConfig.custom()
.setIoThreadCount(1)
.setSoTimeout(15000)
.setTcpNoDelay(true)
.build();
final HttpServer server = ServerBootstrap.bootstrap()
.setListenerPort(PORT_NUMBER)
.setServerInfo("Test/1.1")
.setIOReactorConfig(config)
.setExceptionLogger(ExceptionLogger.STD_ERR)
.registerHandler("*", new PrimaryRequestHandler())
.create();
Runtime.getRuntime().addShutdownHook(new Thread(() -> server.shutdown(5,
TimeUnit.MILLISECONDS)));
Thread serverOwner = new Thread(() -> {
try {
server.start();
} catch (IOException ex) {
Logger.getLogger(HttpComponentsConciseTest.class.getName()).log(Level.SEVERE, null,
ex);
}
}, "ServerOwner");
serverOwner.start();
}
private static class PrimaryRequestHandler implements HttpAsyncRequestHandler<HttpRequest> {
#Override
public HttpAsyncRequestConsumer<HttpRequest> processRequest(
final HttpRequest request,
final HttpContext context) {
return new BasicAsyncRequestConsumer();
}
#Override
public void handle(
final HttpRequest request,
final HttpAsyncExchange httpexchange,
final HttpContext context) throws HttpException, IOException {
HttpResponse response = httpexchange.getResponse();
String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
if (!method.equals("POST")) {
throw new MethodNotSupportedException(method + " method not supported");
}
StringBody soapResponseStringBody = new StringBody(SOAP_RESPONSE_MESSAGE_XML,
ContentType.APPLICATION_XML);
FileBody soapAttachment = new FileBody(LARGE_TEST_GZIP_FILE);
HttpEntity responseEntity = MultipartEntityBuilder.create()
.addPart("SOAP Envelope", soapResponseStringBody)
.addPart(LARGE_COMPRESSED_FILE_NAME, soapAttachment)
.build();
response.setStatusCode(SC_OK);
response.setEntity(responseEntity);
httpexchange.submitResponse(new BasicAsyncResponseProducer(response));
}
}
}
Pastebin link to source
https://pastebin.com/2Hzdhpt3

SRVE0777E: Exception thrown by application class

I have a JEE rest app for consume and build web service. When I use url of app in ibm bluemix I have an error in local server webSphere and also in Bluemix:
SRVE0777E: Exception thrown by application class
'tn.hunterViews.services.OfferService.afficherOffer:31'
java.lang.NullPointerException:
at tn.hunterViews.services.OfferService.afficherOffer(OfferService.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.ibm.ws.jaxrs20.server.LibertyJaxRsServerFactoryBean.performInvocation(LibertyJaxRsServerFactoryBean.java:674)
at [internal classes]
OffersService.java
package tn.hunterViews.services;
import java.util.List;
import javax.ejb.EJB;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import tn.hunterViews.business.OfferBusiness;
import tn.hunterViews.business.OfferBusinessRemote;
import tn.hunterViews.domain.Offer;
#Path("/Offers")
public class OfferService {
#EJB
OfferBusinessRemote ofR;
#GET
#Path("")
#Produces(MediaType.APPLICATION_JSON)
public Response afficherOffer(){
return Response.status(Status.OK).entity(ofR.getOffer()).build();
}
}
offersBuissness.java
package tn.hunterViews.business;
import java.util.List;
import javax.ejb.Stateless;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import tn.hunterViews.domain.Offer;
/**
* Session Bean implementation class OfferBusiness
*/
#Stateless
public class OfferBusiness implements OfferBusinessRemote {
#Override
public List<Offer> getOffer() {
Client cl = ClientBuilder.newClient();
WebTarget target = cl.target("https://pihunterviewsdotnet.mybluemix.net/api");
WebTarget off = target.path("offerApi");
List<Offer> offers = off.request(MediaType.APPLICATION_JSON).get(new GenericType<List<Offer>>(){}) ;
cl.close();
return offers;
}
#Override
public boolean createOffer(Offer offer) {
Client cl = ClientBuilder.newClient();
WebTarget target = cl.target("https://pihunterviewsdotnet.mybluemix.net/api");
WebTarget off = target.path("offerApi");
Response resp=target.request().post(Entity.entity(offer, MediaType.APPLICATION_JSON));
if(resp.getStatus()!=201)
return false;
return true;
}
#Override
public boolean updateOffer(int id, Offer offer) {
if (id+""!=null && id!=0 && offer.getId()!=0)
{
Client cl = ClientBuilder.newClient();
WebTarget target = cl.target("https://pihunterviewsdotnet.mybluemix.net/api/offerApi"+ id);
target.request().build("PUT", Entity.entity(offer, MediaType.APPLICATION_JSON))
.invoke();
return true;
}
return false;
}
#Override
public boolean deleteOffer(int id) {
if (id+""!=null && id!=0)
{
Client cl = ClientBuilder.newClient();
WebTarget target = cl.target("https://pihunterviewsdotnet.mybluemix.net/api/offerApi"+ id);
target.request().delete();
return true;}
return false;
}
#Override
public Offer findOfferById(int id) {
Client cl = ClientBuilder.newClient();
WebTarget baseUrl = cl.target("https://pihunterviewsdotnet.mybluemix.net/api/offerApi");
WebTarget getPostURL=baseUrl.path(""+id);
Response response = getPostURL.request(MediaType.APPLICATION_JSON).get();
Offer offer=response.readEntity(Offer.class);
response.close();
cl.close();
return offer;
}
}
Please help me with this problem. Thanks.
If the #EJB annotation cannot be resolved to an EJB, then you would
have received a failure when the server created an instance of the
class containing the #EJB annotation. Since that does not appear to be
happening for you, and instead the instance is created fine, just
without that field being set, then the server is not scanning your
class for annotations or you have the javax.ejb.EJB annotation class
packaged as part of your application.
I would recommend checking the following:
Make sure the javax.ejb.EJB class is not being packaged as part of your annotation
Check that the web.xml for your WAR module has a version > 2.4. WAR modules with a version of 2.4 (or earlier) will not be scanned for annotations.
Check that the web.xml does not contain the setting metadata-complete="true". This setting turns off annotation scanning.
Source: http://www.developersite.org/102-95523-websphere-liberty

Rest API java, JSON Web token authentication : invalid signature

In Java, I try to set up a JWT authentication on a Rest API using jersey 1.9.
I'm using a friend's code sample (his token are valid with that code) and io.jsonwebtoken to generate token but I keep getting an Invalid signature warning when I test them on https://jwt.io/.
I've done some research and tried to fix that but I'm running out of ideas.
Example of invalid token I get with that code:
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIyIiwiaWF0IjoxNDg1MDI2MDgzLCJzdWIiOiJodHRwOi8vbG9jYWxob3N0OjkxODAvVHJvY1RvblNhdm9pci8iLCJpc3MiOiJzZXJnZW50LWNoZWYiLCJleHAiOjE1MTY1NjIwODN9.HY8S7QbOhSB22d1_Dkmtg6qCiKxQRKz9W1etMqDookw
This is the login path and the method I use to create those token :
import java.security.Key;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.xml.bind.DatatypeConverter;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.TextCodec;
import io.jsonwebtoken.impl.crypto.MacProvider;
import dao.UserDao;
import model.User;
#Path("/home")
public class MainController {
UserController userCtrl = new UserController();
//The not really secret key
String key = "supersecretkey";
#POST
#Path("login")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response Login(
#FormParam("username") String username,
#FormParam("password") String password){
if (username == null || password == null) {
return Response
.status(Status.PRECONDITION_FAILED)
.build();
}
User user = userCtrl.Authenticate(username,password);
if (user == null) {
return Response
.status(Status.FORBIDDEN)
.build();
}
String token = createJWT(user.getUserID()+"",user.getUserName(),"http://localhost:8080/rest_api/",TimeUnit.DAYS.toMillis(365));
return Response
.status(Status.OK)
.entity(token)
.build();
}
private String createJWT(String id, String issuer, String subject, long ttlMillis) {
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//We will sign our JWT with our ApiKey secret
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(key);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//Let's set the JWT Claims
JwtBuilder builder = Jwts.builder().setId(id)
.setIssuedAt(now)
.setSubject(subject)
.setIssuer(issuer)
.signWith(signatureAlgorithm, signingKey );
//if it has been specified, let's add the expiration
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
//Builds the JWT and serializes it to a compact, URL-safe string
return builder.compact();
}
}
Solved
I don't really know what was wrong with my secret key but I manage to validate my token by changing my key generation:
private static final Key secret = MacProvider.generateKey(SignatureAlgorithm.HS256);
private static final byte[] secretBytes = secret.getEncoded();
public static final String base64SecretBytes = Base64.getEncoder().encodeToString(secretBytes);

HTTP Basic Authentication for Play framework 2.4

I am looking some way to make some authentication for my play framework app: I want allow/disallow the whole access to non authenticated users
Is there exists some working module/solution for it? I don't need any forms for auth, just 401 HTTP response for non authenticated users (like Apache .htacccess "AuthType Basic" mode).
I've updated Jonck van der Kogel's answer to be more strict in parsing the authorization header, to not fail with ugly exceptions if the auth header is invalid, to allow passwords with ':', and to work with Play 2.6:
So, BasicAuthAction class:
import java.io.UnsupportedEncodingException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import org.apache.commons.codec.binary.Base64;
import play.Logger;
import play.Logger.ALogger;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Http.Context;
import play.mvc.Result;
public class BasicAuthAction extends Action<Result> {
private static ALogger log = Logger.of(BasicAuthAction.class);
private static final String AUTHORIZATION = "Authorization";
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
private static final String REALM = "Basic realm=\"Realm\"";
#Override
public CompletionStage<Result> call(Context context) {
String authHeader = context.request().getHeader(AUTHORIZATION);
if (authHeader == null) {
context.response().setHeader(WWW_AUTHENTICATE, REALM);
return CompletableFuture.completedFuture(status(Http.Status.UNAUTHORIZED, "Needs authorization"));
}
String[] credentials;
try {
credentials = parseAuthHeader(authHeader);
} catch (Exception e) {
log.warn("Cannot parse basic auth info", e);
return CompletableFuture.completedFuture(status(Http.Status.FORBIDDEN, "Invalid auth header"));
}
String username = credentials[0];
String password = credentials[1];
boolean loginCorrect = checkLogin(username, password);
if (!loginCorrect) {
log.warn("Incorrect basic auth login, username=" + username);
return CompletableFuture.completedFuture(status(Http.Status.FORBIDDEN, "Forbidden"));
} else {
context.request().setUsername(username);
log.info("Successful basic auth login, username=" + username);
return delegate.call(context);
}
}
private String[] parseAuthHeader(String authHeader) throws UnsupportedEncodingException {
if (!authHeader.startsWith("Basic ")) {
throw new IllegalArgumentException("Invalid Authorization header");
}
String[] credString;
String auth = authHeader.substring(6);
byte[] decodedAuth = new Base64().decode(auth);
credString = new String(decodedAuth, "UTF-8").split(":", 2);
if (credString.length != 2) {
throw new IllegalArgumentException("Invalid Authorization header");
}
return credString;
}
private boolean checkLogin(String username, String password) {
/// change this
return username.equals("vlad");
}
}
And then, in controller classes:
#With(BasicAuthAction.class)
public Result authPage() {
String username = request().username();
return Result.ok("Successful login as user: " + username + "! Here's your data: ...");
}
You can try this filter:
https://github.com/Kaliber/play-basic-authentication-filter
It looks pretty simple to use and configure.
You could also solve this with a play.mvc.Action, like this.
First your Action:
import org.apache.commons.codec.binary.Base64;
import play.libs.F;
import play.libs.F.Promise;
import play.mvc.Action;
import play.mvc.Http.Context;
import play.mvc.Result;
import util.ADUtil;
public class BasicAuthAction extends Action<Result> {
private static final String AUTHORIZATION = "authorization";
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
private static final String REALM = "Basic realm=\"yourRealm\"";
#Override
public Promise<Result> call(Context context) throws Throwable {
String authHeader = context.request().getHeader(AUTHORIZATION);
if (authHeader == null) {
context.response().setHeader(WWW_AUTHENTICATE, REALM);
return F.Promise.promise(new F.Function0<Result>() {
#Override
public Result apply() throws Throwable {
return unauthorized("Not authorised to perform action");
}
});
}
String auth = authHeader.substring(6);
byte[] decodedAuth = new Base64().decode(auth);
String[] credString = new String(decodedAuth, "UTF-8").split(":");
String username = credString[0];
String password = credString[1];
// here I authenticate against AD, replace by your own authentication mechanism
boolean loginCorrect = ADUtil.loginCorrect(username, password);
if (!loginCorrect) {
return F.Promise.promise(new F.Function0<Result>() {
#Override
public Result apply() throws Throwable {
return unauthorized("Not authorised to perform action");
}
});
} else {
return delegate.call(context);
}
}
}
Next your annotation:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import play.mvc.With;
#With(BasicAuthAction.class)
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
#Inherited
#Documented
public #interface BasicAuth {
}
You can now annotate your controller functions as follows:
#BasicAuth
public Promise<Result> yourControllerFunction() {
...
I'm afraid there's no such solution, reason is simple: usually when devs need to add authorization/authentication stack they build full solution.
The easiest and fastest way is using HTTP front-end server as a reverse-proxy for your application (I'd choose nginx for that task, but if you have running Apache on the machine it can be used as well). It will allow you to filter/authenticate the traffic with common server's rules
Additionally it gives you other benefits, i.e.: you can create CDN-like path, so you won't waste your apps' resources for serving public, static assets. You can use load-balancer for redeploying your app without stopping it totally for x minutes, etc.