Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RBAC #646

Merged
merged 11 commits into from
Jun 25, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Spliterators;
import java.util.stream.Stream;

@Service
public class CodeListServiceImpl extends RdfService implements CodeListService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,41 @@

public abstract class RdfService {

@Autowired
protected RepositoryGestion repoGestion;

@Autowired
protected RepositoryPublication repositoryPublication;
@Autowired
protected Config config;
@Autowired
protected StampsRestrictionsService stampsRestrictionsService;

@Autowired
protected PublicationUtils publicationUtils;
public void transformTripleToPublish(Model model, Statement st) {
Resource subject = publicationUtils.tranformBaseURIToPublish(st.getSubject());
IRI predicateIRI = RdfUtils
.createIRI(publicationUtils.tranformBaseURIToPublish(st.getPredicate()).stringValue());
Value object = st.getObject();
if (st.getObject() instanceof Resource) {
object = publicationUtils.tranformBaseURIToPublish((Resource) st.getObject());
}

model.add(subject, predicateIRI, object, st.getContext());
}

public void getMultipleTripletsForObject(JSONObject object, String objectKey, String query, String queryKey) throws RmesException {
JSONArray array = this.repoGestion.getResponseAsArray(query);
List<String> results = new ArrayList<>();
if(array == null){
return;
}
array.iterator().forEachRemaining(r -> results.add(((JSONObject) r).getString(queryKey)));
object.put(objectKey, results);
}
@Autowired
protected RepositoryGestion repoGestion;

@Autowired
protected RepositoryPublication repositoryPublication;

@Autowired
protected Config config;

@Autowired
protected StampsRestrictionsService stampsRestrictionsService;

@Autowired
protected PublicationUtils publicationUtils;

public void transformTripleToPublish(Model model, Statement st) {
Resource subject = publicationUtils.tranformBaseURIToPublish(st.getSubject());
IRI predicateIRI = RdfUtils
.createIRI(publicationUtils.tranformBaseURIToPublish(st.getPredicate()).stringValue());
Value object = st.getObject();
if (st.getObject() instanceof Resource) {
object = publicationUtils.tranformBaseURIToPublish((Resource) st.getObject());
}

model.add(subject, predicateIRI, object, st.getContext());
}

public void getMultipleTripletsForObject(JSONObject object, String objectKey, String query, String queryKey) throws RmesException {
JSONArray array = this.repoGestion.getResponseAsArray(query);
List<String> results = new ArrayList<>();
if (array == null) {
return;
}
array.iterator().forEachRemaining(r -> results.add(((JSONObject) r).getString(queryKey)));
object.put(objectKey, results);
}

}
52 changes: 52 additions & 0 deletions src/main/java/fr/insee/rmes/config/auth/RBACConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package fr.insee.rmes.config.auth;

import fr.insee.rmes.model.rbac.AllModuleAccessPrivileges;
import fr.insee.rmes.model.rbac.ModuleAccessPrivileges;
import fr.insee.rmes.model.rbac.RBAC;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.ConstructorBinding;

import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


