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);
Related
I'm developing a web app that will be used inside Cisco Jabber as a Custom Tab.
In my app the user needs to be logged in. The first authentication is done using Spring SAML (SSO). if this authentication fail then the user fallback to one of those auth process :
- A: directly with his userid (not a real auth but needed for some client)
- B: a login form (auth against client database)
The problem is that some actions are creating popups and with Jabber those popup are opened in Internet Explorer which doesn't have any information concerning my user and thus my app tries to authenticate him again. If SSO works no problem no action required by the user, if that fails auth A works fine but if auth B is selected then I have an issue because I need the user to be authenticated without him entering his credentials.
Is there a way with Spring, Spring Security to copy the session from Jabber to IE skipping the log-in page?
I followed the advice here and tried to set the jsessionid as parameter of my popup url like this:
var logUrl = 'login.do' + (this.user === '' ? ';jsessionid=' + sessionId : '?userId=' + this.user);
var w = window.open(logUrl, number, 'width=800,height=600,resizeable=yes,scrollbars=yes,toolbar=no,location=yes,status=yes,menubar=yes');
The problem is that when the user open the popup, the jsessionid in the url is not the same as the one in Jabber. And if I try to log in with the JSESSIONID of the user in Jabber it doesn't work.
Is there some configuration parameter I haven't set for this to work?
The session is tracked using the JSESSIONID cookie so you could pass this as a URL parameter on referral.
However, there are security concerns around session hijacking to consider with this approach.
For example, you must use SSL/HTTPS.
See this answer for more information.
Solution: We dropped the idea of re-using the session and are now using jwt instead as it achieve basically the same thing for us.
I have a web application that I deploy using JBoss 5.2. In order for a user to use the application, he/she must authenticate with an LDAP server (using simple authentication) with a username and password. This is all done through setting up the login-config.xml for JBoss and providing a <login-module> with our implementation.
The problem comes in here: After having logged in, I have a scenario that requires the user to provide a username & password when a particular action is performed (which I will also authenticate with the LDAP server). I want to be able to reuse the same mechanism that I use for authenticating the user into the web application.
My form to log in to the application posts to j_security_check so in accordance with this, I was trying to send a request to j_security_check but JBOSS returns a 404. From reading around a bit, I've gathered j_security_check cannot be accessed by any arbitrary request and must be in response to a challenged request to a secured resource.
So then, how can I authenticate the second set of credentials the user has provided with the same LDAP server?
EDIT:
To clarify, the question is how to send the user's credential inputs to the LDAP server for authentication. Grabbing the input from the user, etc. is all done. All that is left is to take this input and send it to the LDAP server and get the response (which is where I am stuck).
If it helps to mention, the login to the web application uses a custom class that extends UsernamePasswordLoginModule.
So, after lots of research, I ended up finding a solution for JBoss environments (which is what I'm using).
Once you capture the user's credentials, you send them to your server via a POST/GET and your server can perform the following to use whatever authentication policy you have configured (in login-config.xml) to verify the credentials:
WebAuthentication webAuthentication = new WebAuthentication();
boolean success = webAuthentication.login(username, password);
To expand on this, I was also able to check the user's role/group via the HttpServletRequest (which is passed into my server-side handler):
boolean userIsInRole = servletRequest.isUserInRole("nameOfGroup")
The spring security documentation explains it
Wanted to add another answer for JBoss 6.2+, where WebAuthentication no longer exists.
I've used the creation of a LoginContext to achieve the same result:
String SECURITY_DOMAIN_NAME = "ssd"; // the security domain's name from standalone.xml
String username = "user";
String password = "password";
LoginContext lc = null;
try {
lc = new LoginContext(SECURITY_DOMAIN_NAME, new UsernamePasswordHandler(username, password.toCharArray()));
lc.login();
// successful login
} catch (LoginException loginException) {
// failed login
}
And the use uf lc.getSubject().getPrincipals() to verify roles.
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
What I do manually:
I open the URL: http://localhost:8080/webadmin/index.html enter login and password.
And click button wich is really do http get request: http://localhost:8080/rest/platform/domain/list
What I do in java:
String addr = "http://localhost:8080/rest/platform/domain/list?_dc=1325843792402"; //"http://localhost:8080/webadmin/index.html";
URL url = new URL(addr);
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setDoOutput(true);
httpCon.setDoInput(true);
httpCon.setUseCaches(false);
httpCon.setAllowUserInteraction(false);
httpCon.setRequestMethod("GET");
OutputStreamWriter out = new OutputStreamWriter(httpCon.getOutputStream());
System.out.println(httpCon.getResponseCode());
System.out.println(httpCon.getResponseMessage());
out.close();
And get response: 401 Unauthorized.
Understandable why: I should create an authorised connection by entering a login and a password. But how I can do this?
On authentication using form fields in a web page, what happens is the following:
You access a login page. The server marks your session using one of the following methods:
Session cookie, present in the HTTP Response headers. You should store this cookie and resend it afterwards.
Redirect to a new URL in which the session is marked (http://localhost:8080/?sessionKey=3292n9fafjwagwao2903j2fswioanw)
(sometimes) hidden HTML form or Javascript variable which contains the session key and which is POST'ed on every click of a link.
Let us suppose the server uses cookies. You then do a POST request containing:
The cookie you received.
Your username and password in the POST data
The server now marks your session as "logged in" and may even give you a new or extra session identifier.
You then access a secured resource, providing a session identifier proving you are logged in.
You can follow this process very nicely using the Google Chrome Developer Network view (press CTRL+SHIFT+J, go to Network.
How do you translate this to Java code?
Do initial request to login page. Recover session cookie from HTTP headers.
Do a POST to the login form destination. Include the session cookie in the HTTP request header and the username/password in the POST data. Recover the session cookie from HTTP headers.
Now access the protected resource. Include the session cookies in the HTTP request header.
Of course, there are other ways of authenticating users at the webserver level (HTTP BASIC authentication, NTLM...), as explained by other answers here. The above method only works for HTML FORM-based authentication (as used by Facebook, Dropbox, ... and almost all major websites out there)
That depends on the authentication scheme. There are several possibilities, including
Basic access authentication
Digest access authentication
NTLM
Microsoft's HTTP Negotiate/SPNEGO
The server will tell you the correct scheme in its 401 answer. Look for the WWW-Authenticate HTTP header in the answer.
For doing HTTP authentication in Java, see this tutorial which contains a lot of useful information.
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.