java http authentication reuse between servlets - java

not sure how to formulate the question correctly.
i've got two web-apps: A with a servlet and B with two servlets, both protected by basic authentication in web.xml (deployed to weblogic server).
a user authenticates to A and to one of B's servlets (not sure if what i say here is total rubbish) using browser-native login/password window (that's managed by weblogic).
however, the servlet of application A should as well call the other of B's servlets and that requires authentication also.
the question is: can it be avoided? the user has already authenticated to both of web-apps, so i'd like to just somehow reuse this authentication (i'm really not good at all these http session things terminology, don't throw rocks at me :)).
cookies can't be used it seems, as it is really server-side communication.

following should fix the problem:
create javax.servlet.Filter that extracts jsessionid from requests and stores it per user somehow (in my case i put it to org.springframework.security.core.Authentication as details, making sure this filter runs after spring-security's one).
add it to each servlet-servlet request as cookie header:
org.apache.commons.httpclient.HttpMethodBase.setRequestHeader("Cookie",
"jsessionid="+org.springframework.security.core.Authentication.getDetails().toString());
where appropriate.

Do this in your servlet code in app A:
URLConnection conn = new URL("http://hostname/appB/servlet1");
String authorizationHeader = request.getHeader("authorization");
if (null != authorizationHeader) {
conn.setRequestProperty("authorization", authorizationHeader);
}
InputStream inStream = conn.getInputStream();
//Read from inStream in the usual way

Related

How to create cookies in AEM in Java in ViewHelper?

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

ZK multiple webapps in a single project

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

Response code 401 when accesing rest based web services with correct credentials

I am getting Unauthorized error when accessing restful web services. My sample program looks like this.
public static void main(String[] args){
// Use apache commons-httpclient to create the request/response
HttpClient client = new HttpClient();
Credentials defaultcreds = new UsernamePasswordCredentials("aaa", "cdefg");
client.getState().setCredentials(AuthScope.ANY, defaultcreds);
GetMethod method = new GetMethod(
"http://localhost:8080/userService/usersByID/1234");
try {
client.executeMethod(method);
InputStream in = method.getResponseBodyAsStream();
// Use dom4j to parse the response and print nicely to the output stream
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
System.out.println(out.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
My credentials are correct. My web services will consume Basic Http Authentication.
I have doubt at scope of authentication.
client.getState().setCredentials(AuthScope.ANY, defaultcreds);
My credentials are correct.
Can any one help to resolve this issue.
Thanks.
First check your url via browser and verify ?? as mentioned here
Fixing 401 errors - general
Each Web Server manages user authentication in its own way. A security officer (e.g. a Web Master) at the site typically decides which users are allowed to access the URL. This person then uses Web server software to set up those users and their passwords. So if you need to access the URL (or you forgot your user ID or password), only the security officer at that site can help you. Refer any security issues direct to them.
If you think that the URL Web page *should* be accessible to all and sundry on the Internet, then a 401 message indicates a deeper problem. The first thing you can do is check your URL via a Web browser. This browser should be running on a computer to which you have never previously identified yourself in any way, and you should avoid authentication (passwords etc.) that you have used previously. Ideally all this should be done over a completely different Internet connection to any you have used before (e.g. a different ISP dial-up connection). In short, you are trying to get the same behaviour a total stranger would get if they surfed the Internet to the Web page.
If this type of browser check indicates no authority problems, then it is possible that the Web server (or surrounding systems) have been configured to disallow certain patterns of HTTP traffic. In other words, HTTP communication from a well-known Web browser is allowed, but automated communication from other systems is rejected with an 401 error code. This is unusual, but may indicate a very defensive security policy around the Web server.
Manual Fix
Hit the url from the browser and record the HTTP traffic (Headers,body)
Run the Java client code and record the HTTP traffic (Headers,body)
Analyze and fix the differences

Spring Security Logout and standalone application

I have a SOAP web service that is secured with Spring Security using basic authentication.
I've written a Swing application that accesses this web service. When the application starts, a login dialog appears where the user enters its credentials. When the user clicks the Login button, the JAXWS client is created with the given credentials. I also want to give the possibility to the logged user to logout. Spring Security requires to access a URL in order to logout. How does that work in a standalone application? Should this be done through CXF or using a simple HTTP client?
Avoid sessions altogether and have your JAXClient reauthenticate on every conn request. Configure your secuity.xml with stateless which is available from Spring Security 3.1.
It does not matter how do you implement this. The only requirement is to create HTTP GET to logout URL but your request should contain session ID of your session. Otherwise Spring cannot know which session to invalidate. So, I think that the easiest way for you is to use the same client you are currently using.
Ok, I'm not gonna argue about stateful vs. stateless. If you need to logout from your Swing app just send an HTTP GET request to the configured logout URL sending the session ID along. You don't even need Apache HttpClient for this:
String url = "http://example.com/logout";
String charset = "UTF-8";
String session = ";jsessionid=" + sessionId;
URLConnection connection = new URL(url + session).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
See https://stackoverflow.com/a/2793153/131929 (Firing a HTTP GET request) for details.
You can either append to session ID directly to the URL as shown above or send it as a regular cookie header like so:
connection.addRequestProperty("Cookie", "JSESSIONID=" + sessionId);

Acegi throws AuthenticationCredentialsNotFoundException when opening URl with BrowserLauncher 2

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.

Categories