mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 08:25:44 +01:00
start implementation of repository permissions
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2014, 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 org.apache.shiro.authz.AuthorizationException;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Provider
|
||||
public class AuthorizationExceptionMapper
|
||||
extends StatusExceptionMapper<AuthorizationException>
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*/
|
||||
public AuthorizationExceptionMapper()
|
||||
{
|
||||
super(AuthorizationException.class, Response.Status.FORBIDDEN);
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ package sonia.scm.api.rest.resources;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import org.apache.commons.beanutils.BeanComparator;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -44,7 +45,6 @@ import sonia.scm.LastModifiedAware;
|
||||
import sonia.scm.Manager;
|
||||
import sonia.scm.ModelObject;
|
||||
import sonia.scm.api.rest.RestExceptionResult;
|
||||
import sonia.scm.security.ScmSecurityException;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.util.Util;
|
||||
@@ -71,7 +71,7 @@ import javax.ws.rs.core.UriInfo;
|
||||
* @param <E>
|
||||
*/
|
||||
public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
E extends Exception>
|
||||
E extends Exception>
|
||||
{
|
||||
|
||||
/** the logger for AbstractManagerResource */
|
||||
@@ -102,7 +102,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
* @return
|
||||
*/
|
||||
protected abstract GenericEntity<Collection<T>> createGenericEntity(
|
||||
Collection<T> items);
|
||||
Collection<T> items);
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@@ -140,7 +140,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
{
|
||||
preCreate(item);
|
||||
|
||||
Response response = null;
|
||||
Response response;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -153,7 +153,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
uriInfo.getAbsolutePath().resolve(
|
||||
getPathPart().concat("/").concat(id))).build();
|
||||
}
|
||||
catch (ScmSecurityException ex)
|
||||
catch (AuthorizationException ex)
|
||||
{
|
||||
logger.warn("create is not allowd", ex);
|
||||
response = Response.status(Status.FORBIDDEN).build();
|
||||
@@ -189,7 +189,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
manager.delete(item);
|
||||
response = Response.noContent().build();
|
||||
}
|
||||
catch (ScmSecurityException ex)
|
||||
catch (AuthorizationException ex)
|
||||
{
|
||||
logger.warn("delete not allowd", ex);
|
||||
response = Response.status(Response.Status.FORBIDDEN).build();
|
||||
@@ -228,7 +228,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
manager.modify(item);
|
||||
response = Response.noContent().build();
|
||||
}
|
||||
catch (ScmSecurityException ex)
|
||||
catch (AuthorizationException ex)
|
||||
{
|
||||
logger.warn("update not allowd", ex);
|
||||
response = Response.status(Response.Status.FORBIDDEN).build();
|
||||
@@ -293,7 +293,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
* @return
|
||||
*/
|
||||
public Response getAll(Request request, int start, int limit, String sortby,
|
||||
boolean desc)
|
||||
boolean desc)
|
||||
{
|
||||
Collection<T> items = fetchItems(sortby, desc, start, limit);
|
||||
|
||||
@@ -376,7 +376,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
protected Response createErrorResonse(Throwable throwable)
|
||||
{
|
||||
return createErrorResonse(Status.INTERNAL_SERVER_ERROR,
|
||||
throwable.getMessage(), throwable);
|
||||
throwable.getMessage(), throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,10 +404,10 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
* @return
|
||||
*/
|
||||
protected Response createErrorResonse(Status status, String message,
|
||||
Throwable throwable)
|
||||
Throwable throwable)
|
||||
{
|
||||
return Response.status(status).entity(new RestExceptionResult(message,
|
||||
throwable)).build();
|
||||
throwable)).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -486,7 +486,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
* @return
|
||||
*/
|
||||
private <I> Response createCacheResponse(Request request,
|
||||
LastModifiedAware timeItem, I item)
|
||||
LastModifiedAware timeItem, I item)
|
||||
{
|
||||
return createCacheResponse(request, timeItem, item, item);
|
||||
}
|
||||
@@ -504,7 +504,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
* @return
|
||||
*/
|
||||
private <I> Response createCacheResponse(Request request,
|
||||
LastModifiedAware timeItem, Object entityItem, I item)
|
||||
LastModifiedAware timeItem, Object entityItem, I item)
|
||||
{
|
||||
Response.ResponseBuilder builder = null;
|
||||
Date lastModified = getLastModified(timeItem);
|
||||
@@ -568,7 +568,7 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
||||
* @return
|
||||
*/
|
||||
private Collection<T> fetchItems(String sortby, boolean desc, int start,
|
||||
int limit)
|
||||
int limit)
|
||||
{
|
||||
AssertUtil.assertPositive(start);
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.ChangesetPagingResult;
|
||||
import sonia.scm.repository.HealthChecker;
|
||||
import sonia.scm.repository.Permission;
|
||||
import sonia.scm.repository.PermissionType;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryException;
|
||||
import sonia.scm.repository.RepositoryIsNotArchivedException;
|
||||
@@ -71,8 +70,6 @@ import sonia.scm.repository.api.DiffFormat;
|
||||
import sonia.scm.repository.api.LogCommandBuilder;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.security.RepositoryPermission;
|
||||
import sonia.scm.security.ScmSecurityException;
|
||||
import sonia.scm.util.AssertUtil;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.util.IOUtil;
|
||||
@@ -103,6 +100,7 @@ import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.StreamingOutput;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -196,7 +194,7 @@ public class RepositoryResource
|
||||
@Override
|
||||
public Response delete(@PathParam("id") String id)
|
||||
{
|
||||
Response response = null;
|
||||
Response response;
|
||||
Repository repository = manager.get(id);
|
||||
|
||||
if (repository != null)
|
||||
@@ -213,12 +211,12 @@ public class RepositoryResource
|
||||
logger.warn("non archived repository could not be deleted", ex);
|
||||
response = Response.status(Response.Status.PRECONDITION_FAILED).build();
|
||||
}
|
||||
catch (ScmSecurityException ex)
|
||||
catch (AuthorizationException ex)
|
||||
{
|
||||
logger.warn("delete not allowed", ex);
|
||||
response = Response.status(Response.Status.FORBIDDEN).build();
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (RepositoryException | IOException ex)
|
||||
{
|
||||
logger.error("error during create", ex);
|
||||
response = createErrorResonse(ex);
|
||||
@@ -263,12 +261,7 @@ public class RepositoryResource
|
||||
logger.warn("could not find repository ".concat(id), ex);
|
||||
response = Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
catch (RepositoryException ex)
|
||||
{
|
||||
logger.error("error occured during health check", ex);
|
||||
response = Response.serverError().build();
|
||||
}
|
||||
catch (IOException ex)
|
||||
catch (RepositoryException | IOException ex)
|
||||
{
|
||||
logger.error("error occured during health check", ex);
|
||||
response = Response.serverError().build();
|
||||
@@ -610,7 +603,7 @@ public class RepositoryResource
|
||||
public Response getByTypeAndName(@PathParam("type") String type,
|
||||
@PathParam("name") String name)
|
||||
{
|
||||
Response response = null;
|
||||
Response response;
|
||||
Repository repository = repositoryManager.get(type, name);
|
||||
|
||||
if (repository != null)
|
||||
@@ -690,11 +683,7 @@ public class RepositoryResource
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isWarnEnabled())
|
||||
{
|
||||
logger.warn("id or revision is empty");
|
||||
}
|
||||
|
||||
logger.warn("id or revision is empty");
|
||||
response = Response.status(Status.BAD_REQUEST).build();
|
||||
}
|
||||
|
||||
@@ -745,7 +734,7 @@ public class RepositoryResource
|
||||
|
||||
try
|
||||
{
|
||||
ChangesetPagingResult changesets = null;
|
||||
ChangesetPagingResult changesets;
|
||||
|
||||
service = servicefactory.create(id);
|
||||
|
||||
@@ -819,9 +808,9 @@ public class RepositoryResource
|
||||
public Response getContent(@PathParam("id") String id,
|
||||
@QueryParam("revision") String revision, @QueryParam("path") String path)
|
||||
{
|
||||
Response response = null;
|
||||
StreamingOutput output = null;
|
||||
RepositoryService service = null;
|
||||
Response response;
|
||||
StreamingOutput output;
|
||||
RepositoryService service;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -905,8 +894,8 @@ public class RepositoryResource
|
||||
*/
|
||||
HttpUtil.checkForCRLFInjection(revision);
|
||||
|
||||
RepositoryService service = null;
|
||||
Response response = null;
|
||||
RepositoryService service;
|
||||
Response response;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -1062,7 +1051,8 @@ public class RepositoryResource
|
||||
@Override
|
||||
protected Repository prepareForReturn(Repository repository)
|
||||
{
|
||||
if (isOwner(repository))
|
||||
if (SecurityUtils.getSubject().isPermitted(
|
||||
"repository:modify:".concat(repository.getId())))
|
||||
{
|
||||
if (repository.getPermissions() == null)
|
||||
{
|
||||
@@ -1071,11 +1061,8 @@ public class RepositoryResource
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
logger.trace("remove properties and permissions from repository, "
|
||||
+ "because the user is not privileged");
|
||||
}
|
||||
logger.trace("remove properties and permissions from repository, "
|
||||
+ "because the user is not privileged");
|
||||
|
||||
repository.setProperties(null);
|
||||
repository.setPermissions(null);
|
||||
@@ -1147,22 +1134,7 @@ public class RepositoryResource
|
||||
|
||||
return getContentDispositionName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean isOwner(Repository repository)
|
||||
{
|
||||
|
||||
return SecurityUtils.getSubject().isPermitted(
|
||||
new RepositoryPermission(repository, PermissionType.OWNER));
|
||||
}
|
||||
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
|
||||
Reference in New Issue
Block a user