Skip to content

Commit

Permalink
Merge pull request #53 from CityOfNewYork/develop
Browse files Browse the repository at this point in the history
Government Publications Portal v2.2
  • Loading branch information
zgary authored Apr 1, 2019
2 parents 7e01c8c + 6de1f8f commit 7105b65
Show file tree
Hide file tree
Showing 29 changed files with 414 additions and 452 deletions.
6 changes: 3 additions & 3 deletions build_scripts/dspace_install/dspace.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -1030,7 +1030,7 @@ webui.strengths.show = false
#
# For compatibility with previous versions:
#
webui.browse.index.1 = dateissued:item:dateissued
webui.browse.index.1 = dateissued:item:dateissued:desc
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
Expand Down Expand Up @@ -1164,7 +1164,7 @@ recent.submissions.count = 0
# name of the browse index to display collection's items.
# You can set a "item" type of browse index only.
# default = title
#webui.collectionhome.browse-name = title
webui.collectionhome.browse-name = dateissued

# how mamy items should be displayed per page in collection home page
# default = 20
Expand All @@ -1174,7 +1174,7 @@ recent.submissions.count = 0
# If true and the sort option "dateaccessioned" exists, use "dateaccessioned" as a sort option.
# Otherwise use the sort option pertaining the specified browse index.
# default = true
#webui.collectionhome.use.dateaccessioned = true
webui.collectionhome.use.dateaccessioned = false

