Add functionality for all pmg features

This commit is contained in:
2025-03-25 01:37:58 +01:00
parent aa4de7cbe2
commit 91bc0b3b6f
24 changed files with 452 additions and 47 deletions

View File

@ -1,8 +1,10 @@
package de.mummeit.common.config;
import de.mummeit.pmg.config.PermissionManagerAuthConfiguration;
import feign.Client;
import feign.httpclient.ApacheHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@ -13,6 +15,7 @@ import org.springframework.context.annotation.PropertySource;
@ComponentScan(basePackages = "de.mummeit")
@EnableFeignClients(basePackages = "de.mummeit")
@PropertySource(value = "classpath:permission-manager-sdk-application.yaml")
@EnableConfigurationProperties(PermissionManagerAuthConfiguration.class)
public class PermissionManagerSdkConfiguration {
@Bean

View File

@ -5,7 +5,9 @@ import de.mummeit.pmg.api.model.access.request.PermitRequest;
import de.mummeit.pmg.api.model.access.request.RevokeScopeAccessRequest;
import de.mummeit.pmg.api.model.access.request.RevokeUserAccessRequest;
import de.mummeit.pmg.api.model.access.request.SearchPermitRequest;
import de.mummeit.pmg.api.model.access.request.ListPermittedScopesRequest;
import de.mummeit.pmg.api.model.access.response.PermittedResponse;
import de.mummeit.pmg.api.model.access.response.ListPermittedScopesResponse;
import de.mummeit.pmg.api.model.integration.Integration;
import de.mummeit.pmg.api.model.structure.Domain;
import de.mummeit.pmg.api.model.structure.Permission;
@ -43,6 +45,9 @@ public interface PermissionManagerClient {
@PatchMapping("/api/v1/access/revoke/user")
void revokeUserAccess(@RequestBody RevokeUserAccessRequest request);
@PostMapping("/api/v1/access/scopes")
ListPermittedScopesResponse listPermittedScopes(@RequestBody ListPermittedScopesRequest request);
// Domain Management
@PostMapping("/api/v1/domains")
Domain createDomain(@RequestBody Domain domain);

View File

@ -1,7 +1,5 @@
package de.mummeit.pmg.api.annotation;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
/**

View File

@ -3,7 +3,7 @@ package de.mummeit.pmg.api.aspect;
import de.mummeit.pmg.api.PermissionManagerClient;
import de.mummeit.pmg.api.annotation.RequiresPermission;
import de.mummeit.pmg.api.model.access.request.CheckAccessRequest;
import de.mummeit.pmg.service.exception.AccessDeniedException;
import de.mummeit.pmg.exception.AccessDeniedException;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
@ -11,7 +11,6 @@ import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
@ -22,9 +21,7 @@ import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;
@Aspect

View File

@ -0,0 +1,10 @@
package de.mummeit.pmg.api.model.access.request;
import lombok.Data;
@Data
public class ListPermittedScopesRequest {
private String userId;
private String domain;
private String permission;
}

View File

@ -0,0 +1,10 @@
package de.mummeit.pmg.api.model.access.response;
import lombok.Data;
import java.util.List;
@Data
public class ListPermittedScopesResponse {
private List<String> scopes;
}

View File

@ -1,4 +1,4 @@
package de.mummeit.pmg.service.builder;
package de.mummeit.pmg.builder;
import de.mummeit.pmg.api.model.integration.*;

View File

@ -1,4 +1,4 @@
package de.mummeit.pmg.service.config;
package de.mummeit.pmg.config;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -6,6 +6,8 @@ import de.mummeit.pmg.api.model.integration.Integration;
import de.mummeit.pmg.service.PermissionManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.Resource;
@ -24,8 +26,13 @@ import java.util.List;
@RequiredArgsConstructor
public abstract class AbstractPermissionManagerConfiguration {
@Autowired
private final PermissionManager permissionManager;
@Autowired
private final ResourceLoader resourceLoader;
@Autowired
private final ObjectMapper objectMapper;
/**

View File

@ -0,0 +1,34 @@
package de.mummeit.pmg.config;
import feign.RequestInterceptor;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
@Data
@Configuration
@ConfigurationProperties(prefix = "permission-manager")
public class PermissionManagerAuthConfiguration {
private Auth auth = new Auth();
@Data
public static class Auth {
private boolean enabled = false;
private String apiKey;
}
@Bean
public RequestInterceptor apiKeyInterceptor() {
return requestTemplate -> {
if (auth.isEnabled()) {
if (!StringUtils.hasText(auth.getApiKey())) {
throw new IllegalStateException("API key is required when authentication is enabled");
}
requestTemplate.header("x-api-key", auth.getApiKey());
}
};
}
}

View File

@ -1,4 +1,4 @@
package de.mummeit.pmg.service.exception;
package de.mummeit.pmg.exception;
/**
* Exception thrown when access is denied for a user.

View File

@ -1,4 +1,4 @@
package de.mummeit.pmg.service.exception;
package de.mummeit.pmg.exception;
import de.mummeit.pmg.api.model.integration.Integration;

View File

@ -1,4 +1,4 @@
package de.mummeit.pmg.service.exception;
package de.mummeit.pmg.exception;
/**
* Exception thrown when a permission request is invalid.

View File

@ -1,4 +1,4 @@
package de.mummeit.pmg.service.exception;
package de.mummeit.pmg.exception;
/**
* Base exception class for all Permission Manager related exceptions.

View File

@ -3,11 +3,11 @@ package de.mummeit.pmg.service;
import de.mummeit.pmg.api.PermissionManagerClient;
import de.mummeit.pmg.api.model.access.request.*;
import de.mummeit.pmg.api.model.access.response.PermittedResponse;
import de.mummeit.pmg.api.model.access.response.ListPermittedScopesResponse;
import de.mummeit.pmg.api.model.integration.Integration;
import de.mummeit.pmg.api.model.structure.Permission;
import de.mummeit.pmg.service.exception.AccessDeniedException;
import de.mummeit.pmg.service.exception.IntegrationFailedException;
import de.mummeit.pmg.service.exception.InvalidPermissionRequestException;
import de.mummeit.pmg.exception.IntegrationFailedException;
import de.mummeit.pmg.exception.InvalidPermissionRequestException;
import feign.FeignException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -31,7 +31,6 @@ public class PermissionManager {
* @param scope The scope
* @return true if the user has access, false otherwise
* @throws InvalidPermissionRequestException if any of the required parameters are null or empty
* @throws AccessDeniedException if the access check fails
*/
public boolean hasAccess(String userId, String domain, String permission, String scope) {
validateParameters(userId, domain, permission, scope);
@ -46,12 +45,9 @@ public class PermissionManager {
PermittedResponse response = client.checkAccess(request);
return response.isPermitted();
} catch (FeignException e) {
throw new AccessDeniedException(
"Failed to check access",
userId,
domain,
permission,
scope,
throw new InvalidPermissionRequestException(
"Technical error while checking access permissions",
"Failed to communicate with permission service: " + e.getMessage(),
e
);
}
@ -276,6 +272,35 @@ public class PermissionManager {
}
}
/**
* Lists all scopes where a user has access to a specific permission in a domain.
*
* @param userId The ID of the user
* @param domain The domain name
* @param permission The permission name
* @return List of scopes where the user has access
* @throws InvalidPermissionRequestException if any of the required parameters are invalid
*/
public List<String> listPermittedScopes(String userId, String domain, String permission) {
validateParameters(userId, domain, permission);
try {
ListPermittedScopesRequest request = new ListPermittedScopesRequest();
request.setUserId(userId);
request.setDomain(domain);
request.setPermission(permission);
ListPermittedScopesResponse response = client.listPermittedScopes(request);
return response.getScopes();
} catch (FeignException e) {
throw new InvalidPermissionRequestException(
"Failed to list permitted scopes",
"Error occurred while listing permitted scopes",
e
);
}
}
private void validateParameters(String userId, String domain, String permission, String scope) {
validateUserId(userId);
validateDomain(domain);