merge with branch issue-340

This commit is contained in:
Sebastian Sdorra
2013-05-11 19:08:07 +02:00
50 changed files with 4115 additions and 311 deletions

View File

@@ -35,12 +35,14 @@ package sonia.scm;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import sonia.scm.security.PermissionDescriptor;
import sonia.scm.user.User; import sonia.scm.user.User;
import sonia.scm.web.security.WebSecurityContext; import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import java.util.Collection; import java.util.Collection;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
@@ -122,6 +124,29 @@ public class ScmState
public ScmState(SCMContextProvider provider, User user, public ScmState(SCMContextProvider provider, User user,
Collection<String> groups, Collection<Type> repositoryTypes, Collection<String> groups, Collection<Type> repositoryTypes,
String defaultUserType, ScmClientConfig clientConfig) String defaultUserType, ScmClientConfig clientConfig)
{
this(provider, user, groups, repositoryTypes, defaultUserType,
clientConfig, null);
}
/**
* Constructs {@link ScmState} object.
*
*
* @param provider context provider
* @param user current user
* @param groups groups of the current user
* @param repositoryTypes available repository types
* @param defaultUserType default user type
* @param clientConfig client configuration
* @param availablePermissions list of available permissions
*
* @since 1.31
*/
public ScmState(SCMContextProvider provider, User user,
Collection<String> groups, Collection<Type> repositoryTypes,
String defaultUserType, ScmClientConfig clientConfig,
List<PermissionDescriptor> availablePermissions)
{ {
this.version = provider.getVersion(); this.version = provider.getVersion();
this.user = user; this.user = user;
@@ -129,10 +154,23 @@ public class ScmState
this.repositoryTypes = repositoryTypes; this.repositoryTypes = repositoryTypes;
this.clientConfig = clientConfig; this.clientConfig = clientConfig;
this.defaultUserType = defaultUserType; this.defaultUserType = defaultUserType;
this.availablePermissions = availablePermissions;
} }
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/**
* Returns a list of available global permissions.
*
*
* @return available global permissions
* @since 1.31
*/
public List<PermissionDescriptor> getAvailablePermissions()
{
return availablePermissions;
}
/** /**
* Returns configuration for SCM-Manager clients. * Returns configuration for SCM-Manager clients.
* *
@@ -215,6 +253,18 @@ public class ScmState
//~--- set methods ---------------------------------------------------------- //~--- set methods ----------------------------------------------------------
/**
* Sets a list of available global permissions.
*
*
* @param permissions list of available global permisisons
* @since 1.31
*/
public void setAvailablePermissions(List<PermissionDescriptor> permissions)
{
this.availablePermissions = permissions;
}
/** /**
* Setter for the client configuration * Setter for the client configuration
* *
@@ -299,6 +349,12 @@ public class ScmState
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/**
* Avaliable global permission
* @since 1.31
*/
private List<PermissionDescriptor> availablePermissions;
/** Field description */ /** Field description */
private ScmClientConfig clientConfig; private ScmClientConfig clientConfig;

View File

@@ -37,6 +37,8 @@ package sonia.scm.repository;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import sonia.scm.security.PermissionObject;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import java.io.Serializable; import java.io.Serializable;
@@ -52,7 +54,7 @@ import javax.xml.bind.annotation.XmlRootElement;
*/ */
@XmlRootElement(name = "permissions") @XmlRootElement(name = "permissions")
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
public class Permission implements Serializable public class Permission implements PermissionObject, Serializable
{ {
/** Field description */ /** Field description */
@@ -135,7 +137,7 @@ public class Permission implements Serializable
final Permission other = (Permission) obj; final Permission other = (Permission) obj;
return Objects.equal(name, other.name) && Objects.equal(type, other.type) return Objects.equal(name, other.name) && Objects.equal(type, other.type)
&& Objects.equal(groupPermission, groupPermission); && Objects.equal(groupPermission, groupPermission);
} }
/** /**
@@ -176,6 +178,7 @@ public class Permission implements Serializable
* *
* @return name of the user or group * @return name of the user or group
*/ */
@Override
public String getName() public String getName()
{ {
return name; return name;
@@ -198,6 +201,7 @@ public class Permission implements Serializable
* *
* @return true if the permision is a group permission * @return true if the permision is a group permission
*/ */
@Override
public boolean isGroupPermission() public boolean isGroupPermission()
{ {
return groupPermission; return groupPermission;

View File

@@ -44,16 +44,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sonia.scm.config.ScmConfiguration; import sonia.scm.config.ScmConfiguration;
import sonia.scm.group.GroupNames; import sonia.scm.security.RepositoryPermission;
import sonia.scm.security.Role; import sonia.scm.security.Role;
import sonia.scm.security.ScmSecurityException; import sonia.scm.security.ScmSecurityException;
import sonia.scm.util.AssertUtil; import sonia.scm.util.AssertUtil;
import sonia.scm.web.security.WebSecurityContext; import sonia.scm.web.security.WebSecurityContext;
//~--- JDK imports ------------------------------------------------------------
import java.util.List;
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
@@ -179,7 +175,7 @@ public final class PermissionUtil
public static boolean hasPermission(ScmConfiguration configuration, public static boolean hasPermission(ScmConfiguration configuration,
Repository repository, PermissionType pt) Repository repository, PermissionType pt)
{ {
boolean result = false; boolean result;
Subject subject = SecurityUtils.getSubject(); Subject subject = SecurityUtils.getSubject();
@@ -196,16 +192,7 @@ public final class PermissionUtil
} }
else else
{ {
List<Permission> permissions = repository.getPermissions(); result = subject.isPermitted(new RepositoryPermission(repository, pt));
if (permissions != null)
{
GroupNames groupNames =
subject.getPrincipals().oneByType(GroupNames.class);
result = hasPermission(permissions, username, groupNames, pt);
}
} }
} }
else else
@@ -270,37 +257,4 @@ public final class PermissionUtil
return permitted; return permitted;
} }
/**
* Method description
*
*
* @param permissions
* @param username
* @param groups
* @param pt
*
* @return
*/
private static boolean hasPermission(List<Permission> permissions,
String username, GroupNames groups, PermissionType pt)
{
boolean result = false;
for (Permission p : permissions)
{
String name = p.getName();
if (((name != null) && (p.getType().getValue() >= pt.getValue()))
&& (name.equals(username)
|| (p.isGroupPermission() && groups.contains(p.getName()))))
{
result = true;
break;
}
}
return result;
}
} }

View File

@@ -0,0 +1,208 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Objects;
//~--- JDK imports ------------------------------------------------------------
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Permission object which is assigned to a specific user or group.
*
* @author Sebastian Sdorra
* @since 1.31
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "assigned-permission")
public class AssignedPermission implements PermissionObject, Serializable
{
/** serial version uid */
private static final long serialVersionUID = -7411338422110323879L;
//~--- constructors ---------------------------------------------------------
/**
* Constructor is only visible for JAXB.
*
*/
public AssignedPermission() {}
/**
* Constructs a new AssignedPermission.
*
*
* @param permission assigned permission
*/
public AssignedPermission(AssignedPermission permission)
{
this.name = permission.name;
this.groupPermission = permission.groupPermission;
this.permission = permission.permission;
}
/**
* Constructs a new AssingnedPermmission.
*
*
* @param name name of the user
* @param permission permission string
*/
public AssignedPermission(String name, String permission)
{
this.name = name;
this.permission = permission;
}
/**
* Constructs a new AssingnedPermmission.
*
*
* @param name name of the user or group
* @param groupPermission true if the permission should be assigned to a group
* @param permission permission string
*/
public AssignedPermission(String name, boolean groupPermission,
String permission)
{
this.name = name;
this.groupPermission = groupPermission;
this.permission = permission;
}
//~--- methods --------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final AssignedPermission other = (AssignedPermission) obj;
return Objects.equal(name, other.name)
&& Objects.equal(groupPermission, other.groupPermission)
&& Objects.equal(permission, other.permission);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
return Objects.hashCode(name, groupPermission, permission);
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
//J-
return Objects.toStringHelper(this)
.add("name", name)
.add("groupPermisison", groupPermission)
.add("permission", permission)
.toString();
//J+
}
//~--- get methods ----------------------------------------------------------
/**
* Returns the name of the user or group which the permission is assigned.
*
*
* @return name of user or group
*/
@Override
public String getName()
{
return name;
}
/**
* Returns the string representation of the permission.
*
*
* @return string representation of the permission
*/
public String getPermission()
{
return permission;
}
/**
* Returns true if the permission is assigned to a group.
*
*
* @return true if the permission is assigned to a group
*/
@Override
public boolean isGroupPermission()
{
return groupPermission;
}
//~--- fields ---------------------------------------------------------------
/** group permission indicator */
@XmlElement(name = "group-permission")
private boolean groupPermission;
/** name of the user or group */
private String name;
/** string representation of the permission */
private String permission;
}

View File

@@ -0,0 +1,182 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Objects;
//~--- JDK imports ------------------------------------------------------------
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Descriptor for available permission objects.
*
* @author Sebastian Sdorra
* @since 1.31
*/
@XmlRootElement(name = "permission")
@XmlAccessorType(XmlAccessType.FIELD)
public class PermissionDescriptor implements Serializable
{
/** Field description */
private static final long serialVersionUID = -9141065458354047154L;
//~--- constructors ---------------------------------------------------------
/**
* Constructor is only visible for JAXB.
*
*/
public PermissionDescriptor() {}
/**
* Constructs ...
*
*
* @param displayName
* @param description
* @param value
*/
public PermissionDescriptor(String displayName, String description,
String value)
{
this.displayName = displayName;
this.description = description;
this.value = value;
}
//~--- methods --------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final PermissionDescriptor other = (PermissionDescriptor) obj;
return Objects.equal(displayName, other.displayName)
&& Objects.equal(description, other.description)
&& Objects.equal(value, other.value);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
return Objects.hashCode(displayName, description, value);
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
//J-
return Objects.toStringHelper(this)
.add("displayName", displayName)
.add("description", description)
.add("value", value)
.toString();
//J+
}
//~--- get methods ----------------------------------------------------------
/**
* Returns the description of the permission.
*
*
* @return description
*/
public String getDescription()
{
return description;
}
/**
* Returns the display name of the permission.
*
*
* @return display name
*/
public String getDisplayName()
{
return displayName;
}
/**
* Returns the string representation of the permission.
*
*
* @return string representation
*/
public String getValue()
{
return value;
}
//~--- fields ---------------------------------------------------------------
/** description */
private String description;
/** display name */
@XmlElement(name = "display-name")
private String displayName;
/** value */
private String value;
}

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
/**
* Interface for permission objects.
*
* @author Sebastian Sdorra
* @since 1.31
*/
public interface PermissionObject
{
/**
* Returns the name of the user or group which the permission is assigned.
*
*
* @return name of user or group
*/
public String getName();
/**
* Returns the id of the stored permission object.
*
*
* @return id of permission
*/
public boolean isGroupPermission();
}