# tell the community and collection pages that we are using the Recent
# Submissions code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public String loginPageTitle(Context context) {
* Authenticate the user in dspace after successful SAML login.
* SAML entities will be stored in SAMLCredential object inside Authentication.
*
* Query database if eperson exists by guid and userType.
* Query database if eperson exists by guid.
* If eperson does not exist, call registerNewEPerson method to create
* new eperson object.
* If eperson exist, call updateEPerson to update user attributes.
Expand Down Expand Up @@ -149,24 +149,24 @@ public int authenticate(Context context,
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SAMLCredential credential = (SAMLCredential) authentication.getCredentials();

// Check if eperson exists by guid and userType
// Check if eperson exists by guid
EPerson eperson = null;
eperson = ePersonService.findByGuidAndUserType(context,
credential.getAttributeAsString("GUID"),
credential.getAttributeAsString("userType"));
eperson = ePersonService.findByGuid(context, credential.getAttributeAsString("GUID"));

// If eperson cannot be found by guid and userType, query by email
// If eperson cannot be found by guid, query by email
if (eperson == null) {
eperson = ePersonService.findByEmail(context, credential.getAttributeAsString("mail"));
}

String nycEmployee = request.getAttribute("nyc.employee").toString();

// Update or create user
try {
if (eperson != null) {
if (!eperson.canLogIn()) {
return BAD_ARGS;
} else {
updateEPerson(context, credential, eperson);
updateEPerson(context, credential, eperson, nycEmployee);

if (eperson.getLastActive() != null) {
String pattern = "EEEEE MMMMM dd yyyy HH:mm:ss";
Expand Down Expand Up @@ -216,11 +216,9 @@ public String loginPageURL (Context context,

/**
* Register a new eperson object. This method is called when no existing user was
* found for the guid and userType and autoregister is enabled. When these conditions
* found for the guid and autoregister is enabled. When these conditions
* are met this method will create a new eperson object.
*
*
*
* @param context
* The current DSpace database context
*
Expand All @@ -232,7 +230,7 @@ public String loginPageURL (Context context,
*
* @return eperson
* @throws SQLException if database error
* @throws AuthorizeException
* @throws AuthorizeException if database error on update
*/
private EPerson registerNewEPerson(Context context, SAMLCredential credential, HttpServletRequest request)
throws SQLException, AuthorizeException {
Expand All @@ -243,7 +241,7 @@ private EPerson registerNewEPerson(Context context, SAMLCredential credential, H
eperson.setGuid(context, credential.getAttributeAsString("GUID"));
eperson.setFirstName(context, credential.getAttributeAsString("givenName"));
eperson.setLastName(context, credential.getAttributeAsString("sn"));
eperson.setUserType(context, credential.getAttributeAsString("userType"));
eperson.setNYCEmployee(context, request.getAttribute("nyc.employee").toString());
eperson.setCanLogIn(true);
authenticationService.initEPerson(context, request, eperson);
ePersonService.update(context, eperson);
Expand All @@ -266,16 +264,16 @@ private EPerson registerNewEPerson(Context context, SAMLCredential credential, H
* The eperson object to update.
*
* @throws SQLException if database error
* @throws AuthorizeException
* @throws AuthorizeException if database error on update
*/
private void updateEPerson(Context context, SAMLCredential credential, EPerson eperson)
private void updateEPerson(Context context, SAMLCredential credential, EPerson eperson, String nycEmployee)
throws SQLException, AuthorizeException {
context.turnOffAuthorisationSystem();

eperson.setGuid(context, credential.getAttributeAsString("GUID"));
eperson.setFirstName(context, credential.getAttributeAsString("givenName"));
eperson.setLastName(context, credential.getAttributeAsString("sn"));
eperson.setUserType(context, credential.getAttributeAsString("userType"));
eperson.setNYCEmployee(context, nycEmployee);

ePersonService.update(context, eperson);
context.dispatchEvents();
Expand Down
8 changes: 4 additions & 4 deletions dspace-api/src/main/java/org/dspace/eperson/EPerson.java
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,15 @@ public void setGuid(Context context, String guid) throws SQLException {
/**
* Get the e-person's user type
*/
public String getUserType() {
return getePersonService().getMetadataFirstValue(this, "eperson", "userType", null, Item.ANY);
public String getNYCEmployee() {
return getePersonService().getMetadataFirstValue(this, "eperson", "nycEmployee", null, Item.ANY);
}

/**
* Set the e-person's user type
*/
public void setUserType(Context context, String userType) throws SQLException {
getePersonService().setMetadataSingleValue(context, this, "eperson", "userType", null, null, userType);
public void setNYCEmployee(Context context, String nycEmployee) throws SQLException {
getePersonService().setMetadataSingleValue(context, this, "eperson", "nycEmployee", null, null, nycEmployee);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,26 +104,23 @@ public EPerson findByNetid(Context context, String netId) throws SQLException {

/**
* This method overrides method in {@link EPersonService}.
* We get the MetadataField objects for guid and userType here instead of
* We get the MetadataField objects for guid here instead of
* in ePersonDAO because metadataFieldService is already initialized in
* this class.
*
* @param context
* DSpace context
* @param guid
* eperson's guid
* @param userType
* eperson's userType
*
* @return result of ePersonDAO.findByGuidAndUserType, which is null or an eperson
* @return result of ePersonDAO.findByGuid, which is null or an eperson
* @throws SQLException if database error
*/
@Override
public EPerson findByGuidAndUserType(Context context, String guid, String userType) throws SQLException {
public EPerson findByGuid(Context context, String guid) throws SQLException {
MetadataField guidField = metadataFieldService.findByElement(context, "eperson", "guid", null);
MetadataField userTypeField = metadataFieldService.findByElement(context, "eperson", "userType", null);

return ePersonDAO.findByGuidAndUserType(context, guid, userType, Arrays.asList(guidField, userTypeField));
return ePersonDAO.findByGuid(context, guid, guidField);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public interface EPersonDAO extends DSpaceObjectDAO<EPerson>, DSpaceObjectLegacy

public EPerson findByNetid(Context context, String netid) throws SQLException;

public EPerson findByGuidAndUserType(Context context, String guid, String userType, List<MetadataField> queryFields) throws SQLException;
public EPerson findByGuid(Context context, String guid, MetadataField guidField) throws SQLException;

public List<EPerson> search(Context context, String query, List<MetadataField> queryFields, List<MetadataField> sortFields, int offset, int limit) throws SQLException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,39 +61,27 @@ public EPerson findByNetid(Context context, String netid) throws SQLException

/**
* Create a query that joins the eperson table with the metadatavalue table
* and checks if an eperson exists with the specified guid and userType.
* and checks if an eperson exists with the specified guid
*
* @param context
* The DSpace database context.
*
* @param guid
* The guid to query for.
*
* @param userType
* The userType to query for.
*
* @param queryFields
* List of MetadataField objects.
*
* @return eperson or null
* @throws SQLException if database error
*/
@Override
public EPerson findByGuidAndUserType(Context context, String guid, String userType, List<MetadataField> queryFields)
public EPerson findByGuid(Context context, String guid, MetadataField guidField)
throws SQLException {
Query query = createQuery(context,
"SELECT eperson FROM EPerson as eperson " +
"left join eperson.metadata eperson_guid " +
"join eperson.metadata eperson_guid " +
"WITH eperson_guid.metadataField.id = :eperson_guid " +
"left join eperson.metadata eperson_userType " +
"WITH eperson_userType.metadataField.id = :eperson_userType " +
"WHERE eperson_guid.value = :guidValue AND eperson_userType.value = :userTypeValue");
"WHERE eperson_guid.value = :guidValue");
query.setParameter("guidValue", guid);
query.setParameter("userTypeValue", userType);

for (MetadataField metadataField : queryFields) {
query.setParameter(metadataField.toString(), metadataField.getID());
}
query.setParameter(guidField.toString(), guidField.getID());

return singleResult(query);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,16 @@ public EPerson findByNetid(Context context, String netId)
throws SQLException;

/**
* Find the eperson by their guid and userType.
* Find the eperson by their guid.
*
* @param context
* DSpace context
* @param guid
* eperson's guid
* @param userType
* eperson's userType
*
* @return EPerson, or {@code null} if none such exists
*/
public EPerson findByGuidAndUserType(Context context, String guid, String userType) throws SQLException;
public EPerson findByGuid(Context context, String guid) throws SQLException;

/**
* Find the epeople that match the search query across firstname, lastname or email.
Expand Down
114 changes: 114 additions & 0 deletions dspace-api/src/main/java/org/dspace/saml/NYCSingleLogoutImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.dspace.saml;

import org.joda.time.DateTime;
import org.opensaml.common.SAMLException;
import org.opensaml.common.SAMLObject;
import org.opensaml.saml2.core.*;
import org.opensaml.xml.encryption.DecryptionException;
import org.springframework.security.saml.SAMLCredential;
import org.springframework.security.saml.SAMLStatusException;
import org.springframework.security.saml.context.SAMLMessageContext;
import org.springframework.security.saml.util.SAMLUtil;
import org.springframework.security.saml.websso.SingleLogoutProfileImpl;

import java.util.Iterator;

public class NYCSingleLogoutImpl extends SingleLogoutProfileImpl {

@Override
public boolean processLogoutRequest(SAMLMessageContext context, SAMLCredential credential) throws SAMLException {
SAMLObject message = context.getInboundSAMLMessage();
if (message != null && message instanceof LogoutRequest) {
LogoutRequest logoutRequest = (LogoutRequest)message;
if (!context.isInboundSAMLMessageAuthenticated() && context.getLocalExtendedMetadata().isRequireLogoutRequestSigned()) {
throw new SAMLStatusException("urn:oasis:names:tc:SAML:2.0:status:RequestDenied", "LogoutRequest is required to be signed by the entity policy");
} else {
try {
this.verifyEndpoint(context.getLocalEntityEndpoint(), logoutRequest.getDestination());
} catch (SAMLException var14) {
throw new SAMLStatusException("urn:oasis:names:tc:SAML:2.0:status:RequestDenied", "Destination of the LogoutRequest does not match any of the single logout endpoints");
}

try {
if (logoutRequest.getIssuer() != null) {
Issuer issuer = logoutRequest.getIssuer();
this.verifyIssuer(issuer, context);
}
} catch (SAMLException var13) {
throw new SAMLStatusException("urn:oasis:names:tc:SAML:2.0:status:RequestDenied", "Issuer of the LogoutRequest is unknown");
}

DateTime time = logoutRequest.getIssueInstant();
if (!SAMLUtil.isDateTimeSkewValid(this.getResponseSkew(), time)) {
throw new SAMLStatusException("urn:oasis:names:tc:SAML:2.0:status:Requester", "LogoutRequest issue instant is either too old or with date in the future");
} else if (credential == null) {
throw new SAMLStatusException("urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal", "No user is logged in");
} else {
boolean indexFound = false;
if (logoutRequest.getSessionIndexes() != null && logoutRequest.getSessionIndexes().size() > 0) {
Iterator var7 = credential.getAuthenticationAssertion().getAuthnStatements().iterator();

label71:
while(true) {
String statementIndex;
do {
if (!var7.hasNext()) {
break label71;
}

AuthnStatement statement = (AuthnStatement)var7.next();
statementIndex = statement.getSessionIndex();
} while(statementIndex == null);

Iterator var10 = logoutRequest.getSessionIndexes().iterator();

while(var10.hasNext()) {
SessionIndex index = (SessionIndex)var10.next();
if (statementIndex.equals(index.getSessionIndex())) {
indexFound = true;
}
}
}
} else {
indexFound = true;
}

if (!indexFound) {
return true;
} else {
try {
NameID nameID = this.getNameID(context, logoutRequest);
if (nameID != null && this.equalsNameID(credential.getNameID(), nameID)) {
return true;
} else {
throw new SAMLStatusException("urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal", "The requested NameID is invalid");
}
} catch (DecryptionException var12) {
throw new SAMLStatusException("urn:oasis:names:tc:SAML:2.0:status:Responder", "The NameID can't be decrypted", var12);
}
}
}
}
} else {
throw new SAMLException("Message is not of a LogoutRequest object type");
}
}

private boolean equalsNameID(NameID a, NameID b) {
boolean equals = !this.differ(a.getSPProvidedID(), b.getSPProvidedID());
equals = equals && !this.differ(a.getValue(), b.getValue());
equals = equals && !this.differ(a.getFormat(), b.getFormat());
equals = equals && !this.differ(a.getNameQualifier(), b.getNameQualifier());
equals = equals && !this.differ(a.getSPNameQualifier(), b.getSPNameQualifier());
equals = equals && !this.differ(a.getSPProvidedID(), b.getSPProvidedID());
return equals;
}

private boolean differ(Object a, Object b) {
if (a == null) {
return b != null;
} else {
return !a.equals(b);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.dspace.saml.configuration;

import org.opensaml.Configuration;
import org.opensaml.xml.security.BasicSecurityConfiguration;
import org.opensaml.xml.signature.SignatureConstants;
import org.springframework.beans.factory.InitializingBean;

public class SAMLConfigurationBean implements InitializingBean {

/**
* Configure bean to use SHA-256.
*/
@Override
public void afterPropertiesSet() {
BasicSecurityConfiguration config = (BasicSecurityConfiguration) Configuration.getGlobalSecurityConfiguration();
config.registerSignatureAlgorithmURI("RSA", SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
config.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256);
}
}
Loading

0 comments on commit 7105b65

Please sign in to comment.