I have a requirement that I have to create a cookie on server side when page loads. In our AEM project I have a LocatorViewESBOfficeHelper.java file which is mapped to the JSP of the component (Say locateOffice). When page loads first time onGetData method of LocatorViewESBOfficeHelper.java is called.
In this method I want to create cookie using following code but I am unable to create it. When I use same create cookie code in a servlet and call it through ajax call, it successfully create cookie.
One possible reason could be when page is fully loaded, the response object could not have cookies. But I am unable to understand how to manage it.
You might have several problems.
Edit-Mode
You will not see session cookies in the editor, because your page is inside an iframe. Just do "View as published" (?wcmmode=disabled) to get your page directly in the browser window.
Wrong response object
The mapping LocatorViewESBOfficeHelper.java to the component sounds like someone tried to do some magic. Maybe your service doesn't get the real response object, but more a response wrapper. And the output of your service is somehow validated and written to the real response. In such cases, the http headers are often ignored.
Just create your own real AEM component, were the content is written by a SlingSafeMethodsServlet (registered via the resource type). If this works, you know where to go.
The following servlet does work good for me:
#Component(
service = Servlet.class,
property = {
SLING_SERVLET_RESOURCE_TYPES + "=/apps/myproject/components/cookie-test",
SLING_SERVLET_METHODS + "=GET",
SLING_SERVLET_EXTENSIONS + "=html"
})
public class CookieTestServlet extends SlingSafeMethodsServlet {
#Override
protected void doGet(#Nonnull SlingHttpServletRequest request, #Nonnull SlingHttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("<h2>Cookie Test</h2>");
Cookie cookie = new Cookie("alex", "this-is-a-test-" + (System.currentTimeMillis() % 10000));
response.addCookie(cookie);
}
}
Response buffer already flushed
The HttpServletResponse is more like a buffered Writer or OutputStream. You can only add http headers (or cookies) as long as the response output buffer was not flushed yet.
To verify this, either use the test component on a smaller page or simply increase in the OSGi configs the buffer to something real high (e.g. 1MB - but on your local instance only). Therefore go to the web console / OSGi / Configuration / Apache Felix Jetty Based Http Service / Response buffer size
(http://localhost:4502/system/console/configMgr/org.apache.felix.http)
I don't recommend to change it in production. So you should find another way to be early in the content generation. As most extreme workaround you could use a Sling request filter.
Opt-Out-Filter
If your project uses the Adobe Granite Opt-Out Service, then you might have to whitelist your cookie in the OSGi configuration. By default this service should not do anything.
Try Other Alternatives
As alternative I would propose:
Use a Sling Filter
Create the Cookie front-end with JavaScript
I hope one of my ideas might point you in the right direction.
Alex
Related
Background:
I programmed 2 ZK web applications (ZK653CE) with netbeans 8.1 both are moduls for a single task.
Now I want to access application B from within application A both projects are on the same Tomcat 8 webserver.
Why I want to do this:
Application A has a user login and presents data to the user. Application B allows anybody to create a pattern for displaying data. I want a user to start application B and create a pattern (Press save close app). This pattern shall be send back to application A that then changes the display behaviour of the data to the new pattern. I do not want to mix those 2 applications together, because I want them to stay independent.
What I already figured out while searching this topic:
It is not possible to directly access an external webapp from within a zk project
It would be possible to use a shared ressource concept from tomcat (but I don't want that because I want this to run on different webservers like glasfish and others)
The real question:
Is there a way to have both apps independent (if yes please explain or show an example) or do I have to merge them?
I had much time to try differnt things I'll show the 2 best solutions I came a cross:
Using Cookies
One can use Cookies to store data at the client and use the server to access it. It's commonly used for sessionmanagement or other parts that control the content for the current user.
To access Cookies one would use this code in a ZK Class (Controller or Viewmodel):
HttpServletRequest req = (HttpServletRequest) Executions.getCurrent().getNativeRequest();
Cookie[] cookies = req.getCookies();
This will load all cookies of the current session. The HttpServletRequest class can be found in the java docs for more information (it represents the raw client http request). One can then iterrate through the array and look for a Cookie
HttpServletResponse resp = (HttpServletResponse) Executions.getCurrent().getNativeResponse();
for(Cookie c : cookies) {
if(c.getName().equals(COOKIE_MODE)) {
externalAccess = Boolean.parseBoolean(c.getValue());
c.setMaxAge(0);
c.setValue(null);
c.setPath(NAMESPACE);
resp.addCookie(c);
}
}
externalAccess stores if the modul was loaded from an external modul. This external module would have to create that Cookie first of course. The set parameters are used to delete the Cookie setting the age to 0 means its expiered one also sets the value and if a path was used to create it one must also set the path because it must be known where the old Cookie was placed. The cookie must be added to a HTTP Response for the client (from the server) so that the client replaces its old Cookie.
To create a cookie one would use this:
Cookie cookie = new Cookie(COOKIE_NAME, COOKIE_VALUE);
cookie.setPath(NAMESPACE);
HttpServletResponse resp = (HttpServletResponse) Executions.getCurrent().getNativeResponse();
resp.addCookie(cookie);
This is very similar to the for loop before.
Approach
Just add a parameter to the URL (commonly used to provide parameters):
If one hase a webserver on localhost its address is probably this:
http://localhost:8080/
a modul is loaded to / or if a subfolder is specified /modul
if one has a .zul in /modul named index.zul
one can access it by using http://localhost:8080/modul/index.zul
if one want's to add a parameter it would be done like this:
http://localhost:8080/modul/index.zul?externalAccess=1
one can then access this in the viewmodel or controller of index.zul (i used MVVM) with the following code:
String external = Executions.getCurrent().getParameter("externalAccess");
One can then cast the parameter to ones liking.
To create a redirect that uses the URL above one can use this:
Executions.sendRedirect("http://localhost:8080/modul/index.zul?externalAccess=1");
one can get the URL to ones server and the current application like this:
Server:
String server = Executions.getCurrent().getScheme() + "://" + Executions.getCurrent().getServerName() + ":" + Executions.getCurrent().getServerPort();
For the path to the application starting with "/":
Executions.getCurrent().getContextPath() + Executions.getCurrent().getDesktop().getRequestPath();
One could also use a config file that has the URLs stored (on webserver) but i won't cover that here
I have a small servlet returning several html pages. The content of one of these pages is pretty complex, but changes only every hour or so. However, it is requested often by users. I want to avoid recomputing it at each request.
I was wondering whether it is possible to prepare a gzip-ed version in memory (byte array), and set it as the response to all HTML requests for this page. I would also recompute a new cached gzip-ed version every hour.
If this is possible, how can I do this? Should I use a filter? For the sake of this question, we can assume that all browsers can handle gzip-ed responses. I am looking for a code example.
After quite some googling, this seems to be the solution:
public class MyFilter implements Filter {
private byte[] my_gzipped_page = ....
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
if (req instanceof HttpServletRequest) {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String ae = request.getHeader("accept-encoding");
if (ae != null && ae.indexOf("gzip") != -1) {
response.addHeader("Content-Length",
Integer.toString(my_gzipped_page.length));
response.addHeader("Content-Encoding", "gzip");
OutputStream output = response.getOutputStream();
output.write(my_gzipped_page);
output.flush();
output.close();
return;
} else ...
}
}
...
}
Why doing it the hard way?
Open Tomcat's /conf/server.xml, lookup the <Connector> for your HTTP port and edit it as follows to add a new attribute:
<Connector ... compression="on">
Tomcat will then GZIP all responses matching compressableMimeType automagically when the client supports it. All other self-respected webservers have a similar configuration setting.
It's not really clear from your question but I'm guessing you're looking for info on how to cache data, rather than how to serve compressed data. Most web servers will automatically compress data if configured to do so, and if the client supplies the necessary headers in the request. In other words, you don't need to compress the page before transmitting it, the server will compress it automatically if possible.
For caching, you can store a processed version of the page either on disk or in memory using for example memcache.
If you know that you'll only need to update the page, say, every hour, you can run a script, for example with crontab, to generate the page every hour and just serve the generated page. That should be fairly straight forward as you don't really need to make special considerations as far as caching on the server side.
On the other hand, if you need to check if the page is stale before deciding wether to use the cached version or a fresh one, it gets a little more complex. For example it's possible that checking if the data is stale is almost as costly as generating the page.
Can't really give a more specific answer without more details.
there are a bunch of links accessing my servlet without https
As the servlet is a generic form and the http urls are generated with an random id it is difficult to use modrewrite or something like that.
Therefore I modified my servlet with code like that:
//redirect to https
String sec = servletRequest.getParameter("Sec");
String qString = servletRequest.getQueryString();
if (StringUtils.isEmpty(sec)){
try {
HttpServletResponse rsp = request.getServletResponse(true);
String PORTAL_URL = l_aliasHelper.getPath(request);
rsp.sendRedirect("https://"+servletRequest.getServerName() +PORTAL_URL+"?" +qString+"&Sec=yes");
} catch (Exception e) {
e.printStackTrace();
}
}
Now this works fine!
But, what if I want back to http because I want to avoid nagging warnings about insecure elements on other pages.
So how do I redirect to http again after the user has submitted the form?
If everything worked well the user gets displayed a response with a success message under the same URL he started.
So the cycle goes like this:
http://<somedomain>/<anypath>?<anyid>
https://<somedomain>/<anypath>?<anyid>&Sec=yes
and now it should go back maybe with a step inbetween to
http://<somedomain>/<anypath>?<anyid> <- the success message should be
displayed here
the last method before the message is displayed is
sucessmessage.render(request,response)
request and response are both appserver component specific views on all request / response related matters. They have methods like:
getServletResponse
public HttpServletResponse getServletResponse(boolean answering)
Gets the original servlet response. Note: This should be accessed
in extraordinary cases only. If the parameter is set to true all
further content procession of the runtime will be skipped. This is
only available, if the request was initiated from a servlet based
connection.
So how can the response be manipulated in a way that the form is submitted secure, but the user can go on with http on the rest of the site afterwards.
It seems like you are trying to do too much in one place. Maybe the following break down will be easier:
Specify https in the URL for the action parameter in HTML form.
Create a ServletFilter class that uses ServletRequest.isSecure() to
make sure that requests to your form action actually came in over
https. This could also be in your action servlet, but making it a filter means you can reuse it. Just make sure the secure servlets have this filter set.
In your form action servlet, simply send a redirect to the
success page over http
I am currently implementing an OpenID Relying Party (RP) and Identity Provider (IdP) with Java HttpServlets using the OpenID4Java library. I have run into trouble getting two servlets to communicate with each other. I believe the problem I am having is to do more with how Servlets behave, however I have included info about my application for a better sense as to what is happening.
The scenario is as follows:
Servlet #1 (my RP) sends a request to Servlet #2 (my IdP) as follows:
httpResp.sendRedirect(authReq.getDestinationUrl(true));
Essentially authReq = a message with various OpenID specific parameters. By invoking getDestinationUrl(true) it encodes the request into a url to send via a GET.
Servlet #2 catches the above GET in its doGet method. It parses the information, and crafts a reply to send back to Servlet #1 in the following fashion:
String responseText = processRequest(httpReq, httpResp);
httpResp.setContentType("text/html");
OutputStream outputStream = httpResp.getOutputStream();
//
outputStream.write(responseText.getBytes());
outputStream.close();
My problem is, this response never makes it back to Servlet #1. I would expect that when Server #1 receives the response from Servlet #2 that its' doGet or doPost method would catch the message. However neither case happens.
Any advice would be greatly appreciated.
Thanks!
The response of 2nd servlet will directly go on client side i think because its is the original client right? Your 1st servlet is just redirecting the request.
So, if you want to communicate between servlets, Use URLConnection or Apache HttpClient to communicate with 2nd servlet.
You can also make JSP instead of 2nd servlet, then pass you data from 1st servlet to that JSP. That JSP's response will be sent to client then. After all you can do all logic in JSP what you can in servlet.
Hope this helps.
parth.
If you want two servlets to communicate with each other within an application, you can use the ServletContext object and share data via ServletContext.setAttribute and ServletContext.getAttribute and RequestDispatcher obtained via HttServletRequest or ServletContext
In your case can the Servlet#2 be invoked directly by the client? If not then you should probably refactor the processRequest(request, response) into a Utility class or a library. Which in turn can be called by both Servlet#1 and Servlete#2.
response.sendRedirect sends a redirect (301 moved permenently, ithink) to the browser. So your servlet actually sends a response to browser with 301 and then browser makes a request to servlet#2 again.
You can use RequestDispatcher to include your second servlet's response. In this way, the control returns to the first servlet after the method completes.
RequestDispatcher dispatcher = request.getRequestDispatcher(authReq.getDestinationUrl(true));
dispatcher.include(request, response);
However, with this, the response generated by the called servlet will be sent to the browser. If you want your calling servlet to capture the message from called servlet without sending to browser, you can either create a response wrapper (A wrapper writing the contents in a string) and pass this wrapper when you include the second servlet or better you can share the data in either of the scopes (Preferably 'request' scope): You can set the data in the request scope in called servlet and you can retrieve it in the calling servlet after include() completes.
When you redirect, you are telling the browser to make a new request for the URL. So there will be new request/response objects created as if you had clicked on a link in your page.
Hope this helps.
We have a JSF web application that uses Acegi security. We also have a standalone Java Swing application. One function of the Swing app is to load the user's home page in a browser window.
To do this we're currently using Commons HttpClient to authenticate the user with the web app:
String url = "http://someUrl/j_acegi_security_check";
HttpClient client = new HttpClient();
System.setProperty(trustStoreType, "Windows-ROOT");
PostMethod method = new PostMethod(url);
method.addParameter("j_username", "USERNAME");
method.addParameter("j_password", "PASSWORD");
int statusCode = client.executeMethod(method);
if (statusCode == HttpStatus.SC_MOVED_TEMPORARILY ) {
Header locationHeader= method.getResponseHeader("Location");
String redirectUrl = locationHeader.getValue();
BrowserLauncher launcher = new BrowserLauncher();
launcher.openURLinBrowser(redirectUrl);
}
This returns a HTTP 302 redirect response, from which we take the redirect url and open it using BrowserLauncher 2. The url contains the new session ID, something like:
http://someUrl/HomePage.jsf;jsessionid=C4FB2F643CE48AC2DE4A8A4C354033D4
The problem we're seeing is that Acegi processes the redirect but throws an AuthenticationCredentialsNotFoundException. It seems that for some reason the authenticated credentials cannot be found in the security context.
Does anyone have an idea as to why this is happening? If anyone needs more info then I'll be happy to oblige.
Many thanks,
Richard
I have never done Acegi/SpringSecurity, but the symptoms are clear enough: some important information is missing in the request. You at least need to investigate all the response headers if there isn't something new which needs to be passed back in the header of the subsequent request. Maybe another cookie entry which represents the Acegi credentials.
But another caveat is that you in fact cannot open just the URL in a local browser instance, because there's no way to pass the necessary request headers along it. You'll need to have your Swing application act as a builtin webbrowser. E.g. get HTML response in an InputStream and render/display it somehow in a Swing frame. I would check if there isn't already an existing API for that, because it would involve much more work than you'd initially think .. (understatement).
In this case you can do Basic Authentication and set this header in every request instead of sending the jsessionid:
AUTHORIZATION:Basic VVNFUk5BTUU6UEFTU1dPUkQ=
The token VVNFUk5BTUU6UEFTU1dPUkQ= is the username and the password encoded base64.
Example:
scott:tiger
is:
c2NvdHQ6dGlnZXI=
One more thing: use SSL.