-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
invenio-damap: enable connection from InvenioRDM
- Loading branch information
1 parent
f6236ac
commit 29d93ab
Showing
5 changed files
with
593 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
189 changes: 189 additions & 0 deletions
189
src/main/java/org/damap/base/rest/invenio_damap/InvenioDAMAPResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package org.damap.base.rest.invenio_damap; | ||
|
||
import io.smallrye.jwt.auth.principal.JWTParser; | ||
import io.smallrye.jwt.auth.principal.ParseException; | ||
|
||
import io.quarkus.security.ForbiddenException; | ||
import io.quarkus.security.UnauthorizedException; | ||
|
||
import java.util.List; | ||
import java.util.AbstractMap.SimpleEntry; | ||
import java.util.ArrayList; | ||
|
||
import jakarta.enterprise.context.RequestScoped; | ||
import jakarta.inject.Inject; | ||
import jakarta.json.JsonObject; | ||
import jakarta.ws.rs.BadRequestException; | ||
import jakarta.ws.rs.Consumes; | ||
import jakarta.ws.rs.GET; | ||
import jakarta.ws.rs.NotFoundException; | ||
import jakarta.ws.rs.POST; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.Produces; | ||
import jakarta.ws.rs.core.Context; | ||
import jakarta.ws.rs.core.HttpHeaders; | ||
import jakarta.ws.rs.core.MediaType; | ||
|
||
import org.eclipse.microprofile.config.inject.ConfigProperty; | ||
import org.eclipse.microprofile.jwt.JsonWebToken; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import org.damap.base.repo.AccessRepo; | ||
import org.damap.base.rest.dmp.domain.DmpDO; | ||
import org.damap.base.rest.dmp.domain.DmpListItemDO; | ||
import org.damap.base.rest.dmp.service.DmpService; | ||
import org.damap.base.rest.madmp.dto.Dataset; | ||
import org.damap.base.security.SecurityService; | ||
import org.damap.base.validation.AccessValidator; | ||
|
||
import lombok.extern.jbosslog.JBossLog; | ||
|
||
@Path("/api/madmps") | ||
@RequestScoped | ||
@Produces(MediaType.APPLICATION_JSON) | ||
@JBossLog | ||
public class InvenioDAMAPResource { | ||
|
||
@Inject | ||
public InvenioDAMAPResource(SecurityService securityService, AccessValidator accessValidator, AccessRepo accessRepo, | ||
DmpService dmpService, InvenioDAMAPService invenioDAMAPService) { | ||
this.securityService = securityService; | ||
this.accessValidator = accessValidator; | ||
this.accessRepo = accessRepo; | ||
this.dmpService = dmpService; | ||
this.invenioDAMAPService = invenioDAMAPService; | ||
} | ||
|
||
SecurityService securityService; | ||
AccessValidator accessValidator; | ||
AccessRepo accessRepo; | ||
DmpService dmpService; | ||
InvenioDAMAPService invenioDAMAPService; | ||
|
||
@ConfigProperty(name = "invenio.shared-secret") | ||
String sharedSecret; | ||
|
||
@Inject | ||
JWTParser parser; | ||
|
||
/* | ||
* Maybe make it configurable? | ||
* Could be more elaborate but should suffice for PoC | ||
* Could also go into the {@link org.damap.base.security.SecurityService}, | ||
* but keeping everything together for PoC | ||
* | ||
*/ | ||
private JsonWebToken validateAuthHeader(HttpHeaders headers) { | ||
String jwt_token = headers.getHeaderString("X-Auth"); | ||
|
||
if (jwt_token != null && !jwt_token.isEmpty()) { | ||
try { | ||
JsonWebToken jwt = parser.verify(jwt_token, sharedSecret); | ||
log.info("Smallrye jwt: " + jwt); | ||
return jwt; | ||
} catch (ParseException e) { | ||
return null; | ||
} | ||
} | ||
return null; // No Authorization header or not in the correct format | ||
} | ||
|
||
// Checks provided jwt. | ||
private JsonWebToken checkIfUserIsAuthorized(HttpHeaders headers) { | ||
|
||
JsonWebToken jwt = validateAuthHeader(headers); | ||
boolean authorized = jwt != null; | ||
|
||
if (!authorized) { | ||
throw new UnauthorizedException("User unauthorized."); | ||
} | ||
return jwt; | ||
} | ||
|
||
// Resolves user identity based on the DMPs and returns dmp list and list of | ||
// identifiers if successful. | ||
private SimpleEntry<List<DmpListItemDO>, List<String>> resolveDmpsAndIds(JsonObject identifiers) { | ||
List<DmpListItemDO> personDmpList = null; | ||
List<String> matchingIdentifiers = new ArrayList<>(); | ||
|
||
for (String key : identifiers.keySet()) { | ||
String identifier = identifiers.getString(key); | ||
List<DmpListItemDO> dmps = dmpService.getDmpListByPersonId(identifier); | ||
|
||
// Check if returned DMPs is null or the list is empty. | ||
// If yes, no resolving can take place, move to the next identifier. | ||
if (dmps == null || dmps.isEmpty()) | ||
continue; | ||
|
||
// Here dmps would contain at least one DMP so keep track of the current | ||
// iterated identifier. | ||
matchingIdentifiers.add(identifier); | ||
|
||
// Keep track of the 1st list that matches at least one DMP. | ||
// Then compare it with other non-null or non-empty lists. | ||
if (personDmpList == null) | ||
personDmpList = dmps; | ||
|
||
// If a DMP list is different than the previous one, a different identity was | ||
// resolved. | ||
else if (!personDmpList.equals(dmps)) | ||
throw new UnauthorizedException("Mismatch in resolved identities."); | ||
} | ||
|
||
// Check if DMP list is null. This means that no resolving was possible. | ||
if (personDmpList == null) | ||
throw new NotFoundException("No valid identities were found."); | ||
|
||
return new SimpleEntry<>(personDmpList, matchingIdentifiers); | ||
} | ||
|
||
@GET | ||
public List<DmpListItemDO> getDmpListByPerson(@Context HttpHeaders headers) { | ||
JsonWebToken jwt = checkIfUserIsAuthorized(headers); | ||
JsonObject invenioDamap = jwt.getClaim("invenio-damap"); | ||
JsonObject identifiers = invenioDamap.getJsonObject("identifiers"); | ||
|
||
SimpleEntry<List<DmpListItemDO>, List<String>> result = resolveDmpsAndIds(identifiers); | ||
List<DmpListItemDO> dmps = result.getKey(); | ||
return dmps; | ||
} | ||
|
||
@POST | ||
@Consumes(MediaType.APPLICATION_JSON) | ||
public DmpDO addDataSetToDmp(@Context HttpHeaders headers, JsonObject payload) { | ||
|
||
JsonWebToken jwt = checkIfUserIsAuthorized(headers); | ||
JsonObject invenioDamap = jwt.getClaim("invenio-damap"); | ||
JsonObject identifiers = invenioDamap.getJsonObject("identifiers"); | ||
|
||
SimpleEntry<List<DmpListItemDO>, List<String>> result = resolveDmpsAndIds(identifiers); | ||
List<String> personIds = result.getValue(); | ||
String strDmpId = payload.getString("dmp_id"); | ||
long dmpId; | ||
|
||
try { | ||
dmpId = Long.parseLong(strDmpId); | ||
} catch (NumberFormatException e) { | ||
throw new BadRequestException("Invalid dmp_id format."); | ||
} | ||
|
||
// Deserialize the dataset JSON object into a Dataset instance | ||
ObjectMapper objMap = new ObjectMapper(); | ||
Dataset dataset; | ||
|
||
try { | ||
dataset = objMap.readValue(payload.getJsonObject("dataset").toString(), Dataset.class); | ||
} catch (Exception e) { | ||
throw new BadRequestException("Invalid dataset format"); | ||
} | ||
|
||
// Assuming all IDs provided fetch the same DMPs, check permissions. | ||
for (String personId : personIds) { | ||
if (!accessValidator.canEditDmp(dmpId, personId)) | ||
throw new ForbiddenException("Person " + personId + "Not authorized to access dmp with id " + dmpId); | ||
} | ||
log.info("Add dataset to dmp with id: " + dmpId); | ||
return invenioDAMAPService.addDataSetToDMP(dmpId, dataset); | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
src/main/java/org/damap/base/rest/invenio_damap/InvenioDAMAPService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package org.damap.base.rest.invenio_damap; | ||
|
||
import java.text.MessageFormat; | ||
import java.util.Date; | ||
|
||
import jakarta.enterprise.context.ApplicationScoped; | ||
import jakarta.inject.Inject; | ||
import jakarta.transaction.Transactional; | ||
|
||
import org.damap.base.rest.dmp.domain.DatasetDO; | ||
import org.damap.base.rest.dmp.domain.DmpDO; | ||
import org.damap.base.rest.dmp.service.DmpService; | ||
import org.damap.base.rest.madmp.dto.Dataset; | ||
import org.damap.base.rest.version.VersionDO; | ||
import org.damap.base.rest.version.VersionService; | ||
|
||
@ApplicationScoped | ||
public class InvenioDAMAPService { | ||
|
||
protected DmpService dmpService; | ||
protected VersionService versionService; | ||
|
||
@Inject | ||
InvenioDAMAPService(DmpService dmpService, VersionService versionService) { | ||
this.dmpService = dmpService; | ||
this.versionService = versionService; | ||
} | ||
|
||
@Transactional | ||
public DmpDO addDataSetToDMP(long dmpId, Dataset dataset) { | ||
|
||
DmpDO dmpDO = dmpService.getDmpById(dmpId); | ||
var datasetDO = dmpDO.getDatasets().stream().filter(ds -> { | ||
var localIdentifier = ds.getDatasetId(); | ||
var externalIdentifier = dataset.getDatasetId(); | ||
|
||
if (localIdentifier == null || externalIdentifier == null) { | ||
return false; | ||
} | ||
|
||
return localIdentifier.getIdentifier() != null && externalIdentifier.getIdentifier() != null | ||
&& localIdentifier.getType() != null && externalIdentifier.getType() != null | ||
&& localIdentifier.getIdentifier().equals(externalIdentifier.getIdentifier()) | ||
&& localIdentifier.getType().toString().equalsIgnoreCase(externalIdentifier.getType().name()); | ||
}).findFirst().orElse(new DatasetDO()); | ||
|
||
datasetDO = InvenioDamapResourceMapper.mapMaDMPDatasetToDatasetDO(dataset, datasetDO, dmpDO); | ||
|
||
dmpDO.getDatasets().add(datasetDO); | ||
dmpDO = dmpService.update(dmpDO); | ||
|
||
VersionDO version = new VersionDO(); | ||
version.setDmpId(dmpId); | ||
version.setVersionName(MessageFormat.format("Added dataset `{0}` from remote datasource", dataset.getTitle())); | ||
version.setVersionDate(new Date()); | ||
versionService.create(version); | ||
|
||
return dmpDO; | ||
} | ||
} |
Oops, something went wrong.