Securing jax-rs with OAuth - java

I have following problem:
I have JAX-RS service which has a get operation:
#Path("/unsecure/")
#Produces("application/json")
public class MyUnsecureService {
public MyUnsecureService() {
}
#GET
#Path("/get/{id}")
#Produces("application/json")
public User get(#PathParam("id") String id) {
return User.get(id);
}
}
now, I'm going to open this API for mobile devices and I need authentication and authorization mechanism to access the API.
My problem is that I have trusted apps (internal jobs, a website which runs on my hosting) which should be able to expose this API as they want, with no limitation, and mobile devices, which should be able to expose this API only if they have a token, formed using real User's encrypted login/pass, which can be used on service-side to determine:
If the request to that method is allowed.
If the parameters are correct (so, the user can't get other user's info).
Is this possible to do using OAuth1 or OAuth2?

This is a very valid question to raise.
You might want to have a look at Oz (backgroud), which AFAIU will go a long way towards your use cases. Personally, I have interest to solve the issue for Java and track Eran's work with Java implementations ( jiron, hawkj ). To finally do Oz (or something like it) in Java.
Much is not ripe for publishing right now, but get in touch for details if you like.
Specific problem with JAX-RS right now seems to be SecurityContext.

The answer is found:
Using Client Credentials and Resource Owner authorization grants, which are implemented in OAuth2 implementation of Apache CXF.

Related

Expose Web Services to third party applications?

