package edu.lmu.cs.headmaster.client.web;
import java.io.IOException;
import java.util.Collection;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.wicket.Request;
import org.apache.wicket.authentication.AuthenticatedWebSession;
import org.apache.wicket.authorization.strategies.role.Roles;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Session class for the Headmaster client.
*/
public class HeadmasterSession extends AuthenticatedWebSession {
public HeadmasterSession(Request request) {
super(request);
clearUserData();
}
@Override
public boolean authenticate(String username, String password) {
// We authenticate by accessing the user's roles.
DefaultHttpClient httpClient = new DefaultHttpClient();
String serviceUri = ((Headmaster)getApplication()).getServiceRoot() +
"users/login/" + username;
getLogger().info("Authenticating with serviceUri: [" + serviceUri + "]");
// Supply credentials.
httpClient.getCredentialsProvider().setCredentials(
new AuthScope(null, -1), // This is strictly between the web app and the service, so
// no need to get any more specific.
new UsernamePasswordCredentials(username, password)
);
// Create the request. We want JSON.
HttpGet httpGet = new HttpGet(serviceUri);
httpGet.setHeader("Accept", "application/json");
ResponseHandler<String> responseHandler = new BasicResponseHandler();
try {
String response = httpClient.execute(httpGet, responseHandler);
// The response is JSON; parse it.
ServiceUser serviceUser = new ObjectMapper().readValue(response, ServiceUser.class);
currentRoles = new Roles();
// Include a catch-all for anyone with credentials.
currentRoles.add(Roles.USER);
for (ServiceRole role: serviceUser.roles) {
currentRoles.add(role.role);
getLogger().debug("User [" + username + "] has role: [" + role + "]");
}
// Authentication worked. Save the values that will be needed for
// later service requests.
currentUsername = username;
currentPassword = password;
return true;
} catch(ClientProtocolException cpexc) {
getLogger().error(cpexc.getMessage(), cpexc);
return false;
} catch(IOException ioexc) {
getLogger().error(ioexc.getMessage(), ioexc);
return false;
} finally {
httpClient.getConnectionManager().shutdown();
}
}
/**
* @see org.apache.wicket.authentication.AuthenticatedWebSession#getRoles()
*/
@Override
public Roles getRoles() {
return isSignedIn() ? currentRoles : null;
}
/**
* @see org.apache.wicket.authentication.AuthenticatedWebSession#signOut()
*/
@Override
public void signOut() {
super.signOut();
clearUserData();
}
/**
* Returns the current username if the session is signed in.
*/
public String getCurrentUsername() {
return isSignedIn() ? currentUsername : "";
}
/**
* Returns the current password if the session is signed in. Yes, this holds
* the user's password in memory somewhere. Ideally, some kind of token is
* kept, but not in a form as transparent as a password.
*/
public String getCurrentPassword() {
return isSignedIn() ? currentPassword : "";
}
/**
* Convenience method for grabbing the logger. This is not stored as an
* instance variable because Wicket serializes web page classes and this
* logger is not serializable.
*/
protected Logger getLogger() {
return LoggerFactory.getLogger(HeadmasterSession.class);
}
/**
* Convenience method for clearing out current user information.
*/
private void clearUserData() {
currentRoles = null;
}
/**
* Helper classes for parsing user data. For internal use only.
*/
static class ServiceUser {
public long id;
public boolean active;
public String email;
public String login;
public Collection<ServiceRole> roles;
}
static class ServiceRole {
public long id;
public String role;
}
private String currentUsername;
private String currentPassword;
private Roles currentRoles;
}