fully implemented ProjectPermission annotation

If error w/status code 401/403 and user is not logged in, they are redirected to login.
This commit is contained in:
Jake Potrebic 2020-09-06 15:30:17 -07:00
parent 10929c97e6
commit 2e596e7591
No known key found for this signature in database
GPG Key ID: 7C58557EC9C421F8
18 changed files with 189 additions and 157 deletions

View File

@ -4,26 +4,40 @@ import io.papermc.hangar.security.metadatasources.GlobalPermissionSource;
import io.papermc.hangar.security.metadatasources.HangarMetadataSources;
import io.papermc.hangar.security.metadatasources.ProjectPermissionSource;
import io.papermc.hangar.security.voters.GlobalPermissionVoter;
import io.papermc.hangar.security.voters.ProjectPermissionVoter;
import io.papermc.hangar.service.PermissionService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.annotation.Jsr250Voter;
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
import org.springframework.security.access.method.MethodSecurityMetadataSource;
import org.springframework.security.access.vote.AbstractAccessDecisionManager;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.access.vote.UnanimousBased;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import java.util.ArrayList;
import java.util.List;
@Configuration
@AutoConfigureBefore(SecurityConfig.class)
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
private final ApplicationContext applicationContext;
private final PermissionService permissionService;
@Autowired
public MethodSecurityConfig(PermissionService permissionService) {
public MethodSecurityConfig(ApplicationContext applicationContext, PermissionService permissionService) {
this.applicationContext = applicationContext;
this.permissionService = permissionService;
}
@ -34,8 +48,21 @@ public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AccessDecisionManager accessDecisionManager() {
AbstractAccessDecisionManager manager = (AbstractAccessDecisionManager) super.accessDecisionManager();
manager.getDecisionVoters().add(new GlobalPermissionVoter(permissionService));
return manager;
List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
ExpressionBasedPreInvocationAdvice expressionAdvice =
new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler());
decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
decisionVoters.add(new Jsr250Voter());
RoleVoter roleVoter = new RoleVoter();
try {
GrantedAuthorityDefaults grantedAuthorityDefaults = applicationContext.getBean(GrantedAuthorityDefaults.class);
roleVoter.setRolePrefix(grantedAuthorityDefaults.getRolePrefix());
} catch (BeansException ignored) { }
decisionVoters.add(roleVoter);
decisionVoters.add(new AuthenticatedVoter());
decisionVoters.add(new ProjectPermissionVoter(permissionService));
decisionVoters.add(new GlobalPermissionVoter(permissionService));
return new UnanimousBased(decisionVoters);
}
}

View File

@ -3,7 +3,6 @@ package io.papermc.hangar.config;
import freemarker.template.TemplateException;
import io.papermc.hangar.controller.converters.ColorHexConverter;
import io.papermc.hangar.controller.converters.StringToEnumConverterFactory;
import io.papermc.hangar.controller.interceptors.ProjectsInterceptor;
import io.papermc.hangar.service.PermissionService;
import io.papermc.hangar.service.project.ProjectService;
import io.papermc.hangar.util.Routes;
@ -22,7 +21,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.VersionResourceResolver;
@ -129,11 +127,6 @@ public class MvcConfig implements WebMvcConfigurer {
registry.addConverter(new ColorHexConverter());
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ProjectsInterceptor(projectService, permissionService));
}
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();

View File

@ -3,6 +3,7 @@ package io.papermc.hangar.config;
import io.papermc.hangar.filter.HangarAuthenticationFilter;
import io.papermc.hangar.security.HangarAuthenticationProvider;
import io.papermc.hangar.security.voters.GlobalPermissionVoter;
import io.papermc.hangar.security.voters.ProjectPermissionVoter;
import io.papermc.hangar.service.PermissionService;
import io.papermc.hangar.util.Routes;
import org.springframework.beans.factory.annotation.Autowired;
@ -66,6 +67,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
new WebExpressionVoter(),
new RoleVoter(),
new AuthenticatedVoter(),
new ProjectPermissionVoter(permissionService),
new GlobalPermissionVoter(permissionService)
);
return new UnanimousBased(decisionVoters);

View File