I've been asked in tech discussions how do we write an application to use internally in the firm, and also expose it as an API to third party clients?
I am assuming this is in context of Web Services. I am thinking, won't the third party simply call the end point and consume the response?
Clearly, that answer is raw, and I am missing the point.
Is there a known approach, or any Frameworks to do this?
What are the considerations here? And how do we address them?
You would write and expose the RESTful services for internal and external users same way however when you do it for external clients then you have to careful about some of the following points
Security - If your API is secured then how are we going to achieve this ? We can leverage external identity providers to secure our APIs like (Azure AD, Auth0 (https://auth0.com))
Limit call rate - If you want to cap number of call from external Users ? e.g. free tier would only allow 100 req/min etc .
Sign up process - For external users you need to take care how do they have to sign up to your services (acquire token) to access your services.
Scaleable - Your APIs should be scaleable.
HATEOAS - This is very important REST principal. IF you follow this pattern your external users can explore your API in a better way by just following links (https://en.wikipedia.org/wiki/HATEOAS).
Open API Your API should be very well documented and Open API (swagger) is very much a standard now (https://swagger.io/specification/)
You can do all these tasks by your self or you can use Any API manager to do that.
One concrete way to achieve this is with a REST API secured using Json Web Tokens (JWT). On each REST endpoint, you can specify the roles that are allowed to call that endpoint.
For your use case, you could achieve this with a "system" role for internal callers, and unauthorized (i.e. no role) for external callers.
A framework you can use to achieve this is MicroProfile JWT, which might look something like this:
#Path("/rank")
#ApplicationScoped
public class RankingService {
#GET
#Path("/{playerId}")
public long getRank(#PathParam("playerId") String id) {
// get the ranking info for a player
// anyone is allowed to do this
}
#POST
#RolesAllowed({ "system" })
#Path("/{playerId}")
public void recordGame(#PathParam("playerId") String id,
#QueryParam("place") int place,
#HeaderParam("Authorization") String token) {
// update player ranking information
// only internal users are allowed to update ranks!
}
}
Here is a link to a talk that I gave at conference that walks through securing a REST endpoint using MicroProfile JWT.

log out from Oauth2 server AND from all clients

We have a java web app, which contains a lot of wars. We have an Oauth2 server(written by us) and we will have a lot clients( around 8). All of this will be under the same domain. Except of this we have another app( running on completely different tomcat. There a Liferay is used). The idea is that that the user will use them as they are using one app and they should not see big difference.
This is way now what I need is that when I log out from one place in some way to say the oauth2 server and all other clients to log out, too.
Because for client should be : I already logged out why in some parts I'm still logged in?
Currently I'm not sure how to do it.
And to a lot of places I read that normally this is not the practice.
Can you give me hints and explain me from where I can start? Maybe to use Oauth2 in my case in not the best choice?
For your requirement, you can implement OAuth2 using JDBC Token Store from Spring Security. For this to work once user logs out, all client should invoke your Delete token API where you can remove the Access Token
#FrameworkEndpoint
public class RevokeTokenEndpoint {
#Resource(name = "tokenServices")
ConsumerTokenServices tokenServices;
#RequestMapping(method = RequestMethod.DELETE, value = "/oauth/token")
#ResponseBody
public void revokeToken(HttpServletRequest request) {
//Delete the Token
}
}
Also, you should delete the refresh token.This way, the token would be invalidated once user logs-out and subsequent client can no longer use the same token

Add authentication to GAE Java endpoints

I am generating some endpoints and it works correctly, however, I would like to keep one session per client so I do not have to send the request by mail and password, but I am not sure of doing it.
This is an example of one of my endpoints
#Api(name = "test")
public class MyApi {
#ApiMethod(name = "printHi", httpMethod = "POST")
public Message imprimirHola(Input input) {
Message message = new Message();
if(datosCorrectos(input.getMail(), input.getPassword()))
message.setMessage("Hi");
else
message.setMessage("authentication failed");
return message;
}
}
After doing some research in the topic you have issues with, I have found the following information that can be useful for what you are trying to achieve.
Google Cloud Platform offers the Cloud Endpoints service, which has some available frameworks for user authentication. You can find detailed information and procedures about that in the documentation but, in short, you can use Firebase Auth, Auth0 or Google Accounts to authenticate a user against your endpoints (this link will help you decide which option suits you better).
However, in order to operate with one of those options, you will need that your API is managed by Cloud Endpoints, so you will have to follow this walkthrough to Add API Management to your API using OpenAPI.
Finally, here you have a working example on how to that using Java.
I know it is a lot of information, but I think you will be able to solve the authentication issue with your Java API just by reading more detailed information in this last documentation page, and move step by step in the "Getting Started" dropdown menu in the left of this page.

How to authenticate users in Java(REST) app?

I have some java server application and some WEB interface(jQuery). For REST services i'm using Jersey implementation. I can easily sent JSON to the server from WEB page and vice versa.
Example of my REST service:
#Path("/users")
public class User {
#POST
#Path("/login")
#Consumes(MediaType.APPLICATION_JSON)
public Response authUser(User user) {
//code
}
}
But there is one problem. How can I auth users?
For example, i have some private resources: when user in not log in, he can't see it resource/web page, but when he logined(enter correct name and password) he can see it resource.
I didn't use sping application. I have googled a lot of time but I didn't find easy examples, then i tried to read Jose's Sandoval book "RESTful Java Web Services", in "Security" section a lot of useful information but there isn't examples.
Could you please help me?
There are different ways to approach this I believe. One way is that when the user authenticates, you send him back a token [which expires after some time] and he then passes back that token in subsequent calls.
Save the token to a file or db. In subsequent requests that come from client , compare token timestamp and value.
Once that token expires he has to re-authenticate.

Is a GWT app running on Google App Engine protected from CSRF

I'm developing a GWT app running on the Google App Engine and wondering if I need to worry about Cross-site request forgery or is that automatically taken care of for me?
For every RPC request that requires authentication, I have the following code:
public class BookServiceImpl extends RemoteServiceServlet implements
BookService {
public void deleteInventory(Key<Inventory> inventoryKey) throws NotLoggedInException, InvalidStateException, NotFoundException {
DAO dao = new DAO();
// This will throw NotLoggedInException if user is not logged in
User user = dao.getCurrentUser();
// Do deletion here
}
}
public final class DAO extends DAOBase {
public User getCurrentUser() throws NotLoggedInException {
currentUser = UserServiceFactory.getUserService().getCurrentUser();
if(currentUser == null) {
throw new NotLoggedInException();
}
return currentUser;
}
I couldn't find any documentation on how the UserService checks authentication. Is it enough to rely on the code above or do I need to to more? I'm a beginner at this, but from what I understand to avoid CSRF attacks some of the strategies are:
adding an authentication token in
the request payload instead of just
checking a cookie
checking the HTTP
Referer header
I can see that I have cookies set from Google with what look like SID values, but I can't tell from the serialized Java objects in the payloads if tokens are being passed or not. I also don't know if the Referer header is being used or not.
So, am I worrying about a non-issue? If not, what is the best strategy here? This is a common enough problem, that there must be standard solutions out there...
If you were to put the same code in a regular servlet, you'd surely be vulnerable to XSRF. But since you are using GWTs RemoteServiceServlet - the answer depends on the version of GWT you are using.
Starting with the yet-to-be-release GWT 2.1, the RPC mechanism adds request headers and validates the presence of these headers in RemoteServiceServlet. This has its limitations - in particular, older versions of flash allow you to send the request headers from a different domain, but it does make things more difficult for a potential attacker.
If you want to adequately protect yourself from XSRF, refer to Lombardi's Development blog. The blog discusses two techniques. The first is a simple change that ports 2.1 changes to older versions of GWT. The second approach requires duplicating the session identifier as a request parameter, and is the recommended way to protect against XSRF.
References
GWT RPC - Does it do enough to protect against CSRF?
Lombardi development blog on GWT RPC and XSRF
Security for GWT Applications

Categories