Java Web Service - Secure web methods by user - java

Java web service, is it possible to expose different methods to different user?
For example, I have 10 methods in my web service but I want to allow user A access to 1 or 2 methods only, how can this be done?

I guess you can not completely hide the methods from the user. The only thing you can do is to provide only required information to the specific User. In one my application I have implemented this by using Decorate Design Pattern. I will try to explain it.
You can separate this logic in some non-webservice class. Create 2 web services (one for each userAccess Model). Call the separated logic from each of the web service.
Say you have created class CommonA which contains methods 1 ~10. Create web service say ForUserA this contains method 1 and 2 only which calls method 1 and 2 of CommonA. and so on.
It will be a great pleasure if anyone suggest the better way to do this.

In order for your webservice to determine which user is currently calling your webservice method, you need some kind of authentication.
Since both SAOP & REST use HTTP protocol, you can use sessions.
Once your client has authenticated himself, you can allow/deny him access to any webmethod you like.
Here is an easy example for a SOAP service.
#Resource WebServiceContext wsContext;
MessageContext mc = wsContext.getMessageContext();
HttpSession session = ((javax.servlet.http.HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST)).getSession();
String username = (String)session.getAttribute("username");
if(username.equals("userA") {
// Do your thing
} else {
throw new WebServiceException("Not allowed to access this method.");
}

Related

Is it possible to communicate between different rest clients using a common API of another application?

Let's say we have three applications called A,B and C B is an email sending application,and it has a method to send an email like sendEmail(String email) now I need to call that function from A through the rest API of C(Here A and B are rest consumers who can use C as a Common API).Can I do something like that?. I mean you can see there is no any direct communication between A and B so I am simply asking can I use rest API as the one who links them ?I know there is rest template and other rest consuming technologies available to do the consuming tasks,but in all those scenarios there is only two way data exchanging ,which is most probably with a client and a server(Rest service provider and consumer) and there won't be something like server is calling the client,because in every time client is calling the server methods(Get,post,put,delete) .but here you can see we need some kind of a method to call the sendEmail(String email) function of email sending application through the server so basically to do so server(Rest services provider) needs to have an object of that email sending application.How is this possible?
If you doesn't understand the scenario please tell me at-least is it possible to invoke a method of a rest consumer from rest API(rest server)? , because normally we call the methods of rest API from rest consumer [I am using spring boot]
In any case you need to invoke REST method to invoke your sendEmail method because you client is also a REST client and it can communicate with REST method
If you need A to call B directly, you need to have B expose the email sending capability as a REST Endpoint if it doesn't already exist.
Then you can use the Spring Rest Template capability to call application B from A. Make changes to A to use Spring Rest Template and then make the relevant call.

GWT RequestFactory client scenarios

My understanding is that the GWT RequestFactory (RF) API is for building data-oriented services whereby a client-side entity can communicate directly with it's server-side DAO.
My understanding is that when you fire a RF method from the client-side, a RequestFactoryServlet living on the server is what first receives the request. This servlet acts like a DispatchServlet and routes the request on to the correct service, which is tied to a single entity (model) in the data store.
I'm used to writing servlets that might pass the request on to some business logic (like an EJB), and then compute some response to send back. This might be a JSP view, some complicated JSON (Jackson) object, or anything else.
In all the RF examples, I see no such existence of these servlets, and I'm wondering if they even exist in GWT-RF land. If the RequestFactoryServlet is automagically routing requests to the correct DAO and method, and the DAO method is what is returned in the response, then I can see a scenario where GWT RF doesn't even utilize traditional servlets. (1) Is this the case?
Regardless, there are times in my GWT application where I want to hit a specific url, such as http://www.example.com?foo=bar. (2) Can I use RF for this, and if so, how?
I think if I could see two specific examples, side-by-side of GWT RF in action, I'd be able to connect all the dots:
Scenario #1 : I have a Person entity with methods like isHappy(), isSad(), etc. that would require interaction with a server-side DAO; and
Scenario #2 : I want to fire an HTTP request to http://www.example.com?foo=bar and manually inspect the HTTP response
If it's possible to accomplish both with the RF API, that would be my first preference. If the latter scenario can't be accomplished with RF, then please explain why and what is the GWT-preferred alternative. Thanks in advance!
1.- Request factory not only works for Entities but Services, so you could define any service in server-side with methods which you call from client. Of course when you use RF services they are able to deal with certain types (primitive, boxed primitives, sets, lists and RF proxies)
#Service(value=RfService.class, locator=RfServiceLocator.class)
public interface TwService extends RequestContext {
Request<String> parse(String value);
}
public class RfService {
public String parse(String value) {
return value.replace("a", "b");
}
2.- RF is not thought to receive other message payloads than the RF servlet produces, and the most you can do in client side with RF is ask for that services hosted in a different site (when you deploy your server and client sides in different hosts).
You can use other mechanisms in gwt world to get data from other urls, take a look to gwtquery Ajax and data-binding or this article

Concept for reusable login session in rmi ejb calls

This is not a simple question its just because i'm rethinking our architecture for securing our EJB 3.0 service by a login and security.
We have a EJB3.0 application on JBoss 5.1 that offers various services to a SWT client to read and write data. To use a service, the client must login with a valid user and password which is looked up by SpringSecurity in a LDAP server. SpringSecurity generates a session id which is passed back to the client to be resused in any further service call.
client server
| |
|-> login(user/password)-------->|
| |
| <------- sessionId ------------|
| |
|-->serviceXy(sessionId,param1)->|
The situation seems clear. We store the sessionId in our own context object which is the first parameter of each service method. There is an interceptor on each service method which reads the sessionId from the given context object and checks if the session is still valid. The client needs to call the login service first to get a context object filled with the sessionId and reusue this context object in further service calls.
public class OurContext {
private String sessionId;
}
#Stateless
#Interceptors(SecurityInterceptor.class)
public OurServiceImpl implements OurService {
public void doSomething(OurContext context, String param1) {
[...]
}
}
The thing i don't like at this solution is the polution of each service method with the context parameter.
Isn't there a similar mechanism like a http session in rmi calls? I'm thinking of putting our context object in some kind of session that is created in the client(?) right after the login and is passed to the server on each service call so that the SecurityInterceptor can read the sessionId from this "magic context".
Something like this:
OurContext ctx = service.login("user","password");
Magical(Jboss)Session.put("securContext", ctx);
service.doSomething("just the string param");
Since you are already using an app server, it seems that you should be using the built-in EJB security mechanisms, generally provided through JAAS. On the 4.x jboss line, if you implemented your own JAAS plugin for jboss, you could get access to a "special" context map (similar to what you describe) which is passed along on remote requests (by the jboss remote invocation framework). I haven't used jboss in a while, so not sure how this maps to the 5.1 product, but i have to imagine it has similar facilities. This assumes, of course, that you are willing to implement something jboss specific.
There are some kinds of session mechanisms in EJB, but they all start when the remote call starts, and ends when that ends. On old one is the transaction context ( Adam Bien wrote about this some time ago), and a newer one the CDI Session Scope.
Contrary to popular belief, this scope doesn't just mirror the http session scope, but in absence of an http session (like for remote calls), it represents a single call chain or message delivery (for mdbs).
With such a session, your remote SWT client still has to pass the sessionId to the remote service, but any local beans called from there can pick it up from this "cdi" session.
The other option is kinda like what jtahlborn says: with your own login module you can return a custom principal, instead of the default one. Your code can first request the normal principal and then try to cast it.
The problem is that this stuff is container specific and JBoss always forgets about it. It pretty much breaks after every update, and users have to kick and scream to get it fixed in some next version (only to see it break again in the version after that). Without JBoss really supporting this it's an endless battle.
Yet another option is to let the user login with the sessionId as name. The login module behind that could be a simple module that accepts everything and just puts a principal in the security context with the sessionId as 'name'. It's a little weird, but we've used this succesfully to get any data that can be expressed by a string into the security context. Of course, you would need to let your client do a regular container authentication here, which kinda defeats using Spring security in the first place.
We went for another approach which is portable and does not rely on a specific app server. In addition our security implementation frees us from the restrictions of the EJB approach (which by the way I thought were closed 2 decades ago ... but came up again).
Looking top down:
There is a server providing classes with methods to work on same data.
The client(s) provide the data and invoke specific methods.
Our approach is to put all data (and therefore communication between client and server) into a "Business Object". Every BO extends a superclass. This superclass contains a session id. The login method provides and returns that id. Every client only has to ensure to copy the id received in one BO into the next one it sends to the server. Every method which can be remotely (or locally) invoked, first obtains the session object with the received id. The method to return the session object also checks security constraints (which are based on permissions and not on roles like in the EKB approach).

Passing variables to a POST request from an outside controller

Since you guys have been very helpful in my early steps into the Play Framework (thanks for that), here it goes again:
We have a working registration controller, that POSTS all credentials to the database.
But then, we want to make it possible to be immeadiately logged in afterwards. Below is the code that makes this work:
public static void doRegistration(#Valid User user) {
//registering the user
try{
SecureController.authenticate(user.username, user.password, false, "MainController.index");
}catch(Throwable ex){
MainController.index();
}
This works fine, but it is not very safe because it GETs all the credentials to the server. I know I have to edit my routes file somehow, but I can't see how.
The routes file:
* /account SecureController.login
POST /account/register RegistrationController.doRegistration
GET /account/register SecureController.login
Somewhere should be the action SecureController.authenticate, but what do I have to put in the column after the POST... It can't be /account/register, because that fails...
Thank you beforehand!
I am not sure I understand your issue. The routes file is just a way to configure your URLs to be pretty URLs. If you don't specify them, then it falls back on default {controller}/{method} syntax.
The issue you are having, is that when you call another controller Play performs a redirect to that controller's method, which involves sending a request back to your browser telling it to redirect (this ensures that the state of the application is reflected in the URL within the browser). A redirect needs therefore to send a GET request, and included in the GET request will be your parameters.
what you are trying to do, as you said, is not safe. What you should do (not the only option, only one possibility) is:
Maintain your current doRegistration action for the user
Create a service class (that does not inherit Controller). It can be static or require instantiation (with static methods should be enough though).
Add a #Before method to a common controller that will be executed always. One way is to create a controller with a #Before method and add this controller to all other controllers via the #With annotation, so that #Before will be executed always for all controllers. It requires you to add a #With to each new controller, but I believe it keeps the code quite clean.
The idea would be that the controller calls the authenticate method from the service class. It's a simple static This method checks the user (if it's enabled, has proper license, whatever) and sets some parameters in the session (via Session object).
To help with this you may want to create another authenticate method in the user that returns the attributes to set (for example in a Map, if it contains an "error" key the user can't be authenticated for some reason). How to do this step can change according to your requirements.
Once the Session has been set, you redirect to the page of your election (main, profile, etc). As you have the common #Before method, this will be executed. This method should verify the credentials in the session (user authenticated, license type, etc) and act accordingly. You have an example in the Secure controller of Play, but you could create your own.
With this, you could user the authenticate method of the service from any controller, allowing authentication via multiple methods, and using a common point to verify the session.

JAXWS and sessions

I'm fairly new to writing web services. I'm working on a SOAP service using JAXWS. I'd like to be able to have users log-in and in my service know which user is issuing a command. In other words, have some session handling.
One way I've seen to do this is to use cookies and access the HTTP layer from my web service. However, this puts a dependency on using HTTP as the transport layer (I'm aware HTTP is almost always the transport layer but I'm a purist).
Is there a better approach which keeps the service layer unaware of the transport layer? Is there some way I can accomplish this with servlet filters? I'd like the answer to be as framework agnostic as possible.
I'm working on a SOAP service using JAXWS. I'd like to be able to have users log-in and in my service know which user is issuing a command. In other words, have some session handling.
Conventional Web services are stateless in nature, there is no session handling in web services (which has by the say nothing to do with identifying the caller).
If you want to require your users to be authenticated to call a service, the traditional approach is to:
Expose an "authentication" web service (passing user credentials) that returns an authentication token.
Have the users call this authentication first.
Have the users pass the token in a custom header on subsequent calls of "business" web services.
On the server side:
Reject any call that doesn't contain a valid token.
Invalidate tokens after some time of inactivity
You can implement a custom solution for this approach (this is a highly interoperable solution). Or you can use WS-Security/UsernameTokens that provides something similar out of the box. WS-Security is a standard (Metro implements it), it isn't "framework" specific.
As you mention, servlet filters can provide the basis of solution. Use a filter to store the current session details (e.g. the session context Map) in a threadLocal storage. This is implemented as your application class, so is transport agnostic. Your service simply uses a static method to fetch the current context, unaware of where it came from.
E.g.
class ServiceSessionContext
{
static ThreadLocal<Map> local = new ThreadLocal<Map>();
// context set by the transport layer, e.g. servlet filter
static public void setContext(Map map)
{
local.put(map);
}
// called when request is complete
static public void clearContext()
{
local.put(null);
}
// context fetched by the service
static public Map getContext()
{
return local.get();
}
}

Categories