@ -1,5 +1,6 @@
package io.papermc.hangar.controller;
import io.papermc.hangar.util.Routes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
@ -14,7 +15,8 @@ public class HangarErrorController extends HangarController implements ErrorCont
@RequestMapping("/error")
public ModelAndView handleError(HttpServletRequest request) {
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); // TODO redirect to sign on if not signed in
String errorRequestUri = (String) request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI);
ModelAndView mav = new ModelAndView("errors/error"); // TODO show custom message with error if applicable
if (status != null) {
@ -24,6 +26,8 @@ public class HangarErrorController extends HangarController implements ErrorCont
mav = new ModelAndView("errors/notFound");
} else if (statusCode == HttpStatus.GATEWAY_TIMEOUT.value() || statusCode == HttpStatus.REQUEST_TIMEOUT.value()) {
mav = new ModelAndView("errors/timeout");
} else if ((statusCode == HttpStatus.FORBIDDEN.value() || statusCode == HttpStatus.UNAUTHORIZED.value()) && currentUser.get().isEmpty() && errorRequestUri != null) {
return Routes.USERS_LOGIN.getRedirect("", "", errorRequestUri);
}
}
return fillModel(mav);

View File

@ -352,6 +352,7 @@ public class ProjectsController extends HangarController {
userActionLogService.project(request, LoggedActionType.PROJECT_ICON_CHANGED.with(ProjectContext.of(project.getId())), "", "");
}
@ProjectPermission(NamedPermission.EDIT_SUBJECT_SETTINGS)
@Secured("ROLE_USER")
@GetMapping("/{author}/{slug}/manage")
public ModelAndView showSettings(@PathVariable String author, @PathVariable String slug) {

View File

@ -1,68 +0,0 @@
package io.papermc.hangar.controller.interceptors;
import io.papermc.hangar.security.HangarAuthentication;
import io.papermc.hangar.service.project.ProjectService;
import io.papermc.hangar.model.NamedPermission;
import io.papermc.hangar.security.annotations.ProjectPermission;
import io.papermc.hangar.service.PermissionService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@Component
public class ProjectsInterceptor extends HandlerInterceptorAdapter {
private final ProjectService projectService;
private final PermissionService permissionService;
@Autowired
public ProjectsInterceptor(ProjectService projectService, PermissionService permissionService) {
this.projectService = projectService;
this.permissionService = permissionService;
}
@Override
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) return true;
HandlerMethod method = (HandlerMethod) handler;
if (method.getMethod().isAnnotationPresent(ProjectPermission.class)) {
if (!(SecurityContextHolder.getContext().getAuthentication() instanceof HangarAuthentication)) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
@SuppressWarnings("unchecked")
Map<String, String> pathParamMap = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
if (!pathParamMap.keySet().equals(Set.of("author", "slug"))) {
System.err.println("Can't have @ProjectPermission annotation on a request method without an 'author' and 'slug' path parameter");
return false; // shouldnt happen. just don't place the annotations on methods that don't have these parameters
}
if (!(SecurityContextHolder.getContext().getAuthentication() instanceof HangarAuthentication)) {
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
long userId = ((HangarAuthentication) SecurityContextHolder.getContext().getAuthentication()).getUserId();
Collection<NamedPermission> userProjectPermissions = permissionService.getProjectPermissions(userId, projectService.getProjectData(pathParamMap.get("author"), pathParamMap.get("slug")).getProject().getId()).toNamed(); // TODO maybe remove call to getProjectData here and switch to bean
Collection<NamedPermission> requirePermissions = Arrays.asList(AnnotationUtils.getAnnotation(method.getMethod(), ProjectPermission.class).value());
if (!userProjectPermissions.containsAll(requirePermissions)) {
System.out.println("Required perms: " + requirePermissions.toString());
System.out.println("User perms: " + userProjectPermissions.toString());
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
}
}
return true;
}
}

View File

