Cleanup security system

- remove probably unused methods
- use sets instead of lists
- remove old REST resource
This commit is contained in:
René Pfeuffer
2019-01-16 14:19:11 +01:00
parent ada764fd8b
commit f1692aa1c7
16 changed files with 105 additions and 905 deletions

View File

@@ -85,7 +85,7 @@ public final class ScmState
public ScmState(String version, User user, Collection<String> groups, public ScmState(String version, User user, Collection<String> groups,
String token, Collection<RepositoryType> repositoryTypes, String defaultUserType, String token, Collection<RepositoryType> repositoryTypes, String defaultUserType,
ScmClientConfig clientConfig, List<String> assignedPermission, ScmClientConfig clientConfig, List<String> assignedPermission,
List<PermissionDescriptor> availablePermissions) Collection<PermissionDescriptor> availablePermissions)
{ {
this.version = version; this.version = version;
this.user = user; this.user = user;
@@ -119,7 +119,7 @@ public final class ScmState
* @return available global permissions * @return available global permissions
* @since 1.31 * @since 1.31
*/ */
public List<PermissionDescriptor> getAvailablePermissions() public Collection<PermissionDescriptor> getAvailablePermissions()
{ {
return availablePermissions; return availablePermissions;
} }
@@ -232,7 +232,7 @@ public final class ScmState
* Avaliable global permission * Avaliable global permission
* @since 1.31 * @since 1.31
*/ */
private List<PermissionDescriptor> availablePermissions; private Collection<PermissionDescriptor> availablePermissions;
/** Field description */ /** Field description */
private ScmClientConfig clientConfig; private ScmClientConfig clientConfig;

View File

@@ -134,7 +134,7 @@ public final class ScmStateFactory
User user = collection.oneByType(User.class); User user = collection.oneByType(User.class);
GroupNames groups = collection.oneByType(GroupNames.class); GroupNames groups = collection.oneByType(GroupNames.class);
List<PermissionDescriptor> ap = Collections.EMPTY_LIST; Collection<PermissionDescriptor> ap = Collections.EMPTY_LIST;
if (subject.hasRole(Role.ADMIN)) if (subject.hasRole(Role.ADMIN))
{ {
@@ -150,7 +150,7 @@ public final class ScmStateFactory
private ScmState createState(User user, Collection<String> groups, private ScmState createState(User user, Collection<String> groups,
String token, List<String> assignedPermissions, String token, List<String> assignedPermissions,
List<PermissionDescriptor> availablePermissions) Collection<PermissionDescriptor> availablePermissions)
{ {
User u = user.clone(); User u = user.clone();

View File

@@ -67,19 +67,8 @@ public class PermissionDescriptor implements Serializable
*/ */
public PermissionDescriptor() {} public PermissionDescriptor() {}
/** public PermissionDescriptor(String value)
* Constructs ...
*
*
* @param displayName
* @param description
* @param value
*/
public PermissionDescriptor(String displayName, String description,
String value)
{ {
this.displayName = displayName;
this.description = description;
this.value = value; this.value = value;
} }
@@ -103,9 +92,7 @@ public class PermissionDescriptor implements Serializable
final PermissionDescriptor other = (PermissionDescriptor) obj; final PermissionDescriptor other = (PermissionDescriptor) obj;
return Objects.equal(displayName, other.displayName) return Objects.equal(value, other.value);
&& Objects.equal(description, other.description)
&& Objects.equal(value, other.value);
} }
/** /**
@@ -114,7 +101,7 @@ public class PermissionDescriptor implements Serializable
@Override @Override
public int hashCode() public int hashCode()
{ {
return Objects.hashCode(displayName, description, value); return value.hashCode();
} }
/** /**
@@ -126,8 +113,6 @@ public class PermissionDescriptor implements Serializable
//J- //J-
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)
.add("displayName", displayName)
.add("description", description)
.add("value", value) .add("value", value)
.toString(); .toString();
@@ -136,28 +121,6 @@ public class PermissionDescriptor implements Serializable
//~--- get methods ---------------------------------------------------------- //~--- 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. * Returns the string representation of the permission.
* *
@@ -171,13 +134,6 @@ public class PermissionDescriptor implements Serializable
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** description */
private String description;
/** display name */
@XmlElement(name = "display-name")
private String displayName;
/** value */ /** value */
private String value; private String value;
} }

View File

@@ -38,6 +38,7 @@ import com.google.common.base.Predicate;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@@ -75,41 +76,15 @@ public interface SecuritySystem
*/ */
public void deletePermission(String id); public void deletePermission(String id);
/**
* Modify stored permission.
*
*
* @param permission stored permisison
*/
public void modifyPermission(StoredAssignedPermission permission);
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/**
* Return all stored permissions.
*
*
* @return stored permission
*/
public List<StoredAssignedPermission> getAllPermissions();
/** /**
* Return all available permissions. * Return all available permissions.
* *
* *
* @return available permissions * @return available permissions
*/ */
public List<PermissionDescriptor> getAvailablePermissions(); public Collection<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 * Returns all stored permissions which are matched by the given
@@ -120,6 +95,6 @@ public interface SecuritySystem
* *
* @return filtered permissions * @return filtered permissions
*/ */
public List<StoredAssignedPermission> getPermissions( public Collection<StoredAssignedPermission> getPermissions(
Predicate<AssignedPermission> predicate); Predicate<AssignedPermission> predicate);
} }

