# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: C:\workspace\trunk\apps\weblogger # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: build.xml --- build.xml Base (BASE) +++ build.xml Locally Modified (Based On LOCAL) @@ -676,15 +676,6 @@ - - - - - - - - - Index: src/java/META-INF/persistence.xml --- src/java/META-INF/persistence.xml Base (BASE) +++ src/java/META-INF/persistence.xml Locally Modified (Based On LOCAL) @@ -27,6 +27,7 @@ org/apache/roller/weblogger/pojos/ObjectPermission.orm.xml org/apache/roller/weblogger/pojos/WeblogPermission.orm.xml org/apache/roller/weblogger/pojos/Weblog.orm.xml + org/apache/roller/weblogger/pojos/UserPermission.orm.xml Index: src/java/org/apache/roller/weblogger/business/jpa/CustomJPAUserManagerImpl.java --- src/java/org/apache/roller/weblogger/business/jpa/CustomJPAUserManagerImpl.java Locally New +++ src/java/org/apache/roller/weblogger/business/jpa/CustomJPAUserManagerImpl.java Locally New @@ -0,0 +1,800 @@ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ +package org.apache.roller.weblogger.business.jpa; + +import java.sql.Timestamp; +import javax.persistence.NoResultException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.roller.weblogger.WebloggerException; +import org.apache.roller.weblogger.business.UserManager; +import org.apache.roller.weblogger.pojos.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.Comparator; +import javax.persistence.Query; +import org.apache.roller.weblogger.business.Weblogger; +import org.apache.roller.weblogger.config.WebloggerConfig; + + +@com.google.inject.Singleton +public class CustomJPAUserManagerImpl implements UserManager { + + /** The logger instance for this class. */ + private static Log log = LogFactory.getLog(CustomJPAUserManagerImpl.class); + + private static final Comparator statCountCountReverseComparator = + Collections.reverseOrder(StatCountCountComparator.getInstance()); + + private final Weblogger roller; + private final JPAPersistenceStrategy strategy; + + // cached mapping of weblogHandles -> weblogIds + private Map weblogHandleToIdMap = new Hashtable(); + + // cached mapping of userNames -> userIds + private Map userNameToIdMap = new Hashtable(); + + + @com.google.inject.Inject + protected CustomJPAUserManagerImpl(Weblogger roller, JPAPersistenceStrategy strat) { + log.debug("Instantiating JPA User Manager"); + this.roller = roller; + this.strategy = strat; + } + + + public void release() {} + + + //--------------------------------------------------------------- user CRUD + + public void saveUser(User data) throws WebloggerException { + this.strategy.store(data); + } + + + public void removeUser(User user) throws WebloggerException { + //remove permissions + // make sure that both sides of the relationship are maintained + List perms = getWeblogPermissions(user); + for (WeblogPermission perm : perms) { + + //Remove it from database + this.strategy.remove(perms); + } + + this.strategy.remove(user); + + // remove entry from cache mapping + this.userNameToIdMap.remove(user.getUserName()); + } + + + public void addUser(User newUser) throws WebloggerException { + + if(newUser == null) + throw new WebloggerException("cannot add null user"); + + // TODO BACKEND: we must do this in a better fashion, like getUserCnt()? + boolean adminUser = false; + List existingUsers = this.getUsers(Boolean.TRUE, null, null, 0, 1); + boolean firstUserAdmin = WebloggerConfig.getBooleanProperty("users.firstUserAdmin"); + if (existingUsers.size() == 0 && firstUserAdmin) { + // Make first user an admin + adminUser = true; + + //if user was disabled (because of activation user + // account with e-mail property), enable it for admin user + newUser.setEnabled(Boolean.TRUE); + newUser.setActivationCode(null); + } + + if (getUserByUserName(newUser.getUserName()) != null || + getUserByUserName(newUser.getUserName().toLowerCase()) != null) { + throw new WebloggerException("error.add.user.userNameInUse"); + } + + this.strategy.store(newUser); + + grantRole("editor", newUser); + if (adminUser) { + grantRole("admin", newUser); + } + } + + + public User getUser(String id) throws WebloggerException { + return (User)this.strategy.load(User.class, id); + } + + + //------------------------------------------------------------ user queries + + public User getUserByUserName(String userName) throws WebloggerException { + return getUserByUserName(userName, Boolean.TRUE); + } + + + public User getUserByUserName(String userName, Boolean enabled) + throws WebloggerException { + + if (userName==null ) + throw new WebloggerException("userName cannot be null"); + + // check cache first + // NOTE: if we ever allow changing usernames then this needs updating + if(this.userNameToIdMap.containsKey(userName)) { + + User user = this.getUser( + (String) this.userNameToIdMap.get(userName)); + if(user != null) { + // only return the user if the enabled status matches + if(enabled == null || enabled.equals(user.getEnabled())) { + log.debug("userNameToIdMap CACHE HIT - "+userName); + return user; + } + } else { + // mapping hit with lookup miss? mapping must be old, remove it + this.userNameToIdMap.remove(userName); + } + } + + // cache failed, do lookup + Query query; + Object[] params; + if (enabled != null) { + query = strategy.getNamedQuery( + "User.getByUserName&Enabled"); + params = new Object[] {userName, enabled}; + } else { + query = strategy.getNamedQuery( + "User.getByUserName"); + params = new Object[] {userName}; + } + for (int i=0; i ?" + size); + params.add(size++, end); + whereClause.append(" AND u.dateCreated < ?" + size); + } + whereClause.append(" ORDER BY u.dateCreated DESC"); + query = strategy.getDynamicQuery(queryString.toString() + whereClause.toString()); + + if (offset != 0) { + query.setFirstResult(offset); + } + if (length != -1) { + query.setMaxResults(length); + } + for (int i=0; i actions) throws WebloggerException { + + // first, see if user already has a permission for the specified object + Query q = strategy.getNamedQuery("WeblogPermission.getByUserName&WeblogId"); + q.setParameter(1, user.getUserName()); + q.setParameter(2, weblog.getHandle()); + WeblogPermission existingPerm = null; + try { + existingPerm = (WeblogPermission)q.getSingleResult(); + } catch (NoResultException ignored) {} + + // permission already exists, so add any actions specified in perm argument + if (existingPerm != null) { + existingPerm.addActions(actions); + this.strategy.store(existingPerm); + } else { + // it's a new permission, so store it + WeblogPermission perm = new WeblogPermission(weblog, user, actions); + this.strategy.store(perm); + } + } + + + public void grantWeblogPermissionPending(Weblog weblog, User user, List actions) throws WebloggerException { + + // first, see if user already has a permission for the specified object + Query q = strategy.getNamedQuery("WeblogPermission.getByUserName&WeblogId"); + q.setParameter(1, user.getUserName()); + q.setParameter(2, weblog.getHandle()); + WeblogPermission existingPerm = null; + try { + existingPerm = (WeblogPermission)q.getSingleResult(); + } catch (NoResultException ignored) {} + + // permission already exists, so complain + if (existingPerm != null) { + throw new WebloggerException("Cannot make existing permission into pending permission"); + + } else { + // it's a new permission, so store it + WeblogPermission perm = new WeblogPermission(weblog, user, actions); + perm.setPending(true); + this.strategy.store(perm); + } + } + + + public void confirmWeblogPermission(Weblog weblog, User user) throws WebloggerException { + + // get specified permission + Query q = strategy.getNamedQuery("WeblogPermission.getByUserName&WeblogId"); + q.setParameter(1, user.getUserName()); + q.setParameter(2, weblog.getHandle()); + WeblogPermission existingPerm = null; + try { + existingPerm = (WeblogPermission)q.getSingleResult(); + + } catch (NoResultException ignored) { + throw new WebloggerException("ERROR: permission not found"); + } + // set pending to false + existingPerm.setPending(false); + this.strategy.store(existingPerm); + } + + + public void declineWeblogPermission(Weblog weblog, User user) throws WebloggerException { + + // get specified permission + Query q = strategy.getNamedQuery("WeblogPermission.getByUserName&WeblogId"); + q.setParameter(1, user.getUserName()); + q.setParameter(2, weblog.getHandle()); + WeblogPermission existingPerm = null; + try { + existingPerm = (WeblogPermission)q.getSingleResult(); + } catch (NoResultException ignored) { + throw new WebloggerException("ERROR: permission not found"); + } + // remove permission + this.strategy.remove(existingPerm); + } + + + public void revokeWeblogPermission(Weblog weblog, User user, List actions) throws WebloggerException { + + // get specified permission + Query q = strategy.getNamedQuery("WeblogPermission.getByUserName&WeblogId"); + q.setParameter(1, user.getUserName()); + q.setParameter(2, weblog.getHandle()); + WeblogPermission oldperm = null; + try { + oldperm = (WeblogPermission)q.getSingleResult(); + } catch (NoResultException ignored) { + throw new WebloggerException("ERROR: permission not found"); + } + + // remove actions specified in perm agument + oldperm.removeActions(actions); + + if (oldperm.isEmpty()) { + // no actions left in permission so remove it + this.strategy.remove(oldperm); + } else { + // otherwise save it + this.strategy.store(oldperm); + } + } + + + public List getWeblogPermissions(User user) throws WebloggerException { + Query q = strategy.getNamedQuery("WeblogPermission.getByUserName"); + q.setParameter(1, user.getUserName()); + return (List)q.getResultList(); + } + + + public List getWeblogPermissions(Weblog weblog) throws WebloggerException { + Query q = strategy.getNamedQuery("WeblogPermission.getByWeblogId"); + q.setParameter(1, weblog.getHandle()); + return (List)q.getResultList(); + } + + + public List getWeblogPermissionsPending(User user) throws WebloggerException { + Query q = strategy.getNamedQuery("WeblogPermission.getByUserName&Pending"); + q.setParameter(1, user.getUserName()); + return (List)q.getResultList(); + } + + + public List getWeblogPermissionsPending(Weblog weblog) throws WebloggerException { + Query q = strategy.getNamedQuery("WeblogPermission.getByWeblogId&Pending"); + q.setParameter(1, weblog.getHandle()); + return (List)q.getResultList(); + } + + + //-------------------------------------------------------------- role CRUD + + + /** + * Returns true if user has role specified. + */ + public boolean hasRole(String roleName, User user) throws WebloggerException { + Query q = strategy.getNamedQuery("UserRole.getByUserNameAndRole"); + q.setParameter(1, user.getUserName()); + q.setParameter(2, roleName); + try { + q.getSingleResult(); + } catch (NoResultException e) { + return false; + } + return true; + } + + + /** + * Get all of user's roles. + */ + public List getRoles(User user) throws WebloggerException { + Query q = strategy.getNamedQuery("UserRole.getByUserName"); + q.setParameter(1, user.getUserName()); + List roles = q.getResultList(); + List roleNames = new ArrayList(); + for (Iterator it = roles.iterator(); it.hasNext();) { + UserRole userRole = (UserRole)it.next(); + roleNames.add(userRole.getRole()); + } + return roleNames; + } + + + /** + * Grant to user role specified by role name. + */ + public void grantRole(String roleName, User user) throws WebloggerException { + if (!hasRole(roleName, user)) { + UserRole role = new UserRole(user.getUserName(), roleName); + this.strategy.store(role); + } + } + + + public void revokeRole(String roleName, User user) throws WebloggerException { + Query q = strategy.getNamedQuery("UserRole.getByUserNameAndRole"); + q.setParameter(1, user.getUserName()); + q.setParameter(2, roleName); + try { + UserRole role = (UserRole)q.getSingleResult(); + this.strategy.remove(role); + + } catch (NoResultException e) { + throw new WebloggerException("ERROR: removing role", e); + } + } + + + public boolean checkPermission(User user, WebloggerPermission requiredPerm) + throws WebloggerException { + + // first see if the user has this permission defined + WebloggerPermission userPerm = + getPermission(user, requiredPerm.getType(), requiredPerm.getObject()); + if(userPerm != null) { + // yes they do, now lets see if they have the required actions + return userPerm.implies(requiredPerm); + } + + return false; + } + + public void grantPermission(User user, WebloggerPermission perm) + throws WebloggerException { + + // first, see if user already has a permission for the specified object + UserPermission userPerm = getUserPermission(user, perm.getObject(), perm.getType()); + + if (userPerm != null) { + // permission already exists, so just add actions + userPerm.addActions(perm.getActions()); + this.strategy.store(userPerm); + } else { + // it's a new permission + UserPermission newPerm = new UserPermission(user, perm.getType(), perm.getObject(), perm.getActions()); + this.strategy.store(newPerm); + } + } + + public void revokePermission(User user, WebloggerPermission perm) + throws WebloggerException { + + // first, see if user already has a permission for the specified object + UserPermission oldPerm = getUserPermission(user, perm.getObject(), perm.getType()); + if(oldPerm == null) { + return; + } + + // remove actions specified in perm agument + oldPerm.removeActions(perm.getActions()); + + if (oldPerm.getActions() == null || oldPerm.getActions().trim().length() == 0) { + // no actions left in permission so remove it + this.strategy.remove(oldPerm); + } else { + // otherwise save it + this.strategy.store(oldPerm); + } + } + + public List getPermissions(User user, String type) + throws WebloggerException { + + Query q = strategy.getNamedQuery("UserPermission.getByUser&Type"); + q.setParameter(1, user); + q.setParameter(2, type); + List results = q.getResultList(); + List perms = new ArrayList(); + for ( UserPermission uperm : results) { + perms.add(userPermissionToWebloggerPermission(uperm)); + } + return perms; + } + + public List getPermissions(String object, String type) + throws WebloggerException { + + Query q = strategy.getNamedQuery("UserPermission.getByObject&Type"); + q.setParameter(1, object); + q.setParameter(2, type); + List results = q.getResultList(); + List perms = new ArrayList(); + for ( UserPermission uperm : results) { + perms.add(userPermissionToWebloggerPermission(uperm)); + } + return perms; + } + + public WebloggerPermission getPermission(User user, String type, String object) + throws WebloggerException { + + UserPermission userPerm = getUserPermission(user, object, type); + + // transform into WebloggerPermission + if(userPerm != null && !userPerm.isPending()) { + return userPermissionToWebloggerPermission(userPerm); + } else { + return null; + } + } + + private UserPermission getUserPermission(User user, String object, String type) + throws WebloggerException { + + Query q = strategy.getNamedQuery("UserPermission.getByUser&Object&Type"); + q.setParameter(1, user); + q.setParameter(2, object); + q.setParameter(3, type); + try { + return (UserPermission) q.getSingleResult(); + } catch (NoResultException ignored) { + return null; + } + } + + private WebloggerPermission userPermissionToWebloggerPermission(UserPermission perm) { + return new WebloggerPermission(perm.getType(), perm.getObject(), perm.getActions()); + } + +} Index: src/java/org/apache/roller/weblogger/business/jpa/JPAUserManagerImpl.java --- src/java/org/apache/roller/weblogger/business/jpa/JPAUserManagerImpl.java Base (BASE) +++ src/java/org/apache/roller/weblogger/business/jpa/JPAUserManagerImpl.java Locally Modified (Based On LOCAL) @@ -684,7 +684,31 @@ throw new WebloggerException("ERROR: removing role", e); } } + + public boolean checkPermission(User user, WebloggerPermission perm) throws WebloggerException { + throw new UnsupportedOperationException("Not supported yet."); } + public void grantPermission(User user, WebloggerPermission perm) throws WebloggerException { + throw new UnsupportedOperationException("Not supported yet."); + } + public void revokePermission(User user, WebloggerPermission perm) throws WebloggerException { + throw new UnsupportedOperationException("Not supported yet."); + } + public List getPermissions(User user, String type) throws WebloggerException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public List getPermissions(String object, String type) throws WebloggerException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public WebloggerPermission getPermission(User user, String object, String type) throws WebloggerException { + throw new UnsupportedOperationException("Not supported yet."); + } +} + + + Index: src/java/org/apache/roller/weblogger/business/jpa/JPAWebloggerModule.java --- src/java/org/apache/roller/weblogger/business/jpa/JPAWebloggerModule.java Base (BASE) +++ src/java/org/apache/roller/weblogger/business/jpa/JPAWebloggerModule.java Locally Modified (Based On LOCAL) @@ -64,7 +64,7 @@ binder.bind(PropertiesManager.class).to( JPAPropertiesManagerImpl.class); binder.bind(RefererManager.class).to( JPARefererManagerImpl.class); binder.bind(ThreadManager.class).to( JPAThreadManagerImpl.class); - binder.bind(UserManager.class).to( JPAUserManagerImpl.class); + binder.bind(UserManager.class).to( CustomJPAUserManagerImpl.class); binder.bind(WeblogManager.class).to( JPAWeblogManagerImpl.class); binder.bind(WeblogEntryManager.class).to( JPAWeblogEntryManagerImpl.class); Index: src/java/org/apache/roller/weblogger/business/UserManager.java --- src/java/org/apache/roller/weblogger/business/UserManager.java Base (BASE) +++ src/java/org/apache/roller/weblogger/business/UserManager.java Locally Modified (Based On LOCAL) @@ -26,6 +26,7 @@ import org.apache.roller.weblogger.pojos.User; import org.apache.roller.weblogger.pojos.Weblog; import org.apache.roller.weblogger.pojos.WeblogPermission; +import org.apache.roller.weblogger.pojos.WebloggerPermission; /** @@ -167,6 +168,25 @@ //-------------------------------------------------------- permissions CRUD + public boolean checkPermission(User user, WebloggerPermission perm) + throws WebloggerException; + + public void grantPermission(User user, WebloggerPermission perm) + throws WebloggerException; + + public void revokePermission(User user, WebloggerPermission perm) + throws WebloggerException; + + public List getPermissions(User user, String type) + throws WebloggerException; + + public List getPermissions(String object, String type) + throws WebloggerException; + + public WebloggerPermission getPermission(User user, String object, String type) + throws WebloggerException; + + /** * Return true if user has permission specified. */ Index: src/java/org/apache/roller/weblogger/pojos/UserPermission.java --- src/java/org/apache/roller/weblogger/pojos/UserPermission.java Locally New +++ src/java/org/apache/roller/weblogger/pojos/UserPermission.java Locally New @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ + +package org.apache.roller.weblogger.pojos; + +import java.io.Serializable; +import java.util.Date; +import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.roller.util.UUIDGenerator; +import org.apache.roller.weblogger.util.Utilities; + + +/** + * Permissions for a specific user. + */ +public class UserPermission implements Serializable { + + private static Log log = LogFactory.getLog(UserPermission.class); + + private String id = UUIDGenerator.generateUUID(); + private User user = null; + private String type = null; + private String object = null; + private String actions = null; + private Date dateCreated = new Date(); + private boolean pending = false; + + + public UserPermission() {} + + public UserPermission(User user, String type, String object, String actions) { + this.user = user; + this.type = type; + this.object = object; + this.actions = actions; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public void setActions(String actions) { + this.actions = actions; + } + + public String getActions() { + return actions; + } + + public Date getDateCreated() { + return dateCreated; + } + + public void setDateCreated(Date dateCreated) { + this.dateCreated = dateCreated; + } + + public boolean isPending() { + return pending; + } + + public void setPending(boolean pending) { + this.pending = pending; + } + + public void addActions(String newActions) { + Set existing = Utilities.stringToStringSet(actions, ","); + Set newActs = Utilities.stringToStringSet(newActions, ","); + existing.addAll(newActs); + setActions(Utilities.stringSetToString(existing, ",")); + } + + public void removeActions(String removeActions) { + Set existing = Utilities.stringToStringSet(actions, ","); + Set removeActs = Utilities.stringToStringSet(removeActions, ","); + existing.removeAll(removeActs); + setActions(Utilities.stringSetToString(existing, ",")); + } + +} Index: src/java/org/apache/roller/weblogger/pojos/UserPermission.orm.xml --- src/java/org/apache/roller/weblogger/pojos/UserPermission.orm.xml Locally New +++ src/java/org/apache/roller/weblogger/pojos/UserPermission.orm.xml Locally New @@ -0,0 +1,60 @@ + + + Persistence Metadata for Roller + + + PROPERTY + + + org.apache.roller.weblogger.pojos + + + + SELECT p FROM UserPermission p + + + SELECT p FROM UserPermission p WHERE p.user = ?1 AND p.type = ?2 AND p.pending <> TRUE + + + SELECT p FROM UserPermission p WHERE p.object = ?1 AND p.type = ?2 AND p.pending <> TRUE + + + SELECT p FROM UserPermission p WHERE p.user = ?1 AND p.object = ?2 AND p.type = ?3 + + + SELECT p FROM UserPermission p WHERE p.user = ?1 AND p.object = ?2 AND p.type = ?3 AND p.pending <> TRUE + + + SELECT p FROM UserPermission p WHERE p.user = ?1 AND p.pending = TRUE + + + SELECT p FROM UserPermission p WHERE p.object = ?1 AND p.pending = TRUE + + + + + + + + + + + + + + + + + + + + + + + + + + Index: src/java/org/apache/roller/weblogger/pojos/WebloggerPermission.java --- src/java/org/apache/roller/weblogger/pojos/WebloggerPermission.java Locally New +++ src/java/org/apache/roller/weblogger/pojos/WebloggerPermission.java Locally New @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ + +package org.apache.roller.weblogger.pojos; + +import java.security.Permission; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.roller.weblogger.util.Utilities; + + +/** + * Base permission class for Weblogger. + */ +public class WebloggerPermission extends java.security.Permission { + + private static Log log = LogFactory.getLog(WebloggerPermission.class); + + private final String type; + private final String object; + private final String actions; + private final Set actionsAsSet; + private final Set completeActionsAsSet; + + + public WebloggerPermission(String type, String object, String actions) { + super("WebloggerPermission"); + this.type = type; + this.object = object; + this.actions = actions; + this.actionsAsSet = Utilities.stringToStringSet(actions, ","); + this.completeActionsAsSet = buildFullActionsSet(actionsAsSet); + } + + + public String getType() { + return type; + } + + public String getObject() { + return object; + } + + public String getActions() { + return actions; + } + + public Set getActionsAsSet() { + return actionsAsSet; + } + + + public boolean implies(Permission permission) { + + // only compare WebloggerPermission objects + if (!(permission instanceof WebloggerPermission)) + return false; + + WebloggerPermission that = (WebloggerPermission) permission; + + // only compare 2 permissions of the same name ("type") + // name ("type") cannot be null + if(this.getName() == null || that.getName() == null || + !(this.getName().equals(that.getName()))) + return false; + + // does "this" permission contain all actions of "that" permission? + + // we consider a permission implied if our set of granted actions + // contains all of the granted actions of the permission we are checking + if(this.completeActionsAsSet.containsAll(that.completeActionsAsSet)) + return true; + + return false; + } + + + public boolean equals(Object arg0) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public int hashCode() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getName()).append(" : "); + for (String action : getActionsAsSet()) { + sb.append(" ").append(action).append(" "); + } + return sb.toString(); + } + + + // --------------------------------------------------- Private Methods + + + // build an expanded Set of all actions implied by a Set of actions + private Set buildFullActionsSet(Set actions) { + + Set fullSet = new HashSet(); + + for( String action : actions ) { + Set impliedActions = getImpliedActions(action); + if(impliedActions.size() > 0) { + // if an action implies other actions, recurse + fullSet.addAll(buildFullActionsSet(impliedActions)); + } else { + fullSet.add(action); + } + } + + return fullSet; + } + + // get implied actions for an action + private Set getImpliedActions(String action) { + // TODO: lookup if action implies other actions + // this would likely be a function of the UserManager somehow + return Collections.EMPTY_SET; + } + +} Index: src/java/org/apache/roller/weblogger/util/Utilities.java --- src/java/org/apache/roller/weblogger/util/Utilities.java Base (BASE) +++ src/java/org/apache/roller/weblogger/util/Utilities.java Locally Modified (Based On LOCAL) @@ -15,9 +15,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; +import java.util.Set; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -303,6 +305,19 @@ return ret; } + //------------------------------------------------------------------------ + /** Convert string array to string with delimeters. */ + public static String stringSetToString(Set stringList, String delim) { + String ret = ""; + for (String s : stringList) { + if (ret.length() > 0) + ret = ret + delim + s; + else + ret = s; + } + return ret; + } + //-------------------------------------------------------------------------- /** Convert string with delimeters to string array. */ public static String[] stringToStringArray(String instr, String delim) @@ -330,6 +345,18 @@ } //-------------------------------------------------------------------------- + /** Convert string with delimeters to string list. */ + public static Set stringToStringSet(String instr, String delim) + throws NoSuchElementException, NumberFormatException { + StringTokenizer toker = new StringTokenizer(instr, delim); + Set stringSet = new HashSet(); + while (toker.hasMoreTokens()) { + stringSet.add(toker.nextToken()); + } + return stringSet; + } + + //-------------------------------------------------------------------------- /** Convert string to integer array. */ public static int[] stringToIntArray(String instr, String delim) throws NoSuchElementException, NumberFormatException { Index: test/java/org/apache/roller/weblogger/business/CoreWeblogPlatformTestSuite.java --- test/java/org/apache/roller/weblogger/business/CoreWeblogPlatformTestSuite.java Base (BASE) +++ test/java/org/apache/roller/weblogger/business/CoreWeblogPlatformTestSuite.java Locally Modified (Based On LOCAL) @@ -45,6 +45,9 @@ // test permissions suite.addTestSuite(PermissionTest.class); + // test permissions + suite.addTestSuite(CustomPermissionsTest.class); + return suite; } Index: test/java/org/apache/roller/weblogger/business/CustomPermissionsTest.java --- test/java/org/apache/roller/weblogger/business/CustomPermissionsTest.java Locally New +++ test/java/org/apache/roller/weblogger/business/CustomPermissionsTest.java Locally New @@ -0,0 +1,180 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. The ASF licenses this file to You +* under the Apache License, Version 2.0 (the "License"); you may not +* use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. For additional information regarding +* copyright in this work, please see the NOTICE file in the top level +* directory of this distribution. +*/ +package org.apache.roller.weblogger.business; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.roller.weblogger.TestUtils; +import org.apache.roller.weblogger.pojos.User; +import org.apache.roller.weblogger.pojos.Weblog; +import org.apache.roller.weblogger.pojos.WebloggerPermission; + + +/** + * Test User/Weblog Permissions related business operations. + */ +public class CustomPermissionsTest extends TestCase { + + public static Log log = LogFactory.getLog(CustomPermissionsTest.class); + + User testUser = null; + Weblog testWeblog = null; + + + public CustomPermissionsTest(String name) { + super(name); + } + + + public static Test suite() { + return new TestSuite(PermissionTest.class); + } + + + /** + * All tests in this suite require a user and a weblog. + */ + @Override + public void setUp() throws Exception { + + log.info("BEGIN"); + + // setup weblogger + TestUtils.setupWeblogger(); + + try { + testUser = TestUtils.setupUser("custPermsTestUser"); + testWeblog = TestUtils.setupWeblog("custPermsTestWeblog", testUser); + TestUtils.endSession(true); + } catch (Exception ex) { + log.error("ERROR in setup", ex); + throw new Exception("Test setup failed", ex); + } + + log.info("END"); + } + + @Override + public void tearDown() throws Exception { + + log.info("BEGIN"); + + try { + TestUtils.teardownWeblog(testWeblog.getId()); + TestUtils.teardownUser(testUser.getUserName()); + TestUtils.endSession(true); + } catch (Exception ex) { + log.error("ERROR in tear down", ex); + throw new Exception("Test teardown failed", ex); + } + + log.info("END"); + } + + + /** + * Test basic persistence operations ... Create, Update, Delete. + */ + public void testPermissionsCRUD() throws Exception { + + log.info("BEGIN"); + + UserManager mgr = WebloggerFactory.getWeblogger().getUserManager(); + + WebloggerPermission p1 = new WebloggerPermission("test1", "app", "action1"); + WebloggerPermission p2 = new WebloggerPermission("test2", "obj1", "action1,action2"); + + WebloggerPermission perm = null; + + // grant permissions + testUser = TestUtils.getManagedUser(testUser); + mgr.grantPermission(testUser, p1); + mgr.grantPermission(testUser, p2); + TestUtils.endSession(true); + + // check that grant on p2 was successful + testUser = TestUtils.getManagedUser(testUser); + perm = null; + perm = mgr.getPermission(testUser, "test2", "obj1"); + assertNotNull(perm); + assertTrue(perm.getActionsAsSet().contains("action1")); + assertTrue(perm.getActionsAsSet().contains("action2")); + + // check that grant on p1 was successful + testUser = TestUtils.getManagedUser(testUser); + perm = null; + perm = mgr.getPermission(testUser, "test1", "app"); + assertNotNull(perm); + assertTrue(perm.getActionsAsSet().contains("action1")); + + // revoke permissions + mgr.revokePermission(testUser, p1); + TestUtils.endSession(true); + + // check that revoke was successful + testUser = TestUtils.getManagedUser(testUser); + perm = null; + perm = mgr.getPermission(testUser, "test1", "app"); + assertNull(perm); + + // test more inclusive checkPermission() method + boolean result = mgr.checkPermission(testUser, p2); + assertTrue(result); + + // cleanup remaining permission + mgr.revokePermission(testUser, p2); + TestUtils.endSession(true); + + // check that revoke was successful + testUser = TestUtils.getManagedUser(testUser); + perm = null; + perm = mgr.getPermission(testUser, "test2", "obj1"); + assertNull(perm); + + log.info("END"); + } + + + /** + * Tests weblog invitation process. + */ +// public void testPermissionChecks() throws Exception { +// +// log.info("BEGIN"); +// +// UserPermission perm = +// new UserPermission(testWeblog, testUser, UserPermission.POST); +// UserManager umgr = WebloggerFactory.getWeblogger().getUserManager(); +// assertTrue(umgr.checkPermission(perm, testUser)); +// +// // we need a second user for this test +// User adminUser = TestUtils.setupUser("adminUser"); +// umgr.grantRole("admin", adminUser); +// TestUtils.endSession(true); +// +// // because adminUser is a global admin, they should have POST perm +// UserPermission perm2 = +// new UserPermission(testWeblog, testUser, UserPermission.POST); +// assertTrue(umgr.checkPermission(perm, testUser)); +// +// log.info("END"); +// } +}