@ -33,6 +33,15 @@ public interface PermissionsDao {
" WHERE u.id = :userId")
Permission getProjectPermission(long userId, String pluginId);
@SqlQuery("SELECT (coalesce(gt.permission, B'0'::BIT(64)) | coalesce(pt.permission, B'0'::BIT(64)) | coalesce(ot.permission, B'0'::BIT(64)))::BIGINT AS perm_value" +
" FROM users u " +
" LEFT JOIN global_trust gt ON u.id = gt.user_id" +
" LEFT JOIN projects p ON lower(p.owner_name) = lower(:author) AND p.slug = :slug" +
" LEFT JOIN project_trust pt ON u.id = pt.user_id AND pt.project_id = p.id" +
" LEFT JOIN organization_trust ot ON u.id = ot.user_id AND ot.organization_id = p.owner_id" +
" WHERE u.id = :userId")
Permission getProjectPermission(long userId, String author, String slug);
@SqlQuery("SELECT (coalesce(gt.permission, B'0'::BIT(64)) | coalesce(ot.permission, B'0'::BIT(64)))::BIGINT AS perm_value" +
" FROM users u " +
" LEFT JOIN global_trust gt ON u.id = gt.user_id" +

View File

@ -1,40 +0,0 @@
package io.papermc.hangar.security;
import io.papermc.hangar.model.NamedPermission;
import org.springframework.security.core.GrantedAuthority;
/**
* @deprecated Not used atm. This can be used if we want to store global roles on the auth model
*/
@Deprecated
public class PermissionAuthority implements GrantedAuthority {
private final NamedPermission permission;
public PermissionAuthority(NamedPermission permission) {
this.permission = permission;
}
@Override
public int hashCode() {
return this.permission.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj instanceof PermissionAuthority) {
return permission == (((PermissionAuthority) obj).permission);
}
return false;
}
@Override
public String toString() {
return permission.toString();
}
@Override
public String getAuthority() {
return null;
}
}

View File

@ -0,0 +1,25 @@
package io.papermc.hangar.security.attributes;
import io.papermc.hangar.model.NamedPermission;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.List;
public class GlobalPermissionAttribute extends PermissionAttribute {
public GlobalPermissionAttribute(NamedPermission permission) {
super(permission, PermissionAttribute.GLOBAL_TYPE);
}
public static List<ConfigAttribute> createList(NamedPermission...permissions) {
Assert.notNull(permissions, "You must supply an array of permissions");
List<ConfigAttribute> attributes = new ArrayList<>(permissions.length);
for (NamedPermission permission : permissions) {
attributes.add(new GlobalPermissionAttribute(permission));
}
return attributes;
}
}

View File

