I am having issue with Redirect in Java servlet. I want to use Status 401 ( Not authenticated ) instead of 302.
Let say that I have a protected resource with Url is "/protected". This Url mapped to ProtectedServlet. In doGet of ProtectedServlet, I will check whether the request is authenticated OR not, If not, the servlet will redirect the request to Login page. Here is my code:
ProtectedServlet.java
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
boolean isAuth = this.checkAuth();
if (isAuth == false) {
// WAY1
resp.setStatus(401);
resp.sendRedirect(resp.encodeRedirectURL(loginUrl));
// WAY2
resp.setStatus(401);
resp.setHeader("Location", resp.encodeRedirectURL(loginUrl));
}
}
RESULT
If I used "WAY1", when I request "/protected", I will see LOGIN page
but return Status is 302, NOT 401 as I expected.
If WAY2 used: When I request "/protected", I WILL NOT see Login
page. I see EMPTY page return with NO status.
Anyone know what I am wrong? Thanks.
The HTTP protocol is well defined. The client sends an HTTP request and the server sends them back an HTTP response.
The HTTP response can only have one status code. You can see your options here. In other words, you can't do a redirect by sending a 401. You could put a Location header in your 401 response but you would have to tell your client what to do with it because it isn't standard.
Instead of redirecting, if your user is not authenticated return a 401 and render the same Login page HTML, ie. do a RequestDispatcher#forward(..) to the login jsp.
Related
I have a problem with sending API request via postman or Java lib "io.restassured".
When I do the same action on UI the request returns correct response, but when I try the same thing via postman or java code I get:
401 Bad request Your browser sent an invalid
request.
The java code
public static void main(String[] args) {
String requestUrl = "exampleBaseUrl/app/reports/api/rest/v1/graphs?context=shipper&reports_type=freights";
Response response = RestAssured.given().relaxedHTTPSValidation().header("x-csrf-token", "18ea65e740eb0ddddadf0ef435d92564").
when().
get(requestUrl);
}
I assume something is wrong with the authentication, because in dev tools i can see a Get request for CSRF_token, and it looks like this:
the endpoint for the token:
/login?get_csrf_token
and for this request I get following response:
{"csrf_token":"18ea65e740eb0ddddadf0ef435d92564"}
I am not sure how to solve this, I have also tried to get the token via java code by sending a get request to the token's endpoint /login?get_csrf_token
and this one gets my a HTML response with empty username and password input.
Error 401 means your request isn't authorized.
For authorization, usually while logging in you are given a token, which you will have to keep in your cache/local-memory and whenever you communicate with the server you have to add that in your request header (for your own introduction to the server)
It seems like in your case you can get a token from /login?get_csrf_token after logging in. Note that you don't need authorization for a login service.
Now, after getting token from the server, how to add it as a request header? See REST Assured Documentation
I have a Java filter that allows continue or not the request depending of the URL, however I have a problem when the request come from a form.
Let's say I have a HTML form with an action and a submit button, then the filter evaluate the request, if the request is invalid I need to stop the request:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String requestDestination = ((HttpServletRequest) servletRequest).getRequestURI();
if ( requestDestination.contains("/url") ) {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
Cookie denied = new Cookie("denied", "url");
httpResponse.addCookie(denied);
return;
}
}
The problem is that despite this action, the browser goes to this URL showing an empty page off course, but what I need is to stop this default behavior, just leaving the user in the same page.
I can't use JavaScript since I don't know exactly who is triggering the request.
You cannot "stop" the request. Once the browser has submitted the form, it will await a response and will render the content of that response body.
Thus if your servlet filter is blocking the request, it is the responsibility of your filter to also return appropriate content to the browser. This is typically some type of error page, the content of which is entirely up to you.
If you want to make the user return back to the previous page, you can try redirecting the user to the url taken from the Referer header:
if ( requestDestination.contains("/url") ) {
String referer = request.getHeader("Referer");
if (referer != null && referer.length() > 0) {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(referer));
} else {
// just do nothing and display a blank page if there is no Referer
}
}
But for this to work, you need to be sure that the 'previous page' always accepts such a duplicated request using GET method.
It's not possible to do on server side -- because whatever server response is (and there is always a response, even for stopped requests), your browser will display it. Like empty response in your example.
There only thing you can try to archieve without JavaScript is to show user the same page he comes from:
you can just display the same page he comes from (with form, etc.)
you can redirect user to the same page with httpResponse.sendRedirect(httpRequest.getRequestURI())
I am trying to access the linkedIn api from my servlet, i am using OAuth Service.I am able to login from my application to the linkedIn account.Like i am posting the screen shot.
This is working fine .But the problem is that i am not able to get the value from the call back url.i.e
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*String callbackUrl = request.getRequestURL().toString();
HttpSession mySession = request.getSession();
*/
String authUrl = "https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=787mznyz5nn2nl&redirect_uri=http%3A%2F%2Flocalhost:8080%2FConnectSocialMedia%2F&state=DCEeFWf45A53sdfKef424";
//System.out.println("1st URL: "+authUrl);
response.sendRedirect(authUrl);
String query = request.getQueryString();
System.out.println("Query is -->"+query);
Can anyone help me to get the code and state after the allow access button??
The OAuth dance works like the following:
User attempts authentication to your site/app
Your app/site redirects the user to the oauth service provider(LinkedIn), therby passing on as a parameter a redirect url
User authenticates with oauth service provider and grants privileges to your site/app
The auth service provider redirects the user back to the url you provided in step 2
Your site/app must handle the redirected request and extract the oauth token
You need to implement 2 handlers - one for redirecting to LinkedIn with an redirect url provided and a second for accepting the redirect and extracting the token. From your description and code my surmise is that you have implemented half of the first handler.
I am currently developing an app that has a login, after the person logs in I want to remove the login page from history so that if they choose the back button (after login) it wont go back to the login page, but the one before it.
In javascript the code is location.replace('whatever_url_you_are_forwarding_to'); I want to know the equivalent in Java / JSF
There is no way for server-side Java code to modify the history of the client-side browser.
I wouldn't mess with the browser history: users expect a consistent and predictable behavior for the back button. If they want to go back to the login page, let them go back to the login page.
You can solve this the following way:
Tell the browser to not cache the login page, so that it will always send a fullworthy GET request on it instead of loading from the browser cache.
When the login page is requested while the user is already logged-in, then send a redirect to the desired page (which you've remembered in the session when the user logs in).
This could be done in one and same filter (although I'd personally prefer to disable browser caching on all change-sensitive dynamic pages, so that would then be done in another filter on a more generic URL pattern covering those pages).
Here's a kickoff example assuming that you're using container managed authentication (for homegrown authentication wherein you manually put the user in the session, just check the presence of the session attribute instead):
#WebFilter("/login.xhtml")
public class LoginPageFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession();
// Tell browser to not cache this page.
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
// Check if user is logged in.
if (request.getRemoteUser() == null) {
// Not logged in, so remember previous URL and continue request.
session.setAttribute("referrer", request.getHeader("referer")); // Yes, the misspelling is "correct"!
chain.doFilter(request, response);
}
else {
// Logged in, so redirect to initial referring URL, if any.
String referrer = (String) session.getAttribute("referrer");
if (referrer != null) {
response.sendRedirect(referrer);
}
else {
// There was no referring page. Just continue request?
chain.doFilter(request, response);
}
}
}
// ...
}
I've some web page deployed at some server say:
http://myhost/some_secured_file.html
when I access this file within a browser it returns 401 asking me to authorize myself.
The problem is that I am trying to include this page inside some JSP page using the c:import tag.
The app server returns :
javax.servlet.jsp.JspException: Problem accessing the absolute URL "http://myhost/some_secured_file.html". java
.io.IOException: Server returned HTTP response code: 401 for URL: http://myhost/some_secured_file.html
How I can accomplish the include!?
Consider proxying the request through another jsp page or servlet. Then you let the proxy perform an authenticating request, e.g., using Apache HTTPClient, and have the contents of that response written to the page. Then you can simply import the url of your proxy on your jsp page.
Alright, consider the following pseudo code as clarification:
class Proxy extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Perform a new request to get contents from secured page
HttpClient client = new HttpClient();
Credentials credentials = new UsernamePasswordCredentials("user", "pass");
client.getState().setCredentials(authScope, credentials);
GetMethod method = new GetMethod("/secure_page.jsp");
client.executeMethod(client.getHostConfiguration();, method);
// write result to the outputstream
resp.getWriter().write( method.getResponseBodyAsString() );
}
}
What this servlet does is fetch the secured page for you. You need to hook this servlet up in your web descriptor. This is necessary to map e.g., /proxy.jsp request to it. What you then can do in your jsp page is something like <c:import value="proxy.jsp"/>.