How to approach this authentication mechanism in Jersey - java

I am new to Jersey REST Framework , so please excuse if this is a dumb question .
I am using Tomcat with Hibernate and Jersey REST Webservices.
I have got set of HTML pages in my Web APP
login.html
dealer.html
sales.html
I dont want the User to access the HTML pages directly other than login.html
So to resolve this issue , when submit is pressed , under login.html call
following call is made to the backend
#Path("/webchecklogin")
public class WebLoginCheck {
#Context
private HttpServletResponse response;
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces("application/json")
public String getData(LoginInfo loginInfo ) throws JSONException,ClassNotFoundException, SQLException
{
String ID = loginInfo.getID();
String email = loginInfo.getEmail();
// validate this values with Database and if successfully logged in , stored them in session AND cookies also
}
}
And inside dealer.html and sales.html , on page ready i am calling a service as shown below
var checkcallajax = $.ajax({
type: 'GET',
url: url + '/ORIENT/orn/checkifuserloggedin',
jsonpCallback: 'jsonCallback',
success: function(response) {
}
})
#Path("/checkifuserloggedin")
public class CheckIfUserLoggedIn {
#Context
private HttpServletRequest request;
#GET
#Consumes(MediaType.APPLICATION_JSON)
#Produces("application/json")
public String checkIfUserLoggedIn() throws JSONException,ClassNotFoundException, SQLException
{
// On what basis , should i check wheher the USER is logged or NOT
// I tried storing data with Session and cookies , but i am unable to retrive them here
//return true or false
// based on true or false , i am redireting user to appropiate page
}
}
Could anybody please let me know how to approach this

RestFUL web services are supposed to be stateless, so in theory, you could send the credential with every request, and that would be totally stateless from the "server point of view"
Most will find this cumbersome, resource intensive, and storing credentials on the client is somewhat bad from a security point.
The alternative approach could be that your login method returns a token, that needs to be re-sent (in a header maybe) to the server with every request.
The client must know how to store it (session cookie? on the domain
serving html, if you are in a CORS scenario)
The server must know how to validate the token.
On top of it, the validation of the Token can be done in a JaxRS Filter... before reaching your service entry point. And even better, this filter could add roles to the request context, so you can the use the #RolesAllowed annotation with your services.
I "very personnally" avoid relying on the javax.servlet.Session, as this is fundamentally stateful. But, you should be able to do it, given that the clients stores the jSessionId (other other cookie name) in a session cookie. If it does not work, you might have CORS or other domain specific problem, preventing the client from storing and returning this cookie automatically.
Hope it helps.

Related

Spring Interceptor which matches user id with a token

I am porting a REST web application from struts 2 to spring 5 (w/ spring boot). In our Api, we pass three attributes in each request (names are anonymised):
uuid, token, bananaId
In the backend we look for a user in a database with uuid, and check if it has token in it's list of tokens. If it has, the request is authorized and we add bananaId to the user's set of bananas.
I can do checking in each request individually -- and this is how it was implemented in struts. How to make a spring interceptor which would do this for each request (excluding a login action)?
I have successfully configured HandlerInterceptorAdapter, but I'm stuck on what to do next. Which approach is the best in this case?
EDIT: pseudo code of a controller
#RequestMapping("/getFoo")
public GetFooRsponse getFoo(#RequestBody Request request) {
Optional<User> user = getUser(request.getUuid());
if (user.isPresent() && user.get().getGcmTokens().contains(request.getGcmToken())){
user.get().getBanIds().add(request.getbanId());
// handle request
} else {
// unauthorized?
}
}
A solution which would be fine:
#RequestMapping("/getFoo")
#CheckGcmToken
public GetFooRsponse getFoo(#RequestBody UserRequest request) {
// handle request
}

Java webapp responding the source code of my login page

