Okay, so I have most of the pieces, but I can't seem to put them together properly. I'm basically trying to protect database data with a simple authentication process (maybe with a GUI) to ensure that the correct people are viewing the data. Right now I'm using UnboundID to handle the actual authentication, although I am open to other methods such as JAAS. Here is the method that I wrote for that (the bypass is for testing purposes):
public static boolean authenticate(String username, String password) {
if (username == null || password == null) {
return false;
}
if (username.equals("bypass") && password.equals("bypass")) {
return true;
}
try {
LDAPConnection conn = new LDAPConnection(AUTH_URL,AUTH_PORT);
BindRequest request = new SimpleBindRequest(username,password);
BindResult result = conn.bind(request);
return result.getResultCode().equals(ResultCode.SUCCESS);
} catch (LDAPException ex) {
ex.printStackTrace();
return false;
}
}
This code is obviously dangerous due to the fact that the password is being inputted as plaintext. I did some digging and discovered that I should be using something like SSL for the actual request to protect the password. This raised another question: if I'm sending the request via SSL, don't I still need to somehow supply the password in plaintext form before I send the request? Isn't this dangerous? I'm surprised something like password authentication isn't done by a simple API since so many applications need to be secure. I'm very new to this stuff and would appreciate some guidance. Thanks!
Use TLS everywhere including your LDAP connection. As long as you follow good TLS connection practices your connection is safe.
-jim
You could use Stormpath's Servlet Plugin to authenticate your users. You only need to follow these very simple steps to create your ready to use Web Application.
You can also take the example Servlet App (completely Open Source) as the foundations for your Web App.
You will get:
Out of the box complete Web Application
Complete User Management: user authentication, user management, user storage, workflows, etc.
API Management
Hassle free world-class Security
Frequent free updates
In summary, the workflow will be like this. You will redirect your users to the Login page (or Registration for them to sign up first). Once your user is properly authenticated (via login) you can get your own code executed via the Next URI or the SuccessfulAuthenticationRequestEvent.
Disclaimer, I am an active Stormpath contributor.
Related
Ok, Here is my scenarios. I manage session at server side, see the following code:
HttpSession session = requestProvider.get().getSession();
String userMeaningID=(String)(session.getAttribute("userMeaningID"));
Then I bring the userMeaningID into client website, this code is at clinet
private AsyncCall<PostSignUpResult> postSessionCallback=new AsyncCall<PostSignUpResult>(){
#Override
public void onCustomSuccess(PostSignUpResult result) {
String userMeaningID=result.getUserMeaningID();
if(userMeaningID!=null && isNumber(userMeaningID)){
// user can manipulate info here
}
}
}
so my question is that, is there any risk that hacker somehow pass the fake userMeaningID into result so that result.getUserMeaningID(); will return the fake ID & thus the hacker can play with the data on client. This is not a too big problem cos even they mess up data & send to server, then at server side I double check data again to make sure they valid.
Although all data will be checked at server side before inserting into DB I still want to know
Is there any risk of hacker intercepting the session data that is downloaded into client website in GWT?
If there is a risk then how can we deal with it?
SSL is only part of the solution since an attacker can still steal a session and send requests to attack your rpc services. Use XSRF token to ensure third parties can't send malicious requests to the rpc services handled by GWT.
The implementation is straightforward. http://www.gwtproject.org/doc/latest/DevGuideSecurityRpcXsrf.html
Well yes, when your network is compromised it is possible for a hacker to intercept data and send you false data (e.g.: Man-in-the-midle-attack). You can protect yourself from such attacks by securing your connection through asynchrous encryption algorithms (e.g. algorithms like a SSL, etc.). The https:// protocol is an example of such a secure connection.
But I wouldn't worry too much about this scenario. Unless you're coding a bank's website or an online nuclear launch controller, this is all overkill for your standard web application.
I am obtaining a kerberos ticket with the following code:
String client = "com.sun.security.jgss.krb5.initiate";
LoginContext lc = new LoginContext(client, new CallbackHandler() {
#Override
public void handle(Callback[] arg0) throws IOException, UnsupportedCallbackException {
System.out.println("CB: " + arg0);
}
});
lc.login();
System.out.println("SUBJ: " + lc.getSubject());
This code works fine, I get a subject that shows my user ID. The problem I'm having is now I need to know whether the user belongs to a certain group in AD. Is there a way to do this from here?
I've seen code to get user groups using LDAP but it requires logging in with a user/password, I need to do it the SSO way.
You cannot actually do this with the kind of ticket you get at login. The problem is that the Windows PAC (which contains the group membership information) is in the encrypted part of the ticket. Only the domain controller knows how to decrypt that initial ticket.
It is possible to do with a service ticket.
So, you could set up a keytab, use jgss to authenticate to yourself and then decrypt the ticket, find the PAC, decode the PAC and then process the SIDs. I wasn't able to find code for most of that in Java, although it is available in C. Take a look at this for how to decrypt the ticket.
Now, at this point you're talking about writing or finding an NDR decoder, reading all the specs about how the PAC and sids are put together, or porting the C code to Java.
My recommendation would be to take a different approach.
Instead, use Kerberos to sign into LDAP. Find an LDAP library that supports Java SASL and you should be able to use a Kerberos ticket to log in.
If your application wants to know the groups the user belongs to in order to populate menus and stuff like that, you can just log in as the user.
However, if you're going to decide what access the user has, don't log in as the user to gain access to LDAP. The problem is that with Kerberos, an attacker can cooperate with the user to impersonate the entire infrastructure to your application unless you confirm that your ticket comes from the infrastructure.
That is, because the user knows their password, and because that's the only secret your application knows about, the user can cooperate with someone to pretend to be the LDAP server and claim to have any access they want.
Instead, your application should have its own account to use when accessing LDAP. If you do that, you can just look up the group list.
I do realize this is all kind of complex.
I am experimenting with GWT RequestFactory (RF) for the first time and am trying to implement a simple sign-in screen and authentication system (not using anything fancy, just fiddling around with the basics here). The basic user experience I'm looking to achieve is pretty par for the course:
The user will be presented with a sign-in screen (email and password and "Sign In" button). When they click the button, I want to use RF to send their credentials to the server (using ValueProxy since these are not entities) and authenticate them. If the credentials were correct, they are now "signed in" to the system, and the GWT app will download a whole new module and they'll be redirected to their account's main menu. If the credentials were incorrect, I want to send back a String explaining that the email or password was incorrect, and they are still "signed out" of the app.
Regarding this question that I posted yesterday, I have now figured out how to use RF to expose a SignInOutService which has a signIn(SignIn) method for attempting to sign the user in, and a signOut(SignOut) method for signing the user out of the system. But now I'm actuallly trying to implement that service, and here's what I have so far:
public class DefaultSignInOutService {
// Try to sign the user into the system.
public String signIn(SignIn signIn) {
// The SignIn object contains the email/hashed password the user tried
// signing-in with, as well as other metadata I'm looking to store for
// security purposes (IP address, user agent, etc.).
String email = signIn.getEmail();
String hashedPassword = signIn.getHashedPassword();
// This will be set to a non-null value if the sign-in attempt fails.
// Otherwise (on successful sign-in) it will stay NULL. The client-side
// handler will know what to do with the UI based on this value.
String failReason = null;
// For this simple example, the password is "12345" and below is it's MD5 hash.
// Hey! That's the combination on my luggage!
if(!"skroob#spaceballs.example.com".equals(email) || !"827ccb0eea8a706c4c34a16891f84e7b".equals(hashedPassword))
failReason = "Login failed; incorrect email or password.";
else {
// Log the user into the system...
// TODO: How?
}
return failReason;
}
// Sign the user out of the system.
public void signOut(SignOut signOut) {
// The SignOut object should reference the user attempting to sign out, as well as a reason
// for why the sign out is occurring: the user manually requested to be signed out, or they
// "expired" due to inactivity or navigating the browser away from the app, and so the system
// auto-signed them out, etc.
// TODO: How?
return;
}
}
So now, I've implemented my super-simple email/password check, and I'm ready to write the code that somehow signs the user into the app (so that they're not presented with a login screen over and over again). And I'm choking on what to do next.
Issues I'm trying to find solutions for:
Is GWT RF somehow session- or token-based? If so, under the commented line "Log the user into the system...", what code can I write that says "this user is now authenticated, set some cookie or session variable to make it so!"? I ask this because once they sign in and are routed to the new module and main menu, GWT will need a way to authenticate every subsequent RF request thereafter.
What does the signOut() method need to reset/clear/nullify in order to clear these cookies/session vars? In other words, how do I actually sign the user out, so if they try to go to the URL for their main menu (which again is only accessible if they're signed in), they'll be redirected to the sign-in screen?
How could I implement a 15-min inactivity timeout, where the user is automatically signed out of the app after a certain length of time? I think this answer will become more obvious once I see how questions #1 and #2 above work.
I was told that I may need to have two servlets and/or filters: one for handling unauthenticated RF requests (while a user is signed out or has not yet signed in), and one for handling authenticated RF requests (once the user is actively signed in). But I can't see how they fit into the overall picture here.
The easiest way is to store your authentication details in session.
public String signIn(SignIn signIn) {
...
if(!"skroob#spaceballs.example.com".equals(email) || !"827ccb0eea8a706c4c34a16891f84e7b".equals(hashedPassword))
failReason = "Login failed; incorrect email or password.";
else {
RequestFactoryServlet.getThreadLocalRequest().getSession().setAttribute("auth", signIn);
}
return failReason;
}
public void signOut(SignOut signOut) {
RequestFactoryServlet.getThreadLocalRequest().getSession().removeAttribute("auth");
return;
}
On every request you can check if SignIn object is still present in session:
SignIn signIn = null;
final Object userObject = RequestFactoryServlet.getThreadLocalRequest().getSession().getAttribute("auth");
if (userObject != null && userObject instanceof SignIn) {
signIn = (SignIn) userObject;
}
In case of absence of this object you should cancel the request and redirect user to login page.
I am currently working on a installed desktop application implemented in java. I intend to integrate Google Calendar API into the application.
During the authorization procedure, I come to this stage where I am able to get the authorization code only through triggering a browser where the user consent page is displayed. Users then have to click "accept" and will be redirected to a webpage where the authorization code is presented. Users are to copy this code to the Eclipse System.in in order for the authorization process to continue (to exchange the authorization code for a TokenResponse).
My question is that how can I simplify this process so that the user won't have to do this stupid copy-and-paste stuff for the authorization code to be received? (This won't work anyway, if the project is compiled into a jar file...) Currently all I know is that I will need to provide a callbackurl or something, I just can't figure this out. Therefore, I would appreciate a more concrete answer, rather than simply tell me the concepts.
Thanks in advance.
You have to use a service account (which comes with a private key) in order to skip the step involving user interaction. There is a detailed guide about this here.
The oauth2 authorization grant flow (I think, that's what you are doing) defines that your application gets the flow back via a HTTP redirect.
It's like this:
Your application opens a socket and listens there for HTTP requests
It now opens the browser and lets the user enter his/her credentials
The user clicks submit and sends the credentials to the oauth server
The server checks the credentials and, if correct, redirects the browser to your application (to the socket you opened in 1.)
Your application gets the auth code from the browser and exchanges it with the access ticket.
To let the server know where to redirect to, you use the oauth parameter redirect_uri in step 2.
This page seems to indicate that the auth code is in the title of the browser window, and the desktop app is expected to read it from there. (Gack.)
I found the solution.
Note: this is java code, but I bet it works the same way in all other languages.
The problem is my server is very restricted with and so I cannot start either browser there(since that is just a server without UI), either start localhost server for getting the code.
All you need is custom VerificationCodeReceiver:
VerificationCodeReceiver inbrowserListener = new VerificationCodeReceiver() {
#Override
public String getRedirectUri() throws IOException {
return "urn:ietf:wg:oauth:2.0:oob";
}
#Override
public String waitForCode() throws IOException {
// Reading console line
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
return reader.readLine();
}
#Override
public void stop() throws IOException {
}
};
then simply use it in usual flow:
private static Credential getCredentials() {
.....
return new AuthorizationCodeInstalledApp(flow, inbrowserListener).authorize("user");
}
I am Using Google App Engine for Java and I want to be able to share session data between subdomains:
www.myapp.com
user1.myapp.com
user2.myapp.com
The reason I need this is that I need to be able to detect if the user was logged in on www.myapp.com when trying to access user1.myapp.com. I want to do this to give them admin abilities on their own subdomains as well as allow them to seamlessly switch between subdomains without having to login again.
I am willing to share all cookie data between the subdomains and this is possible using Tomcat as seen here: Share session data between 2 subdomains
Is this possible with App Engine in Java?
Update 1
I got a good tip that I could share information using a cookie with the domain set to ".myapp.com". This allows me to set something like the "current_user" to "4" and have access to that on all subdomains. Then my server code can be responsible for checking cookies if the user does not have an active session.
This still doesn't allow me to get access to the original session (which seems like it might not be possible).
My concern now is security. Should I allow a user to be authenticated purely on the fact that the cookie ("current_user" == user_id)? This seems very un-secure and I certainly hope I'm missing something.
Shared cookie is most optimal way for your case. But you cannot use it to share a session on appengine. Except the case when you have a 3rd party service to store sessions, like Redis deployed to Cloud Instances.
You also need to add some authentication to your cookie. In cryptography there is a special thing called Message Authentication Code (MAC), or most usually HMAC.
Basically you need to store user id + hash of this id and a secret key (known to both servers, but not to the user). So each time you could check if user have provided valid id, like:
String cookie = "6168165_4aee8fb290d94bf4ba382dc01873b5a6";
String[] pair = cookie.split('_');
assert pair.length == 2
String id = pair[0];
String sign = pair[1];
assert DigestUtils.md5Hex(id + "_mysecretkey").equals(sign);
Take a look also at TokenBasedRememberMeServices from Spring Security, you can use it as an example.