Permalink
Browse files

Access Control: create HTTP sessions (#293).

For a logged in user a HTTP session is created.
The dm4_username cookie is not used anymore.

Furthermore in Webclient: the API method require_login() is removed.

See ticket 293.
  • Loading branch information...
1 parent 6564300 commit faa7485e02f3caeb506853d1a67db0b5f941f9f1 @jri committed Aug 15, 2012
@@ -1,5 +1,6 @@
package de.deepamehta.plugins.accesscontrol;
+import de.deepamehta.plugins.accesscontrol.model.Credentials;
import de.deepamehta.plugins.accesscontrol.model.Operation;
import de.deepamehta.plugins.accesscontrol.model.Permissions;
import de.deepamehta.plugins.accesscontrol.model.Role;
@@ -28,7 +29,6 @@
import de.deepamehta.core.service.listener.PostInstallPluginListener;
import de.deepamehta.core.service.listener.PluginServiceArrivedListener;
import de.deepamehta.core.service.listener.PluginServiceGoneListener;
-import de.deepamehta.core.util.JavaUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@@ -60,7 +60,7 @@
@Consumes("application/json")
@Produces("application/json")
public class AccessControlPlugin extends PluginActivator implements AccessControlService, InitializePluginListener,
- PostCreateTopicListener,
+ SecurityContext, PostCreateTopicListener,
PreSendTopicListener,
PreSendTopicTypeListener,
PostInstallPluginListener,
@@ -72,7 +72,6 @@
private static final String DEFAULT_USERNAME = "admin";
private static final String DEFAULT_PASSWORD = "";
- private static final String ENCRYPTED_PASSWORD_PREFIX = "-SHA256-"; // don't change this
// association type semantics ### TODO: to be dropped. Model-driven manipulators required.
private static final String WORKSPACE_MEMBERSHIP = "dm4.accesscontrol.membership";
@@ -107,16 +106,11 @@
+ @GET
+ @Path("/login/{username}/{password}")
@Override
- public Topic checkCredentials(String username, String password) {
- Topic userName = getUsername(username);
- if (userName == null) {
- return null;
- }
- if (!matches(userName, password)) {
- return null;
- }
- return userName;
+ public Topic login(@PathParam("username") String username, @PathParam("password") String password) {
+ return login(username, password, request);
}
@GET
@@ -206,6 +200,35 @@ public void joinWorkspace(@PathParam("workspace_id") long workspaceId, @PathPara
+ // **************************************
+ // *** SecurityContext Implementation ***
+ // **************************************
+
+
+
+ /**
+ * Checks weather the credentials match an existing User Account.
+ *
+ * @return The username of the matched User Account (a Topic of type "Username" /
+ * <code>dm4.accesscontrol.username</code>), or <code>null</code> if there is no matching User Account.
+ */
+ @Override
+ public Topic login(String username, String password, HttpServletRequest request) {
+ Topic userName = checkCredentials(username, password);
+ //
+ if (userName != null) {
+ HttpSession session = createSession(userName, request);
+ logger.info("##### Logging in as \"" + username + "\" => SUCCESSFUL!" +
+ "\n ##### Creating new " + info(session));
+ return userName;
+ } else {
+ logger.info("##### Logging in as \"" + username + "\" => FAILED!");
+ return null;
+ }
+ }
+
+
+
// ********************************
// *** Listener Implementations ***
// ********************************
@@ -215,7 +238,7 @@ public void joinWorkspace(@PathParam("workspace_id") long workspaceId, @PathPara
@Override
public void initializePlugin() {
try {
- registerFilter(new SecurityFilter(this));
+ registerFilter(new RequestFilter(this));
} catch (Exception e) {
throw new RuntimeException("Registering the security filter failed", e);
}
@@ -289,7 +312,7 @@ public void preSendTopicType(TopicType topicType, ClientState clientState) {
@Override
public void postInstallPlugin() {
- Topic userAccount = createUserAccount(DEFAULT_USERNAME, DEFAULT_PASSWORD);
+ Topic userAccount = createUserAccount(new Credentials(DEFAULT_USERNAME, DEFAULT_PASSWORD));
logger.info("Creating \"admin\" user account => ID=" + userAccount.getId());
}
@@ -317,10 +340,10 @@ public void pluginServiceGone(PluginService service) {
// ------------------------------------------------------------------------------------------------- Private Methods
- private Topic createUserAccount(String username, String password) {
+ private Topic createUserAccount(Credentials cred) {
return dms.createTopic(new TopicModel("dm4.accesscontrol.user_account", new CompositeValue()
- .put("dm4.accesscontrol.username", username)
- .put("dm4.accesscontrol.password", encryptPassword(password))), null); // clientState=null
+ .put("dm4.accesscontrol.username", cred.username)
+ .put("dm4.accesscontrol.password", cred.password)), null); // clientState=null
}
// ---
@@ -364,7 +387,7 @@ private Topic getUsername(String username) {
return dms.getTopic("dm4.accesscontrol.username", new SimpleValue(username), false, null);
}
- // ### FIXME: there is a principal copy in SecurityFilter
+ // ### FIXME: there is a principal copy in RequestFilter
private Topic getUsername(HttpSession session) {
Topic username = (Topic) session.getAttribute("username");
if (username == null) {
@@ -391,41 +414,53 @@ private Topic getAdminUser() {
// ---
- /**
- * @return The encryted password of the specified User Account.
- */
- private String getPassword(Topic userAccount) {
- return userAccount.getCompositeValue().getString("dm4.accesscontrol.password");
+ private void setCreator(Topic topic) {
+ Topic username = getUsername();
+ if (username == null) {
+ logger.warning("Assigning a creator to " + info(topic) + " failed (no user is logged in). " +
+ "Assigning user \"admin\" instead.");
+ username = getAdminUser();
+ }
+ setCreator(topic, username.getId());
}
- private String encryptPassword(String password) {
- return ENCRYPTED_PASSWORD_PREFIX + JavaUtils.encodeSHA256(password);
+ private void setCreator(Topic topic, long usernameId) {
+ facetsService.updateFacet(topic, "dm4.accesscontrol.creator_facet", creatorModel(usernameId), null, null);
+ }
+
+ // === Login ===
+
+ private Topic checkCredentials(String username, String password) {
+ Topic userName = getUsername(username);
+ if (userName == null) {
+ return null;
+ }
+ if (!matches(userName, password)) {
+ return null;
+ }
+ return userName;
}
/**
* Prerequisite: username is not <code>null</code>.
*
- * @param password The plain text password.
+ * @param password The encrypted password.
*/
private boolean matches(Topic username, String password) {
- String encryptedPassword = getPassword(getUserAccount(username));
- return encryptedPassword.equals(encryptPassword(password));
+ return getPassword(getUserAccount(username)).equals(password);
}
- // ---
-
- private void setCreator(Topic topic) {
- Topic username = getUsername();
- if (username == null) {
- logger.warning("Assigning a creator to " + info(topic) + " failed (no user is logged in). " +
- "Assigning user \"admin\" instead.");
- username = getAdminUser();
- }
- setCreator(topic, username.getId());
+ /**
+ * @return The encryted password of the specified User Account.
+ */
+ private String getPassword(Topic userAccount) {
+ return userAccount.getCompositeValue().getString("dm4.accesscontrol.password");
}
- private void setCreator(Topic topic, long usernameId) {
- facetsService.updateFacet(topic, "dm4.accesscontrol.creator_facet", creatorModel(usernameId), null, null);
+ private HttpSession createSession(Topic username, HttpServletRequest request) {
+ HttpSession session = request.getSession();
+ session.setAttribute("username", username);
+ return session;
}
// === ACL Entries ===
@@ -706,4 +741,9 @@ private String info(Topic topic) {
}
return "topic " + topic.getId() + " (typeUri=\"" + topic.getTypeUri() + "\", uri=\"" + topic.getUri() + "\")";
}
+
+ private String info(HttpSession session) {
+ return "session" + (session != null ? " " + session.getId() +
+ " (username=\"" + getUsername(session) + "\")" : ": null");
+ }
}
@@ -1,7 +1,7 @@
package de.deepamehta.plugins.accesscontrol;
+import de.deepamehta.plugins.accesscontrol.model.Credentials;
import de.deepamehta.core.Topic;
-import de.deepamehta.plugins.accesscontrol.service.AccessControlService;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@@ -17,31 +17,29 @@
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
-import com.sun.jersey.core.util.Base64;
-
import java.io.IOException;
import java.util.logging.Logger;
-class SecurityFilter implements Filter {
+class RequestFilter implements Filter {
// ------------------------------------------------------------------------------------------------------- Constants
private static final String INSTALLATION_TYPE = System.getProperty("dm4.installation.type");
// ---------------------------------------------------------------------------------------------- Instance Variables
- AccessControlService acService;
+ SecurityContext securityContext;
private InstallationType installationType;
private Logger logger = Logger.getLogger(getClass().getName());
// ---------------------------------------------------------------------------------------------------- Constructors
- SecurityFilter(AccessControlService acService) {
+ RequestFilter(SecurityContext securityContext) {
try {
- this.acService = acService;
+ this.securityContext = securityContext;
this.installationType = InstallationType.valueOf(INSTALLATION_TYPE);
logger.info("########## Installation type is \"" + installationType + "\"");
} catch (IllegalArgumentException e) {
@@ -62,7 +60,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
HttpServletResponse resp = (HttpServletResponse) response;
String authHeader = req.getHeader("Authorization");
HttpSession session = req.getSession(false); // create=false
- logger.info("##### " + req.getRequestURL() +
+ logger.info("##### " + req.getMethod() + " " + req.getRequestURL() +
"\n ##### \"Authorization\"=\"" + authHeader + "\"" +
"\n ##### " + info(session));
//
@@ -75,15 +73,9 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
} else {
if (authHeader != null) {
Credentials cred = new Credentials(authHeader);
- Topic username = acService.checkCredentials(cred.username, cred.password);
+ Topic username = securityContext.login(cred.username, cred.password, req);
if (username != null) {
- session = req.getSession();
- session.setAttribute("username", username);
- logger.info("##### Logging in with " + cred + " => SUCCESSFUL!" +
- "\n ##### Creating new " + info(session));
allowed = true;
- } else {
- logger.info("##### Logging in with " + cred + " => FAILED!");
}
}
}
@@ -106,6 +98,7 @@ public void destroy() {
// ------------------------------------------------------------------------------------------------- Private Methods
+ // ### FIXME: there is a copy in AccessControlPlugin
private String info(HttpSession session) {
return "session" + (session != null ? " " + session.getId() +
" (username=\"" + getUsername(session) + "\")" : ": null");
@@ -152,21 +145,4 @@ boolean lookup(boolean isReadRequest) {
return isReadRequest ? readAllowed : writeAllowed;
}
}
-
- private class Credentials {
-
- String username;
- String password;
-
- Credentials(String authHeader) {
- authHeader = authHeader.substring("Basic ".length());
- String[] values = new String(Base64.base64Decode(authHeader)).split(":");
- this.username = values[0];
- this.password = values.length > 1 ? values[1] : "";
- }
-
- public String toString() {
- return "username=\"" + username + "\", password=\""+ password + "\"";
- }
- }
}
@@ -0,0 +1,10 @@
+package de.deepamehta.plugins.accesscontrol;
+
+import de.deepamehta.core.Topic;
+import javax.servlet.http.HttpServletRequest;
+
+
+interface SecurityContext {
+
+ Topic login(String username, String password, HttpServletRequest request);
+}
@@ -0,0 +1,49 @@
+package de.deepamehta.plugins.accesscontrol.model;
+
+import de.deepamehta.core.util.JavaUtils;
+
+import com.sun.jersey.core.util.Base64;
+
+
+
+public class Credentials {
+
+ // ------------------------------------------------------------------------------------------------------- Constants
+
+ private static final String ENCRYPTED_PASSWORD_PREFIX = "-SHA256-"; // don't change this
+
+ // ---------------------------------------------------------------------------------------------- Instance Variables
+
+ public String username;
+ public String password; // encrypted
+
+ // ---------------------------------------------------------------------------------------------------- Constructors
+
+ /**
+ * @param password as plain text
+ */
+ public Credentials(String username, String password) {
+ this.username = username;
+ this.password = encryptPassword(password);
+ }
+
+ public Credentials(String authHeader) {
+ authHeader = authHeader.substring("Basic ".length());
+ String[] values = new String(Base64.base64Decode(authHeader)).split(":");
+ this.username = values[0];
+ this.password = encryptPassword(values.length > 1 ? values[1] : "");
+ // Note: credentials obtained through Basic authorization are always plain text
+ }
+
+ // -------------------------------------------------------------------------------------------------- Public Methods
+
+ public String toString() {
+ return "username=\"" + username + "\", password=\""+ password + "\"";
+ }
+
+ // ------------------------------------------------------------------------------------------------- Private Methods
+
+ private String encryptPassword(String password) {
+ return ENCRYPTED_PASSWORD_PREFIX + JavaUtils.encodeSHA256(password);
+ }
+}
Oops, something went wrong.

0 comments on commit faa7485

Please sign in to comment.