@ConfigurationProperties("rbac")
public record RBACConfiguration (Set<AllModuleAccessPrivileges> allModulesAccessPrivileges){

@ConstructorBinding
public RBACConfiguration(Map<String, Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>>> config){
this(toSetOfAllModulesAccessPrivileges(config));
}

private static Set<AllModuleAccessPrivileges> toSetOfAllModulesAccessPrivileges(Map<String, Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>>> rbac) {
return rbac.entrySet().stream()
.map(RBACConfiguration::toAllModuleAccessPrivileges)
.collect(Collectors.toSet());
}

private static AllModuleAccessPrivileges toAllModuleAccessPrivileges(Map.Entry<String, Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>>> entry) {
EmmanuelDemey marked this conversation as resolved.
Show resolved Hide resolved
return new AllModuleAccessPrivileges(new AllModuleAccessPrivileges.RoleName(entry.getKey()), toSetOfModuleAccessPrivileges(entry.getValue()));
}

private static Set<ModuleAccessPrivileges> toSetOfModuleAccessPrivileges(Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> privilegesForOneRole) {
return privilegesForOneRole.entrySet().stream()
.map(RBACConfiguration::toModuleAccessPrivileges)
.collect(Collectors.toSet());
}

private static ModuleAccessPrivileges toModuleAccessPrivileges(Map.Entry<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> entry) {
return new ModuleAccessPrivileges(entry.getKey(), toSetOfPrivileges(entry.getValue()));
}

private static Set<ModuleAccessPrivileges.Privilege> toSetOfPrivileges(Map<RBAC.PRIVILEGE, RBAC.STRATEGY> privilegesForOneModule) {
return privilegesForOneModule.entrySet().stream()
.map(RBACConfiguration::toPrivilege)
.collect(Collectors.toSet());
}

private static ModuleAccessPrivileges.Privilege toPrivilege(Map.Entry<RBAC.PRIVILEGE, RBAC.STRATEGY> entry) {
return new ModuleAccessPrivileges.Privilege(entry.getKey(), entry.getValue());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package fr.insee.rmes.external_services.rbac;

import fr.insee.rmes.model.rbac.RBAC;

import java.util.List;
import java.util.Map;

public interface RBACService {

Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> computeRbac(List<String> roles);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package fr.insee.rmes.external_services.rbac;

import fr.insee.rmes.config.auth.RBACConfiguration;
import fr.insee.rmes.model.rbac.RBAC;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class RBACServiceImpl implements RBACService {

private final RBACConfiguration configuration;

public RBACServiceImpl(RBACConfiguration configuration) {
this.configuration = configuration;
}

@Override
public Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> computeRbac(List<String> roles) {
/*if(roles.isEmpty()){
return Map.of();
}

Map<String, Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>>> rbac = configuration.getRbac();

Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> results = new HashMap<>();

for (String role : roles) {
Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> rolePrivileges = rbac.get(role);
if (rolePrivileges != null) {
mergePrivileges(results, rolePrivileges);
}
}

return results;*/
return Map.of();
}

private void mergePrivileges(Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> target,
Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> source) {
for (Map.Entry<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> entry : source.entrySet()) {
RBAC.APPLICATION app = entry.getKey();
Map<RBAC.PRIVILEGE, RBAC.STRATEGY> sourcePrivileges = entry.getValue();

target.merge(app, new HashMap<>(sourcePrivileges), (targetPrivileges, newPrivileges) -> {
for (Map.Entry<RBAC.PRIVILEGE, RBAC.STRATEGY> privilegeEntry : newPrivileges.entrySet()) {
RBAC.PRIVILEGE privilege = privilegeEntry.getKey();
RBAC.STRATEGY strategy = privilegeEntry.getValue();

targetPrivileges.merge(privilege, strategy, (existingStrategy, newStrategy) -> {
if (existingStrategy == RBAC.STRATEGY.ALL || newStrategy == RBAC.STRATEGY.ALL) {
return RBAC.STRATEGY.ALL;
}
return existingStrategy;
});
}
return targetPrivileges;
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package fr.insee.rmes.model.rbac;

import java.util.Set;

public record AllModuleAccessPrivileges(RoleName roleName, Set<ModuleAccessPrivileges> privileges) {


public record RoleName(String role) {}
}
10 changes: 10 additions & 0 deletions src/main/java/fr/insee/rmes/model/rbac/ModuleAccessPrivileges.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package fr.insee.rmes.model.rbac;

import java.util.Set;

public record ModuleAccessPrivileges(RBAC.APPLICATION application, Set<Privilege> privileges) {

public record Privilege(RBAC.PRIVILEGE privilege, RBAC.STRATEGY strategy) {
}

}
27 changes: 27 additions & 0 deletions src/main/java/fr/insee/rmes/model/rbac/RBAC.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package fr.insee.rmes.model.rbac;

public class RBAC {
public enum APPLICATION {
concept,
collection,
family,
serie,
operation,
indicator,
sims,
classification
}

public enum PRIVILEGE {
create,
read,
update,
delete,
publish,
validate
}

public enum STRATEGY {
ALL, STAMP
}
}
36 changes: 32 additions & 4 deletions src/main/java/fr/insee/rmes/webservice/UserResources.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package fr.insee.rmes.webservice;

import fr.insee.rmes.config.auth.security.UserDecoder;
import fr.insee.rmes.config.auth.user.Stamp;
import fr.insee.rmes.config.auth.user.User;
import fr.insee.rmes.exceptions.RmesException;
import fr.insee.rmes.external_services.authentication.stamps.StampsService;
import fr.insee.rmes.external_services.rbac.RBACService;
import fr.insee.rmes.model.rbac.RBAC;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
Expand All @@ -12,14 +17,15 @@
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
* WebService class for resources of Concepts
*
Expand All @@ -44,18 +50,40 @@
@ApiResponse(responseCode = "404", description = "Not found"),
@ApiResponse(responseCode = "406", description = "Not Acceptable"),
@ApiResponse(responseCode = "500", description = "Internal server error")})
public class UserResources extends GenericResources {
public class UserResources {

static final Logger logger = LoggerFactory.getLogger(UserResources.class);

private final StampsService stampsService;
private final RBACService rbacService;
private final UserDecoder userDecoder;


@Autowired
public UserResources(StampsService stampsService) {
public UserResources(StampsService stampsService, RBACService rbacService, UserDecoder userDecoder) {
this.stampsService = stampsService;
this.rbacService = rbacService;
this.userDecoder = userDecoder;
}

@GetMapping(
value = "/info",
produces = MediaType.APPLICATION_JSON_VALUE
)
@Operation(
operationId = "getUserInformation",
summary = "Get information about the logged-in user",
responses = {
@ApiResponse(content = @Content(mediaType = "application/json"))
}
)
public Map<RBAC.APPLICATION, Map<RBAC.PRIVILEGE, RBAC.STRATEGY>> getUserInformation(@AuthenticationPrincipal Object principal) throws RmesException {
User user = this.userDecoder.fromPrincipal(principal).get();
return rbacService.computeRbac(user.roles());
}

/**
* @deprecated
*/
@GetMapping(value = "/stamp",
produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(operationId = "getStamp", summary = "User's stamp", responses = {@ApiResponse(content = @Content(mediaType = "application/json", schema = @Schema(implementation = String.class)))})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class DatasetResources {
final DatasetService datasetService;

public DatasetResources(DatasetService datasetService) {

this.datasetService = datasetService;
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# For executions within insee context, overrides properties using spring.config.additional-location parameter on command line
spring.config.import=classpath:bauhaus-core.properties,optional:classpath:bauhaus-local-dev.properties,optional:classpath:feature-flipping.yml
spring.config.import=classpath:bauhaus-core.properties,optional:classpath:bauhaus-local-dev.properties,optional:classpath:feature-flipping.yml,classpath:rbac.yml

# spring boot config
spring.application.name=Bauhaus-Back-Office
Expand Down
Loading
Loading