I have a java web application which publish a service that returns an object in JSON format, and I have another java web app just to consume that service through a JSONP call and show the response. In my local machine it's working fine, but now that I want to test it in a web environment (Layershift in my case), I can't get the JSON object. I don't see any errors on Chrome developer tools, but when I look into the Response tab (in Network option) I see the source code of the login page of my application. Let me show you the my code
Controller with the service:
#RestController
public class MyController {
#RequestMapping(value="/myservice/get/{somevar}")
public MappingJacksonValue getMyObject (#RequestParam String callback, #PathVariable String somevar, HttpServletRequest request, HttpServletResponse response) {
MyObject obj = new MyObject();
//some logic
MappingJacksonValue value = new MappingJacksonValue(obj);
value.setJsonpFunction(callback);
return value;
}
}
javascript code for call the service:
$.fn.callWithJsonP = function(somevar) {
var url = "/myservice/get/" + somevar + "?callback=myCallback";
$.getJSON(url, function(data) {
if (data.value.status == "OK") {
//shows the data contained
}
});
}
Apache configuration (added to avoid CORS error), present in both applications
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
Header always unset X-Frame-Options
This is working perfectly on muy local machine (except for the Apache, I don't use it locally), but as I said, on a web environment I receive the source code of my login page. In the Headers tab I can see the headers added in Apache, and the status code of the response is OK, any clues about what's goin on?
Kind regards
UPDATEI've removed the Apache web server, and even tested the web service with Postman (meaning, no second application), and still the same result. I've tried changing #RestController for #Controller and returning an instance of MyObject (instead of MappingJacksonValue), with no results, please help me
I am probably way off here, but is it possible that you have a servlet filter or other part of your web app config that is routing your get request to your login page before your REST framework is able to map it to your endpoint? I use Jersey for this usually, so I am unfamiliar with Spring's RestController, but I assume it is doing similar thing - routes URLs that match to the java code. If you are seeing login page in response it sounds like something is interfering and trying to force user to login before Spring directs to your endpoint method.
It seems like you have a fallback set in your server, maybe configured for a single page application. This is normally used for routing with HTML5 mode using routers like angular's.
you are getting the login page code as response because the login is failed and you are redirected to the same page.. so before calling the service first you need to do the authentication and then by using the authentication token call the service..

Spring #ResponseBody can not use session

I have angular2 app and use Tomcat with spring for getting data. I don't want any page reloads or redirects, all I need is data, so all responses from server have #ResponseBody annotations.
My problem is, that because of this annotation I can not get users session variable. When I log in I create session, store user data in it but can not get it with next call.
#JsonIgnoreProperties(ignoreUnknown = true)
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public String login(HttpServletRequest REQ, #RequestBody String BODY) throws Exception
{
...check if all ok...
REQ.getSession().setAttribute("user", user);
... return user data...
}
Is there any other way I can send my data back to client, together with the data needed, to be able to use session.
Edit:
Problem is not on server side but client. Angular is not sending cookie JSESSIONID at cross domain requests by default.
First check your request/response (for example in Chrome dev tools). Tomcat creates new cookie named JSESSIONID to bind client with server session object, so look for this one in your login method response header. Then make sure you are sending this cookie back to your server in next request. Session creation has nothing to do with Spring or #ResponseBody, its lifetime is managed by container (Tomcat).
Also, if you are making cross domain requests, check this answer.
Anything you put on the session context isn't available to clients, it's only available to the server. see this stack overflow post for a good explanation on how servlets work, and specifically the part on how session state works.
As you can see, it works by adding a session-cookie to the response which contains a session-Id. The server stores the session state under that id in memory, and when a future request comes with that session-id, it makes the session state available again to the future request.
If your next requests do not have access to the session state, it's quite possible that the session-cookie isn't propagated properly. I suggest you check that first. It should be in the response where you log in, and should be posted in further requests to the server.

Dropwizard View authentication by example

I'm familiar with implementing BasicAuth security in Dropwizard, but only for RESTful endpoints/resources.
I am now experimenting with Dropwizard Views to see if I can use it to be both a web and REST server all in one. The web app will have "public" pages (that are really just static HTML files; "About Us", "Contact Us", etc.) as well as "private" (dynamic) pages, which really form the app. To get to these pages the user must be authenticated (logged in).
So this means I have the need for two distinct DW authentication mechanisms:
A typical DW security mechanism for authenticating REST API clients, which I'm familiar with; and
A way to implement a log in system for authenticating end users for the web app pages/resources
Ideally, I'd like Apache Shiro to handle all auth for my system (REST and web alike), and I see the Dropwizard-Shiro lib, but that seems to only authenticate REST endpoints.
My web login system need to work like so:
A user tries to go to an "authenticated" (private) URL.
A servlet filter (that I create myself and register with the environment) intercepts the request and can tell (perhaps a cookie/session var?) whether the user is authenticated or not.
If the user is authenticated, they are allowed to proceed to their intended URL ("target URL"). Otherwise they are redirected to a login page. When they login a DW resource/controller hands their credentials off to Shiro, who then decides whether the credentials are valid or not.
If the credentials are valid, they get a cookie/session var (?) and are redirected to their target URL. Otherwise they are redirected back to the login page which will now display a failure message.
My main concerns are:
* What should I implement for the cookie/session var that the servlet will check for?; and
* How do I integrate my auth controller (that is, the resource that handles redirection between the login page and the target URL) with Shiro? Is it possible to do this via that Dropwizard-Shiro lib?
My best attempt thus far:
Custom Servlet Filter (registered with environment):
public class AuthFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) {
Cookie[] cookies = requestContext.getCookies();
boolean authenticated = false;
for(Cookie cookie : cookies) {
// 1. This is my first concern. What is better/more secure
// than what I'm doing here?
if("my_app_auth_cookie".equals(cookie.getName())) {
authenticated = true;
}
}
if(authenticated == false) {
responseContext.sendDirect("/auth/login");
}
}
}
If they are not authenticated they redirect to /auth/login which hits a AuthController (again, registered with the environment as a resource):
#Path("/auth")
#Produces(MediaType.TEXT_HTML)
public class AuthController {
#GET
#Path("/login")
public LoginPageView login() {
// Render some "login.ftl" template as HTML.
}
#POST
#Path("/authenticate")
public ??? authenticate(??? username, ??? password) {
// 2. Somehow send 'username' and 'password' to Shiro...
MyAppUser user = myAppRealm.authenticate(username, password);
// Now what do I do with 'user'?
}
}
When the user submits the form on the login page (which might be a POST to /auth/authenticate) we somehow hand their inputted credentials off to Shiro (again I'd like to use that Dropwizard-Shiro lib since I will likely also be using it for my REST endpoints).
Apache Shiro has its own type of filters which are configured in shiro.ini.
Example:
[urls]
/api/** = noSessionCreation, authcBasic
/views/login = authc
/views/authenticated = authc, user
Configure the authc filter to redirect to a login form page that you implement. Use the filter's form parameters and POST to /views/login.
If you enable the session manager in Jetty, Shiro should create servlet sessions when they log in from the login form page.
Please note that I haven't actually tested this configuration.

getting and setting cookie spring mvc

I am using #requestbody and #responsebody annotations for my authentication method using Spring MVC. I want to know how can I get and set cookies in spring mvc.. I need to store username and password in my cookie, which I am getting through the requestbody. Also want to know how can I get this set cookie in the browser, the next time the user logs in. Also does the browser sends the cookie automatically with the request body ? To be specific I don't want to go for Spring Security Remember me option. I am new to spring framework so an example code would be highly appreciated.
Ajax Code in JS:
var ajaxOptions = {
type: callType,
url: serviceCompleteUrl,
/* Add if required.
dataType: returnType */
async: false,
success: function(data, status, xhr) {
/*
* TODO: See if this is required
if (xhr.status == 200) {
*/
ajaxSuccess = true;
serviceResponse = data;
/*
}
*/
},
in the service I am just returning the object which will be mapped onto the serviceResponse and could be used by JS..
Sample code for service :
#RequestMapping("/login")
public #ResponseBody LoginObject Login(#RequestBody LoginParameter request)
{
/* Code */
return LoginObject;
}
This is how I am returning the object from the service, which is then catched by the serviceresponse in js..
Never store passwords (even encrypted) in Cookies. To implement the Remember me functionality you desire, you follow this answer
Update:
You need the logic for saving data in cookies on JS side. After the call to the service returns LoginObject, use some JS or jQuery code (like document.cookie="key=" + value;) to store data in cookies.

Categories