View File

@@ -1,298 +0,0 @@
/**
* 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 com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
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;
/**
* Abstract base class for global permission resources.
*
* @author Sebastian Sdorra
* @since 1.31
*/
public abstract class AbstractPermissionResource
{
/**
* Constructs a new {@link AbstractPermissionResource}.
*
*
* @param securitySystem security system
* @param name name of the user or group
*/
protected AbstractPermissionResource(SecuritySystem securitySystem,
String name)
{
this.securitySystem = securitySystem;
this.name = name;
}
//~--- methods --------------------------------------------------------------
/**
* Transforms a {@link Permission} to a {@link AssignedPermission}.
*
*
* @param permission permission object to transform
*
* @return transformed {@link AssignedPermission}
*/
protected abstract AssignedPermission transformPermission(
Permission permission);
//~--- get methods ----------------------------------------------------------
/**
* Returns a {@link Predicate} to filter permissions.
*
*
* @return {@link Predicate} to filter permissions
*/
protected abstract Predicate<AssignedPermission> getPredicate();
//~--- methods --------------------------------------------------------------
/**
* Adds a new permission to the user or group managed by the resource.
*
* @param uriInfo uri informations
* @param permission permission to add
*
* @return web response
*/
@POST
@StatusCodes({
@ResponseCode(code = 201, condition = "creates", additionalHeaders = {
@ResponseHeader(name = "Location", description = "uri to new create permission")
}),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(TypeHint.NO_CONTENT.class)
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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();
}
/**
* Deletes a permission from the user or group managed by the resource.
*
* @param id id of the permission
*
* @return web response
*/
@DELETE
@Path("{id}")
@StatusCodes({
@ResponseCode(code = 204, condition = "success"),
@ResponseCode(code = 400, condition = "bad request, permission id does not belong to the user or group"),
@ResponseCode(code = 404, condition = "not found, no permission with the specified id available"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(TypeHint.NO_CONTENT.class)
public Response delete(@PathParam("id") String id)
{
StoredAssignedPermission sap = getPermission(id);
securitySystem.deletePermission(sap);
return Response.noContent().build();
}
/**
* Updates the specified permission on the user or group managed by the resource.
*
* @param id id of the permission
* @param permission updated permission
*
* @return web response
*/
@PUT
@Path("{id}")
@StatusCodes({
@ResponseCode(code = 204, condition = "success"),
@ResponseCode(code = 400, condition = "bad request, permission id does not belong to the user or group"),
@ResponseCode(code = 404, condition = "not found, no permission with the specified id available"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(TypeHint.NO_CONTENT.class)
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
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 ----------------------------------------------------------
/**
* Returns the {@link Permission} with the specified id.
*
* @param id id of the {@link Permission}
*
* @return {@link Permission} with the specified id
*/
@GET
@Path("{id}")
@StatusCodes({
@ResponseCode(code = 204, condition = "success"),
@ResponseCode(code = 400, condition = "bad request, permission id does not belong to the user or group"),
@ResponseCode(code = 404, condition = "not found, no permission with the specified id available"),
@ResponseCode(code = 500, condition = "internal server error")
})
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Permission get(@PathParam("id") String id)
{
StoredAssignedPermission sap = getPermission(id);
return new Permission(sap.getId(), sap.getPermission());
}
/**
* Returns all permissions of the user or group managed by the resource.
*
* @return all permissions of the user or group
*/
@GET
@StatusCodes({
@ResponseCode(code = 204, condition = "success"),
@ResponseCode(code = 500, condition = "internal server error")
})
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List<Permission> getAll()
{
return getPermissions(getPredicate());
}
/**
* Returns the {@link StoredAssignedPermission} with the given id.
*
*
* @param id id of the stored permission
*
* @return {@link StoredAssignedPermission} with the given id
*/
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;
}
/**
* Returns all permissions which matches the given {@link Predicate}.
*
*
* @param predicate predicate for filtering
*
* @return all permissions which matches the given {@link Predicate}
*/
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 ---------------------------------------------------------------
/** name of the user or the group */
protected String name;
/** security system */
private SecuritySystem securitySystem;
}

View File

@@ -1,127 +0,0 @@
/**
* 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;
/**
* Resource to manage global group permission for a specified group.
*
* @author Sebastian Sdorra
* @since 1.31
*/
public class GroupPermissionResource extends AbstractPermissionResource
{
/**
* Constructs a new group permissions resource
*
*
* @param securitySystem security system
* @param name name of the group
*/
public GroupPermissionResource(SecuritySystem securitySystem, String name)
{
super(securitySystem, name);
}
//~--- methods --------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
protected AssignedPermission transformPermission(Permission permission)
{
return new AssignedPermission(name, true, permission.getValue());
}
//~--- get methods ----------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
protected Predicate<AssignedPermission> getPredicate()
{
return new GroupPredicate(name);
}
//~--- inner classes --------------------------------------------------------
/**
* Group predicate to filter permissions.
*/
private static class GroupPredicate implements Predicate<AssignedPermission>
{
/**
* Constructs a new group predicate
*
*
* @param name name of the group
*/
public GroupPredicate(String name)
{
this.name = name;
}
//~--- methods ------------------------------------------------------------
/**
* Returns true if the permission is a group permission and the name is
* equals.
*
* @param input permission
*
* @return true if the permission is a group permission and the name is
* equals
*/
@Override
public boolean apply(AssignedPermission input)
{
return input.isGroupPermission() && input.getName().equals(name);
}
//~--- fields -------------------------------------------------------------
/** name of the group */
private String name;
}
}

View File

@@ -1,106 +0,0 @@
/**
* 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;
/**
* Resource for managing system security permissions.
*
* @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 ----------------------------------------------------------
/**
* Returns group permission sub resource.
*
* @param group name of group
*
* @return sub resource
*/
@Path("group/{group}")
public GroupPermissionResource getGroupSubResource(@PathParam("group") String group)
{
return new GroupPermissionResource(system, group);
}
/**
* Returns user permission sub resource.
*
*
* @param user name of user
*
* @return sub resource
*/
@Path("user/{user}")
public UserPermissionResource getUserSubResource(@PathParam("user") String user)
{
return new UserPermissionResource(system, user);
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final SecuritySystem system;
}

View File

@@ -1,127 +0,0 @@
/**
* 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;
/**
* Resource to manage global user permission for a specified user.
*
* @author Sebastian Sdorra
* @since 1.31
*/
public class UserPermissionResource extends AbstractPermissionResource
{
/**
* Constructs a new user permission resource.
*
*
* @param securitySystem security system
* @param name name of the user
*/
public UserPermissionResource(SecuritySystem securitySystem, String name)
{
super(securitySystem, name);
}
//~--- methods --------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
protected AssignedPermission transformPermission(Permission permission)
{
return new AssignedPermission(name, permission.getValue());
}
//~--- get methods ----------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
protected Predicate<AssignedPermission> getPredicate()
{
return new UserPredicate(name);
}
//~--- inner classes --------------------------------------------------------
/**
* User predicate to filter permissions.
*/
private static class UserPredicate implements Predicate<AssignedPermission>
{
/**
* Constructs a new user predicate.
*
*
* @param name name of the user
*/
public UserPredicate(String name)
{
this.name = name;
}
//~--- methods ------------------------------------------------------------
/**
* Returns true if the permission is a user permission and the name is
* equals.
*
* @param input permission
*
* @return true if the permission is a user permission and the name is
* equals
*/
@Override
public boolean apply(AssignedPermission input)
{
return !input.isGroupPermission() && input.getName().equals(name);
}
//~--- fields -------------------------------------------------------------
/** name of the user */
private String name;
}
}

View File

@@ -2,12 +2,15 @@ package sonia.scm.api.v2.resources;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import sonia.scm.security.AssignedPermission; import sonia.scm.security.AssignedPermission;
import sonia.scm.security.PermissionDescriptor;
import sonia.scm.security.SecuritySystem; import sonia.scm.security.SecuritySystem;
import javax.inject.Inject; import javax.inject.Inject;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@@ -71,8 +74,6 @@ public class GlobalPermissionPocResource {
// Core: scm-webapp/src/main/resources/META-INF/scm/permissions.xml // Core: scm-webapp/src/main/resources/META-INF/scm/permissions.xml
// Plugins, e.g. scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/permissions.xml // Plugins, e.g. scm-plugins/scm-git-plugin/src/main/resources/META-INF/scm/permissions.xml
log.info("{} Available permissions: {}", securitySystem.getAvailablePermissions().size(), securitySystem.getAvailablePermissions()); log.info("{} Available permissions: {}", securitySystem.getAvailablePermissions().size(), securitySystem.getAvailablePermissions());
// Should contain all stored permissions. See assignExemplaryPermissions() for example.
log.info("{} All permissions: {}", securitySystem.getAllPermissions().size(), securitySystem.getAllPermissions());
assignExemplaryPermissions(); assignExemplaryPermissions();
@@ -80,12 +81,20 @@ public class GlobalPermissionPocResource {
return Response.noContent().build(); return Response.noContent().build();
} }
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("")
public Response getAll() {
String[] permissions = securitySystem.getAvailablePermissions().stream().map(PermissionDescriptor::getValue).toArray(String[]::new);
return Response.ok(new PerminssionListDto(permissions)).build();
}
protected void assignExemplaryPermissions() { protected void assignExemplaryPermissions() {
AssignedPermission groupPermission = new AssignedPermission("configurers", true,"configuration:*"); AssignedPermission groupPermission = new AssignedPermission("configurers", true,"configuration:*");
log.info("try to add new permission: {}", groupPermission); log.info("try to add new permission: {}", groupPermission);
securitySystem.addPermission(groupPermission); securitySystem.addPermission(groupPermission);
AssignedPermission userPermission = new AssignedPermission("arthur", "group:*"); AssignedPermission userPermission = new AssignedPermission("rene", "group:*");
log.info("try to add new permission: {}", userPermission); log.info("try to add new permission: {}", userPermission);
securitySystem.addPermission(userPermission); securitySystem.addPermission(userPermission);
} }

View File

@@ -0,0 +1,15 @@
package sonia.scm.api.v2.resources;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class PerminssionListDto {
private String[] permissions;
}

View File

@@ -4,12 +4,14 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes; import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint; import com.webcohesion.enunciate.metadata.rs.TypeHint;
import org.apache.shiro.authc.credential.PasswordService; import org.apache.shiro.authc.credential.PasswordService;
import sonia.scm.security.PermissionDescriptor;
import sonia.scm.security.SecuritySystem;
import sonia.scm.security.StoredAssignedPermission;
import sonia.scm.user.User; import sonia.scm.user.User;
import sonia.scm.user.UserManager; import sonia.scm.user.UserManager;
import sonia.scm.web.VndMediaType; import sonia.scm.web.VndMediaType;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import javax.validation.Valid; import javax.validation.Valid;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
@@ -28,14 +30,16 @@ public class UserResource {
private final IdResourceManagerAdapter<User, UserDto> adapter; private final IdResourceManagerAdapter<User, UserDto> adapter;
private final UserManager userManager; private final UserManager userManager;
private final PasswordService passwordService; private final PasswordService passwordService;
private final SecuritySystem securitySystem;
@Inject @Inject
public UserResource(UserDtoToUserMapper dtoToUserMapper, UserToUserDtoMapper userToDtoMapper, UserManager manager, PasswordService passwordService) { public UserResource(UserDtoToUserMapper dtoToUserMapper, UserToUserDtoMapper userToDtoMapper, UserManager manager, PasswordService passwordService, SecuritySystem securitySystem) {
this.dtoToUserMapper = dtoToUserMapper; this.dtoToUserMapper = dtoToUserMapper;
this.userToDtoMapper = userToDtoMapper; this.userToDtoMapper = userToDtoMapper;
this.adapter = new IdResourceManagerAdapter<>(manager, User.class); this.adapter = new IdResourceManagerAdapter<>(manager, User.class);
this.userManager = manager; this.userManager = manager;
this.passwordService = passwordService; this.passwordService = passwordService;
this.securitySystem = securitySystem;
} }
/** /**
@@ -132,4 +136,25 @@ public class UserResource {
userManager.overwritePassword(name, passwordService.encryptPassword(passwordOverwrite.getNewPassword())); userManager.overwritePassword(name, passwordService.encryptPassword(passwordOverwrite.getNewPassword()));
return Response.noContent().build(); return Response.noContent().build();
} }
/**
* Returns permissions for a user.
*
* @param id the id/name of the user
*/
@GET
@Path("permissions")
@Produces(VndMediaType.USER)
@TypeHint(UserDto.class)
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the user"),
@ResponseCode(code = 404, condition = "not found, no user with the specified id/name available"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response getPermissions(@PathParam("id") String id) {
String[] permissions = securitySystem.getPermissions(p -> !p.isGroupPermission() && p.getName().equals(id)).stream().map(StoredAssignedPermission::getPermission).toArray(String[]::new);
return Response.ok(new PerminssionListDto(permissions)).build();
}
} }

View File

@@ -175,7 +175,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
private void collectGlobalPermissions(Builder<String> builder, private void collectGlobalPermissions(Builder<String> builder,
final User user, final GroupNames groups) final User user, final GroupNames groups)
{ {
List<StoredAssignedPermission> globalPermissions = Collection<StoredAssignedPermission> globalPermissions =
securitySystem.getPermissions((AssignedPermission input) -> isUserPermitted(user, groups, input)); securitySystem.getPermissions((AssignedPermission input) -> isUserPermitted(user, groups, input));
for (StoredAssignedPermission gp : globalPermissions) for (StoredAssignedPermission gp : globalPermissions)

View File

@@ -39,8 +39,8 @@ import com.github.legman.Subscribe;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
@@ -62,6 +62,7 @@ import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
@@ -92,8 +93,6 @@ public class DefaultSecuritySystem implements SecuritySystem
private static final Logger logger = private static final Logger logger =
LoggerFactory.getLogger(DefaultSecuritySystem.class); LoggerFactory.getLogger(DefaultSecuritySystem.class);
private PluginLoader pluginLoader;
//~--- constructors --------------------------------------------------------- //~--- constructors ---------------------------------------------------------
/** /**
@@ -110,8 +109,7 @@ public class DefaultSecuritySystem implements SecuritySystem
.withType(AssignedPermission.class) .withType(AssignedPermission.class)
.withName(NAME) .withName(NAME)
.build(); .build();
this.pluginLoader = pluginLoader; this.availablePermissions = readAvailablePermissions(pluginLoader);
readAvailablePermissions();
} }
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -228,31 +226,6 @@ public class DefaultSecuritySystem implements SecuritySystem
} }
} }
/**
* Method description
*
*
* @param permission
*/
@Override
public void modifyPermission(StoredAssignedPermission permission)
{
assertIsAdmin();
validatePermission(permission);
synchronized (store)
{
store.remove(permission.getId());
store.put(permission.getId(), new AssignedPermission(permission));
}
//J-
ScmEventBus.getInstance().post(
new StoredAssignedPermissionEvent(HandlerEventType.CREATE, permission)
);
//J+
}
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/** /**
@@ -262,49 +235,13 @@ public class DefaultSecuritySystem implements SecuritySystem
* @return * @return
*/ */
@Override @Override
public List<StoredAssignedPermission> getAllPermissions() public Collection<PermissionDescriptor> getAvailablePermissions()
{
return getPermissions(null);
}
/**
* Method description
*
*
* @return
*/
@Override
public List<PermissionDescriptor> getAvailablePermissions()
{ {
assertIsAdmin(); assertIsAdmin();
return availablePermissions; 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 * Method description
* *
@@ -314,10 +251,9 @@ public class DefaultSecuritySystem implements SecuritySystem
* @return * @return
*/ */
@Override @Override
public List<StoredAssignedPermission> getPermissions( public Collection<StoredAssignedPermission> getPermissions(Predicate<AssignedPermission> predicate)
Predicate<AssignedPermission> predicate)
{ {
Builder<StoredAssignedPermission> permissions = ImmutableList.builder(); Builder<StoredAssignedPermission> permissions = ImmutableSet.builder();
for (Entry<String, AssignedPermission> e : store.getAll().entrySet()) for (Entry<String, AssignedPermission> e : store.getAll().entrySet())
{ {
@@ -349,7 +285,7 @@ public class DefaultSecuritySystem implements SecuritySystem
*/ */
private void deletePermissions(Predicate<AssignedPermission> predicate) private void deletePermissions(Predicate<AssignedPermission> predicate)
{ {
List<StoredAssignedPermission> permissions = getPermissions(predicate); Collection<StoredAssignedPermission> permissions = getPermissions(predicate);
for (StoredAssignedPermission permission : permissions) for (StoredAssignedPermission permission : permissions)
{ {
@@ -367,7 +303,7 @@ public class DefaultSecuritySystem implements SecuritySystem
* @return * @return
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private List<PermissionDescriptor> parsePermissionDescriptor( private static List<PermissionDescriptor> parsePermissionDescriptor(
JAXBContext context, URL descriptorUrl) JAXBContext context, URL descriptorUrl)
{ {
List<PermissionDescriptor> descriptors = Collections.EMPTY_LIST; List<PermissionDescriptor> descriptors = Collections.EMPTY_LIST;
@@ -395,10 +331,11 @@ public class DefaultSecuritySystem implements SecuritySystem
/** /**
* Method description * Method description
* *
* @param pluginLoader
*/ */
private void readAvailablePermissions() private static ImmutableSet<PermissionDescriptor> readAvailablePermissions(PluginLoader pluginLoader)
{ {
Builder<PermissionDescriptor> builder = ImmutableList.builder(); ImmutableSet.Builder<PermissionDescriptor> builder = ImmutableSet.builder();
try try
{ {
@@ -428,7 +365,7 @@ public class DefaultSecuritySystem implements SecuritySystem
"could not create jaxb context to read permission descriptors", ex); "could not create jaxb context to read permission descriptors", ex);
} }
availablePermissions = builder.build(); return builder.build();
} }
/** /**
@@ -455,12 +392,6 @@ public class DefaultSecuritySystem implements SecuritySystem
private static class PermissionDescriptors private static class PermissionDescriptors
{ {
/**
* Constructs ...
*
*/
public PermissionDescriptors() {}
//~--- get methods -------------------------------------------------------- //~--- get methods --------------------------------------------------------
/** /**
@@ -494,5 +425,5 @@ public class DefaultSecuritySystem implements SecuritySystem
private final ConfigurationEntryStore<AssignedPermission> store; private final ConfigurationEntryStore<AssignedPermission> store;
/** Field description */ /** Field description */
private List<PermissionDescriptor> availablePermissions; private final ImmutableSet<PermissionDescriptor> availablePermissions;
} }

View File

@@ -34,20 +34,14 @@
<permissions> <permissions>
<permission> <permission>
<display-name>All Repository (read)</display-name> <value>repository:read:*</value>
<description>Read access to all repositories</description>
<value>repository:*:READ</value>
</permission> </permission>
<permission> <permission>
<display-name>All Repository (write)</display-name>
<description>Write access to all repositories</description>
<value>repository:*:WRITE</value> <value>repository:*:WRITE</value>
</permission> </permission>
<permission> <permission>
<display-name>All Repository (owner)</display-name>
<description>Owner access to all repositories</description>
<value>repository:*:OWNER</value> <value>repository:*:OWNER</value>
</permission> </permission>

View File

@@ -17,6 +17,7 @@ import org.mockito.Mock;
import sonia.scm.ContextEntry; import sonia.scm.ContextEntry;
import sonia.scm.NotFoundException; import sonia.scm.NotFoundException;
import sonia.scm.PageResult; import sonia.scm.PageResult;
import sonia.scm.security.SecuritySystem;
import sonia.scm.user.ChangePasswordNotAllowedException; import sonia.scm.user.ChangePasswordNotAllowedException;
import sonia.scm.user.User; import sonia.scm.user.User;
import sonia.scm.user.UserManager; import sonia.scm.user.UserManager;
@@ -59,6 +60,8 @@ public class UserRootResourceTest {
private PasswordService passwordService; private PasswordService passwordService;
@Mock @Mock
private UserManager userManager; private UserManager userManager;
@Mock
private SecuritySystem securitySystem;
@InjectMocks @InjectMocks
private UserDtoToUserMapperImpl dtoToUserMapper; private UserDtoToUserMapperImpl dtoToUserMapper;
@InjectMocks @InjectMocks
@@ -80,7 +83,7 @@ public class UserRootResourceTest {
UserCollectionToDtoMapper userCollectionToDtoMapper = new UserCollectionToDtoMapper(userToDtoMapper, resourceLinks); UserCollectionToDtoMapper userCollectionToDtoMapper = new UserCollectionToDtoMapper(userToDtoMapper, resourceLinks);
UserCollectionResource userCollectionResource = new UserCollectionResource(userManager, dtoToUserMapper, UserCollectionResource userCollectionResource = new UserCollectionResource(userManager, dtoToUserMapper,
userCollectionToDtoMapper, resourceLinks, passwordService); userCollectionToDtoMapper, resourceLinks, passwordService);
UserResource userResource = new UserResource(dtoToUserMapper, userToDtoMapper, userManager, passwordService); UserResource userResource = new UserResource(dtoToUserMapper, userToDtoMapper, userManager, passwordService, securitySystem);
UserRootResource userRootResource = new UserRootResource(Providers.of(userCollectionResource), UserRootResource userRootResource = new UserRootResource(Providers.of(userCollectionResource),
Providers.of(userResource)); Providers.of(userResource));

View File

@@ -32,9 +32,6 @@
package sonia.scm.security; package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Predicate;
import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.SimpleAccountRealm; import org.apache.shiro.realm.SimpleAccountRealm;
@@ -48,14 +45,15 @@ import sonia.scm.store.JAXBConfigurationEntryStoreFactory;
import sonia.scm.util.ClassLoaders; import sonia.scm.util.ClassLoaders;
import sonia.scm.util.MockUtil; import sonia.scm.util.MockUtil;
import java.util.Collection;
import java.util.List; import java.util.List;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*; import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
//~--- JDK imports ------------------------------------------------------------ import static org.mockito.Mockito.when;
/** /**
* *
@@ -111,10 +109,10 @@ public class DefaultSecuritySystemTest extends AbstractTestBase
{ {
setAdminSubject(); setAdminSubject();
List<PermissionDescriptor> list = securitySystem.getAvailablePermissions(); Collection<PermissionDescriptor> list = securitySystem.getAvailablePermissions();
assertNotNull(list); assertNotNull(list);
assertThat(list.size(), greaterThan(0)); assertThat(list).isNotEmpty();
} }
/** /**
@@ -131,7 +129,7 @@ public class DefaultSecuritySystemTest extends AbstractTestBase
securitySystem.deletePermission(sap); securitySystem.deletePermission(sap);
assertNull(securitySystem.getPermission(sap.getId())); assertThat(securitySystem.getPermissions(p -> p.getName().equals("trillian"))).isEmpty();
} }
/** /**
@@ -150,10 +148,10 @@ public class DefaultSecuritySystemTest extends AbstractTestBase
StoredAssignedPermission marvin = createPermission("marvin", false, StoredAssignedPermission marvin = createPermission("marvin", false,
"repository:*:READ"); "repository:*:READ");
List<StoredAssignedPermission> all = securitySystem.getAllPermissions(); List<StoredAssignedPermission> all = securitySystem.getPermissions(p -> true);
assertEquals(3, all.size()); assertEquals(3, all.size());
assertThat(all, containsInAnyOrder(trillian, dent, marvin)); assertThat(all).contains(trillian, dent, marvin);
} }
/** /**
@@ -168,10 +166,9 @@ public class DefaultSecuritySystemTest extends AbstractTestBase
StoredAssignedPermission sap = createPermission("trillian", false, StoredAssignedPermission sap = createPermission("trillian", false,
"repository:*:READ"); "repository:*:READ");
StoredAssignedPermission other = securitySystem.getPermission(sap.getId()); List<StoredAssignedPermission> other = securitySystem.getPermissions(p -> p.getName().equals("trillian"));
assertEquals(sap.getId(), other.getId()); assertThat(other).containsExactly(sap);
assertEquals(sap, other);
} }
/** /**
@@ -191,41 +188,11 @@ public class DefaultSecuritySystemTest extends AbstractTestBase
createPermission("hitchhiker", true, "repository:*:READ"); createPermission("hitchhiker", true, "repository:*:READ");
List<StoredAssignedPermission> filtered = List<StoredAssignedPermission> filtered =
securitySystem.getPermissions(new Predicate<AssignedPermission>() securitySystem.getPermissions(p -> !p.isGroupPermission());
{
@Override assertThat(filtered)
public boolean apply(AssignedPermission input) .hasSize(2)
{ .contains(trillian, dent);
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);
} }
/** /**
@@ -268,24 +235,7 @@ public class DefaultSecuritySystemTest extends AbstractTestBase
"repository:*:READ"); "repository:*:READ");
setUserSubject(); setUserSubject();
securitySystem.getPermission(sap.getId()); securitySystem.getPermissions(p -> true);
}
/**
* Method description
*
*/
@Test(expected = UnauthorizedException.class)
public void testUnauthorizedModifyPermission()
{
setAdminSubject();
StoredAssignedPermission sap = createPermission("trillian", false,
"repository:*:READ");
setUserSubject();
securitySystem.modifyPermission(sap);
} }
/** /**