@ -1,17 +1,16 @@
package io.papermc.hangar.security;
package io.papermc.hangar.security.attributes;
import io.papermc.hangar.model.NamedPermission;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.List;
public class PermissionAttribute implements ConfigAttribute {
public abstract class PermissionAttribute implements ConfigAttribute {
private final NamedPermission permission;
private final String type;
public PermissionAttribute(NamedPermission permission) {
public PermissionAttribute(NamedPermission permission, String type) {
this.type = type;
Assert.notNull(permission, "You must provide a NamedPermission");
this.permission = permission;
}
@ -34,6 +33,10 @@ public class PermissionAttribute implements ConfigAttribute {
return null;
}
public String getType() {
return type;
}
@Override
public int hashCode() {
return this.permission.hashCode();
@ -44,12 +47,6 @@ public class PermissionAttribute implements ConfigAttribute {
return this.permission.toString();
}
public static List<ConfigAttribute> createList(NamedPermission...permissions) {
Assert.notNull(permissions, "You must supply an array of permissions");
List<ConfigAttribute> attributes = new ArrayList<>(permissions.length);
for (NamedPermission permission : permissions) {
attributes.add(new PermissionAttribute(permission));
}
return attributes;
}
public static final String GLOBAL_TYPE = "GLOBAL";
public static final String PROJECT_TYPE = "PROJECT";
}

View File

@ -0,0 +1,24 @@
package io.papermc.hangar.security.attributes;
import io.papermc.hangar.model.NamedPermission;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.List;
public class ProjectPermissionAttribute extends PermissionAttribute {
public ProjectPermissionAttribute(NamedPermission permission) {
super(permission, PermissionAttribute.PROJECT_TYPE);
}
public static List<ConfigAttribute> createList(NamedPermission...permissions) {
Assert.notNull(permissions, "You must supply an array of permissions");
List<ConfigAttribute> attributes = new ArrayList<>(permissions.length);
for (NamedPermission permission : permissions) {
attributes.add(new ProjectPermissionAttribute(permission));
}
return attributes;
}
}

View File

@ -1,7 +1,7 @@
package io.papermc.hangar.security.metadatasources;
import io.papermc.hangar.security.PermissionAttribute;
import io.papermc.hangar.security.annotations.GlobalPermission;
import io.papermc.hangar.security.attributes.GlobalPermissionAttribute;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.annotation.AnnotationMetadataExtractor;
@ -10,6 +10,6 @@ import java.util.Collection;
public class GlobalPermissionSource implements AnnotationMetadataExtractor<GlobalPermission> {
@Override
public Collection<? extends ConfigAttribute> extractAttributes(GlobalPermission securityAnnotation) {
return PermissionAttribute.createList(securityAnnotation.value());
return GlobalPermissionAttribute.createList(securityAnnotation.value());
}
}

View File

@ -34,7 +34,7 @@ public class HangarMetadataSources extends AbstractFallbackMethodSecurityMetadat
annotationMetadataExtractors.forEach(annotationMetadataExtractor -> {
Class<? extends Annotation> annotationType = (Class<? extends Annotation>) GenericTypeResolver.resolveTypeArgument(annotationMetadataExtractor.getClass(), AnnotationMetadataExtractor.class);
Assert.notNull(annotationType, () -> annotationMetadataExtractor.getClass().getName() + " must supply a generic parameter for AnnotationMetadataExtracto");
Assert.notNull(annotationType, () -> annotationMetadataExtractor.getClass().getName() + " must supply a generic parameter for AnnotationMetadataExtractor");
annotationExtractors.put(annotationType, annotationMetadataExtractor);
});
}

View File

@ -1,7 +1,7 @@
package io.papermc.hangar.security.metadatasources;
import io.papermc.hangar.security.PermissionAttribute;
import io.papermc.hangar.security.annotations.ProjectPermission;
import io.papermc.hangar.security.attributes.ProjectPermissionAttribute;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.annotation.AnnotationMetadataExtractor;
@ -10,6 +10,6 @@ import java.util.Collection;
public class ProjectPermissionSource implements AnnotationMetadataExtractor<ProjectPermission> {
@Override
public Collection<? extends ConfigAttribute> extractAttributes(ProjectPermission securityAnnotation) {
return PermissionAttribute.createList(securityAnnotation.value());
return ProjectPermissionAttribute.createList(securityAnnotation.value());
}
}

View File

@ -1,18 +1,13 @@
package io.papermc.hangar.security.voters;
import io.papermc.hangar.model.NamedPermission;
import io.papermc.hangar.security.attributes.PermissionAttribute;
import io.papermc.hangar.service.PermissionService;
import java.util.Collection;
import java.util.Set;
public class GlobalPermissionVoter extends HangarPermissionVoter {
public GlobalPermissionVoter(PermissionService permissionService) {
super(hangarAuth -> {
Collection<NamedPermission> globalPerms = permissionService.getGlobalPermissions(hangarAuth.getUserId()).toNamed();
if (globalPerms.isEmpty()) globalPerms = Set.of(NamedPermission.HARD_DELETE_PROJECT, NamedPermission.SEE_HIDDEN); // TODO for development
return globalPerms;
}, hangarAuth -> true);
super((hangarAuth, ignored) -> permissionService.getGlobalPermissions(hangarAuth.getUserId()).toNamed(),
hangarAuth -> true,
permissionAttribute -> permissionAttribute.getType().equals(PermissionAttribute.GLOBAL_TYPE));
}
}

View File

@ -1,25 +1,28 @@
package io.papermc.hangar.security.voters;
import io.papermc.hangar.security.HangarAuthentication;
import io.papermc.hangar.model.NamedPermission;
import io.papermc.hangar.security.PermissionAttribute;
import io.papermc.hangar.security.HangarAuthentication;
import io.papermc.hangar.security.attributes.PermissionAttribute;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import java.util.Collection;
import java.util.function.Function;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public abstract class HangarPermissionVoter implements AccessDecisionVoter {
private final Function<HangarAuthentication, Collection<NamedPermission>> getUserPermissions;
private final BiFunction<HangarAuthentication, MethodInvocation, Collection<NamedPermission>> getUserPermissions;
private final Predicate<HangarAuthentication> authChecks;
private final Predicate<PermissionAttribute> typeCheck;
public HangarPermissionVoter(Function<HangarAuthentication, Collection<NamedPermission>> getUserPermissions, Predicate<HangarAuthentication> authChecks) {
public HangarPermissionVoter(BiFunction<HangarAuthentication, MethodInvocation, Collection<NamedPermission>> getUserPermissions, Predicate<HangarAuthentication> authChecks, Predicate<PermissionAttribute> typeCheck) {
this.getUserPermissions = getUserPermissions;
this.authChecks = authChecks;
this.typeCheck = typeCheck;
}
@Override
@ -34,7 +37,9 @@ public abstract class HangarPermissionVoter implements AccessDecisionVoter {
@Override
public int vote(Authentication authentication, Object object, Collection collection) {
Collection<NamedPermission> requiredPermissions = ((Collection<ConfigAttribute>) collection).stream().filter(this::supports).map(PermissionAttribute.class::cast).map(PermissionAttribute::getPermission).collect(Collectors.toSet());
if (!(object instanceof MethodInvocation)) return ACCESS_ABSTAIN;
MethodInvocation method = (MethodInvocation) object;
Collection<NamedPermission> requiredPermissions = ((Collection<ConfigAttribute>) collection).stream().filter(this::supports).map(PermissionAttribute.class::cast).filter(typeCheck).map(PermissionAttribute::getPermission).collect(Collectors.toSet());
if (requiredPermissions.isEmpty() && (!(authentication instanceof HangarAuthentication) || authentication.getPrincipal().equals("anonymousUser"))) {
return ACCESS_ABSTAIN;
}
@ -44,7 +49,7 @@ public abstract class HangarPermissionVoter implements AccessDecisionVoter {
HangarAuthentication hangarAuth = (HangarAuthentication) authentication;
if (!authChecks.test(hangarAuth)) return ACCESS_DENIED;
Collection<NamedPermission> userPermissions = getUserPermissions.apply(hangarAuth);
Collection<NamedPermission> userPermissions = getUserPermissions.apply(hangarAuth, method);
if (!userPermissions.containsAll(requiredPermissions)) {
System.out.println("Required perms: " + requiredPermissions.toString());
System.out.println("User perms: " + userPermissions.toString());

View File

@ -0,0 +1,54 @@
package io.papermc.hangar.security.voters;
import io.papermc.hangar.security.attributes.PermissionAttribute;
import io.papermc.hangar.service.PermissionService;
import org.springframework.web.bind.annotation.PathVariable;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Set;
public class ProjectPermissionVoter extends HangarPermissionVoter {
public ProjectPermissionVoter(PermissionService permissionService) {
super(
(hangarAuthentication, methodInvocation) -> {
Method method = methodInvocation.getMethod();
if (method.getParameterCount() == 0) return Set.of();
String author = null;
String slug = null;
Object[] arguments = methodInvocation.getArguments();
for (int i = 0; i < method.getParameters().length; i++) {
Parameter parameter = method.getParameters()[i];
if (parameter.isAnnotationPresent(PathVariable.class)) { // TODO too tired to figure out what the nicer looking way of doing this is
PathVariable pathVarAnnotation = parameter.getAnnotation(PathVariable.class);
if (pathVarAnnotation.name().equalsIgnoreCase("author")) {
author = arguments[i].toString();
continue;
}
else if (pathVarAnnotation.value().equalsIgnoreCase("author")) {
author = arguments[i].toString();
continue;
} else if (parameter.getName().equalsIgnoreCase("author")) {
author = arguments[i].toString();
continue;
}
if (pathVarAnnotation.name().equalsIgnoreCase("slug")) {
slug = arguments[i].toString();
continue;
} else if (pathVarAnnotation.value().equalsIgnoreCase("slug")) {
slug = arguments[i].toString();
continue;
} else if (parameter.getName().equalsIgnoreCase("slug")) {
slug = arguments[i].toString();
continue;
}
}
}
return permissionService.getProjectPermissions(hangarAuthentication.getUserId(), author, slug).toNamed();
},
hangarAuthentication -> true,
permissionAttribute -> permissionAttribute.getType().equals(PermissionAttribute.PROJECT_TYPE)
);
}
}

View File

@ -32,6 +32,10 @@ public class PermissionService {
return addDefaults(permissionsDao.get().getProjectPermission(userId, projectId));
}
public Permission getProjectPermissions(long userId, String author, String slug) {
return addDefaults(permissionsDao.get().getProjectPermission(userId, author, slug));
}
public Permission getProjectPermissions(UsersTable usersTable, String pluginId) {
if (usersTable == null) {
return Permission.None;