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

tul/merge-into-clarin-dspace #402

Merged
merged 11 commits into from
Aug 8, 2023
2 changes: 1 addition & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,4 @@ jobs:
--request POST \
https://api.github.com/repos/dataquest-dev/\
dspace-angular/actions/workflows/deploy.yml/dispatches \
--data "{\"ref\":\"refs/heads/dtq-dev-7.5\"}"
--data "{\"ref\":\"refs/heads/dtq-dev\"}"
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,10 @@ private String getItemIdentifier(Item item) {
public void trackBitstreamDownload(Context context, HttpServletRequest request, Bitstream bit) throws SQLException {
// We only track a download request when serving a request without Range header. Do not track the
// download if the downloading continues or the tracking is not allowed by the configuration.
if (StringUtils.isNotBlank(request.getHeader("Range")) &&
BooleanUtils.isFalse(configurationService.getBooleanProperty("matomo.track.enabled"))) {
if (StringUtils.isNotBlank(request.getHeader("Range"))) {
return;
}
if (BooleanUtils.isFalse(configurationService.getBooleanProperty("matomo.track.enabled"))) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,25 @@
/* Created for LINDAT/CLARIN */
package org.dspace.authenticate.clarin;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* Helper class for request headers.
* Class is copied from UFAL/CLARIN-DSPACE (https://github.com/ufal/clarin-dspace) and modified by
* @author Milan Majchrak (milan.majchrak at dataquest.sk)
*/
public class Headers {

private static final Logger log = LogManager.getLogger(org.dspace.authenticate.clarin.Headers.class);
// variables
//

Expand Down Expand Up @@ -56,7 +61,7 @@ public void initialise(HttpServletRequest request, String header_separator, List
List<String> vals = new ArrayList<String>();
Enumeration e_vals = request.getHeaders(key);
while (e_vals.hasMoreElements()) {
String values = (String)e_vals.nextElement();
String values = updateValueByCharset((String) e_vals.nextElement());
vals.addAll( header2values(values) );
}

Expand Down Expand Up @@ -149,4 +154,20 @@ private List<String> header2values(String header) {

return values;
}


/**
* Convert ISO header value to UTF-8
* @param value ISO header value String
* @return
*/
private String updateValueByCharset(String value) {
try {
return new String(value.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException ex) {
log.warn("Failed to reconvert shibboleth attribute with value ("
+ value + ").", ex);
}
return value;
}
}
3 changes: 3 additions & 0 deletions dspace-api/src/test/data/dspaceFolder/config/local.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,6 @@ authority.controlled.dspace.object.owner = true
# Configuration required for thorough testing of browse links
webui.browse.link.1 = author:dc.contributor.*
webui.browse.link.2 = subject:dc.subject.*

# If the versioning is disabled Versioning Integration Tests will fail - allow it for the tests
versioning.enabled=true
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.function.Predicate;
import javax.servlet.Filter;

import org.dspace.app.rest.filter.DSpaceRequestContextFilter;
Expand Down Expand Up @@ -39,6 +40,8 @@
import org.springframework.lang.NonNull;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
Expand Down Expand Up @@ -167,6 +170,23 @@ protected LinkRelationProvider dspaceLinkRelationProvider() {
return new DSpaceLinkRelationProvider();
}

/**
* StrictHttpFirewall doesn't allow ISO header values by default. It could throw an error during Shibboleth
* authentication if the user has UTF-8 characters in the name.
* Updated allowedHeaderValues without any regex - it allows every character.
* @return
*/
@Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
Predicate<String> test = (s) -> {
return true;
};

firewall.setAllowedHeaderValues(test);
return firewall;
}

@Bean
public WebMvcConfigurer webMvcConfigurer() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ public class ClarinShibbolethLoginFilter extends StatelessLoginFilter {

public static final String VERIFICATION_TOKEN_HEADER = "Verification-Token";

private static final Logger log = LogManager.getLogger(org.dspace.app.rest.security.ShibbolethLoginFilter.class);
private static final Logger log = LogManager.getLogger(org.dspace.app.rest.security.clarin.
ClarinShibbolethLoginFilter.class);

/**
* Property which handles information if the IdP send required information.
Expand Down Expand Up @@ -176,6 +177,11 @@ public Authentication attemptAuthentication(HttpServletRequest req,
}
}

// logging
log.info("Shib-Identity-Provider: " + idp);
log.info("authentication-shibboleth.netid-header: " + netidHeader + " with value: " + netid);
log.info("authentication-shibboleth.email-header: " + emailHeader + " with value: " + email);

try {
if (StringUtils.isEmpty(netid) || StringUtils.isEmpty(idp)) {
log.error("Cannot load the netid or idp from the request headers.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,4 +458,35 @@ public void testRedirectToGivenUntrustedUrl() throws Exception {
.header("SHIB-NETID", NET_ID_TEST_EPERSON))
.andExpect(status().isBadRequest());
}

@Test
public void testUTF8ShibHeaders() throws Exception {
// NOTE: The initial call to /shibboleth comes *from* an external Shibboleth site. So, it is always
// unauthenticated, but it must include some expected SHIB attributes.
// SHIB-MAIL attribute is the default email header sent from Shibboleth after a successful login.
// In this test we are simply mocking that behavior by setting it to an existing EPerson.
String token = getClient().perform(get("/api/authn/shibboleth")
.header("SHIB-MAIL", clarinEperson.getEmail())
.header("Shib-Identity-Provider", IDP_TEST_EPERSON)
.header("SHIB-NETID", NET_ID_TEST_EPERSON)
.header("SHIB-GIVENNAME", "knihovna KůÅ\u0088 test ŽluÅ¥ouÄ\u008Dký"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost:4000"))
.andReturn().getResponse().getHeader("Authorization");


getClient(token).perform(get("/api/authn/status"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.authenticated", is(true)))
.andExpect(jsonPath("$.authenticationMethod", is("shibboleth")));

getClient(token).perform(
get("/api/authz/authorizations/search/object")
.param("embed", "feature")
.param("feature", feature)
.param("uri", utils.linkToSingleResource(ePersonRest, "self").getHref()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.page.totalElements", is(0)))
.andExpect(jsonPath("$._embedded").doesNotExist());
}
}
45 changes: 45 additions & 0 deletions dspace/config/clarin-dspace.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,48 @@ statistics.cache-server.uri = http://cache-server.none

##### Importing #####
import.metadata.field.not.update = dc.description.provenance, dc.date.available, dc.date.accessioned, dc.identifier.uri

#------------------------------------------------------------------#
#-------------------------Configure DOI----------------------------#
#------------------------------------------------------------------#

# Credentials used to authenticate against the registration agency:
identifier.doi.user = username
identifier.doi.password = password
# DOI prefix used to mint DOIs. All DOIs minted by DSpace will use this prefix.
# The Prefix will be assigned by the registration agency.
identifier.doi.prefix = 10.5072
# If you want to, you can further separate your namespace. Should all the
# suffixes of all DOIs minted by DSpace start with a special string to separate
# it from other services also minting DOIs under your prefix?
identifier.doi.namespaceseparator = dspace/

##
## Configure XSLT-driven submission crosswalk for DataCite
##
crosswalk.dissemination.DataCite.stylesheet = crosswalks/DIM2DataCite.xsl
crosswalk.dissemination.DataCite.schemaLocation = \
http://datacite.org/schema/kernel-3 \
http://schema.datacite.org/meta/kernel-3/metadata.xsd
crosswalk.dissemination.DataCite.preferList = false
crosswalk.dissemination.DataCite.publisher = My University
#crosswalk.dissemination.DataCite.dataManager = # defaults to publisher
#crosswalk.dissemination.DataCite.hostingInstitution = # defaults to publisher
crosswalk.dissemination.DataCite.namespace = http://datacite.org/schema/kernel-3

# consumer to update metadata of DOIs
event.consumer.doi.class = org.dspace.identifier.doi.DOIConsumer
event.consumer.doi.filters = Item+Modify_Metadata

# Add doi here if you are using org.dspace.identifier.DOIIdentifierProvider to generate DOIs.
# Adding doi here makes DSpace send metadata updates to your doi registration agency.
# Add rdf here, if you are using dspace-rdf to export your repository content as RDF.
# Add iiif here, if you are using dspace-iiif.
event.dispatcher.default.consumers = versioning, discovery, eperson

# Edit Item - Status option
identifiers.item-status.register-doi = false

##### Dataquest URL - sing in the footer #####
themed.by.url = https://www.dataquest.sk/dspace
themed.by.company.name = dataquest s.r.o.
7 changes: 6 additions & 1 deletion dspace/config/dspace.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ identifier.doi.user = username
identifier.doi.password = password

# URL for the DOI resolver. This will be the stem for generated DOIs.
#identifier.doi.resolver = https://doi.org
# identifier.doi.resolver = https://doi.org

# DOI prefix used to mint DOIs. All DOIs minted by DSpace will use this prefix.
# The Prefix will be assigned by the registration agency.
Expand Down Expand Up @@ -1157,6 +1157,11 @@ webui.browse.index.1 = dateissued:item:dateissued
webui.browse.index.2 = author:metadata:dc.contributor.*\,dc.creator:text
webui.browse.index.3 = title:item:title
webui.browse.index.4 = subject:metadata:dc.subject.*:text
# webui.browse.index.5 = publisher:metadata:dc.publisher:text
# webui.browse.index.6 = language:metadata:dc.language.iso:iso_lang
# webui.browse.index.7 = itemtype:metadata:dc.type:text
# webui.browse.index.8 = rights:metadata:dc.rights.label:text


## example of authority-controlled browse category - see authority control config
#webui.browse.index.5 = lcAuthor:metadataAuthority:dc.contributor.author:authority
Expand Down
10 changes: 10 additions & 0 deletions dspace/config/modules/rest.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ rest.properties.exposed = dspace.name
rest.properties.exposed = dspace.ui.url
rest.properties.exposed = versioning.item.history.include.submitter
rest.properties.exposed = statistics.cache-server.uri
rest.properties.exposed = themed.by.url
rest.properties.exposed = themed.by.company.name
rest.properties.exposed = identifier.doi.resolver
# TUL
rest.properties.exposed = dspace.ui.url
rest.properties.exposed = versioning.item.history.include.submitter
rest.properties.exposed = statistics.cache-server.uri
rest.properties.exposed = citace.pro.url
rest.properties.exposed = citace.pro.university
rest.properties.exposed = citace.pro.allowed


#---------------------------------------------------------------#
Expand Down
2 changes: 1 addition & 1 deletion dspace/config/spring/api/core-services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
<!-- Matomo statistics -->
<bean class="org.matomo.java.tracking.MatomoTracker">
<!-- TODO change me -->
<constructor-arg value="http://dev-5.pc:8135/matomo.php"/>
<constructor-arg value="http://url:port/matomo.php"/>
</bean>
<bean class="org.dspace.app.statistics.clarin.ClarinMatomoBitstreamTracker"/>
<bean class="org.dspace.app.statistics.clarin.ClarinMatomoOAITracker"/>
Expand Down
Loading