View File

@@ -0,0 +1,124 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Predicate;
//~--- JDK imports ------------------------------------------------------------
import java.util.List;
/**
* The SecuritySystem manages global permissions.
*
* @author Sebastian Sdorra
* @since 1.31
*/
public interface SecuritySystem
{
/**
* Store a new permission.
*
*
* @param permission permission to be stored
*
* @return stored permission
*/
public StoredAssignedPermission addPermission(AssignedPermission permission);
/**
* Delete stored permission.
*
*
* @param permission permission to be deleted
*/
public void deletePermission(StoredAssignedPermission permission);
/**
* Delete stored permission.
*
*
* @param id id of the permission
*/
public void deletePermission(String id);
/**
* Modify stored permission.
*
*
* @param permission stored permisison
*/
public void modifyPermission(StoredAssignedPermission permission);
//~--- get methods ----------------------------------------------------------
/**
* Return all stored permissions.
*
*
* @return stored permission
*/
public List<StoredAssignedPermission> getAllPermissions();
/**
* Return all available permissions.
*
*
* @return available permissions
*/
public List<PermissionDescriptor> getAvailablePermissions();
/**
* Return the stored permission which is stored with the given id.
*
*
* @param id id of the stored permission
*
* @return stored permission
*/
public StoredAssignedPermission getPermission(String id);
/**
* Returns all stored permissions which are matched by the given
* {@link Predicate}.
*
*
* @param predicate predicate to filter
*
* @return filtered permissions
*/
public List<StoredAssignedPermission> getPermissions(
Predicate<AssignedPermission> predicate);
}

View File

@@ -0,0 +1,93 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- JDK imports ------------------------------------------------------------
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Permission object which is stored and assigned to a specific user or group.
*
* @author Sebastian Sdorra
* @since 1.31
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "assigned-permission")
public class StoredAssignedPermission extends AssignedPermission
{
/** serial version uid */
private static final long serialVersionUID = -4593919877023168090L;
//~--- constructors ---------------------------------------------------------
/**
* Constructor is only visible for JAXB.
*
*/
public StoredAssignedPermission() {}
/**
* Constructs a new StoredAssignedPermission.
*
*
* @param id id of the permission object
* @param permission assigned permission object
*/
public StoredAssignedPermission(String id, AssignedPermission permission)
{
super(permission);
this.id = id;
}
//~--- get methods ----------------------------------------------------------
/**
* Returns the id of the stored permission object.
*
*
* @return id of permission
*/
public String getId()
{
return id;
}
//~--- fields ---------------------------------------------------------------
/** id */
private String id;
}

View File

@@ -0,0 +1,152 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Objects;
import sonia.scm.HandlerEvent;
//~--- JDK imports ------------------------------------------------------------
import java.io.Serializable;
/**
* Event which is fired after a {@link StoredAssignedPermission} was added,
* removed or changed.
*
* @author Sebastian Sdorra
* @since 1.31
*/
public final class StoredAssignedPermissionEvent implements Serializable
{
/** serial version uid */
private static final long serialVersionUID = 706824497813169009L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs a new StoredAssignedPermissionEvent.
*
*
* @param type type of the event
* @param permission permission object which has changed
*/
public StoredAssignedPermissionEvent(HandlerEvent type,
StoredAssignedPermission permission)
{
this.type = type;
this.permission = permission;
}
//~--- methods --------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final StoredAssignedPermissionEvent other =
(StoredAssignedPermissionEvent) obj;
return Objects.equal(type, other.type)
&& Objects.equal(permission, other.permission);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
return Objects.hashCode(type, permission);
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
//J-
return Objects.toStringHelper(this)
.add("type", type)
.add("permission", permission)
.toString();
//J+
}
//~--- get methods ----------------------------------------------------------
/**
* Return the type of the event.
*
*
* @return type of event
*/
public HandlerEvent getEventType()
{
return type;
}
/**
* Returns the changed permission object.
*
*
* @return changed permission
*/
public StoredAssignedPermission getPermission()
{
return permission;
}
//~--- fields ---------------------------------------------------------------
/** changed permission */
private StoredAssignedPermission permission;
/** type of the event */
private HandlerEvent type;
}

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Predicate;
//~--- JDK imports ------------------------------------------------------------
import java.util.Collection;
/**
* A ConfigurationEntryStore can be used to store multiple entries of structured
* configuration data. <b>Note:<b> the default implementation use JAXB to
* marshall the items.
*
* @author Sebastian Sdorra
*
* @param <V> store value type
* @since 1.31
*/
public interface ConfigurationEntryStore<V> extends DataStore<V>
{
/**
* Return all values matching the given {@link Predicate}.
*
*
* @param predicate predicate to match values
*
* @return filtered collection of values
*/
public Collection<V> getMatchingValues(Predicate<V> predicate);
}

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.store;
/**
* The ConfigurationEntryStoreFactory can be used to create new or get existing
* {@link ConfigurationEntryStore}s. <b>Note:</b> the default implementation
* uses the same location as the {@link StoreFactory}, so be sure that the
* store names are unique for all {@link ConfigurationEntryStore}s and
* {@link Store}s.
*
* @author Sebastian Sdorra
* @since 1.31
*
* @apiviz.landmark
* @apiviz.uses sonia.scm.store.ConfigurationEntryStore
*/
public interface ConfigurationEntryStoreFactory
{
/**
* Get an existing {@link ConfigurationEntryStore} or create a new one.
*
*
* @param type type of the store objects
* @param name name of the store
* @param <T> type of the store objects
*
* @return {@link ConfigurationEntryStore} with given name and type
*/
public <T> ConfigurationEntryStore<T> getStore(Class<T> type, String name);
}

View File

