Skip to content

Commit

Permalink
Merged in task/dspace-cris-2023_02_x/DSC-1860 (pull request DSpace#2552)
Browse files Browse the repository at this point in the history
Task/dspace cris 2023 02 x/DSC-1860

Approved-by: Vincenzo Mecca
  • Loading branch information
atarix83 committed Sep 26, 2024
2 parents 6157c42 + 4e5731d commit 39c9ef1
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1018,21 +1018,27 @@ public Object getDSpaceAPIObjectFromRest(Context context, BaseObjectRest restObj
*/
public BaseObjectRest getBaseObjectRestFromUri(Context context, String uri) throws SQLException {
String dspaceUrl = configurationService.getProperty("dspace.server.url");
String dspaceSSRUrl = configurationService.getProperty("dspace.server.ssr.url", "");

// Convert strings to URL objects.
// Do this early to check that inputs are well-formed.
URL dspaceUrlObject;
URL dspaceUrlSSRObject = null;
URL requestUrlObject;
try {
dspaceUrlObject = new URL(dspaceUrl);
requestUrlObject = new URL(uri);
if (StringUtils.isNoneBlank(dspaceSSRUrl)) {
dspaceUrlSSRObject = new URL(dspaceSSRUrl);
}
} catch (MalformedURLException ex) {
throw new IllegalArgumentException(
String.format("Configuration '%s' or request '%s' is malformed", dspaceUrl, uri));
}

// Check whether the URI could be valid.
if (!urlIsPrefixOf(dspaceUrl, uri)) {
if (!urlIsPrefixOf(dspaceUrl, uri) && (StringUtils.isBlank(dspaceSSRUrl) ||
!urlIsPrefixOf(dspaceSSRUrl, uri))) {
throw new IllegalArgumentException("the supplied uri is not ours: " + uri);
}

Expand All @@ -1042,10 +1048,16 @@ public BaseObjectRest getBaseObjectRestFromUri(Context context, String uri) thro
String[] requestPath = StringUtils.split(requestUrlObject.getPath(), '/');
String[] uriParts = Arrays.copyOfRange(requestPath, dspacePathLength,
requestPath.length);
String[] uriSSRParts = new String[0];
if (StringUtils.isNoneBlank(dspaceSSRUrl) && !Objects.isNull(dspaceUrlSSRObject)) {
int dspaceSSRPathLength = StringUtils.split(dspaceUrlSSRObject.getPath(), '/').length;
uriSSRParts = Arrays.copyOfRange(requestPath, dspaceSSRPathLength,
requestPath.length);
}
if ("api".equalsIgnoreCase(uriParts[0])) {
uriParts = Arrays.copyOfRange(uriParts, 1, uriParts.length);
}
if (uriParts.length != 3) {
if (uriParts.length != 3 && uriSSRParts.length != 3) {
throw new IllegalArgumentException("the supplied uri lacks required path elements: " + uri);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,133 @@ public void findByObjectBadRequestTest() throws Exception {
.andExpect(status().isBadRequest());
}

@Test
/**
* Verify that the findByObject return the 400 Bad Request response for invalid or missing URI (required parameter)
*
* @throws Exception
*/
public void findByObjectBadRequestSSRTest() throws Exception {
Site site = siteService.findSite(context);
SiteRest siteRest = siteConverter.convert(site, DefaultProjection.DEFAULT);
String siteUri = "http://ssr.example.com/api/core/sites/" + siteRest.getId();
String[] invalidUris = new String[] {
"invalid-uri",
"",
"http://localhost/api/wrongcategory/wrongmodel/1",
"http://localhost/api/core/sites/this-is-not-an-uuid"
};

// disarm the alwaysThrowExceptionFeature
configurationService.setProperty("org.dspace.app.rest.authorization.AlwaysThrowExceptionFeature.turnoff", true);
configurationService.setProperty("dspace.server.ssr.url", "http://ssr.example.com/api");

String adminToken = getAuthToken(admin.getEmail(), password);
String epersonToken = getAuthToken(eperson.getEmail(), password);

// verify that it works for administrator users
getClient(adminToken).perform(get("/api/authz/authorizations/search/object")
.param("uri", siteUri))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.authorizations", Matchers.hasSize(greaterThanOrEqualTo(1))))
.andExpect(jsonPath("$._embedded.authorizations", Matchers.everyItem(
Matchers.anyOf(
JsonPathMatchers.hasJsonPath("$.type", is("authorization")),
JsonPathMatchers.hasJsonPath("$._embedded.feature",
Matchers.allOf(
is(alwaysTrue.getName())
)),
JsonPathMatchers.hasJsonPath("$._embedded.feature",
Matchers.not(Matchers.anyOf(
is(alwaysFalse.getName()),
is(alwaysException.getName()),
is(trueForTestUsers.getName()),
is(trueForAdmins.getName())
)
)),
JsonPathMatchers.hasJsonPath("$._embedded.feature.resourcetypes",
Matchers.hasItem(is("authorization"))),
JsonPathMatchers.hasJsonPath("$.id",
Matchers.anyOf(
Matchers.startsWith(eperson.getID().toString()),
Matchers.endsWith(siteRest.getUniqueType() + "_" + siteRest.getId()))))
)
)
)
.andExpect(jsonPath("$._links.self.href",
Matchers.containsString("/api/authz/authorizations/search/object")))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", greaterThanOrEqualTo(1)));

// verify that it works for authenticated users
getClient(epersonToken).perform(get("/api/authz/authorizations/search/object")
.param("uri", siteUri))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.authorizations", Matchers.hasSize(greaterThanOrEqualTo(1))))
.andExpect(jsonPath("$._embedded.authorizations", Matchers.everyItem(
Matchers.anyOf(
JsonPathMatchers.hasJsonPath("$.type", is("authorization")),
JsonPathMatchers.hasJsonPath("$._embedded.feature",
Matchers.allOf(
is(alwaysTrue.getName())
)),
JsonPathMatchers.hasJsonPath("$._embedded.feature",
Matchers.not(Matchers.anyOf(
is(alwaysFalse.getName()),
is(alwaysException.getName()),
is(trueForTestUsers.getName()),
is(trueForAdmins.getName())
)
)),
JsonPathMatchers.hasJsonPath("$._embedded.feature.resourcetypes",
Matchers.hasItem(is("authorization"))),
JsonPathMatchers.hasJsonPath("$.id",
Matchers.anyOf(
Matchers.startsWith(eperson.getID().toString()),
Matchers.endsWith(siteRest.getUniqueType() + "_" + siteRest.getId()))))
)
)
)
.andExpect(jsonPath("$._links.self.href",
Matchers.containsString("/api/authz/authorizations/search/object")))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", greaterThanOrEqualTo(1)));

// verify that it works for anonymous users
getClient(epersonToken).perform(get("/api/authz/authorizations/search/object")
.param("uri", siteUri))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.authorizations", Matchers.hasSize(greaterThanOrEqualTo(1))))
.andExpect(jsonPath("$._embedded.authorizations", Matchers.everyItem(
Matchers.anyOf(
JsonPathMatchers.hasJsonPath("$.type", is("authorization")),
JsonPathMatchers.hasJsonPath("$._embedded.feature",
Matchers.allOf(
is(alwaysTrue.getName())
)),
JsonPathMatchers.hasJsonPath("$._embedded.feature",
Matchers.not(Matchers.anyOf(
is(alwaysFalse.getName()),
is(alwaysException.getName()),
is(trueForTestUsers.getName()),
is(trueForAdmins.getName())
)
)),
JsonPathMatchers.hasJsonPath("$._embedded.feature.resourcetypes",
Matchers.hasItem(is("authorization"))),
JsonPathMatchers.hasJsonPath("$.id",
Matchers.anyOf(
Matchers.startsWith(eperson.getID().toString()),
Matchers.endsWith(siteRest.getUniqueType() + "_" + siteRest.getId()))))
)
)
)
.andExpect(jsonPath("$._links.self.href",
Matchers.containsString("/api/authz/authorizations/search/object")))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", greaterThanOrEqualTo(1)));
}

@Test
/**
* Verify that the findByObject return the 401 Unauthorized response when an eperson is involved
Expand Down
4 changes: 4 additions & 0 deletions dspace/config/dspace.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ csvexport.dir = ${dspace.dir}/exports
# and is usually "synced" with the "rest" section in the DSpace User Interface's config.*.yml.
# It corresponds to the URL that you would type into your browser to access the REST API.
dspace.server.url = http://localhost:8080/server
# Additional URL of DSpace backend which could be used by DSpace frontend during SSR execution.
# May require a port number if not using standard ports (80 or 443)
# DO NOT end it with '/'.
dspace.server.ssr.url =

# Public URL of DSpace frontend (Angular UI). May require a port number if not using standard ports (80 or 443)
# DO NOT end it with '/'.
Expand Down
5 changes: 5 additions & 0 deletions dspace/config/local.cfg.EXAMPLE
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ dspace.dir=/dspace
# It corresponds to the URL that you would type into your browser to access the REST API.
dspace.server.url = http://localhost:8080/server

# Additional URL of DSpace backend which could be used by DSpace frontend during SSR execution.
# May require a port number if not using standard ports (80 or 443)
# DO NOT end it with '/'.
dspace.server.ssr.url =

# Public URL of DSpace frontend (Angular UI). May require a port number if not using standard ports (80 or 443)
# DO NOT end it with '/'.
# This is used by the backend to provide links in emails, RSS feeds, Sitemaps, etc.
Expand Down

0 comments on commit 39c9ef1

Please sign in to comment.