@@ -0,0 +1,407 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.security.KeyGenerator;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.FileOutputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.stream.StreamSource;
/**
*
* @author Sebastian Sdorra
*
* @param <V>
*/
public class JAXBConfigurationEntryStore<V>
implements ConfigurationEntryStore<V>
{
/** Field description */
private static final Object LOCK = new Object();
/** Field description */
private static final String TAG_CONFIGURATION = "configuration";
/** Field description */
private static final String TAG_ENTRY = "entry";
/** Field description */
private static final String TAG_KEY = "key";
/** Field description */
private static final String TAG_VALUE = "value";
/**
* the logger for JAXBConfigurationEntryStore
*/
private static final Logger logger =
LoggerFactory.getLogger(JAXBConfigurationEntryStore.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
* @param keyGenerator
* @param file
* @param type
*/
JAXBConfigurationEntryStore(KeyGenerator keyGenerator, File file,
Class<V> type)
{
this.keyGenerator = keyGenerator;
this.file = file;
this.type = type;
try
{
this.context = JAXBContext.newInstance(type);
if (file.exists())
{
load();
}
}
catch (JAXBException ex)
{
throw new StoreException("could not create jaxb context", ex);
}
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*/
@Override
public void clear()
{
logger.debug("clear configuration store");
synchronized (LOCK)
{
entries.clear();
store();
}
}
/**
* Method description
*
*
* @param item
*
* @return
*/
@Override
public String put(V item)
{
String id = keyGenerator.createKey();
put(id, item);
return id;
}
/**
* Method description
*
*
* @param id
* @param item
*/
@Override
public void put(String id, V item)
{
logger.debug("put item {} to configuration store", id);
synchronized (LOCK)
{
entries.put(id, item);
store();
}
}
/**
* Method description
*
*
* @param id
*/
@Override
public void remove(String id)
{
logger.debug("remove item {} from configuration store", id);
synchronized (LOCK)
{
entries.remove(id);
store();
}
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param id
*
* @return
*/
@Override
public V get(String id)
{
logger.trace("get item {} from configuration store", id);
return entries.get(id);
}
/**
* Method description
*
*
* @return
*/
@Override
public Map<String, V> getAll()
{
logger.trace("get all items from configuration store");
return Collections.unmodifiableMap(entries);
}
/**
* Method description
*
*
* @param predicate
*
* @return
*/
@Override
public Collection<V> getMatchingValues(Predicate<V> predicate)
{
return Collections2.filter(entries.values(), predicate);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param writer
*/
private void close(XMLStreamWriter writer)
{
if (writer != null)
{
try
{
writer.close();
}
catch (XMLStreamException ex)
{
logger.error("could not close writer", ex);
}
}
}
/**
* Method description
*
*
* @param reader
*/
private void close(XMLStreamReader reader)
{
if (reader != null)
{
try
{
reader.close();
}
catch (XMLStreamException ex)
{
logger.error("could not close reader", ex);
}
}
}
/**
* Method description
*
*
* @return
*/
private void load()
{
logger.debug("load configuration from {}", file);
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLStreamReader reader = null;
try
{
Unmarshaller u = context.createUnmarshaller();
reader = xmlInputFactory.createXMLStreamReader(new StreamSource(file));
reader.nextTag();
reader.nextTag();
while (reader.isStartElement() && reader.getLocalName().equals(TAG_ENTRY))
{
// read key
reader.nextTag();
String key = reader.getElementText();
// read entry
reader.nextTag();
V v = (V) u.unmarshal(reader, type).getValue();
entries.put(key, v);
}
}
catch (Exception ex)
{
throw new StoreException("could not load configuration", ex);
}
finally
{
close(reader);
}
}
/**
* Method description
*
*/
private void store()
{
logger.debug("store configuration to {}", file);
XMLStreamWriter writer = null;
try
{
writer = XMLOutputFactory.newFactory().createXMLStreamWriter(
new FileOutputStream(file));
writer.writeStartDocument();
writer.writeStartElement(TAG_CONFIGURATION);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
for (Entry<String, V> e : entries.entrySet())
{
writer.writeStartElement(TAG_ENTRY);
writer.writeStartElement(TAG_KEY);
writer.writeCharacters(e.getKey());
writer.writeEndElement();
JAXBElement<V> je = new JAXBElement<V>(QName.valueOf(TAG_VALUE), type,
e.getValue());
m.marshal(je, writer);
}
writer.writeEndElement();
writer.writeEndDocument();
}
catch (Exception ex)
{
throw new StoreException("could not store configuration", ex);
}
finally
{
close(writer);
}
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private JAXBContext context;
/** Field description */
private Map<String, V> entries = Maps.newHashMap();
/** Field description */
private File file;
/** Field description */
private KeyGenerator keyGenerator;
/** Field description */
private Class<V> type;
}

View File

@@ -0,0 +1,113 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContextProvider;
import sonia.scm.security.KeyGenerator;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
/**
*
* @author Sebastian Sdorra
*/
@Singleton
public class JAXBConfigurationEntryStoreFactory
implements ConfigurationEntryStoreFactory
{
/**
* the logger for JAXBConfigurationEntryStoreFactory
*/
private static final Logger logger =
LoggerFactory.getLogger(JAXBConfigurationEntryStoreFactory.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param keyGenerator
* @param context
*/
@Inject
public JAXBConfigurationEntryStoreFactory(KeyGenerator keyGenerator,
SCMContextProvider context)
{
this.keyGenerator = keyGenerator;
directory = new File(context.getBaseDirectory(),
StoreConstants.CONFIGDIRECTORY_NAME);
IOUtil.mkdirs(directory);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param type
* @param name
* @param <T>
*
* @return
*/
@Override
public <T> ConfigurationEntryStore<T> getStore(Class<T> type, String name)
{
logger.debug("create new configuration store for type {} with name {}",
type, name);
return new JAXBConfigurationEntryStore<T>(keyGenerator,
new File(directory, name.concat(StoreConstants.FILE_EXTENSION)), type);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private File directory;
/** Field description */
private KeyGenerator keyGenerator;
}

View File

@@ -61,9 +61,6 @@ import javax.xml.bind.Marshaller;
public class JAXBDataStore<T> extends FileBasedStore<T> implements DataStore<T> public class JAXBDataStore<T> extends FileBasedStore<T> implements DataStore<T>
{ {
/** Field description */
private static final String SUFFIX = ".xml";
/** /**
* the logger for JAXBDataStore * the logger for JAXBDataStore
*/ */
@@ -82,7 +79,7 @@ public class JAXBDataStore<T> extends FileBasedStore<T> implements DataStore<T>
*/ */
public JAXBDataStore(KeyGenerator keyGenerator, Class<T> type, File directory) public JAXBDataStore(KeyGenerator keyGenerator, Class<T> type, File directory)
{ {
super(directory, SUFFIX); super(directory, StoreConstants.FILE_EXTENSION);
this.keyGenerator = keyGenerator; this.keyGenerator = keyGenerator;
try try

View File

@@ -56,12 +56,6 @@ import java.io.IOException;
public class JAXBStoreFactory implements ListenableStoreFactory public class JAXBStoreFactory implements ListenableStoreFactory
{ {
/** Field description */
public static final String CONFIGDIRECTORY_NAME = "config";
/** Field description */
public static final String FILE_EXTENSION = ".xml";
/** the logger for JAXBStoreFactory */ /** the logger for JAXBStoreFactory */
private static final Logger logger = private static final Logger logger =
LoggerFactory.getLogger(JAXBStoreFactory.class); LoggerFactory.getLogger(JAXBStoreFactory.class);
@@ -91,7 +85,7 @@ public class JAXBStoreFactory implements ListenableStoreFactory
public void init(SCMContextProvider context) public void init(SCMContextProvider context)
{ {
configDirectory = new File(context.getBaseDirectory(), configDirectory = new File(context.getBaseDirectory(),
CONFIGDIRECTORY_NAME); StoreConstants.CONFIGDIRECTORY_NAME);
IOUtil.mkdirs(configDirectory); IOUtil.mkdirs(configDirectory);
} }
@@ -115,7 +109,8 @@ public class JAXBStoreFactory implements ListenableStoreFactory
throw new IllegalStateException("store factory is not initialized"); throw new IllegalStateException("store factory is not initialized");
} }
File configFile = new File(configDirectory, name.concat(FILE_EXTENSION)); File configFile = new File(configDirectory,
name.concat(StoreConstants.FILE_EXTENSION));
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.store;
/**
*
* @author Sebastian Sdorra
*/
public interface StoreConstants
{
/** Field description */
public static final String CONFIGDIRECTORY_NAME = "config";
/** Field description */
public static final String FILE_EXTENSION = ".xml";
}

View File

@@ -0,0 +1,57 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.security.UUIDKeyGenerator;
/**
*
* @author Sebastian Sdorra
*/
public class JAXBConfigurationEntryStoreTest extends ConfigurationEntryStoreTestBase
{
/**
* Method description
*
*
* @return
*/
@Override
protected ConfigurationEntryStoreFactory createConfigurationStoreFactory()
{
return new JAXBConfigurationEntryStoreFactory(new UUIDKeyGenerator(),
contextProvider);
}
}

View File

@@ -151,6 +151,7 @@ public class AbstractTestBase
try try
{ {
preTearDown(); preTearDown();
clearSubject();
} }
finally finally
{ {

View File

@@ -0,0 +1,63 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.store;
/**
*
* @author Sebastian Sdorra
*/
public abstract class ConfigurationEntryStoreTestBase extends KeyValueStoreTestBase
{
/**
* Method description
*
*
* @return
*/
protected abstract ConfigurationEntryStoreFactory createConfigurationStoreFactory();
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected ConfigurationEntryStore<StoreObject> getDataStore()
{
return createConfigurationStoreFactory().getStore(StoreObject.class,
"test");
}
}

View File

@@ -30,26 +30,14 @@
*/ */
package sonia.scm.store; package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Before;
import org.junit.Test;
import sonia.scm.AbstractTestBase;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.util.Map;
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
*/ */
public abstract class DataStoreTestBase extends AbstractTestBase public abstract class DataStoreTestBase extends KeyValueStoreTestBase
{ {
/** /**
@@ -60,155 +48,6 @@ public abstract class DataStoreTestBase extends AbstractTestBase
*/ */
protected abstract DataStoreFactory createDataStoreFactory(); protected abstract DataStoreFactory createDataStoreFactory();
/**
* Method description
*
*/
@Before
public void before()
{
store = getDataStore();
store.clear();
}
/**
* Method description
*
*/
@Test
public void testClear()
{
testPutWithId();
store.clear();
assertNull(store.get("1"));
assertNull(store.get("2"));
assertTrue(store.getAll().isEmpty());
}
/**
* Method description
*
*/
@Test
public void testGet()
{
StoreObject other = store.get("1");
assertNull(other);
StoreObject obj = new StoreObject("test-1");
store.put("1", obj);
other = store.get("1");
assertNotNull(other);
assertEquals(obj, other);
}
/**
* Method description
*
*/
@Test
public void testGetAll()
{
StoreObject obj1 = new StoreObject("test-1");
store.put("1", obj1);
StoreObject obj2 = new StoreObject("test-2");
store.put("2", obj2);
Map<String, StoreObject> map = store.getAll();
assertNotNull(map);
assertFalse(map.isEmpty());
assertEquals(2, map.size());
assertEquals(obj1, map.get("1"));
assertEquals(obj2, map.get("2"));
assertNull(map.get("3"));
}
/**
* Method description
*
*/
@Test
public void testGetAllFromEmpty()
{
Map<String, StoreObject> map = store.getAll();
assertNotNull(map);
assertTrue(map.isEmpty());
}
/**
* Method description
*
*/
@Test
public void testGetFromEmpty()
{
StoreObject obj = store.get("test");
assertNull(obj);
}
/**
* Method description
*
*/
@Test
public void testPutWithId()
{
StoreObject obj1 = new StoreObject("test-1");
store.put("1", obj1);
StoreObject obj2 = new StoreObject("test-2");
store.put("2", obj2);
assertEquals(obj1, store.get("1"));
assertEquals(obj2, store.get("2"));
}
/**
* Method description
*
*/
@Test
public void testPutWithoutId()
{
StoreObject obj = new StoreObject("test-1");
String id = store.put(obj);
assertNotNull(id);
assertEquals(obj, store.get(id));
}
/**
* Method description
*
*/
@Test
public void testRemove()
{
testPutWithId();
store.remove("1");
assertNull(store.get("1"));
assertNotNull(store.get("2"));
store.remove("2");
assertNull(store.get("2"));
}
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/** /**
@@ -217,13 +56,9 @@ public abstract class DataStoreTestBase extends AbstractTestBase
* *
* @return * @return
*/ */
private DataStore<StoreObject> getDataStore() @Override
protected DataStore<StoreObject> getDataStore()
{ {
return createDataStoreFactory().getStore(StoreObject.class, "test"); return createDataStoreFactory().getStore(StoreObject.class, "test");
} }
//~--- fields ---------------------------------------------------------------
/** Field description */
private DataStore<StoreObject> store;
} }

View File

@@ -0,0 +1,221 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.store;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Before;
import org.junit.Test;
import sonia.scm.AbstractTestBase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
//~--- JDK imports ------------------------------------------------------------
import java.util.Map;
/**
*
* @author Sebastian Sdorra
*/
public abstract class KeyValueStoreTestBase extends AbstractTestBase
{
/**
* Method description
*
*
* @return
*/
protected abstract DataStore<StoreObject> getDataStore();
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*/
@Before
public void before()
{
store = getDataStore();
store.clear();
}
/**
* Method description
*
*/
@Test
public void testClear()
{
testPutWithId();
store.clear();
assertNull(store.get("1"));
assertNull(store.get("2"));
assertTrue(store.getAll().isEmpty());
}
/**
* Method description
*
*/
@Test
public void testGet()
{
StoreObject other = store.get("1");
assertNull(other);
StoreObject obj = new StoreObject("test-1");
store.put("1", obj);
other = store.get("1");
assertNotNull(other);
assertEquals(obj, other);
}
/**
* Method description
*
*/
@Test
public void testGetAll()
{
StoreObject obj1 = new StoreObject("test-1");
store.put("1", obj1);
StoreObject obj2 = new StoreObject("test-2");
store.put("2", obj2);
Map<String, StoreObject> map = store.getAll();
assertNotNull(map);
assertFalse(map.isEmpty());
assertEquals(2, map.size());
assertEquals(obj1, map.get("1"));
assertEquals(obj2, map.get("2"));
assertNull(map.get("3"));
}
/**
* Method description
*
*/
@Test
public void testGetAllFromEmpty()
{
Map<String, StoreObject> map = store.getAll();
assertNotNull(map);
assertTrue(map.isEmpty());
}
/**
* Method description
*
*/
@Test
public void testGetFromEmpty()
{
StoreObject obj = store.get("test");
assertNull(obj);
}
/**
* Method description
*
*/
@Test
public void testPutWithId()
{
StoreObject obj1 = new StoreObject("test-1");
store.put("1", obj1);
StoreObject obj2 = new StoreObject("test-2");
store.put("2", obj2);
assertEquals(obj1, store.get("1"));
assertEquals(obj2, store.get("2"));
}
/**
* Method description
*
*/
@Test
public void testPutWithoutId()
{
StoreObject obj = new StoreObject("test-1");
String id = store.put(obj);
assertNotNull(id);
assertEquals(obj, store.get(id));
}
/**
* Method description
*
*/
@Test
public void testRemove()
{
testPutWithId();
store.remove("1");
assertNull(store.get("1"));
assertNotNull(store.get("2"));
store.remove("2");
assertNull(store.get("2"));
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private DataStore<StoreObject> store;
}

View File

@@ -41,6 +41,7 @@ import org.apache.shiro.authz.Permission;
import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.Subject.Builder;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
@@ -138,6 +139,20 @@ public final class MockUtil
* @return * @return
*/ */
public static Subject createUserSubject() public static Subject createUserSubject()
{
return createUserSubject(null);
}
/**
* Method description
*
*
*
* @param securityManager
* @return
*/
public static Subject createUserSubject(
org.apache.shiro.mgt.SecurityManager securityManager)
{ {
SimplePrincipalCollection collection = new SimplePrincipalCollection(); SimplePrincipalCollection collection = new SimplePrincipalCollection();
User user = UserTestData.createTrillian(); User user = UserTestData.createTrillian();
@@ -145,8 +160,18 @@ public final class MockUtil
collection.add(user.getName(), "junit"); collection.add(user.getName(), "junit");
collection.add(user, "junit"); collection.add(user, "junit");
return new Subject.Builder().principals(collection).authenticated( Builder builder;
true).buildSubject();
if (securityManager != null)
{
builder = new Subject.Builder(securityManager);
}
else
{
builder = new Subject.Builder();
}
return builder.principals(collection).authenticated(true).buildSubject();
} }
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------

View File

@@ -47,7 +47,7 @@ import org.slf4j.LoggerFactory;
import sonia.scm.api.rest.UriExtensionsConfig; import sonia.scm.api.rest.UriExtensionsConfig;
import sonia.scm.cache.CacheManager; import sonia.scm.cache.CacheManager;
import sonia.scm.cache.EhCacheManager; import sonia.scm.cache.GuavaCacheManager;
import sonia.scm.config.ScmConfiguration; import sonia.scm.config.ScmConfiguration;
import sonia.scm.event.ScmEventBus; import sonia.scm.event.ScmEventBus;
import sonia.scm.filter.AdminSecurityFilter; import sonia.scm.filter.AdminSecurityFilter;
@@ -86,13 +86,17 @@ import sonia.scm.resources.ScriptResourceServlet;
import sonia.scm.security.CipherHandler; import sonia.scm.security.CipherHandler;
import sonia.scm.security.CipherUtil; import sonia.scm.security.CipherUtil;
import sonia.scm.security.DefaultKeyGenerator; import sonia.scm.security.DefaultKeyGenerator;
import sonia.scm.security.DefaultSecuritySystem;
import sonia.scm.security.EncryptionHandler; import sonia.scm.security.EncryptionHandler;
import sonia.scm.security.KeyGenerator; import sonia.scm.security.KeyGenerator;
import sonia.scm.security.MessageDigestEncryptionHandler; import sonia.scm.security.MessageDigestEncryptionHandler;
import sonia.scm.security.SecurityContext; import sonia.scm.security.SecurityContext;
import sonia.scm.security.SecuritySystem;
import sonia.scm.store.BlobStoreFactory; import sonia.scm.store.BlobStoreFactory;
import sonia.scm.store.ConfigurationEntryStoreFactory;
import sonia.scm.store.DataStoreFactory; import sonia.scm.store.DataStoreFactory;
import sonia.scm.store.FileBlobStoreFactory; import sonia.scm.store.FileBlobStoreFactory;
import sonia.scm.store.JAXBConfigurationEntryStoreFactory;
import sonia.scm.store.JAXBDataStoreFactory; import sonia.scm.store.JAXBDataStoreFactory;
import sonia.scm.store.JAXBStoreFactory; import sonia.scm.store.JAXBStoreFactory;
import sonia.scm.store.ListenableStoreFactory; import sonia.scm.store.ListenableStoreFactory;
@@ -142,7 +146,6 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import sonia.scm.cache.GuavaCacheManager;
/** /**
* *
@@ -252,6 +255,8 @@ public class ScmServletModule extends ServletModule
// bind core // bind core
bind(StoreFactory.class, JAXBStoreFactory.class); bind(StoreFactory.class, JAXBStoreFactory.class);
bind(ListenableStoreFactory.class, JAXBStoreFactory.class); bind(ListenableStoreFactory.class, JAXBStoreFactory.class);
bind(ConfigurationEntryStoreFactory.class,
JAXBConfigurationEntryStoreFactory.class);
bind(DataStoreFactory.class, JAXBDataStoreFactory.class); bind(DataStoreFactory.class, JAXBDataStoreFactory.class);
bind(BlobStoreFactory.class, FileBlobStoreFactory.class); bind(BlobStoreFactory.class, FileBlobStoreFactory.class);
bind(ScmConfiguration.class).toInstance(config); bind(ScmConfiguration.class).toInstance(config);
@@ -271,6 +276,7 @@ public class ScmServletModule extends ServletModule
bind(AuthenticationManager.class, ChainAuthenticatonManager.class); bind(AuthenticationManager.class, ChainAuthenticatonManager.class);
bind(SecurityContext.class).to(BasicSecurityContext.class); bind(SecurityContext.class).to(BasicSecurityContext.class);
bind(WebSecurityContext.class).to(BasicSecurityContext.class); bind(WebSecurityContext.class).to(BasicSecurityContext.class);
bind(SecuritySystem.class).to(DefaultSecuritySystem.class);
bind(AdministrationContext.class, DefaultAdministrationContext.class); bind(AdministrationContext.class, DefaultAdministrationContext.class);
// bind cache // bind cache

View File

@@ -0,0 +1,167 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.api.rest;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Objects;
//~--- JDK imports ------------------------------------------------------------
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author Sebastian Sdorra
*/
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Permission implements Serializable
{
/** Field description */
private static final long serialVersionUID = 4320217034601679261L;
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*/
public Permission() {}
/**
* Constructs ...
*
*
* @param id
* @param value
*/
public Permission(String id, String value)
{
this.id = id;
this.value = value;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param obj
*
* @return
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Permission other = (Permission) obj;
return Objects.equal(id, other.id) && Objects.equal(value, other.value);
}
/**
* Method description
*
*
* @return
*/
@Override
public int hashCode()
{
return Objects.hashCode(id, value);
}
/**
* Method description
*
*
* @return
*/
@Override
public String toString()
{
//J-
return Objects.toStringHelper(this)
.add("id", id)
.add("value", value)
.toString();
//J+
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public String getId()
{
return id;
}
/**
* Method description
*
*
* @return
*/
public String getValue()
{
return value;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private String id;
/** Field description */
private String value;
}

View File

@@ -0,0 +1,265 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import sonia.scm.api.rest.Permission;
import sonia.scm.security.AssignedPermission;
import sonia.scm.security.SecuritySystem;
import sonia.scm.security.StoredAssignedPermission;
//~--- JDK imports ------------------------------------------------------------
import java.net.URI;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
/**
*
* @author Sebastian Sdorra
* @since 1.31
*/
public abstract class AbstractPermissionResource
{
/**
* Constructs ...
*
*
* @param securitySystem
* @param name
*/
protected AbstractPermissionResource(SecuritySystem securitySystem,
String name)
{
this.securitySystem = securitySystem;
this.name = name;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param permission
*
* @return
*/
protected abstract AssignedPermission transformPermission(
Permission permission);
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
protected abstract Predicate<AssignedPermission> getPredicate();
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param uriInfo
* @param permission
*
* @return
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response add(@Context UriInfo uriInfo, Permission permission)
{
AssignedPermission ap = transformPermission(permission);
StoredAssignedPermission sap = securitySystem.addPermission(ap);
URI uri = uriInfo.getAbsolutePathBuilder().path(sap.getId()).build();
return Response.created(uri).build();
}
/**
* Method description
*
*
* @param id
*
* @return
*/
@DELETE
@Path("{id}")
public Response delete(@PathParam("id") String id)
{
StoredAssignedPermission sap = getPermission(id);
securitySystem.deletePermission(sap);
return Response.noContent().build();
}
/**
* Method description
*
*
* @param id
* @param permission
*
* @return
*/
@PUT
@Path("{id}")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response update(@PathParam("id") String id, Permission permission)
{
StoredAssignedPermission sap = getPermission(id);
securitySystem.modifyPermission(new StoredAssignedPermission(sap.getId(),
transformPermission(permission)));
return Response.noContent().build();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param id
*
* @return
*/
@GET
@Path("{id}")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Permission get(@PathParam("id") String id)
{
StoredAssignedPermission sap = getPermission(id);
return new Permission(sap.getId(), sap.getPermission());
}
/**
* Method description
*
*
* @return
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public List<Permission> getAll()
{
return getPermissions(getPredicate());
}
/**
* Method description
*
*
* @param id
*
* @return
*/
private StoredAssignedPermission getPermission(String id)
{
StoredAssignedPermission sap = securitySystem.getPermission(id);
if (sap == null)
{
throw new WebApplicationException(Status.NOT_FOUND);
}
if (!getPredicate().apply(sap))
{
throw new WebApplicationException(Status.BAD_REQUEST);
}
return sap;
}
/**
* Method description
*
*
* @param predicate
*
* @return
*/
private List<Permission> getPermissions(
Predicate<AssignedPermission> predicate)
{
List<StoredAssignedPermission> permissions =
securitySystem.getPermissions(predicate);
return Lists.transform(permissions,
new Function<StoredAssignedPermission, Permission>()
{
@Override
public Permission apply(StoredAssignedPermission mgp)
{
return new Permission(mgp.getId(), mgp.getPermission());
}
});
}
//~--- fields ---------------------------------------------------------------
/** Field description */
protected String name;
/** Field description */
private SecuritySystem securitySystem;
}

View File

@@ -56,6 +56,9 @@ import sonia.scm.ScmState;
import sonia.scm.config.ScmConfiguration; import sonia.scm.config.ScmConfiguration;
import sonia.scm.group.GroupNames; import sonia.scm.group.GroupNames;
import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryManager;
import sonia.scm.security.PermissionDescriptor;
import sonia.scm.security.Role;
import sonia.scm.security.SecuritySystem;
import sonia.scm.security.Tokens; import sonia.scm.security.Tokens;
import sonia.scm.user.User; import sonia.scm.user.User;
import sonia.scm.user.UserManager; import sonia.scm.user.UserManager;
@@ -64,6 +67,7 @@ import sonia.scm.user.UserManager;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@@ -105,16 +109,18 @@ public class AuthenticationResource
* @param repositoryManger * @param repositoryManger
* @param userManager * @param userManager
* @param securityContextProvider * @param securityContextProvider
* @param securitySystem
*/ */
@Inject @Inject
public AuthenticationResource(SCMContextProvider contextProvider, public AuthenticationResource(SCMContextProvider contextProvider,
ScmConfiguration configuration, RepositoryManager repositoryManger, ScmConfiguration configuration, RepositoryManager repositoryManger,
UserManager userManager) UserManager userManager, SecuritySystem securitySystem)
{ {
this.contextProvider = contextProvider; this.contextProvider = contextProvider;
this.configuration = configuration; this.configuration = configuration;
this.repositoryManger = repositoryManger; this.repositoryManger = repositoryManger;
this.userManager = userManager; this.userManager = userManager;
this.securitySystem = securitySystem;
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -295,7 +301,8 @@ public class AuthenticationResource
*/ */
private ScmState createAnonymousState() private ScmState createAnonymousState()
{ {
return createState(SCMContext.ANONYMOUS, Collections.EMPTY_LIST); return createState(SCMContext.ANONYMOUS, Collections.EMPTY_LIST,
Collections.EMPTY_LIST);
} }
/** /**
@@ -314,7 +321,14 @@ public class AuthenticationResource
User user = collection.oneByType(User.class); User user = collection.oneByType(User.class);
GroupNames groups = collection.oneByType(GroupNames.class); GroupNames groups = collection.oneByType(GroupNames.class);
return createState(user, groups.getCollection()); List<PermissionDescriptor> ap = Collections.EMPTY_LIST;
if (subject.hasRole(Role.ADMIN))
{
ap = securitySystem.getAvailablePermissions();
}
return createState(user, groups.getCollection(), ap);
} }
/** /**
@@ -323,14 +337,16 @@ public class AuthenticationResource
* *
* @param user * @param user
* @param groups * @param groups
* @param availablePermissions
* *
* @return * @return
*/ */
private ScmState createState(User user, Collection<String> groups) private ScmState createState(User user, Collection<String> groups,
List<PermissionDescriptor> availablePermissions)
{ {
return new ScmState(contextProvider, user, groups, return new ScmState(contextProvider, user, groups,
repositoryManger.getConfiguredTypes(), userManager.getDefaultType(), repositoryManger.getConfiguredTypes(), userManager.getDefaultType(),
new ScmClientConfig(configuration)); new ScmClientConfig(configuration), availablePermissions);
} }
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
@@ -344,6 +360,9 @@ public class AuthenticationResource
/** Field description */ /** Field description */
private RepositoryManager repositoryManger; private RepositoryManager repositoryManger;
/** Field description */
private SecuritySystem securitySystem;
/** Field description */ /** Field description */
private UserManager userManager; private UserManager userManager;
} }

View File

@@ -0,0 +1,135 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Predicate;
import sonia.scm.api.rest.Permission;
import sonia.scm.security.AssignedPermission;
import sonia.scm.security.SecuritySystem;
/**
*
* @author Sebastian Sdorra
*/
public class GroupPermissionResource extends AbstractPermissionResource
{
/**
* Constructs ...
*
*
* @param securitySystem
* @param name
*/
public GroupPermissionResource(SecuritySystem securitySystem, String name)
{
super(securitySystem, name);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param permission
*
* @return
*/
@Override
protected AssignedPermission transformPermission(Permission permission)
{
return new AssignedPermission(name, true, permission.getValue());
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected Predicate<AssignedPermission> getPredicate()
{
return new GroupPredicate(name);
}
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 13/05/01
* @author Enter your name here...
*/
private static class GroupPredicate implements Predicate<AssignedPermission>
{
/**
* Constructs ...
*
*
* @param name
*/
public GroupPredicate(String name)
{
this.name = name;
}
//~--- methods ------------------------------------------------------------
/**
* Method description
*
*
* @param input
*
* @return
*/
@Override
public boolean apply(AssignedPermission input)
{
return input.isGroupPermission() && input.getName().equals(name);
}
//~--- fields -------------------------------------------------------------
/** Field description */
private String name;
}
}

View File

@@ -0,0 +1,107 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import org.apache.shiro.SecurityUtils;
import sonia.scm.security.Role;
import sonia.scm.security.SecuritySystem;
//~--- JDK imports ------------------------------------------------------------
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
/**
*
* @author Sebastian Sdorra
*/
@Path("security/permission")
public class SecuritySystemResource
{
/**
* Constructs ...
*
*
* @param system
*/
@Inject
public SecuritySystemResource(SecuritySystem system)
{
this.system = system;
// only administrators can use this resource
SecurityUtils.getSubject().checkRole(Role.ADMIN);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param group
*
* @return
*/
@Path("group/{group}")
public GroupPermissionResource getGroupSubResource(
@PathParam("group") String group)
{
return new GroupPermissionResource(system, group);
}
/**
* Method description
*
*
* @param user
*
* @return
*/
@Path("user/{user}")
public UserPermissionResource getUserSubResource(
@PathParam("user") String user)
{
return new UserPermissionResource(system, user);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private SecuritySystem system;
}

View File

@@ -0,0 +1,135 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Predicate;
import sonia.scm.api.rest.Permission;
import sonia.scm.security.AssignedPermission;
import sonia.scm.security.SecuritySystem;
/**
*
* @author Sebastian Sdorra
*/
public class UserPermissionResource extends AbstractPermissionResource
{
/**
* Constructs ...
*
*
* @param securitySystem
* @param name
*/
public UserPermissionResource(SecuritySystem securitySystem, String name)
{
super(securitySystem, name);
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param permission
*
* @return
*/
@Override
protected AssignedPermission transformPermission(Permission permission)
{
return new AssignedPermission(name, permission.getValue());
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected Predicate<AssignedPermission> getPredicate()
{
return new UserPredicate(name);
}
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 13/05/01
* @author Enter your name here...
*/
private static class UserPredicate implements Predicate<AssignedPermission>
{
/**
* Constructs ...
*
*
* @param name
*/
public UserPredicate(String name)
{
this.name = name;
}
//~--- methods ------------------------------------------------------------
/**
* Method description
*
*
* @param input
*
* @return
*/
@Override
public boolean apply(AssignedPermission input)
{
return !input.isGroupPermission() && input.getName().equals(name);
}
//~--- fields -------------------------------------------------------------
/** Field description */
private String name;
}
}

View File

@@ -0,0 +1,501 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.HandlerEvent;
import sonia.scm.event.ScmEventBus;
import sonia.scm.event.Subscriber;
import sonia.scm.group.GroupEvent;
import sonia.scm.store.ConfigurationEntryStore;
import sonia.scm.store.ConfigurationEntryStoreFactory;
import sonia.scm.user.UserEvent;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map.Entry;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* TODO add events
*
* @author Sebastian Sdorra
* @since 1.31
*/
@Singleton
@Subscriber(async = true)
public class DefaultSecuritySystem implements SecuritySystem
{
/** Field description */
private static final String NAME = "security";
/** Field description */
private static final String PERMISSION_DESCRIPTOR =
"META-INF/scm/permissions.xml";
/**
* the logger for DefaultSecuritySystem
*/
private static final Logger logger =
LoggerFactory.getLogger(DefaultSecuritySystem.class);
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
* @param storeFactory
*/
@Inject
public DefaultSecuritySystem(ConfigurationEntryStoreFactory storeFactory)
{
store = storeFactory.getStore(AssignedPermission.class, NAME);
readAvailablePermissions();
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param permission
*
* @return
*/
@Override
public StoredAssignedPermission addPermission(AssignedPermission permission)
{
assertIsAdmin();
String id = store.put(permission);
StoredAssignedPermission sap = new StoredAssignedPermission(id, permission);
//J-
ScmEventBus.getInstance().post(
new StoredAssignedPermissionEvent(HandlerEvent.CREATE, sap)
);
//J+
return sap;
}
/**
* Method description
*
*
* @param permission
*/
@Override
public void deletePermission(StoredAssignedPermission permission)
{
assertIsAdmin();
store.remove(permission.getId());
//J-
ScmEventBus.getInstance().post(
new StoredAssignedPermissionEvent(HandlerEvent.CREATE, permission)
);
//J+
}
/**
* Method description
*
*
* @param id
*/
@Override
public void deletePermission(String id)
{
assertIsAdmin();
AssignedPermission ap = store.get(id);
if (ap != null)
{
deletePermission(new StoredAssignedPermission(id, ap));
}
}
/**
* Method description
*
*
* @param event
*/
@Subscribe
public void handleEvent(final UserEvent event)
{
if (event.getEventType() == HandlerEvent.DELETE)
{
deletePermissions(new Predicate<AssignedPermission>()
{
@Override
public boolean apply(AssignedPermission p)
{
return !p.isGroupPermission()
&& event.getItem().getName().equals(p.getName());
}
});
}
}
/**
* Method description
*
*
* @param event
*/
@Subscribe
public void handleEvent(final GroupEvent event)
{
if (event.getEventType() == HandlerEvent.DELETE)
{
deletePermissions(new Predicate<AssignedPermission>()
{
@Override
public boolean apply(AssignedPermission p)
{
return p.isGroupPermission()
&& event.getItem().getName().equals(p.getName());
}
});
}
}
/**
* Method description
*
*
* @param permission
*/
@Override
public void modifyPermission(StoredAssignedPermission permission)
{
assertIsAdmin();
synchronized (store)
{
store.remove(permission.getId());
store.put(permission.getId(), new AssignedPermission(permission));
}
//J-
ScmEventBus.getInstance().post(
new StoredAssignedPermissionEvent(HandlerEvent.CREATE, permission)
);
//J+
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
public List<StoredAssignedPermission> getAllPermissions()
{
return getPermissions(null);
}
/**
* Method description
*
*
* @return
*/
@Override
public List<PermissionDescriptor> getAvailablePermissions()
{
assertIsAdmin();
return availablePermissions;
}
/**
* Method description
*
*
* @param id
*
* @return
*/
@Override
public StoredAssignedPermission getPermission(String id)
{
assertIsAdmin();
StoredAssignedPermission sap = null;
AssignedPermission ap = store.get(id);
if (ap != null)
{
sap = new StoredAssignedPermission(id, ap);
}
return sap;
}
/**
* Method description
*
*
* @param predicate
*
* @return
*/
@Override
public List<StoredAssignedPermission> getPermissions(
Predicate<AssignedPermission> predicate)
{
Builder<StoredAssignedPermission> permissions = ImmutableList.builder();
for (Entry<String, AssignedPermission> e : store.getAll().entrySet())
{
if ((predicate == null) || predicate.apply(e.getValue()))
{
permissions.add(new StoredAssignedPermission(e.getKey(), e.getValue()));
}
}
return permissions.build();
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*/
private void assertIsAdmin()
{
SecurityUtils.getSubject().checkRole(Role.ADMIN);
}
/**
* Method description
*
*
* @param predicate
*/
private void deletePermissions(Predicate<AssignedPermission> predicate)
{
List<StoredAssignedPermission> permissions = getPermissions(predicate);
for (StoredAssignedPermission permission : permissions)
{
deletePermission(permission);
}
}
/**
* Method description
*
*
* @param context
* @param descriptorUrl
*
* @return
*/
private List<PermissionDescriptor> parsePermissionDescriptor(
JAXBContext context, URL descriptorUrl)
{
List<PermissionDescriptor> descriptors = Collections.EMPTY_LIST;
try
{
PermissionDescriptors descriptorWrapper =
(PermissionDescriptors) context.createUnmarshaller().unmarshal(
descriptorUrl);
descriptors = descriptorWrapper.getPermissions();
logger.debug("found {} permissions at {}", descriptors.size(),
descriptorUrl);
logger.trace("permissions from {}: {}", descriptorUrl, descriptors);
}
catch (JAXBException ex)
{
logger.error("could not parse permission descriptor", ex);
}
return descriptors;
}
/**
* Method description
*
*/
private void readAvailablePermissions()
{
Builder<PermissionDescriptor> builder = ImmutableList.builder();
try
{
JAXBContext context =
JAXBContext.newInstance(PermissionDescriptors.class);
Enumeration<URL> descirptorEnum =
getClassLoader().getResources(PERMISSION_DESCRIPTOR);
while (descirptorEnum.hasMoreElements())
{
URL descriptorUrl = descirptorEnum.nextElement();
logger.debug("read permission descriptor from {}", descriptorUrl);
builder.addAll(parsePermissionDescriptor(context, descriptorUrl));
}
}
catch (IOException ex)
{
logger.error("could not read permission descriptors", ex);
}
catch (JAXBException ex)
{
logger.error(
"could not create jaxb context to read permission descriptors", ex);
}
availablePermissions = builder.build();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
private ClassLoader getClassLoader()
{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null)
{
logger.warn("could not find context classloader, use default");
classLoader = DefaultSecuritySystem.class.getClassLoader();
}
return classLoader;
}
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 13/04/30
* @author Enter your name here...
*/
@XmlRootElement(name = "permissions")
@XmlAccessorType(XmlAccessType.FIELD)
private static class PermissionDescriptors
{
/**
* Constructs ...
*
*/
public PermissionDescriptors() {}
//~--- get methods --------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public List<PermissionDescriptor> getPermissions()
{
if (permissions == null)
{
permissions = Collections.EMPTY_LIST;
}
return permissions;
}
//~--- fields -------------------------------------------------------------
/** Field description */
@XmlElement(name = "permission")
private List<PermissionDescriptor> permissions;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final ConfigurationEntryStore<AssignedPermission> store;
/** Field description */
private List<PermissionDescriptor> availablePermissions;
}

View File

@@ -36,6 +36,7 @@ package sonia.scm.security;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.eventbus.Subscribe; import com.google.common.eventbus.Subscribe;
@@ -128,6 +129,7 @@ public class ScmRealm extends AuthorizingRealm
* *
* *
* @param configuration * @param configuration
* @param securitySystem
* @param cacheManager * @param cacheManager
* @param userManager * @param userManager
* @param groupManager * @param groupManager
@@ -139,7 +141,8 @@ public class ScmRealm extends AuthorizingRealm
* @param responseProvider * @param responseProvider
*/ */
@Inject @Inject
public ScmRealm(ScmConfiguration configuration, CacheManager cacheManager, public ScmRealm(ScmConfiguration configuration,
SecuritySystem securitySystem, CacheManager cacheManager,
UserManager userManager, GroupManager groupManager, UserManager userManager, GroupManager groupManager,
RepositoryDAO repositoryDAO, UserDAO userDAO, RepositoryDAO repositoryDAO, UserDAO userDAO,
AuthenticationManager authenticator, RepositoryManager manager, AuthenticationManager authenticator, RepositoryManager manager,
@@ -147,6 +150,7 @@ public class ScmRealm extends AuthorizingRealm
Provider<HttpServletResponse> responseProvider) Provider<HttpServletResponse> responseProvider)
{ {
this.configuration = configuration; this.configuration = configuration;
this.securitySystem = securitySystem;
this.userManager = userManager; this.userManager = userManager;
this.groupManager = groupManager; this.groupManager = groupManager;
this.repositoryDAO = repositoryDAO; this.repositoryDAO = repositoryDAO;
@@ -194,6 +198,27 @@ public class ScmRealm extends AuthorizingRealm
} }
} }
/**
* Method description
*
*
* @param event
*/
@Subscribe
public void onEvent(StoredAssignedPermissionEvent event)
{
if (event.getEventType().isPost())
{
if (logger.isDebugEnabled())
{
logger.debug("clear cache, because permission {} has changed",
event.getPermission().getId());
}
cache.clear();
}
}
/** /**
* Method description * Method description
* *
@@ -474,6 +499,51 @@ public class ScmRealm extends AuthorizingRealm
} }
} }
/**
* Method description
*
*
* @param user
* @param groups
*
* @return
*/
private List<String> collectGlobalPermissions(final User user,
final GroupNames groups)
{
if (logger.isTraceEnabled())
{
logger.trace("collect global permissions for user {}", user.getName());
}
List<String> permissions = Lists.newArrayList();
List<StoredAssignedPermission> globalPermissions =
securitySystem.getPermissions(new Predicate<AssignedPermission>()
{
@Override
public boolean apply(AssignedPermission input)
{
return isUserPermission(user, groups, input);
}
});
for (StoredAssignedPermission gp : globalPermissions)
{
if (logger.isTraceEnabled())
{
logger.trace("add permission {} for user {}", gp.getPermission(),
user.getName());
}
permissions.add(gp.getPermission());
}
return permissions;
}
/** /**
* Method description * Method description
* *
@@ -585,7 +655,8 @@ public class ScmRealm extends AuthorizingRealm
GroupNames groups) GroupNames groups)
{ {
Set<String> roles = Sets.newHashSet(); Set<String> roles = Sets.newHashSet();
List<org.apache.shiro.authz.Permission> permissions = null; List<org.apache.shiro.authz.Permission> permissions;
List<String> globalPermissions = null;
roles.add(Role.USER); roles.add(Role.USER);
@@ -604,12 +675,18 @@ public class ScmRealm extends AuthorizingRealm
else else
{ {
permissions = collectRepositoryPermissions(user, groups); permissions = collectRepositoryPermissions(user, groups);
globalPermissions = collectGlobalPermissions(user, groups);
} }
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
info.addObjectPermissions(permissions); info.addObjectPermissions(permissions);
if (globalPermissions != null)
{
info.addStringPermissions(globalPermissions);
}
return info; return info;
} }
@@ -737,7 +814,7 @@ public class ScmRealm extends AuthorizingRealm
* @return * @return
*/ */
private boolean isUserPermission(User user, GroupNames groups, private boolean isUserPermission(User user, GroupNames groups,
Permission perm) PermissionObject perm)
{ {
//J- //J-
return (perm.isGroupPermission() && groups.contains(perm.getName())) return (perm.isGroupPermission() && groups.contains(perm.getName()))
@@ -768,6 +845,9 @@ public class ScmRealm extends AuthorizingRealm
/** Field description */ /** Field description */
private Provider<HttpServletResponse> responseProvider; private Provider<HttpServletResponse> responseProvider;
/** Field description */
private SecuritySystem securitySystem;
/** Field description */ /** Field description */
private UserDAO userDAO; private UserDAO userDAO;

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--*
Copyright (c) 2010, Sebastian Sdorra
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of SCM-Manager; nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
http://bitbucket.org/sdorra/scm-manager
-->
<permissions>
<permission>
<display-name>All Repository (read)</display-name>
<description>Read access to all repositories</description>
<value>repository:*:READ</value>
</permission>
<permission>
<display-name>All Repository (write)</display-name>
<description>Write access to all repositories</description>
<value>repository:*:WRITE</value>
</permission>
<permission>
<display-name>All Repository (owner)</display-name>
<description>Owner access to all repositories</description>
<value>repository:*:OWNER</value>
</permission>
</permissions>

View File

@@ -143,6 +143,10 @@
<script type="text/javascript" src="resources/js/group/sonia.group.memberformpanel.js"></script> <script type="text/javascript" src="resources/js/group/sonia.group.memberformpanel.js"></script>
<script type="text/javascript" src="resources/js/group/sonia.group.panel.js"></script> <script type="text/javascript" src="resources/js/group/sonia.group.panel.js"></script>
<!-- sonia.security -->
<script type="text/javascript" src="resources/js/security/sonia.security.js"></script>
<script type="text/javascript" src="resources/js/security/sonia.security.permissionspanel.js"></script>
<!-- sonia.config --> <!-- sonia.config -->
<script type="text/javascript" src="resources/js/config/sonia.config.js"></script> <script type="text/javascript" src="resources/js/config/sonia.config.js"></script>
<script type="text/javascript" src="resources/js/config/sonia.config.configpanel.js"></script> <script type="text/javascript" src="resources/js/config/sonia.config.configpanel.js"></script>

View File

@@ -47,7 +47,7 @@ Sonia.group.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
initComponent: function(){ initComponent: function(){
this.addEvents('preCreate', 'created', 'preUpdate', 'updated', 'updateFailed', 'creationFailed'); this.addEvents('preCreate', 'created', 'preUpdate', 'updated', 'updateFailed', 'creationFailed');
Sonia.repository.FormPanel.superclass.initComponent.apply(this, arguments); Sonia.group.FormPanel.superclass.initComponent.apply(this, arguments);
}, },
update: function(group){ update: function(group){

View File

@@ -105,7 +105,7 @@ Sonia.group.Grid = Ext.extend(Sonia.rest.Grid, {
renderMembers: function(members){ renderMembers: function(members){
var out = ''; var out = '';
if ( members != null ){ if ( members !== null ){
var s = members.length; var s = members.length;
for ( var i=0; i<s; i++ ){ for ( var i=0; i<s; i++ ){
out += members[i]; out += members[i];
@@ -151,6 +151,9 @@ Sonia.group.Grid = Ext.extend(Sonia.rest.Grid, {
scope: this scope: this
} }
} }
},{
xtype: 'permissionsPanel',
baseUrl: 'security/permission/group/' + group.name
}]); }]);
} }

View File

@@ -39,7 +39,7 @@ Sonia.group.setEditPanel = function(panels){
}); });
editPanel.setActiveTab(0); editPanel.setActiveTab(0);
editPanel.doLayout(); editPanel.doLayout();
} };
/** /**
* panels * panels
@@ -51,4 +51,4 @@ Sonia.group.DefaultPanel = {
bodyCssClass: 'x-panel-mc', bodyCssClass: 'x-panel-mc',
padding: 5, padding: 5,
html: 'Add or select a Group' html: 'Add or select a Group'
} };

View File

@@ -69,9 +69,9 @@ Sonia.group.MemberFormPanel = Ext.extend(Sonia.group.FormPanel, {
singleSelect: true singleSelect: true
}); });
if ( this.item != null ){ if ( this.item !== null ){
var data = []; var data = [];
if ( this.item.members != null ){ if ( this.item.members !== null ){
for ( var i=0; i<this.item.members.length; i++ ){ for ( var i=0; i<this.item.members.length; i++ ){
var a = []; var a = [];
a.push( this.item.members[i] ); a.push( this.item.members[i] );

View File

@@ -50,27 +50,26 @@ Sonia.group.Panel = Ext.extend(Sonia.rest.Panel, {
{xtype: 'tbbutton', text: this.reloadText, icon: this.reloadIcon, scope: this, handler: this.reload} {xtype: 'tbbutton', text: this.reloadText, icon: this.reloadIcon, scope: this, handler: this.reload}
], ],
items: [{ items: [{
id: 'groupGrid', id: 'groupGrid',
xtype: 'groupGrid', xtype: 'groupGrid',
region: 'center', region: 'center',
parentPanel: this parentPanel: this
}, { }, {
id: 'groupEditPanel', id: 'groupEditPanel',
xtype: 'tabpanel', xtype: 'tabpanel',
activeTab: 0, activeTab: 0,
height: 250, height: 250,
split: true, split: true,
border: true, border: true,
region: 'south', region: 'south',
items: [{ items: [{
bodyCssClass: 'x-panel-mc', bodyCssClass: 'x-panel-mc',
title: this.titleText, title: this.titleText,
padding: 5, padding: 5,
html: this.emptyText html: this.emptyText
}] }]
} }]
] };
}
Ext.apply(this, Ext.apply(this.initialConfig, config)); Ext.apply(this, Ext.apply(this.initialConfig, config));
Sonia.group.Panel.superclass.initComponent.apply(this, arguments); Sonia.group.Panel.superclass.initComponent.apply(this, arguments);
@@ -104,7 +103,7 @@ Sonia.group.Panel = Ext.extend(Sonia.rest.Panel, {
buttons: Ext.MessageBox.OKCANCEL, buttons: Ext.MessageBox.OKCANCEL,
icon: Ext.MessageBox.QUESTION, icon: Ext.MessageBox.QUESTION,
fn: function(result){ fn: function(result){
if ( result == 'ok' ){ if ( result === 'ok' ){
if ( debug ){ if ( debug ){
console.debug( 'remove group ' + item.name ); console.debug( 'remove group ' + item.name );

View File

@@ -38,7 +38,7 @@ Sonia.group.PropertiesFormPanel = Ext.extend(Sonia.group.FormPanel, {
fieldLabel: this.nameText, fieldLabel: this.nameText,
name: 'name', name: 'name',
allowBlank: false, allowBlank: false,
readOnly: this.item != null, readOnly: this.item !== null,
helpText: this.nameHelpText, helpText: this.nameHelpText,
vtype: 'name' vtype: 'name'
},{ },{
@@ -47,7 +47,7 @@ Sonia.group.PropertiesFormPanel = Ext.extend(Sonia.group.FormPanel, {
xtype: 'textarea', xtype: 'textarea',
helpText: this.descriptionHelpText helpText: this.descriptionHelpText
}] }]
} };
Ext.apply(this, Ext.apply(this.initialConfig, config)); Ext.apply(this, Ext.apply(this.initialConfig, config));
Sonia.group.PropertiesFormPanel.superclass.initComponent.apply(this, arguments); Sonia.group.PropertiesFormPanel.superclass.initComponent.apply(this, arguments);

View File

@@ -56,12 +56,12 @@ Sonia.rest.FormPanel = Ext.extend(Ext.FormPanel,{
{text: this.okText, formBind: true, scope: this, handler: this.submit}, {text: this.okText, formBind: true, scope: this, handler: this.submit},
{text: this.cancelText, scope: this, handler: this.cancel} {text: this.cancelText, scope: this, handler: this.cancel}
] ]
} };
Ext.apply(this, Ext.apply(this.initialConfig, config)); Ext.apply(this, Ext.apply(this.initialConfig, config));
Sonia.rest.FormPanel.superclass.initComponent.apply(this, arguments); Sonia.rest.FormPanel.superclass.initComponent.apply(this, arguments);
if ( this.item != null ){ if ( this.item !== null ){
this.loadData(this.item); this.loadData(this.item);
} }
}, },
@@ -77,7 +77,7 @@ Sonia.rest.FormPanel = Ext.extend(Ext.FormPanel,{
console.debug( 'form submitted' ); console.debug( 'form submitted' );
} }
var item = this.getForm().getFieldValues(); var item = this.getForm().getFieldValues();
if ( this.item != null ){ if ( this.item !== null ){
this.update(item); this.update(item);
} else { } else {
this.create(item); this.create(item);

View File

@@ -39,6 +39,7 @@ Sonia.rest.Panel = Ext.extend(Ext.Panel, {
addIcon: 'resources/images/add.png', addIcon: 'resources/images/add.png',
removeIcon: 'resources/images/delete.png', removeIcon: 'resources/images/delete.png',
reloadIcon: 'resources/images/reload.png', reloadIcon: 'resources/images/reload.png',
helpIcon: 'resources/images/help.png',
initComponent: function(){ initComponent: function(){
@@ -48,7 +49,7 @@ Sonia.rest.Panel = Ext.extend(Ext.Panel, {
enableTabScroll: true, enableTabScroll: true,
region:'center', region:'center',
autoScroll: true autoScroll: true
} };
Ext.apply(this, Ext.apply(this.initialConfig, config)); Ext.apply(this, Ext.apply(this.initialConfig, config));
Sonia.rest.Panel.superclass.initComponent.apply(this, arguments); Sonia.rest.Panel.superclass.initComponent.apply(this, arguments);

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
// register namespace
Ext.ns('Sonia.security');

View File

@@ -0,0 +1,235 @@
/*
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of SCM-Manager; nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
Sonia.security.PermissionsPanel = Ext.extend(Ext.Panel, {
addText: 'Add',
removeText: 'Remove',
reloadText: 'Reload',
// icons
addIcon: 'resources/images/add.png',
removeIcon: 'resources/images/delete.png',
reloadIcon: 'resources/images/reload.png',
helpIcon: 'resources/images/help.png',
//TODO i18n
titleText: 'Permissions',
permissionStore: null,
baseUrl: null,
initComponent: function(){
this.permissionStore = new Sonia.rest.JsonStore({
proxy: new Ext.data.HttpProxy({
api: {
read: restUrl + this.baseUrl + '.json'
},
disableCaching: false
}),
idProperty: 'id',
fields: [ 'id', 'value'],
listeners: {
update: {
fn: this.modifyOrAddPermission,
scope: this
},
remove: {
fn: this.removePermission,
scope: this
}
}
});
var availablePermissionStore = new Ext.data.JsonStore({
fields: ['display-name', 'description', 'value'],
sortInfo: {
field: 'display-name'
}
});
availablePermissionStore.loadData(state.availablePermissions);
var permissionColModel = new Ext.grid.ColumnModel({
columns: [{
id: 'value',
header: 'Permission',
dataIndex: 'value',
renderer: this.renderPermission,
editor: new Ext.form.ComboBox({
store: availablePermissionStore,
displayField: 'display-name',
valueField: 'value',
typeAhead: false,
editable: false,
triggerAction: 'all',
mode: 'local',
width: 250
})
}]
});
var selectionModel = new Ext.grid.RowSelectionModel({
singleSelect: true
});
var config = {
title: this.titleText,
bodyCssClass: 'x-panel-mc',
padding: 5,
items: [{
id: 'permissionGrid',
xtype: 'editorgrid',
clicksToEdit: 1,
frame: true,
width: '100%',
autoHeight: true,
autoScroll: false,
colModel: permissionColModel,
sm: selectionModel,
store: this.permissionStore,
viewConfig: {
forceFit: true,
markDirty: false
},
tbar: [{
text: this.addText,
scope: this,
icon: this.addIcon,
handler : function(){
var Permission = this.permissionStore.recordType;
var grid = Ext.getCmp('permissionGrid');
grid.stopEditing();
this.permissionStore.insert(0, new Permission());
grid.startEditing(0, 0);
}
},{
text: this.removeText,
scope: this,
icon: this.removeIcon,
handler: function(){
var grid = Ext.getCmp('permissionGrid');
var selected = grid.getSelectionModel().getSelected();
if ( selected ){
this.permissionStore.remove(selected);
}
}
},'->',{
id: 'permissionGridHelp',
xtype: 'box',
autoEl: {
tag: 'img',
src: this.helpIcon
}
}]
}]
};
Ext.apply(this, Ext.apply(this.initialConfig, config));
Sonia.security.PermissionsPanel.superclass.initComponent.apply(this, arguments);
},
getIdFromResponse: function(response){
var id = null;
var location = response.getResponseHeader('Location');
if (location){
var parts = location.split('/');
id = parts[parts.length - 1];
}
return id;
},
modifyOrAddPermission: function(store, record){
var id = record.get('id');
if ( id ){
this.modifyPermission(id, record);
} else {
this.addPermission(record);
}
},
addPermission: function(record){
Ext.Ajax.request({
url: restUrl + this.baseUrl + '.json',
method: 'POST',
jsonData: record.data,
scope: this,
success: function(response){
var id = this.getIdFromResponse(response);
record.data.id = id;
},
failure: function(result){
}
});
},
modifyPermission: function(id, record){
Ext.Ajax.request({
url: restUrl + this.baseUrl + '/' + id + '.json',
method: 'PUT',
jsonData: record.data,
scope: this,
success: function(){
},
failure: function(result){
}
});
},
removePermission: function(store, record){
Ext.Ajax.request({
url: restUrl + this.baseUrl + '/' + record.get('id') + '.json',
method: 'DELETE',
scope: this,
success: function(){
},
failure: function(result){
}
});
},
renderPermission: function(value){
var ap = state.availablePermissions;
for (var i=0; i<ap.length; i++){
if ( value === ap[i].value ){
value = ap[i]['display-name'];
break;
}
}
return value;
}
});
// register xtype
Ext.reg('permissionsPanel', Sonia.security.PermissionsPanel);

View File

@@ -236,8 +236,7 @@ Sonia.scm.Main = Ext.extend(Ext.util.Observable, {
label: this.navUsersText, label: this.navUsersText,
fn: this.addUsersTabPanel, fn: this.addUsersTabPanel,
scope: this scope: this
}); },{
securitySection.links.push({
label: this.navGroupsText, label: this.navGroupsText,
fn: this.addGroupsTabPanel, fn: this.addGroupsTabPanel,
scope: this scope: this

View File

@@ -57,7 +57,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
fieldLabel: this.nameText, fieldLabel: this.nameText,
name: 'name', name: 'name',
allowBlank: false, allowBlank: false,
readOnly: this.item != null, readOnly: this.item !== null,
helpText: this.usernameHelpText, helpText: this.usernameHelpText,
vtype: 'username' vtype: 'username'
},{ },{
@@ -75,7 +75,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
helpText: this.mailHelpText helpText: this.mailHelpText
}]; }];
if ( this.item == null || this.item.type == state.defaultUserType ){ if ( this.item === null || this.item.type === state.defaultUserType ){
items.push({ items.push({
fieldLabel: this.passwordText, fieldLabel: this.passwordText,
id: 'pwd', id: 'pwd',
@@ -115,7 +115,7 @@ Sonia.user.FormPanel = Ext.extend(Sonia.rest.FormPanel,{
}, },
isReadOnly: function(){ isReadOnly: function(){
return this.item != null && this.item.type != state.defaultUserType; return this.item !== null && this.item.type !== state.defaultUserType;
}, },
fixRequest: function(user){ fixRequest: function(user){

View File

@@ -128,13 +128,16 @@ Sonia.user.Grid = Ext.extend(Sonia.rest.Grid, {
scope: this scope: this
} }
}); });
if ( item.type == state.defaultUserType ){ if ( item.type === state.defaultUserType ){
panel.getForm().setValues([ panel.getForm().setValues([
{id: 'password', value: dummyPassword}, {id: 'password', value: dummyPassword},
{id: 'password-confirm', value: dummyPassword} {id: 'password-confirm', value: dummyPassword}
]); ]);
} }
Sonia.user.setEditPanel(panel); Sonia.user.setEditPanel([panel,{
xtype: 'permissionsPanel',
baseUrl: 'security/permission/user/' + item.name
}]);
} }
}); });

View File

@@ -34,12 +34,15 @@ Ext.ns('Sonia.user');
// functions // functions
Sonia.user.setEditPanel = function(panel){ Sonia.user.setEditPanel = function(panels){
var editPanel = Ext.getCmp('userEditPanel'); var editPanel = Ext.getCmp('userEditPanel');
editPanel.removeAll(); editPanel.removeAll();
editPanel.add(panel); Ext.each(panels, function(panel){
editPanel.add(panel);
});
editPanel.setActiveTab(0);
editPanel.doLayout(); editPanel.doLayout();
} };
/** /**
* Panels * Panels
@@ -49,6 +52,7 @@ Sonia.user.DefaultPanel = {
title: 'User Form', title: 'User Form',
padding: 5, padding: 5,
xtype: 'panel', xtype: 'panel',
bodyCssClass: 'x-panel-mc',
html: 'Add or select an User' html: 'Add or select an User'
}; };

View File

@@ -43,9 +43,7 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, {
userGrid: null, userGrid: null,
initComponent: function(){ initComponent: function(){
var config = { var config = {
bodyCssClass: 'x-panel-mc',
tbar: [ tbar: [
{xtype: 'tbbutton', text: this.addText, icon: this.addIcon, scope: this, handler: this.showAddPanel}, {xtype: 'tbbutton', text: this.addText, icon: this.addIcon, scope: this, handler: this.showAddPanel},
{xtype: 'tbbutton', text: this.removeText, icon: this.removeIcon, scope: this, handler: this.removeUser}, {xtype: 'tbbutton', text: this.removeText, icon: this.removeIcon, scope: this, handler: this.removeUser},
@@ -61,20 +59,20 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, {
xtype: 'userGrid', xtype: 'userGrid',
region: 'center', region: 'center',
parentPanel: this parentPanel: this
},{ }, {
id: 'userEditPanel', id: 'userEditPanel',
layout: 'fit', xtype: 'tabpanel',
items: [{ activeTab: 0,
region: 'south',
title: 'User Form',
xtype: 'panel',
padding: 5,
html: this.emptyText
}],
height: 250, height: 250,
split: true, split: true,
border: false, border: true,
region: 'south' region: 'south',
items: [{
bodyCssClass: 'x-panel-mc',
title: 'User Form',
padding: 5,
html: this.emptyText
}]
}] }]
}; };
@@ -103,10 +101,8 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, {
}, },
showAddPanel: function(){ showAddPanel: function(){
var editPanel = Ext.getCmp('userEditPanel'); Sonia.user.setEditPanel({
editPanel.removeAll(); xtype: 'userForm',
var panel = new Sonia.user.FormPanel({
region: 'south',
title: this.titleText, title: this.titleText,
padding: 5, padding: 5,
onUpdate: { onUpdate: {
@@ -118,8 +114,6 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, {
scope: this scope: this
} }
}); });
editPanel.add(panel);
editPanel.doLayout();
}, },
resetPanel: function(){ resetPanel: function(){
@@ -140,7 +134,7 @@ Sonia.user.Panel = Ext.extend(Sonia.rest.Panel, {
buttons: Ext.MessageBox.OKCANCEL, buttons: Ext.MessageBox.OKCANCEL,
icon: Ext.MessageBox.QUESTION, icon: Ext.MessageBox.QUESTION,
fn: function(result){ fn: function(result){
if ( result == 'ok' ){ if ( result === 'ok' ){
if ( debug ){ if ( debug ){
console.debug( 'remove user ' + item.name ); console.debug( 'remove user ' + item.name );

View File

@@ -0,0 +1,333 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Predicate;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.junit.Before;
import org.junit.Test;
import sonia.scm.AbstractTestBase;
import sonia.scm.store.JAXBConfigurationEntryStoreFactory;
import sonia.scm.util.MockUtil;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.util.List;
/**
*
* @author Sebastian Sdorra
*/
public class DefaultSecuritySystemTest extends AbstractTestBase
{
/**
* Method description
*
*/
@Before
public void createSecuritySystem()
{
JAXBConfigurationEntryStoreFactory factory =
new JAXBConfigurationEntryStoreFactory(new UUIDKeyGenerator(),
contextProvider);
securitySystem = new DefaultSecuritySystem(factory);
// ScmEventBus.getInstance().register(listener);
}
/**
* Method description
*
*/
@Test
public void testAddPermission()
{
setAdminSubject();
StoredAssignedPermission sap = createPermission("trillian", false,
"repository:*:READ");
assertEquals("trillian", sap.getName());
assertEquals("repository:*:READ", sap.getPermission());
assertEquals(false, sap.isGroupPermission());
}
/**
* Method description
*
*/
@Test
public void testAvailablePermissions()
{
setAdminSubject();
List<PermissionDescriptor> list = securitySystem.getAvailablePermissions();
assertNotNull(list);
assertThat(list.size(), greaterThan(0));
}
/**
* Method description
*
*/
@Test
public void testDeletePermission()
{
setAdminSubject();
StoredAssignedPermission sap = createPermission("trillian", false,
"repository:*:READ");
securitySystem.deletePermission(sap);
assertNull(securitySystem.getPermission(sap.getId()));
}
/**
* Method description
*
*/
@Test
public void testGetAllPermissions()
{
setAdminSubject();
StoredAssignedPermission trillian = createPermission("trillian", false,
"repository:*:READ");
StoredAssignedPermission dent = createPermission("dent", false,
"repository:*:READ");
StoredAssignedPermission marvin = createPermission("marvin", false,
"repository:*:READ");
List<StoredAssignedPermission> all = securitySystem.getAllPermissions();
assertEquals(3, all.size());
assertThat(all, containsInAnyOrder(trillian, dent, marvin));
}
/**
* Method description
*
*/
@Test
public void testGetPermission()
{
setAdminSubject();
StoredAssignedPermission sap = createPermission("trillian", false,
"repository:*:READ");
StoredAssignedPermission other = securitySystem.getPermission(sap.getId());
assertEquals(sap.getId(), other.getId());
assertEquals(sap, other);
}
/**
* Method description
*
*/
@Test
public void testGetPermissionsWithPredicate()
{
setAdminSubject();
StoredAssignedPermission trillian = createPermission("trillian", false,
"repository:*:READ");
StoredAssignedPermission dent = createPermission("dent", false,
"repository:*:READ");
createPermission("hitchhiker", true, "repository:*:READ");
List<StoredAssignedPermission> filtered =
securitySystem.getPermissions(new Predicate<AssignedPermission>()
{
@Override
public boolean apply(AssignedPermission input)
{
return !input.isGroupPermission();
}
});
assertEquals(2, filtered.size());
assertThat(filtered, containsInAnyOrder(trillian, dent));
}
/**
* Method description
*
*/
@Test
public void testModifyPermission()
{
setAdminSubject();
StoredAssignedPermission sap = createPermission("trillian", false,
"repository:*:READ");
StoredAssignedPermission modified =
new StoredAssignedPermission(sap.getId(),
new AssignedPermission("trillian", "repository:*:WRITE"));
securitySystem.modifyPermission(modified);
sap = securitySystem.getPermission(modified.getId());
assertEquals(modified.getId(), sap.getId());
assertEquals(modified, sap);
}
/**
* Method description
*
*/
@Test(expected = UnauthorizedException.class)
public void testUnauthorizedAddPermission()
{
setUserSubject();
createPermission("trillian", false, "repository:*:READ");
}
/**
* Method description
*
*/
@Test(expected = UnauthorizedException.class)
public void testUnauthorizedDeletePermission()
{
setAdminSubject();
StoredAssignedPermission sap = createPermission("trillian", false,
"repository:*:READ");
setUserSubject();
securitySystem.deletePermission(sap);
}
/**
* Method description
*
*/
@Test(expected = UnauthorizedException.class)
public void testUnauthorizedGetPermission()
{
setAdminSubject();
StoredAssignedPermission sap = createPermission("trillian", false,
"repository:*:READ");
setUserSubject();
securitySystem.getPermission(sap.getId());
}
/**
* Method description
*
*/
@Test(expected = UnauthorizedException.class)
public void testUnauthorizedModifyPermission()
{
setAdminSubject();
StoredAssignedPermission sap = createPermission("trillian", false,
"repository:*:READ");
setUserSubject();
securitySystem.modifyPermission(sap);
}
/**
* Method description
*
*
* @param name
* @param groupPermission
* @param value
*
* @return
*/
private StoredAssignedPermission createPermission(String name,
boolean groupPermission, String value)
{
AssignedPermission ap = new AssignedPermission(name, groupPermission,
value);
StoredAssignedPermission sap = securitySystem.addPermission(ap);
assertNotNull(sap);
assertNotNull(sap.getId());
return sap;
}
//~--- set methods ----------------------------------------------------------
/**
* Method description
*
*/
private void setAdminSubject()
{
setSubject(MockUtil.createAdminSubject());
}
/**
* Method description
*
*/
private void setUserSubject()
{
org.apache.shiro.mgt.SecurityManager sm =
new DefaultSecurityManager(new SimpleAccountRealm());
setSubject(MockUtil.createUserSubject(sm));
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private DefaultSecuritySystem securitySystem;
}

View File

@@ -35,6 +35,7 @@ package sonia.scm.security;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -50,6 +51,8 @@ import org.apache.shiro.subject.PrincipalCollection;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito;
import sonia.scm.cache.MapCacheManager; import sonia.scm.cache.MapCacheManager;
import sonia.scm.config.ScmConfiguration; import sonia.scm.config.ScmConfiguration;
import sonia.scm.group.Group; import sonia.scm.group.Group;
@@ -76,6 +79,7 @@ import static org.mockito.Mockito.*;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@@ -464,9 +468,16 @@ public class ScmRealmTest
AuthenticationResult.NOT_FOUND AuthenticationResult.NOT_FOUND
); );
SecuritySystem securitySystem = mock(SecuritySystem.class);
when(
securitySystem.getPermissions(Mockito.<Predicate>any())
).thenReturn(
Collections.EMPTY_LIST
);
return new ScmRealm( return new ScmRealm(
new ScmConfiguration(), new ScmConfiguration(),
securitySystem,
new MapCacheManager(), new MapCacheManager(),
userManager, userManager,
groupManager, groupManager,