From 439017090da3278f5e689b5732b658f964fa1b79 Mon Sep 17 00:00:00 2001 From: stea-uw Date: Tue, 16 Apr 2024 11:24:03 -0700 Subject: [PATCH] Apply google-java-format to the codebase in bulk Doing this now will prevent spurious diffs in the future --- .../iam/registry/accessctrl/AccessCtrl.java | 378 +- .../accessctrl/AccessCtrlManager.java | 13 +- .../accessctrl/AccessCtrlManagerDB.java | 256 +- .../exception/AccessCtrlException.java | 5 +- .../exception/AttributeException.java | 3 + .../exception/AttributeNotFoundException.java | 3 + .../exception/FilterPolicyException.java | 3 + .../exception/NoPermissionException.java | 3 + .../registry/exception/ProxyException.java | 5 +- .../exception/RelyingPartyException.java | 3 + .../iam/registry/filter/Attribute.java | 206 +- .../iam/registry/filter/AttributeDAO.java | 6 +- .../iam/registry/filter/AttributeDAOXML.java | 222 +- .../filter/AttributeFilterPolicy.java | 396 +- .../iam/registry/filter/AttributeRule.java | 175 +- .../registry/filter/DBFilterPolicyDAO.java | 728 ++-- .../iam/registry/filter/FilterPolicyDAO.java | 35 +- .../registry/filter/FilterPolicyGroup.java | 42 +- .../registry/filter/FilterPolicyManager.java | 36 +- .../filter/FilterPolicyManagerImpl.java | 289 +- .../washington/iam/registry/filter/Rule.java | 134 +- .../iam/registry/filter/ValueRule.java | 216 +- .../registry/filter/XMLFilterPolicyDAO.java | 181 +- .../registry/filter/XMLFilterPolicyGroup.java | 645 ++- .../washington/iam/registry/proxy/Proxy.java | 116 +- .../iam/registry/proxy/ProxyIdp.java | 161 +- .../iam/registry/proxy/ProxyManager.java | 30 +- .../iam/registry/proxy/ProxyManagerDB.java | 216 +- .../registry/rp/AssertionConsumerService.java | 157 +- .../iam/registry/rp/ContactPerson.java | 224 +- .../iam/registry/rp/DBMetadata.java | 587 +-- .../iam/registry/rp/HistoryItem.java | 157 +- .../iam/registry/rp/KeyDescriptor.java | 209 +- .../iam/registry/rp/ManageNameIDService.java | 99 +- .../iam/registry/rp/MetadataDAO.java | 44 +- .../iam/registry/rp/Organization.java | 156 +- .../iam/registry/rp/RelyingParty.java | 1057 ++--- .../registry/rp/RelyingPartyComparator.java | 44 +- .../iam/registry/rp/RelyingPartyEntry.java | 30 +- .../rp/RelyingPartyEntryComparator.java | 16 +- .../registry/rp/RelyingPartyIdComparator.java | 27 +- .../iam/registry/rp/RelyingPartyManager.java | 75 +- .../registry/rp/RelyingPartyManagerImpl.java | 544 ++- .../iam/registry/rp/SchemaVerifier.java | 102 +- .../registry/rp/TrustAnyX509TrustManager.java | 14 +- .../iam/registry/rp/UuidManager.java | 138 +- .../iam/registry/rp/XMLMetadata.java | 661 ++-- .../washington/iam/registry/rp/XMLText.java | 21 +- .../washington/iam/registry/ws/RPCrypt.java | 126 +- .../registry/ws/RelyingPartyController.java | 3458 +++++++++-------- .../iam/tools/ComboDNSVerifier.java | 102 +- .../edu/washington/iam/tools/DNSVerifier.java | 24 +- .../iam/tools/DNSVerifyException.java | 3 + .../java/edu/washington/iam/tools/Group.java | 27 +- .../washington/iam/tools/GroupManager.java | 9 +- .../washington/iam/tools/IamCertificate.java | 138 +- .../iam/tools/IamCertificateException.java | 3 + .../iam/tools/IamCertificateHelper.java | 347 +- .../iam/tools/IamConnectionManager.java | 364 +- .../edu/washington/iam/tools/IamCrypt.java | 126 +- .../washington/iam/tools/IamMailMessage.java | 181 +- .../washington/iam/tools/IamMailSender.java | 134 +- .../iam/tools/IamVelocityConfig.java | 18 +- .../edu/washington/iam/tools/IdpHelper.java | 106 +- .../java/edu/washington/iam/tools/PKCS1.java | 300 +- .../edu/washington/iam/tools/WebClient.java | 568 ++- .../iam/tools/WebClientException.java | 3 + .../edu/washington/iam/tools/XMLHelper.java | 235 +- .../washington/iam/tools/XMLSerializable.java | 2 +- .../iam/tools/gws/GWSDNSVerifier.java | 139 +- .../iam/tools/gws/GWSGroupManager.java | 99 +- .../iam/tools/netact/NetactDNSVerifier.java | 283 +- .../accessctrl/AccessCtrlManagerDBTest.java | 484 ++- .../registry/filter/AttributeDAOXMLTest.java | 54 +- .../filter/DBFilterPolicyDAOTest.java | 838 ++-- .../filter/FilterPolicyManagerTest.java | 47 +- .../filter/XMLFilterPolicyDAOTest.java | 16 +- .../registry/proxy/ProxyManagerDBTest.java | 83 +- .../iam/registry/rp/DBMetadataTest.java | 427 +- .../rp/RelyingPartyManagerImplTest.java | 35 +- 80 files changed, 8791 insertions(+), 8856 deletions(-) diff --git a/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrl.java b/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrl.java index f9e1661..5111571 100644 --- a/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrl.java +++ b/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrl.java @@ -15,197 +15,207 @@ * ======================================================================== */ - package edu.washington.iam.registry.accessctrl; import edu.washington.iam.registry.exception.AccessCtrlException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.Serializable; import java.util.UUID; import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class AccessCtrl implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private Boolean is2FASet; - private Boolean auto2FA; - private String groupAuto2FA; - private Boolean conditional; - private String conditionalGroup; - private String conditionalLink; - private String entityId; - private UUID uuid; - private String startTime; - private String endTime; - private String updatedBy; - - - private String safePy(String in) { - return in.replaceAll("\"","\\\""); - } - - - - - public AccessCtrl(){ - - //is2FASet keeps track if some idiot (like your author) tries to enable conditional AND auto 2fa - //perhaps a better name would have been "is2FASetByUser". If the DB sets the value we don't care. - is2FASet = false; - auto2FA = false; - groupAuto2FA = ""; - conditional = false; - conditionalGroup = ""; - conditionalLink = ""; - entityId = ""; - uuid = null; - startTime = null; - endTime = null; - updatedBy = ""; - - } - - - //"conditional 2fa" is a virtual state--it means auto2fa is true and a group is set to a non-empty string - public Boolean getCond2FA() { - if (auto2FA && getGroupAuto2FA() != "") - { - return true; - } else return false; - } - //for setting the virtual state above - public void setCond2FA(String group) throws AccessCtrlException { - if (is2FASet) { throw new AccessCtrlException("Can't sent Auto 2FA AND Conditional 2FA!!"); } - if (StringUtils.isNotBlank(group)) - { - this.auto2FA = true; - this.groupAuto2FA = group; - is2FASet = true; //2fa is set. We can't set it again - - } else { - throw new AccessCtrlException("tried to set conditional 2FA but provided empty or whitespace string for group name"); - } - - } - - //this is for external stuff to call--if this returns true then the entity ID uses "auto 2fa". Handles the logic - //of figuring out the auto2fa/group-is-populated permutations. - public Boolean getAuto2FA() { - if (auto2FA && getGroupAuto2FA() == "") - { - return true; - } else return false; - } - //like the get method, sets the state to "auto 2fa" without you having to figure out if the group field is populated - //or not - public void setAuto2FA(Boolean auto2FA) throws AccessCtrlException { - if (is2FASet) { throw new AccessCtrlException("Can't sent Auto 2FA AND Conditional 2FA!!"); } - this.auto2FA = auto2FA; - this.groupAuto2FA = ""; - is2FASet = true; //2fa is set. We can't set it again - } - - //only use when DB is setting this property (doesn't have the safety features of the other methods) - //DB needs to be able to set auto2fa and groupAuto2FA properties independently - public void setAuto2FAInternal(Boolean auto2FA) - { - this.auto2FA = auto2FA; - } - //also for DB use only--DB needs to be able to get the "naked" auto2fa state - public Boolean getAuto2FAInternal() { - return this.auto2FA; - } - - public String getGroupAuto2FA() { - //if not null, empty, or only whitespace, return the string - if (StringUtils.isNotBlank(groupAuto2FA)) { return groupAuto2FA; } - //otherwise return a string that is definitely empty (avoids whitespace issues) - else { return ""; } - } - - public void setGroupAuto2FA(String groupAuto2FA) { - this.groupAuto2FA = groupAuto2FA; - } - - public Boolean getConditional() { - return conditional; - } - - public void setConditional(Boolean conditional) { - this.conditional = conditional; - } - - public String getConditionalGroup() { - return conditionalGroup; - } - - public void setConditionalGroup(String conditionalGroup) { +public class AccessCtrl implements Serializable { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private Boolean is2FASet; + private Boolean auto2FA; + private String groupAuto2FA; + private Boolean conditional; + private String conditionalGroup; + private String conditionalLink; + private String entityId; + private UUID uuid; + private String startTime; + private String endTime; + private String updatedBy; + + private String safePy(String in) { + return in.replaceAll("\"", "\\\""); + } + + public AccessCtrl() { + + // is2FASet keeps track if some idiot (like your author) tries to enable conditional AND auto + // 2fa + // perhaps a better name would have been "is2FASetByUser". If the DB sets the value we don't + // care. + is2FASet = false; + auto2FA = false; + groupAuto2FA = ""; + conditional = false; + conditionalGroup = ""; + conditionalLink = ""; + entityId = ""; + uuid = null; + startTime = null; + endTime = null; + updatedBy = ""; + } + + // "conditional 2fa" is a virtual state--it means auto2fa is true and a group is set to a + // non-empty string + public Boolean getCond2FA() { + if (auto2FA && getGroupAuto2FA() != "") { + return true; + } else return false; + } + + // for setting the virtual state above + public void setCond2FA(String group) throws AccessCtrlException { + if (is2FASet) { + throw new AccessCtrlException("Can't sent Auto 2FA AND Conditional 2FA!!"); + } + if (StringUtils.isNotBlank(group)) { + this.auto2FA = true; + this.groupAuto2FA = group; + is2FASet = true; // 2fa is set. We can't set it again + + } else { + throw new AccessCtrlException( + "tried to set conditional 2FA but provided empty or whitespace string for group name"); + } + } + + // this is for external stuff to call--if this returns true then the entity ID uses "auto 2fa". + // Handles the logic + // of figuring out the auto2fa/group-is-populated permutations. + public Boolean getAuto2FA() { + if (auto2FA && getGroupAuto2FA() == "") { + return true; + } else return false; + } + + // like the get method, sets the state to "auto 2fa" without you having to figure out if the group + // field is populated + // or not + public void setAuto2FA(Boolean auto2FA) throws AccessCtrlException { + if (is2FASet) { + throw new AccessCtrlException("Can't sent Auto 2FA AND Conditional 2FA!!"); + } + this.auto2FA = auto2FA; + this.groupAuto2FA = ""; + is2FASet = true; // 2fa is set. We can't set it again + } + + // only use when DB is setting this property (doesn't have the safety features of the other + // methods) + // DB needs to be able to set auto2fa and groupAuto2FA properties independently + public void setAuto2FAInternal(Boolean auto2FA) { + this.auto2FA = auto2FA; + } + + // also for DB use only--DB needs to be able to get the "naked" auto2fa state + public Boolean getAuto2FAInternal() { + return this.auto2FA; + } + + public String getGroupAuto2FA() { + // if not null, empty, or only whitespace, return the string + if (StringUtils.isNotBlank(groupAuto2FA)) { + return groupAuto2FA; + } + // otherwise return a string that is definitely empty (avoids whitespace issues) + else { + return ""; + } + } + + public void setGroupAuto2FA(String groupAuto2FA) { + this.groupAuto2FA = groupAuto2FA; + } + + public Boolean getConditional() { + return conditional; + } + + public void setConditional(Boolean conditional) { + this.conditional = conditional; + } + + public String getConditionalGroup() { + return conditionalGroup; + } + + public void setConditionalGroup(String conditionalGroup) { + this.conditionalGroup = conditionalGroup; + } + + public String getConditionalLink() { + return conditionalLink; + } + + public void setConditionalLink(String conditionalLink) { + this.conditionalLink = conditionalLink; + } + + // for setting conditional access using user input--DB uses plain "unsafe" methods above + public void setConditionalByUser( + Boolean conditional, String conditionalGroup, String conditionalLink) + throws AccessCtrlException { + + if (conditional) { + if (StringUtils.isNotBlank(conditionalGroup)) { this.conditionalGroup = conditionalGroup; - } - - public String getConditionalLink() { - return conditionalLink; - } - - public void setConditionalLink(String conditionalLink) { this.conditionalLink = conditionalLink; - } - - //for setting conditional access using user input--DB uses plain "unsafe" methods above - public void setConditionalByUser(Boolean conditional, String conditionalGroup, String conditionalLink) throws AccessCtrlException { - - if (conditional) { - if (StringUtils.isNotBlank(conditionalGroup)) - { - this.conditionalGroup = conditionalGroup; - this.conditionalLink = conditionalLink; - this.conditional = true; - } else { - throw new AccessCtrlException("tried to set conditional access but provided empty or whitespace" + - "string for group name"); - } - } else { this.conditional = false; } - } - public String getEntityId() { - return entityId; - } - - public void setEntityId(String entityId) { - this.entityId = entityId; - } - - public UUID getUuid() { - return uuid; - } - - public void setUuid(UUID uuid) { - this.uuid = uuid; - } - public String getStartTime() { - return startTime; - } - - public void setStartTime(String startTime) { - this.startTime = startTime; - } - - public String getEndTime() { - return endTime; - } - - public void setEndTime(String endTime) { - this.endTime = endTime; - } - - public String getUpdatedBy() { - return updatedBy; - } - - public void setUpdatedBy(String updatedBy) { - this.updatedBy = updatedBy; - } + this.conditional = true; + } else { + throw new AccessCtrlException( + "tried to set conditional access but provided empty or whitespace" + + "string for group name"); + } + } else { + this.conditional = false; + } + } + + public String getEntityId() { + return entityId; + } + + public void setEntityId(String entityId) { + this.entityId = entityId; + } + + public UUID getUuid() { + return uuid; + } + + public void setUuid(UUID uuid) { + this.uuid = uuid; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } } - diff --git a/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrlManager.java b/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrlManager.java index 67dbb62..229c7d8 100644 --- a/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrlManager.java +++ b/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrlManager.java @@ -18,16 +18,15 @@ package edu.washington.iam.registry.accessctrl; import edu.washington.iam.registry.exception.AccessCtrlException; -import edu.washington.iam.registry.exception.ProxyException; -import edu.washington.iam.registry.proxy.Proxy; - import java.io.Serializable; import java.util.List; public interface AccessCtrlManager extends Serializable { - public AccessCtrl getAccessCtrl(String entityId); - public void updateAccessCtrl(AccessCtrl accessCtrl, String updatedBy) throws AccessCtrlException; - public List getAccessCtrlHistory(String entityId) throws AccessCtrlException; - public int removeAccessCtrl(String entityId, String updatedBy) throws AccessCtrlException; + public AccessCtrl getAccessCtrl(String entityId); + + public void updateAccessCtrl(AccessCtrl accessCtrl, String updatedBy) throws AccessCtrlException; + + public List getAccessCtrlHistory(String entityId) throws AccessCtrlException; + public int removeAccessCtrl(String entityId, String updatedBy) throws AccessCtrlException; } diff --git a/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrlManagerDB.java b/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrlManagerDB.java index 554fd6b..ec8e69b 100644 --- a/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrlManagerDB.java +++ b/src/main/java/edu/washington/iam/registry/accessctrl/AccessCtrlManagerDB.java @@ -2,6 +2,12 @@ import edu.washington.iam.registry.exception.AccessCtrlException; import edu.washington.iam.registry.rp.UuidManager; +import edu.washington.iam.tools.IdpHelper; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -9,135 +15,137 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import edu.washington.iam.tools.IdpHelper; - public class AccessCtrlManagerDB implements AccessCtrlManager { - private final Logger log = LoggerFactory.getLogger(getClass()); - private JdbcTemplate template; - - public void setTemplate(JdbcTemplate template) { - this.template = template; + private final Logger log = LoggerFactory.getLogger(getClass()); + private JdbcTemplate template; + + public void setTemplate(JdbcTemplate template) { + this.template = template; + } + + private IdpHelper idpHelper = null; + + public void setIdpHelper(IdpHelper v) { + idpHelper = v; + } + + @Autowired private UuidManager uuidManager; + + public List getAccessCtrlHistory(String entityId) throws AccessCtrlException { + List AccessCtrlHistory = null; + try { + AccessCtrlHistory = + template.query( + "select * from access_ctrl where end_time is not null and entity_id = ?", + new Object[] {entityId}, + new AccessCtrlMapper()); + return AccessCtrlHistory; + } catch (Exception e) { + String errorMsg = String.format("error getting access control history: %s", entityId); + log.debug(errorMsg); + throw new AccessCtrlException(errorMsg); } - - private IdpHelper idpHelper = null; - public void setIdpHelper(IdpHelper v) { - idpHelper = v; + } + + public AccessCtrl getAccessCtrl(String entityId) { + log.debug("looking for access control for " + entityId); + AccessCtrl accessCtrl = new AccessCtrl(); + + List accessCtrlList = + template.query( + "select * from access_control where entity_id = ? and end_time is null", + new Object[] {entityId}, + new AccessCtrlMapper()); + if (accessCtrlList.size() != 0) { + accessCtrl = accessCtrlList.get(0); } - @Autowired - private UuidManager uuidManager; - - - public List getAccessCtrlHistory(String entityId) throws AccessCtrlException { - List AccessCtrlHistory = null; - try { - AccessCtrlHistory = template.query( - "select * from access_ctrl where end_time is not null and entity_id = ?", - new Object[] {entityId}, - new AccessCtrlMapper()); - return AccessCtrlHistory; - } - catch (Exception e){ - String errorMsg = String.format("error getting access control history: %s", entityId); - log.debug(errorMsg); - throw new AccessCtrlException(errorMsg); - } - + return accessCtrl; + } + + public void updateAccessCtrl(AccessCtrl accessCtrl, String updatedBy) throws AccessCtrlException { + log.debug("looking to update access control for " + accessCtrl.getEntityId()); + + try { + + accessCtrl.setUuid(uuidManager.getUuid(accessCtrl.getEntityId())); + log.info("attempting access control update for " + accessCtrl.getEntityId()); + // recycle "delete" method to mark current record inactive + removeAccessCtrl(accessCtrl.getEntityId(), updatedBy); + log.info("Marked current access control record (if any) inactive--adding new one next"); + // add new active record + log.info( + Integer.toString( + template.update( + "insert into access_control (uuid, entity_id, end_time, start_time, updated_by, auto_2fa," + + "auto_2fa_group, conditional, conditional_group, conditional_link) values " + + "(? ,?, ?, now(), ?, ?, ?, ?, ?, ?)", + accessCtrl.getUuid(), + accessCtrl.getEntityId(), + null, + updatedBy, + accessCtrl.getAuto2FAInternal(), + accessCtrl.getGroupAuto2FA(), + accessCtrl.getConditional(), + accessCtrl.getConditionalGroup(), + accessCtrl.getConditionalLink()))); + log.debug("updated existing access control for " + accessCtrl.getEntityId()); + + if (idpHelper != null) idpHelper.notifyIdps("accessctrl"); + } catch (Exception e) { + log.info("update access control trouble: " + e.getMessage()); + throw new AccessCtrlException("update access control trouble: " + e.getMessage()); } - - public AccessCtrl getAccessCtrl(String entityId) { - log.debug("looking for access control for " + entityId); - AccessCtrl accessCtrl = new AccessCtrl(); - - List accessCtrlList = template.query("select * from access_control where entity_id = ? and end_time is null", - new Object[] {entityId}, - new AccessCtrlMapper()); - if(accessCtrlList.size() != 0){ - accessCtrl = accessCtrlList.get(0); - } - - return accessCtrl; - } - - public void updateAccessCtrl(AccessCtrl accessCtrl, String updatedBy) throws AccessCtrlException { - log.debug("looking to update access control for " + accessCtrl.getEntityId()); - - try { - - accessCtrl.setUuid(uuidManager.getUuid(accessCtrl.getEntityId())); - log.info("attempting access control update for " + accessCtrl.getEntityId()); - //recycle "delete" method to mark current record inactive - removeAccessCtrl(accessCtrl.getEntityId(), updatedBy); - log.info("Marked current access control record (if any) inactive--adding new one next"); - // add new active record - log.info(Integer.toString(template.update( - "insert into access_control (uuid, entity_id, end_time, start_time, updated_by, auto_2fa," + - "auto_2fa_group, conditional, conditional_group, conditional_link) values " + - "(? ,?, ?, now(), ?, ?, ?, ?, ?, ?)", - accessCtrl.getUuid(), accessCtrl.getEntityId(), null, updatedBy, accessCtrl.getAuto2FAInternal(), - accessCtrl.getGroupAuto2FA(), accessCtrl.getConditional(), - accessCtrl.getConditionalGroup(), accessCtrl.getConditionalLink()))); - log.debug("updated existing access control for " + accessCtrl.getEntityId()); - - if (idpHelper!=null) idpHelper.notifyIdps("accessctrl"); - } catch (Exception e) { - log.info("update access control trouble: " + e.getMessage()); - throw new AccessCtrlException("update access control trouble: " + e.getMessage()); - } - - - - + } + + public int removeAccessCtrl(String entityId, String updatedBy) throws AccessCtrlException { + log.debug("looking to delete access control for " + entityId); + + List ids = + template.queryForList( + "select id from access_control where entity_id = ? and end_time is null", + Integer.class, + entityId); + if (ids.size() == 1 && ids.get(0) != null) { + template.update( + "update access_control set end_time = now(), updated_by = ? where id = ?", + updatedBy, + ids.get(0)); + log.info("updated (delete) access control for %s", entityId); + if (idpHelper != null) idpHelper.notifyIdps("accessctrl"); + return 200; + } else if (ids.size() == 0) { + // there is no record with end_time = null if access control has never been enabled + log.info( + String.format( + "No access control found for %s (usually not an error--wasn't set before)", + entityId)); + // if there are no records with end_time = null then there are no active records to remove + // and everything is fine. mattjm 2018-10-23 + return 200; + } else { + throw new AccessCtrlException( + "more than one active access control record found!! No update performed."); + // TODO what about a return code? } - - public int removeAccessCtrl(String entityId, String updatedBy) throws AccessCtrlException { - log.debug("looking to delete access control for " + entityId); - - List ids = template.queryForList( - "select id from access_control where entity_id = ? and end_time is null", - Integer.class, entityId); - if (ids.size() == 1 && ids.get(0) != null) { - template.update("update access_control set end_time = now(), updated_by = ? where id = ?", updatedBy, ids.get(0)); - log.info("updated (delete) access control for %s", entityId); - if (idpHelper!=null) idpHelper.notifyIdps("accessctrl"); - return 200; - } - else if (ids.size() == 0) { - //there is no record with end_time = null if access control has never been enabled - log.info(String.format("No access control found for %s (usually not an error--wasn't set before)", entityId)); - //if there are no records with end_time = null then there are no active records to remove - //and everything is fine. mattjm 2018-10-23 - return 200; - } - else{ - throw new AccessCtrlException("more than one active access control record found!! No update performed."); - //TODO what about a return code? - } - } - - - private static final class AccessCtrlMapper implements ResultSetExtractor> { - @Override - public List extractData(ResultSet rs) throws SQLException, DataAccessException{ - List accessCtrlList = new ArrayList<>(); - while (rs.next()) { - AccessCtrl accessCtrlItem = new AccessCtrl(); - accessCtrlItem.setEntityId(rs.getString("entity_id")); - accessCtrlItem.setUuid((UUID) rs.getObject("uuid")); - accessCtrlItem.setAuto2FAInternal(rs.getBoolean("auto_2fa")); - accessCtrlItem.setConditional(rs.getBoolean("conditional")); - accessCtrlItem.setConditionalGroup(rs.getString("conditional_group")); - accessCtrlItem.setConditionalLink(rs.getString("conditional_link")); - accessCtrlItem.setGroupAuto2FA(rs.getString("auto_2fa_group")); - accessCtrlList.add(accessCtrlItem); - } - return accessCtrlList; - } + } + + private static final class AccessCtrlMapper implements ResultSetExtractor> { + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + List accessCtrlList = new ArrayList<>(); + while (rs.next()) { + AccessCtrl accessCtrlItem = new AccessCtrl(); + accessCtrlItem.setEntityId(rs.getString("entity_id")); + accessCtrlItem.setUuid((UUID) rs.getObject("uuid")); + accessCtrlItem.setAuto2FAInternal(rs.getBoolean("auto_2fa")); + accessCtrlItem.setConditional(rs.getBoolean("conditional")); + accessCtrlItem.setConditionalGroup(rs.getString("conditional_group")); + accessCtrlItem.setConditionalLink(rs.getString("conditional_link")); + accessCtrlItem.setGroupAuto2FA(rs.getString("auto_2fa_group")); + accessCtrlList.add(accessCtrlItem); + } + return accessCtrlList; } + } } diff --git a/src/main/java/edu/washington/iam/registry/exception/AccessCtrlException.java b/src/main/java/edu/washington/iam/registry/exception/AccessCtrlException.java index 906b7f5..2b470ed 100644 --- a/src/main/java/edu/washington/iam/registry/exception/AccessCtrlException.java +++ b/src/main/java/edu/washington/iam/registry/exception/AccessCtrlException.java @@ -21,13 +21,16 @@ public class AccessCtrlException extends Exception { public AccessCtrlException() { super(); } + public AccessCtrlException(String msg) { super(msg); } + public AccessCtrlException(String msg, Throwable cause) { super(msg, cause); } + public AccessCtrlException(Throwable cause) { super(cause); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/washington/iam/registry/exception/AttributeException.java b/src/main/java/edu/washington/iam/registry/exception/AttributeException.java index 492d38e..070bf5a 100644 --- a/src/main/java/edu/washington/iam/registry/exception/AttributeException.java +++ b/src/main/java/edu/washington/iam/registry/exception/AttributeException.java @@ -21,12 +21,15 @@ public class AttributeException extends Exception { public AttributeException() { super(); } + public AttributeException(String msg) { super(msg); } + public AttributeException(String msg, Throwable cause) { super(msg, cause); } + public AttributeException(Throwable cause) { super(cause); } diff --git a/src/main/java/edu/washington/iam/registry/exception/AttributeNotFoundException.java b/src/main/java/edu/washington/iam/registry/exception/AttributeNotFoundException.java index 2b673e0..790e2c4 100644 --- a/src/main/java/edu/washington/iam/registry/exception/AttributeNotFoundException.java +++ b/src/main/java/edu/washington/iam/registry/exception/AttributeNotFoundException.java @@ -21,12 +21,15 @@ public class AttributeNotFoundException extends Exception { public AttributeNotFoundException() { super(); } + public AttributeNotFoundException(String msg) { super(msg); } + public AttributeNotFoundException(String msg, Throwable cause) { super(msg, cause); } + public AttributeNotFoundException(Throwable cause) { super(cause); } diff --git a/src/main/java/edu/washington/iam/registry/exception/FilterPolicyException.java b/src/main/java/edu/washington/iam/registry/exception/FilterPolicyException.java index 908b68e..9cadd2d 100644 --- a/src/main/java/edu/washington/iam/registry/exception/FilterPolicyException.java +++ b/src/main/java/edu/washington/iam/registry/exception/FilterPolicyException.java @@ -21,12 +21,15 @@ public class FilterPolicyException extends Exception { public FilterPolicyException() { super(); } + public FilterPolicyException(String msg) { super(msg); } + public FilterPolicyException(String msg, Throwable cause) { super(msg, cause); } + public FilterPolicyException(Throwable cause) { super(cause); } diff --git a/src/main/java/edu/washington/iam/registry/exception/NoPermissionException.java b/src/main/java/edu/washington/iam/registry/exception/NoPermissionException.java index d72d784..1137c69 100644 --- a/src/main/java/edu/washington/iam/registry/exception/NoPermissionException.java +++ b/src/main/java/edu/washington/iam/registry/exception/NoPermissionException.java @@ -21,12 +21,15 @@ public class NoPermissionException extends Exception { public NoPermissionException() { super(); } + public NoPermissionException(String msg) { super(msg); } + public NoPermissionException(String msg, Throwable cause) { super(msg, cause); } + public NoPermissionException(Throwable cause) { super(cause); } diff --git a/src/main/java/edu/washington/iam/registry/exception/ProxyException.java b/src/main/java/edu/washington/iam/registry/exception/ProxyException.java index edd67e6..866bb51 100644 --- a/src/main/java/edu/washington/iam/registry/exception/ProxyException.java +++ b/src/main/java/edu/washington/iam/registry/exception/ProxyException.java @@ -21,13 +21,16 @@ public class ProxyException extends Exception { public ProxyException() { super(); } + public ProxyException(String msg) { super(msg); } + public ProxyException(String msg, Throwable cause) { super(msg, cause); } + public ProxyException(Throwable cause) { super(cause); } -} \ No newline at end of file +} diff --git a/src/main/java/edu/washington/iam/registry/exception/RelyingPartyException.java b/src/main/java/edu/washington/iam/registry/exception/RelyingPartyException.java index 41ca66c..a7c139c 100644 --- a/src/main/java/edu/washington/iam/registry/exception/RelyingPartyException.java +++ b/src/main/java/edu/washington/iam/registry/exception/RelyingPartyException.java @@ -21,12 +21,15 @@ public class RelyingPartyException extends Exception { public RelyingPartyException() { super(); } + public RelyingPartyException(String msg) { super(msg); } + public RelyingPartyException(String msg, Throwable cause) { super(msg, cause); } + public RelyingPartyException(Throwable cause) { super(cause); } diff --git a/src/main/java/edu/washington/iam/registry/filter/Attribute.java b/src/main/java/edu/washington/iam/registry/filter/Attribute.java index 23addc6..db26ded 100644 --- a/src/main/java/edu/washington/iam/registry/filter/Attribute.java +++ b/src/main/java/edu/washington/iam/registry/filter/Attribute.java @@ -15,117 +15,111 @@ * ======================================================================== */ - package edu.washington.iam.registry.filter; +import edu.washington.iam.registry.exception.AttributeException; import java.io.Serializable; - -import java.util.List; -import java.util.Vector; -import java.util.Arrays; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; - -import edu.washington.iam.registry.exception.AttributeException; -import edu.washington.iam.tools.XMLHelper; - -import edu.washington.iam.registry.exception.FilterPolicyException; - -public class Attribute implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private String id; - private String name; - private String description; - private boolean ferpa; - private boolean hippa; - private String authorizingGroup; - private String type; - // reqHidden = hidden on attribute request page - private boolean reqHidden = false; - private boolean editable = false; - AttributeFilterPolicy attributeFilterPolicy; - AttributeRule attributeRule; - - // create from document element - public Attribute (Element ele) throws AttributeException { - - id = ele.getAttribute("id"); - if (id==null) throw new AttributeException("No id for attribute"); - name = ele.getAttribute("name"); - description = ele.getAttribute("description"); - type = ele.getAttribute("type"); - reqHidden = ele.getAttribute("reqHidden").equals("true"); - - log.debug("create from doc: " + id); - - // get authorized users - authorizingGroup = ele.getAttribute("authorizingGroup"); - - } - - // create from another attribute - public Attribute (Attribute src) { - - id = src.getId(); - name = src.getName(); - description = src.getDescription(); - type = src.getType(); - editable = src.isEditable(); - reqHidden = src.isReqHidden(); - } - - - public void setId(String v) { - id = v; - } - public String getId() { - return (id); - } - public String getName() { - return (name); - } - public String getDescription() { - return description; - } - public String getType() { - return type; - } - public String getAuthorizingGroup() { - return authorizingGroup; - } - public AttributeFilterPolicy getAttributeFilterPolicy() { - return attributeFilterPolicy; - } - public void setAttributeFilterPolicy(AttributeFilterPolicy v) { - attributeFilterPolicy = v; - } - public AttributeRule getAttributeRule() { - return attributeRule; - } - public void setAttributeRule(AttributeRule v) { - attributeRule = v; - } - - public void setEditable(boolean v) { - editable = v; - } - public boolean isEditable() { - return editable; - } - public void setReqHidden(boolean v) { - reqHidden = v; - } - public boolean isReqHidden() { - return reqHidden; - } +public class Attribute implements Serializable { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private String id; + private String name; + private String description; + private boolean ferpa; + private boolean hippa; + private String authorizingGroup; + private String type; + // reqHidden = hidden on attribute request page + private boolean reqHidden = false; + private boolean editable = false; + AttributeFilterPolicy attributeFilterPolicy; + AttributeRule attributeRule; + + // create from document element + public Attribute(Element ele) throws AttributeException { + + id = ele.getAttribute("id"); + if (id == null) throw new AttributeException("No id for attribute"); + name = ele.getAttribute("name"); + description = ele.getAttribute("description"); + type = ele.getAttribute("type"); + reqHidden = ele.getAttribute("reqHidden").equals("true"); + + log.debug("create from doc: " + id); + + // get authorized users + authorizingGroup = ele.getAttribute("authorizingGroup"); + } + + // create from another attribute + public Attribute(Attribute src) { + + id = src.getId(); + name = src.getName(); + description = src.getDescription(); + type = src.getType(); + editable = src.isEditable(); + reqHidden = src.isReqHidden(); + } + + public void setId(String v) { + id = v; + } + + public String getId() { + return (id); + } + + public String getName() { + return (name); + } + + public String getDescription() { + return description; + } + + public String getType() { + return type; + } + + public String getAuthorizingGroup() { + return authorizingGroup; + } + + public AttributeFilterPolicy getAttributeFilterPolicy() { + return attributeFilterPolicy; + } + + public void setAttributeFilterPolicy(AttributeFilterPolicy v) { + attributeFilterPolicy = v; + } + + public AttributeRule getAttributeRule() { + return attributeRule; + } + + public void setAttributeRule(AttributeRule v) { + attributeRule = v; + } + + public void setEditable(boolean v) { + editable = v; + } + + public boolean isEditable() { + return editable; + } + + public void setReqHidden(boolean v) { + reqHidden = v; + } + + public boolean isReqHidden() { + return reqHidden; + } } - diff --git a/src/main/java/edu/washington/iam/registry/filter/AttributeDAO.java b/src/main/java/edu/washington/iam/registry/filter/AttributeDAO.java index 2053ef2..8d02a3e 100644 --- a/src/main/java/edu/washington/iam/registry/filter/AttributeDAO.java +++ b/src/main/java/edu/washington/iam/registry/filter/AttributeDAO.java @@ -1,10 +1,10 @@ package edu.washington.iam.registry.filter; import edu.washington.iam.registry.exception.AttributeNotFoundException; - import java.util.List; public interface AttributeDAO { - List getAttributes(); - Attribute getAttribute(String id) throws AttributeNotFoundException; + List getAttributes(); + + Attribute getAttribute(String id) throws AttributeNotFoundException; } diff --git a/src/main/java/edu/washington/iam/registry/filter/AttributeDAOXML.java b/src/main/java/edu/washington/iam/registry/filter/AttributeDAOXML.java index 35ae457..5941693 100644 --- a/src/main/java/edu/washington/iam/registry/filter/AttributeDAOXML.java +++ b/src/main/java/edu/washington/iam/registry/filter/AttributeDAOXML.java @@ -2,137 +2,135 @@ import edu.washington.iam.registry.exception.AttributeException; import edu.washington.iam.registry.exception.AttributeNotFoundException; -import edu.washington.iam.registry.rp.RelyingParty; import edu.washington.iam.tools.XMLHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import java.io.File; import java.util.List; import java.util.Vector; import java.util.concurrent.locks.ReentrantReadWriteLock; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; public class AttributeDAOXML implements AttributeDAO { - private final Logger log = LoggerFactory.getLogger(getClass()); - private final ReentrantReadWriteLock locker = new ReentrantReadWriteLock(); - - private List attributes; - private String attributeUri; - private String attributeSourceName; - public void setAttributeUri(String v) { - attributeUri = v; - attributeSourceName = attributeUri.replaceFirst("file:",""); - } + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ReentrantReadWriteLock locker = new ReentrantReadWriteLock(); - private int attributeRefresh = 0; // seconds - public void setAttributeRefresh(int i) { - attributeRefresh = i; - } - Thread reloader = null; - private long modifyTime = 0; // for the attrs + private List attributes; + private String attributeUri; + private String attributeSourceName; - @Override - public List getAttributes() { - return attributes; - } + public void setAttributeUri(String v) { + attributeUri = v; + attributeSourceName = attributeUri.replaceFirst("file:", ""); + } - // find an attribute - @Override - public Attribute getAttribute(String id) throws AttributeNotFoundException { - for (int i=0; imodifyTime) { - // reload the attributes - log.debug("reload starting for " + attributeUri); - locker.writeLock().lock(); - try { - loadAttributes(); - } catch (Exception e) { - log.error("reload errro: " + e); - } - locker.writeLock().unlock(); - log.debug("reload completed, time now " + modifyTime); - } - try { - if (isInterrupted()) { - log.info("interrupted during processing"); - break; - } - Thread.sleep(attributeRefresh * 1000); - } catch (InterruptedException e) { - log.info("sleep interrupted"); - break; - } - } - } + @Override + public List getAttributes() { + return attributes; + } + // find an attribute + @Override + public Attribute getAttribute(String id) throws AttributeNotFoundException { + for (int i = 0; i < attributes.size(); i++) { + if (attributes.get(i).getId().equals(id)) return attributes.get(i); + } + throw new AttributeNotFoundException(); + } + + private void loadAttributes() { + attributes = new Vector(); + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + builderFactory.setNamespaceAware(false); + Document doc; + + try { + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + doc = builder.parse(attributeUri); + } catch (Exception e) { + log.error("parse issue: " + e); + return; + } + // update the timestamp + File f = new File(attributeSourceName); + modifyTime = f.lastModified(); + log.debug("attr load " + f.getName() + ": time = " + modifyTime); + + List list = XMLHelper.getElementsByName(doc.getDocumentElement(), "Attribute"); + log.info("found " + list.size()); + + for (int i = 0; i < list.size(); i++) { + Element fpe = list.get(i); + try { + attributes.add(new Attribute(fpe)); + } catch (AttributeException e) { + log.error("load of element failed: " + e); + } } + } - @PostConstruct - public void init() { - loadAttributes(); + // attribute reloader + class AttributeReloader extends Thread { - // start attribute list refresher - if (attributeRefresh>0) { - reloader = new Thread(new AttributeReloader()); - reloader.start(); + public void run() { + log.debug("attr reloader running: interval = " + attributeRefresh); + + while (true) { + log.debug("reloader checking..."); + File f = new File(attributeSourceName); + if (f.lastModified() > modifyTime) { + // reload the attributes + log.debug("reload starting for " + attributeUri); + locker.writeLock().lock(); + try { + loadAttributes(); + } catch (Exception e) { + log.error("reload errro: " + e); + } + locker.writeLock().unlock(); + log.debug("reload completed, time now " + modifyTime); } + try { + if (isInterrupted()) { + log.info("interrupted during processing"); + break; + } + Thread.sleep(attributeRefresh * 1000); + } catch (InterruptedException e) { + log.info("sleep interrupted"); + break; + } + } } + } - @PreDestroy - public void cleanup() { - if (reloader != null) reloader.interrupt(); + @PostConstruct + public void init() { + loadAttributes(); + + // start attribute list refresher + if (attributeRefresh > 0) { + reloader = new Thread(new AttributeReloader()); + reloader.start(); } + } + + @PreDestroy + public void cleanup() { + if (reloader != null) reloader.interrupt(); + } } diff --git a/src/main/java/edu/washington/iam/registry/filter/AttributeFilterPolicy.java b/src/main/java/edu/washington/iam/registry/filter/AttributeFilterPolicy.java index 3cf139b..64d91e4 100644 --- a/src/main/java/edu/washington/iam/registry/filter/AttributeFilterPolicy.java +++ b/src/main/java/edu/washington/iam/registry/filter/AttributeFilterPolicy.java @@ -15,224 +15,226 @@ * ======================================================================== */ - package edu.washington.iam.registry.filter; +import edu.washington.iam.registry.exception.FilterPolicyException; +import edu.washington.iam.registry.rp.RelyingParty; +import edu.washington.iam.tools.XMLHelper; +import edu.washington.iam.tools.XMLSerializable; import java.io.BufferedWriter; import java.io.IOException; - import java.util.List; -import java.util.Vector; import java.util.UUID; - -import edu.washington.iam.tools.XMLSerializable; +import java.util.Vector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.w3c.dom.Element; -import org.w3c.dom.NodeList; import org.w3c.dom.Node; - -import edu.washington.iam.tools.XMLHelper; - -import edu.washington.iam.registry.exception.FilterPolicyException; -import edu.washington.iam.registry.rp.RelyingParty; +import org.w3c.dom.NodeList; public class AttributeFilterPolicy implements XMLSerializable { - private final Logger log = LoggerFactory.getLogger(getClass()); - - private String entityId; - private UUID uuid; - private String start_time; - private String end_time; - private String updatedBy; - private boolean regex; - private boolean editable; - private List attributeRules; - private String policyGroupId; - private String policyGroupDescription; - private boolean category; - - // create from document element ( partly parsed ) - public AttributeFilterPolicy (String type, String name, Element ele, boolean edit, FilterPolicyGroup pg) throws FilterPolicyException { - - editable = edit; - attributeRules = new Vector(); - entityId = name; - policyGroupId = pg.getId(); - policyGroupDescription = pg.getDescription(); - category = false; - if (type.equals("basic:AttributeRequesterString")) regex = false; - else if (type.equals("basic:AttributeRequesterRegex")) regex = true; - else if (type.equals("saml:AttributeRequesterEntityAttributeExactMatch")) category = true; - else throw new FilterPolicyException("cant use type " + type); - - // log.debug("create filter policy for " + entityId + " regex?" + regex + " cat?" + category ); - addAttributeRules(ele, edit, policyGroupId); - } - - // create from strings - public AttributeFilterPolicy (FilterPolicyGroup pg, String rpid) { - editable = false; - attributeRules = new Vector(); - policyGroupId = pg.getId(); - policyGroupDescription = pg.getDescription(); - entityId = rpid; - regex = false; - } - - // add rules - public void addAttributeRules(Element ele, boolean edit, String pgid) { - NodeList nl1 = ele.getChildNodes(); - for (int i=0; i attributeRules; + private String policyGroupId; + private String policyGroupDescription; + private boolean category; + + // create from document element ( partly parsed ) + public AttributeFilterPolicy( + String type, String name, Element ele, boolean edit, FilterPolicyGroup pg) + throws FilterPolicyException { + + editable = edit; + attributeRules = new Vector(); + entityId = name; + policyGroupId = pg.getId(); + policyGroupDescription = pg.getDescription(); + category = false; + if (type.equals("basic:AttributeRequesterString")) regex = false; + else if (type.equals("basic:AttributeRequesterRegex")) regex = true; + else if (type.equals("saml:AttributeRequesterEntityAttributeExactMatch")) category = true; + else throw new FilterPolicyException("cant use type " + type); + + // log.debug("create filter policy for " + entityId + " regex?" + regex + " cat?" + category ); + addAttributeRules(ele, edit, policyGroupId); + } + + // create from strings + public AttributeFilterPolicy(FilterPolicyGroup pg, String rpid) { + editable = false; + attributeRules = new Vector(); + policyGroupId = pg.getId(); + policyGroupDescription = pg.getDescription(); + entityId = rpid; + regex = false; + } + + // add rules + public void addAttributeRules(Element ele, boolean edit, String pgid) { + NodeList nl1 = ele.getChildNodes(); + for (int i = 0; i < nl1.getLength(); i++) { + if (nl1.item(i).getNodeType() != Node.ELEMENT_NODE) continue; + Element e1 = (Element) nl1.item(i); + String name = e1.getNodeName(); + // log.info("rp ele: " + name); - // add an attribute to this policy - public void addAttribute(String id, String type, String value) { try { - for (int i=0; i\n" + - " \n"); - for (int i=0; i\n\n"); - } - - public void setEntityId(String v) { - entityId = v; - } - public String getEntityId() { - return (entityId); - } - public String getPolicyGroupId() { - return (policyGroupId); - } - public String getPolicyGroupDescription() { - return (policyGroupDescription); - } - - public void setEditable(boolean v) { - editable = v; - } - public boolean isEditable() { - return (editable); - } - - public void setAttributeRules(List v) { - attributeRules = v; - } - public List getAttributeRules() { - return (attributeRules); - } - - public UUID getUuid() { - return uuid; - } + // replace rules + public void replaceAttributeRule(String id, Element rule) throws FilterPolicyException { + removeAttributeRule(id); + attributeRules.add(new AttributeRule(rule)); + } - public void setUuid(UUID uuid) { - this.uuid = uuid; - } - - public String getStart_time() { - return start_time; - } - - public void setStart_time(String start_time) { - this.start_time = start_time; - } - - public String getEnd_time() { - return end_time; - } - - public void setEnd_time(String end_time) { - this.end_time = end_time; - } - - public String getUpdatedBy() { - return updatedBy; + // remove an attribute from this policy + public void removeAttributeRule(String id) { + for (int i = 0; i < attributeRules.size(); i++) { + if (attributeRules.get(i).getId().equals(id)) { + attributeRules.remove(i); + break; + } } + } - public void setUpdatedBy(String updatedBy) { - this.updatedBy = updatedBy; + // add an attribute to this policy + public void addAttribute(String id, String type, String value) { + try { + for (int i = 0; i < attributeRules.size(); i++) { + if (attributeRules.get(i).equals(id)) { + attributeRules.get(i).addValue(type, value); + return; + } + } + attributeRules.add(new AttributeRule(id, type, value)); + } catch (FilterPolicyException e) { + log.error("except: " + e); + } + } + + // remove an attribute from this policy + public void removeAttribute(String id, String type, String value) { + for (int i = 0; i < attributeRules.size(); i++) { + if (attributeRules.get(i).equals(id)) { + attributeRules.get(i).removeValue(type, value); + return; + } } - - + // throw exception + } + + // see if this policy applies to the rp + public boolean matches(String rpid) { + // log.debug("string match: " + entityId + " = " + rpid ); + if (regex) return rpid.matches(entityId); + return rpid.equals(entityId); + } + + // see if this policy applies to the rp + public boolean matches(RelyingParty rp) { + // log.debug("policy match: " + entityId + " = " + rp.getEntityId()); + if (category && rp.getEntityCategory() != null) return rp.getEntityCategory().equals(entityId); + return matches(rp.getEntityId()); + } + + // write xml doc + public void writeXml(BufferedWriter xout) throws IOException { + + // skip if no rules + if (attributeRules.size() == 0) { + log.debug("no rules for " + entityId); + return; + } + String pid = entityId.replaceAll("[^a-zA-Z0-9]", "_"); + xout.write( + " \n" + + " \n"); + for (int i = 0; i < attributeRules.size(); i++) attributeRules.get(i).writeXml(xout); + xout.write(" \n\n"); + } + + public void setEntityId(String v) { + entityId = v; + } + + public String getEntityId() { + return (entityId); + } + + public String getPolicyGroupId() { + return (policyGroupId); + } + + public String getPolicyGroupDescription() { + return (policyGroupDescription); + } + + public void setEditable(boolean v) { + editable = v; + } + + public boolean isEditable() { + return (editable); + } + + public void setAttributeRules(List v) { + attributeRules = v; + } + + public List getAttributeRules() { + return (attributeRules); + } + + public UUID getUuid() { + return uuid; + } + + public void setUuid(UUID uuid) { + this.uuid = uuid; + } + + public String getStart_time() { + return start_time; + } + + public void setStart_time(String start_time) { + this.start_time = start_time; + } + + public String getEnd_time() { + return end_time; + } + + public void setEnd_time(String end_time) { + this.end_time = end_time; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } } - diff --git a/src/main/java/edu/washington/iam/registry/filter/AttributeRule.java b/src/main/java/edu/washington/iam/registry/filter/AttributeRule.java index efa5076..2a7635a 100644 --- a/src/main/java/edu/washington/iam/registry/filter/AttributeRule.java +++ b/src/main/java/edu/washington/iam/registry/filter/AttributeRule.java @@ -15,123 +15,114 @@ * ======================================================================== */ - package edu.washington.iam.registry.filter; -import java.io.Serializable; +import edu.washington.iam.registry.exception.FilterPolicyException; +import edu.washington.iam.tools.XMLHelper; import java.io.BufferedWriter; import java.io.IOException; - +import java.io.Serializable; import java.util.List; import java.util.Vector; -import java.util.Arrays; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; -import edu.washington.iam.tools.XMLHelper; - -import edu.washington.iam.registry.exception.FilterPolicyException; - -public class AttributeRule implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private String id; - private List valueRules; - - private boolean editable = false; // used by controller-velocity - - // create from document element - public AttributeRule (Element ele) throws FilterPolicyException { +public class AttributeRule implements Serializable { - valueRules = new Vector(); - id = ele.getAttribute("attributeID"); - if (id==null) throw new FilterPolicyException("No attributeId attribute"); - // log.debug("create atr rule from doc: " + id); + private final Logger log = LoggerFactory.getLogger(getClass()); + private String id; + private List valueRules; - NodeList nl1 = ele.getChildNodes(); - for (int i=0; i 0) { + xout.write(" \n"); + for (int i = 0; i < valueRules.size(); i++) valueRules.get(i).writeXml(xout); + xout.write(" \n"); } + } - public boolean equals(String id) { - if (this.id.equals(id)) return true; - return false; - } + public void setId(String v) { + id = v; + } - // write - public void writeXml(BufferedWriter xout) throws IOException { - if (valueRules.size()>0) { - xout.write(" \n"); - for (int i=0; i\n"); - } - } + public String getId() { + return (id); + } - public void setId(String v) { - id = v; - } - public String getId() { - return (id); - } + public void setValueRules(List v) { + valueRules = v; + } - public void setValueRules(List v) { - valueRules = v; - } - public List getValueRules() { - return (valueRules); - } + public List getValueRules() { + return (valueRules); + } - public void setEditable(boolean v) { - editable = v; - } - public boolean isEditable() { - return editable; - } + public void setEditable(boolean v) { + editable = v; + } + public boolean isEditable() { + return editable; + } } - diff --git a/src/main/java/edu/washington/iam/registry/filter/DBFilterPolicyDAO.java b/src/main/java/edu/washington/iam/registry/filter/DBFilterPolicyDAO.java index 552566b..9bfb547 100644 --- a/src/main/java/edu/washington/iam/registry/filter/DBFilterPolicyDAO.java +++ b/src/main/java/edu/washington/iam/registry/filter/DBFilterPolicyDAO.java @@ -2,8 +2,14 @@ import edu.washington.iam.registry.exception.FilterPolicyException; import edu.washington.iam.registry.rp.UuidManager; -import edu.washington.iam.tools.XMLHelper; import edu.washington.iam.tools.IdpHelper; +import edu.washington.iam.tools.XMLHelper; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.*; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -14,396 +20,398 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.*; - public class DBFilterPolicyDAO implements FilterPolicyDAO { - private final Logger log = LoggerFactory.getLogger(getClass()); + private final Logger log = LoggerFactory.getLogger(getClass()); - private IdpHelper idpHelper = null; - public void setIdpHelper(IdpHelper v) { - idpHelper = v; - } + private IdpHelper idpHelper = null; - @Autowired - private UuidManager uuidManager; - - @Autowired - private JdbcTemplate template; - - private List filterPolicyGroups; - private FilterPolicyGetter filterPolicyGetter = new FilterPolicyGetter(); - - //private Map> attributeFilterListMap = new HashMap<>(); - - @Override - public List getFilterPolicyGroups() { - if(filterPolicyGroups == null){ - filterPolicyGroups = template.query("select * from filter_group where status = 1", - new RowMapper() { - @Override - public FilterPolicyGroup mapRow(ResultSet resultSet, int i) throws SQLException { - FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); - filterPolicyGroup.setId(resultSet.getString("id")); - filterPolicyGroup.setEditable(resultSet.getInt("edit_mode") == 1); - filterPolicyGroup.setDescription(filterPolicyGroup.getId()); - return filterPolicyGroup; - } - }); - } - return filterPolicyGroups; - } - - @Override - public FilterPolicyGroup getFilterPolicyGroup(String id) { - for(FilterPolicyGroup filterPolicyGroup : this.getFilterPolicyGroups()){ - if(filterPolicyGroup.getId().equals(id)) - return filterPolicyGroup; - } - return null; - } + public void setIdpHelper(IdpHelper v) { + idpHelper = v; + } - private class AttributeFilterPolicyEntries { - private List attributeFilterPolicies; - - public Timestamp getLastFetchTime() { - return lastFetchTime; - } - - public void setLastFetchTime(Timestamp lastFetchTime) { - this.lastFetchTime = lastFetchTime; - } + @Autowired private UuidManager uuidManager; - public List getAttributeFilterPolicies() { - return attributeFilterPolicies; - } + @Autowired private JdbcTemplate template; - public void setAttributeFilterPolicies(List attributeFilterPolicies) { - this.attributeFilterPolicies = attributeFilterPolicies; - } + private List filterPolicyGroups; + private FilterPolicyGetter filterPolicyGetter = new FilterPolicyGetter(); - private Timestamp lastFetchTime; - } + // private Map> attributeFilterListMap = new HashMap<>(); - private class FilterPolicyGetter { - //private final Logger log = LoggerFactory.getLogger(getClass()); - - private Map attributeFiltersMap = new HashMap<>(); - - public List getFilterPolicies(final FilterPolicyGroup filterPolicyGroup) - { - if(attributeFiltersMap.containsKey(filterPolicyGroup.getId())){ - log.debug("checking filter table for updates to " + filterPolicyGroup.getId()); - Timestamp lastUpdateTime = null; - //the most recent start_time will almost always be the most recent update time - //but if someone has "deleted" an SP then the most recent end_time will be the most recent update time - //so we get both and see which is more recent and use that - Timestamp lastUpdateTimeStart = - template.queryForObject("select max(start_time) from filter where group_id = ? and end_time is null", - new Object[]{filterPolicyGroup.getId()}, - Timestamp.class); - Timestamp lastUpdateTimeEnd = - template.queryForObject("select max(end_time) from filter where group_id = ? and end_time is not null", - new Object[]{filterPolicyGroup.getId()}, - Timestamp.class); - if ( lastUpdateTimeEnd == null || lastUpdateTimeStart.after(lastUpdateTimeEnd)){ - lastUpdateTime = lastUpdateTimeStart; - } else { lastUpdateTime = lastUpdateTimeEnd; } - log.debug("last update = " + lastUpdateTime.toString()); - Timestamp ft = attributeFiltersMap.get(filterPolicyGroup.getId()).getLastFetchTime(); - if(ft==null || lastUpdateTime.after(ft)){ - log.info("attribute filter policy has been updated, rebuilding for " + filterPolicyGroup.getId()); - attributeFiltersMap.remove(filterPolicyGroup.getId()); - } - else { - return attributeFiltersMap.get(filterPolicyGroup.getId()).getAttributeFilterPolicies(); + @Override + public List getFilterPolicyGroups() { + if (filterPolicyGroups == null) { + filterPolicyGroups = + template.query( + "select * from filter_group where status = 1", + new RowMapper() { + @Override + public FilterPolicyGroup mapRow(ResultSet resultSet, int i) throws SQLException { + FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); + filterPolicyGroup.setId(resultSet.getString("id")); + filterPolicyGroup.setEditable(resultSet.getInt("edit_mode") == 1); + filterPolicyGroup.setDescription(filterPolicyGroup.getId()); + return filterPolicyGroup; } - } - Timestamp fetchTime = new Timestamp(new Date().getTime()); - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - List tmpAttributeFilterPolicies = - template.query("select * from filter where group_id = ? and end_time is null", - new Object[] {filterPolicyGroup.getId()}, - new RowMapper() { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - - @Override - public AttributeFilterPolicy mapRow(ResultSet resultSet, int i) throws SQLException { - Document document; - String entityId = resultSet.getString("entity_id"); - String groupId = resultSet.getString("group_id"); - try { - DocumentBuilder builder = dbf.newDocumentBuilder(); - document = builder.parse(resultSet.getAsciiStream("xml")); - - } - catch(Exception e){ - return null; - } - - AttributeFilterPolicy attributeFilterPolicy = - attributeFilterPolicyFromElement( - document.getDocumentElement(), - filterPolicyGroup); - - if(attributeFilterPolicy == null){ - log.info(String.format("unparseable attribute filter for entity: %s in group: %s", - entityId, groupId)); - } - - return attributeFilterPolicy; - } - }); - - // TODO: figure if this next block should come out. Only if we're confident there could never be nulls - List attributeFilterPolicies = new ArrayList<>(); - for(AttributeFilterPolicy attributeFilterPolicy : tmpAttributeFilterPolicies){ - if(attributeFilterPolicy != null) - attributeFilterPolicies.add(attributeFilterPolicy); - } - - log.info("got the following attributeFilterPolicies: " + attributeFilterPolicies.size()); - AttributeFilterPolicyEntries newEntry = new AttributeFilterPolicyEntries(); - newEntry.setLastFetchTime(fetchTime); - newEntry.setAttributeFilterPolicies(attributeFilterPolicies); - attributeFiltersMap.put(filterPolicyGroup.getId(), newEntry); - return attributeFilterPolicies; - } + }); } + return filterPolicyGroups; + } - @Override - public List getFilterPolicies(FilterPolicyGroup filterPolicyGroup) { - return filterPolicyGetter.getFilterPolicies(filterPolicyGroup); + @Override + public FilterPolicyGroup getFilterPolicyGroup(String id) { + for (FilterPolicyGroup filterPolicyGroup : this.getFilterPolicyGroups()) { + if (filterPolicyGroup.getId().equals(id)) return filterPolicyGroup; } + return null; + } - @Override - public AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, String rpid) { - for(AttributeFilterPolicy attributeFilterPolicy : getFilterPolicies(filterPolicyGroup)){ - if(attributeFilterPolicy.matches(rpid)) - return attributeFilterPolicy; - } - return null; - } - - /**mattjm 2018-10-26 - * I still have no idea why this takes a LIST of filter policies as an argument - */ - @Override - public void updateFilterPolicies(FilterPolicyGroup filterPolicyGroup, - List attributeFilterPolicies, String updatedBy) - throws FilterPolicyException { - Map afpMap = new HashMap<>(); - for(AttributeFilterPolicy attributeFilterPolicy : attributeFilterPolicies){ - //map of new entityids and filter policies as received via arguments - afpMap.put(attributeFilterPolicy.getEntityId(), attributeFilterPolicy); - } + private class AttributeFilterPolicyEntries { + private List attributeFilterPolicies; - NamedParameterJdbcTemplate npTemplate = new NamedParameterJdbcTemplate(template); - //get existing group/entityid pairs by group and entityid - List entityIdsToUpdate = npTemplate.queryForList( - "select entity_id from filter where end_time is null and group_id = :groupId and entity_id in (:ids)" - ,new MapSqlParameterSource() - .addValue("groupId", filterPolicyGroup.getId()) - .addValue("ids", afpMap.keySet()) - , String.class - ); - //this is a list of ONLY entity IDs from the hashmap above--all this came in from the client via - // XML PUT(e.g. NEW STUFF) - List entityIdsToAdd = new ArrayList<>(afpMap.keySet()); - //this removes the entityids already in the database from the "to add" list above - entityIdsToAdd.removeAll(entityIdsToUpdate); - - //add a new entry if no active records in the DB already--all this does is keep us from having to make an extra, - //unnecessary "removerelyingparty" (i.e. mark an attribute entry deleted) call to the DB - for(String addEntityId : entityIdsToAdd){ - createFilterPolicy(filterPolicyGroup, afpMap.get(addEntityId), updatedBy); - } - //update the entry if there are active DB records already - for(String updateEntityId : entityIdsToUpdate){ - updateFilterPolicy(filterPolicyGroup, afpMap.get(updateEntityId), updatedBy); - } + public Timestamp getLastFetchTime() { + return lastFetchTime; + } + public void setLastFetchTime(Timestamp lastFetchTime) { + this.lastFetchTime = lastFetchTime; } - public void updateFilterPolicy(FilterPolicyGroup filterPolicyGroup, - AttributeFilterPolicy attributeFilterPolicy, String updatedBy) throws FilterPolicyException { - - attributeFilterPolicy.setUuid(uuidManager.getUuid(attributeFilterPolicy.getEntityId())); - log.info(String.format("updating %s for %s", attributeFilterPolicy.getEntityId(), filterPolicyGroup.getId())); - //recycle delete method - removeRelyingParty(filterPolicyGroup, attributeFilterPolicy.getEntityId(), updatedBy); - log.info(String.format("marked old fp deleted %s for %s, attempting to add new one", attributeFilterPolicy.getEntityId(), filterPolicyGroup.getId())); - try { - String xml = XMLHelper.serializeXmlToString(attributeFilterPolicy); - template.update("insert into filter (uuid, entity_id, start_time, end_time, updated_by, xml, group_id, status) " - + "values (?, ?, now(), null, ?, ?, ?, 1)", - attributeFilterPolicy.getUuid(), - attributeFilterPolicy.getEntityId(), - updatedBy, - xml, - filterPolicyGroup.getId()); - if (idpHelper!=null) idpHelper.notifyIdps("filter"); - } catch (Exception e) { - log.info("fp update trouble: " + e.getMessage()); - throw(new FilterPolicyException(e)); - } + public List getAttributeFilterPolicies() { + return attributeFilterPolicies; } - public void createFilterPolicy(FilterPolicyGroup filterPolicyGroup, - AttributeFilterPolicy attributeFilterPolicy, String updatedBy) throws FilterPolicyException { - - attributeFilterPolicy.setUuid(uuidManager.getUuid(attributeFilterPolicy.getEntityId())); - log.info(String.format("creating %s for %s", attributeFilterPolicy.getEntityId(), filterPolicyGroup.getId())); - try { - String xml = XMLHelper.serializeXmlToString(attributeFilterPolicy); - template.update("insert into filter (uuid, entity_id, start_time, end_time, updated_by, xml, group_id, status) " - + "values (?, ?, now(), null, ?, ?, ?, 1)", - attributeFilterPolicy.getUuid(), - attributeFilterPolicy.getEntityId(), - updatedBy, - xml, - filterPolicyGroup.getId()); - if (idpHelper!=null) idpHelper.notifyIdps("filter"); - } catch (Exception e) { - log.info("create trouble: " + e.getMessage()); - throw(new FilterPolicyException(e)); - } + public void setAttributeFilterPolicies(List attributeFilterPolicies) { + this.attributeFilterPolicies = attributeFilterPolicies; } - @Override - public int removeRelyingParty(FilterPolicyGroup filterPolicyGroup, String entityId, String updatedBy) - throws FilterPolicyException { - log.info("marking old fp record deleted for " + entityId + " in " + filterPolicyGroup.getId()); - List rpIds = template.queryForList( - "select id from filter where entity_id = ? and group_id = ? and end_time is null", - Integer.class, - entityId, - filterPolicyGroup.getId() - ); - if (rpIds.size() == 1 && rpIds.get(0) != null) { - template.update("update filter set end_time = now(), updated_by = ?, status = ? where id= ?", - updatedBy, - 0, - rpIds.get(0)); + private Timestamp lastFetchTime; + } + + private class FilterPolicyGetter { + // private final Logger log = LoggerFactory.getLogger(getClass()); + + private Map attributeFiltersMap = new HashMap<>(); + + public List getFilterPolicies( + final FilterPolicyGroup filterPolicyGroup) { + if (attributeFiltersMap.containsKey(filterPolicyGroup.getId())) { + log.debug("checking filter table for updates to " + filterPolicyGroup.getId()); + Timestamp lastUpdateTime = null; + // the most recent start_time will almost always be the most recent update time + // but if someone has "deleted" an SP then the most recent end_time will be the most recent + // update time + // so we get both and see which is more recent and use that + Timestamp lastUpdateTimeStart = + template.queryForObject( + "select max(start_time) from filter where group_id = ? and end_time is null", + new Object[] {filterPolicyGroup.getId()}, + Timestamp.class); + Timestamp lastUpdateTimeEnd = + template.queryForObject( + "select max(end_time) from filter where group_id = ? and end_time is not null", + new Object[] {filterPolicyGroup.getId()}, + Timestamp.class); + if (lastUpdateTimeEnd == null || lastUpdateTimeStart.after(lastUpdateTimeEnd)) { + lastUpdateTime = lastUpdateTimeStart; + } else { + lastUpdateTime = lastUpdateTimeEnd; } - else if (rpIds.size() == 0) - { - log.info(String.format("No filter policy found for %s ", entityId)); + log.debug("last update = " + lastUpdateTime.toString()); + Timestamp ft = attributeFiltersMap.get(filterPolicyGroup.getId()).getLastFetchTime(); + if (ft == null || lastUpdateTime.after(ft)) { + log.info( + "attribute filter policy has been updated, rebuilding for " + + filterPolicyGroup.getId()); + attributeFiltersMap.remove(filterPolicyGroup.getId()); + } else { + return attributeFiltersMap.get(filterPolicyGroup.getId()).getAttributeFilterPolicies(); } - else - { - throw new FilterPolicyException("more than one active filter policy record found!! No update performed."); - } - if (idpHelper!=null) idpHelper.notifyIdps("filter"); - // TODO: DB error handling - // one way to clear the cache - //attributeFilterListMap.remove(filterPolicyGroup.getId()); - return 200; - } - - public AttributeFilterPolicy attributeFilterPolicyFromElement(Element topElement, - FilterPolicyGroup filterPolicyGroup) { - AttributeFilterPolicy attributeFilterPolicy = null; - // scan requirement rules - for (Element childElement : XMLHelper.getChildElements(topElement)) { - String name = childElement.getNodeName(); - - if (XMLHelper.matches(name, "PolicyRequirementRule")) { - String type = childElement.getAttribute("xsi:type"); - if (type.equals("basic:AttributeRequesterString") || type.equals("basic:AttributeRequesterRegex")) - attributeFilterPolicy = addOrUpdatePolicy( - attributeFilterPolicy, - childElement, - topElement, - filterPolicyGroup); - else if (type.equals("saml:AttributeRequesterEntityAttributeExactMatch")) - attributeFilterPolicy = addOrUpdateSamlPolicy( - attributeFilterPolicy, - childElement, - topElement, - filterPolicyGroup); - else if (type.equals("basic:OR")) { - // scan rules - for (Element orElement : XMLHelper.getChildElements(childElement)) { - name = orElement.getNodeName(); - - if (XMLHelper.matches(name,"Rule")) { - attributeFilterPolicy = addOrUpdatePolicy( - attributeFilterPolicy, - orElement, - topElement, - filterPolicyGroup); - } - } + } + Timestamp fetchTime = new Timestamp(new Date().getTime()); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + List tmpAttributeFilterPolicies = + template.query( + "select * from filter where group_id = ? and end_time is null", + new Object[] {filterPolicyGroup.getId()}, + new RowMapper() { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + @Override + public AttributeFilterPolicy mapRow(ResultSet resultSet, int i) + throws SQLException { + Document document; + String entityId = resultSet.getString("entity_id"); + String groupId = resultSet.getString("group_id"); + try { + DocumentBuilder builder = dbf.newDocumentBuilder(); + document = builder.parse(resultSet.getAsciiStream("xml")); + + } catch (Exception e) { + return null; + } + + AttributeFilterPolicy attributeFilterPolicy = + attributeFilterPolicyFromElement( + document.getDocumentElement(), filterPolicyGroup); + + if (attributeFilterPolicy == null) { + log.info( + String.format( + "unparseable attribute filter for entity: %s in group: %s", + entityId, groupId)); + } + + return attributeFilterPolicy; } - } - } - return attributeFilterPolicy; + }); + + // TODO: figure if this next block should come out. Only if we're confident there could never + // be nulls + List attributeFilterPolicies = new ArrayList<>(); + for (AttributeFilterPolicy attributeFilterPolicy : tmpAttributeFilterPolicies) { + if (attributeFilterPolicy != null) attributeFilterPolicies.add(attributeFilterPolicy); + } + + log.info("got the following attributeFilterPolicies: " + attributeFilterPolicies.size()); + AttributeFilterPolicyEntries newEntry = new AttributeFilterPolicyEntries(); + newEntry.setLastFetchTime(fetchTime); + newEntry.setAttributeFilterPolicies(attributeFilterPolicies); + attributeFiltersMap.put(filterPolicyGroup.getId(), newEntry); + return attributeFilterPolicies; } + } - private AttributeFilterPolicy addOrUpdatePolicy(AttributeFilterPolicy existingAttributeFilterPolicy, - Element childElement, - Element topElement, - FilterPolicyGroup filterPolicyGroup - ) { - - AttributeFilterPolicy attributeFilterPolicy = null; - String type = childElement.getAttribute("xsi:type"); - String value = childElement.getAttribute("value"); - if (value.length()==0) value = childElement.getAttribute("regex"); - try { - if(existingAttributeFilterPolicy != null){ - attributeFilterPolicy = existingAttributeFilterPolicy; - attributeFilterPolicy.addAttributeRules(topElement, filterPolicyGroup.isEditable(), filterPolicyGroup.getId() ); - } - else - attributeFilterPolicy = new AttributeFilterPolicy( - type, - value, - topElement, - filterPolicyGroup.isEditable(), - filterPolicyGroup); - } catch (FilterPolicyException ex) { - log.error("load of attribute failed: " + ex); + @Override + public List getFilterPolicies(FilterPolicyGroup filterPolicyGroup) { + return filterPolicyGetter.getFilterPolicies(filterPolicyGroup); + } - } - return attributeFilterPolicy; + @Override + public AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, String rpid) { + for (AttributeFilterPolicy attributeFilterPolicy : getFilterPolicies(filterPolicyGroup)) { + if (attributeFilterPolicy.matches(rpid)) return attributeFilterPolicy; + } + return null; + } + + /**mattjm 2018-10-26 + * I still have no idea why this takes a LIST of filter policies as an argument + */ + @Override + public void updateFilterPolicies( + FilterPolicyGroup filterPolicyGroup, + List attributeFilterPolicies, + String updatedBy) + throws FilterPolicyException { + Map afpMap = new HashMap<>(); + for (AttributeFilterPolicy attributeFilterPolicy : attributeFilterPolicies) { + // map of new entityids and filter policies as received via arguments + afpMap.put(attributeFilterPolicy.getEntityId(), attributeFilterPolicy); } - private AttributeFilterPolicy addOrUpdateSamlPolicy(AttributeFilterPolicy existingAttributeFilterPolicy, - Element childElement, - Element topElement, - FilterPolicyGroup filterPolicyGroup) { - AttributeFilterPolicy attributeFilterPolicy = null; + NamedParameterJdbcTemplate npTemplate = new NamedParameterJdbcTemplate(template); + // get existing group/entityid pairs by group and entityid + List entityIdsToUpdate = + npTemplate.queryForList( + "select entity_id from filter where end_time is null and group_id = :groupId and entity_id in (:ids)", + new MapSqlParameterSource() + .addValue("groupId", filterPolicyGroup.getId()) + .addValue("ids", afpMap.keySet()), + String.class); + // this is a list of ONLY entity IDs from the hashmap above--all this came in from the client + // via + // XML PUT(e.g. NEW STUFF) + List entityIdsToAdd = new ArrayList<>(afpMap.keySet()); + // this removes the entityids already in the database from the "to add" list above + entityIdsToAdd.removeAll(entityIdsToUpdate); + + // add a new entry if no active records in the DB already--all this does is keep us from having + // to make an extra, + // unnecessary "removerelyingparty" (i.e. mark an attribute entry deleted) call to the DB + for (String addEntityId : entityIdsToAdd) { + createFilterPolicy(filterPolicyGroup, afpMap.get(addEntityId), updatedBy); + } + // update the entry if there are active DB records already + for (String updateEntityId : entityIdsToUpdate) { + updateFilterPolicy(filterPolicyGroup, afpMap.get(updateEntityId), updatedBy); + } + } + + public void updateFilterPolicy( + FilterPolicyGroup filterPolicyGroup, + AttributeFilterPolicy attributeFilterPolicy, + String updatedBy) + throws FilterPolicyException { + + attributeFilterPolicy.setUuid(uuidManager.getUuid(attributeFilterPolicy.getEntityId())); + log.info( + String.format( + "updating %s for %s", attributeFilterPolicy.getEntityId(), filterPolicyGroup.getId())); + // recycle delete method + removeRelyingParty(filterPolicyGroup, attributeFilterPolicy.getEntityId(), updatedBy); + log.info( + String.format( + "marked old fp deleted %s for %s, attempting to add new one", + attributeFilterPolicy.getEntityId(), filterPolicyGroup.getId())); + try { + String xml = XMLHelper.serializeXmlToString(attributeFilterPolicy); + template.update( + "insert into filter (uuid, entity_id, start_time, end_time, updated_by, xml, group_id, status) " + + "values (?, ?, now(), null, ?, ?, ?, 1)", + attributeFilterPolicy.getUuid(), + attributeFilterPolicy.getEntityId(), + updatedBy, + xml, + filterPolicyGroup.getId()); + if (idpHelper != null) idpHelper.notifyIdps("filter"); + } catch (Exception e) { + log.info("fp update trouble: " + e.getMessage()); + throw (new FilterPolicyException(e)); + } + } + + public void createFilterPolicy( + FilterPolicyGroup filterPolicyGroup, + AttributeFilterPolicy attributeFilterPolicy, + String updatedBy) + throws FilterPolicyException { + + attributeFilterPolicy.setUuid(uuidManager.getUuid(attributeFilterPolicy.getEntityId())); + log.info( + String.format( + "creating %s for %s", attributeFilterPolicy.getEntityId(), filterPolicyGroup.getId())); + try { + String xml = XMLHelper.serializeXmlToString(attributeFilterPolicy); + template.update( + "insert into filter (uuid, entity_id, start_time, end_time, updated_by, xml, group_id, status) " + + "values (?, ?, now(), null, ?, ?, ?, 1)", + attributeFilterPolicy.getUuid(), + attributeFilterPolicy.getEntityId(), + updatedBy, + xml, + filterPolicyGroup.getId()); + if (idpHelper != null) idpHelper.notifyIdps("filter"); + } catch (Exception e) { + log.info("create trouble: " + e.getMessage()); + throw (new FilterPolicyException(e)); + } + } + + @Override + public int removeRelyingParty( + FilterPolicyGroup filterPolicyGroup, String entityId, String updatedBy) + throws FilterPolicyException { + log.info("marking old fp record deleted for " + entityId + " in " + filterPolicyGroup.getId()); + List rpIds = + template.queryForList( + "select id from filter where entity_id = ? and group_id = ? and end_time is null", + Integer.class, + entityId, + filterPolicyGroup.getId()); + if (rpIds.size() == 1 && rpIds.get(0) != null) { + template.update( + "update filter set end_time = now(), updated_by = ?, status = ? where id= ?", + updatedBy, + 0, + rpIds.get(0)); + } else if (rpIds.size() == 0) { + log.info(String.format("No filter policy found for %s ", entityId)); + } else { + throw new FilterPolicyException( + "more than one active filter policy record found!! No update performed."); + } + if (idpHelper != null) idpHelper.notifyIdps("filter"); + // TODO: DB error handling + // one way to clear the cache + // attributeFilterListMap.remove(filterPolicyGroup.getId()); + return 200; + } + + public AttributeFilterPolicy attributeFilterPolicyFromElement( + Element topElement, FilterPolicyGroup filterPolicyGroup) { + AttributeFilterPolicy attributeFilterPolicy = null; + // scan requirement rules + for (Element childElement : XMLHelper.getChildElements(topElement)) { + String name = childElement.getNodeName(); + + if (XMLHelper.matches(name, "PolicyRequirementRule")) { String type = childElement.getAttribute("xsi:type"); - String name = childElement.getAttribute("attributeName"); - if (!name.equals("http://macedir.org/entity-category")) { - log.error("saml policy not category"); - return existingAttributeFilterPolicy; - } - String value = childElement.getAttribute("attributeValue"); - try { - if (existingAttributeFilterPolicy != null){ - attributeFilterPolicy = existingAttributeFilterPolicy; - attributeFilterPolicy.addAttributeRules(topElement, - filterPolicyGroup.isEditable(), - filterPolicyGroup.getId()); + if (type.equals("basic:AttributeRequesterString") + || type.equals("basic:AttributeRequesterRegex")) + attributeFilterPolicy = + addOrUpdatePolicy(attributeFilterPolicy, childElement, topElement, filterPolicyGroup); + else if (type.equals("saml:AttributeRequesterEntityAttributeExactMatch")) + attributeFilterPolicy = + addOrUpdateSamlPolicy( + attributeFilterPolicy, childElement, topElement, filterPolicyGroup); + else if (type.equals("basic:OR")) { + // scan rules + for (Element orElement : XMLHelper.getChildElements(childElement)) { + name = orElement.getNodeName(); + + if (XMLHelper.matches(name, "Rule")) { + attributeFilterPolicy = + addOrUpdatePolicy( + attributeFilterPolicy, orElement, topElement, filterPolicyGroup); } - else attributeFilterPolicy = new AttributeFilterPolicy( - type, - value, - topElement, - filterPolicyGroup.isEditable(), - filterPolicyGroup); - } catch (FilterPolicyException ex) { - log.error("load of attribute failed: " + ex); + } } - return attributeFilterPolicy; + } } - - + return attributeFilterPolicy; + } + + private AttributeFilterPolicy addOrUpdatePolicy( + AttributeFilterPolicy existingAttributeFilterPolicy, + Element childElement, + Element topElement, + FilterPolicyGroup filterPolicyGroup) { + + AttributeFilterPolicy attributeFilterPolicy = null; + String type = childElement.getAttribute("xsi:type"); + String value = childElement.getAttribute("value"); + if (value.length() == 0) value = childElement.getAttribute("regex"); + try { + if (existingAttributeFilterPolicy != null) { + attributeFilterPolicy = existingAttributeFilterPolicy; + attributeFilterPolicy.addAttributeRules( + topElement, filterPolicyGroup.isEditable(), filterPolicyGroup.getId()); + } else + attributeFilterPolicy = + new AttributeFilterPolicy( + type, value, topElement, filterPolicyGroup.isEditable(), filterPolicyGroup); + } catch (FilterPolicyException ex) { + log.error("load of attribute failed: " + ex); + } + return attributeFilterPolicy; + } + + private AttributeFilterPolicy addOrUpdateSamlPolicy( + AttributeFilterPolicy existingAttributeFilterPolicy, + Element childElement, + Element topElement, + FilterPolicyGroup filterPolicyGroup) { + AttributeFilterPolicy attributeFilterPolicy = null; + String type = childElement.getAttribute("xsi:type"); + String name = childElement.getAttribute("attributeName"); + if (!name.equals("http://macedir.org/entity-category")) { + log.error("saml policy not category"); + return existingAttributeFilterPolicy; + } + String value = childElement.getAttribute("attributeValue"); + try { + if (existingAttributeFilterPolicy != null) { + attributeFilterPolicy = existingAttributeFilterPolicy; + attributeFilterPolicy.addAttributeRules( + topElement, filterPolicyGroup.isEditable(), filterPolicyGroup.getId()); + } else + attributeFilterPolicy = + new AttributeFilterPolicy( + type, value, topElement, filterPolicyGroup.isEditable(), filterPolicyGroup); + } catch (FilterPolicyException ex) { + log.error("load of attribute failed: " + ex); + } + return attributeFilterPolicy; + } } diff --git a/src/main/java/edu/washington/iam/registry/filter/FilterPolicyDAO.java b/src/main/java/edu/washington/iam/registry/filter/FilterPolicyDAO.java index ce52be2..f138e95 100644 --- a/src/main/java/edu/washington/iam/registry/filter/FilterPolicyDAO.java +++ b/src/main/java/edu/washington/iam/registry/filter/FilterPolicyDAO.java @@ -1,25 +1,26 @@ package edu.washington.iam.registry.filter; -import edu.washington.iam.registry.exception.AttributeNotFoundException; import edu.washington.iam.registry.exception.FilterPolicyException; -import edu.washington.iam.registry.exception.NoPermissionException; - import java.util.List; public interface FilterPolicyDAO { - List getFilterPolicyGroups(); - FilterPolicyGroup getFilterPolicyGroup(String id); - - List getFilterPolicies(FilterPolicyGroup filterPolicyGroup); - // returns filter policy for a given rp or null if none exist - AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, - String rpid); - // add new or update existing filterPolicies - void updateFilterPolicies(FilterPolicyGroup filterPolicyGroup, - List attributeFilterPolicies, String updatedBy) - throws FilterPolicyException; - int removeRelyingParty(FilterPolicyGroup filterPolicyGroup, - String entityId, String updatedBy) - throws FilterPolicyException; + List getFilterPolicyGroups(); + + FilterPolicyGroup getFilterPolicyGroup(String id); + + List getFilterPolicies(FilterPolicyGroup filterPolicyGroup); + + // returns filter policy for a given rp or null if none exist + AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, String rpid); + + // add new or update existing filterPolicies + void updateFilterPolicies( + FilterPolicyGroup filterPolicyGroup, + List attributeFilterPolicies, + String updatedBy) + throws FilterPolicyException; + + int removeRelyingParty(FilterPolicyGroup filterPolicyGroup, String entityId, String updatedBy) + throws FilterPolicyException; } diff --git a/src/main/java/edu/washington/iam/registry/filter/FilterPolicyGroup.java b/src/main/java/edu/washington/iam/registry/filter/FilterPolicyGroup.java index 541c4c6..f011a5e 100644 --- a/src/main/java/edu/washington/iam/registry/filter/FilterPolicyGroup.java +++ b/src/main/java/edu/washington/iam/registry/filter/FilterPolicyGroup.java @@ -1,33 +1,33 @@ package edu.washington.iam.registry.filter; public class FilterPolicyGroup { - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - private String id; + private String id; - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } - private String description; + private String description; - public boolean isEditable() { - return editable; - } + public boolean isEditable() { + return editable; + } - public void setEditable(boolean editable) { - this.editable = editable; - } + public void setEditable(boolean editable) { + this.editable = editable; + } - private boolean editable; + private boolean editable; } diff --git a/src/main/java/edu/washington/iam/registry/filter/FilterPolicyManager.java b/src/main/java/edu/washington/iam/registry/filter/FilterPolicyManager.java index 8de588f..76f77d1 100644 --- a/src/main/java/edu/washington/iam/registry/filter/FilterPolicyManager.java +++ b/src/main/java/edu/washington/iam/registry/filter/FilterPolicyManager.java @@ -17,36 +17,32 @@ package edu.washington.iam.registry.filter; +import edu.washington.iam.registry.exception.FilterPolicyException; +import edu.washington.iam.registry.rp.RelyingParty; import java.io.Serializable; import java.util.List; - import org.w3c.dom.Document; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +public interface FilterPolicyManager extends Serializable { + + public List getAttributes(); + public List getAttributes(RelyingParty rp); -import edu.washington.iam.registry.rp.RelyingParty; -import edu.washington.iam.registry.exception.FilterPolicyException; -import edu.washington.iam.registry.exception.AttributeNotFoundException; -import edu.washington.iam.registry.exception.NoPermissionException; + public List getFilterPolicies(RelyingParty rp); -public interface FilterPolicyManager extends Serializable { + public AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, String rpid); - public List getAttributes(); - public List getAttributes(RelyingParty rp); - public List getFilterPolicies(RelyingParty rp); - public AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, String rpid); + public int removeRelyingParty(String entityId, String pgid, String updatedBy) + throws FilterPolicyException; - public int removeRelyingParty(String entityId, String pgid, String updatedBy) - throws FilterPolicyException; + public int removeEditableRelyingParty(String entityId, String updatedBy) + throws FilterPolicyException; - public int removeEditableRelyingParty(String entityId, String updatedBy) - throws FilterPolicyException; + public List getFilterPolicyGroups(); - public List getFilterPolicyGroups(); - public void updateRelyingParty(String pgid, Document doc, String updatedBy) - throws FilterPolicyException; - public FilterPolicyGroup getPolicyGroup(String pgid); + public void updateRelyingParty(String pgid, Document doc, String updatedBy) + throws FilterPolicyException; + public FilterPolicyGroup getPolicyGroup(String pgid); } diff --git a/src/main/java/edu/washington/iam/registry/filter/FilterPolicyManagerImpl.java b/src/main/java/edu/washington/iam/registry/filter/FilterPolicyManagerImpl.java index 00958ad..052a4d6 100644 --- a/src/main/java/edu/washington/iam/registry/filter/FilterPolicyManagerImpl.java +++ b/src/main/java/edu/washington/iam/registry/filter/FilterPolicyManagerImpl.java @@ -17,175 +17,168 @@ package edu.washington.iam.registry.filter; - +import edu.washington.iam.registry.exception.AttributeNotFoundException; +import edu.washington.iam.registry.exception.FilterPolicyException; +import edu.washington.iam.registry.rp.RelyingParty; +import edu.washington.iam.tools.XMLHelper; import java.util.*; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import edu.washington.iam.registry.rp.RelyingParty; -import edu.washington.iam.tools.XMLHelper; -import edu.washington.iam.registry.exception.FilterPolicyException; -import edu.washington.iam.registry.exception.AttributeNotFoundException; - public class FilterPolicyManagerImpl implements FilterPolicyManager { - private final Logger log = LoggerFactory.getLogger(getClass()); + private final Logger log = LoggerFactory.getLogger(getClass()); - @Autowired - private FilterPolicyDAO filterPolicyDAO; + @Autowired private FilterPolicyDAO filterPolicyDAO; - @Autowired - private AttributeDAO attributeDAO; - - @Override - public AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, String rpid){ - log.debug(String.format("getting filter policy: pgid: %s; rpid: %s", - filterPolicyGroup != null ? filterPolicyGroup.getId() : "null", - rpid)); - return filterPolicyDAO.getFilterPolicy(filterPolicyGroup, rpid); - } + @Autowired private AttributeDAO attributeDAO; - @Override - public List getFilterPolicies(RelyingParty rp) { - log.debug("looking for fps for " + rp.getEntityId()); - List list = new Vector(); - - for(FilterPolicyGroup filterPolicyGroup : filterPolicyDAO.getFilterPolicyGroups()){ - List attributeFilterPolicies = filterPolicyDAO.getFilterPolicies(filterPolicyGroup); - for(AttributeFilterPolicy attributeFilterPolicy : attributeFilterPolicies){ - if(attributeFilterPolicy.matches(rp)){ - list.add(attributeFilterPolicy); - } - } - } - - log.info("fp search found "+list.size()); - return list; - } + @Override + public AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, String rpid) { + log.debug( + String.format( + "getting filter policy: pgid: %s; rpid: %s", + filterPolicyGroup != null ? filterPolicyGroup.getId() : "null", rpid)); + return filterPolicyDAO.getFilterPolicy(filterPolicyGroup, rpid); + } - @Override - public List getAttributes(){ - return attributeDAO.getAttributes(); - } + @Override + public List getFilterPolicies(RelyingParty rp) { + log.debug("looking for fps for " + rp.getEntityId()); + List list = new Vector(); - @Override - public List getAttributes(RelyingParty rp) { - List ret = new Vector(); - log.debug("getting editable attributes for " + rp.getEntityId()); - List fps = this.getFilterPolicies(rp); - int matches = 0; - for (Attribute attribute : attributeDAO.getAttributes()) { - Attribute attr = new Attribute(attribute); - for (AttributeFilterPolicy afp : fps) { - for (AttributeRule attributeRule : afp.getAttributeRules()) { - if (attributeRule.getId().equals(attr.getId())) { - //attributefilterpolicy is set so we can see attribute source with mouseover text - //on attribute page. - attr.setAttributeFilterPolicy(afp); - attr.setAttributeRule(attributeRule); - matches++; - } - } - } - ret.add(attr); + for (FilterPolicyGroup filterPolicyGroup : filterPolicyDAO.getFilterPolicyGroups()) { + List attributeFilterPolicies = + filterPolicyDAO.getFilterPolicies(filterPolicyGroup); + for (AttributeFilterPolicy attributeFilterPolicy : attributeFilterPolicies) { + if (attributeFilterPolicy.matches(rp)) { + list.add(attributeFilterPolicy); } - log.debug("from " + attributeDAO.getAttributes().size() + ", found " + matches + " matches"); - return ret; + } } - /* - * Update policies from an API PUT. - * simplified document - */ - @Override - public void updateRelyingParty(String pgid, Document doc, String updatedBy) - throws FilterPolicyException { - // we have received an XML document (doc) containing the new requested new attribute state - // "pgid" is the request policygroup as passed from spreg UI, "doc" contains the actual entityid - // within the XML payload - log.info("rp update attr doc for " + pgid); - - FilterPolicyGroup policyGroup = filterPolicyDAO.getFilterPolicyGroup(pgid); - if (policyGroup==null) throw new FilterPolicyException("policy group not found"); - if (!policyGroup.isEditable()) throw new FilterPolicyException("policy group not editable"); - - // process each policy ( will be only one requirement rule ) - List attributeFilterPolicies = new ArrayList<>(); - for(Element policy : XMLHelper.getElementsByName(doc.getDocumentElement(), "AttributeFilterPolicy")){ - Element reqRule = XMLHelper.getElementByName(policy, "PolicyRequirementRule"); - if (reqRule==null) throw new FilterPolicyException("invalid post"); - - // type assumed - String rpid = reqRule.getAttribute("value"); - log.debug("attr update, pol=" + pgid + ", rp=" + rpid); - AttributeFilterPolicy afp = filterPolicyDAO.getFilterPolicy(policyGroup, rpid); - if (afp==null) { - afp = new AttributeFilterPolicy(policyGroup, rpid); - } - - for (Element attributeRule : XMLHelper.getElementsByName(policy, "AttributeRule")) { - String attributeId = attributeRule.getAttribute("attributeID"); - String act = attributeRule.getAttribute("action"); - Attribute attribute; - try { - attribute = attributeDAO.getAttribute(attributeId); - } catch (AttributeNotFoundException e){ - throw new FilterPolicyException(String.format("attribute not found: %s", attributeId), e); - } - - log.debug(".." + act + " " + attributeId); - - if (act.equals("replace")) afp.replaceAttributeRule(attributeId, attributeRule); - else if (act.equals("remove")) afp.removeAttributeRule(attributeId); - else throw new FilterPolicyException("unknown action"); - } - //create list of filter policies (based on XML doc) to send to updatefilterpolicy method - attributeFilterPolicies.add(afp); + log.info("fp search found " + list.size()); + return list; + } + + @Override + public List getAttributes() { + return attributeDAO.getAttributes(); + } + + @Override + public List getAttributes(RelyingParty rp) { + List ret = new Vector(); + log.debug("getting editable attributes for " + rp.getEntityId()); + List fps = this.getFilterPolicies(rp); + int matches = 0; + for (Attribute attribute : attributeDAO.getAttributes()) { + Attribute attr = new Attribute(attribute); + for (AttributeFilterPolicy afp : fps) { + for (AttributeRule attributeRule : afp.getAttributeRules()) { + if (attributeRule.getId().equals(attr.getId())) { + // attributefilterpolicy is set so we can see attribute source with mouseover text + // on attribute page. + attr.setAttributeFilterPolicy(afp); + attr.setAttributeRule(attributeRule); + matches++; + } } - - filterPolicyDAO.updateFilterPolicies(policyGroup, attributeFilterPolicies, updatedBy); - // save the new doc - //policyGroup.writePolicyGroup(); + } + ret.add(attr); } - - @Override - public int removeEditableRelyingParty(String entityId, String updatedBy) - throws FilterPolicyException { - int status = 200; - for (FilterPolicyGroup filterPolicyGroup : this.getFilterPolicyGroups()){ - if(filterPolicyGroup.isEditable()){ - log.info(String.format("Removing %s from policy group %s", entityId, filterPolicyGroup.getId())); - status = filterPolicyDAO.removeRelyingParty(filterPolicyGroup, entityId, updatedBy); - } + log.debug("from " + attributeDAO.getAttributes().size() + ", found " + matches + " matches"); + return ret; + } + + /* + * Update policies from an API PUT. + * simplified document + */ + @Override + public void updateRelyingParty(String pgid, Document doc, String updatedBy) + throws FilterPolicyException { + // we have received an XML document (doc) containing the new requested new attribute state + // "pgid" is the request policygroup as passed from spreg UI, "doc" contains the actual entityid + // within the XML payload + log.info("rp update attr doc for " + pgid); + + FilterPolicyGroup policyGroup = filterPolicyDAO.getFilterPolicyGroup(pgid); + if (policyGroup == null) throw new FilterPolicyException("policy group not found"); + if (!policyGroup.isEditable()) throw new FilterPolicyException("policy group not editable"); + + // process each policy ( will be only one requirement rule ) + List attributeFilterPolicies = new ArrayList<>(); + for (Element policy : + XMLHelper.getElementsByName(doc.getDocumentElement(), "AttributeFilterPolicy")) { + Element reqRule = XMLHelper.getElementByName(policy, "PolicyRequirementRule"); + if (reqRule == null) throw new FilterPolicyException("invalid post"); + + // type assumed + String rpid = reqRule.getAttribute("value"); + log.debug("attr update, pol=" + pgid + ", rp=" + rpid); + AttributeFilterPolicy afp = filterPolicyDAO.getFilterPolicy(policyGroup, rpid); + if (afp == null) { + afp = new AttributeFilterPolicy(policyGroup, rpid); + } + + for (Element attributeRule : XMLHelper.getElementsByName(policy, "AttributeRule")) { + String attributeId = attributeRule.getAttribute("attributeID"); + String act = attributeRule.getAttribute("action"); + Attribute attribute; + try { + attribute = attributeDAO.getAttribute(attributeId); + } catch (AttributeNotFoundException e) { + throw new FilterPolicyException(String.format("attribute not found: %s", attributeId), e); } - return status; - } - @Override - public int removeRelyingParty(String entityId, String pgid, String updatedBy) - throws FilterPolicyException { + log.debug(".." + act + " " + attributeId); - return filterPolicyDAO.removeRelyingParty( - filterPolicyDAO.getFilterPolicyGroup(pgid), - entityId, - updatedBy - ); + if (act.equals("replace")) afp.replaceAttributeRule(attributeId, attributeRule); + else if (act.equals("remove")) afp.removeAttributeRule(attributeId); + else throw new FilterPolicyException("unknown action"); + } + // create list of filter policies (based on XML doc) to send to updatefilterpolicy method + attributeFilterPolicies.add(afp); } - @Override - public FilterPolicyGroup getPolicyGroup(String pgid) { - return filterPolicyDAO.getFilterPolicyGroup(pgid); + filterPolicyDAO.updateFilterPolicies(policyGroup, attributeFilterPolicies, updatedBy); + // save the new doc + // policyGroup.writePolicyGroup(); + } + + @Override + public int removeEditableRelyingParty(String entityId, String updatedBy) + throws FilterPolicyException { + int status = 200; + for (FilterPolicyGroup filterPolicyGroup : this.getFilterPolicyGroups()) { + if (filterPolicyGroup.isEditable()) { + log.info( + String.format("Removing %s from policy group %s", entityId, filterPolicyGroup.getId())); + status = filterPolicyDAO.removeRelyingParty(filterPolicyGroup, entityId, updatedBy); + } } - - @Override - public List getFilterPolicyGroups() - { - return filterPolicyDAO.getFilterPolicyGroups(); - } - + return status; + } + + @Override + public int removeRelyingParty(String entityId, String pgid, String updatedBy) + throws FilterPolicyException { + + return filterPolicyDAO.removeRelyingParty( + filterPolicyDAO.getFilterPolicyGroup(pgid), entityId, updatedBy); + } + + @Override + public FilterPolicyGroup getPolicyGroup(String pgid) { + return filterPolicyDAO.getFilterPolicyGroup(pgid); + } + + @Override + public List getFilterPolicyGroups() { + return filterPolicyDAO.getFilterPolicyGroups(); + } } diff --git a/src/main/java/edu/washington/iam/registry/filter/Rule.java b/src/main/java/edu/washington/iam/registry/filter/Rule.java index 693771a..53b6b36 100644 --- a/src/main/java/edu/washington/iam/registry/filter/Rule.java +++ b/src/main/java/edu/washington/iam/registry/filter/Rule.java @@ -15,88 +15,82 @@ * ======================================================================== */ - package edu.washington.iam.registry.filter; -import java.io.Serializable; +import edu.washington.iam.registry.exception.FilterPolicyException; +import edu.washington.iam.tools.XMLHelper; import java.io.BufferedWriter; import java.io.IOException; - -import java.util.List; -import java.util.Vector; -import java.util.Arrays; - +import java.io.Serializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - - -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; - -import edu.washington.iam.tools.XMLHelper; - -import edu.washington.iam.registry.exception.FilterPolicyException; -public class Rule implements Serializable { +public class Rule implements Serializable { - private final Logger log = LoggerFactory.getLogger(getClass()); + private final Logger log = LoggerFactory.getLogger(getClass()); - private String id; - private String type; - private String value; + private String id; + private String type; + private String value; - // create from document element - public Rule (Element ele) throws FilterPolicyException { + // create from document element + public Rule(Element ele) throws FilterPolicyException { - type = ele.getAttribute("xsi:type"); - if (type==null) throw new FilterPolicyException("No type attribute"); - // log.debug("create from doc: " + type); + type = ele.getAttribute("xsi:type"); + if (type == null) throw new FilterPolicyException("No type attribute"); + // log.debug("create from doc: " + type); - if (type.equals("basic:AttributeValueString")) { - value = ele.getAttribute("value"); - } else if (type.equals("basic:AttributeValueRegex")) { - value = ele.getAttribute("regex"); - } else { - throw new FilterPolicyException("unknown rule requirement rules not editable"); - } - } - - // create from strings - public Rule (String t, String v) throws FilterPolicyException { - type = t; - if (type==null) throw new FilterPolicyException("No type attribute"); - value = v; - } - - public void writeXml(BufferedWriter xout) throws IOException { - String valueStr = "value"; - if (type.equals("basic:AttributeValueRegex")) valueStr = "regex"; - xout.write(" \n"); - } - - public void setType(String v) { - type = v; - } - public String getType() { - return (type); - } - - public void setValue(String v) { - value = v; - } - public String getValue() { - return (value); - } - - public boolean isString() { - return type.equals("basic:AttributeValueString"); - } - public boolean isRegex() { - return type.equals("basic:AttributeValueRegex"); + if (type.equals("basic:AttributeValueString")) { + value = ele.getAttribute("value"); + } else if (type.equals("basic:AttributeValueRegex")) { + value = ele.getAttribute("regex"); + } else { + throw new FilterPolicyException("unknown rule requirement rules not editable"); } + } + + // create from strings + public Rule(String t, String v) throws FilterPolicyException { + type = t; + if (type == null) throw new FilterPolicyException("No type attribute"); + value = v; + } + + public void writeXml(BufferedWriter xout) throws IOException { + String valueStr = "value"; + if (type.equals("basic:AttributeValueRegex")) valueStr = "regex"; + xout.write( + " \n"); + } + + public void setType(String v) { + type = v; + } + + public String getType() { + return (type); + } + + public void setValue(String v) { + value = v; + } + + public String getValue() { + return (value); + } + + public boolean isString() { + return type.equals("basic:AttributeValueString"); + } + + public boolean isRegex() { + return type.equals("basic:AttributeValueRegex"); + } } - diff --git a/src/main/java/edu/washington/iam/registry/filter/ValueRule.java b/src/main/java/edu/washington/iam/registry/filter/ValueRule.java index 69ff41c..b19affc 100644 --- a/src/main/java/edu/washington/iam/registry/filter/ValueRule.java +++ b/src/main/java/edu/washington/iam/registry/filter/ValueRule.java @@ -15,136 +15,132 @@ * ======================================================================== */ - package edu.washington.iam.registry.filter; -import java.io.Serializable; +import edu.washington.iam.registry.exception.FilterPolicyException; +import edu.washington.iam.tools.XMLHelper; import java.io.BufferedWriter; import java.io.IOException; - +import java.io.Serializable; import java.util.List; import java.util.Vector; -import java.util.Arrays; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - - -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; -import edu.washington.iam.tools.XMLHelper; - -import edu.washington.iam.registry.exception.FilterPolicyException; - -public class ValueRule implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private String id; - private String type; - private String value; - private List rules; - private boolean permit; - - // create from document element - public ValueRule (Element ele, boolean pf) throws FilterPolicyException { - - rules = new Vector(); - type = ele.getAttribute("xsi:type"); - if (type==null) throw new FilterPolicyException("No type attribute"); - // log.debug("create from doc: " + type); - - permit = pf; - - // add value as first rule - if (type.equals("basic:AttributeValueString")) { - value = ele.getAttribute("value"); - if (value.length()>0) { - log.debug("adding value as rule: " + value); - rules.add(new Rule(type, value)); - } - } else if (type.equals("basic:AttributeValueRegex")) { - value = ele.getAttribute("regex"); - if (value.length()>0) { - log.debug("adding value as rule: " + value); - rules.add(new Rule(type, value)); - } - } - - NodeList nl1 = ele.getChildNodes(); - for (int i=0; i rules; + private boolean permit; + + // create from document element + public ValueRule(Element ele, boolean pf) throws FilterPolicyException { + + rules = new Vector(); + type = ele.getAttribute("xsi:type"); + if (type == null) throw new FilterPolicyException("No type attribute"); + // log.debug("create from doc: " + type); + + permit = pf; + + // add value as first rule + if (type.equals("basic:AttributeValueString")) { + value = ele.getAttribute("value"); + if (value.length() > 0) { + log.debug("adding value as rule: " + value); + rules.add(new Rule(type, value)); + } + } else if (type.equals("basic:AttributeValueRegex")) { + value = ele.getAttribute("regex"); + if (value.length() > 0) { + log.debug("adding value as rule: " + value); + rules.add(new Rule(type, value)); + } } + NodeList nl1 = ele.getChildNodes(); + for (int i = 0; i < nl1.getLength(); i++) { + if (nl1.item(i).getNodeType() != Node.ELEMENT_NODE) continue; + Element e1 = (Element) nl1.item(i); + String name = e1.getNodeName(); + // log.info("rp ele: " + name); - // create from string element - public ValueRule (String type, String value, boolean pf) throws FilterPolicyException { - - rules = new Vector(); - this.type = type; - log.debug("create from string: " + type); - - permit = pf; - this.value = value; + if (XMLHelper.matches(name, "Rule")) { + rules.add(new Rule(e1)); + } } - - // equals - public boolean equals(String type, String value) { - if (this.type.equals(type) && this.value.equals(value)) return true; - return false; + } + + // create from string element + public ValueRule(String type, String value, boolean pf) throws FilterPolicyException { + + rules = new Vector(); + this.type = type; + log.debug("create from string: " + type); + + permit = pf; + this.value = value; + } + + // equals + public boolean equals(String type, String value) { + if (this.type.equals(type) && this.value.equals(value)) return true; + return false; + } + + public void writeXml(BufferedWriter xout) throws IOException { + String pd = "PermitValueRule"; + if (!permit) pd = "DenyValueRule"; + if (rules.size() == 0) { + xout.write(" <" + pd + " xsi:type=\"" + type + "\"/>\n"); + } else if (rules.size() == 1) { + String valueStr = "value"; + if (rules.get(0).getType().equals("basic:AttributeValueRegex")) valueStr = "regex"; + xout.write( + " <" + + pd + + " xsi:type=\"" + + rules.get(0).getType() + + "\" " + + valueStr + + "=\"" + + XMLHelper.safeXml(rules.get(0).getValue()) + + "\"/>\n"); + } else { + xout.write(" <" + pd + " xsi:type=\"" + type + "\">\n"); + for (int i = 0; i < rules.size(); i++) rules.get(i).writeXml(xout); + xout.write(" \n"); } + } + public void setId(String v) { + id = v; + } - public void writeXml(BufferedWriter xout) throws IOException { - String pd = "PermitValueRule"; - if (!permit) pd = "DenyValueRule"; - if (rules.size()==0) { - xout.write(" <" + pd + " xsi:type=\"" + type + "\"/>\n"); - } else if (rules.size()==1) { - String valueStr = "value"; - if (rules.get(0).getType().equals("basic:AttributeValueRegex")) valueStr = "regex"; - xout.write(" <" + pd + " xsi:type=\"" + rules.get(0).getType() + "\" " + valueStr + "=\"" - + XMLHelper.safeXml(rules.get(0).getValue()) + "\"/>\n"); - } else { - xout.write(" <" + pd + " xsi:type=\"" + type + "\">\n"); - for (int i=0; i\n"); - } - } - - public void setId(String v) { - id = v; - } - public String getId() { - return (id); - } + public String getId() { + return (id); + } - public void setType(String v) { - type = v; - } - public String getType() { - return (type); - } + public void setType(String v) { + type = v; + } - public void setRules(List v) { - rules = v; - } - public List getRules() { - return (rules); - } + public String getType() { + return (type); + } + public void setRules(List v) { + rules = v; + } + public List getRules() { + return (rules); + } } - diff --git a/src/main/java/edu/washington/iam/registry/filter/XMLFilterPolicyDAO.java b/src/main/java/edu/washington/iam/registry/filter/XMLFilterPolicyDAO.java index 5970602..43d4766 100644 --- a/src/main/java/edu/washington/iam/registry/filter/XMLFilterPolicyDAO.java +++ b/src/main/java/edu/washington/iam/registry/filter/XMLFilterPolicyDAO.java @@ -1,111 +1,106 @@ package edu.washington.iam.registry.filter; -import edu.washington.iam.registry.exception.AttributeNotFoundException; import edu.washington.iam.registry.exception.FilterPolicyException; -import edu.washington.iam.registry.exception.NoPermissionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import javax.annotation.PostConstruct; -import javax.xml.parsers.DocumentBuilderFactory; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.Vector; +import javax.annotation.PostConstruct; +import javax.xml.parsers.DocumentBuilderFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class XMLFilterPolicyDAO implements FilterPolicyDAO { - private final Logger log = LoggerFactory.getLogger(getClass()); - private List filterPolicyGroups; - - public void setPolicyGroupSources(List policyGroupSources) { - this.policyGroupSources = policyGroupSources; - } - - List policyGroupSources; + private final Logger log = LoggerFactory.getLogger(getClass()); + private List filterPolicyGroups; - @Override - public List getFilterPolicyGroups() { - List filterPolicyGroupList = new ArrayList<>(); - for(XMLFilterPolicyGroup xmlFilterPolicyGroup : filterPolicyGroups) - { - filterPolicyGroupList.add(xmlFilterPolicyGroup.toFilterPolicyGroup()); - } - return filterPolicyGroupList; - } - - @Override - public FilterPolicyGroup getFilterPolicyGroup(String pgid) { - for (XMLFilterPolicyGroup filterPolicyGroup : filterPolicyGroups) - if (filterPolicyGroup.getId().equals(pgid)) - return filterPolicyGroup.toFilterPolicyGroup(); - return null; - } + public void setPolicyGroupSources(List policyGroupSources) { + this.policyGroupSources = policyGroupSources; + } - @Override - public List getFilterPolicies(FilterPolicyGroup filterPolicyGroup) { - return getXMLFilterPolicyGroup(filterPolicyGroup).getFilterPolicies(); - } - - @Override - public AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, String rpid) { - XMLFilterPolicyGroup xmlFilterPolicyGroup = this.getXMLFilterPolicyGroup(filterPolicyGroup); - xmlFilterPolicyGroup.refreshPolicyIfNeeded(); - return xmlFilterPolicyGroup.getFilterPolicy(rpid); - } + List policyGroupSources; - @Override - public void updateFilterPolicies(FilterPolicyGroup filterPolicyGroup, - List attributeFilterPolicies, String updatedBy) - throws FilterPolicyException - { - // updates against AttributeFilterPolicy mean that existing afps are already updated in memory - // this means that it's updated the moment we do writePolicyGroup() - XMLFilterPolicyGroup xmlFilterPolicyGroup = this.getXMLFilterPolicyGroup(filterPolicyGroup); - for(AttributeFilterPolicy attributeFilterPolicy : attributeFilterPolicies){ - if(xmlFilterPolicyGroup.getFilterPolicy(attributeFilterPolicy.getEntityId()) == null){ - xmlFilterPolicyGroup.getFilterPolicies().add(attributeFilterPolicy); - } - // else already updated in memory - } - xmlFilterPolicyGroup.writePolicyGroup(); + @Override + public List getFilterPolicyGroups() { + List filterPolicyGroupList = new ArrayList<>(); + for (XMLFilterPolicyGroup xmlFilterPolicyGroup : filterPolicyGroups) { + filterPolicyGroupList.add(xmlFilterPolicyGroup.toFilterPolicyGroup()); } - - @Override - public int removeRelyingParty(FilterPolicyGroup filterPolicyGroup, String entityId, String updatedBy) - throws FilterPolicyException { - return this.getXMLFilterPolicyGroup(filterPolicyGroup).removeFilterPolicy(entityId); + return filterPolicyGroupList; + } + + @Override + public FilterPolicyGroup getFilterPolicyGroup(String pgid) { + for (XMLFilterPolicyGroup filterPolicyGroup : filterPolicyGroups) + if (filterPolicyGroup.getId().equals(pgid)) return filterPolicyGroup.toFilterPolicyGroup(); + return null; + } + + @Override + public List getFilterPolicies(FilterPolicyGroup filterPolicyGroup) { + return getXMLFilterPolicyGroup(filterPolicyGroup).getFilterPolicies(); + } + + @Override + public AttributeFilterPolicy getFilterPolicy(FilterPolicyGroup filterPolicyGroup, String rpid) { + XMLFilterPolicyGroup xmlFilterPolicyGroup = this.getXMLFilterPolicyGroup(filterPolicyGroup); + xmlFilterPolicyGroup.refreshPolicyIfNeeded(); + return xmlFilterPolicyGroup.getFilterPolicy(rpid); + } + + @Override + public void updateFilterPolicies( + FilterPolicyGroup filterPolicyGroup, + List attributeFilterPolicies, + String updatedBy) + throws FilterPolicyException { + // updates against AttributeFilterPolicy mean that existing afps are already updated in memory + // this means that it's updated the moment we do writePolicyGroup() + XMLFilterPolicyGroup xmlFilterPolicyGroup = this.getXMLFilterPolicyGroup(filterPolicyGroup); + for (AttributeFilterPolicy attributeFilterPolicy : attributeFilterPolicies) { + if (xmlFilterPolicyGroup.getFilterPolicy(attributeFilterPolicy.getEntityId()) == null) { + xmlFilterPolicyGroup.getFilterPolicies().add(attributeFilterPolicy); + } + // else already updated in memory } - - private XMLFilterPolicyGroup getXMLFilterPolicyGroup(FilterPolicyGroup filterPolicyGroup){ - for(XMLFilterPolicyGroup xmlFilterPolicyGroup : filterPolicyGroups){ - if(xmlFilterPolicyGroup.getId().equals(filterPolicyGroup.getId())){ - return xmlFilterPolicyGroup; - } - } - log.info("The unthinkable has happened"); - return null; + xmlFilterPolicyGroup.writePolicyGroup(); + } + + @Override + public int removeRelyingParty( + FilterPolicyGroup filterPolicyGroup, String entityId, String updatedBy) + throws FilterPolicyException { + return this.getXMLFilterPolicyGroup(filterPolicyGroup).removeFilterPolicy(entityId); + } + + private XMLFilterPolicyGroup getXMLFilterPolicyGroup(FilterPolicyGroup filterPolicyGroup) { + for (XMLFilterPolicyGroup xmlFilterPolicyGroup : filterPolicyGroups) { + if (xmlFilterPolicyGroup.getId().equals(filterPolicyGroup.getId())) { + return xmlFilterPolicyGroup; + } } - - private void loadPolicyGroups() { - filterPolicyGroups = new Vector(); - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - builderFactory.setNamespaceAware(true); - - // load policyGroups from each source - for (int p=0; p filterPolicies; - - private String xmlStart = "\n" + - "\n"; - - private String xmlEnd = ""; - private String xmlNotice = "\n \n\n"; - - private long modifyTime = 0; - - Thread reloader = null; - - - public void refreshPolicyIfNeeded() { - log.debug("fp reloader checking..."); - File f = new File(sourceName); - if (f.lastModified()>modifyTime) { - log.debug("reloading policy for " + id + " from " + uri); - locker.writeLock().lock(); - try { - loadPolicyGroup(); - } catch (Exception e) { - log.error("reload errro: " + e); - } - locker.writeLock().unlock(); - log.debug("reload completed, time now " + modifyTime); - } - } - - // thread to sometimes reload the policies - class PolicyReloader extends Thread { - - public void run() { - log.debug("policy reloader running: interval = " + refreshInterval); - - // loop on checking the source - - while (true) { - refreshPolicyIfNeeded(); - try { - if (isInterrupted()) { - log.info("interrupted during processing"); - break; - } - Thread.sleep(refreshInterval * 1000); - } catch (InterruptedException e) { - log.info("sleep interrupted"); - break; - } - } - } + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ReentrantReadWriteLock locker = new ReentrantReadWriteLock(); + + private String id; + private String description; + private Document doc; + private boolean editable; + private String uri; + private String sourceName; + private String tempUri; + private int refreshInterval = 0; + private List filterPolicies; + + private String xmlStart = + "\n" + + "\n"; + + private String xmlEnd = ""; + private String xmlNotice = + "\n \n\n"; + + private long modifyTime = 0; + + Thread reloader = null; + + public void refreshPolicyIfNeeded() { + log.debug("fp reloader checking..."); + File f = new File(sourceName); + if (f.lastModified() > modifyTime) { + log.debug("reloading policy for " + id + " from " + uri); + locker.writeLock().lock(); + try { + loadPolicyGroup(); + } catch (Exception e) { + log.error("reload errro: " + e); + } + locker.writeLock().unlock(); + log.debug("reload completed, time now " + modifyTime); } + } - public XMLFilterPolicyGroup(Properties prop) throws FilterPolicyException { - id = prop.getProperty("id"); - description = prop.getProperty("description"); - uri = prop.getProperty("uri"); - sourceName = uri.replaceFirst("file:",""); - tempUri = prop.getProperty("tempUri"); - String v = prop.getProperty("editable"); - if (v.equalsIgnoreCase("true")) editable = true; - else editable = false; - v = prop.getProperty("refresh"); - try { - if (v!=null) refreshInterval = Integer.parseInt(v); // seconds - } catch (NumberFormatException e) { - log.error("invalid refresh arg " + v); - } - loadPolicyGroup(); - if (refreshInterval>0) { - reloader = new Thread(new PolicyReloader()); - reloader.start(); - } - - } - - /* - * Load policies. This code allows us to input more complex documents - * than we produce. e.g. multiple requirement rules, split requirement rules. - */ - private void loadPolicyGroup() throws FilterPolicyException { - log.info("load policy group for " + id + " from " + uri); - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - builderFactory.setNamespaceAware(true); - filterPolicies = new Vector(); - - if (uri!=null) { - try { - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - doc = builder.parse (uri); - } catch (Exception ex) { - log.error("parse issue: " + ex); - throw new FilterPolicyException("parse error"); - } + // thread to sometimes reload the policies + class PolicyReloader extends Thread { - // update the timestamp - File f = new File(sourceName); - modifyTime = f.lastModified(); - log.debug("filter load " + f.getName() + ": time = " + modifyTime); + public void run() { + log.debug("policy reloader running: interval = " + refreshInterval); + // loop on checking the source - List list = XMLHelper.getElementsByName(doc.getDocumentElement(), "AttributeFilterPolicy"); - log.info("found " + list.size()); + while (true) { + refreshPolicyIfNeeded(); + try { + if (isInterrupted()) { + log.info("interrupted during processing"); + break; + } + Thread.sleep(refreshInterval * 1000); + } catch (InterruptedException e) { + log.info("sleep interrupted"); + break; + } + } + } + } + + public XMLFilterPolicyGroup(Properties prop) throws FilterPolicyException { + id = prop.getProperty("id"); + description = prop.getProperty("description"); + uri = prop.getProperty("uri"); + sourceName = uri.replaceFirst("file:", ""); + tempUri = prop.getProperty("tempUri"); + String v = prop.getProperty("editable"); + if (v.equalsIgnoreCase("true")) editable = true; + else editable = false; + v = prop.getProperty("refresh"); + try { + if (v != null) refreshInterval = Integer.parseInt(v); // seconds + } catch (NumberFormatException e) { + log.error("invalid refresh arg " + v); + } + loadPolicyGroup(); + if (refreshInterval > 0) { + reloader = new Thread(new PolicyReloader()); + reloader.start(); + } + } + + /* + * Load policies. This code allows us to input more complex documents + * than we produce. e.g. multiple requirement rules, split requirement rules. + */ + private void loadPolicyGroup() throws FilterPolicyException { + log.info("load policy group for " + id + " from " + uri); + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + builderFactory.setNamespaceAware(true); + filterPolicies = new Vector(); + + if (uri != null) { + try { + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + doc = builder.parse(uri); + } catch (Exception ex) { + log.error("parse issue: " + ex); + throw new FilterPolicyException("parse error"); + } - for (int i=0; i getFilterPolicies() { - return filterPolicies; - } - public boolean isEditable() { - return editable; - } - -} + // move the temp file to live + try { + File live = new File(new URI(uri)); + File temp = new File(new URI(tempUri)); + temp.renameTo(live); + } catch (Exception e) { + log.error("rename: " + e); + return 1; + } + return 0; + } + + public String getId() { + return (id); + } + public String getUri() { + return (uri); + } + + public String getDescription() { + return (description); + } + + public List getFilterPolicies() { + return filterPolicies; + } + + public boolean isEditable() { + return editable; + } +} diff --git a/src/main/java/edu/washington/iam/registry/proxy/Proxy.java b/src/main/java/edu/washington/iam/registry/proxy/Proxy.java index 5a8bbf5..7b46c44 100644 --- a/src/main/java/edu/washington/iam/registry/proxy/Proxy.java +++ b/src/main/java/edu/washington/iam/registry/proxy/Proxy.java @@ -15,92 +15,78 @@ * ======================================================================== */ - package edu.washington.iam.registry.proxy; import java.io.Serializable; - -import java.util.List; -import java.util.Vector; -import java.util.Arrays; -import java.io.BufferedWriter; -import java.io.IOException; - - +import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; +public class Proxy implements Serializable { -import edu.washington.iam.tools.XMLHelper; + private final Logger log = LoggerFactory.getLogger(getClass()); -import edu.washington.iam.registry.exception.ProxyException; -import java.util.UUID; - -public class Proxy implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); + private UUID uuid; + private String entityId; + private boolean socialActive; + private String updatedBy; + private String startTime; + private String endTime; - private UUID uuid; - private String entityId; - private boolean socialActive; - private String updatedBy; - private String startTime; - private String endTime; + private String safePy(String in) { + return in.replaceAll("\"", "\\\""); + } + public Proxy() {} - private String safePy(String in) { - return in.replaceAll("\"","\\\""); - } + // 2017-11-13 mattjm constructor taking XML document as argument removed (and deleted + // XMLProxyManager) - public Proxy (){} + public void setEntityId(String entityId) { + this.entityId = entityId; + } - //2017-11-13 mattjm constructor taking XML document as argument removed (and deleted XMLProxyManager) + public String getEntityId() { + return (entityId); + } + public void setSocialActive(boolean socialActive) { + this.socialActive = socialActive; + } - public void setEntityId(String entityId) { - this.entityId = entityId; - } - public String getEntityId() { - return (entityId); - } + public boolean getSocialActive() { + return (socialActive); + } - public void setSocialActive(boolean socialActive) { - this.socialActive = socialActive; - } - public boolean getSocialActive() { return (socialActive); } + public void setUuid(UUID uuid) { + this.uuid = uuid; + } - public void setUuid(UUID uuid) { - this.uuid = uuid; - } - public UUID getUuid() { return uuid; } + public UUID getUuid() { + return uuid; + } - public String getUpdatedBy() { - return updatedBy; - } + public String getUpdatedBy() { + return updatedBy; + } - public void setUpdatedBy(String updatedBy) { - this.updatedBy = updatedBy; - } + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } - public String getStartTime() { - return startTime; - } + public String getStartTime() { + return startTime; + } - public void setStartTime(String startTime) { - this.startTime = startTime; - } + public void setStartTime(String startTime) { + this.startTime = startTime; + } - public String getEndTime() { - return endTime; - } - - public void setEndTime(String endTime) { - this.endTime = endTime; - } + public String getEndTime() { + return endTime; + } + public void setEndTime(String endTime) { + this.endTime = endTime; + } } - diff --git a/src/main/java/edu/washington/iam/registry/proxy/ProxyIdp.java b/src/main/java/edu/washington/iam/registry/proxy/ProxyIdp.java index 827e870..d151be2 100644 --- a/src/main/java/edu/washington/iam/registry/proxy/ProxyIdp.java +++ b/src/main/java/edu/washington/iam/registry/proxy/ProxyIdp.java @@ -18,90 +18,95 @@ /*TODO mattjm 2017-11-13 this class can be deleted soon--no non-test JAVA code reaches it (some tests and javascript still do)*/ - package edu.washington.iam.registry.proxy; -import java.io.Serializable; - -import java.util.List; -import java.util.Vector; -import java.util.Arrays; +import edu.washington.iam.registry.exception.ProxyException; +import edu.washington.iam.tools.XMLHelper; import java.io.BufferedWriter; import java.io.IOException; - - +import java.io.Serializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; - -import edu.washington.iam.tools.XMLHelper; - -import edu.washington.iam.registry.exception.ProxyException; - -public class ProxyIdp implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private String idp; - private String clientId; - private String clientSecret; - - private String safePy(String in) { - return in.replaceAll("\"","\\\""); - } - - // TODO: Our new constructor doesn't check for 'invalid' characters. Sort out if these are really invalid - // check for any bad chars - private void isOK(String s) throws ProxyException { - if (s.indexOf('<')>=0 || s.indexOf('>')>=0 || s.indexOf('"')>=0 || s.indexOf('\'')>=0 ) throw new ProxyException("invalid characters"); - } - - // create from document element - public ProxyIdp(){} - public ProxyIdp (Element ele) throws ProxyException { - - idp = ele.getAttribute("idp"); - clientId = ele.getAttribute("clientId"); - clientSecret = ele.getAttribute("clientSecret"); - isOK(clientId); - isOK(clientSecret); - log.debug("create from doc: " + clientId); - } - - // write xml doc - public void writeXml(BufferedWriter xout) throws IOException { - xout.write("\n"); - } - - // write py doc - public void writePy(BufferedWriter xout) throws IOException { - xout.write("\"" + idp + "\": {\"key\": \"" + safePy(clientId) + "\", \"secret\": \"" + safePy(clientSecret) + "\"},\n"); - } - - public void setIdp(String v) { - idp = v; - } - public String getIdp() { - return (idp); - } - public void setClientId(String v) { - clientId = v; - } - public String getClientId() { - return (clientId); - } - public void setClientSecret(String v) { - clientSecret = v; - } - public String getClientSecret() { - return (clientSecret); - } +public class ProxyIdp implements Serializable { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private String idp; + private String clientId; + private String clientSecret; + + private String safePy(String in) { + return in.replaceAll("\"", "\\\""); + } + + // TODO: Our new constructor doesn't check for 'invalid' characters. Sort out if these are really + // invalid + // check for any bad chars + private void isOK(String s) throws ProxyException { + if (s.indexOf('<') >= 0 || s.indexOf('>') >= 0 || s.indexOf('"') >= 0 || s.indexOf('\'') >= 0) + throw new ProxyException("invalid characters"); + } + + // create from document element + public ProxyIdp() {} + + public ProxyIdp(Element ele) throws ProxyException { + + idp = ele.getAttribute("idp"); + clientId = ele.getAttribute("clientId"); + clientSecret = ele.getAttribute("clientSecret"); + isOK(clientId); + isOK(clientSecret); + log.debug("create from doc: " + clientId); + } + + // write xml doc + public void writeXml(BufferedWriter xout) throws IOException { + xout.write( + "\n"); + } + + // write py doc + public void writePy(BufferedWriter xout) throws IOException { + xout.write( + "\"" + + idp + + "\": {\"key\": \"" + + safePy(clientId) + + "\", \"secret\": \"" + + safePy(clientSecret) + + "\"},\n"); + } + + public void setIdp(String v) { + idp = v; + } + + public String getIdp() { + return (idp); + } + + public void setClientId(String v) { + clientId = v; + } + + public String getClientId() { + return (clientId); + } + + public void setClientSecret(String v) { + clientSecret = v; + } + + public String getClientSecret() { + return (clientSecret); + } } - diff --git a/src/main/java/edu/washington/iam/registry/proxy/ProxyManager.java b/src/main/java/edu/washington/iam/registry/proxy/ProxyManager.java index 0496de1..91de01e 100644 --- a/src/main/java/edu/washington/iam/registry/proxy/ProxyManager.java +++ b/src/main/java/edu/washington/iam/registry/proxy/ProxyManager.java @@ -17,29 +17,23 @@ package edu.washington.iam.registry.proxy; +import edu.washington.iam.registry.exception.ProxyException; import java.io.Serializable; import java.util.List; -import org.w3c.dom.Document; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +public interface ProxyManager extends Serializable { + public List getProxys(); -import edu.washington.iam.registry.exception.ProxyException; -import edu.washington.iam.registry.exception.NoPermissionException; + public Proxy getProxy(String entityId); -public interface ProxyManager extends Serializable { - public List getProxys(); - public Proxy getProxy(String entityId); - public int removeProxy(String rpid, String updatedBy) throws ProxyException; - public List getProxyHistory(String entityId) throws ProxyException; - ; + public int removeProxy(String rpid, String updatedBy) throws ProxyException; - /** - * - * @param proxy Takes a validated proxy and stores it - */ - public void updateProxy(Proxy proxy, String updatedBy) throws ProxyException; + public List getProxyHistory(String entityId) throws ProxyException; + ; + /** + * + * @param proxy Takes a validated proxy and stores it + */ + public void updateProxy(Proxy proxy, String updatedBy) throws ProxyException; } diff --git a/src/main/java/edu/washington/iam/registry/proxy/ProxyManagerDB.java b/src/main/java/edu/washington/iam/registry/proxy/ProxyManagerDB.java index c4f8a98..3dd629e 100644 --- a/src/main/java/edu/washington/iam/registry/proxy/ProxyManagerDB.java +++ b/src/main/java/edu/washington/iam/registry/proxy/ProxyManagerDB.java @@ -2,6 +2,11 @@ import edu.washington.iam.registry.exception.ProxyException; import edu.washington.iam.registry.rp.UuidManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -9,119 +14,114 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - public class ProxyManagerDB implements ProxyManager { - private final Logger log = LoggerFactory.getLogger(getClass()); - private JdbcTemplate template; - - public void setTemplate(JdbcTemplate template) { - this.template = template; + private final Logger log = LoggerFactory.getLogger(getClass()); + private JdbcTemplate template; + + public void setTemplate(JdbcTemplate template) { + this.template = template; + } + + @Autowired private UuidManager uuidManager; + + public List getProxys() { + log.debug("getting the list of proxies"); + return template.query("select * from proxy where end_time is null", new ProxyMapper()); + } + + public List getProxyHistory(String entityId) throws ProxyException { + List proxys = null; + try { + proxys = + template.query( + "select * from proxy where end_time is not null and entity_id = ?", + new Object[] {entityId}, + new ProxyMapper()); + return proxys; + } catch (Exception e) { + String errorMsg = String.format("error getting proxy history: %s", entityId); + log.debug(errorMsg); + throw new ProxyException(errorMsg); } - - @Autowired - private UuidManager uuidManager; - - public List getProxys() { - log.debug("getting the list of proxies"); - return template.query("select * from proxy where end_time is null", - new ProxyMapper()); + } + + public Proxy getProxy(String entityId) { + log.debug("looking for proxy for " + entityId); + Proxy proxy = null; + + List proxies = + template.query( + "select * from proxy where entity_id = ? and end_time is null", + new Object[] {entityId}, + new ProxyMapper()); + if (proxies.size() != 0) { + proxy = proxies.get(0); } - public List getProxyHistory(String entityId) throws ProxyException { - List proxys = null; - try { - proxys = template.query( - "select * from proxy where end_time is not null and entity_id = ?", - new Object[] {entityId}, - new ProxyMapper()); - return proxys; - } - catch (Exception e){ - String errorMsg = String.format("error getting proxy history: %s", entityId); - log.debug(errorMsg); - throw new ProxyException(errorMsg); - } - + return proxy; + } + + public int removeProxy(String rpid, String updatedBy) throws ProxyException { + log.debug("looking to delete proxy for " + rpid); + + List rpIds = + template.queryForList( + "select id from proxy where entity_id = ? and end_time is null", Integer.class, rpid); + if (rpIds.size() == 1 && rpIds.get(0) != null) { + template.update( + "update proxy set end_time = now(), updated_by = ?, status = ? where id = ?", + updatedBy, + 0, + rpIds.get(0)); + log.debug("updated (delete) proxy for %s", rpid); + return 200; + } else if (rpIds.size() == 0) { + // there is no record with end_time = null if social gateway wasn't enabled + log.info(String.format("No proxy found for %s (usually not an error--was inactive)", rpid)); + // if there are no records with end_time = null then there are no active records to remove + // and everything is fine. mattjm 2018-10-23 + return 200; + } else { + throw new ProxyException("more than one active proxy record found!! No update performed."); + // TODO what about a return code? } - - public Proxy getProxy(String entityId) { - log.debug("looking for proxy for " + entityId); - Proxy proxy = null; - - List proxies = template.query("select * from proxy where entity_id = ? and end_time is null", - new Object[] {entityId}, - new ProxyMapper()); - if(proxies.size() != 0){ - proxy = proxies.get(0); - } - - return proxy; - } - - public int removeProxy(String rpid, String updatedBy) throws ProxyException { - log.debug("looking to delete proxy for " + rpid); - - List rpIds = template.queryForList( - "select id from proxy where entity_id = ? and end_time is null", - Integer.class, rpid); - if (rpIds.size() == 1 && rpIds.get(0) != null) { - template.update("update proxy set end_time = now(), updated_by = ?, status = ? where id = ?", updatedBy, 0, rpIds.get(0)); - log.debug("updated (delete) proxy for %s", rpid); - return 200; - } - else if (rpIds.size() == 0) { - //there is no record with end_time = null if social gateway wasn't enabled - log.info(String.format("No proxy found for %s (usually not an error--was inactive)", rpid)); - //if there are no records with end_time = null then there are no active records to remove - //and everything is fine. mattjm 2018-10-23 - return 200; - } - else{ - throw new ProxyException("more than one active proxy record found!! No update performed."); - //TODO what about a return code? - } + } + + // add or update a proxy + public void updateProxy(Proxy proxy, String updatedBy) throws ProxyException { + + proxy.setUuid(uuidManager.getUuid(proxy.getEntityId())); + log.info("attempting proxy update " + proxy.getEntityId()); + // recycle "delete" method to mark current record inactive + removeProxy(proxy.getEntityId(), updatedBy); + // only add a record with end_time=null if social gateway should be active. + if (proxy.getSocialActive()) { + log.info("Marked current proxy record inactive--adding new one next"); + template.update( + "insert into proxy (uuid, entity_id, start_time, end_time, updated_by, status) " + + "values (?, ?, now(), null, ?, 1)", + proxy.getUuid(), + proxy.getEntityId(), + updatedBy); } - - //add or update a proxy - public void updateProxy(Proxy proxy, String updatedBy) throws ProxyException { - - proxy.setUuid(uuidManager.getUuid(proxy.getEntityId())); - log.info("attempting proxy update " + proxy.getEntityId()); - //recycle "delete" method to mark current record inactive - removeProxy(proxy.getEntityId(), updatedBy); - //only add a record with end_time=null if social gateway should be active. - if (proxy.getSocialActive()) { - log.info("Marked current proxy record inactive--adding new one next"); - template.update("insert into proxy (uuid, entity_id, start_time, end_time, updated_by, status) " - + "values (?, ?, now(), null, ?, 1)", - proxy.getUuid(), - proxy.getEntityId(), - updatedBy); - - } - } - - private static final class ProxyMapper implements ResultSetExtractor> { - @Override - public List extractData(ResultSet rs) throws SQLException, DataAccessException{ - List proxyList = new ArrayList<>(); - while(rs.next()){ - Proxy proxy = new Proxy(); - proxy.setEntityId(rs.getString("entity_id")); - proxy.setUuid((UUID)rs.getObject("uuid")); - proxy.setSocialActive(true); - proxy.setUpdatedBy(rs.getString("updated_by")); - proxy.setStartTime(rs.getString("start_time")); - proxy.setEndTime(rs.getString("end_time")); - proxyList.add(proxy); - } - - return proxyList; - } + } + + private static final class ProxyMapper implements ResultSetExtractor> { + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + List proxyList = new ArrayList<>(); + while (rs.next()) { + Proxy proxy = new Proxy(); + proxy.setEntityId(rs.getString("entity_id")); + proxy.setUuid((UUID) rs.getObject("uuid")); + proxy.setSocialActive(true); + proxy.setUpdatedBy(rs.getString("updated_by")); + proxy.setStartTime(rs.getString("start_time")); + proxy.setEndTime(rs.getString("end_time")); + proxyList.add(proxy); + } + + return proxyList; } + } } diff --git a/src/main/java/edu/washington/iam/registry/rp/AssertionConsumerService.java b/src/main/java/edu/washington/iam/registry/rp/AssertionConsumerService.java index 03eb8c7..e1dca59 100644 --- a/src/main/java/edu/washington/iam/registry/rp/AssertionConsumerService.java +++ b/src/main/java/edu/washington/iam/registry/rp/AssertionConsumerService.java @@ -15,94 +15,89 @@ * ======================================================================== */ - package edu.washington.iam.registry.rp; -import java.io.Serializable; +import edu.washington.iam.registry.exception.RelyingPartyException; +import edu.washington.iam.tools.XMLHelper; import java.io.BufferedWriter; import java.io.IOException; - -import java.lang.NumberFormatException; -import java.util.List; -import java.util.Vector; - +import java.io.Serializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import edu.washington.iam.tools.XMLHelper; -import edu.washington.iam.registry.exception.RelyingPartyException; - -public class AssertionConsumerService implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private String binding; - private String location; - private String index; - - // create from document element - public AssertionConsumerService (Element ele) throws RelyingPartyException { - binding = ele.getAttribute("Binding"); - location = ele.getAttribute("Location"); - index = ele.getAttribute("index"); - if (binding==null || location==null || index==null) throw new RelyingPartyException("missing ACS attributes"); - if (!binding.startsWith("urn:")) throw new RelyingPartyException("invalid ACS binding"); - if (!location.startsWith("http")) throw new RelyingPartyException("invalid ACS location"); - try { - int i = Integer.parseInt(index); - } catch (NumberFormatException e) { - throw new RelyingPartyException("invalid acs index"); - } - } - // create from inputs - public AssertionConsumerService (int i, String b, String l) { - binding = b; - location = l; - index = "" + i; +public class AssertionConsumerService implements Serializable { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private String binding; + private String location; + private String index; + + // create from document element + public AssertionConsumerService(Element ele) throws RelyingPartyException { + binding = ele.getAttribute("Binding"); + location = ele.getAttribute("Location"); + index = ele.getAttribute("index"); + if (binding == null || location == null || index == null) + throw new RelyingPartyException("missing ACS attributes"); + if (!binding.startsWith("urn:")) throw new RelyingPartyException("invalid ACS binding"); + if (!location.startsWith("http")) throw new RelyingPartyException("invalid ACS location"); + try { + int i = Integer.parseInt(index); + } catch (NumberFormatException e) { + throw new RelyingPartyException("invalid acs index"); } - -/** - public Element toDOM(Document doc) { - Element acs = doc.createElement("AssertionConsumerService"); - acs.setAttribute("Binding", binding); - acs.setAttribute("Location", location); - acs.setAttribute("index", index); - return acs; - } - **/ - - public void writeXml(BufferedWriter xout) throws IOException { - xout.write(" \n"); - } - - public void setBinding(String v) { - binding = v; - } - public String getBinding() { - return (binding); - } - - public void setLocation(String v) { - location = v; - } - public String getLocation() { - return (location); - } - - public void setIndex(String v) { - index = v; - } - public String getIndex() { - return (index); - } - + } + + // create from inputs + public AssertionConsumerService(int i, String b, String l) { + binding = b; + location = l; + index = "" + i; + } + + /** + * public Element toDOM(Document doc) { + * Element acs = doc.createElement("AssertionConsumerService"); + * acs.setAttribute("Binding", binding); + * acs.setAttribute("Location", location); + * acs.setAttribute("index", index); + * return acs; + * } + **/ + public void writeXml(BufferedWriter xout) throws IOException { + xout.write( + " \n"); + } + + public void setBinding(String v) { + binding = v; + } + + public String getBinding() { + return (binding); + } + + public void setLocation(String v) { + location = v; + } + + public String getLocation() { + return (location); + } + + public void setIndex(String v) { + index = v; + } + + public String getIndex() { + return (index); + } } - diff --git a/src/main/java/edu/washington/iam/registry/rp/ContactPerson.java b/src/main/java/edu/washington/iam/registry/rp/ContactPerson.java index b7fc374..98fabd3 100644 --- a/src/main/java/edu/washington/iam/registry/rp/ContactPerson.java +++ b/src/main/java/edu/washington/iam/registry/rp/ContactPerson.java @@ -15,126 +15,126 @@ * ======================================================================== */ - package edu.washington.iam.registry.rp; -import java.io.Serializable; +import edu.washington.iam.registry.exception.RelyingPartyException; +import edu.washington.iam.tools.XMLHelper; import java.io.BufferedWriter; import java.io.IOException; - -import java.util.List; -import java.util.Vector; - +import java.io.Serializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; -import edu.washington.iam.tools.XMLHelper; - -import edu.washington.iam.registry.exception.RelyingPartyException; - -public class ContactPerson implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - - private String type; - private String company; - private String surName; - private String givenName; - private String email; - private String phone; - - // create from document element - public ContactPerson (Element ele) throws RelyingPartyException { - type = ele.getAttribute("contactType"); - if (type==null || !(type.equals("technical") || type.equals("administrative") || type.equals("support") || - type.equals("billing") || type.equals("other"))) throw new RelyingPartyException("invalid contact type"); - company = null; - surName = null; - givenName = null; - email = null; - phone = null; - - NodeList chl = ele.getChildNodes(); - for (int i=0; i\n"); - if (company != null) xout.write(" " + XMLHelper.safeXml(company) + "\n"); - if (givenName != null) xout.write(" " + XMLHelper.safeXml(givenName) + "\n"); - if (surName != null) xout.write(" " + XMLHelper.safeXml(surName) + "\n"); - if (email != null) xout.write(" " + XMLHelper.safeXml(email) + "\n"); - if (phone != null) xout.write(" " + XMLHelper.safeXml(phone) + "\n"); - xout.write(" \n"); - } - - public void setType(String v) { - type = v; - } - public String getType() { - return (type); - } - - public void setCompany(String v) { - company = v; - } - public String getCompany() { - return (company); - } - - public void setSurName(String v) { - surName = v; - } - public String getSurName() { - return (surName); - } - - public void setGivenName(String v) { - givenName = v; - } - public String getGivenName() { - return (givenName); - } - - public void setEmail(String v) { - email = v; - } - public String getEmail() { - return (email); - } - - public void setPhone(String v) { - phone = v; - } - public String getPhone() { - return (phone); +public class ContactPerson implements Serializable { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private String type; + private String company; + private String surName; + private String givenName; + private String email; + private String phone; + + // create from document element + public ContactPerson(Element ele) throws RelyingPartyException { + type = ele.getAttribute("contactType"); + if (type == null + || !(type.equals("technical") + || type.equals("administrative") + || type.equals("support") + || type.equals("billing") + || type.equals("other"))) throw new RelyingPartyException("invalid contact type"); + company = null; + surName = null; + givenName = null; + email = null; + phone = null; + + NodeList chl = ele.getChildNodes(); + for (int i = 0; i < chl.getLength(); i++) { + if (chl.item(i).getNodeType() != Node.ELEMENT_NODE) continue; + Element ch = (Element) chl.item(i); + String name = ch.getNodeName(); + if (XMLHelper.matches(name, "Company")) company = ch.getTextContent(); + if (XMLHelper.matches(name, "SurName")) surName = ch.getTextContent(); + if (XMLHelper.matches(name, "GivenName")) givenName = ch.getTextContent(); + if (XMLHelper.matches(name, "EmailAddress")) email = ch.getTextContent(); + if (XMLHelper.matches(name, "TelephoneNumber")) phone = ch.getTextContent(); } + } + + // create from string + public ContactPerson(String t) { + type = t; + company = null; + surName = null; + givenName = null; + email = null; + phone = null; + } + + public void writeXml(BufferedWriter xout) throws IOException { + xout.write(" \n"); + if (company != null) xout.write(" " + XMLHelper.safeXml(company) + "\n"); + if (givenName != null) + xout.write(" " + XMLHelper.safeXml(givenName) + "\n"); + if (surName != null) xout.write(" " + XMLHelper.safeXml(surName) + "\n"); + if (email != null) + xout.write(" " + XMLHelper.safeXml(email) + "\n"); + if (phone != null) + xout.write(" " + XMLHelper.safeXml(phone) + "\n"); + xout.write(" \n"); + } + + public void setType(String v) { + type = v; + } + + public String getType() { + return (type); + } + + public void setCompany(String v) { + company = v; + } + + public String getCompany() { + return (company); + } + + public void setSurName(String v) { + surName = v; + } + + public String getSurName() { + return (surName); + } + + public void setGivenName(String v) { + givenName = v; + } + + public String getGivenName() { + return (givenName); + } + + public void setEmail(String v) { + email = v; + } + + public String getEmail() { + return (email); + } + + public void setPhone(String v) { + phone = v; + } + + public String getPhone() { + return (phone); + } } - diff --git a/src/main/java/edu/washington/iam/registry/rp/DBMetadata.java b/src/main/java/edu/washington/iam/registry/rp/DBMetadata.java index c71b714..abcd5e5 100644 --- a/src/main/java/edu/washington/iam/registry/rp/DBMetadata.java +++ b/src/main/java/edu/washington/iam/registry/rp/DBMetadata.java @@ -1,276 +1,311 @@ -package edu.washington.iam.registry.rp; - - -import edu.washington.iam.registry.exception.RelyingPartyException; -import edu.washington.iam.tools.XMLHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.w3c.dom.Document; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.*; -import java.sql.Timestamp; - -import edu.washington.iam.tools.IdpHelper; - -public class DBMetadata implements MetadataDAO { - private final Logger log = LoggerFactory.getLogger(getClass()); - - - private String id; - private String groupId; - private boolean editable; - private IdpHelper idpHelper = null; - public void setIdpHelper(IdpHelper v) { - idpHelper = v; - } - - - - @Autowired - private JdbcTemplate template; - - - @Override - public List getRelyingParties() { - List rps = template.query( - "select * from metadata where end_time is null and group_id = ?", - new Object[] {groupId}, - new RelyingPartyMapper()); - return rps; - } - - - @Override - public List getRelyingPartyHistoryById(String id) throws RelyingPartyException { - // get metadata - List rps = null; - try { - rps = template.query( - "select * from metadata where group_id = ? and entity_id = ?" + - " order by start_time ASC", - new Object[]{groupId, id}, - new RelyingPartyMapper()); - log.info("Got a response in getRelyingPartyHistoryById"); - return rps; - } - catch (Exception e){ - String errorMsg = String.format("error getting rp: %s, rps size = %s", id, (rps == null) ? 0 : rps.size()); - log.error(errorMsg, e); - throw new RelyingPartyException(errorMsg); - } - - - } - - - @Override - public RelyingParty getRelyingPartyById(String id) throws RelyingPartyException { - List rps = template.query( - "select * from metadata where end_time is null and group_id = ? and entity_id = ?", - new Object[] { groupId, id}, - new RelyingPartyMapper()); - if(rps.size() == 1 && rps.get(0) != null){ - return rps.get(0); - } - else { - String errorMsg = String.format("error getting rp: %s, rps size = %s", id, (rps == null) ? 0 : rps.size()); - log.error(errorMsg); - throw new RelyingPartyException(errorMsg); - } - } - - @Override - public List searchRelyingPartyIds(String searchStr){ - String sql; - List results; - if(searchStr != null) { - results = template.queryForList( - "select entity_id from metadata where end_time is null and group_id = ? and entity_id like ?", - new Object[]{groupId, '%' + searchStr + '%'}, - String.class); - } - else { - results = template.queryForList( - "select entity_id from metadata where end_time is null and group_id = ?", - new Object[]{groupId}, - String.class); - } - return results; - } - - @Override - public List getRelyingPartiesById(String search){ - String sql; - log.debug("DB search for id like " + search); - List rps = template.query( - "select * from metadata where end_time is null and group_id = ? and entity_id like ?", - new Object[]{groupId, '%' + search + '%'}, - new RelyingPartyMapper()); - return rps; - } - - @Override - public List getRelyingPartiesByAdmin(String admin){ - String sql; - log.debug("DB search for admin " + admin); - List rps = null; - if (admin.indexOf("@")>0) { - rps = template.query( - "select * from metadata where end_time is null and group_id = ? and (xml like ? or xml like ?)", - new Object[]{groupId, "%"+admin+"%", - "%mailto:"+admin+"%"}, - new RelyingPartyMapper()); - } else { - rps = template.query( - "select * from metadata where end_time is null and group_id = ? and (xml like ? or xml like ? or xml like ? or xml like ?)", - new Object[]{groupId, "%"+admin+"@uw.edu%", - "%"+admin+"@washington.edu%", - "%mailto:"+admin+"@uw.edu%", - "%mailto:"+admin+"@washington.edu%"}, - new RelyingPartyMapper()); - } - return rps; - } - - @Override - public void updateRelyingParty(RelyingParty relyingParty, String updatedBy) { - log.info(String.format("updating metadata for rp %s in %s", relyingParty.getEntityId(), groupId)); - try { - String xml = XMLHelper.serializeXmlToString(relyingParty); - List existingIds = template.queryForList( - "select id from metadata where group_id = ? and entity_id = ? and end_time is null", - Integer.class, - groupId, relyingParty.getEntityId()); - if (existingIds.size() == 0) { - // no active records so we add an active record - - template.update( - "insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time, updated_by, status) values " + - "(? ,?, ?, ?, ?, now(), ?, 1)", - genUUID(), groupId, relyingParty.getEntityId(), xml, null, updatedBy); - log.debug("added new rp " + relyingParty.getEntityId()); - } else if (existingIds.size() == 1) { - //we need to get the uuid - List uuid = template.queryForList("select uuid from metadata where entity_id = ? and end_time is null", - UUID.class, - relyingParty.getEntityId()); - relyingParty.setUuid(uuid.get(0)); - // active record exists so mark last one inactive - template.update("update metadata set end_time = now(), status = ? where id = ?", 0, existingIds.get(0)); - // add new active record - log.info(Integer.toString(template.update( - "insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time, updated_by, status) values " + - "(?, ?, ?, ?, ?, now(), ?, 1)", - relyingParty.getUuid(), groupId, relyingParty.getEntityId(), xml, null, updatedBy))); - log.debug("updated existing rp " + relyingParty.getEntityId()); - } else { - throw new RelyingPartyException("more than one active metadata record found!! No update performed. "); - } - if (idpHelper!=null) idpHelper.notifyIdps("metadata"); - } catch (Exception e) { - log.info("update metadata trouble: " + e.getMessage()); - // just eat it - don't know the repercussions - } - } - - - @Override - public void removeRelyingParty(String rpid, String updatedBy) { - try { - log.info(String.format("looking to remove metadata for rp %s in %s", rpid, groupId)); - /* small bit of errata: when removing an RP we rewrite the updatedBy field of the last record to the netid - of the person who deleted it. In this sense we lose the data of whoever made the last update, - but I think it's more important to know who deleted it over who made the last update - before it was deleted. Contrast with an update (above) where we mark the old record - inactive but don't change who updated it. We don't display deletes to users, so this mostly - matters in an audit situation. - I supposed a smarter implementation could put an end_date on the last update record and just add a new one - with end_date already set. */ - List rpIds = template.queryForList( - "select id from metadata where group_id = ? and entity_id = ? and end_time is null", - Integer.class, - groupId, rpid); - if (rpIds.size() == 1 && rpIds.get(0) != null) { - log.info(Integer.toString(template.update("update metadata set end_time = now(), updated_by = ?, status = ? where id = ?", - updatedBy, 0, rpIds.get(0)))); - log.info(String.format("updated (delete) %s", rpid)); - } - else if (rpIds.size() == 0) { - log.info(String.format("No rp found for %s", rpid)); - } - else { - throw new RelyingPartyException("more than one active metadata record found!! No update performed. "); - } - - - } - catch (Exception e) { - log.info("remove metadata trouble: " + e.getMessage()); - } - } - @Override - public boolean isEditable() { - return editable; - } - - @Override - public void cleanup() { - - } - - public void setGroupId(String groupId) { this.groupId = groupId; } - public void setId(String id) { this.id = id; } - public void setEditable(boolean editable) { this.editable = editable; } - //we don't use uuidmanager here because this class only handles UW metadata - private UUID genUUID() { return UUID.randomUUID(); } - - - private class RelyingPartyMapper implements RowMapper { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - - @Override - public RelyingParty mapRow(ResultSet resultSet, int i) throws SQLException { - - Document document; - RelyingParty relyingParty; - String groupId = resultSet.getString("group_id"); - String entityId = resultSet.getString("entity_id"); - String startTime = resultSet.getString("start_time"); - String endTime = resultSet.getString("end_time"); - String updatedBy = resultSet.getString("updated_by"); - UUID uuid = (UUID) resultSet.getObject("uuid"); - - try { - DocumentBuilder builder = dbf.newDocumentBuilder(); - document = builder.parse(resultSet.getAsciiStream("xml")); - - } catch (Exception e) { - return null; - } - - try { - relyingParty = new RelyingParty(document.getDocumentElement(), id, true, updatedBy, startTime, endTime, uuid); - } catch (RelyingPartyException ex) { - log.debug(String.format("exception for new Relying Party group_id: %s entity_id: %s message: %s", - groupId, entityId, ex.getMessage())); - relyingParty = null; - } - - if (relyingParty == null) { - log.info(String.format("unparseable attribute filter for entity: %s in group: %s", - entityId, groupId)); - } - - return relyingParty; - } - } - - -} +package edu.washington.iam.registry.rp; + +import edu.washington.iam.registry.exception.RelyingPartyException; +import edu.washington.iam.tools.IdpHelper; +import edu.washington.iam.tools.XMLHelper; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.w3c.dom.Document; + +public class DBMetadata implements MetadataDAO { + private final Logger log = LoggerFactory.getLogger(getClass()); + + private String id; + private String groupId; + private boolean editable; + private IdpHelper idpHelper = null; + + public void setIdpHelper(IdpHelper v) { + idpHelper = v; + } + + @Autowired private JdbcTemplate template; + + @Override + public List getRelyingParties() { + List rps = + template.query( + "select * from metadata where end_time is null and group_id = ?", + new Object[] {groupId}, + new RelyingPartyMapper()); + return rps; + } + + @Override + public List getRelyingPartyHistoryById(String id) throws RelyingPartyException { + // get metadata + List rps = null; + try { + rps = + template.query( + "select * from metadata where group_id = ? and entity_id = ?" + + " order by start_time ASC", + new Object[] {groupId, id}, + new RelyingPartyMapper()); + log.info("Got a response in getRelyingPartyHistoryById"); + return rps; + } catch (Exception e) { + String errorMsg = + String.format("error getting rp: %s, rps size = %s", id, (rps == null) ? 0 : rps.size()); + log.error(errorMsg, e); + throw new RelyingPartyException(errorMsg); + } + } + + @Override + public RelyingParty getRelyingPartyById(String id) throws RelyingPartyException { + List rps = + template.query( + "select * from metadata where end_time is null and group_id = ? and entity_id = ?", + new Object[] {groupId, id}, + new RelyingPartyMapper()); + if (rps.size() == 1 && rps.get(0) != null) { + return rps.get(0); + } else { + String errorMsg = + String.format("error getting rp: %s, rps size = %s", id, (rps == null) ? 0 : rps.size()); + log.error(errorMsg); + throw new RelyingPartyException(errorMsg); + } + } + + @Override + public List searchRelyingPartyIds(String searchStr) { + String sql; + List results; + if (searchStr != null) { + results = + template.queryForList( + "select entity_id from metadata where end_time is null and group_id = ? and entity_id like ?", + new Object[] {groupId, '%' + searchStr + '%'}, + String.class); + } else { + results = + template.queryForList( + "select entity_id from metadata where end_time is null and group_id = ?", + new Object[] {groupId}, + String.class); + } + return results; + } + + @Override + public List getRelyingPartiesById(String search) { + String sql; + log.debug("DB search for id like " + search); + List rps = + template.query( + "select * from metadata where end_time is null and group_id = ? and entity_id like ?", + new Object[] {groupId, '%' + search + '%'}, + new RelyingPartyMapper()); + return rps; + } + + @Override + public List getRelyingPartiesByAdmin(String admin) { + String sql; + log.debug("DB search for admin " + admin); + List rps = null; + if (admin.indexOf("@") > 0) { + rps = + template.query( + "select * from metadata where end_time is null and group_id = ? and (xml like ? or xml like ?)", + new Object[] { + groupId, + "%" + admin + "%", + "%mailto:" + admin + "%" + }, + new RelyingPartyMapper()); + } else { + rps = + template.query( + "select * from metadata where end_time is null and group_id = ? and (xml like ? or xml like ? or xml like ? or xml like ?)", + new Object[] { + groupId, + "%" + admin + "@uw.edu%", + "%" + admin + "@washington.edu%", + "%mailto:" + admin + "@uw.edu%", + "%mailto:" + admin + "@washington.edu%" + }, + new RelyingPartyMapper()); + } + return rps; + } + + @Override + public void updateRelyingParty(RelyingParty relyingParty, String updatedBy) { + log.info( + String.format("updating metadata for rp %s in %s", relyingParty.getEntityId(), groupId)); + try { + String xml = XMLHelper.serializeXmlToString(relyingParty); + List existingIds = + template.queryForList( + "select id from metadata where group_id = ? and entity_id = ? and end_time is null", + Integer.class, + groupId, + relyingParty.getEntityId()); + if (existingIds.size() == 0) { + // no active records so we add an active record + + template.update( + "insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time, updated_by, status) values " + + "(? ,?, ?, ?, ?, now(), ?, 1)", + genUUID(), + groupId, + relyingParty.getEntityId(), + xml, + null, + updatedBy); + log.debug("added new rp " + relyingParty.getEntityId()); + } else if (existingIds.size() == 1) { + // we need to get the uuid + List uuid = + template.queryForList( + "select uuid from metadata where entity_id = ? and end_time is null", + UUID.class, + relyingParty.getEntityId()); + relyingParty.setUuid(uuid.get(0)); + // active record exists so mark last one inactive + template.update( + "update metadata set end_time = now(), status = ? where id = ?", 0, existingIds.get(0)); + // add new active record + log.info( + Integer.toString( + template.update( + "insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time, updated_by, status) values " + + "(?, ?, ?, ?, ?, now(), ?, 1)", + relyingParty.getUuid(), + groupId, + relyingParty.getEntityId(), + xml, + null, + updatedBy))); + log.debug("updated existing rp " + relyingParty.getEntityId()); + } else { + throw new RelyingPartyException( + "more than one active metadata record found!! No update performed. "); + } + if (idpHelper != null) idpHelper.notifyIdps("metadata"); + } catch (Exception e) { + log.info("update metadata trouble: " + e.getMessage()); + // just eat it - don't know the repercussions + } + } + + @Override + public void removeRelyingParty(String rpid, String updatedBy) { + try { + log.info(String.format("looking to remove metadata for rp %s in %s", rpid, groupId)); + /* small bit of errata: when removing an RP we rewrite the updatedBy field of the last record to the netid + of the person who deleted it. In this sense we lose the data of whoever made the last update, + but I think it's more important to know who deleted it over who made the last update + before it was deleted. Contrast with an update (above) where we mark the old record + inactive but don't change who updated it. We don't display deletes to users, so this mostly + matters in an audit situation. + I supposed a smarter implementation could put an end_date on the last update record and just add a new one + with end_date already set. */ + List rpIds = + template.queryForList( + "select id from metadata where group_id = ? and entity_id = ? and end_time is null", + Integer.class, + groupId, + rpid); + if (rpIds.size() == 1 && rpIds.get(0) != null) { + log.info( + Integer.toString( + template.update( + "update metadata set end_time = now(), updated_by = ?, status = ? where id = ?", + updatedBy, + 0, + rpIds.get(0)))); + log.info(String.format("updated (delete) %s", rpid)); + } else if (rpIds.size() == 0) { + log.info(String.format("No rp found for %s", rpid)); + } else { + throw new RelyingPartyException( + "more than one active metadata record found!! No update performed. "); + } + + } catch (Exception e) { + log.info("remove metadata trouble: " + e.getMessage()); + } + } + + @Override + public boolean isEditable() { + return editable; + } + + @Override + public void cleanup() {} + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public void setId(String id) { + this.id = id; + } + + public void setEditable(boolean editable) { + this.editable = editable; + } + + // we don't use uuidmanager here because this class only handles UW metadata + private UUID genUUID() { + return UUID.randomUUID(); + } + + private class RelyingPartyMapper implements RowMapper { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + @Override + public RelyingParty mapRow(ResultSet resultSet, int i) throws SQLException { + + Document document; + RelyingParty relyingParty; + String groupId = resultSet.getString("group_id"); + String entityId = resultSet.getString("entity_id"); + String startTime = resultSet.getString("start_time"); + String endTime = resultSet.getString("end_time"); + String updatedBy = resultSet.getString("updated_by"); + UUID uuid = (UUID) resultSet.getObject("uuid"); + + try { + DocumentBuilder builder = dbf.newDocumentBuilder(); + document = builder.parse(resultSet.getAsciiStream("xml")); + + } catch (Exception e) { + return null; + } + + try { + relyingParty = + new RelyingParty( + document.getDocumentElement(), id, true, updatedBy, startTime, endTime, uuid); + } catch (RelyingPartyException ex) { + log.debug( + String.format( + "exception for new Relying Party group_id: %s entity_id: %s message: %s", + groupId, entityId, ex.getMessage())); + relyingParty = null; + } + + if (relyingParty == null) { + log.info( + String.format( + "unparseable attribute filter for entity: %s in group: %s", entityId, groupId)); + } + + return relyingParty; + } + } +} diff --git a/src/main/java/edu/washington/iam/registry/rp/HistoryItem.java b/src/main/java/edu/washington/iam/registry/rp/HistoryItem.java index 1dd5f82..987db7d 100644 --- a/src/main/java/edu/washington/iam/registry/rp/HistoryItem.java +++ b/src/main/java/edu/washington/iam/registry/rp/HistoryItem.java @@ -4,116 +4,103 @@ public class HistoryItem { + private String effectiveDate; + private List changes; + private String updatedBy; - private String effectiveDate; - private List changes; - private String updatedBy; + public class ChangeItem { - public class ChangeItem - { + private String objectName; + private Object oldValue; + private Object newValue; + private int changeType; + private void LocalInit() { - private String objectName; - private Object oldValue; - private Object newValue; - private int changeType; - - private void LocalInit(){ - - objectName = null; - oldValue = null; - newValue = null; - changeType = 0; - } - - private ChangeItem(String objectName, Object oldValue, Object newValue, int changeType) { - - LocalInit(); - - this.objectName = objectName; - this.oldValue = oldValue; - this.newValue = newValue; - this.changeType = changeType; - - - } - - public String getObjectName() { - return this.objectName; - } - - public Object getOldValue() { - return this.oldValue; - } - - public Object getNewValue() { - return this.newValue; - } + objectName = null; + oldValue = null; + newValue = null; + changeType = 0; + } - public int getChangeType() { - return this.changeType; - } + private ChangeItem(String objectName, Object oldValue, Object newValue, int changeType) { + LocalInit(); + this.objectName = objectName; + this.oldValue = oldValue; + this.newValue = newValue; + this.changeType = changeType; } - private void localInit () { - effectiveDate = null; - changes = new Vector(); - updatedBy = ""; - + public String getObjectName() { + return this.objectName; } + public Object getOldValue() { + return this.oldValue; + } + public Object getNewValue() { + return this.newValue; + } - public HistoryItem (String effectiveDate, String updatedBy) { - - localInit(); - - this.effectiveDate = effectiveDate; - this.updatedBy = updatedBy; - + public int getChangeType() { + return this.changeType; } + } - //1 = object changed - //add a new instance of something that changed - public void AddChangeItem(String objectName, Object oldValue, Object newValue){ + private void localInit() { + effectiveDate = null; + changes = new Vector(); + updatedBy = ""; + } - ChangeItem myItem = new ChangeItem(objectName, oldValue, newValue, 1); - changes.add(myItem); + public HistoryItem(String effectiveDate, String updatedBy) { - } - //2 = object added (only new is populated) - // something added that wasn't there before - public void AddNewItem(String objectName, Object newValue){ + localInit(); - ChangeItem myItem = new ChangeItem(objectName, null, newValue, 2); - changes.add(myItem); + this.effectiveDate = effectiveDate; + this.updatedBy = updatedBy; + } - } - //3 = object removed (only old is populated) - //something completely removed - public void AddDeleteItem(String objectName, Object oldValue){ + // 1 = object changed + // add a new instance of something that changed + public void AddChangeItem(String objectName, Object oldValue, Object newValue) { - ChangeItem myItem = new ChangeItem(objectName, oldValue, null, 3); - changes.add(myItem); + ChangeItem myItem = new ChangeItem(objectName, oldValue, newValue, 1); + changes.add(myItem); + } - } + // 2 = object added (only new is populated) + // something added that wasn't there before + public void AddNewItem(String objectName, Object newValue) { - public String getEffectiveDate() { - return effectiveDate; - } + ChangeItem myItem = new ChangeItem(objectName, null, newValue, 2); + changes.add(myItem); + } - public List getChanges() { - return changes; - } + // 3 = object removed (only old is populated) + // something completely removed + public void AddDeleteItem(String objectName, Object oldValue) { - public String getUpdatedBy() { - return updatedBy; - } + ChangeItem myItem = new ChangeItem(objectName, oldValue, null, 3); + changes.add(myItem); + } - public int getNumberOfChanges() { return changes.size(); } -} + public String getEffectiveDate() { + return effectiveDate; + } + public List getChanges() { + return changes; + } + public String getUpdatedBy() { + return updatedBy; + } + public int getNumberOfChanges() { + return changes.size(); + } +} diff --git a/src/main/java/edu/washington/iam/registry/rp/KeyDescriptor.java b/src/main/java/edu/washington/iam/registry/rp/KeyDescriptor.java index edfb6fa..7485baa 100644 --- a/src/main/java/edu/washington/iam/registry/rp/KeyDescriptor.java +++ b/src/main/java/edu/washington/iam/registry/rp/KeyDescriptor.java @@ -15,127 +15,122 @@ * ======================================================================== */ - package edu.washington.iam.registry.rp; -import java.io.Serializable; +import edu.washington.iam.registry.exception.RelyingPartyException; +import edu.washington.iam.tools.IamCertificate; +import edu.washington.iam.tools.IamCertificateException; +import edu.washington.iam.tools.XMLHelper; import java.io.BufferedWriter; import java.io.IOException; - -import java.util.List; -import java.util.Vector; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -import org.w3c.dom.Document; +import java.io.Serializable; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; -import edu.washington.iam.tools.XMLHelper; -import edu.washington.iam.tools.IamCertificate; -import edu.washington.iam.tools.IamCertificateHelper; -import edu.washington.iam.tools.IamCertificateException; +// small subset of all possible keydescriptors +public class KeyDescriptor implements Serializable { -import edu.washington.iam.registry.exception.RelyingPartyException; + // private final Logger log = LoggerFactory.getLogger(getClass()); -// small subset of all possible keydescriptors -public class KeyDescriptor implements Serializable { - - //private final Logger log = LoggerFactory.getLogger(getClass()); - - - private String use; - private String keyName; - private String certificate; - - // expanded cert (not written to the xml files) - private IamCertificate cert; - - // create from document element (KeyDescriptor) - public KeyDescriptor (Element ele) throws RelyingPartyException { - - use = ele.getAttribute("use"); - if (use==null) use = ""; - - Element ki = XMLHelper.getElementByName(ele, "KeyInfo"); - keyName = null; - certificate = null; - if (ki==null) throw new RelyingPartyException("missing keyinfo"); - - Element kn = XMLHelper.getElementByName(ki, "KeyName"); - Element x5 = XMLHelper.getElementByName(ki, "X509Data"); - - if (kn==null && x5==null) throw new RelyingPartyException("invlaid keyinfo"); - - if (kn!=null) keyName = kn.getTextContent(); - if (x5!=null) { - Element crt = XMLHelper.getElementByName(x5, "X509Certificate"); - if (crt!=null) { - try { - String pem = crt.getTextContent(); - cert = new IamCertificate(pem); - setCertificate(pem); - } catch (IamCertificateException e) { - throw new RelyingPartyException("The certificate PEM text is not valid."); - } - } - } - } + private String use; + private String keyName; + private String certificate; - // create from dns default - public KeyDescriptor (String dns) { - keyName = dns; - certificate = null; - } + // expanded cert (not written to the xml files) + private IamCertificate cert; + // create from document element (KeyDescriptor) + public KeyDescriptor(Element ele) throws RelyingPartyException { - public void writeXml(BufferedWriter xout) throws IOException { - if (use.length()>0) xout.write(" \n"); - else xout.write(" \n"); - xout.write(" \n"); - if (keyName!=null) xout.write(" " + XMLHelper.safeXml(keyName) + "\n"); - if (certificate!=null) xout.write(" " + XMLHelper.safeXml(certificate) + "\n"); - xout.write(" \n"); - xout.write(" \n"); - } + use = ele.getAttribute("use"); + if (use == null) use = ""; - // check for duplicate descriptor (ignore 'use') - public boolean isDuplicate(KeyDescriptor test) { - if (test.getUse()!=null && !use.equals(test.getUse())) return false; - if (keyName!=null && (test.getKeyName()==null || !test.getKeyName().equals(keyName))) return false; - if (keyName==null && test.getKeyName()!=null) return false; - if (certificate!=null && (test.getCertificate()==null || !test.getCertificate().equals(certificate))) return false; - if (certificate==null && test.getCertificate()!=null) return false; - return true; - } + Element ki = XMLHelper.getElementByName(ele, "KeyInfo"); + keyName = null; + certificate = null; + if (ki == null) throw new RelyingPartyException("missing keyinfo"); - public void setUse(String v) { - use = v; - if (use==null) use = ""; - } - public String getUse() { - return (use); - } + Element kn = XMLHelper.getElementByName(ki, "KeyName"); + Element x5 = XMLHelper.getElementByName(ki, "X509Data"); - public void setKeyName(String v) { - keyName = v; - } - public String getKeyName() { - return (keyName); - } + if (kn == null && x5 == null) throw new RelyingPartyException("invlaid keyinfo"); - public void setCertificate(String v) { - certificate = v.replaceAll("\\s*-----BEGIN CERTIFICATE-----\\s*","").replaceAll("\\s*-----END CERTIFICATE-----\\s*",""); - } - public String getCertificate() { - return (certificate); - } - public IamCertificate getCert() { - return (cert); + if (kn != null) keyName = kn.getTextContent(); + if (x5 != null) { + Element crt = XMLHelper.getElementByName(x5, "X509Certificate"); + if (crt != null) { + try { + String pem = crt.getTextContent(); + cert = new IamCertificate(pem); + setCertificate(pem); + } catch (IamCertificateException e) { + throw new RelyingPartyException("The certificate PEM text is not valid."); + } + } } - + } + + // create from dns default + public KeyDescriptor(String dns) { + keyName = dns; + certificate = null; + } + + public void writeXml(BufferedWriter xout) throws IOException { + if (use.length() > 0) xout.write(" \n"); + else xout.write(" \n"); + xout.write(" \n"); + if (keyName != null) + xout.write(" " + XMLHelper.safeXml(keyName) + "\n"); + if (certificate != null) + xout.write( + " " + + XMLHelper.safeXml(certificate) + + "\n"); + xout.write(" \n"); + xout.write(" \n"); + } + + // check for duplicate descriptor (ignore 'use') + public boolean isDuplicate(KeyDescriptor test) { + if (test.getUse() != null && !use.equals(test.getUse())) return false; + if (keyName != null && (test.getKeyName() == null || !test.getKeyName().equals(keyName))) + return false; + if (keyName == null && test.getKeyName() != null) return false; + if (certificate != null + && (test.getCertificate() == null || !test.getCertificate().equals(certificate))) + return false; + if (certificate == null && test.getCertificate() != null) return false; + return true; + } + + public void setUse(String v) { + use = v; + if (use == null) use = ""; + } + + public String getUse() { + return (use); + } + + public void setKeyName(String v) { + keyName = v; + } + + public String getKeyName() { + return (keyName); + } + + public void setCertificate(String v) { + certificate = + v.replaceAll("\\s*-----BEGIN CERTIFICATE-----\\s*", "") + .replaceAll("\\s*-----END CERTIFICATE-----\\s*", ""); + } + + public String getCertificate() { + return (certificate); + } + + public IamCertificate getCert() { + return (cert); + } } - diff --git a/src/main/java/edu/washington/iam/registry/rp/ManageNameIDService.java b/src/main/java/edu/washington/iam/registry/rp/ManageNameIDService.java index 8f4c615..5e666dd 100644 --- a/src/main/java/edu/washington/iam/registry/rp/ManageNameIDService.java +++ b/src/main/java/edu/washington/iam/registry/rp/ManageNameIDService.java @@ -15,66 +15,57 @@ * ======================================================================== */ - package edu.washington.iam.registry.rp; -import java.io.Serializable; +import edu.washington.iam.registry.exception.RelyingPartyException; import java.io.BufferedWriter; import java.io.IOException; - -import java.lang.NumberFormatException; -import java.util.List; -import java.util.Vector; - +import java.io.Serializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import edu.washington.iam.registry.exception.RelyingPartyException; - -public class ManageNameIDService implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private String binding; - private String location; - private String index; - - // create from document element - public ManageNameIDService (Element ele) throws RelyingPartyException { - binding = ele.getAttribute("Binding"); - location = ele.getAttribute("Location"); - if (binding==null || location==null) throw new RelyingPartyException("missing NIM attributes"); - if (!binding.startsWith("urn:")) throw new RelyingPartyException("invalid NIM binding"); - if (!location.startsWith("http")) throw new RelyingPartyException("invalid NIM location"); - } - - public ManageNameIDService (String b, String l) { - binding = b; - location = l; - } - - public void writeXml(BufferedWriter xout) throws IOException { - xout.write(" \n"); - } - - public void setBinding(String v) { - binding = v; - } - public String getBinding() { - return (binding); - } - - public void setLocation(String v) { - location = v; - } - public String getLocation() { - return (location); - } +public class ManageNameIDService implements Serializable { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private String binding; + private String location; + private String index; + + // create from document element + public ManageNameIDService(Element ele) throws RelyingPartyException { + binding = ele.getAttribute("Binding"); + location = ele.getAttribute("Location"); + if (binding == null || location == null) + throw new RelyingPartyException("missing NIM attributes"); + if (!binding.startsWith("urn:")) throw new RelyingPartyException("invalid NIM binding"); + if (!location.startsWith("http")) throw new RelyingPartyException("invalid NIM location"); + } + + public ManageNameIDService(String b, String l) { + binding = b; + location = l; + } + + public void writeXml(BufferedWriter xout) throws IOException { + xout.write( + " \n"); + } + + public void setBinding(String v) { + binding = v; + } + + public String getBinding() { + return (binding); + } + + public void setLocation(String v) { + location = v; + } + + public String getLocation() { + return (location); + } } - diff --git a/src/main/java/edu/washington/iam/registry/rp/MetadataDAO.java b/src/main/java/edu/washington/iam/registry/rp/MetadataDAO.java index 23416f4..45d1564 100644 --- a/src/main/java/edu/washington/iam/registry/rp/MetadataDAO.java +++ b/src/main/java/edu/washington/iam/registry/rp/MetadataDAO.java @@ -1,18 +1,26 @@ -package edu.washington.iam.registry.rp; - -import edu.washington.iam.registry.exception.RelyingPartyException; - -import java.util.List; - -public interface MetadataDAO { - public List getRelyingParties(); - public List getRelyingPartyHistoryById(String id) throws RelyingPartyException; - public RelyingParty getRelyingPartyById(String id) throws RelyingPartyException; - public List searchRelyingPartyIds(String searchStr); - public List getRelyingPartiesById(String searchStr); - public List getRelyingPartiesByAdmin(String admin); - public void updateRelyingParty(RelyingParty rp, String updatedBy); - public void removeRelyingParty(String rpid, String updatedBy); - public boolean isEditable(); - public void cleanup(); -} +package edu.washington.iam.registry.rp; + +import edu.washington.iam.registry.exception.RelyingPartyException; +import java.util.List; + +public interface MetadataDAO { + public List getRelyingParties(); + + public List getRelyingPartyHistoryById(String id) throws RelyingPartyException; + + public RelyingParty getRelyingPartyById(String id) throws RelyingPartyException; + + public List searchRelyingPartyIds(String searchStr); + + public List getRelyingPartiesById(String searchStr); + + public List getRelyingPartiesByAdmin(String admin); + + public void updateRelyingParty(RelyingParty rp, String updatedBy); + + public void removeRelyingParty(String rpid, String updatedBy); + + public boolean isEditable(); + + public void cleanup(); +} diff --git a/src/main/java/edu/washington/iam/registry/rp/Organization.java b/src/main/java/edu/washington/iam/registry/rp/Organization.java index f2560ec..90ceecc 100644 --- a/src/main/java/edu/washington/iam/registry/rp/Organization.java +++ b/src/main/java/edu/washington/iam/registry/rp/Organization.java @@ -15,92 +15,92 @@ * ======================================================================== */ - package edu.washington.iam.registry.rp; -import java.io.Serializable; +import edu.washington.iam.registry.exception.RelyingPartyException; +import edu.washington.iam.tools.XMLHelper; import java.io.BufferedWriter; import java.io.IOException; - -import java.util.List; -import java.util.Vector; - +import java.io.Serializable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; -import edu.washington.iam.tools.XMLHelper; -import edu.washington.iam.registry.exception.RelyingPartyException; - - -public class Organization implements Serializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private String name; - private String displayName; - private String url; - - // create from document element - public Organization (Element ele) throws RelyingPartyException { - name = null; - displayName = null; - url = null; - NodeList chl = ele.getChildNodes(); - for (int i=0; i\n"); - if (name!=null) xout.write(" " + XMLHelper.safeXml(name) + "\n"); - if (displayName!=null) xout.write(" " + XMLHelper.safeXml(displayName) + "\n"); - if (url!=null) xout.write(" " + XMLHelper.safeXml(url) + "\n"); - xout.write(" \n"); - } - - - public void setName(String v) { - name = v; - } - public String getName() { - return (name); - } - - public void setDisplayName(String v) { - displayName = v; - } - public String getDisplayName() { - return (displayName); - } - - public void setUrl(String v) { - url = v; - } - public String getUrl() { - return (url); +public class Organization implements Serializable { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private String name; + private String displayName; + private String url; + + // create from document element + public Organization(Element ele) throws RelyingPartyException { + name = null; + displayName = null; + url = null; + NodeList chl = ele.getChildNodes(); + for (int i = 0; i < chl.getLength(); i++) { + if (chl.item(i).getNodeType() != Node.ELEMENT_NODE) continue; + Element ch = (Element) chl.item(i); + String nn = ch.getNodeName(); + if (XMLHelper.matches(nn, "OrganizationName")) name = ch.getTextContent(); + if (XMLHelper.matches(nn, "OrganizationDisplayName")) displayName = ch.getTextContent(); + if (XMLHelper.matches(nn, "OrganizationURL")) url = ch.getTextContent(); } + // if (name==null) throw new RelyingPartyException("missing org name"); + // if (displayName==null) throw new RelyingPartyException("missing org displayName"); + // if (url==null) throw new RelyingPartyException("missing org url"); + } + + // create from strings + public Organization(String n, String d, String u) { + name = n; + displayName = d; + url = u; + } + + public void writeXml(BufferedWriter xout) throws IOException { + xout.write(" \n"); + if (name != null) + xout.write( + " " + + XMLHelper.safeXml(name) + + "\n"); + if (displayName != null) + xout.write( + " " + + XMLHelper.safeXml(displayName) + + "\n"); + if (url != null) + xout.write( + " " + XMLHelper.safeXml(url) + "\n"); + xout.write(" \n"); + } + + public void setName(String v) { + name = v; + } + + public String getName() { + return (name); + } + + public void setDisplayName(String v) { + displayName = v; + } + + public String getDisplayName() { + return (displayName); + } + + public void setUrl(String v) { + url = v; + } + + public String getUrl() { + return (url); + } } - diff --git a/src/main/java/edu/washington/iam/registry/rp/RelyingParty.java b/src/main/java/edu/washington/iam/registry/rp/RelyingParty.java index 52ea396..fd219ad 100644 --- a/src/main/java/edu/washington/iam/registry/rp/RelyingParty.java +++ b/src/main/java/edu/washington/iam/registry/rp/RelyingParty.java @@ -1,523 +1,534 @@ -/* ======================================================================== - * Copyright (c) 2009 The University of Washington - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== - */ - - -package edu.washington.iam.registry.rp; - -import java.io.BufferedWriter; -import java.io.IOException; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.*; - -import edu.washington.iam.tools.XMLSerializable; - -import org.javers.core.diff.Change; -import org.javers.core.diff.changetype.NewObject; -import org.javers.core.diff.changetype.ObjectRemoved; -import org.javers.core.diff.changetype.ValueChange; -import org.javers.core.metamodel.annotation.Id; -import org.javers.core.metamodel.annotation.TypeName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; - -import edu.washington.iam.tools.XMLHelper; - -import edu.washington.iam.registry.exception.RelyingPartyException; - -import org.javers.core.*; -import org.javers.core.diff.Diff; -import org.javers.core.metamodel.object.*; - -import edu.washington.iam.registry.rp.HistoryItem; -import edu.washington.iam.registry.rp.HistoryItem.*; - -import javax.xml.bind.ValidationEvent; - -import static org.javers.core.diff.ListCompareAlgorithm.LEVENSHTEIN_DISTANCE; - -//decorator for javers compare functions -@TypeName("RelyingParty") -public class RelyingParty implements XMLSerializable { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - private UUID uuid; - @Id //decorator for javers - private String entityId; - private String startTime; - private String endTime; - private String updatedBy; - private String metadataId; - private boolean editable; - private String protocolSupportEnumerationsUnsplit; - private List protocolSupportEnumerations; - // List extensions; - private List keyDescriptors; - private List nameIDFormats; - private List assertionConsumerServices; - private Organization organization; - private List contactPersons; - - private String authnRequestsSigned; - private List manageNameIDServices; - - private String entityCategory; - - // initialize - private void localInit () { - metadataId = ""; - - updatedBy = ""; - startTime = ""; - endTime = ""; - uuid = null; - editable = false; - // extensions = new Vector(); - keyDescriptors = new Vector(); - nameIDFormats = new Vector(); - assertionConsumerServices = new Vector(); - organization = null; - contactPersons = new Vector(); - manageNameIDServices = new Vector(); - } - - // create from document element -// public RelyingParty (Element ele, Metadata md) throws RelyingPartyException { -// this(ele, md.getId(), md.isEditable()); -// } - - public RelyingParty (Element ele, String mdid, boolean edit) throws RelyingPartyException { - - this(ele, mdid, edit, "", "", "", null); - - } - - // create from document element - - public RelyingParty (Element ele, String mdid, boolean edit, String updatedBy, String startTime, String endTime, - UUID uuid) - throws RelyingPartyException { - - localInit(); - this.entityId = ele.getAttribute("entityID"); - if (entityId==null) throw new RelyingPartyException("No entity id attribute"); - // log.debug("create from doc: " + entityId); - - this.metadataId = mdid; - this.editable = edit; - this.updatedBy = updatedBy; - this.startTime = startTime; - this.endTime = endTime; - this.uuid = uuid; - - NodeList nl1 = ele.getChildNodes(); - for (int i=0; i\n"); - String ars = ""; - if (authnRequestsSigned.length()>0) ars = " AuthnRequestsSigned=\"" + XMLHelper.safeXml(authnRequestsSigned) + "\""; - xout.write(" \n"); - - for (int i=0; i" + XMLHelper.safeXml(nameIDFormats.get(i)) + "\n"); - } - -/*** don't know if this goes before or after the nameidformats - for (int i=0; i\n"); - - if (organization!=null) organization.writeXml(xout); - else log.info("no org for " + entityId); - for (int i=0; i\n"); - } - - public HistoryItem RpCompare(RelyingParty obj){ - - HistoryItem historyItems; - - Javers javers = JaversBuilder.javers() - .withListCompareAlgorithm(LEVENSHTEIN_DISTANCE) - .build(); - - //take a diff - Diff diff = javers.compare(this, obj); - String foo = javers.getJsonConverter().toJson(diff).toString(); - //get the date - ValueChange effectiveDate = (ValueChange)diff.getPropertyChanges("startTime").get(0); - //create new history item using date - historyItems = new HistoryItem(effectiveDate.getRight().toString(), obj.getUpdatedBy()); - //now iterate over all changes and put into history item (ignore start and end times now) - try { - //select out ValueChange objects only - int objDupIndex = -1; //prevent duplicates - Object objDupType = null; //prevent duplicates - List myValueChanges = diff.getChangesByType(ValueChange.class); - for (ValueChange change : myValueChanges) { - //changed value - Object obj1 = change.getAffectedObject(); //returns changed object - //we don't care about these fields - if (change.getPropertyName().equalsIgnoreCase("startTime") || - change.getPropertyName().equalsIgnoreCase("endTime") || - change.getPropertyName().equalsIgnoreCase("uuid") || - change.getPropertyName().equalsIgnoreCase("updatedBy")) continue; - //if object type is RelyingParty then this change is a single valued field, not a list of fields of a different object type (e.g. contactPersons). - if (obj1 instanceof RelyingParty) { - String propertyName = change.getPropertyName().toString(); - String left = change.getLeft().toString(); - String right = change.getRight().toString(); - historyItems.AddChangeItem(propertyName, left, right); - - } else { //else should catch any "object" type fields of RelyingParty - String propertyName = change.getPropertyName().toString(); - //string containing index of affected object - GlobalId globalId = change.getAffectedGlobalId(); - ValueObjectId valueId = (ValueObjectId) globalId; - String[] idList = valueId.getFragment().split("/"); - int objIndex = Integer.parseInt(idList[1]); - //since we grab the entire object when we detect one change, - //don't bother tracking additional changes - if (objIndex == objDupIndex && obj1.equals(objDupType)) { - continue; - } - objDupIndex = objIndex; //keep track of this instance index - objDupType = obj1; //keep track of this object so we don't duplicate it - //easy to get the change TO value from the change object - Object right = change.getAffectedObject().get(); - //some nutty reflection to get the original value - Class leftCls = this.getClass(); - Field leftField = leftCls.getDeclaredField(idList[0]); - Object left = ((Vector) leftField.get(this)).get(objIndex); - - //idList[0] is the name of the property in RelyingParty Object - //note the object type name from left and right are different from idlist[0]. The latter is the name of - //the list of the former objects in RelyingParty Object. - historyItems.AddChangeItem(idList[0], left, right); - - - } - } - List myNewObjects = diff.getChangesByType(NewObject.class); - for (Change change : myNewObjects) { - Object obj2 = change.getAffectedObject().get(); - String[] classNameSplit = obj2.getClass().toString().split("\\."); - String className = classNameSplit[classNameSplit.length - 1]; - if (className.equalsIgnoreCase("startTime") || - className.equalsIgnoreCase("endTime") || - className.equalsIgnoreCase("uuid") || - className.equalsIgnoreCase("loggerRemoteView") || - className.equalsIgnoreCase("logger") || - className.equalsIgnoreCase("updatedBy")) continue; - //if object type is RelyingParty then this change is a single valued field, not a list of fields of a different object type (e.g. contactPersons). - if (obj2 instanceof RelyingParty) { - historyItems.AddNewItem(className, obj2); - } else { //else should catch any "object" type fields of RelyingParty - String propertyName = className; - //string containing index of affected object - GlobalId globalId = change.getAffectedGlobalId(); - ValueObjectId valueId = (ValueObjectId) globalId; - String[] idList = valueId.getFragment().split("/"); - int objIndex = Integer.parseInt(idList[1]); - //since we grab the entire object when we detect one change, - //don't bother tracking additional changes - if (objIndex == objDupIndex && obj2.equals(objDupType)) { - continue; - } - objDupIndex = objIndex; //keep track of this instance index - objDupType = obj2; //keep track of this object so we don't duplicate it - //idList[0] is the name of the property in RelyingParty Object - //note the object type (classname above) is different from idlist[0]. The latter is the name of - //the list of the former objects in RelyingParty Object. - historyItems.AddNewItem(idList[0], obj2); - - - } - - } - List myRemovedObjects = diff.getChangesByType(ObjectRemoved.class); - for (Change change : myRemovedObjects) { - Object obj3 = change.getAffectedObject().get(); - String[] classNameSplit = obj3.getClass().toString().split("\\."); - String className = classNameSplit[classNameSplit.length - 1]; - if (className.equalsIgnoreCase("startTime") || - className.equalsIgnoreCase("endTime") || - className.equalsIgnoreCase("uuid") || - className.equalsIgnoreCase("loggerRemoteView") || - className.equalsIgnoreCase("logger") || - className.equalsIgnoreCase("updatedBy")) continue; - //if object type is RelyingParty then this change is a single valued field, not a list of fields of a different object type (e.g. contactPersons). - if (obj3 instanceof RelyingParty) { - historyItems.AddDeleteItem(className, change.toString()); //will that work? - } else { //else should catch any "object" type fields of RelyingParty - String propertyName = className; - //string containing index of affected object - GlobalId globalId = change.getAffectedGlobalId(); - ValueObjectId valueId = (ValueObjectId) globalId; - String[] idList = valueId.getFragment().split("/"); - int objIndex = Integer.parseInt(idList[1]); - //since we grab the entire object when we detect one change, - //don't bother tracking additional changes - if (objIndex == objDupIndex && obj3.equals(objDupType)) { - continue; - } - objDupIndex = objIndex; //keep track of this instance index - objDupType = obj3; //keep track of this object so we don't duplicate it - //some nutty reflection to get the original value - Class leftCls = this.getClass(); - Field leftField = leftCls.getDeclaredField(idList[0]); - Object left = ((Vector) leftField.get(this)).get(objIndex); - //idList[0] is the name of the property in RelyingParty Object - //note the object type (classname above) is different from idlist[0]. The latter is the name of - //the list of the former objects in RelyingParty Object. - historyItems.AddDeleteItem(idList[0], left); - } - - } - } - catch (Exception e) { - Exception ee = e; - } - - return historyItems; - } - - public RelyingParty replicate(String dns) { - return null; - } - - public void setEntityId(String v) { - entityId = v; - } - public String getEntityId() { - return (entityId); - } - - public void setMetadataId(String v) { - metadataId = v; - } - public String getMetadataId() { - return (metadataId); - } - - public void setStartTime(String v) { - startTime = v; - } - public String getStartTime() { - return (startTime); - } - public void setEndTime(String v) { - endTime = v; - } - public String getEndTime() { - return (endTime); - } - public void setUuid(UUID v) { - uuid = v; - } - public UUID getUuid() { - return (uuid); - } - public void setUpdatedBy(String v) { - updatedBy = v; - } - public String getUpdatedBy() { - return (updatedBy); - } - - - public void setEditable(boolean v) { - editable = v; - } - public boolean getEditable() { - return (editable); - } - - public List getProtocolSupportEnumerations() { - return (protocolSupportEnumerations); - } - public void setKeyDescriptors(List v) { - keyDescriptors = v; - } - public List getKeyDescriptors() { - return (keyDescriptors); - } - - public void setNameIDFormats(List v) { - nameIDFormats = v; - } - public List getNameIDFormats() { - return (nameIDFormats); - } - - public void setAssertionConsumerServices(List v) { - assertionConsumerServices = v; - } - public List getAssertionConsumerServices() { - return (assertionConsumerServices); - } - public String getAuthnRequestsSigned(){ - return authnRequestsSigned; - } - public void setAuthnRequestsSigned(String v){ - authnRequestsSigned = v; - } - - public void setOrganization(Organization v) { - organization = v; - } - public Organization getOrganization() { - return organization; - } - - public void setContactPersons(List v) { - contactPersons = v; - } - public List getContactPersons() { - return (contactPersons); - } - - public String getEntityCategory() { - return (entityCategory); - } - -} - +/* ======================================================================== + * Copyright (c) 2009 The University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== + */ + +package edu.washington.iam.registry.rp; + +import static org.javers.core.diff.ListCompareAlgorithm.LEVENSHTEIN_DISTANCE; + +import edu.washington.iam.registry.exception.RelyingPartyException; +import edu.washington.iam.registry.rp.HistoryItem.*; +import edu.washington.iam.tools.XMLHelper; +import edu.washington.iam.tools.XMLSerializable; +import java.io.BufferedWriter; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.*; +import org.javers.core.*; +import org.javers.core.diff.Change; +import org.javers.core.diff.Diff; +import org.javers.core.diff.changetype.NewObject; +import org.javers.core.diff.changetype.ObjectRemoved; +import org.javers.core.diff.changetype.ValueChange; +import org.javers.core.metamodel.annotation.Id; +import org.javers.core.metamodel.annotation.TypeName; +import org.javers.core.metamodel.object.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +// decorator for javers compare functions +@TypeName("RelyingParty") +public class RelyingParty implements XMLSerializable { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private UUID uuid; + @Id // decorator for javers + private String entityId; + private String startTime; + private String endTime; + private String updatedBy; + private String metadataId; + private boolean editable; + private String protocolSupportEnumerationsUnsplit; + private List protocolSupportEnumerations; + // List extensions; + private List keyDescriptors; + private List nameIDFormats; + private List assertionConsumerServices; + private Organization organization; + private List contactPersons; + + private String authnRequestsSigned; + private List manageNameIDServices; + + private String entityCategory; + + // initialize + private void localInit() { + metadataId = ""; + + updatedBy = ""; + startTime = ""; + endTime = ""; + uuid = null; + editable = false; + // extensions = new Vector(); + keyDescriptors = new Vector(); + nameIDFormats = new Vector(); + assertionConsumerServices = new Vector(); + organization = null; + contactPersons = new Vector(); + manageNameIDServices = new Vector(); + } + + // create from document element + // public RelyingParty (Element ele, Metadata md) throws RelyingPartyException { + // this(ele, md.getId(), md.isEditable()); + // } + + public RelyingParty(Element ele, String mdid, boolean edit) throws RelyingPartyException { + + this(ele, mdid, edit, "", "", "", null); + } + + // create from document element + + public RelyingParty( + Element ele, + String mdid, + boolean edit, + String updatedBy, + String startTime, + String endTime, + UUID uuid) + throws RelyingPartyException { + + localInit(); + this.entityId = ele.getAttribute("entityID"); + if (entityId == null) throw new RelyingPartyException("No entity id attribute"); + // log.debug("create from doc: " + entityId); + + this.metadataId = mdid; + this.editable = edit; + this.updatedBy = updatedBy; + this.startTime = startTime; + this.endTime = endTime; + this.uuid = uuid; + + NodeList nl1 = ele.getChildNodes(); + for (int i = 0; i < nl1.getLength(); i++) { + if (nl1.item(i).getNodeType() != Node.ELEMENT_NODE) continue; + Element e1 = (Element) nl1.item(i); + String name = e1.getNodeName(); + // log.debug("rp ele: " + name); + + if (XMLHelper.matches(name, "SPSSODescriptor")) { + authnRequestsSigned = ele.getAttribute("AuthnRequestsSigned"); + protocolSupportEnumerationsUnsplit = e1.getAttribute("protocolSupportEnumeration"); + protocolSupportEnumerations = Arrays.asList(protocolSupportEnumerationsUnsplit.split(" ")); + /*** + * for (int j=0; j\n"); + String ars = ""; + if (authnRequestsSigned.length() > 0) + ars = " AuthnRequestsSigned=\"" + XMLHelper.safeXml(authnRequestsSigned) + "\""; + xout.write( + " \n"); + + for (int i = 0; i < keyDescriptors.size(); i++) { + keyDescriptors.get(i).writeXml(xout); + } + + for (int i = 0; i < nameIDFormats.size(); i++) { + xout.write( + " " + XMLHelper.safeXml(nameIDFormats.get(i)) + "\n"); + } + + /*** don't know if this goes before or after the nameidformats + * for (int i=0; i\n"); + + if (organization != null) organization.writeXml(xout); + else log.info("no org for " + entityId); + for (int i = 0; i < contactPersons.size(); i++) { + contactPersons.get(i).writeXml(xout); + } + xout.write(" \n"); + } + + public HistoryItem RpCompare(RelyingParty obj) { + + HistoryItem historyItems; + + Javers javers = JaversBuilder.javers().withListCompareAlgorithm(LEVENSHTEIN_DISTANCE).build(); + + // take a diff + Diff diff = javers.compare(this, obj); + String foo = javers.getJsonConverter().toJson(diff).toString(); + // get the date + ValueChange effectiveDate = (ValueChange) diff.getPropertyChanges("startTime").get(0); + // create new history item using date + historyItems = new HistoryItem(effectiveDate.getRight().toString(), obj.getUpdatedBy()); + // now iterate over all changes and put into history item (ignore start and end times now) + try { + // select out ValueChange objects only + int objDupIndex = -1; // prevent duplicates + Object objDupType = null; // prevent duplicates + List myValueChanges = diff.getChangesByType(ValueChange.class); + for (ValueChange change : myValueChanges) { + // changed value + Object obj1 = change.getAffectedObject(); // returns changed object + // we don't care about these fields + if (change.getPropertyName().equalsIgnoreCase("startTime") + || change.getPropertyName().equalsIgnoreCase("endTime") + || change.getPropertyName().equalsIgnoreCase("uuid") + || change.getPropertyName().equalsIgnoreCase("updatedBy")) continue; + // if object type is RelyingParty then this change is a single valued field, not a list of + // fields of a different object type (e.g. contactPersons). + if (obj1 instanceof RelyingParty) { + String propertyName = change.getPropertyName().toString(); + String left = change.getLeft().toString(); + String right = change.getRight().toString(); + historyItems.AddChangeItem(propertyName, left, right); + + } else { // else should catch any "object" type fields of RelyingParty + String propertyName = change.getPropertyName().toString(); + // string containing index of affected object + GlobalId globalId = change.getAffectedGlobalId(); + ValueObjectId valueId = (ValueObjectId) globalId; + String[] idList = valueId.getFragment().split("/"); + int objIndex = Integer.parseInt(idList[1]); + // since we grab the entire object when we detect one change, + // don't bother tracking additional changes + if (objIndex == objDupIndex && obj1.equals(objDupType)) { + continue; + } + objDupIndex = objIndex; // keep track of this instance index + objDupType = obj1; // keep track of this object so we don't duplicate it + // easy to get the change TO value from the change object + Object right = change.getAffectedObject().get(); + // some nutty reflection to get the original value + Class leftCls = this.getClass(); + Field leftField = leftCls.getDeclaredField(idList[0]); + Object left = ((Vector) leftField.get(this)).get(objIndex); + + // idList[0] is the name of the property in RelyingParty Object + // note the object type name from left and right are different from idlist[0]. The latter + // is the name of + // the list of the former objects in RelyingParty Object. + historyItems.AddChangeItem(idList[0], left, right); + } + } + List myNewObjects = diff.getChangesByType(NewObject.class); + for (Change change : myNewObjects) { + Object obj2 = change.getAffectedObject().get(); + String[] classNameSplit = obj2.getClass().toString().split("\\."); + String className = classNameSplit[classNameSplit.length - 1]; + if (className.equalsIgnoreCase("startTime") + || className.equalsIgnoreCase("endTime") + || className.equalsIgnoreCase("uuid") + || className.equalsIgnoreCase("loggerRemoteView") + || className.equalsIgnoreCase("logger") + || className.equalsIgnoreCase("updatedBy")) continue; + // if object type is RelyingParty then this change is a single valued field, not a list of + // fields of a different object type (e.g. contactPersons). + if (obj2 instanceof RelyingParty) { + historyItems.AddNewItem(className, obj2); + } else { // else should catch any "object" type fields of RelyingParty + String propertyName = className; + // string containing index of affected object + GlobalId globalId = change.getAffectedGlobalId(); + ValueObjectId valueId = (ValueObjectId) globalId; + String[] idList = valueId.getFragment().split("/"); + int objIndex = Integer.parseInt(idList[1]); + // since we grab the entire object when we detect one change, + // don't bother tracking additional changes + if (objIndex == objDupIndex && obj2.equals(objDupType)) { + continue; + } + objDupIndex = objIndex; // keep track of this instance index + objDupType = obj2; // keep track of this object so we don't duplicate it + // idList[0] is the name of the property in RelyingParty Object + // note the object type (classname above) is different from idlist[0]. The latter is the + // name of + // the list of the former objects in RelyingParty Object. + historyItems.AddNewItem(idList[0], obj2); + } + } + List myRemovedObjects = diff.getChangesByType(ObjectRemoved.class); + for (Change change : myRemovedObjects) { + Object obj3 = change.getAffectedObject().get(); + String[] classNameSplit = obj3.getClass().toString().split("\\."); + String className = classNameSplit[classNameSplit.length - 1]; + if (className.equalsIgnoreCase("startTime") + || className.equalsIgnoreCase("endTime") + || className.equalsIgnoreCase("uuid") + || className.equalsIgnoreCase("loggerRemoteView") + || className.equalsIgnoreCase("logger") + || className.equalsIgnoreCase("updatedBy")) continue; + // if object type is RelyingParty then this change is a single valued field, not a list of + // fields of a different object type (e.g. contactPersons). + if (obj3 instanceof RelyingParty) { + historyItems.AddDeleteItem(className, change.toString()); // will that work? + } else { // else should catch any "object" type fields of RelyingParty + String propertyName = className; + // string containing index of affected object + GlobalId globalId = change.getAffectedGlobalId(); + ValueObjectId valueId = (ValueObjectId) globalId; + String[] idList = valueId.getFragment().split("/"); + int objIndex = Integer.parseInt(idList[1]); + // since we grab the entire object when we detect one change, + // don't bother tracking additional changes + if (objIndex == objDupIndex && obj3.equals(objDupType)) { + continue; + } + objDupIndex = objIndex; // keep track of this instance index + objDupType = obj3; // keep track of this object so we don't duplicate it + // some nutty reflection to get the original value + Class leftCls = this.getClass(); + Field leftField = leftCls.getDeclaredField(idList[0]); + Object left = ((Vector) leftField.get(this)).get(objIndex); + // idList[0] is the name of the property in RelyingParty Object + // note the object type (classname above) is different from idlist[0]. The latter is the + // name of + // the list of the former objects in RelyingParty Object. + historyItems.AddDeleteItem(idList[0], left); + } + } + } catch (Exception e) { + Exception ee = e; + } + + return historyItems; + } + + public RelyingParty replicate(String dns) { + return null; + } + + public void setEntityId(String v) { + entityId = v; + } + + public String getEntityId() { + return (entityId); + } + + public void setMetadataId(String v) { + metadataId = v; + } + + public String getMetadataId() { + return (metadataId); + } + + public void setStartTime(String v) { + startTime = v; + } + + public String getStartTime() { + return (startTime); + } + + public void setEndTime(String v) { + endTime = v; + } + + public String getEndTime() { + return (endTime); + } + + public void setUuid(UUID v) { + uuid = v; + } + + public UUID getUuid() { + return (uuid); + } + + public void setUpdatedBy(String v) { + updatedBy = v; + } + + public String getUpdatedBy() { + return (updatedBy); + } + + public void setEditable(boolean v) { + editable = v; + } + + public boolean getEditable() { + return (editable); + } + + public List getProtocolSupportEnumerations() { + return (protocolSupportEnumerations); + } + + public void setKeyDescriptors(List v) { + keyDescriptors = v; + } + + public List getKeyDescriptors() { + return (keyDescriptors); + } + + public void setNameIDFormats(List v) { + nameIDFormats = v; + } + + public List getNameIDFormats() { + return (nameIDFormats); + } + + public void setAssertionConsumerServices(List v) { + assertionConsumerServices = v; + } + + public List getAssertionConsumerServices() { + return (assertionConsumerServices); + } + + public String getAuthnRequestsSigned() { + return authnRequestsSigned; + } + + public void setAuthnRequestsSigned(String v) { + authnRequestsSigned = v; + } + + public void setOrganization(Organization v) { + organization = v; + } + + public Organization getOrganization() { + return organization; + } + + public void setContactPersons(List v) { + contactPersons = v; + } + + public List getContactPersons() { + return (contactPersons); + } + + public String getEntityCategory() { + return (entityCategory); + } +} diff --git a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyComparator.java b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyComparator.java index d4405a3..ea47524 100644 --- a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyComparator.java +++ b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyComparator.java @@ -1,39 +1,31 @@ package edu.washington.iam.registry.rp; import java.util.Comparator; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - - /* Comparator for relying parties. Sort by reverse dns */ -public class RelyingPartyComparator implements Comparator { +public class RelyingPartyComparator implements Comparator { - private final Logger log = LoggerFactory.getLogger(getClass()); + private final Logger log = LoggerFactory.getLogger(getClass()); + public int compare(Object rp1, Object rp2) { - public int compare(Object rp1, Object rp2) { - - String id1 = ((RelyingParty)rp1).getEntityId(); - if (id1.startsWith("https://")) id1 = id1.substring(8); - if (id1.startsWith("http://")) id1 = id1.substring(7); - String id2 = ((RelyingParty)rp2).getEntityId(); - if (id2.startsWith("https://")) id2 = id2.substring(8); - if (id2.startsWith("http://")) id2 = id2.substring(7); - RelyingPartyIdComparator c = new RelyingPartyIdComparator(); -// log.info("compare " + id1 + " to " + id2); - return (c.compare(id1, id2)); - } - - public boolean equals(Object rp1, Object rp2) { - String id1 = ((RelyingParty)rp1).getEntityId(); - String id2 = ((RelyingParty)rp2).getEntityId(); - return (id1.equals(id2)); - } + String id1 = ((RelyingParty) rp1).getEntityId(); + if (id1.startsWith("https://")) id1 = id1.substring(8); + if (id1.startsWith("http://")) id1 = id1.substring(7); + String id2 = ((RelyingParty) rp2).getEntityId(); + if (id2.startsWith("https://")) id2 = id2.substring(8); + if (id2.startsWith("http://")) id2 = id2.substring(7); + RelyingPartyIdComparator c = new RelyingPartyIdComparator(); + // log.info("compare " + id1 + " to " + id2); + return (c.compare(id1, id2)); + } + public boolean equals(Object rp1, Object rp2) { + String id1 = ((RelyingParty) rp1).getEntityId(); + String id2 = ((RelyingParty) rp2).getEntityId(); + return (id1.equals(id2)); + } } - - - diff --git a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyEntry.java b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyEntry.java index 612fd9c..97014a6 100644 --- a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyEntry.java +++ b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyEntry.java @@ -2,24 +2,22 @@ public class RelyingPartyEntry { - public String getMetadataId() { - return metadataId; - } + public String getMetadataId() { + return metadataId; + } - public void setMetadataId(String metadataId) { - this.metadataId = metadataId; - } + public void setMetadataId(String metadataId) { + this.metadataId = metadataId; + } - public String getRelyingPartyId() { - return relyingPartyId; - } - - public void setRelyingPartyId(String relyingPartyId) { - this.relyingPartyId = relyingPartyId; - } - - private String relyingPartyId; - private String metadataId; + public String getRelyingPartyId() { + return relyingPartyId; + } + public void setRelyingPartyId(String relyingPartyId) { + this.relyingPartyId = relyingPartyId; + } + private String relyingPartyId; + private String metadataId; } diff --git a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyEntryComparator.java b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyEntryComparator.java index 2059b30..2232537 100644 --- a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyEntryComparator.java +++ b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyEntryComparator.java @@ -3,13 +3,13 @@ import java.util.Comparator; public class RelyingPartyEntryComparator implements Comparator { - @Override - public int compare(RelyingPartyEntry rpe1, RelyingPartyEntry rpe2) { - int entityIdCompare = new RelyingPartyIdComparator() - .compare(rpe1.getRelyingPartyId(), rpe2.getRelyingPartyId()); - if(entityIdCompare == 0){ - return rpe1.getMetadataId().compareTo(rpe2.getMetadataId()); - } - return entityIdCompare; + @Override + public int compare(RelyingPartyEntry rpe1, RelyingPartyEntry rpe2) { + int entityIdCompare = + new RelyingPartyIdComparator().compare(rpe1.getRelyingPartyId(), rpe2.getRelyingPartyId()); + if (entityIdCompare == 0) { + return rpe1.getMetadataId().compareTo(rpe2.getMetadataId()); } + return entityIdCompare; + } } diff --git a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyIdComparator.java b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyIdComparator.java index 26f9a34..82b49d6 100644 --- a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyIdComparator.java +++ b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyIdComparator.java @@ -1,30 +1,21 @@ package edu.washington.iam.registry.rp; import java.util.Comparator; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import org.apache.commons.lang.ArrayUtils; - - /* Comparator for relying parties. Sort by reverse dns */ public class RelyingPartyIdComparator implements Comparator { - private final Logger log = LoggerFactory.getLogger(getClass()); - - @Override - public int compare(String id1, String id2) { - if (id1.startsWith("https://")) id1 = id1.substring(8); - if (id1.startsWith("http://")) id1 = id1.substring(7); - if (id2.startsWith("https://")) id2 = id2.substring(8); - if (id2.startsWith("http://")) id2 = id2.substring(7); - return id1.compareTo(id2); - } + private final Logger log = LoggerFactory.getLogger(getClass()); + @Override + public int compare(String id1, String id2) { + if (id1.startsWith("https://")) id1 = id1.substring(8); + if (id1.startsWith("http://")) id1 = id1.substring(7); + if (id2.startsWith("https://")) id2 = id2.substring(8); + if (id2.startsWith("http://")) id2 = id2.substring(7); + return id1.compareTo(id2); + } } - - - diff --git a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyManager.java b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyManager.java index f38cfc2..f720fea 100644 --- a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyManager.java +++ b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyManager.java @@ -1,36 +1,39 @@ -package edu.washington.iam.registry.rp; - -import java.io.Serializable; -import java.util.List; - -import org.w3c.dom.Document; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -import edu.washington.iam.registry.exception.RelyingPartyException; - -public interface RelyingPartyManager extends Serializable { - - public List getRelyingParties(); - public List getRelyingParties(String search, String admin); - public List getRelyingPartyHistoryById(String id) throws RelyingPartyException; - public List getMetadataIds(); - public List searchRelyingPartyIds(String searchStr, String metadataId); - public RelyingParty getRelyingPartyById(String id) throws RelyingPartyException; - public RelyingParty getRelyingPartyById(String id, String mdid) throws RelyingPartyException; - - public int updateRelyingParty(RelyingParty relyingParty, String mdId, String remoteUser) throws RelyingPartyException; - public int removeRelyingParty(String id, String mdId, String remoteUser); - - public RelyingParty genRelyingPartyByLookup(String dns) throws RelyingPartyException; - public RelyingParty genRelyingPartyByName(String entityId, String dns); - public RelyingParty genRelyingPartyByCopy(String dns, String entityId); - - public boolean isMetadataEditable(String mdid); - - public void init(); - public void cleanup(); - -} +package edu.washington.iam.registry.rp; + +import edu.washington.iam.registry.exception.RelyingPartyException; +import java.io.Serializable; +import java.util.List; + +public interface RelyingPartyManager extends Serializable { + + public List getRelyingParties(); + + public List getRelyingParties(String search, String admin); + + public List getRelyingPartyHistoryById(String id) throws RelyingPartyException; + + public List getMetadataIds(); + + public List searchRelyingPartyIds(String searchStr, String metadataId); + + public RelyingParty getRelyingPartyById(String id) throws RelyingPartyException; + + public RelyingParty getRelyingPartyById(String id, String mdid) throws RelyingPartyException; + + public int updateRelyingParty(RelyingParty relyingParty, String mdId, String remoteUser) + throws RelyingPartyException; + + public int removeRelyingParty(String id, String mdId, String remoteUser); + + public RelyingParty genRelyingPartyByLookup(String dns) throws RelyingPartyException; + + public RelyingParty genRelyingPartyByName(String entityId, String dns); + + public RelyingParty genRelyingPartyByCopy(String dns, String entityId); + + public boolean isMetadataEditable(String mdid); + + public void init(); + + public void cleanup(); +} diff --git a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyManagerImpl.java b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyManagerImpl.java index 206de89..c31f5a4 100644 --- a/src/main/java/edu/washington/iam/registry/rp/RelyingPartyManagerImpl.java +++ b/src/main/java/edu/washington/iam/registry/rp/RelyingPartyManagerImpl.java @@ -1,285 +1,259 @@ -/* ======================================================================== - * Copyright (c) 2010-2011 The University of Washington - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ======================================================================== - */ - -package edu.washington.iam.registry.rp; - -import java.util.*; -import java.io.File; -import java.io.FileWriter; -import java.io.BufferedWriter; -import java.net.URI; -import java.net.URISyntaxException; -import java.io.IOException; - -import org.w3c.dom.Node; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.DOMConfiguration; -import org.w3c.dom.ls.DOMImplementationLS; -import org.w3c.dom.ls.LSOutput; -import org.w3c.dom.ls.LSSerializer; - -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.ParserConfigurationException; -import org.xml.sax.SAXException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.net.ssl.TrustManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; - -import java.security.SecureRandom; -import java.security.Security; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.HostnameVerifier; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -import edu.washington.iam.tools.XMLHelper; -import edu.washington.iam.registry.exception.RelyingPartyException; - -public class RelyingPartyManagerImpl implements RelyingPartyManager { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - - public void setMetadataDAOs(Map metadataDAOs) { - this.metadataDAOs = metadataDAOs; - } - - private Map metadataDAOs; - - private SchemaVerifier schemaVerifier = null; - public void setSchemaVerifier(SchemaVerifier v) { - this.schemaVerifier = v; - } - - static { - Security.addProvider(new BouncyCastleProvider()); - } - - - - - @Override - public void init() { - //loadMetadata(); - } - @Override - public void cleanup() { - for(MetadataDAO metadataDAO : metadataDAOs.values()){ - metadataDAO.cleanup(); - } - } - - @Override - public List getRelyingParties(){ - List list = new ArrayList<>(); - for(String mdid : metadataDAOs.keySet()){ - list.addAll(metadataDAOs.get(mdid).getRelyingParties()); - } - Collections.sort(list, new RelyingPartyComparator()); - return list; - } - - @Override - public List getRelyingParties(String search, String admin){ - log.debug("rp search: str=" + search + ", adm=" + admin); - if (search==null && admin==null) return getRelyingParties(); - List rps = new ArrayList<>(); - for (String mdid : metadataDAOs.keySet()){ - log.debug(" .. adding from : " + mdid); - if (search!=null && search.length()>0) rps.addAll(metadataDAOs.get(mdid).getRelyingPartiesById(search)); - else if (admin!=null && admin.length()>0) rps.addAll(metadataDAOs.get(mdid).getRelyingPartiesByAdmin(admin)); - } - Collections.sort(rps, new RelyingPartyComparator()); - return rps; - } - - @Override - public List searchRelyingPartyIds(String searchStr, String metadataId){ - log.debug("rp search: " + searchStr + ", md=" + metadataId); - List list = new ArrayList<>(); - Map> idsMap = new HashMap<>(); - if(metadataId == null){ - for(String mdid : metadataDAOs.keySet()){ - idsMap.put(mdid, metadataDAOs.get(mdid).searchRelyingPartyIds(searchStr)); - } - } - else if(metadataDAOs.containsKey(metadataId)){ - idsMap.put(metadataId, metadataDAOs.get(metadataId).searchRelyingPartyIds(searchStr)); - } - - for(String mdid : idsMap.keySet()){ - for(String entityId : idsMap.get(mdid)) { - RelyingPartyEntry rpEntry = new RelyingPartyEntry(); - rpEntry.setRelyingPartyId(entityId); - rpEntry.setMetadataId(mdid); - list.add(rpEntry); - } - } - - Collections.sort(list, new RelyingPartyEntryComparator()); - return list; - } - - - @Override - public List getRelyingPartyHistoryById(String id) throws RelyingPartyException { - log.debug("rp history search: " + id); - for (MetadataDAO metadataDAO : metadataDAOs.values()){ - try { - return metadataDAO.getRelyingPartyHistoryById(id); - } - catch (RelyingPartyException e){ - - } - } - throw new RelyingPartyException("not found"); - } - - - // get rp by id - @Override - public RelyingParty getRelyingPartyById(String id, String mdid) throws RelyingPartyException { - log.debug("rp search: " + id + ", md=" + mdid); - if (mdid==null) - return this.getRelyingPartyById(id); - return metadataDAOs.get(mdid).getRelyingPartyById(id); - } - - @Override - public RelyingParty getRelyingPartyById(String id) throws RelyingPartyException { - log.debug("rp search: " + id); - for (MetadataDAO metadataDAO : metadataDAOs.values()){ - try { - return metadataDAO.getRelyingPartyById(id); - } - catch (RelyingPartyException e){ - - } - } - throw new RelyingPartyException("not found"); - } - - private HostnameVerifier hostv = new HostnameVerifier() { - @Override - public boolean verify(String urlhost, SSLSession session) { - log.info("verify host: "+urlhost+" vs. "+session.getPeerHost()); - return true; - } - }; - - // create RP by copy of another - @Override - public RelyingParty genRelyingPartyByCopy(String dns, String id) { - try { - RelyingParty rp = this.getRelyingPartyById(id); - return rp.replicate(dns); - } catch (RelyingPartyException e) { - // log.debug("not that one"); - } - return null; - } - - - // create RP by dns lookup - @Override - public RelyingParty genRelyingPartyByLookup(String url) throws RelyingPartyException { - - RelyingParty rp = null; - log.info("getrpmd: genRelyingPartyByLookup: " + url); - - // install the all trusting trust manager - try { - TrustManager[] managers = { new TrustAnyX509TrustManager() }; - SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(null, managers, new SecureRandom()); - HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); - HttpsURLConnection.setDefaultHostnameVerifier(hostv); - } catch (Exception e) { - log.error("trust install: " + e); - throw new RelyingPartyException("trust insall fails: " + e); - } - - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - Document doc = builder.parse (url); - - Element ele = doc.getDocumentElement(); - - log.info("spm: tagname: " + ele.getTagName()); - - if (XMLHelper.getElementByName(ele, "SPSSODescriptor")==null) { - throw new RelyingPartyException("no spsso in document"); - } - rp = new RelyingParty(ele, "lookup", true); - } catch (ParserConfigurationException e) { - throw new RelyingPartyException("parser: " + e); - } catch (SAXException e) { - throw new RelyingPartyException("SAXException: " + e); - } catch (IOException e) { - throw new RelyingPartyException("IOException: " + e); - } catch (Exception e) { - throw new RelyingPartyException("Exception: " + e); - } - return rp; - } - - // create RP with defaults - @Override - public RelyingParty genRelyingPartyByName(String entityId, String dns) { - return new RelyingParty(entityId, dns); - } - - @Override - public List getMetadataIds() { - return new ArrayList<>(metadataDAOs.keySet()); - } - - public int updateRelyingParty(RelyingParty relyingParty, String mdid, String remoteUser) throws RelyingPartyException { - int status = 200; - log.info(String.format("rp update doc, source=%s; rpid=%s", mdid, relyingParty.getEntityId())); - // do a final verification of the new metadata - if (schemaVerifier!=null && ! schemaVerifier.testSchemaValid(relyingParty)) throw new RelyingPartyException("The posted document did not produce valid metadata."); - metadataDAOs.get(mdid).updateRelyingParty(relyingParty, remoteUser); - return (status); - } - - - /* delete relyingParty */ - @Override - public int removeRelyingParty(String id, String mdid, String remoteUser) { - log.info("rp delete doc " + id); - - metadataDAOs.get(mdid).removeRelyingParty(id, remoteUser); - return (200); - } - - @Override - public boolean isMetadataEditable(String mdid){ - return (metadataDAOs.containsKey(mdid) && metadataDAOs.get(mdid).isEditable()); - } - -} +/* ======================================================================== + * Copyright (c) 2010-2011 The University of Washington + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== + */ + +package edu.washington.iam.registry.rp; + +import edu.washington.iam.registry.exception.RelyingPartyException; +import edu.washington.iam.tools.XMLHelper; +import java.io.IOException; +import java.security.SecureRandom; +import java.security.Security; +import java.util.*; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +public class RelyingPartyManagerImpl implements RelyingPartyManager { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + public void setMetadataDAOs(Map metadataDAOs) { + this.metadataDAOs = metadataDAOs; + } + + private Map metadataDAOs; + + private SchemaVerifier schemaVerifier = null; + + public void setSchemaVerifier(SchemaVerifier v) { + this.schemaVerifier = v; + } + + static { + Security.addProvider(new BouncyCastleProvider()); + } + + @Override + public void init() { + // loadMetadata(); + } + + @Override + public void cleanup() { + for (MetadataDAO metadataDAO : metadataDAOs.values()) { + metadataDAO.cleanup(); + } + } + + @Override + public List getRelyingParties() { + List list = new ArrayList<>(); + for (String mdid : metadataDAOs.keySet()) { + list.addAll(metadataDAOs.get(mdid).getRelyingParties()); + } + Collections.sort(list, new RelyingPartyComparator()); + return list; + } + + @Override + public List getRelyingParties(String search, String admin) { + log.debug("rp search: str=" + search + ", adm=" + admin); + if (search == null && admin == null) return getRelyingParties(); + List rps = new ArrayList<>(); + for (String mdid : metadataDAOs.keySet()) { + log.debug(" .. adding from : " + mdid); + if (search != null && search.length() > 0) + rps.addAll(metadataDAOs.get(mdid).getRelyingPartiesById(search)); + else if (admin != null && admin.length() > 0) + rps.addAll(metadataDAOs.get(mdid).getRelyingPartiesByAdmin(admin)); + } + Collections.sort(rps, new RelyingPartyComparator()); + return rps; + } + + @Override + public List searchRelyingPartyIds(String searchStr, String metadataId) { + log.debug("rp search: " + searchStr + ", md=" + metadataId); + List list = new ArrayList<>(); + Map> idsMap = new HashMap<>(); + if (metadataId == null) { + for (String mdid : metadataDAOs.keySet()) { + idsMap.put(mdid, metadataDAOs.get(mdid).searchRelyingPartyIds(searchStr)); + } + } else if (metadataDAOs.containsKey(metadataId)) { + idsMap.put(metadataId, metadataDAOs.get(metadataId).searchRelyingPartyIds(searchStr)); + } + + for (String mdid : idsMap.keySet()) { + for (String entityId : idsMap.get(mdid)) { + RelyingPartyEntry rpEntry = new RelyingPartyEntry(); + rpEntry.setRelyingPartyId(entityId); + rpEntry.setMetadataId(mdid); + list.add(rpEntry); + } + } + + Collections.sort(list, new RelyingPartyEntryComparator()); + return list; + } + + @Override + public List getRelyingPartyHistoryById(String id) throws RelyingPartyException { + log.debug("rp history search: " + id); + for (MetadataDAO metadataDAO : metadataDAOs.values()) { + try { + return metadataDAO.getRelyingPartyHistoryById(id); + } catch (RelyingPartyException e) { + + } + } + throw new RelyingPartyException("not found"); + } + + // get rp by id + @Override + public RelyingParty getRelyingPartyById(String id, String mdid) throws RelyingPartyException { + log.debug("rp search: " + id + ", md=" + mdid); + if (mdid == null) return this.getRelyingPartyById(id); + return metadataDAOs.get(mdid).getRelyingPartyById(id); + } + + @Override + public RelyingParty getRelyingPartyById(String id) throws RelyingPartyException { + log.debug("rp search: " + id); + for (MetadataDAO metadataDAO : metadataDAOs.values()) { + try { + return metadataDAO.getRelyingPartyById(id); + } catch (RelyingPartyException e) { + + } + } + throw new RelyingPartyException("not found"); + } + + private HostnameVerifier hostv = + new HostnameVerifier() { + @Override + public boolean verify(String urlhost, SSLSession session) { + log.info("verify host: " + urlhost + " vs. " + session.getPeerHost()); + return true; + } + }; + + // create RP by copy of another + @Override + public RelyingParty genRelyingPartyByCopy(String dns, String id) { + try { + RelyingParty rp = this.getRelyingPartyById(id); + return rp.replicate(dns); + } catch (RelyingPartyException e) { + // log.debug("not that one"); + } + return null; + } + + // create RP by dns lookup + @Override + public RelyingParty genRelyingPartyByLookup(String url) throws RelyingPartyException { + + RelyingParty rp = null; + log.info("getrpmd: genRelyingPartyByLookup: " + url); + + // install the all trusting trust manager + try { + TrustManager[] managers = {new TrustAnyX509TrustManager()}; + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, managers, new SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + HttpsURLConnection.setDefaultHostnameVerifier(hostv); + } catch (Exception e) { + log.error("trust install: " + e); + throw new RelyingPartyException("trust insall fails: " + e); + } + + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document doc = builder.parse(url); + + Element ele = doc.getDocumentElement(); + + log.info("spm: tagname: " + ele.getTagName()); + + if (XMLHelper.getElementByName(ele, "SPSSODescriptor") == null) { + throw new RelyingPartyException("no spsso in document"); + } + rp = new RelyingParty(ele, "lookup", true); + } catch (ParserConfigurationException e) { + throw new RelyingPartyException("parser: " + e); + } catch (SAXException e) { + throw new RelyingPartyException("SAXException: " + e); + } catch (IOException e) { + throw new RelyingPartyException("IOException: " + e); + } catch (Exception e) { + throw new RelyingPartyException("Exception: " + e); + } + return rp; + } + + // create RP with defaults + @Override + public RelyingParty genRelyingPartyByName(String entityId, String dns) { + return new RelyingParty(entityId, dns); + } + + @Override + public List getMetadataIds() { + return new ArrayList<>(metadataDAOs.keySet()); + } + + public int updateRelyingParty(RelyingParty relyingParty, String mdid, String remoteUser) + throws RelyingPartyException { + int status = 200; + log.info(String.format("rp update doc, source=%s; rpid=%s", mdid, relyingParty.getEntityId())); + // do a final verification of the new metadata + if (schemaVerifier != null && !schemaVerifier.testSchemaValid(relyingParty)) + throw new RelyingPartyException("The posted document did not produce valid metadata."); + metadataDAOs.get(mdid).updateRelyingParty(relyingParty, remoteUser); + return (status); + } + + /* delete relyingParty */ + @Override + public int removeRelyingParty(String id, String mdid, String remoteUser) { + log.info("rp delete doc " + id); + + metadataDAOs.get(mdid).removeRelyingParty(id, remoteUser); + return (200); + } + + @Override + public boolean isMetadataEditable(String mdid) { + return (metadataDAOs.containsKey(mdid) && metadataDAOs.get(mdid).isEditable()); + } +} diff --git a/src/main/java/edu/washington/iam/registry/rp/SchemaVerifier.java b/src/main/java/edu/washington/iam/registry/rp/SchemaVerifier.java index bf347f0..c2e5d8f 100644 --- a/src/main/java/edu/washington/iam/registry/rp/SchemaVerifier.java +++ b/src/main/java/edu/washington/iam/registry/rp/SchemaVerifier.java @@ -15,71 +15,65 @@ * ======================================================================== */ - package edu.washington.iam.registry.rp; -import java.util.List; -import java.io.File; -import java.io.InputStreamReader; import java.io.BufferedReader; -import java.io.IOException; -import java.io.FileWriter; import java.io.BufferedWriter; - +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - /* Use saml xmlsectool to test metadata validity */ public class SchemaVerifier { - private final Logger log = LoggerFactory.getLogger(getClass()); - - private String verifyCommand = null; - public void setVerifyCommand(String v) { - verifyCommand = v; - } - - /** - * Test if a RelyingParty is schema valid - * - * @param relying party - */ - - public boolean testSchemaValid(RelyingParty rp) { - - boolean isValid = false; - log.debug("testing schema validity of " + rp.getEntityId()); - - try { - File tmp = File.createTempFile("md_", ".xml", new File("/tmp")); - tmp.deleteOnExit(); - FileWriter xstream = new FileWriter(tmp); - BufferedWriter xout = new BufferedWriter(xstream); - - xout.write(XMLText.xmlStart); - rp.writeXml(xout); - xout.write(XMLText.xmlEnd); - xout.close(); - - String cmd = verifyCommand + " " + tmp.getAbsolutePath(); - Runtime rt = Runtime.getRuntime(); - Process pc = rt.exec(cmd); - InputStreamReader isr = new InputStreamReader( pc.getInputStream() ); - BufferedReader br = new BufferedReader(isr); - String line; - while ((line = br.readLine()) != null) { - log.debug("xmlsectool says: " + line); - if (line.contains("XML document is schema valid")) return true; - } - } catch (IOException e) { - log.error("xmlsectool error: " + e); - } - return false; - //return true; //for testing on Windows - + private final Logger log = LoggerFactory.getLogger(getClass()); + + private String verifyCommand = null; + + public void setVerifyCommand(String v) { + verifyCommand = v; + } + + /** + * Test if a RelyingParty is schema valid + * + * @param relying party + */ + public boolean testSchemaValid(RelyingParty rp) { + + boolean isValid = false; + log.debug("testing schema validity of " + rp.getEntityId()); + + try { + File tmp = File.createTempFile("md_", ".xml", new File("/tmp")); + tmp.deleteOnExit(); + FileWriter xstream = new FileWriter(tmp); + BufferedWriter xout = new BufferedWriter(xstream); + + xout.write(XMLText.xmlStart); + rp.writeXml(xout); + xout.write(XMLText.xmlEnd); + xout.close(); + + String cmd = verifyCommand + " " + tmp.getAbsolutePath(); + Runtime rt = Runtime.getRuntime(); + Process pc = rt.exec(cmd); + InputStreamReader isr = new InputStreamReader(pc.getInputStream()); + BufferedReader br = new BufferedReader(isr); + String line; + while ((line = br.readLine()) != null) { + log.debug("xmlsectool says: " + line); + if (line.contains("XML document is schema valid")) return true; + } + } catch (IOException e) { + log.error("xmlsectool error: " + e); } + return false; + // return true; //for testing on Windows + } } - diff --git a/src/main/java/edu/washington/iam/registry/rp/TrustAnyX509TrustManager.java b/src/main/java/edu/washington/iam/registry/rp/TrustAnyX509TrustManager.java index 5790b98..6dea725 100644 --- a/src/main/java/edu/washington/iam/registry/rp/TrustAnyX509TrustManager.java +++ b/src/main/java/edu/washington/iam/registry/rp/TrustAnyX509TrustManager.java @@ -15,7 +15,6 @@ * ======================================================================== */ - package edu.washington.iam.registry.rp; import java.security.cert.X509Certificate; @@ -23,14 +22,11 @@ public class TrustAnyX509TrustManager implements X509TrustManager { - public void checkClientTrusted(X509Certificate[] certs, String auth) { - } + public void checkClientTrusted(X509Certificate[] certs, String auth) {} - public void checkServerTrusted(X509Certificate[] certs, String auth) { - } + public void checkServerTrusted(X509Certificate[] certs, String auth) {} - public X509Certificate[] getAcceptedIssuers() { - return (new X509Certificate[] {}); - } + public X509Certificate[] getAcceptedIssuers() { + return (new X509Certificate[] {}); + } } - diff --git a/src/main/java/edu/washington/iam/registry/rp/UuidManager.java b/src/main/java/edu/washington/iam/registry/rp/UuidManager.java index 54ced99..642caa6 100644 --- a/src/main/java/edu/washington/iam/registry/rp/UuidManager.java +++ b/src/main/java/edu/washington/iam/registry/rp/UuidManager.java @@ -1,81 +1,77 @@ package edu.washington.iam.registry.rp; +import java.util.List; +import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; -import java.util.List; -import java.util.UUID; - /* -* This class manages UUIDs. -* -* FOr UW SPs, the table of record for UUID is metadata. For InCommon SPs, the table of record is incommon_sp. -* -* */ + * This class manages UUIDs. + * + * FOr UW SPs, the table of record for UUID is metadata. For InCommon SPs, the table of record is incommon_sp. + * + * */ public class UuidManager { - private JdbcTemplate template; - public void setTemplate(JdbcTemplate m) { template = m; } - - - private final Logger log = LoggerFactory.getLogger(getClass()); - - /*Feed an entityid to getUuid and it will get the UUID if one exists, or return - * a new one if one isn't found. Works for InCommon (no entry in metadata table) and UW SPs.*/ - public UUID getUuid(String entityId){ - - //look in metadata table - List uuid = template.queryForList( - "select uuid from metadata where entity_id = ? and end_time is null", - UUID.class, - entityId); - if (uuid.size() > 0) { - return uuid.get(0); - } - //the above should hit most of the time...for InCommon SPs it will take some extra work - else { - //look in the special InCommon EntityID mapping table - List uuidIc = template.queryForList( - "select uuid from incommon_sp where entity_id = ? and active is true", - UUID.class, - entityId); - if (uuidIc.size() > 0) { - return uuidIc.get(0); - } - else { - //we have never done anything in the database with this SP, so we have to create a UUID for it - UUID newUuid = UUID.randomUUID(); - template.update( - "insert into incommon_sp (uuid, entity_id, active) values " + - "(? ,?, true)", - newUuid, entityId); - log.debug("added new incommon SP mapping for " + entityId); - return newUuid; - - } - } - - - } - - /*Given an entity ID, returns whether or not that entityID has a UUID entry in the - * incommon_sp table */ - public Boolean hasIncUuid(String entityId){ - - List uuidIc = template.queryForList( - "select uuid from incommon_sp where entity_id = ? and active is true", - UUID.class, - entityId); - if (uuidIc.size() > 0) { - return true; - } else { return false; } - - } - - - - - + private JdbcTemplate template; + + public void setTemplate(JdbcTemplate m) { + template = m; + } + + private final Logger log = LoggerFactory.getLogger(getClass()); + + /*Feed an entityid to getUuid and it will get the UUID if one exists, or return + * a new one if one isn't found. Works for InCommon (no entry in metadata table) and UW SPs.*/ + public UUID getUuid(String entityId) { + + // look in metadata table + List uuid = + template.queryForList( + "select uuid from metadata where entity_id = ? and end_time is null", + UUID.class, + entityId); + if (uuid.size() > 0) { + return uuid.get(0); + } + // the above should hit most of the time...for InCommon SPs it will take some extra work + else { + // look in the special InCommon EntityID mapping table + List uuidIc = + template.queryForList( + "select uuid from incommon_sp where entity_id = ? and active is true", + UUID.class, + entityId); + if (uuidIc.size() > 0) { + return uuidIc.get(0); + } else { + // we have never done anything in the database with this SP, so we have to create a UUID for + // it + UUID newUuid = UUID.randomUUID(); + template.update( + "insert into incommon_sp (uuid, entity_id, active) values " + "(? ,?, true)", + newUuid, + entityId); + log.debug("added new incommon SP mapping for " + entityId); + return newUuid; + } + } + } + + /*Given an entity ID, returns whether or not that entityID has a UUID entry in the + * incommon_sp table */ + public Boolean hasIncUuid(String entityId) { + + List uuidIc = + template.queryForList( + "select uuid from incommon_sp where entity_id = ? and active is true", + UUID.class, + entityId); + if (uuidIc.size() > 0) { + return true; + } else { + return false; + } + } } diff --git a/src/main/java/edu/washington/iam/registry/rp/XMLMetadata.java b/src/main/java/edu/washington/iam/registry/rp/XMLMetadata.java index e9789f6..d278d87 100644 --- a/src/main/java/edu/washington/iam/registry/rp/XMLMetadata.java +++ b/src/main/java/edu/washington/iam/registry/rp/XMLMetadata.java @@ -17,380 +17,373 @@ package edu.washington.iam.registry.rp; -import java.util.ArrayList; -import java.util.List; -import java.util.Vector; +import edu.washington.iam.registry.exception.RelyingPartyException; +import edu.washington.iam.tools.XMLHelper; +import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; -import java.io.BufferedWriter; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.io.IOException; -import java.lang.InterruptedException; - +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; import java.util.concurrent.locks.ReentrantReadWriteLock; - -import java.util.Properties; - -import org.springframework.beans.factory.annotation.Autowired; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - import javax.annotation.PostConstruct; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.ParserConfigurationException; -import org.xml.sax.SAXException; - +import javax.xml.parsers.DocumentBuilderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import edu.washington.iam.tools.XMLHelper; -import edu.washington.iam.registry.exception.RelyingPartyException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; public class XMLMetadata implements MetadataDAO { - - private final Logger log = LoggerFactory.getLogger(getClass()); - private final ReentrantReadWriteLock locker = new ReentrantReadWriteLock(); - public void setId(String id) { - this.id = id; + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ReentrantReadWriteLock locker = new ReentrantReadWriteLock(); + + public void setId(String id) { + this.id = id; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setEditable(boolean editable) { + this.editable = editable; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public void setRefresh(int refresh) { + this.refresh = refresh; + } + + private String id; + private String description; + private boolean editable; + private String uri; + private String sourceName; + private String tempUri; + private int refresh = 0; + private List relyingParties; + + Thread reloader = null; + + private String xmlStart = + "\n" + + "\n"; + private String xmlEnd = ""; + private String xmlNotice = + "\n \n\n"; + + private long modifyTime = 0; + + private void refreshMetadataIfNeeded() { + log.debug("reloader checking..."); + File f = new File(sourceName); + if (f.lastModified() > modifyTime) { + // reload the metadata + log.debug("reloading metadata for " + id + " from " + uri); + locker.writeLock().lock(); + try { + loadMetadata(); + } catch (Exception e) { + log.error("reload errro: " + e); + } + locker.writeLock().unlock(); + log.debug("reload completed, time now " + modifyTime); } + } - public void setDescription(String description) { - this.description = description; - } + // thread to sometimes reload the metadata + class MetadataReloader extends Thread { - public void setEditable(boolean editable) { - this.editable = editable; - } + public void run() { + log.debug("reloader running: interval = " + refresh); - public void setUri(String uri) { - this.uri = uri; - } - - public void setRefresh(int refresh) { - this.refresh = refresh; - } + // loop on checking the source - private String id; - private String description; - private boolean editable; - private String uri; - private String sourceName; - private String tempUri; - private int refresh = 0; - private List relyingParties; - - Thread reloader = null; - - private String xmlStart = "\n" + - "\n"; - private String xmlEnd = ""; - private String xmlNotice = "\n \n\n"; - - private long modifyTime = 0; - - private void refreshMetadataIfNeeded() { - log.debug("reloader checking..."); - File f = new File(sourceName); - if (f.lastModified()>modifyTime) { - // reload the metadata - log.debug("reloading metadata for " + id + " from " + uri); - locker.writeLock().lock(); - try { - loadMetadata(); - } catch (Exception e) { - log.error("reload errro: " + e); + while (true) { + refreshMetadataIfNeeded(); + try { + if (isInterrupted()) { + log.info("interrupted during processing"); + break; } - locker.writeLock().unlock(); - log.debug("reload completed, time now " + modifyTime); - } - } - - // thread to sometimes reload the metadata - class MetadataReloader extends Thread { - - public void run() { - log.debug("reloader running: interval = " + refresh); - - // loop on checking the source - - while (true) { - refreshMetadataIfNeeded(); - try { - if (isInterrupted()) { - log.info("interrupted during processing"); - break; - } - Thread.sleep(refresh * 1000); - } catch (InterruptedException e) { - log.info("sleep interrupted"); - break; - } - } + Thread.sleep(refresh * 1000); + } catch (InterruptedException e) { + log.info("sleep interrupted"); + break; } - + } } - - - @PostConstruct - private void init() throws RelyingPartyException { - sourceName = uri.replaceFirst("file:",""); - loadMetadata(); - if(refresh > 0){ - reloader = new Thread(new MetadataReloader()); - reloader.start(); - } + } + + @PostConstruct + private void init() throws RelyingPartyException { + sourceName = uri.replaceFirst("file:", ""); + loadMetadata(); + if (refresh > 0) { + reloader = new Thread(new MetadataReloader()); + reloader.start(); + } + } + + // load metadata from the url + private void loadMetadata() throws RelyingPartyException { + log.info("load relyingParties for " + id + " from " + uri); + + relyingParties = new Vector(); + Document doc; + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + builderFactory.setNamespaceAware(true); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + doc = builder.parse(uri); + } catch (Exception e) { + log.error("parse issue: " + e); + throw new RelyingPartyException("bad xml"); } - // load metadata from the url - private void loadMetadata() throws RelyingPartyException { - log.info("load relyingParties for " + id + " from " + uri); - - relyingParties = new Vector(); - Document doc; - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - builderFactory.setNamespaceAware(true); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - doc = builder.parse (uri); - } catch (Exception e) { - log.error("parse issue: " + e); - throw new RelyingPartyException("bad xml"); - } - - // update the timestamp - File f = new File(sourceName); - modifyTime = f.lastModified(); - log.debug("rp load " + f.getName() + ": time = " + modifyTime); - - List list = XMLHelper.getElementsByName(doc.getDocumentElement(), "EntityDescriptor"); - log.info("found " + list.size()); - - for (int i=0; i getRelyingPartyHistoryById(String rpid) throws RelyingPartyException { + log.debug("md " + id + " looking for history for fixed rp" + rpid); + log.debug(" ..nope. No history for fixed rps. "); + throw new RelyingPartyException("not found--no history for fixed rps"); + } + + // get rp by id + @Override + public RelyingParty getRelyingPartyById(String rpid) throws RelyingPartyException { + log.debug("md " + id + " looking for " + rpid); + refreshMetadataIfNeeded(); + RelyingParty ret = null; + locker.readLock().lock(); + for (int i = 0; i < relyingParties.size(); i++) { + if (relyingParties.get(i).getEntityId().equals(rpid)) ret = relyingParties.get(i); + } + locker.readLock().unlock(); + if (ret != null) return ret; + log.debug(" ..nope"); + throw new RelyingPartyException("not found"); + } + + @Override + public List searchRelyingPartyIds(String searchStr) { + refreshMetadataIfNeeded(); + List list = new ArrayList<>(); + locker.readLock().lock(); + try { + for (RelyingParty rp : relyingParties) { + if (searchStr == null || rp.getEntityId().matches(String.format(".*{0}.*", searchStr))) { + list.add(rp.getEntityId()); + } + } + } finally { locker.readLock().unlock(); - writeMetadata(); - } - - @Override - public List getRelyingPartyHistoryById(String rpid) throws RelyingPartyException { - log.debug("md " + id + " looking for history for fixed rp" + rpid); - log.debug(" ..nope. No history for fixed rps. "); - throw new RelyingPartyException("not found--no history for fixed rps"); } - - // get rp by id - @Override - public RelyingParty getRelyingPartyById(String rpid) throws RelyingPartyException { - log.debug("md " + id + " looking for " + rpid); - refreshMetadataIfNeeded(); - RelyingParty ret = null; - locker.readLock().lock(); - for (int i=0; i getRelyingPartiesById(String search) { + refreshMetadataIfNeeded(); + List rps = new ArrayList<>(); + search = search.toLowerCase(); + locker.readLock().lock(); + try { + for (RelyingParty rp : relyingParties) { + if (rp.getEntityId().toLowerCase().indexOf(search) >= 0) rps.add(rp); } + } finally { locker.readLock().unlock(); - if (ret != null) return ret; - log.debug(" ..nope"); - throw new RelyingPartyException("not found"); - } - - @Override - public List searchRelyingPartyIds(String searchStr) { - refreshMetadataIfNeeded(); - List list = new ArrayList<>(); - locker.readLock().lock(); - try { - for(RelyingParty rp : relyingParties){ - if(searchStr == null || rp.getEntityId().matches(String.format(".*{0}.*", searchStr))){ - list.add(rp.getEntityId()); - } - } - } - finally { - locker.readLock().unlock(); + } + return rps; + } + + @Override + public List getRelyingPartiesByAdmin(String admin) { + refreshMetadataIfNeeded(); + List rps = new ArrayList<>(); + admin = admin.toLowerCase(); + locker.readLock().lock(); + try { + for (RelyingParty rp : relyingParties) { + for (ContactPerson contact : rp.getContactPersons()) { + String cmail = contact.getEmail(); + // log.debug(".. try: " + cmail); + if (cmail != null + && (cmail.equals(admin) + || cmail.equals(admin + "@uw.edu") + || cmail.equals(admin + "@washington.edu"))) { + log.debug(".. adding by admin: " + rp.getEntityId()); + rps.add(rp); + break; + } } - return list; + } + } finally { + locker.readLock().unlock(); } + return rps; + } + + // write the metadata + public int writeMetadata() { + + locker.readLock().lock(); + try { + URI xUri = new URI(tempUri); + File xfile = new File(xUri); + FileWriter xstream = new FileWriter(xfile); + BufferedWriter xout = new BufferedWriter(xstream); + + // write header + xout.write(xmlStart); + xout.write(xmlNotice); + + // write rps + for (int i = 0; i < relyingParties.size(); i++) { + RelyingParty rp = relyingParties.get(i); + rp.writeXml(xout); + xout.write("\n"); + } - @Override - public List getRelyingPartiesById(String search) { - refreshMetadataIfNeeded(); - List rps = new ArrayList<>(); - search = search.toLowerCase(); - locker.readLock().lock(); - try { - for(RelyingParty rp : relyingParties){ - if (rp.getEntityId().toLowerCase().indexOf(search)>=0) rps.add(rp); - } - } - finally { - locker.readLock().unlock(); - } - return rps; + // write trailer + xout.write(xmlEnd); + xout.close(); + } catch (IOException e) { + log.error("write io error: " + e); + locker.readLock().unlock(); + return 1; + } catch (URISyntaxException e) { + log.error("bad uri error: " + e); + locker.readLock().unlock(); + return 1; + } catch (Exception e) { + log.error("write error: " + e); + locker.readLock().unlock(); + return 1; } - @Override - public List getRelyingPartiesByAdmin(String admin) { - refreshMetadataIfNeeded(); - List rps = new ArrayList<>(); - admin = admin.toLowerCase(); - locker.readLock().lock(); - try { - for (RelyingParty rp : relyingParties){ - for (ContactPerson contact: rp.getContactPersons()) { - String cmail = contact.getEmail(); - // log.debug(".. try: " + cmail); - if (cmail!=null && (cmail.equals(admin) || - cmail.equals(admin+"@uw.edu") || cmail.equals(admin+"@washington.edu"))) { - log.debug(".. adding by admin: " + rp.getEntityId()); - rps.add(rp); - break; - } - } - } - } - finally { - locker.readLock().unlock(); - } - return rps; + // move the temp file to live + try { + File live = new File(new URI(uri)); + File temp = new File(new URI(tempUri)); + temp.renameTo(live); + } catch (Exception e) { + log.info("rename: " + e); } - // write the metadata - public int writeMetadata() { + locker.readLock().unlock(); + return 0; + } - locker.readLock().lock(); - try { - URI xUri = new URI(tempUri); - File xfile = new File(xUri); - FileWriter xstream = new FileWriter(xfile); - BufferedWriter xout = new BufferedWriter(xstream); - - // write header - xout.write(xmlStart); - xout.write(xmlNotice); - - // write rps - for (int i=0; i getRelyingParties() { - return relyingParties; - } - - public void setTempUri(String v) { - tempUri = v; - } - public String getTempUri() { - return tempUri; - } - public String getXmlStart() { - return (xmlStart); - } - public String getXmlEnd() { - return (xmlEnd); - } - public String getXmlNotice() { - return (xmlNotice); - } - - public void cleanup() { - log.info("Metadata got signal to cleanup"); - if (reloader!=null) reloader.interrupt(); - } + public boolean isEditable() { + return editable; + } -} + public List getRelyingParties() { + return relyingParties; + } + public void setTempUri(String v) { + tempUri = v; + } + + public String getTempUri() { + return tempUri; + } + + public String getXmlStart() { + return (xmlStart); + } + + public String getXmlEnd() { + return (xmlEnd); + } + + public String getXmlNotice() { + return (xmlNotice); + } + + public void cleanup() { + log.info("Metadata got signal to cleanup"); + if (reloader != null) reloader.interrupt(); + } +} diff --git a/src/main/java/edu/washington/iam/registry/rp/XMLText.java b/src/main/java/edu/washington/iam/registry/rp/XMLText.java index 9b87e54..b281a51 100644 --- a/src/main/java/edu/washington/iam/registry/rp/XMLText.java +++ b/src/main/java/edu/washington/iam/registry/rp/XMLText.java @@ -2,14 +2,15 @@ public final class XMLText { - public static String xmlStart = "\n" + - "\n"; - public static String xmlEnd = ""; - public static String xmlNotice = "\n \n\n"; - + public static String xmlStart = + "\n" + + "\n"; + public static String xmlEnd = ""; + public static String xmlNotice = + "\n \n\n"; } diff --git a/src/main/java/edu/washington/iam/registry/ws/RPCrypt.java b/src/main/java/edu/washington/iam/registry/ws/RPCrypt.java index adab698..16a4836 100644 --- a/src/main/java/edu/washington/iam/registry/ws/RPCrypt.java +++ b/src/main/java/edu/washington/iam/registry/ws/RPCrypt.java @@ -19,23 +19,17 @@ package edu.washington.iam.registry.ws; +import java.security.InvalidKeyException; +import java.security.Key; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.InvalidKeyException; import java.security.NoSuchProviderException; -import javax.crypto.IllegalBlockSizeException; import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; -import java.security.Security; -import java.security.Key; -import javax.crypto.KeyGenerator; -import javax.crypto.Cipher; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Base64; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,73 +40,71 @@ public final class RPCrypt { private static Key key; private static Cipher cipher; private static Base64 b64; - private static Logger log = LoggerFactory.getLogger(RPCrypt.class); - private final static String MDAlgorithm = "MD5"; + private static Logger log = LoggerFactory.getLogger(RPCrypt.class); + private static final String MDAlgorithm = "MD5"; public static void init(String secretKey) { - cryptKey = secretKey; - b64 = new Base64(); - String key16 = secretKey + "xxxxxxxxxxxxxxxxxxxxxxx"; - try { - key = new SecretKeySpec(key16.getBytes(), 0, 16, "AES"); - cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); - messageDigest = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - log.error("no algorithm? " + e); - } catch (NoSuchProviderException e) { - log.error("no BC? " + e); - } catch (NoSuchPaddingException e) { - log.error("no BC? " + e); - } + cryptKey = secretKey; + b64 = new Base64(); + String key16 = secretKey + "xxxxxxxxxxxxxxxxxxxxxxx"; + try { + key = new SecretKeySpec(key16.getBytes(), 0, 16, "AES"); + cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); + messageDigest = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("no algorithm? " + e); + } catch (NoSuchProviderException e) { + log.error("no BC? " + e); + } catch (NoSuchPaddingException e) { + log.error("no BC? " + e); + } } public static synchronized String genMD(String in) { - messageDigest.reset(); - byte[] bt = in.getBytes(); - // messageDigest.update(bt); - String md = new String( b64.encode(messageDigest.digest(bt))); - log.debug("md of " + in + " = " + md); - messageDigest.reset(); - return (md); + messageDigest.reset(); + byte[] bt = in.getBytes(); + // messageDigest.update(bt); + String md = new String(b64.encode(messageDigest.digest(bt))); + log.debug("md of " + in + " = " + md); + messageDigest.reset(); + return (md); } public static synchronized String encode(String in) { - byte[] bt = in.getBytes(); - try { - cipher.init(Cipher.ENCRYPT_MODE, key); - String out = new String(b64.encode(cipher.doFinal(bt))); - log.debug("encode: " + in + " to " + out); - return out; - } catch (InvalidKeyException e) { - log.error("encode: " + e); - return null; - } catch (IllegalBlockSizeException e) { - log.error("encode: " + e); - return null; - } catch (BadPaddingException e) { - log.error("encode: " + e); - return null; - } + byte[] bt = in.getBytes(); + try { + cipher.init(Cipher.ENCRYPT_MODE, key); + String out = new String(b64.encode(cipher.doFinal(bt))); + log.debug("encode: " + in + " to " + out); + return out; + } catch (InvalidKeyException e) { + log.error("encode: " + e); + return null; + } catch (IllegalBlockSizeException e) { + log.error("encode: " + e); + return null; + } catch (BadPaddingException e) { + log.error("encode: " + e); + return null; + } } public static synchronized String decode(String in) { - byte[] inb = b64.decode(in); - try { - cipher.init(Cipher.DECRYPT_MODE, key); - String out = new String(cipher.doFinal(inb)); - log.debug("decode: " + in + " to " + out); - return out; - } catch (InvalidKeyException e) { - log.error("encode: " + e); - return null; - } catch (IllegalBlockSizeException e) { - log.error("encode: " + e); - return null; - } catch (BadPaddingException e) { - log.error("encode: " + e); - return null; - } + byte[] inb = b64.decode(in); + try { + cipher.init(Cipher.DECRYPT_MODE, key); + String out = new String(cipher.doFinal(inb)); + log.debug("decode: " + in + " to " + out); + return out; + } catch (InvalidKeyException e) { + log.error("encode: " + e); + return null; + } catch (IllegalBlockSizeException e) { + log.error("encode: " + e); + return null; + } catch (BadPaddingException e) { + log.error("encode: " + e); + return null; + } } - } - diff --git a/src/main/java/edu/washington/iam/registry/ws/RelyingPartyController.java b/src/main/java/edu/washington/iam/registry/ws/RelyingPartyController.java index f6cc9c2..a9bc2f9 100644 --- a/src/main/java/edu/washington/iam/registry/ws/RelyingPartyController.java +++ b/src/main/java/edu/washington/iam/registry/ws/RelyingPartyController.java @@ -17,1755 +17,1809 @@ package edu.washington.iam.registry.ws; -import java.lang.Exception; +import edu.washington.iam.registry.accessctrl.AccessCtrl; +import edu.washington.iam.registry.accessctrl.AccessCtrlManager; +import edu.washington.iam.registry.exception.*; +import edu.washington.iam.registry.filter.Attribute; +import edu.washington.iam.registry.filter.FilterPolicyGroup; +import edu.washington.iam.registry.filter.FilterPolicyManager; +import edu.washington.iam.registry.proxy.Proxy; +import edu.washington.iam.registry.proxy.ProxyManager; +import edu.washington.iam.registry.rp.HistoryItem; +import edu.washington.iam.registry.rp.RelyingParty; +import edu.washington.iam.registry.rp.RelyingPartyManager; +import edu.washington.iam.registry.rp.UuidManager; +import edu.washington.iam.tools.DNSVerifier; +import edu.washington.iam.tools.DNSVerifyException; +import edu.washington.iam.tools.Group; +import edu.washington.iam.tools.GroupManager; +import edu.washington.iam.tools.XMLHelper; +import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; -import java.io.BufferedWriter; -import java.util.*; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; - -import edu.washington.iam.registry.exception.*; - -import edu.washington.iam.registry.rp.UuidManager; +import java.util.*; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.MailException; +import org.springframework.mail.MailSender; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mobile.device.Device; +import org.springframework.mobile.device.DeviceUtils; import org.springframework.stereotype.Controller; - import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; - import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; - -import org.springframework.mail.MailException; -import org.springframework.mail.MailSender; -import org.springframework.mail.SimpleMailMessage; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.Cookie; - -import edu.washington.iam.registry.rp.RelyingParty; -import edu.washington.iam.registry.rp.RelyingPartyManager; -import edu.washington.iam.registry.rp.RelyingPartyEntry; -import edu.washington.iam.tools.XMLHelper; -import edu.washington.iam.tools.DNSVerifier; -import edu.washington.iam.tools.DNSVerifyException; -import edu.washington.iam.tools.Group; -import edu.washington.iam.tools.GroupManager; - -import edu.washington.iam.registry.filter.FilterPolicyManager; - -import edu.washington.iam.registry.filter.FilterPolicyGroup; -import edu.washington.iam.registry.filter.Attribute; - -import edu.washington.iam.registry.proxy.Proxy; - -import edu.washington.iam.registry.proxy.ProxyManager; - -import edu.washington.iam.registry.accessctrl.AccessCtrlManager; -import edu.washington.iam.registry.accessctrl.AccessCtrl; - import org.w3c.dom.Document; import org.w3c.dom.Element; - -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.DocumentBuilder; - -import java.security.cert.X509Certificate; -import java.security.cert.CertificateParsingException; - -import org.springframework.mobile.device.Device; -import org.springframework.mobile.device.DeviceUtils; - - -import edu.washington.iam.registry.rp.HistoryItem; - - @Controller public class RelyingPartyController { - private final Logger log = LoggerFactory.getLogger(getClass()); - - public static String SECURE_LOGIN_CLASS = "urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken"; - - private static FilterPolicyManager filterPolicyManager; - private static RelyingPartyManager rpManager; - private static ProxyManager proxyManager; - private static AccessCtrlManager accessCtrlManager; - private static UuidManager uuidManager; - - private static DNSVerifier dnsVerifier; - private static GroupManager groupManager; - private String adminGroupName = null; - private String auto2faPath = null; - private Group adminGroup = null; - - public DNSVerifier getDnsVerifier() { - return dnsVerifier; - } - public void setDnsVerifier(DNSVerifier v) { - dnsVerifier = v; - } - public void setGroupManager(GroupManager v) { - groupManager = v; - } - - private MailSender mailSender; - private SimpleMailMessage templateMessage; - - public void setMailSender(MailSender mailSender) { - this.mailSender = mailSender; - } - - public void setTemplateMessage(SimpleMailMessage templateMessage) { - this.templateMessage = templateMessage; - } - - private static String browserRootPath; - private static String certRootPath; - private static String loginCookie; - private static String roleCookie = "spck2"; - private static String logoutUrl; - - private static String mailTo = "u_weblogin_spreg-notify@uw.edu"; - private static String requestMailTo = "help@uw.edu"; - - // sessions - private String standardLoginPath = "/login"; - private String secureLoginPath = "/securelogin"; - private String googleLoginPath = "/googlelogin"; - private String incommonLoginPath = "/incommonlogin"; - private long standardLoginSec = 9*60*60; // 9 hour session lifetime - private long secureLoginSec = 1*60*60; // 1 hour session lifetime - private String googleIdentityProvider = "https://idp-gw.u.washington.edu/google"; //value overridden by spreg.properties - private String spRegistryUrl = "https://iam-tools.u.washington.edu/spreg/"; - - private String myEntityId = null; - private String eppnName = "eppn"; // env var name of user eppn - - // key for crypt ops - private static String cryptKey; - - class RPSession { - private String viewType; - private String remoteUser; - private String rootPath; - private String servletPath; - private String pageType; - private String pageTitle; - private long ifMatch; - private long ifNoneMatch; - private String errorCode; - private String errorText; - private boolean isBrowser; - private String xsrfCode; - private String remoteAddr; - private String loginMethod; - private boolean isAdmin; - private boolean authn2; - private boolean isUWLogin; - private String userIdProvider; - private String userDisplayName; - private ModelAndView mv; - private long timeLeft; - private boolean isProxy; - private List altNames; - private boolean adminRole; - private boolean isMobile; - } - - /* send user to login chooser page */ - private ModelAndView loginChooserMV(RPSession session, HttpServletRequest request, HttpServletResponse response) { - - String rp = ""; - if (request.getPathInfo()!=null) rp = request.getPathInfo(); - String rqs = ""; - if (request.getQueryString()!=null) rqs = "?" + request.getQueryString(); - String red = browserRootPath + request.getServletPath() + rp + rqs; - log.debug("no user yet: final path=" + red); - - String view = "browser"; - if (session.isMobile) view = "mobile"; - ModelAndView mv = new ModelAndView(view + "/chooser"); - mv.addObject("root", browserRootPath); - mv.addObject("vers", request.getServletPath()); - mv.addObject("pathextra", rp + rqs); - mv.addObject("uwloginpath", standardLoginPath); - mv.addObject("googleloginpath", googleLoginPath); - mv.addObject("incommonloginpath", incommonLoginPath); - return (mv); - } - - private RPSession processRequestInfo(HttpServletRequest request, HttpServletResponse response) { - return processRequestInfo(request, response, true); - } - - private RPSession processRequestInfo(HttpServletRequest request, HttpServletResponse response, boolean canLogin) { - RPSession session = new RPSession(); - session.isAdmin = false; - session.adminRole = false; - session.isUWLogin = false; - session.isProxy = false; - String reloginPath = null; - - log.info("RP new session =============== path=" + request.getPathInfo()); - - session.isMobile = false; - Device currentDevice = DeviceUtils.getCurrentDevice(request); - if (currentDevice!=null) session.isMobile = currentDevice.isMobile(); - log.debug("mobile? " + session.isMobile); - - // see if logged in (browser has login cookie; cert user has cert) - - int resetAdmin = 1; // on expired or no cookie, reset the 'admin role cookie' - Cookie[] cookies = request.getCookies(); - if (cookies!=null) { - for (int i=0; i0) { - if ((nSec>(cSec+secureLoginSec)) && session.authn2) { - log.debug("secure expired"); - session.authn2 = false; - resetAdmin = 2; - } - - // cookie OK - session.remoteUser = cookieData[1]; - session.xsrfCode = cookieData[2]; - log.debug("login for " + session.remoteUser ); - if (session.authn2) log.debug("secure login"); - if (adminGroup.isMember(session.remoteUser)) { - log.debug("is admin"); - session.isAdmin = true; - } - - if (resetAdmin==1) resetAdmin = 0; - } else { - log.debug("cookie expired for " + cookieData[1]); - // remember where they logged in last - if (session.isUWLogin) reloginPath = browserRootPath + request.getServletPath() + standardLoginPath; - else if (cookieData[1].indexOf("gmail.com")>0) reloginPath = browserRootPath + request.getServletPath() + googleLoginPath; - // let others choose - } - } - } else if (cookies[i].getName().equals(roleCookie) && cookies[i].getValue().equals("a")) { - log.debug("got role=admin cookie"); - session.adminRole = true; - } - } - } - - if (resetAdmin>0) { - log.debug("clearing expired admn request"); - session.adminRole = false; - Cookie c = new Cookie(roleCookie, "x"); - c.setSecure(true); - c.setPath("/"); - response.addCookie(c); - } - - if (session.remoteUser!=null) { - // ok, is a logged in browser - session.viewType = "browser"; - session.isBrowser = true; - session.rootPath = browserRootPath; - - } else { - // maybe is cert client - // use the CN portion of the DN as the client userid - X509Certificate[] certs = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate"); - if (certs != null) { - session.viewType = "xml"; - session.isBrowser = false; - session.rootPath = certRootPath; - X509Certificate cert = certs[0]; - String dn = cert.getSubjectX500Principal().getName(); - session.remoteUser = dn.replaceAll(".*CN=", "").replaceAll(",.*",""); - log.info(".. remote user by cert, dn=" + dn + ", cn=" + session.remoteUser); - session.altNames = new Vector(); - try { - Collection altNames = cert.getSubjectAlternativeNames(); - if (altNames!=null) { - for (Iterator i = altNames.iterator(); i.hasNext(); ) { - List item = (List)i.next(); - Integer type = (Integer)item.get(0); - if (type.intValue() == 2) { - String altName = (String)item.get(1); - log.info(".. adding altname " + altName); - session.altNames.add(altName); - } - } - } else session.altNames.add(session.remoteUser); // rules say cn meaningful only when altnames not present - } catch (CertificateParsingException e) { - log.info(".. altname parse failed: " + e); - } - } - - } - - /* send missing remoteUser to login */ - - if (session.remoteUser==null) { - if (canLogin) { - if (reloginPath!=null) { - log.debug("no user yet: relogin at " + reloginPath); - try { - response.sendRedirect(reloginPath); - } catch (IOException e) { - log.error("redirect: " + e); - } + private final Logger log = LoggerFactory.getLogger(getClass()); + + public static String SECURE_LOGIN_CLASS = "urn:oasis:names:tc:SAML:2.0:ac:classes:TimeSyncToken"; + + private static FilterPolicyManager filterPolicyManager; + private static RelyingPartyManager rpManager; + private static ProxyManager proxyManager; + private static AccessCtrlManager accessCtrlManager; + private static UuidManager uuidManager; + + private static DNSVerifier dnsVerifier; + private static GroupManager groupManager; + private String adminGroupName = null; + private String auto2faPath = null; + private Group adminGroup = null; + + public DNSVerifier getDnsVerifier() { + return dnsVerifier; + } + + public void setDnsVerifier(DNSVerifier v) { + dnsVerifier = v; + } + + public void setGroupManager(GroupManager v) { + groupManager = v; + } + + private MailSender mailSender; + private SimpleMailMessage templateMessage; + + public void setMailSender(MailSender mailSender) { + this.mailSender = mailSender; + } + + public void setTemplateMessage(SimpleMailMessage templateMessage) { + this.templateMessage = templateMessage; + } + + private static String browserRootPath; + private static String certRootPath; + private static String loginCookie; + private static String roleCookie = "spck2"; + private static String logoutUrl; + + private static String mailTo = "u_weblogin_spreg-notify@uw.edu"; + private static String requestMailTo = "help@uw.edu"; + + // sessions + private String standardLoginPath = "/login"; + private String secureLoginPath = "/securelogin"; + private String googleLoginPath = "/googlelogin"; + private String incommonLoginPath = "/incommonlogin"; + private long standardLoginSec = 9 * 60 * 60; // 9 hour session lifetime + private long secureLoginSec = 1 * 60 * 60; // 1 hour session lifetime + private String googleIdentityProvider = + "https://idp-gw.u.washington.edu/google"; // value overridden by spreg.properties + private String spRegistryUrl = "https://iam-tools.u.washington.edu/spreg/"; + + private String myEntityId = null; + private String eppnName = "eppn"; // env var name of user eppn + + // key for crypt ops + private static String cryptKey; + + class RPSession { + private String viewType; + private String remoteUser; + private String rootPath; + private String servletPath; + private String pageType; + private String pageTitle; + private long ifMatch; + private long ifNoneMatch; + private String errorCode; + private String errorText; + private boolean isBrowser; + private String xsrfCode; + private String remoteAddr; + private String loginMethod; + private boolean isAdmin; + private boolean authn2; + private boolean isUWLogin; + private String userIdProvider; + private String userDisplayName; + private ModelAndView mv; + private long timeLeft; + private boolean isProxy; + private List altNames; + private boolean adminRole; + private boolean isMobile; + } + + /* send user to login chooser page */ + private ModelAndView loginChooserMV( + RPSession session, HttpServletRequest request, HttpServletResponse response) { + + String rp = ""; + if (request.getPathInfo() != null) rp = request.getPathInfo(); + String rqs = ""; + if (request.getQueryString() != null) rqs = "?" + request.getQueryString(); + String red = browserRootPath + request.getServletPath() + rp + rqs; + log.debug("no user yet: final path=" + red); + + String view = "browser"; + if (session.isMobile) view = "mobile"; + ModelAndView mv = new ModelAndView(view + "/chooser"); + mv.addObject("root", browserRootPath); + mv.addObject("vers", request.getServletPath()); + mv.addObject("pathextra", rp + rqs); + mv.addObject("uwloginpath", standardLoginPath); + mv.addObject("googleloginpath", googleLoginPath); + mv.addObject("incommonloginpath", incommonLoginPath); + return (mv); + } + + private RPSession processRequestInfo(HttpServletRequest request, HttpServletResponse response) { + return processRequestInfo(request, response, true); + } + + private RPSession processRequestInfo( + HttpServletRequest request, HttpServletResponse response, boolean canLogin) { + RPSession session = new RPSession(); + session.isAdmin = false; + session.adminRole = false; + session.isUWLogin = false; + session.isProxy = false; + String reloginPath = null; + + log.info("RP new session =============== path=" + request.getPathInfo()); + + session.isMobile = false; + Device currentDevice = DeviceUtils.getCurrentDevice(request); + if (currentDevice != null) session.isMobile = currentDevice.isMobile(); + log.debug("mobile? " + session.isMobile); + + // see if logged in (browser has login cookie; cert user has cert) + + int resetAdmin = 1; // on expired or no cookie, reset the 'admin role cookie' + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) { + if (cookies[i].getName().equals(loginCookie)) { + log.debug("got cookie " + cookies[i].getName()); + String cookieStr = RPCrypt.decode(cookies[i].getValue()); + if (cookieStr == null) continue; + String[] cookieData = cookieStr.split(";"); + if (cookieData.length == 5) { + + if (cookieData[3].charAt(0) == '2') session.authn2 = true; + + log.debug("login time = " + cookieData[4]); + long cSec = new Long(cookieData[4]); + long nSec = new Date().getTime() / 1000; + if (cookieData[1].indexOf("@") < 0) + session.isUWLogin = true; // klugey way to know UW people + session.timeLeft = (cSec + standardLoginSec) - nSec; + if (session.timeLeft > 0) { + if ((nSec > (cSec + secureLoginSec)) && session.authn2) { + log.debug("secure expired"); + session.authn2 = false; + resetAdmin = 2; } - log.debug("no user yet: send to choose"); - session.mv = loginChooserMV(session, request, response); - return session; - } - return null; - } - - // only admins can get admin role - if (!session.isAdmin) session.adminRole = false; - if (session.adminRole && !session.authn2) { // admin needs 2f - log.debug("need secure login for admin role"); - sendToLogin(request, response, secureLoginPath); - } - session.servletPath = request.getServletPath(); - session.remoteAddr = request.getRemoteAddr(); - - // etag headers - session.ifMatch = getLongHeader(request, "If-Match"); - session.ifNoneMatch = getLongHeader(request, "If-None-Match"); - log.info("tags: match=" + session.ifMatch + ", nonematch=" + session.ifNoneMatch); - - response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max_age=1"); - response.setHeader("X-UA-Compatible", "IE=7"); - - log.info("user: " + session.remoteUser); - if (session.viewType.equals("browser") && session.isMobile) session.viewType = "mobile"; - return session; - } - - private String fixPathName(String start, HttpServletRequest request) { - String path = request.getPathInfo(); - // log.debug("full path = " + path); - path = path.substring(start.length()); - // log.debug("trunc path = " + path); - int slash = path.indexOf("/"); - if (slash>0) path = path.substring(0, slash); - // log.debug("fixed path = " + path); - return path; - } - - /* send user to login page */ - private void sendToLogin(HttpServletRequest request, HttpServletResponse response, String loginPath) { - - // delete any existing sessions first - Cookie[] cookies = request.getCookies(); - if (cookies!=null) { - for (int i=0; i google - * method = 1 -> incommon shib - * method = 2 -> 2-factor uw shib - */ - - private ModelAndView loginPage(HttpServletRequest request, HttpServletResponse response, int method) { - String remoteUser = request.getRemoteUser(); - //String remoteUser = "mattjm@washington.edu"; //netid@washington.edu goes here for testing locally - log.debug("social login attempt, shib remoteUser value: " + remoteUser); - if (method==0) { // social login - String idp = (String)request.getAttribute("Shib-Identity-Provider"); - String mail = (String)request.getAttribute("mail"); - log.info("social login from " + idp + ", email = " + mail); - log.debug("hardwired idp we expect is: " + googleIdentityProvider); - if (idp.equals(googleIdentityProvider)) { - remoteUser = mail; - } else { - log.debug("invalid social login"); - return emptyMV("invalid social login"); - } - } - - String methodKey = "P"; - if (method==2) methodKey = "2"; - String aclass = (String)request.getAttribute("Shib-AuthnContext-Class"); - if (aclass!=null && aclass.equals(SECURE_LOGIN_CLASS)) methodKey = "2"; - log.debug("method = " + method + ", key = " + methodKey); - - if (remoteUser!=null) { - if (remoteUser.endsWith("@washington.edu")) { - remoteUser = remoteUser.substring(0, remoteUser.lastIndexOf("@washington.edu")); - log.info("dropped @washington.edu to get id = " + remoteUser); - } - - if (remoteUser.endsWith("@uw.edu")) { - // no longer allow google's @uw to be same as UW login - // remoteUser = remoteUser.substring(0, remoteUser.lastIndexOf("@uw.edu")); - // log.info("dropped @uw.edu to get id = " + remoteUser); - ////return loginChooserMV(session, request, response); // return to login chooser - // until we can report some misuse - return emptyMV("invalid social login"); - } - - double dbl = Math.random(); - long modtime = new Date().getTime(); // milliseconds - log.debug("login: ck = ...;" + remoteUser + ";" + dbl + ";" + methodKey + ";" + modtime/1000); - String enc = RPCrypt.encode(Double.toString(modtime)+ ";" + remoteUser + ";" + dbl + ";" + methodKey + ";" + modtime/1000); - log.debug("login: enc = " + enc); - Cookie c = new Cookie(loginCookie, enc); - c.setSecure(true); - c.setPath("/"); - response.addCookie(c); - try { - String rp = request.getPathInfo(); - int sp = rp.indexOf("/", 2); - log.debug("in path = " + rp); - String red = browserRootPath + request.getServletPath(); - if (sp>1) red = red + rp.substring(sp); - if (request.getQueryString()!=null) red = red + "?" + request.getQueryString(); - log.debug("logon ok, return to " + red); - response.sendRedirect(red); - } catch (IOException e) { - log.error("redirect: " + e); - return emptyMV("redirect error"); - } - } else { - // send login failed message - ModelAndView mv = new ModelAndView("browser/nologin"); - mv.addObject("root", browserRootPath); - mv.addObject("vers", request.getServletPath()); - mv.addObject("pageTitle", "login failed"); - mv.addObject("myEntityId", myEntityId); - return mv; - } - return emptyMV(); - } - - @RequestMapping(value="/login/**", method=RequestMethod.GET) - public ModelAndView basicLoginPage(HttpServletRequest request, HttpServletResponse response) { - return loginPage(request, response, 1); - } - - @RequestMapping(value="/securelogin/**", method=RequestMethod.GET) - public ModelAndView secureLoginPage(HttpServletRequest request, HttpServletResponse response) { - return loginPage(request, response, 2); - } - - @RequestMapping(value="/googlelogin/**", method=RequestMethod.GET) - public ModelAndView googleLoginPage(HttpServletRequest request, HttpServletResponse response) { - log.debug("hitting /googlelogin/** endpoint now"); - return loginPage(request, response, 0); - } - - @RequestMapping(value="/incommonlogin/**", method=RequestMethod.GET) - public ModelAndView incommonLoginPage(HttpServletRequest request, HttpServletResponse response) { - return loginPage(request, response, 1); - } - - /* - * Process logoutt page - * Clear cookies, redirect to shib logout - */ - - @RequestMapping(value="/logout/**", method=RequestMethod.GET) - public ModelAndView logoutPage(HttpServletRequest request, HttpServletResponse response) { - // clear cookies - Cookie[] cookies = request.getCookies(); - if (cookies!=null) { - for (int i=0; i relyingPartyIds = rpManager.getRelyingParties(selRp, selMine==null?null:session.remoteUser); - // List relyingPartyIds = rpManager.getRelyingParties(); - log.info("found " + relyingPartyIds.size() + " rps" ); - - ModelAndView mv = basicModelAndView(session, "json", "rps"); - // mv.addObject("selectrp", selRp==null?"":selRp); - // mv.addObject("selecttype", selType==null?"all":selType); - mv.addObject("relyingParties", relyingPartyIds); - - return (mv); - } - - // specific party - @RequestMapping(value="/rp", method=RequestMethod.GET) - public ModelAndView getRelyingParty(@RequestParam(value="id", required=true) String id, - @RequestParam(value="mdid", required=true) String mdid, - @RequestParam(value="view", required=false) String view, - @RequestParam(value="dns", required=false) String dns, - @RequestParam(value="role", required=false) String role, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response); - if (session==null) return (emptyMV()); - if (session.mv!=null) return (session.mv); - - session.pageType = "rp"; - session.pageTitle = "Service provider"; - - RelyingParty rp = null; - RelyingParty rrp = null; - - List relyingPartyEntries = null; //list of all RP entries from the database - List proxyHistory = null; - - try { - relyingPartyEntries = rpManager.getRelyingPartyHistoryById(id); - } catch (RelyingPartyException e) { - log.debug("Exception occurred getting metadata history"); - return emptyMV("SP not found"); - } - try { - proxyHistory = proxyManager.getProxyHistory(id); - - } catch (ProxyException e){ - log.debug("Exception occurred getting proxy history"); - } - - - List rpHistory = new LinkedList(); //list of parsed history items - if (relyingPartyEntries.size() > 1) { - int i = 0; - while (i < relyingPartyEntries.size() - 1) { - HistoryItem item = relyingPartyEntries.get(i).RpCompare(relyingPartyEntries.get(i + 1)); - //little bit of a hack to not add an "empty" item if we didn't parse out changes properly - if (item.getNumberOfChanges() != 0) { - rpHistory.add(item); - } - i++; - } - } - - - - - - - - - - - - boolean canEdit = false; - - String errmsg = null; - - ModelAndView mv = basicModelAndView(session, "browser", "rp"); - - try { - rp = rpManager.getRelyingPartyById(id, mdid); - } catch (RelyingPartyException e) { - return emptyMV("not found"); - } - session.pageTitle = rp.getEntityId(); - try { - if (userCanEdit(session, id)) { - log.debug("user can edit"); - canEdit = true; - } - } catch (DNSVerifyException e) { - mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); - response.setStatus(500); - return mv; - } - - - - log.info("returning rp id=" + id ); - List filterPolicyGroups = filterPolicyManager.getFilterPolicyGroups(); - List attributes = filterPolicyManager.getAttributes(rp); - - Proxy proxy = proxyManager.getProxy(id); - AccessCtrl accessCtrl = accessCtrlManager.getAccessCtrl(id); - - mv.addObject("canEdit", canEdit); - mv.addObject("relyingParty", rp); - mv.addObject("filterPolicyGroups", filterPolicyGroups); - mv.addObject("filterPolicyManager", filterPolicyManager); - mv.addObject("attributes", attributes); - mv.addObject("relyingPartyId", id); - mv.addObject("proxy", proxy); - mv.addObject("accessCtrl", accessCtrl); - mv.addObject("rpHistory", rpHistory); - //mv.addObject("proxyHistory", proxyHistory); - mv.addObject("isAdmin", session.isAdmin); - mv.addObject("isProxy", session.isProxy); - mv.addObject("dateFormatter", new SimpleDateFormat("yy/MM/dd")); - return (mv); - } - - // rp's metadata (API endpoint) - @RequestMapping(value="/ws/metadata", method=RequestMethod.GET) - public ModelAndView getRelyingParty(@RequestParam(value="id", required=true) String id, - @RequestParam(value="mdid", required=true) String mdid, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response); - if (session==null) return (emptyMV()); - if (session.mv!=null) return (session.mv); - - session.pageType = "metadata"; - session.pageTitle = "Service provider"; - - RelyingParty rp = null; - - String errmsg = null; - - ModelAndView mv = basicModelAndView(session, "xml", "metadata"); - - try { - rp = rpManager.getRelyingPartyById(id, mdid); - } catch (RelyingPartyException e) { - response.setStatus(404); - return emptyMV("not found"); - } - log.info("returning metadata id=" + id ); - try { - StringWriter writer = new StringWriter(); - BufferedWriter xout = new BufferedWriter(writer); - rp.writeXml(xout); - xout.close(); - mv.addObject("metadata", writer.toString()); - } catch (IOException e) { - log.error("string writer errro: " + e); - response.setStatus(500); - return emptyMV("internal error"); - } - - return (mv); - } - - - // new rp - @RequestMapping(value="/new", method=RequestMethod.GET) - public ModelAndView getRelyingPartyNew(@RequestParam(value="rpid", required=true) String rpid, - @RequestParam(value="mdid", required=false) String mdid, - @RequestParam(value="view", required=false) String view, - @RequestParam(value="role", required=false) String role, - @RequestParam(value="lookup", required=false) String lookup, // enter manual data for this entity - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response); - if (session==null) return (emptyMV()); - if (session.mv!=null) return (session.mv); - - session.pageType = "rp"; - session.pageTitle = "New service provider"; - if (lookup!=null) lookup = java.net.URLDecoder.decode(lookup); - - String dns = dnsFromEntityId(rpid); - - if (dns.length()==0) return (emptyMV()); - RelyingParty rp = null; - boolean canEdit = true; - String errmsg = null; - ModelAndView mv = basicModelAndView(session, "browser", "rp"); + // cookie OK + session.remoteUser = cookieData[1]; + session.xsrfCode = cookieData[2]; + log.debug("login for " + session.remoteUser); + if (session.authn2) log.debug("secure login"); + if (adminGroup.isMember(session.remoteUser)) { + log.debug("is admin"); + session.isAdmin = true; + } - // check access - try { - if (userCanEdit(session, dns)) { - log.debug("user owns dns"); + if (resetAdmin == 1) resetAdmin = 0; } else { - // response.setStatus(200); // 403 - return emptyMV("No permission for " + rpid); + log.debug("cookie expired for " + cookieData[1]); + // remember where they logged in last + if (session.isUWLogin) + reloginPath = browserRootPath + request.getServletPath() + standardLoginPath; + else if (cookieData[1].indexOf("gmail.com") > 0) + reloginPath = browserRootPath + request.getServletPath() + googleLoginPath; + // let others choose } - } catch (DNSVerifyException e) { - // mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); - // response.setStatus(500); - return emptyMV("Could not verify ownership:\n" + e.getCause()); + } + } else if (cookies[i].getName().equals(roleCookie) && cookies[i].getValue().equals("a")) { + log.debug("got role=admin cookie"); + session.adminRole = true; } - - // check that it doesn't already exist + } + } + + if (resetAdmin > 0) { + log.debug("clearing expired admn request"); + session.adminRole = false; + Cookie c = new Cookie(roleCookie, "x"); + c.setSecure(true); + c.setPath("/"); + response.addCookie(c); + } + + if (session.remoteUser != null) { + // ok, is a logged in browser + session.viewType = "browser"; + session.isBrowser = true; + session.rootPath = browserRootPath; + + } else { + // maybe is cert client + // use the CN portion of the DN as the client userid + X509Certificate[] certs = + (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate"); + if (certs != null) { + session.viewType = "xml"; + session.isBrowser = false; + session.rootPath = certRootPath; + X509Certificate cert = certs[0]; + String dn = cert.getSubjectX500Principal().getName(); + session.remoteUser = dn.replaceAll(".*CN=", "").replaceAll(",.*", ""); + log.info(".. remote user by cert, dn=" + dn + ", cn=" + session.remoteUser); + session.altNames = new Vector(); try { - rpManager.getRelyingPartyById(rpid, "UW"); - log.debug("wants new, but already exists"); - return emptyMV("Entity " + rpid + " already exists in the UW federation metadata"); - } catch (RelyingPartyException e) { - log.debug("really new"); - } - - mv.addObject("newEntity", true); - - if (lookup!=null) { - mv.addObject("newByLookup", true); - try { - if (lookup.equals("sp")) lookup = "https://" + hostPortFromEntityId(rpid) + "/Shibboleth.sso/Metadata"; - log.debug("SP by lookup: " + lookup); - rp = rpManager.genRelyingPartyByLookup(lookup); - if (rp!=null) log.debug("rp: " + rp.getEntityId()); - try { - RelyingParty orp = rpManager.getRelyingPartyById(rp.getEntityId(), "UW"); - if (orp!=null) rp = orp; - } - catch (RelyingPartyException e){ - log.debug("rp doesn't already exist in our metadata"); + Collection altNames = cert.getSubjectAlternativeNames(); + if (altNames != null) { + for (Iterator i = altNames.iterator(); i.hasNext(); ) { + List item = (List) i.next(); + Integer type = (Integer) item.get(0); + if (type.intValue() == 2) { + String altName = (String) item.get(1); + log.info(".. adding altname " + altName); + session.altNames.add(altName); } - - if(!hostPortFromEntityId(rpid).equals(hostPortFromEntityId(rp.getEntityId()))){ - log.info(String.format("requested dns '%s' not equal to fetched entityId '%s'", - hostPortFromEntityId(rpid), rp.getEntityId())); - return emptyMV(String.format("The requested entity id's domain name, '%s', does not match the fetched name: '%s'", - hostPortFromEntityId(rpid), rp.getEntityId())); - } - - mv.addObject("relyingParty", rp); - mv.addObject("relyingPartyId", rp.getEntityId()); - session.pageTitle = rp.getEntityId(); - } catch (RelyingPartyException e) { - mv.addObject("rpnotfound", true); - log.debug("metadata not found for " + dns); - log.debug(e.getMessage()); - } - } - if (rp==null) { - if (lookup!=null) return emptyMV("URL did not respond with metadata"); - rp = rpManager.genRelyingPartyByName(rpid, dns); - mv.addObject("relyingParty", rp); - mv.addObject("relyingPartyId", rpid); - session.pageTitle = rpid; - } - - List filterPolicyGroups = filterPolicyManager.getFilterPolicyGroups(); - List attributes = filterPolicyManager.getAttributes(rp); - mv.addObject("filterPolicyGroups", filterPolicyGroups); - mv.addObject("filterPolicyManager", filterPolicyManager); - return (mv); - } - - // update an rp metadata - @RequestMapping(value="/rp", method=RequestMethod.PUT) - public ModelAndView putRelyingParty(@RequestParam(value="id", required=true) String id, - @RequestParam(value="mdid", required=true) String mdid, - @RequestParam(value="role", required=false) String role, - @RequestParam(value="xsrf", required=false) String paramXsrf, - InputStream in, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response, false); - if (session==null) return (emptyMV()); - - log.info("PUT update for: " + id); - int status = 200; - - if (session.isBrowser && !(paramXsrf!=null && paramXsrf.equals(session.xsrfCode))) { - log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); - return emptyMV("invalid session (xsrf)"); - } - - ModelAndView mv = emptyMV("OK dokey"); - - try { - if (!userCanEdit(session, id)) { - status = 401; - mv.addObject("alert", "You are not an owner of that entity."); - response.setStatus(status); - return mv; } - } catch (DNSVerifyException e) { - mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); - response.setStatus(500); - return mv; - } - - // if new, check for URL entityid - try { - rpManager.getRelyingPartyById(id, mdid); - } catch (RelyingPartyException e) { - if (!isProperEntityId(session, id)) { - log.info("improper entity id"); - status = 400; - mv.addObject("alert", "The posted entityid was not a URL\n"); - response.setStatus(status); - return mv; - } - } - - RelyingParty relyingParty = null; - try { - Document doc = null; - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - //In parser we trust. (no server side input validation on XML payload) - doc = builder.parse(in); - relyingParty = new RelyingParty(doc.getDocumentElement(), mdid, rpManager.isMetadataEditable(mdid)); - } catch (Exception e) { - log.info("parse error: " + e); - status = 400; - mv.addObject("alert", e.getMessage()); - response.setStatus(status); - return mv; - } - - if (!relyingParty.getEntityId().equals(id)) { - log.info("entity id mismatch"); - status = 400; - mv.addObject("alert", "The posted entityid did not match the request\n"); - response.setStatus(status); - return mv; + } else + session.altNames.add( + session.remoteUser); // rules say cn meaningful only when altnames not present + } catch (CertificateParsingException e) { + log.info(".. altname parse failed: " + e); } - - try { - status = rpManager.updateRelyingParty(relyingParty, mdid, session.remoteUser); - } catch (RelyingPartyException e) { - status = 400; - mv.addObject("alert", e.getMessage()); - response.setStatus(status); - return mv; - } - - SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); - msg.setTo(mailTo); - String act = "updated"; - if (status==201) act = "created"; - else if (status>=400) act = "attempted edit of"; - msg.setSubject("Service provider metadata " + act + " by " + session.remoteUser); - msg.setText( "User '" + session.remoteUser + "' " + act + " metadata for '" + id + "'.\nRequest status: " + status + - "\n\nThis message is advisory. No response is indicated."); - try{ - this.mailSender.send(msg); - } catch(MailException ex) { - log.error("sending mail: " + ex.getMessage()); - } - - response.setStatus(status); - return mv; + } } + /* send missing remoteUser to login */ - // API update an rp metadata - @RequestMapping(value="/ws/metadata", method=RequestMethod.PUT) - public ModelAndView putRelyingParty(@RequestParam(value="id", required=true) String id, - @RequestParam(value="mdid", required=true) String mdid, - InputStream in, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response, false); - if (session==null) return (emptyMV()); - log.info("API PUT update for: " + id); - int status = 403; - - ModelAndView mv = basicModelAndView(session, "xml", "empty"); - - String dns = dnsFromEntityId(id); - for (String alt : (List) session.altNames) { - if (dns.equals(alt) || (alt.startsWith("*.") && dns.endsWith(alt.substring(1))) ) { - log.info("dns match found for " + dns); - status = 200; - break; - } - } - if (status==403) { - mv.addObject("alert", "You are not an owner of that entity."); - response.setStatus(status); - return mv; - } - if (!rpManager.isMetadataEditable(mdid)) { - status = 400; - mv.addObject("alert", "The metadata was not found or is not editable"); - response.setStatus(status); - return mv; - } - - // if new, check for URL entityid - try { - rpManager.getRelyingPartyById(id, mdid); - } catch (RelyingPartyException e) { - if (!isProperEntityId(session, id)) { - log.info("improper entity id"); - status = 400; - mv.addObject("alert", "The posted entityid was not a URL\n"); - response.setStatus(status); - return mv; - } - } - - RelyingParty rp = null; - try { - Document doc = null; - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - doc = builder.parse (in); - rp = new RelyingParty(doc.getDocumentElement(), mdid, rpManager.isMetadataEditable(mdid)); - } catch (Exception e) { - log.info("parse error: " + e); - status = 400; - mv.addObject("alert", e.getMessage()); - response.setStatus(status); - return mv; - } - if(rp.getEntityId().equals(id)){ - try { - rpManager.updateRelyingParty(rp, mdid, session.remoteUser); - } catch (RelyingPartyException e) { - status = 400; - mv.addObject("alert", "Update of the metadata failed:\n" + e.getMessage()); - } - } - else{ - mv.addObject("alert", String.format("Id %s doesn't match %s", - rp.getEntityId(), id)); + if (session.remoteUser == null) { + if (canLogin) { + if (reloginPath != null) { + log.debug("no user yet: relogin at " + reloginPath); + try { + response.sendRedirect(reloginPath); + } catch (IOException e) { + log.error("redirect: " + e); + } } - - SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); - msg.setTo(mailTo); - String act = "updated"; - if (status==201) act = "created"; - else if (status>=400) act = "attempted edit of"; - msg.setSubject("Service provider metadata " + act + " by " + session.remoteUser); - msg.setText( "User '" + session.remoteUser + "' " + act + " metadata for '" + id + "'.\nRequest status: " + status + - "\n\nThis message is advisory. No response is indicated."); - try{ - this.mailSender.send(msg); - } catch(MailException ex) { - log.error("sending mail: " + ex.getMessage()); + log.debug("no user yet: send to choose"); + session.mv = loginChooserMV(session, request, response); + return session; + } + return null; + } + + // only admins can get admin role + if (!session.isAdmin) session.adminRole = false; + if (session.adminRole && !session.authn2) { // admin needs 2f + log.debug("need secure login for admin role"); + sendToLogin(request, response, secureLoginPath); + } + session.servletPath = request.getServletPath(); + session.remoteAddr = request.getRemoteAddr(); + + // etag headers + session.ifMatch = getLongHeader(request, "If-Match"); + session.ifNoneMatch = getLongHeader(request, "If-None-Match"); + log.info("tags: match=" + session.ifMatch + ", nonematch=" + session.ifNoneMatch); + + response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max_age=1"); + response.setHeader("X-UA-Compatible", "IE=7"); + + log.info("user: " + session.remoteUser); + if (session.viewType.equals("browser") && session.isMobile) session.viewType = "mobile"; + return session; + } + + private String fixPathName(String start, HttpServletRequest request) { + String path = request.getPathInfo(); + // log.debug("full path = " + path); + path = path.substring(start.length()); + // log.debug("trunc path = " + path); + int slash = path.indexOf("/"); + if (slash > 0) path = path.substring(0, slash); + // log.debug("fixed path = " + path); + return path; + } + + /* send user to login page */ + private void sendToLogin( + HttpServletRequest request, HttpServletResponse response, String loginPath) { + + // delete any existing sessions first + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) { + if (cookies[i].getName().startsWith("_shib")) { + log.debug("clearing cookie " + cookies[i].getName()); + Cookie c = new Cookie(cookies[i].getName(), ""); + c.setSecure(true); + c.setPath("/"); + c.setMaxAge(0); + response.addCookie(c); } - - response.setStatus(status); - return mv; - } - - // delete an rp - @RequestMapping(value="/rp", method=RequestMethod.DELETE) - public ModelAndView deleteRelyingParty(@RequestParam(value="id", required=true) String id, - @RequestParam(value="mdid", required=true) String mdid, - @RequestParam(value="role", required=false) String role, - @RequestParam(value="xsrf", required=false) String paramXsrf, - InputStream in, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response, false); - if (session==null) return (emptyMV()); - - log.info("DELETE for: " + id); - int status = 200; - - if (session.isBrowser && !(paramXsrf!=null && paramXsrf.equals(session.xsrfCode))) { - log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); - return emptyMV("invalid session (xsrf)"); - } - - ModelAndView mv = emptyMV("OK dokey delete rp"); - - try { - if (!userCanEdit(session, id)) { - status = 401; - mv.addObject("alert", "You are not the owner."); - } else { - /* If there is NOT an incommon uuid we can delete these. If there is one we need to keep them. - * Otherwise attributes/proxy/access control for InCommon SP get clobbered when we delete - * the UW SP*/ - if(!uuidManager.hasIncUuid(id)) { - status = accessCtrlManager.removeAccessCtrl(id, session.remoteUser); - status = proxyManager.removeProxy(id, session.remoteUser); - status = filterPolicyManager.removeEditableRelyingParty(id, session.remoteUser); - } - status = rpManager.removeRelyingParty(id, mdid, session.remoteUser); - } - } catch (FilterPolicyException e) { - mv.addObject("alert", "(while attempting rp delete) delete of filter policy failed:\n" + e.getCause()); - response.setStatus(500); - return mv; - } catch (DNSVerifyException e) { - mv.addObject("alert", "(while attempting rp delete) Could not verify ownership:\n" + e.getCause()); - response.setStatus(500); - return mv; - } catch (ProxyException e) { - mv.addObject("alert", "(while attempting rp delete) Proxy (gateway) error:\n" + e.getCause()); - response.setStatus(500); - return mv; - } catch (AccessCtrlException e) { - mv.addObject("alert", "(while attempting rp delete) Access control error:\n" + e.getCause()); - response.setStatus(500); - return mv; + } + } + + String rp = ""; + if (request.getPathInfo() != null) rp = request.getPathInfo(); + String rqs = ""; + if (request.getQueryString() != null) rqs = "?" + request.getQueryString(); + String red = browserRootPath + request.getServletPath() + loginPath + rp + rqs; + log.debug("no user yet: redirect for login to " + red); + try { + response.sendRedirect(red); + } catch (IOException e) { + log.error("redirect: " + e); + } + } + + // create basic model and view + private ModelAndView basicModelAndView(RPSession session, String view, String basePage) { + ModelAndView mv = new ModelAndView(view + "/" + basePage); + mv.addObject("XMLHelper", XMLHelper.class); + mv.addObject("remote_user", session.remoteUser); + mv.addObject("root", session.rootPath); + mv.addObject("vers", session.servletPath); + if (session.pageType != null) mv.addObject("pageType", view + "/" + session.pageType); + mv.addObject("pageTitle", session.pageTitle); + mv.addObject("xsrf", session.xsrfCode); + mv.addObject("timeLeft", session.timeLeft); + mv.addObject("adminRole", session.adminRole); + return mv; + } + + private ModelAndView basicModelAndView(RPSession session) { + return (basicModelAndView(session, session.viewType, "page")); + } + + private ModelAndView basicModelAndView(RPSession session, String view) { + return (basicModelAndView(session, view, "page")); + } + + // create 'empty' model and view + private ModelAndView emptyMV(String message, String alert) { + ModelAndView mv = new ModelAndView("empty"); + if (message != null) mv.addObject("msg", message); + if (message != null) mv.addObject("alert", alert); + return mv; + } + + private ModelAndView emptyMV(String msg) { + return emptyMV(msg, null); + } + + private ModelAndView emptyMV() { + return emptyMV("session error"); + } + + /* + * Process login page. + * Set a cookie and redirect back to original request + * Encode remoteuser, method and time into the login cookie + * + * method = 0 -> google + * method = 1 -> incommon shib + * method = 2 -> 2-factor uw shib + */ + + private ModelAndView loginPage( + HttpServletRequest request, HttpServletResponse response, int method) { + String remoteUser = request.getRemoteUser(); + // String remoteUser = "mattjm@washington.edu"; //netid@washington.edu goes here for testing + // locally + log.debug("social login attempt, shib remoteUser value: " + remoteUser); + if (method == 0) { // social login + String idp = (String) request.getAttribute("Shib-Identity-Provider"); + String mail = (String) request.getAttribute("mail"); + log.info("social login from " + idp + ", email = " + mail); + log.debug("hardwired idp we expect is: " + googleIdentityProvider); + if (idp.equals(googleIdentityProvider)) { + remoteUser = mail; + } else { + log.debug("invalid social login"); + return emptyMV("invalid social login"); + } + } + + String methodKey = "P"; + if (method == 2) methodKey = "2"; + String aclass = (String) request.getAttribute("Shib-AuthnContext-Class"); + if (aclass != null && aclass.equals(SECURE_LOGIN_CLASS)) methodKey = "2"; + log.debug("method = " + method + ", key = " + methodKey); + + if (remoteUser != null) { + if (remoteUser.endsWith("@washington.edu")) { + remoteUser = remoteUser.substring(0, remoteUser.lastIndexOf("@washington.edu")); + log.info("dropped @washington.edu to get id = " + remoteUser); + } + + if (remoteUser.endsWith("@uw.edu")) { + // no longer allow google's @uw to be same as UW login + // remoteUser = remoteUser.substring(0, remoteUser.lastIndexOf("@uw.edu")); + // log.info("dropped @uw.edu to get id = " + remoteUser); + //// return loginChooserMV(session, request, response); // return to login chooser + // until we can report some misuse + return emptyMV("invalid social login"); + } + + double dbl = Math.random(); + long modtime = new Date().getTime(); // milliseconds + log.debug( + "login: ck = ...;" + remoteUser + ";" + dbl + ";" + methodKey + ";" + modtime / 1000); + String enc = + RPCrypt.encode( + Double.toString(modtime) + + ";" + + remoteUser + + ";" + + dbl + + ";" + + methodKey + + ";" + + modtime / 1000); + log.debug("login: enc = " + enc); + Cookie c = new Cookie(loginCookie, enc); + c.setSecure(true); + c.setPath("/"); + response.addCookie(c); + try { + String rp = request.getPathInfo(); + int sp = rp.indexOf("/", 2); + log.debug("in path = " + rp); + String red = browserRootPath + request.getServletPath(); + if (sp > 1) red = red + rp.substring(sp); + if (request.getQueryString() != null) red = red + "?" + request.getQueryString(); + log.debug("logon ok, return to " + red); + response.sendRedirect(red); + } catch (IOException e) { + log.error("redirect: " + e); + return emptyMV("redirect error"); + } + } else { + // send login failed message + ModelAndView mv = new ModelAndView("browser/nologin"); + mv.addObject("root", browserRootPath); + mv.addObject("vers", request.getServletPath()); + mv.addObject("pageTitle", "login failed"); + mv.addObject("myEntityId", myEntityId); + return mv; + } + return emptyMV(); + } + + @RequestMapping(value = "/login/**", method = RequestMethod.GET) + public ModelAndView basicLoginPage(HttpServletRequest request, HttpServletResponse response) { + return loginPage(request, response, 1); + } + + @RequestMapping(value = "/securelogin/**", method = RequestMethod.GET) + public ModelAndView secureLoginPage(HttpServletRequest request, HttpServletResponse response) { + return loginPage(request, response, 2); + } + + @RequestMapping(value = "/googlelogin/**", method = RequestMethod.GET) + public ModelAndView googleLoginPage(HttpServletRequest request, HttpServletResponse response) { + log.debug("hitting /googlelogin/** endpoint now"); + return loginPage(request, response, 0); + } + + @RequestMapping(value = "/incommonlogin/**", method = RequestMethod.GET) + public ModelAndView incommonLoginPage(HttpServletRequest request, HttpServletResponse response) { + return loginPage(request, response, 1); + } + + /* + * Process logoutt page + * Clear cookies, redirect to shib logout + */ + + @RequestMapping(value = "/logout/**", method = RequestMethod.GET) + public ModelAndView logoutPage(HttpServletRequest request, HttpServletResponse response) { + // clear cookies + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) { + String ckName = cookies[i].getName(); + if (ckName.equals(loginCookie) || ckName.equals(roleCookie) || ckName.startsWith("_shib")) { + log.debug("cookie to clear " + ckName); + Cookie c = new Cookie(ckName, "void"); + c.setSecure(true); + c.setPath("/"); + c.setMaxAge(0); + response.addCookie(c); } - SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); - msg.setTo(mailTo); - msg.setText( "User '" + session.remoteUser + "' deleted metadata for '" + id + "'.\nRequest status: " + status); - try{ - this.mailSender.send(msg); - } catch(MailException ex) { - log.error("sending mail: " + ex.getMessage()); + } + } + /** + * try { + * log.debug("redirect to: " + logoutUrl); + * response.sendRedirect(logoutUrl); + * } catch (IOException e) { + * log.error("redirect: " + e); + * } + * return emptyMV("configuration error"); + **/ + String view = "browser"; + Device currentDevice = DeviceUtils.getCurrentDevice(request); + if (currentDevice != null && currentDevice.isMobile()) view = "mobile"; + ModelAndView mv = new ModelAndView(view + "/chooser"); + mv.addObject("root", browserRootPath); + mv.addObject("vers", request.getServletPath()); + mv.addObject("pagetype", "browser/loggedout"); + mv.addObject("pathextra", ""); + mv.addObject("uwloginpath", standardLoginPath); + mv.addObject("googleloginpath", googleLoginPath); + mv.addObject("incommonloginpath", incommonLoginPath); + return (mv); + } + + // show main page + @RequestMapping(value = "/", method = RequestMethod.GET) + public ModelAndView homePage(HttpServletRequest request, HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response); + if (session == null) return (emptyMV()); + if (session.mv != null) return (session.mv); + log.info("/ view"); + log.info(".. path=" + request.getPathInfo()); + + session.pageTitle = "SP registry home"; + session.pageType = "home"; + + ModelAndView mv = basicModelAndView(session); + mv.addObject("isAdmin", session.isAdmin); + mv.addObject("isProxy", session.isProxy); + + return (mv); + } + + // home pages (if 'v1' alone) + @RequestMapping(value = "/v1", method = RequestMethod.GET) + public ModelAndView homePageV1(HttpServletRequest request, HttpServletResponse response) { + log.info("v1 view"); + return homePage(request, response); + } + + // show rp list page + @RequestMapping(value = "/rps", method = RequestMethod.GET) + public ModelAndView getRelyingParties( + @RequestParam(value = "selectrp", required = false) String selRp, + @RequestParam(value = "selecttype", required = false) String selType, + @RequestParam(value = "selectmine", required = false) String selMine, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response, false); + if (session == null) { + response.setStatus(418); + return (emptyMV()); + } + if (session.mv != null) return (session.mv); + log.info("match: " + selRp); + log.info("mine: " + selMine); + + List relyingPartyIds = + rpManager.getRelyingParties(selRp, selMine == null ? null : session.remoteUser); + // List relyingPartyIds = rpManager.getRelyingParties(); + log.info("found " + relyingPartyIds.size() + " rps"); + + ModelAndView mv = basicModelAndView(session, "json", "rps"); + // mv.addObject("selectrp", selRp==null?"":selRp); + // mv.addObject("selecttype", selType==null?"all":selType); + mv.addObject("relyingParties", relyingPartyIds); + + return (mv); + } + + // specific party + @RequestMapping(value = "/rp", method = RequestMethod.GET) + public ModelAndView getRelyingParty( + @RequestParam(value = "id", required = true) String id, + @RequestParam(value = "mdid", required = true) String mdid, + @RequestParam(value = "view", required = false) String view, + @RequestParam(value = "dns", required = false) String dns, + @RequestParam(value = "role", required = false) String role, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response); + if (session == null) return (emptyMV()); + if (session.mv != null) return (session.mv); + + session.pageType = "rp"; + session.pageTitle = "Service provider"; + + RelyingParty rp = null; + RelyingParty rrp = null; + + List relyingPartyEntries = null; // list of all RP entries from the database + List proxyHistory = null; + + try { + relyingPartyEntries = rpManager.getRelyingPartyHistoryById(id); + } catch (RelyingPartyException e) { + log.debug("Exception occurred getting metadata history"); + return emptyMV("SP not found"); + } + try { + proxyHistory = proxyManager.getProxyHistory(id); + + } catch (ProxyException e) { + log.debug("Exception occurred getting proxy history"); + } + + List rpHistory = new LinkedList(); // list of parsed history items + if (relyingPartyEntries.size() > 1) { + int i = 0; + while (i < relyingPartyEntries.size() - 1) { + HistoryItem item = relyingPartyEntries.get(i).RpCompare(relyingPartyEntries.get(i + 1)); + // little bit of a hack to not add an "empty" item if we didn't parse out changes properly + if (item.getNumberOfChanges() != 0) { + rpHistory.add(item); } - - response.setStatus(status); - return mv; - } - - - - - // rp attributes - @RequestMapping(value="/rp/attr", method=RequestMethod.GET) - public ModelAndView getRelyingPartyAttributes(@RequestParam(value="id", required=true) String id, - @RequestParam(value="mdid", required=false) String mdid, - @RequestParam(value="view", required=false) String view, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response); - if (session==null) return (emptyMV()); - if (session.mv!=null) return (session.mv); - - session.pageType = "relying-party-attr"; - session.pageTitle = "Service provider"; - if (view==null) view = ""; - else if (view.equals("edit")) session.pageType = "relying-party-attr-edit"; - - RelyingParty rp = null; - String errmsg = null; - + i++; + } + } + + boolean canEdit = false; + + String errmsg = null; + + ModelAndView mv = basicModelAndView(session, "browser", "rp"); + + try { + rp = rpManager.getRelyingPartyById(id, mdid); + } catch (RelyingPartyException e) { + return emptyMV("not found"); + } + session.pageTitle = rp.getEntityId(); + try { + if (userCanEdit(session, id)) { + log.debug("user can edit"); + canEdit = true; + } + } catch (DNSVerifyException e) { + mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); + response.setStatus(500); + return mv; + } + + log.info("returning rp id=" + id); + List filterPolicyGroups = filterPolicyManager.getFilterPolicyGroups(); + List attributes = filterPolicyManager.getAttributes(rp); + + Proxy proxy = proxyManager.getProxy(id); + AccessCtrl accessCtrl = accessCtrlManager.getAccessCtrl(id); + + mv.addObject("canEdit", canEdit); + mv.addObject("relyingParty", rp); + mv.addObject("filterPolicyGroups", filterPolicyGroups); + mv.addObject("filterPolicyManager", filterPolicyManager); + mv.addObject("attributes", attributes); + mv.addObject("relyingPartyId", id); + mv.addObject("proxy", proxy); + mv.addObject("accessCtrl", accessCtrl); + mv.addObject("rpHistory", rpHistory); + // mv.addObject("proxyHistory", proxyHistory); + mv.addObject("isAdmin", session.isAdmin); + mv.addObject("isProxy", session.isProxy); + mv.addObject("dateFormatter", new SimpleDateFormat("yy/MM/dd")); + return (mv); + } + + // rp's metadata (API endpoint) + @RequestMapping(value = "/ws/metadata", method = RequestMethod.GET) + public ModelAndView getRelyingParty( + @RequestParam(value = "id", required = true) String id, + @RequestParam(value = "mdid", required = true) String mdid, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response); + if (session == null) return (emptyMV()); + if (session.mv != null) return (session.mv); + + session.pageType = "metadata"; + session.pageTitle = "Service provider"; + + RelyingParty rp = null; + + String errmsg = null; + + ModelAndView mv = basicModelAndView(session, "xml", "metadata"); + + try { + rp = rpManager.getRelyingPartyById(id, mdid); + } catch (RelyingPartyException e) { + response.setStatus(404); + return emptyMV("not found"); + } + log.info("returning metadata id=" + id); + try { + StringWriter writer = new StringWriter(); + BufferedWriter xout = new BufferedWriter(writer); + rp.writeXml(xout); + xout.close(); + mv.addObject("metadata", writer.toString()); + } catch (IOException e) { + log.error("string writer errro: " + e); + response.setStatus(500); + return emptyMV("internal error"); + } + + return (mv); + } + + // new rp + @RequestMapping(value = "/new", method = RequestMethod.GET) + public ModelAndView getRelyingPartyNew( + @RequestParam(value = "rpid", required = true) String rpid, + @RequestParam(value = "mdid", required = false) String mdid, + @RequestParam(value = "view", required = false) String view, + @RequestParam(value = "role", required = false) String role, + @RequestParam(value = "lookup", required = false) + String lookup, // enter manual data for this entity + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response); + if (session == null) return (emptyMV()); + if (session.mv != null) return (session.mv); + + session.pageType = "rp"; + session.pageTitle = "New service provider"; + if (lookup != null) lookup = java.net.URLDecoder.decode(lookup); + + String dns = dnsFromEntityId(rpid); + + if (dns.length() == 0) return (emptyMV()); + + RelyingParty rp = null; + boolean canEdit = true; + String errmsg = null; + ModelAndView mv = basicModelAndView(session, "browser", "rp"); + + // check access + try { + if (userCanEdit(session, dns)) { + log.debug("user owns dns"); + } else { + // response.setStatus(200); // 403 + return emptyMV("No permission for " + rpid); + } + } catch (DNSVerifyException e) { + // mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); + // response.setStatus(500); + return emptyMV("Could not verify ownership:\n" + e.getCause()); + } + + // check that it doesn't already exist + try { + rpManager.getRelyingPartyById(rpid, "UW"); + log.debug("wants new, but already exists"); + return emptyMV("Entity " + rpid + " already exists in the UW federation metadata"); + } catch (RelyingPartyException e) { + log.debug("really new"); + } + + mv.addObject("newEntity", true); + + if (lookup != null) { + mv.addObject("newByLookup", true); + try { + if (lookup.equals("sp")) + lookup = "https://" + hostPortFromEntityId(rpid) + "/Shibboleth.sso/Metadata"; + log.debug("SP by lookup: " + lookup); + rp = rpManager.genRelyingPartyByLookup(lookup); + if (rp != null) log.debug("rp: " + rp.getEntityId()); try { - rp = rpManager.getRelyingPartyById(id, mdid); + RelyingParty orp = rpManager.getRelyingPartyById(rp.getEntityId(), "UW"); + if (orp != null) rp = orp; } catch (RelyingPartyException e) { - return emptyMV("SP not found"); - } - session.pageTitle = rp.getEntityId(); - - List filterPolicyGroups = filterPolicyManager.getFilterPolicyGroups(); - List attributes = filterPolicyManager.getAttributes(); - - ModelAndView mv = basicModelAndView(session); - - log.info("returning attrs for id=" + id ); - - mv.addObject("relyingPartyId", id); - mv.addObject("relyingParty", rp); - mv.addObject("filterPolicyGroups", filterPolicyGroups); - mv.addObject("filterPolicyManager", filterPolicyManager); - mv.addObject("remoteUser", session.remoteUser); - try { - if (userCanEdit(session, id)) mv.addObject("domainOwner",true); - } catch (DNSVerifyException e) { - mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); - response.setStatus(500); - return mv; - } - mv.addObject("attributes", attributes); - return (mv); - } - - // update an rp's attrs - @RequestMapping(value="/rp/attr", method=RequestMethod.PUT) - public ModelAndView putRelyingPartyAttributes(@RequestParam(value="id", required=true) String id, - @RequestParam(value="policyId", required=true) String policyId, - @RequestParam(value="xsrf", required=false) String paramXsrf, - InputStream in, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response, false); - if (session==null) return (emptyMV()); - log.info("PUT update attrs for " + id + " in " + policyId); - int status = 200; - -/** - if (session.isBrowser && !(paramXsrf!=null && paramXsrf.equals(session.xsrfCode))) { - log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); - return emptyMV("invalid session (xsrf)"); - } - **/ - - ModelAndView mv = emptyMV("OK dokey"); - - if (!session.isAdmin) { - status = 401; - mv.addObject("alert", "You are not permitted to update attriubtes."); - response.setStatus(status); - return mv; - } - - Document doc = null; - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - doc = builder.parse (in); - } catch (Exception e) { - log.info("parse error: " + e); - status = 400; - mv.addObject("alert", "The posted document was not valid:\n" + e.getMessage()); - } - if (doc!=null) { - try { - filterPolicyManager.updateRelyingParty(policyId, doc, session.remoteUser); - status = 200; - } catch (FilterPolicyException e) { - status = 400; - mv.addObject("alert", "Update of the entity failed:" + e.getMessage()); - } + log.debug("rp doesn't already exist in our metadata"); } - SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); - msg.setTo(mailTo); - String act = "updated"; - if (status==201) act = "created"; - msg.setSubject("Service provider attributes " + act + " by " + session.remoteUser); - msg.setText( "User '" + session.remoteUser + "' " + act + " attributes for '" + id + "'.\nRequest status: " + status + "\n"); - try{ - this.mailSender.send(msg); - } catch(MailException ex) { - log.error("sending mail: " + ex.getMessage()); + if (!hostPortFromEntityId(rpid).equals(hostPortFromEntityId(rp.getEntityId()))) { + log.info( + String.format( + "requested dns '%s' not equal to fetched entityId '%s'", + hostPortFromEntityId(rpid), rp.getEntityId())); + return emptyMV( + String.format( + "The requested entity id's domain name, '%s', does not match the fetched name: '%s'", + hostPortFromEntityId(rpid), rp.getEntityId())); } + mv.addObject("relyingParty", rp); + mv.addObject("relyingPartyId", rp.getEntityId()); + session.pageTitle = rp.getEntityId(); + } catch (RelyingPartyException e) { + mv.addObject("rpnotfound", true); + log.debug("metadata not found for " + dns); + log.debug(e.getMessage()); + } + } + if (rp == null) { + if (lookup != null) return emptyMV("URL did not respond with metadata"); + rp = rpManager.genRelyingPartyByName(rpid, dns); + mv.addObject("relyingParty", rp); + mv.addObject("relyingPartyId", rpid); + session.pageTitle = rpid; + } + + List filterPolicyGroups = filterPolicyManager.getFilterPolicyGroups(); + List attributes = filterPolicyManager.getAttributes(rp); + mv.addObject("filterPolicyGroups", filterPolicyGroups); + mv.addObject("filterPolicyManager", filterPolicyManager); + return (mv); + } + + // update an rp metadata + @RequestMapping(value = "/rp", method = RequestMethod.PUT) + public ModelAndView putRelyingParty( + @RequestParam(value = "id", required = true) String id, + @RequestParam(value = "mdid", required = true) String mdid, + @RequestParam(value = "role", required = false) String role, + @RequestParam(value = "xsrf", required = false) String paramXsrf, + InputStream in, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response, false); + if (session == null) return (emptyMV()); + + log.info("PUT update for: " + id); + int status = 200; + + if (session.isBrowser && !(paramXsrf != null && paramXsrf.equals(session.xsrfCode))) { + log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); + return emptyMV("invalid session (xsrf)"); + } + + ModelAndView mv = emptyMV("OK dokey"); + + try { + if (!userCanEdit(session, id)) { + status = 401; + mv.addObject("alert", "You are not an owner of that entity."); response.setStatus(status); return mv; - } - - - // request for attributes - @RequestMapping(value="/rp/attrReq", method=RequestMethod.PUT) - public ModelAndView putRelyingPartyAttrReq(@RequestParam(value="id", required=true) String id, - InputStream in, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response, false); - if (session==null) return (emptyMV()); - log.info("PUT request for: " + id); - int status = 200; - - ModelAndView mv = emptyMV("OK dokey"); - - try { - if (!userCanEdit(session, id)) { - status = 401; - mv.addObject("alert", "You are not an owner of that entity."); - } - } catch (DNSVerifyException e) { - mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); - response.setStatus(500); - return mv; - } - - Document doc = null; - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - doc = builder.parse (in); - } catch (Exception e) { - log.info("parse error: " + e.getMessage()); - status = 400; - mv.addObject("alert", "The posted document was not valid:\n" + e.getMessage()); - } - if (doc!=null) { - StringBuffer txt = new StringBuffer("[ Assign to Identity and Access Management. ]\n\nEntity Id: " + id + "\n"); - txt.append("User: " + session.remoteUser + "\n\nRequesting:\n"); - List attrs = XMLHelper.getElementsByName(doc.getDocumentElement(), "Add"); - log.debug(attrs.size() + " adds"); - for (int i=0; i0) msg.setFrom(session.remoteUser); - else msg.setFrom(session.remoteUser + "@uw.edu"); - msg.setText(txt.toString()); - try{ - this.mailSender.send(msg); - } catch(MailException ex) { - log.error("sending mail: " + ex.getMessage()); - status = 500; - mv.addObject("alert", "Could not complete attribute request (sending mail failed)."); - } - - } + } + } catch (DNSVerifyException e) { + mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); + response.setStatus(500); + return mv; + } + + // if new, check for URL entityid + try { + rpManager.getRelyingPartyById(id, mdid); + } catch (RelyingPartyException e) { + if (!isProperEntityId(session, id)) { + log.info("improper entity id"); + status = 400; + mv.addObject("alert", "The posted entityid was not a URL\n"); response.setStatus(status); return mv; - } - - // all attributes - @RequestMapping(value="/attr", method=RequestMethod.GET) - public ModelAndView getAttributes(@RequestParam(value="id", required=false) String id, - @RequestParam(value="mdid", required=false) String mdid, - @RequestParam(value="view", required=false) String view, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response); - if (session==null) return (emptyMV()); - if (session.mv!=null) return (session.mv); - - session.pageType = "attributes"; - session.pageTitle = "Attributes"; - - // if (view!=null && view.equals("edit")) session.pageType = "relying-party-attr-edit"; - // RelyingParty rp = null; - - List attributes = filterPolicyManager.getAttributes(); - - ModelAndView mv = basicModelAndView(session); - - log.info("returning attrs"); - - mv.addObject("attributes", attributes); - mv.addObject("filterPolicyManager", filterPolicyManager); - mv.addObject("remoteUser", session.remoteUser); - return (mv); - } - - - // update an rp's proxy - @RequestMapping(value="/rp/proxy", method=RequestMethod.PUT) - public ModelAndView putRelyingPartyAttributesZ(@RequestParam(value="id", required=true) String id, - @RequestParam(value="role", required=false) String role, - @RequestParam(value="xsrf", required=false) String paramXsrf, - @RequestParam(value="social_login_flag", required=true) boolean socialActive, - InputStream in, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response, false); - if (session==null) return (emptyMV()); - - log.info("PUT update proxy for " + id); - int status = 200; - - if (session.isBrowser && !(paramXsrf!=null && paramXsrf.equals(session.xsrfCode))) { - log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); - return emptyMV("invalid session (xsrf)"); - } - - ModelAndView mv = emptyMV("OK dokey"); - try { - if (!userCanEdit(session, id)) { - status = 401; - mv.addObject("alert", "You are not an owner of that entity."); - response.setStatus(status); - return mv; - } - } catch (DNSVerifyException e) { - mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); - response.setStatus(500); - return mv; - } - - - try { - Proxy newproxy = new Proxy(); - newproxy.setEntityId(id); - newproxy.setSocialActive(socialActive); - proxyManager.updateProxy(newproxy, session.remoteUser); - status = 200; - } catch (ProxyException e) { - status = 400; - mv.addObject("alert", "Update of the entity failed:" + e.getMessage()); - } - - - SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); - msg.setTo(mailTo); - String act = "updated"; - if (status==201) act = "created"; - msg.setSubject("Service provider proxy info " + act + " by " + session.remoteUser); - msg.setText( "User '" + session.remoteUser + "' " + act + " proxy info '" + id + "'.\nRequest status: " + status + "\n"); - try{ - this.mailSender.send(msg); - } catch(MailException ex) { - log.error("sending mail: " + ex.getMessage()); - } - + } + } + + RelyingParty relyingParty = null; + try { + Document doc = null; + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + // In parser we trust. (no server side input validation on XML payload) + doc = builder.parse(in); + relyingParty = + new RelyingParty(doc.getDocumentElement(), mdid, rpManager.isMetadataEditable(mdid)); + } catch (Exception e) { + log.info("parse error: " + e); + status = 400; + mv.addObject("alert", e.getMessage()); + response.setStatus(status); + return mv; + } + + if (!relyingParty.getEntityId().equals(id)) { + log.info("entity id mismatch"); + status = 400; + mv.addObject("alert", "The posted entityid did not match the request\n"); + response.setStatus(status); + return mv; + } + + try { + status = rpManager.updateRelyingParty(relyingParty, mdid, session.remoteUser); + } catch (RelyingPartyException e) { + status = 400; + mv.addObject("alert", e.getMessage()); + response.setStatus(status); + return mv; + } + + SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); + msg.setTo(mailTo); + String act = "updated"; + if (status == 201) act = "created"; + else if (status >= 400) act = "attempted edit of"; + msg.setSubject("Service provider metadata " + act + " by " + session.remoteUser); + msg.setText( + "User '" + + session.remoteUser + + "' " + + act + + " metadata for '" + + id + + "'.\nRequest status: " + + status + + "\n\nThis message is advisory. No response is indicated."); + try { + this.mailSender.send(msg); + } catch (MailException ex) { + log.error("sending mail: " + ex.getMessage()); + } + + response.setStatus(status); + return mv; + } + + // API update an rp metadata + @RequestMapping(value = "/ws/metadata", method = RequestMethod.PUT) + public ModelAndView putRelyingParty( + @RequestParam(value = "id", required = true) String id, + @RequestParam(value = "mdid", required = true) String mdid, + InputStream in, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response, false); + if (session == null) return (emptyMV()); + log.info("API PUT update for: " + id); + int status = 403; + + ModelAndView mv = basicModelAndView(session, "xml", "empty"); + + String dns = dnsFromEntityId(id); + for (String alt : (List) session.altNames) { + if (dns.equals(alt) || (alt.startsWith("*.") && dns.endsWith(alt.substring(1)))) { + log.info("dns match found for " + dns); + status = 200; + break; + } + } + if (status == 403) { + mv.addObject("alert", "You are not an owner of that entity."); + response.setStatus(status); + return mv; + } + if (!rpManager.isMetadataEditable(mdid)) { + status = 400; + mv.addObject("alert", "The metadata was not found or is not editable"); + response.setStatus(status); + return mv; + } + + // if new, check for URL entityid + try { + rpManager.getRelyingPartyById(id, mdid); + } catch (RelyingPartyException e) { + if (!isProperEntityId(session, id)) { + log.info("improper entity id"); + status = 400; + mv.addObject("alert", "The posted entityid was not a URL\n"); response.setStatus(status); return mv; - } - - @RequestMapping(value="/rp/accessCtrl", method=RequestMethod.PUT) - public ModelAndView putRelyingPartyAccessCtrl(@RequestParam(value="id", required=true) String id, - @RequestParam(value="role", required=false) String role, - @RequestParam(value="xsrf", required=false) String paramXsrf, - @RequestParam(value="type_2fa", required=true) String type2FA, - @RequestParam(value="group_2fa", required=true) String group2FA, - @RequestParam(value="conditional_flag", required=true) boolean conditional, - @RequestParam(value="conditional_group_name", required=true) String conditionalGroup, - @RequestParam(value="conditional_link", required=false) String conditionalLink, - - InputStream in, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response, false); - if (session==null) return (emptyMV()); - - log.info("PUT update access control for " + id); - int status = 200; - - if (session.isBrowser && !(paramXsrf!=null && paramXsrf.equals(session.xsrfCode))) { - log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); - return emptyMV("invalid session (xsrf)"); - } - - ModelAndView mv = emptyMV("OK dokey"); - - if (!session.isAdmin) { - status = 401; - mv.addObject("alert", "You are not permitted to update access control."); - response.setStatus(status); - return mv; - } - - try { - if (!userCanEdit(session, id)) { - status = 401; - mv.addObject("alert", "You are not an owner of that entity."); - response.setStatus(status); - return mv; - } - } catch (DNSVerifyException e) { - mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); - response.setStatus(500); - return mv; + } + } + + RelyingParty rp = null; + try { + Document doc = null; + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + doc = builder.parse(in); + rp = new RelyingParty(doc.getDocumentElement(), mdid, rpManager.isMetadataEditable(mdid)); + } catch (Exception e) { + log.info("parse error: " + e); + status = 400; + mv.addObject("alert", e.getMessage()); + response.setStatus(status); + return mv; + } + if (rp.getEntityId().equals(id)) { + try { + rpManager.updateRelyingParty(rp, mdid, session.remoteUser); + } catch (RelyingPartyException e) { + status = 400; + mv.addObject("alert", "Update of the metadata failed:\n" + e.getMessage()); + } + } else { + mv.addObject("alert", String.format("Id %s doesn't match %s", rp.getEntityId(), id)); + } + + SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); + msg.setTo(mailTo); + String act = "updated"; + if (status == 201) act = "created"; + else if (status >= 400) act = "attempted edit of"; + msg.setSubject("Service provider metadata " + act + " by " + session.remoteUser); + msg.setText( + "User '" + + session.remoteUser + + "' " + + act + + " metadata for '" + + id + + "'.\nRequest status: " + + status + + "\n\nThis message is advisory. No response is indicated."); + try { + this.mailSender.send(msg); + } catch (MailException ex) { + log.error("sending mail: " + ex.getMessage()); + } + + response.setStatus(status); + return mv; + } + + // delete an rp + @RequestMapping(value = "/rp", method = RequestMethod.DELETE) + public ModelAndView deleteRelyingParty( + @RequestParam(value = "id", required = true) String id, + @RequestParam(value = "mdid", required = true) String mdid, + @RequestParam(value = "role", required = false) String role, + @RequestParam(value = "xsrf", required = false) String paramXsrf, + InputStream in, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response, false); + if (session == null) return (emptyMV()); + + log.info("DELETE for: " + id); + int status = 200; + + if (session.isBrowser && !(paramXsrf != null && paramXsrf.equals(session.xsrfCode))) { + log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); + return emptyMV("invalid session (xsrf)"); + } + + ModelAndView mv = emptyMV("OK dokey delete rp"); + + try { + if (!userCanEdit(session, id)) { + status = 401; + mv.addObject("alert", "You are not the owner."); + } else { + /* If there is NOT an incommon uuid we can delete these. If there is one we need to keep them. + * Otherwise attributes/proxy/access control for InCommon SP get clobbered when we delete + * the UW SP*/ + if (!uuidManager.hasIncUuid(id)) { + status = accessCtrlManager.removeAccessCtrl(id, session.remoteUser); + status = proxyManager.removeProxy(id, session.remoteUser); + status = filterPolicyManager.removeEditableRelyingParty(id, session.remoteUser); } - - - try { - AccessCtrl newAccessCtrl = new AccessCtrl(); - newAccessCtrl.setEntityId(id); - - if(type2FA.equals("cond")) { - newAccessCtrl.setCond2FA(group2FA); - } else if (type2FA.equals("auto")) { - newAccessCtrl.setAuto2FA(true); - } - newAccessCtrl.setConditionalByUser(conditional, conditionalGroup, conditionalLink); - accessCtrlManager.updateAccessCtrl(newAccessCtrl, session.remoteUser); - status = 200; - } catch (AccessCtrlException e) { - status = 400; - mv.addObject("alert", "Update of access control for entity failed:" + e.getMessage()); - } - + status = rpManager.removeRelyingParty(id, mdid, session.remoteUser); + } + } catch (FilterPolicyException e) { + mv.addObject( + "alert", + "(while attempting rp delete) delete of filter policy failed:\n" + e.getCause()); + response.setStatus(500); + return mv; + } catch (DNSVerifyException e) { + mv.addObject( + "alert", "(while attempting rp delete) Could not verify ownership:\n" + e.getCause()); + response.setStatus(500); + return mv; + } catch (ProxyException e) { + mv.addObject( + "alert", "(while attempting rp delete) Proxy (gateway) error:\n" + e.getCause()); + response.setStatus(500); + return mv; + } catch (AccessCtrlException e) { + mv.addObject("alert", "(while attempting rp delete) Access control error:\n" + e.getCause()); + response.setStatus(500); + return mv; + } + SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); + msg.setTo(mailTo); + msg.setText( + "User '" + + session.remoteUser + + "' deleted metadata for '" + + id + + "'.\nRequest status: " + + status); + try { + this.mailSender.send(msg); + } catch (MailException ex) { + log.error("sending mail: " + ex.getMessage()); + } + + response.setStatus(status); + return mv; + } + + // rp attributes + @RequestMapping(value = "/rp/attr", method = RequestMethod.GET) + public ModelAndView getRelyingPartyAttributes( + @RequestParam(value = "id", required = true) String id, + @RequestParam(value = "mdid", required = false) String mdid, + @RequestParam(value = "view", required = false) String view, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response); + if (session == null) return (emptyMV()); + if (session.mv != null) return (session.mv); + + session.pageType = "relying-party-attr"; + session.pageTitle = "Service provider"; + if (view == null) view = ""; + else if (view.equals("edit")) session.pageType = "relying-party-attr-edit"; + + RelyingParty rp = null; + String errmsg = null; + + try { + rp = rpManager.getRelyingPartyById(id, mdid); + } catch (RelyingPartyException e) { + return emptyMV("SP not found"); + } + session.pageTitle = rp.getEntityId(); + + List filterPolicyGroups = filterPolicyManager.getFilterPolicyGroups(); + List attributes = filterPolicyManager.getAttributes(); + + ModelAndView mv = basicModelAndView(session); + + log.info("returning attrs for id=" + id); + + mv.addObject("relyingPartyId", id); + mv.addObject("relyingParty", rp); + mv.addObject("filterPolicyGroups", filterPolicyGroups); + mv.addObject("filterPolicyManager", filterPolicyManager); + mv.addObject("remoteUser", session.remoteUser); + try { + if (userCanEdit(session, id)) mv.addObject("domainOwner", true); + } catch (DNSVerifyException e) { + mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); + response.setStatus(500); + return mv; + } + mv.addObject("attributes", attributes); + return (mv); + } + + // update an rp's attrs + @RequestMapping(value = "/rp/attr", method = RequestMethod.PUT) + public ModelAndView putRelyingPartyAttributes( + @RequestParam(value = "id", required = true) String id, + @RequestParam(value = "policyId", required = true) String policyId, + @RequestParam(value = "xsrf", required = false) String paramXsrf, + InputStream in, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response, false); + if (session == null) return (emptyMV()); + log.info("PUT update attrs for " + id + " in " + policyId); + int status = 200; + + /** + * if (session.isBrowser && !(paramXsrf!=null && paramXsrf.equals(session.xsrfCode))) { + * log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); + * return emptyMV("invalid session (xsrf)"); + * } + **/ + ModelAndView mv = emptyMV("OK dokey"); + + if (!session.isAdmin) { + status = 401; + mv.addObject("alert", "You are not permitted to update attriubtes."); + response.setStatus(status); + return mv; + } + + Document doc = null; + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + doc = builder.parse(in); + } catch (Exception e) { + log.info("parse error: " + e); + status = 400; + mv.addObject("alert", "The posted document was not valid:\n" + e.getMessage()); + } + if (doc != null) { + try { + filterPolicyManager.updateRelyingParty(policyId, doc, session.remoteUser); + status = 200; + } catch (FilterPolicyException e) { + status = 400; + mv.addObject("alert", "Update of the entity failed:" + e.getMessage()); + } + } + + SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); + msg.setTo(mailTo); + String act = "updated"; + if (status == 201) act = "created"; + msg.setSubject("Service provider attributes " + act + " by " + session.remoteUser); + msg.setText( + "User '" + + session.remoteUser + + "' " + + act + + " attributes for '" + + id + + "'.\nRequest status: " + + status + + "\n"); + try { + this.mailSender.send(msg); + } catch (MailException ex) { + log.error("sending mail: " + ex.getMessage()); + } + + response.setStatus(status); + return mv; + } + + // request for attributes + @RequestMapping(value = "/rp/attrReq", method = RequestMethod.PUT) + public ModelAndView putRelyingPartyAttrReq( + @RequestParam(value = "id", required = true) String id, + InputStream in, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response, false); + if (session == null) return (emptyMV()); + log.info("PUT request for: " + id); + int status = 200; + + ModelAndView mv = emptyMV("OK dokey"); + + try { + if (!userCanEdit(session, id)) { + status = 401; + mv.addObject("alert", "You are not an owner of that entity."); + } + } catch (DNSVerifyException e) { + mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); + response.setStatus(500); + return mv; + } + + Document doc = null; + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + doc = builder.parse(in); + } catch (Exception e) { + log.info("parse error: " + e.getMessage()); + status = 400; + mv.addObject("alert", "The posted document was not valid:\n" + e.getMessage()); + } + if (doc != null) { + StringBuffer txt = + new StringBuffer( + "[ Assign to Identity and Access Management. ]\n\nEntity Id: " + id + "\n"); + txt.append("User: " + session.remoteUser + "\n\nRequesting:\n"); + List attrs = XMLHelper.getElementsByName(doc.getDocumentElement(), "Add"); + log.debug(attrs.size() + " adds"); + for (int i = 0; i < attrs.size(); i++) + txt.append(" Add new attribute: " + attrs.get(i).getAttribute("id") + "\n\n"); + attrs = XMLHelper.getElementsByName(doc.getDocumentElement(), "Drop"); + log.debug(attrs.size() + " drops"); + for (int i = 0; i < attrs.size(); i++) + txt.append(" Drop existing attribute: " + attrs.get(i).getAttribute("id") + "\n\n"); + Element mele = XMLHelper.getElementByName(doc.getDocumentElement(), "Comments"); + if (mele != null) txt.append("\nComment:\n\n" + mele.getTextContent() + "\n\n"); + txt.append("Quick link:\n\n " + spRegistryUrl + "#a" + id + "\n"); + + SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); + /* production to RT system */ + msg.setTo(requestMailTo); + msg.setSubject("IdP attribute request for " + id); + if (session.remoteUser.indexOf("@") > 0) msg.setFrom(session.remoteUser); + else msg.setFrom(session.remoteUser + "@uw.edu"); + msg.setText(txt.toString()); + try { + this.mailSender.send(msg); + } catch (MailException ex) { + log.error("sending mail: " + ex.getMessage()); + status = 500; + mv.addObject("alert", "Could not complete attribute request (sending mail failed)."); + } + } + response.setStatus(status); + return mv; + } + + // all attributes + @RequestMapping(value = "/attr", method = RequestMethod.GET) + public ModelAndView getAttributes( + @RequestParam(value = "id", required = false) String id, + @RequestParam(value = "mdid", required = false) String mdid, + @RequestParam(value = "view", required = false) String view, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response); + if (session == null) return (emptyMV()); + if (session.mv != null) return (session.mv); + + session.pageType = "attributes"; + session.pageTitle = "Attributes"; + + // if (view!=null && view.equals("edit")) session.pageType = "relying-party-attr-edit"; + // RelyingParty rp = null; + + List attributes = filterPolicyManager.getAttributes(); + + ModelAndView mv = basicModelAndView(session); + + log.info("returning attrs"); + + mv.addObject("attributes", attributes); + mv.addObject("filterPolicyManager", filterPolicyManager); + mv.addObject("remoteUser", session.remoteUser); + return (mv); + } + + // update an rp's proxy + @RequestMapping(value = "/rp/proxy", method = RequestMethod.PUT) + public ModelAndView putRelyingPartyAttributesZ( + @RequestParam(value = "id", required = true) String id, + @RequestParam(value = "role", required = false) String role, + @RequestParam(value = "xsrf", required = false) String paramXsrf, + @RequestParam(value = "social_login_flag", required = true) boolean socialActive, + InputStream in, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response, false); + if (session == null) return (emptyMV()); + + log.info("PUT update proxy for " + id); + int status = 200; + + if (session.isBrowser && !(paramXsrf != null && paramXsrf.equals(session.xsrfCode))) { + log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); + return emptyMV("invalid session (xsrf)"); + } + + ModelAndView mv = emptyMV("OK dokey"); + try { + if (!userCanEdit(session, id)) { + status = 401; + mv.addObject("alert", "You are not an owner of that entity."); response.setStatus(status); return mv; - } - - private String hostFromId(String id) throws AccessCtrlException { - String ret = ""; - if (id.startsWith("https://")) ret = id.substring(8); - else if (id.startsWith("http://")) ret = id.substring(7); - else if (id.startsWith("oidc/")) ret = id.substring(5); - else throw new AccessCtrlException("Cannot form a group name from that id"); - if (ret.indexOf("/")>0) ret = ret.substring(0, ret.indexOf("/")); - return ret; - } - - - // request for access control - @RequestMapping(value="/rp/accessCtrlReq", method=RequestMethod.PUT) - public ModelAndView putAccessCtrlReq(@RequestParam(value="id", required=true) String id, - InputStream in, - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response, false); - if (session==null) return (emptyMV()); - log.info("PUT request for: " + id); - int status = 200; - - ModelAndView mv = emptyMV("OK dokey"); - - try { - if (!userCanEdit(session, id)) { - status = 401; - mv.addObject("alert", "You are not an owner of that entity."); - } - } catch (DNSVerifyException e) { - mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); - response.setStatus(500); - return mv; - } - - Document doc = null; - try { - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); - doc = builder.parse (in); - } catch (Exception e) { - log.info("parse error: " + e.getMessage()); - status = 400; - mv.addObject("alert", "The posted document was not valid:\n" + e.getMessage()); - } - if (doc!=null) { - StringBuffer txt = new StringBuffer("[ Assign to Identity and Access Management. ]\n\nEntity Id: " + id + "\n"); - txt.append("User: " + session.remoteUser + "\n\nRequesting:\n"); - List attrs = XMLHelper.getElementsByName(doc.getDocumentElement(), "Add"); - log.debug(attrs.size() + " access control adds"); - for (int i=0; i0) msg.setFrom(session.remoteUser); - else msg.setFrom(session.remoteUser + "@uw.edu"); - msg.setText(txt.toString()); - try{ - this.mailSender.send(msg); - } catch(MailException ex) { - log.error("sending mail: " + ex.getMessage()); - status = 500; - mv.addObject("alert", "Could not complete attribute request (sending mail failed)."); - } - - } + } + } catch (DNSVerifyException e) { + mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); + response.setStatus(500); + return mv; + } + + try { + Proxy newproxy = new Proxy(); + newproxy.setEntityId(id); + newproxy.setSocialActive(socialActive); + proxyManager.updateProxy(newproxy, session.remoteUser); + status = 200; + } catch (ProxyException e) { + status = 400; + mv.addObject("alert", "Update of the entity failed:" + e.getMessage()); + } + + SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); + msg.setTo(mailTo); + String act = "updated"; + if (status == 201) act = "created"; + msg.setSubject("Service provider proxy info " + act + " by " + session.remoteUser); + msg.setText( + "User '" + + session.remoteUser + + "' " + + act + + " proxy info '" + + id + + "'.\nRequest status: " + + status + + "\n"); + try { + this.mailSender.send(msg); + } catch (MailException ex) { + log.error("sending mail: " + ex.getMessage()); + } + + response.setStatus(status); + return mv; + } + + @RequestMapping(value = "/rp/accessCtrl", method = RequestMethod.PUT) + public ModelAndView putRelyingPartyAccessCtrl( + @RequestParam(value = "id", required = true) String id, + @RequestParam(value = "role", required = false) String role, + @RequestParam(value = "xsrf", required = false) String paramXsrf, + @RequestParam(value = "type_2fa", required = true) String type2FA, + @RequestParam(value = "group_2fa", required = true) String group2FA, + @RequestParam(value = "conditional_flag", required = true) boolean conditional, + @RequestParam(value = "conditional_group_name", required = true) String conditionalGroup, + @RequestParam(value = "conditional_link", required = false) String conditionalLink, + InputStream in, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response, false); + if (session == null) return (emptyMV()); + + log.info("PUT update access control for " + id); + int status = 200; + + if (session.isBrowser && !(paramXsrf != null && paramXsrf.equals(session.xsrfCode))) { + log.info("got invalid xsrf=" + paramXsrf + ", expected+" + session.xsrfCode); + return emptyMV("invalid session (xsrf)"); + } + + ModelAndView mv = emptyMV("OK dokey"); + + if (!session.isAdmin) { + status = 401; + mv.addObject("alert", "You are not permitted to update access control."); + response.setStatus(status); + return mv; + } + + try { + if (!userCanEdit(session, id)) { + status = 401; + mv.addObject("alert", "You are not an owner of that entity."); response.setStatus(status); return mv; - } - - public void setRelyingPartyManager(RelyingPartyManager m) { - rpManager = m; - } - - public void setFilterPolicyManager(FilterPolicyManager m) { - filterPolicyManager = m; - } - - public void setProxyManager(ProxyManager m) { - proxyManager = m; - } - - public void setAccessCtrlManager(AccessCtrlManager m) { - accessCtrlManager = m; - } - - public void setUuidManager(UuidManager m) { uuidManager = m; } - - /* utility */ - private boolean userCanEdit(RPSession session, String entityId) - throws DNSVerifyException { - return session.adminRole || dnsVerifier.isOwner(entityId, session.remoteUser, null); - } - - private boolean isProperEntityId(RPSession session, String id) { - return (session.adminRole || id.startsWith("http://") || id.startsWith("https://")); - } - - private long getLongHeader(HttpServletRequest request, String name) { - try { - String hdr = request.getHeader(name); - if (hdr==null) return 0; - if (hdr.equals("*")) return (-1); - return Long.parseLong(hdr); - } catch (NumberFormatException e) { - return 0; - } - } - private String hostPortFromEntityId(String entityId){ - entityId = entityId.replaceFirst("^https?://", ""); - entityId = entityId.replaceFirst("/.*$", ""); - return entityId; - } - private String dnsFromEntityId(String entityid) { - String dns = entityid; - if (dns.startsWith("http://")) dns = dns.substring(7); - if (dns.startsWith("https://")) dns = dns.substring(8); - int i = dns.indexOf("/"); - if (i>0) dns = dns.substring(0,i); - i = dns.indexOf(":"); - if (i>0) dns = dns.substring(0,i); - return dns; - } - private String cleanString(String in) { - if (in==null) return null; - return in.replaceAll("&", "").replaceAll("<", "").replaceAll(">", ""); - } - public void setCertRootPath(String path) { - certRootPath = path; - } - public void setBrowserRootPath(String path) { - browserRootPath = path; - } - - public void setLoginCookie(String v) { - loginCookie = v; - } - public void setRoleCookie(String v) { - roleCookie = v; - } - - public void setLogoutUrl(String v) { - logoutUrl = v; - } - - public void setCryptKey(String v) { - cryptKey = v; - } - - public void setMailTo(String v) { - log.debug("mailTo = " + v); - mailTo = v; - } - public void setRequestMailTo(String v) { - requestMailTo = v; - } - public void setAdminGroupName(String v) { - log.debug("admin group = " + v); - adminGroupName = v; - } - public void setAuto2faPath(String v) { - auto2faPath = v; - } - public void setStandardLoginSec(long v) { - standardLoginSec = v; - } - public void setSecureLoginSec(long v) { - secureLoginSec = v; - } - - public void setStandardLoginPath(String v) { - standardLoginPath = v; - } - public void setSecureLoginPath(String v) { - secureLoginPath = v; - } - public void setGoogleIdentityProvider(String v) { - googleIdentityProvider = v; - } - - public void setMyEntityId(String v) { - myEntityId = v; - } - public void setEppnName(String v) { - eppnName = v; - } - public void setSpRegistryUrl(String v) { - spRegistryUrl = v; - } - - public static RelyingPartyManager getRelyingPartyManager() { - return rpManager; - } - - - /* See if extra login suggested. - */ -/** - private boolean needMoreAuthn(GwsGroup group, GwsSession session, HttpServletResponse response) { - if (group.getSecurityLevel()>1 && !session.authn2) { - log.debug("update needs 2-factor"); - if (session.isBrowser) response.setStatus(402); - else response.setStatus(401); - return true; - } - return false; - } - **/ - - public void init() { - log.info("RelyingPartyController init"); - RPCrypt.init(cryptKey); - adminGroup = groupManager.getGroup(adminGroupName); - } - - /* refresh cache groups */ - - @RequestMapping(value="/ws/refresh", method=RequestMethod.GET) - public ModelAndView getSet( - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response); - response.setStatus(200); - log.info("refreshing cache groups"); - adminGroup = groupManager.getGroup(adminGroupName); - return emptyMV(); - } - - /* status */ - - @RequestMapping(value="/status", method=RequestMethod.GET) - public ModelAndView gettatus( - HttpServletRequest request, - HttpServletResponse response) { - - RPSession session = processRequestInfo(request, response); - response.setStatus(200); - log.info("status request"); - adminGroup = groupManager.getGroup(adminGroupName); - return emptyMV(); - } - - // diagnostic - @RequestMapping(value="/**", method=RequestMethod.GET) - public ModelAndView homePageStar(HttpServletRequest request, HttpServletResponse response) { - log.info("Star view"); - return homePage(request, response); - } - - - + } + } catch (DNSVerifyException e) { + mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); + response.setStatus(500); + return mv; + } + + try { + AccessCtrl newAccessCtrl = new AccessCtrl(); + newAccessCtrl.setEntityId(id); + + if (type2FA.equals("cond")) { + newAccessCtrl.setCond2FA(group2FA); + } else if (type2FA.equals("auto")) { + newAccessCtrl.setAuto2FA(true); + } + newAccessCtrl.setConditionalByUser(conditional, conditionalGroup, conditionalLink); + accessCtrlManager.updateAccessCtrl(newAccessCtrl, session.remoteUser); + status = 200; + } catch (AccessCtrlException e) { + status = 400; + mv.addObject("alert", "Update of access control for entity failed:" + e.getMessage()); + } + + response.setStatus(status); + return mv; + } + + private String hostFromId(String id) throws AccessCtrlException { + String ret = ""; + if (id.startsWith("https://")) ret = id.substring(8); + else if (id.startsWith("http://")) ret = id.substring(7); + else if (id.startsWith("oidc/")) ret = id.substring(5); + else throw new AccessCtrlException("Cannot form a group name from that id"); + if (ret.indexOf("/") > 0) ret = ret.substring(0, ret.indexOf("/")); + return ret; + } + + // request for access control + @RequestMapping(value = "/rp/accessCtrlReq", method = RequestMethod.PUT) + public ModelAndView putAccessCtrlReq( + @RequestParam(value = "id", required = true) String id, + InputStream in, + HttpServletRequest request, + HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response, false); + if (session == null) return (emptyMV()); + log.info("PUT request for: " + id); + int status = 200; + + ModelAndView mv = emptyMV("OK dokey"); + + try { + if (!userCanEdit(session, id)) { + status = 401; + mv.addObject("alert", "You are not an owner of that entity."); + } + } catch (DNSVerifyException e) { + mv.addObject("alert", "Could not verify ownership:\n" + e.getCause()); + response.setStatus(500); + return mv; + } + + Document doc = null; + try { + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + doc = builder.parse(in); + } catch (Exception e) { + log.info("parse error: " + e.getMessage()); + status = 400; + mv.addObject("alert", "The posted document was not valid:\n" + e.getMessage()); + } + if (doc != null) { + StringBuffer txt = + new StringBuffer( + "[ Assign to Identity and Access Management. ]\n\nEntity Id: " + id + "\n"); + txt.append("User: " + session.remoteUser + "\n\nRequesting:\n"); + List attrs = XMLHelper.getElementsByName(doc.getDocumentElement(), "Add"); + log.debug(attrs.size() + " access control adds"); + for (int i = 0; i < attrs.size(); i++) + txt.append(" Add new access control feature: " + attrs.get(i).getAttribute("id") + "\n\n"); + attrs = XMLHelper.getElementsByName(doc.getDocumentElement(), "Drop"); + log.debug(attrs.size() + " access control drops"); + for (int i = 0; i < attrs.size(); i++) + txt.append( + " Drop existing access control feature: " + attrs.get(i).getAttribute("id") + "\n\n"); + Element mele = XMLHelper.getElementByName(doc.getDocumentElement(), "Comments"); + if (mele != null) txt.append("\nComment:\n\n" + mele.getTextContent() + "\n\n"); + txt.append("Quick link:\n\n " + spRegistryUrl + "#a" + id + "\n"); + + SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage); + /* production to RT system */ + msg.setTo(requestMailTo); + msg.setSubject("IdP access control request for " + id); + if (session.remoteUser.indexOf("@") > 0) msg.setFrom(session.remoteUser); + else msg.setFrom(session.remoteUser + "@uw.edu"); + msg.setText(txt.toString()); + try { + this.mailSender.send(msg); + } catch (MailException ex) { + log.error("sending mail: " + ex.getMessage()); + status = 500; + mv.addObject("alert", "Could not complete attribute request (sending mail failed)."); + } + } + response.setStatus(status); + return mv; + } + + public void setRelyingPartyManager(RelyingPartyManager m) { + rpManager = m; + } + + public void setFilterPolicyManager(FilterPolicyManager m) { + filterPolicyManager = m; + } + + public void setProxyManager(ProxyManager m) { + proxyManager = m; + } + + public void setAccessCtrlManager(AccessCtrlManager m) { + accessCtrlManager = m; + } + + public void setUuidManager(UuidManager m) { + uuidManager = m; + } + + /* utility */ + private boolean userCanEdit(RPSession session, String entityId) throws DNSVerifyException { + return session.adminRole || dnsVerifier.isOwner(entityId, session.remoteUser, null); + } + + private boolean isProperEntityId(RPSession session, String id) { + return (session.adminRole || id.startsWith("http://") || id.startsWith("https://")); + } + + private long getLongHeader(HttpServletRequest request, String name) { + try { + String hdr = request.getHeader(name); + if (hdr == null) return 0; + if (hdr.equals("*")) return (-1); + return Long.parseLong(hdr); + } catch (NumberFormatException e) { + return 0; + } + } + + private String hostPortFromEntityId(String entityId) { + entityId = entityId.replaceFirst("^https?://", ""); + entityId = entityId.replaceFirst("/.*$", ""); + return entityId; + } + + private String dnsFromEntityId(String entityid) { + String dns = entityid; + if (dns.startsWith("http://")) dns = dns.substring(7); + if (dns.startsWith("https://")) dns = dns.substring(8); + int i = dns.indexOf("/"); + if (i > 0) dns = dns.substring(0, i); + i = dns.indexOf(":"); + if (i > 0) dns = dns.substring(0, i); + return dns; + } + + private String cleanString(String in) { + if (in == null) return null; + return in.replaceAll("&", "").replaceAll("<", "").replaceAll(">", ""); + } + + public void setCertRootPath(String path) { + certRootPath = path; + } + + public void setBrowserRootPath(String path) { + browserRootPath = path; + } + + public void setLoginCookie(String v) { + loginCookie = v; + } + + public void setRoleCookie(String v) { + roleCookie = v; + } + + public void setLogoutUrl(String v) { + logoutUrl = v; + } + + public void setCryptKey(String v) { + cryptKey = v; + } + + public void setMailTo(String v) { + log.debug("mailTo = " + v); + mailTo = v; + } + + public void setRequestMailTo(String v) { + requestMailTo = v; + } + + public void setAdminGroupName(String v) { + log.debug("admin group = " + v); + adminGroupName = v; + } + + public void setAuto2faPath(String v) { + auto2faPath = v; + } + + public void setStandardLoginSec(long v) { + standardLoginSec = v; + } + + public void setSecureLoginSec(long v) { + secureLoginSec = v; + } + + public void setStandardLoginPath(String v) { + standardLoginPath = v; + } + + public void setSecureLoginPath(String v) { + secureLoginPath = v; + } + + public void setGoogleIdentityProvider(String v) { + googleIdentityProvider = v; + } + + public void setMyEntityId(String v) { + myEntityId = v; + } + + public void setEppnName(String v) { + eppnName = v; + } + + public void setSpRegistryUrl(String v) { + spRegistryUrl = v; + } + + public static RelyingPartyManager getRelyingPartyManager() { + return rpManager; + } + + /* See if extra login suggested. + */ + /** + * private boolean needMoreAuthn(GwsGroup group, GwsSession session, HttpServletResponse response) { + * if (group.getSecurityLevel()>1 && !session.authn2) { + * log.debug("update needs 2-factor"); + * if (session.isBrowser) response.setStatus(402); + * else response.setStatus(401); + * return true; + * } + * return false; + * } + **/ + public void init() { + log.info("RelyingPartyController init"); + RPCrypt.init(cryptKey); + adminGroup = groupManager.getGroup(adminGroupName); + } + + /* refresh cache groups */ + + @RequestMapping(value = "/ws/refresh", method = RequestMethod.GET) + public ModelAndView getSet(HttpServletRequest request, HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response); + response.setStatus(200); + log.info("refreshing cache groups"); + adminGroup = groupManager.getGroup(adminGroupName); + return emptyMV(); + } + + /* status */ + + @RequestMapping(value = "/status", method = RequestMethod.GET) + public ModelAndView gettatus(HttpServletRequest request, HttpServletResponse response) { + + RPSession session = processRequestInfo(request, response); + response.setStatus(200); + log.info("status request"); + adminGroup = groupManager.getGroup(adminGroupName); + return emptyMV(); + } + + // diagnostic + @RequestMapping(value = "/**", method = RequestMethod.GET) + public ModelAndView homePageStar(HttpServletRequest request, HttpServletResponse response) { + log.info("Star view"); + return homePage(request, response); + } } diff --git a/src/main/java/edu/washington/iam/tools/ComboDNSVerifier.java b/src/main/java/edu/washington/iam/tools/ComboDNSVerifier.java index 93b9575..0d52446 100644 --- a/src/main/java/edu/washington/iam/tools/ComboDNSVerifier.java +++ b/src/main/java/edu/washington/iam/tools/ComboDNSVerifier.java @@ -15,66 +15,60 @@ * ======================================================================== */ - package edu.washington.iam.tools; import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; - - public class ComboDNSVerifier implements DNSVerifier { - private final Logger log = LoggerFactory.getLogger(getClass()); - - private DNSVerifier netVerifier = null; - private DNSVerifier gwsVerifier = null; - - /** - * Test if a user has ownership of a domain - * - * @param id user's uwnetid - * @param domain to test - * @param return list of owners (can be null) - */ - - public boolean isOwner(String entity, String id, List owners) throws DNSVerifyException { - log.debug("combo verify: owner for " + entity); - // maybe strip junk from entity - String dns = entity; - if (dns.startsWith("http://")) dns = dns.substring(7); - if (dns.startsWith("https://")) dns = dns.substring(8); - int i = dns.indexOf("/"); - if (i>0) dns = dns.substring(0,i); - i = dns.indexOf(":"); - if (i>0) dns = dns.substring(0,i); - i = dns.indexOf("?"); - if (i>0) dns = dns.substring(0,i); - - log.debug("looking for owner (" + id + ") in " + dns); - - boolean isNetOwner = netVerifier.isOwner(dns, id, owners); - if (isNetOwner && owners==null) return true; - log.debug("combo verify: gws for " + dns); - boolean isGwsOwner = gwsVerifier.isOwner(dns, id, owners); - if (isNetOwner || isGwsOwner) return true; - return false; - } - - - public boolean isOwner(String dns, String id) throws DNSVerifyException { - return isOwner(dns, id, null); - } - - public void setNetVerifier(DNSVerifier v) { - netVerifier = v; - } - public void setGwsVerifier(DNSVerifier v) { - gwsVerifier = v; - } - public void init() { - } + private final Logger log = LoggerFactory.getLogger(getClass()); + + private DNSVerifier netVerifier = null; + private DNSVerifier gwsVerifier = null; + + /** + * Test if a user has ownership of a domain + * + * @param id user's uwnetid + * @param domain to test + * @param return list of owners (can be null) + */ + public boolean isOwner(String entity, String id, List owners) throws DNSVerifyException { + log.debug("combo verify: owner for " + entity); + // maybe strip junk from entity + String dns = entity; + if (dns.startsWith("http://")) dns = dns.substring(7); + if (dns.startsWith("https://")) dns = dns.substring(8); + int i = dns.indexOf("/"); + if (i > 0) dns = dns.substring(0, i); + i = dns.indexOf(":"); + if (i > 0) dns = dns.substring(0, i); + i = dns.indexOf("?"); + if (i > 0) dns = dns.substring(0, i); + + log.debug("looking for owner (" + id + ") in " + dns); + + boolean isNetOwner = netVerifier.isOwner(dns, id, owners); + if (isNetOwner && owners == null) return true; + log.debug("combo verify: gws for " + dns); + boolean isGwsOwner = gwsVerifier.isOwner(dns, id, owners); + if (isNetOwner || isGwsOwner) return true; + return false; + } + + public boolean isOwner(String dns, String id) throws DNSVerifyException { + return isOwner(dns, id, null); + } + + public void setNetVerifier(DNSVerifier v) { + netVerifier = v; + } + + public void setGwsVerifier(DNSVerifier v) { + gwsVerifier = v; + } + + public void init() {} } diff --git a/src/main/java/edu/washington/iam/tools/DNSVerifier.java b/src/main/java/edu/washington/iam/tools/DNSVerifier.java index ddcb7e2..b873ed8 100644 --- a/src/main/java/edu/washington/iam/tools/DNSVerifier.java +++ b/src/main/java/edu/washington/iam/tools/DNSVerifier.java @@ -15,26 +15,20 @@ * ======================================================================== */ - package edu.washington.iam.tools; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.w3c.dom.Element; - public interface DNSVerifier { - /** - * Test if a user has ownership of a domain - * - * @param id user's uwnetid - * @param domain to test - * @param return list of owners (can be null) - */ + /** + * Test if a user has ownership of a domain + * + * @param id user's uwnetid + * @param domain to test + * @param return list of owners (can be null) + */ + public boolean isOwner(String dns, String id, List owners) throws DNSVerifyException; - public boolean isOwner(String dns, String id, List owners) throws DNSVerifyException; - public boolean isOwner(String dns, String id) throws DNSVerifyException; + public boolean isOwner(String dns, String id) throws DNSVerifyException; } diff --git a/src/main/java/edu/washington/iam/tools/DNSVerifyException.java b/src/main/java/edu/washington/iam/tools/DNSVerifyException.java index e75c242..d455d75 100644 --- a/src/main/java/edu/washington/iam/tools/DNSVerifyException.java +++ b/src/main/java/edu/washington/iam/tools/DNSVerifyException.java @@ -21,12 +21,15 @@ public class DNSVerifyException extends Exception { public DNSVerifyException() { super(); } + public DNSVerifyException(String msg) { super(msg); } + public DNSVerifyException(String msg, Throwable cause) { super(msg, cause); } + public DNSVerifyException(Throwable cause) { super(cause); } diff --git a/src/main/java/edu/washington/iam/tools/Group.java b/src/main/java/edu/washington/iam/tools/Group.java index 6f85420..5f7052b 100644 --- a/src/main/java/edu/washington/iam/tools/Group.java +++ b/src/main/java/edu/washington/iam/tools/Group.java @@ -15,26 +15,25 @@ * ======================================================================== */ - package edu.washington.iam.tools; import java.util.List; import java.util.Vector; public class Group { - public String name; - public List members; - public long mtime; + public String name; + public List members; + public long mtime; - public Group(String n) { - name = n; - members = new Vector(); - mtime = 0; - } + public Group(String n) { + name = n; + members = new Vector(); + mtime = 0; + } - // test membership - public boolean isMember(String user) { - for (int j=0;j names; // cn (1st) + altnames - public Date issued; - public Date expires; - public String pemRequest; - public String pemCert; - public String remHash; - public String dnC; // country code - public String dnST; // state - public int keySize; - public String issuerDn; - public String snStr; // sn as string - - public IamCertificate() { - names = new Vector(); - cn = ""; - dn = ""; - expires = null; - } - public IamCertificate(String pem) throws IamCertificateException { - names = new Vector(); - cn = ""; - dn = ""; - expires = null; - pemCert = pem; - if (!pem.startsWith("-----")) pemCert = "-----BEGIN CERTIFICATE-----\n" + pem + "\n-----END CERTIFICATE-----"; - IamCertificateHelper.parseCert(this); - } - - public int getId() { - return id; - } - public String getCn() { - return cn; - } - public String getDn() { - return dn; - } - public String getCleanDn() { - if (dn!=null) return dn.replaceAll("<","").replaceAll(">","").replaceAll("&",""); - return null; - } - - public String getPemCert() { - return pemCert; - } - public Date getIssued() { - return issued; - } - public Date getExpires() { - return expires; - } - public int getKeySize() { - return keySize; - } - public String getIssuerDn() { - return issuerDn; - } - public String getSnStr() { - return snStr; - } + public int id; // my id + public String cn; // CN from cert + public String dn; // DN from cert + public List names; // cn (1st) + altnames + public Date issued; + public Date expires; + public String pemRequest; + public String pemCert; + public String remHash; + public String dnC; // country code + public String dnST; // state + public int keySize; + public String issuerDn; + public String snStr; // sn as string -} + public IamCertificate() { + names = new Vector(); + cn = ""; + dn = ""; + expires = null; + } + + public IamCertificate(String pem) throws IamCertificateException { + names = new Vector(); + cn = ""; + dn = ""; + expires = null; + pemCert = pem; + if (!pem.startsWith("-----")) + pemCert = "-----BEGIN CERTIFICATE-----\n" + pem + "\n-----END CERTIFICATE-----"; + IamCertificateHelper.parseCert(this); + } + + public int getId() { + return id; + } + + public String getCn() { + return cn; + } + + public String getDn() { + return dn; + } + public String getCleanDn() { + if (dn != null) return dn.replaceAll("<", "").replaceAll(">", "").replaceAll("&", ""); + return null; + } + + public String getPemCert() { + return pemCert; + } + + public Date getIssued() { + return issued; + } + + public Date getExpires() { + return expires; + } + + public int getKeySize() { + return keySize; + } + + public String getIssuerDn() { + return issuerDn; + } + + public String getSnStr() { + return snStr; + } +} diff --git a/src/main/java/edu/washington/iam/tools/IamCertificateException.java b/src/main/java/edu/washington/iam/tools/IamCertificateException.java index dc73544..b622a48 100644 --- a/src/main/java/edu/washington/iam/tools/IamCertificateException.java +++ b/src/main/java/edu/washington/iam/tools/IamCertificateException.java @@ -21,12 +21,15 @@ public class IamCertificateException extends Exception { public IamCertificateException() { super(); } + public IamCertificateException(String msg) { super(msg); } + public IamCertificateException(String msg, Throwable cause) { super(msg, cause); } + public IamCertificateException(Throwable cause) { super(cause); } diff --git a/src/main/java/edu/washington/iam/tools/IamCertificateHelper.java b/src/main/java/edu/washington/iam/tools/IamCertificateHelper.java index 78cb0ca..84416e4 100644 --- a/src/main/java/edu/washington/iam/tools/IamCertificateHelper.java +++ b/src/main/java/edu/washington/iam/tools/IamCertificateHelper.java @@ -17,217 +17,196 @@ package edu.washington.iam.tools; -import java.lang.Exception; import java.io.IOException; -import java.io.InputStream; -import java.util.Iterator; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.Date; -import java.util.Enumeration; -import java.util.Collection; import java.io.StringReader; -import java.io.IOException; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.security.PublicKey; -import java.security.interfaces.RSAPublicKey; -import java.security.cert.X509Certificate; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPublicKey; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; import javax.security.auth.x500.X500Principal; - - -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.jce.PKCS10CertificationRequest; -import org.bouncycastle.asn1.x509.X509Name; -import org.bouncycastle.asn1.pkcs.CertificationRequestInfo; import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.pkcs.CertificationRequestInfo; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.Attribute; -import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.X509Extension; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.asn1.x509.X509Name; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.PKCS10CertificationRequest; +import org.bouncycastle.openssl.PEMParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public final class IamCertificateHelper { - private static final Logger log = LoggerFactory.getLogger(IamCertificateHelper.class); + private static final Logger log = LoggerFactory.getLogger(IamCertificateHelper.class); + + /* extract some info from the submitted CSR */ - /* extract some info from the submitted CSR */ + public static int parseCsr(IamCertificate cert) throws IamCertificateException { - public static int parseCsr(IamCertificate cert) throws IamCertificateException { + try { + PEMParser pRd = new PEMParser(new StringReader(cert.pemRequest)); + PKCS10CertificationRequest request = (PKCS10CertificationRequest) pRd.readObject(); + if (request == null) throw new IamCertificateException("invalid CSR (request)"); + CertificationRequestInfo info = request.getCertificationRequestInfo(); + if (info == null) throw new IamCertificateException("invalid CSR (info)"); + X509Name dn = X509Name.getInstance(info.getSubject()); + if (dn == null) throw new IamCertificateException("invalid CSR (dn)"); + log.debug("dn=" + dn.toString()); + cert.dn = dn.toString(); try { - PEMParser pRd = new PEMParser(new StringReader(cert.pemRequest)); - PKCS10CertificationRequest request = (PKCS10CertificationRequest) pRd.readObject(); - if (request==null) throw new IamCertificateException("invalid CSR (request)"); - CertificationRequestInfo info = request.getCertificationRequestInfo(); - if (info==null) throw new IamCertificateException("invalid CSR (info)"); - - X509Name dn = X509Name.getInstance(info.getSubject()); - if (dn==null) throw new IamCertificateException("invalid CSR (dn)"); - log.debug("dn=" + dn.toString()); - cert.dn = dn.toString(); - try { - List cns = dn.getValues(X509Name.CN); - cert.cn = (String)(cns.get(0)); - log.debug("cn=" + cert.cn); - cert.names.add(cert.cn); // first entry for names is always cn - cns = dn.getValues(X509Name.C); - cert.dnC = (String)(cns.get(0)); - cns = dn.getValues(X509Name.ST); - cert.dnST = (String)(cns.get(0)); - } catch (Exception e) { - log.debug("get cn error: " + e); - throw new IamCertificateException("invalid CSR"); - } - - // see if we've got alt names (in extensions) - - ASN1Set attrs = info.getAttributes(); - if (attrs!=null) { - for (int a=0; a0) cert.cn = cert.names.get(0); - } catch (CertificateParsingException e) { - log.debug("parse error on alt names: " + e); - } - - - // check for expired -/*** - try { - x509.checkValidity(); - } catch (CertificateExpiredException e) { - cert.status = IamCertificate.CERT_STATUS_EXPIRED; - } catch (CertificateNotYetValidException e) { - log.debug("not yet valid?"); - } - ***/ - - // get the key size - PublicKey pk = x509.getPublicKey(); - if (pk.getAlgorithm().equals("RSA")) { - RSAPublicKey rpk = (RSAPublicKey) pk; - cert.keySize = rpk.getModulus().bitLength(); - // log.debug("pub key size = " + cert.keySize); - } - - return 1; - - } catch (IOException e) { - log.info("ioerror: " + e); - throw new IamCertificateException("invalid cert: ioerror"); - } catch (Exception ex) { - log.info("excp: " + ex); - throw new IamCertificateException("invalid cert: excep"); + } + } + if (cert.cn.equals("") && cert.names.size() > 0) cert.cn = cert.names.get(0); + } catch (CertificateParsingException e) { + log.debug("parse error on alt names: " + e); + } + + // check for expired + /*** + * try { + * x509.checkValidity(); + * } catch (CertificateExpiredException e) { + * cert.status = IamCertificate.CERT_STATUS_EXPIRED; + * } catch (CertificateNotYetValidException e) { + * log.debug("not yet valid?"); + * } + ***/ + + // get the key size + PublicKey pk = x509.getPublicKey(); + if (pk.getAlgorithm().equals("RSA")) { + RSAPublicKey rpk = (RSAPublicKey) pk; + cert.keySize = rpk.getModulus().bitLength(); + // log.debug("pub key size = " + cert.keySize); } - } + + return 1; + + } catch (IOException e) { + log.info("ioerror: " + e); + throw new IamCertificateException("invalid cert: ioerror"); + } catch (Exception ex) { + log.info("excp: " + ex); + throw new IamCertificateException("invalid cert: excep"); + } + } } diff --git a/src/main/java/edu/washington/iam/tools/IamConnectionManager.java b/src/main/java/edu/washington/iam/tools/IamConnectionManager.java index bb6d4b3..c883ac8 100644 --- a/src/main/java/edu/washington/iam/tools/IamConnectionManager.java +++ b/src/main/java/edu/washington/iam/tools/IamConnectionManager.java @@ -17,205 +17,201 @@ package edu.washington.iam.tools; -import org.apache.http.config.RegistryBuilder; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.Iterator; - -import java.net.URL; -import java.net.MalformedURLException; - -import javax.net.ssl.*; - import java.io.FileInputStream; import java.io.IOException; - -import java.security.cert.X509Certificate; -import java.security.cert.CertificateFactory; -import java.security.cert.CertificateException; -import java.security.KeyStore; -import java.security.PrivateKey; import java.security.Key; +import java.security.KeyStore; import java.security.KeyStoreException; -import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Iterator; +import javax.net.ssl.*; import org.apache.http.config.Registry; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; - - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Build a connection manager from PEM ca, cert, and key files */ - public class IamConnectionManager { - private String caCertificateFile; - private String certificateFile; - private String keyFile; - - private SSLConnectionSocketFactory socketFactory; - private TrustManager[] trustManagers; - private KeyManager[] keyManagers; - private KeyStore keyStore; - private KeyStore trustStore; - private Registry schemeRegistry; - private PoolingHttpClientConnectionManager connectionManager; - - private static Logger log = LoggerFactory.getLogger(IamConnectionManager.class); - - public IamConnectionManager(String cafile, String certfile, String keyfile) { - log.debug("create connection manager"); - caCertificateFile = cafile; - certificateFile = certfile; - keyFile = keyfile; - String protocol = "https"; - int port = 443; - - initManagers(); - - try { - SSLContext ctx = SSLContext.getInstance("TLS"); - ctx.init(keyManagers, trustManagers, null); - socketFactory = new SSLConnectionSocketFactory(ctx, new NoopHostnameVerifier()); - schemeRegistry = RegistryBuilder. create() - .register("https", socketFactory).build(); - log.debug("create conn mgr"); - connectionManager = new PoolingHttpClientConnectionManager(schemeRegistry); - - } catch (Exception e) { - log.error("sf error: " + e); - } - } - - - public SSLConnectionSocketFactory getSocketFactory() { - log.debug("sr get sock factory"); - return socketFactory; - } - public Registry getSchemeRegistry() { - log.debug("sr get scheme reg"); - return schemeRegistry; - } - public HttpClientConnectionManager getConnectionManager() { - return connectionManager; - } - - protected void __initSocketFactory() { - log.debug("sr sock factory init"); - - TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(X509Certificate[] certs, String authType) { - return; - } - - public void checkServerTrusted(X509Certificate[] certs, String authType) { - log.debug("Trusting server cert"); - return; - } - }}; - - try { - SSLContext sc = SSLContext.getInstance("SSL"); - // sc.init(keyManagers, trustManagers, new java.security.SecureRandom()); - sc.init(keyManagers, trustAllCerts, new java.security.SecureRandom()); - // socketFactory = sc.getSocketFactory(); - } catch (Exception e) { - log.error("mango initSF error: " + e); - } - } - - - protected void initManagers() { - - try { - /* trust managers */ - if (caCertificateFile != null) { - KeyStore trustStore; - int cn = 0; - - // at this point the logger isn't usually running yet - log.info("Setting x509 trust from " + caCertificateFile); - System.out.println("Setting x509 trust from " + caCertificateFile); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - FileInputStream in = new FileInputStream(caCertificateFile); - Collection certs = cf.generateCertificates(in); - - trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - trustStore.load(null, null); - - Iterator cit = certs.iterator(); - while (cit.hasNext()) { - X509Certificate cert = (X509Certificate) cit.next(); - log.info(" adding " + cert.getSubjectX500Principal().toString()); - System.out.println(" adding " + cert.getSubjectX500Principal().toString()); - trustStore.setCertificateEntry("CACERT" + cn, cert); - cn += 1; - } - tmf.init(trustStore); - trustManagers = tmf.getTrustManagers(); - } else { // no verification - trustManagers = new TrustManager[] { new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(X509Certificate[] certs, String authType) { - return; - } - - public void checkServerTrusted(X509Certificate[] certs, String authType) { - return; - } - }}; - } - - /* key manager */ - if (certificateFile != null && keyFile != null) { - KeyStore keyStore; - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(null, null); - - FileInputStream in = new FileInputStream(certificateFile); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) cf.generateCertificate(in); - PKCS1 pkcs = new PKCS1(); - log.info("reading key file: " + keyFile); - PrivateKey key = pkcs.readKey(keyFile); - - X509Certificate[] chain = new X509Certificate[1]; - chain[0] = cert; - keyStore.setKeyEntry("CERT", (Key) key, "pw".toCharArray(), chain); - kmf.init(keyStore, "pw".toCharArray()); - keyManagers = kmf.getKeyManagers(); - } - } catch (IOException e) { - log.error("error reading cert or key error: " + e); - } catch (KeyStoreException e) { - log.error("keystore error: " + e); - } catch (NoSuchAlgorithmException e) { - log.error("sf error: " + e); - } catch (CertificateException e) { - log.error("sf error: " + e); - } catch (UnrecoverableKeyException e) { - log.error("sf error: " + e); + private String caCertificateFile; + private String certificateFile; + private String keyFile; + + private SSLConnectionSocketFactory socketFactory; + private TrustManager[] trustManagers; + private KeyManager[] keyManagers; + private KeyStore keyStore; + private KeyStore trustStore; + private Registry schemeRegistry; + private PoolingHttpClientConnectionManager connectionManager; + + private static Logger log = LoggerFactory.getLogger(IamConnectionManager.class); + + public IamConnectionManager(String cafile, String certfile, String keyfile) { + log.debug("create connection manager"); + caCertificateFile = cafile; + certificateFile = certfile; + keyFile = keyfile; + String protocol = "https"; + int port = 443; + + initManagers(); + + try { + SSLContext ctx = SSLContext.getInstance("TLS"); + ctx.init(keyManagers, trustManagers, null); + socketFactory = new SSLConnectionSocketFactory(ctx, new NoopHostnameVerifier()); + schemeRegistry = + RegistryBuilder.create() + .register("https", socketFactory) + .build(); + log.debug("create conn mgr"); + connectionManager = new PoolingHttpClientConnectionManager(schemeRegistry); + + } catch (Exception e) { + log.error("sf error: " + e); + } + } + + public SSLConnectionSocketFactory getSocketFactory() { + log.debug("sr get sock factory"); + return socketFactory; + } + + public Registry getSchemeRegistry() { + log.debug("sr get scheme reg"); + return schemeRegistry; + } + + public HttpClientConnectionManager getConnectionManager() { + return connectionManager; + } + + protected void __initSocketFactory() { + log.debug("sr sock factory init"); + + TrustManager[] trustAllCerts = + new TrustManager[] { + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) { + return; + } + + public void checkServerTrusted(X509Certificate[] certs, String authType) { + log.debug("Trusting server cert"); + return; + } + } + }; + + try { + SSLContext sc = SSLContext.getInstance("SSL"); + // sc.init(keyManagers, trustManagers, new java.security.SecureRandom()); + sc.init(keyManagers, trustAllCerts, new java.security.SecureRandom()); + // socketFactory = sc.getSocketFactory(); + } catch (Exception e) { + log.error("mango initSF error: " + e); + } + } + + protected void initManagers() { + + try { + /* trust managers */ + if (caCertificateFile != null) { + KeyStore trustStore; + int cn = 0; + + // at this point the logger isn't usually running yet + log.info("Setting x509 trust from " + caCertificateFile); + System.out.println("Setting x509 trust from " + caCertificateFile); + + TrustManagerFactory tmf = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + FileInputStream in = new FileInputStream(caCertificateFile); + Collection certs = cf.generateCertificates(in); + + trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null, null); + + Iterator cit = certs.iterator(); + while (cit.hasNext()) { + X509Certificate cert = (X509Certificate) cit.next(); + log.info(" adding " + cert.getSubjectX500Principal().toString()); + System.out.println(" adding " + cert.getSubjectX500Principal().toString()); + trustStore.setCertificateEntry("CACERT" + cn, cert); + cn += 1; } + tmf.init(trustStore); + trustManagers = tmf.getTrustManagers(); + } else { // no verification + trustManagers = + new TrustManager[] { + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) { + return; + } + + public void checkServerTrusted(X509Certificate[] certs, String authType) { + return; + } + } + }; + } - } - - + /* key manager */ + if (certificateFile != null && keyFile != null) { + KeyStore keyStore; + KeyManagerFactory kmf = + KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, null); + + FileInputStream in = new FileInputStream(certificateFile); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(in); + PKCS1 pkcs = new PKCS1(); + log.info("reading key file: " + keyFile); + PrivateKey key = pkcs.readKey(keyFile); + + X509Certificate[] chain = new X509Certificate[1]; + chain[0] = cert; + keyStore.setKeyEntry("CERT", (Key) key, "pw".toCharArray(), chain); + kmf.init(keyStore, "pw".toCharArray()); + keyManagers = kmf.getKeyManagers(); + } + } catch (IOException e) { + log.error("error reading cert or key error: " + e); + } catch (KeyStoreException e) { + log.error("keystore error: " + e); + } catch (NoSuchAlgorithmException e) { + log.error("sf error: " + e); + } catch (CertificateException e) { + log.error("sf error: " + e); + } catch (UnrecoverableKeyException e) { + log.error("sf error: " + e); + } + } } diff --git a/src/main/java/edu/washington/iam/tools/IamCrypt.java b/src/main/java/edu/washington/iam/tools/IamCrypt.java index 316bc87..d421688 100644 --- a/src/main/java/edu/washington/iam/tools/IamCrypt.java +++ b/src/main/java/edu/washington/iam/tools/IamCrypt.java @@ -19,23 +19,17 @@ package edu.washington.iam.tools; +import java.security.InvalidKeyException; +import java.security.Key; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.InvalidKeyException; import java.security.NoSuchProviderException; -import javax.crypto.IllegalBlockSizeException; import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; -import java.security.Security; -import java.security.Key; -import javax.crypto.KeyGenerator; -import javax.crypto.Cipher; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Base64; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,73 +40,71 @@ public final class IamCrypt { private static Key key; private static Cipher cipher; private static Base64 b64; - private static Logger log = LoggerFactory.getLogger(IamCrypt.class); - private final static String MDAlgorithm = "MD5"; + private static Logger log = LoggerFactory.getLogger(IamCrypt.class); + private static final String MDAlgorithm = "MD5"; public static void init(String secretKey) { - cryptKey = secretKey; - b64 = new Base64(); - String key16 = secretKey + "xxxxxxxxxxxxxxxxxxxxxxx"; - try { - key = new SecretKeySpec(key16.getBytes(), 0, 16, "AES"); - cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); - messageDigest = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - log.error("no algorithm? " + e); - } catch (NoSuchProviderException e) { - log.error("no BC? " + e); - } catch (NoSuchPaddingException e) { - log.error("no BC? " + e); - } + cryptKey = secretKey; + b64 = new Base64(); + String key16 = secretKey + "xxxxxxxxxxxxxxxxxxxxxxx"; + try { + key = new SecretKeySpec(key16.getBytes(), 0, 16, "AES"); + cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); + messageDigest = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException e) { + log.error("no algorithm? " + e); + } catch (NoSuchProviderException e) { + log.error("no BC? " + e); + } catch (NoSuchPaddingException e) { + log.error("no BC? " + e); + } } public static synchronized String genMD(String in) { - messageDigest.reset(); - byte[] bt = in.getBytes(); - // messageDigest.update(bt); - String md = new String( b64.encode(messageDigest.digest(bt))); - // log.debug("md of " + in + " = " + md); - messageDigest.reset(); - return (md); + messageDigest.reset(); + byte[] bt = in.getBytes(); + // messageDigest.update(bt); + String md = new String(b64.encode(messageDigest.digest(bt))); + // log.debug("md of " + in + " = " + md); + messageDigest.reset(); + return (md); } public static synchronized String encode(String in) { - byte[] bt = in.getBytes(); - try { - cipher.init(Cipher.ENCRYPT_MODE, key); - String out = new String(b64.encode(cipher.doFinal(bt))); - // log.debug("encode: " + in + " to " + out); - return out; - } catch (InvalidKeyException e) { - log.error("encode: " + e); - return null; - } catch (IllegalBlockSizeException e) { - log.error("encode: " + e); - return null; - } catch (BadPaddingException e) { - log.error("encode: " + e); - return null; - } + byte[] bt = in.getBytes(); + try { + cipher.init(Cipher.ENCRYPT_MODE, key); + String out = new String(b64.encode(cipher.doFinal(bt))); + // log.debug("encode: " + in + " to " + out); + return out; + } catch (InvalidKeyException e) { + log.error("encode: " + e); + return null; + } catch (IllegalBlockSizeException e) { + log.error("encode: " + e); + return null; + } catch (BadPaddingException e) { + log.error("encode: " + e); + return null; + } } public static synchronized String decode(String in) { - byte[] inb = b64.decode(in); - try { - cipher.init(Cipher.DECRYPT_MODE, key); - String out = new String(cipher.doFinal(inb)); - // log.debug("decode: " + in + " to " + out); - return out; - } catch (InvalidKeyException e) { - log.error("encode: " + e); - return null; - } catch (IllegalBlockSizeException e) { - log.error("encode: " + e); - return null; - } catch (BadPaddingException e) { - log.error("encode: " + e); - return null; - } + byte[] inb = b64.decode(in); + try { + cipher.init(Cipher.DECRYPT_MODE, key); + String out = new String(cipher.doFinal(inb)); + // log.debug("decode: " + in + " to " + out); + return out; + } catch (InvalidKeyException e) { + log.error("encode: " + e); + return null; + } catch (IllegalBlockSizeException e) { + log.error("encode: " + e); + return null; + } catch (BadPaddingException e) { + log.error("encode: " + e); + return null; + } } - } - diff --git a/src/main/java/edu/washington/iam/tools/IamMailMessage.java b/src/main/java/edu/washington/iam/tools/IamMailMessage.java index 7cc29b6..cef2e93 100644 --- a/src/main/java/edu/washington/iam/tools/IamMailMessage.java +++ b/src/main/java/edu/washington/iam/tools/IamMailMessage.java @@ -17,101 +17,102 @@ package edu.washington.iam.tools; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - // mail message extension // mostly holds parameters public class IamMailMessage { - private String from; - private String replyTo; - private String to; // comma separated lists - private String cc; - private String bcc; - private String subject; - private String text; - - // substution values - private String certcn = ""; - private String certid = ""; - private String issuer = ""; - - public void setSubstitutions(String cn, String id, String is) { - this.certcn = cn; - this.certid = id; - this.issuer = is; - } - public String makeSubstitutions(String text) { - return text.replaceAll("CERTCN",certcn).replaceAll("CERTID",certid).replaceAll("NL","\n").replaceAll("ISSUER",issuer); - } - - public IamMailMessage() { - } - - public IamMailMessage(IamMailMessage src) { - this.from = src.getFrom(); - this.replyTo = src.getReplyTo(); - this.to = src.getTo(); - this.cc = src.getCc(); - this.bcc = src.getBcc(); - this.subject = src.getSubject(); - this.text = src.getText(); - } - - public void setFrom(String from) { - this.from = from; - } - public String getFrom() { - return this.from; - } - - public void setReplyTo(String replyTo) { + private String from; + private String replyTo; + private String to; // comma separated lists + private String cc; + private String bcc; + private String subject; + private String text; + + // substution values + private String certcn = ""; + private String certid = ""; + private String issuer = ""; + + public void setSubstitutions(String cn, String id, String is) { + this.certcn = cn; + this.certid = id; + this.issuer = is; + } + + public String makeSubstitutions(String text) { + return text.replaceAll("CERTCN", certcn) + .replaceAll("CERTID", certid) + .replaceAll("NL", "\n") + .replaceAll("ISSUER", issuer); + } + + public IamMailMessage() {} + + public IamMailMessage(IamMailMessage src) { + this.from = src.getFrom(); + this.replyTo = src.getReplyTo(); + this.to = src.getTo(); + this.cc = src.getCc(); + this.bcc = src.getBcc(); + this.subject = src.getSubject(); + this.text = src.getText(); + } + + public void setFrom(String from) { + this.from = from; + } + + public String getFrom() { + return this.from; + } + + public void setReplyTo(String replyTo) { this.replyTo = replyTo; - } - - public String getReplyTo() { - return replyTo; - } - - public void setTo(String to) { - this.to = to; - } - public String getTo() { - return to; - } - - - public void setCc(String cc) { - this.cc = cc; - } - - public String getCc() { - return cc; - } - - public void setBcc(String bcc) { - this.bcc = bcc; - } - public String getBcc() { - return bcc; - } - - public void setSubject(String subject) { - this.subject = subject; - } - public String getSubject() { - return this.subject; - } - - - public void setText(String text) { - this.text = text; - } - public String getText() { - return this.text; - } + } -} + public String getReplyTo() { + return replyTo; + } + + public void setTo(String to) { + this.to = to; + } + + public String getTo() { + return to; + } + + public void setCc(String cc) { + this.cc = cc; + } + + public String getCc() { + return cc; + } + public void setBcc(String bcc) { + this.bcc = bcc; + } + + public String getBcc() { + return bcc; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getSubject() { + return this.subject; + } + + public void setText(String text) { + this.text = text; + } + + public String getText() { + return this.text; + } +} diff --git a/src/main/java/edu/washington/iam/tools/IamMailSender.java b/src/main/java/edu/washington/iam/tools/IamMailSender.java index 603a1ff..5a7bd03 100644 --- a/src/main/java/edu/washington/iam/tools/IamMailSender.java +++ b/src/main/java/edu/washington/iam/tools/IamMailSender.java @@ -17,89 +17,85 @@ package edu.washington.iam.tools; +import com.sun.mail.smtp.SMTPSenderFailedException; import java.util.List; import java.util.Vector; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.mail.MailException; -import org.springframework.mail.MailSender; -import org.springframework.mail.javamail.JavaMailSender; import javax.mail.Address; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.InternetAddress; import javax.mail.Message.RecipientType; import javax.mail.MessagingException; - -import edu.washington.iam.tools.DNSVerifier; -import edu.washington.iam.tools.DNSVerifyException; -import com.sun.mail.smtp.SMTPSenderFailedException; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.javamail.JavaMailSender; // local interface to java mail sender public class IamMailSender { - private final Logger log = LoggerFactory.getLogger(getClass()); + private final Logger log = LoggerFactory.getLogger(getClass()); - private JavaMailSender mailSender; - public void setMailSender(JavaMailSender mailSender) { - this.mailSender = mailSender; - } - private String replyTo = "iam-support@uw.edu"; - public void setReplyTo(String replyTo) { - this.replyTo = replyTo; - } - private String from = "SP Registry "; - public void setFrom(String from) { - this.from = from; - } + private JavaMailSender mailSender; - // create a standard message with the headers - private MimeMessage genMimeMessage(IamMailMessage msg) { - MimeMessage mime = mailSender.createMimeMessage(); - try { - mime.setRecipients(RecipientType.TO, InternetAddress.parse(msg.getTo())); - mime.setSubject(msg.makeSubstitutions(msg.getSubject())); - mime.setReplyTo(InternetAddress.parse(replyTo)); - mime.setFrom(new InternetAddress(msg.getFrom())); - mime.addHeader("X-Auto-Response-Suppress", "NDR, OOF, AutoReply"); - mime.addHeader("Precedence", "Special-Delivery, never-bounce"); - mime.setText(msg.makeSubstitutions(msg.getText())); - } catch (MessagingException e) { - log.error("iam mail build fails: " + e); - } - return mime; - } + public void setMailSender(JavaMailSender mailSender) { + this.mailSender = mailSender; + } - // send mail - public void send(IamMailMessage msg) { - MimeMessage mime = genMimeMessage(msg); - mailSender.send(mime); - } + private String replyTo = "iam-support@uw.edu"; - // send mail with owner cc - public void sendWithOwnerCc(IamMailMessage msg, DNSVerifier verifier, List cns) { + public void setReplyTo(String replyTo) { + this.replyTo = replyTo; + } - MimeMessage mime = genMimeMessage(msg); - try { - List owners = new Vector(); - for (int i=0; i cns) { + + MimeMessage mime = genMimeMessage(msg); + try { + List owners = new Vector(); + for (int i = 0; i < cns.size(); i++) verifier.isOwner(cns.get(i), null, owners); + Address[] oAddrs = new Address[owners.size()]; + for (int i = 0; i < owners.size(); i++) { + oAddrs[i] = new InternetAddress(owners.get(i) + "@uw.edu"); + // log.debug(" cc to: " + owners.get(i)); + } + mime.setRecipients(RecipientType.CC, oAddrs); + mailSender.send(mime); + } catch (DNSVerifyException ex) { + log.error("checking dns: " + ex.getMessage()); + } catch (SMTPSenderFailedException e) { + log.error("cannot send email: " + e); + } catch (MessagingException e) { + log.error("iam mail failure: " + e); + } + } +} diff --git a/src/main/java/edu/washington/iam/tools/IamVelocityConfig.java b/src/main/java/edu/washington/iam/tools/IamVelocityConfig.java index ae502d5..6dca978 100644 --- a/src/main/java/edu/washington/iam/tools/IamVelocityConfig.java +++ b/src/main/java/edu/washington/iam/tools/IamVelocityConfig.java @@ -14,16 +14,16 @@ */ public class IamVelocityConfig implements VelocityConfig { - private VelocityEngine velocityEngine; + private VelocityEngine velocityEngine; - public IamVelocityConfig() {} + public IamVelocityConfig() {} - @Override - public VelocityEngine getVelocityEngine() { - return velocityEngine; - } + @Override + public VelocityEngine getVelocityEngine() { + return velocityEngine; + } - public void setVelocityEngine(VelocityEngine velocityEngine) { - this.velocityEngine = velocityEngine; - } + public void setVelocityEngine(VelocityEngine velocityEngine) { + this.velocityEngine = velocityEngine; + } } diff --git a/src/main/java/edu/washington/iam/tools/IdpHelper.java b/src/main/java/edu/washington/iam/tools/IdpHelper.java index 7b77c2e..96b3118 100644 --- a/src/main/java/edu/washington/iam/tools/IdpHelper.java +++ b/src/main/java/edu/washington/iam/tools/IdpHelper.java @@ -15,90 +15,62 @@ * ======================================================================== */ - package edu.washington.iam.tools; -import java.util.List; import java.util.ArrayList; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.http.entity.StringEntity; +import java.util.List; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; - -import org.apache.http.client.ResponseHandler; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.BasicResponseHandler; -import org.apache.http.impl.client.DefaultHttpClient; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.util.EntityUtils; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.params.BasicHttpParams; - -import edu.washington.iam.tools.WebClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; // google-gson -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonElement; -import com.google.gson.JsonArray; -import com.google.gson.JsonPrimitive; - public class IdpHelper { - private final Logger log = LoggerFactory.getLogger(getClass()); - - private static String[] idpHosts; - private static String refreshUrl; - private WebClient webClient; + private final Logger log = LoggerFactory.getLogger(getClass()); - /** - * Notify IdPs of metadata or filter update - * - */ + private static String[] idpHosts; + private static String refreshUrl; + private WebClient webClient; - public boolean notifyIdps(String type) { + /** + * Notify IdPs of metadata or filter update + * + */ + public boolean notifyIdps(String type) { - int status = 0; - List data = new ArrayList(); - data.add(new BasicNameValuePair("type", type)); + int status = 0; + List data = new ArrayList(); + data.add(new BasicNameValuePair("type", type)); - log.debug("notify IdPs of update"); + log.debug("notify IdPs of update"); - try { - for ( String host : idpHosts ) { - String url = String.format(refreshUrl, host); - status = webClient.simpleRestPut(url, data); - log.debug(String.format("got: %d", status)); - } + try { + for (String host : idpHosts) { + String url = String.format(refreshUrl, host); + status = webClient.simpleRestPut(url, data); + log.debug(String.format("got: %d", status)); + } - } catch (Exception e) { - log.debug("idp notify error: " + e); - } - - return status==200; + } catch (Exception e) { + log.debug("idp notify error: " + e); } - public void setWebClient(WebClient v) { - webClient = v; - } - public void setIdpHosts(String[] v) { - idpHosts = v; - } - public void setRefreshUrl(String v) { - refreshUrl = v; - } + return status == 200; + } - public void init() { - } + public void setWebClient(WebClient v) { + webClient = v; + } + + public void setIdpHosts(String[] v) { + idpHosts = v; + } + + public void setRefreshUrl(String v) { + refreshUrl = v; + } + + public void init() {} } - diff --git a/src/main/java/edu/washington/iam/tools/PKCS1.java b/src/main/java/edu/washington/iam/tools/PKCS1.java index ff34cd4..3cd437e 100644 --- a/src/main/java/edu/washington/iam/tools/PKCS1.java +++ b/src/main/java/edu/washington/iam/tools/PKCS1.java @@ -8,9 +8,8 @@ */ /** note: presently doesn't look fo rthe 'PRIVATE KEY' line, - so the key file can have ONLY a private key + * so the key file can have ONLY a private key **/ - package edu.washington.iam.tools; import java.io.EOFException; @@ -22,153 +21,162 @@ import java.security.PrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAPrivateCrtKeySpec; - import org.bouncycastle.util.encoders.Base64; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - class PKCS1 { - int pos; - byte[] code; - BigInteger[] ints; - - private static Logger log = LoggerFactory.getLogger(PKCS1.class); - - public PKCS1() { } - - RSAPrivateCrtKeySpec keySpec() { - return new RSAPrivateCrtKeySpec(ints[0] // modulus - , ints[1] // publicExponent - , ints[2] // privateExponent - , ints[3] // primeP - , ints[4] // primeQ - , ints[5] // primeExponentP - , ints[6] // primeExponentQ - , ints[7] // crtCoefficient - ); - } - int rdLen() throws IOException { - int t; - if ((code[pos] & 0x80) == 0x80) { - int n = (int) code[pos] & 0x7f; - pos = pos + 1; - t = rdLongLen(n); - } else { - t = (int) code[pos]; - pos = pos + 1; - } - return t; - } - int rdLongLen(int n) throws IOException { - int r = 0; - for (int i = 0; i < n; ++i) { - r = (r << 8) | (code[pos] & 0xff); - pos = pos + 1; - } - return r; - } - void skipInteger() throws IOException { - if (code[pos] != 2) - throw new IOException("encountered invalid integer tag " - + ((int) code[pos]) + " at " + pos); - pos = pos + 1; - int len = rdLen(); - pos = pos + len; - } - BigInteger rdInteger() throws IOException { - if (pos >= code.length) - throw new EOFException("end of file at " + pos); - if (code[pos] != 2) - throw new IOException("encountered invalid integer tag " - + ((int) code[pos]) + " at " + pos); - pos = pos + 1; - int len = rdLen(); - byte[] x = new byte[len]; - System.arraycopy(code, pos, x, 0, len); - pos = pos + len; - return new BigInteger(x); - } - void rdKey(int nb) throws IOException { - ints = new BigInteger[8]; - skipInteger(); // version - for (int i = 0; i < 8; ++i) - ints[i] = rdInteger(); - } - public void extractIntegers(byte[] data) throws IOException { - pos = 0; - code = data; - if (code[pos] == 0x30) { - pos = 1; - int nb = rdLen(); - rdKey(nb); - } else - throw new IOException("invalid private key leading tag " - + (int) code[pos]); - } - char[] readWrappedBody(String name) throws IOException { - FileReader file = new FileReader(name); - char[] ba = new char[20480]; - int i; - StringBuffer banner = null; - boolean bnl = false; - boolean knl = false; - try { - for (i = 0; i < 20480; ) { - int ic = file.read(); - char c = (char) ic; - if (ic < 0) break; - else if (c == '\n') { - if (bnl) { // processing a banner? - bnl = false; - if (banner.indexOf("PRIVATE KEY")>0) knl = true; - } - } else if (bnl) { - banner.append(c); - } else if (c=='-') { - bnl = true; - if (knl) break; // done with key - banner = new StringBuffer(128); - } else if (knl) { - ba[i++] = c; - } - } - file.close(); - char[] contents = new char[i]; - System.arraycopy(ba, 0, contents, 0, i); - log.debug("readWrapped done, length = " + i); - return contents; - } catch (Exception e) { - log.debug("readWrapped error: " + e); - } - return null; - } - byte[] readDecodedBytes(String name) throws IOException { - char[] ba = readWrappedBody(name); - int n = ba.length; - // return new BASE64Decoder().decodeBuffer(new String(ba, 0, n)); - return new Base64().decode(new String(ba, 0, n)); - } - RSAPrivateCrtKeySpec readKeyFile(String name) throws IOException { - byte[] data = readDecodedBytes(name); - extractIntegers(data); - return keySpec(); - } - public PrivateKey readKey(String name) throws IOException { - RSAPrivateCrtKeySpec sp = readKeyFile(name); - KeyFactory kf; - try { - kf = KeyFactory.getInstance("RSA"); - } catch (NoSuchAlgorithmException e) { - throw new IOException("RSA: " + e.toString()); - } - PrivateKey pk; - try { - pk = kf.generatePrivate(sp); - } catch (InvalidKeySpecException e) { - throw new IOException(e.toString()); - } - return pk; - } + int pos; + byte[] code; + BigInteger[] ints; + + private static Logger log = LoggerFactory.getLogger(PKCS1.class); + + public PKCS1() {} + + RSAPrivateCrtKeySpec keySpec() { + return new RSAPrivateCrtKeySpec( + ints[0] // modulus + , + ints[1] // publicExponent + , + ints[2] // privateExponent + , + ints[3] // primeP + , + ints[4] // primeQ + , + ints[5] // primeExponentP + , + ints[6] // primeExponentQ + , + ints[7] // crtCoefficient + ); + } + + int rdLen() throws IOException { + int t; + if ((code[pos] & 0x80) == 0x80) { + int n = (int) code[pos] & 0x7f; + pos = pos + 1; + t = rdLongLen(n); + } else { + t = (int) code[pos]; + pos = pos + 1; + } + return t; + } + + int rdLongLen(int n) throws IOException { + int r = 0; + for (int i = 0; i < n; ++i) { + r = (r << 8) | (code[pos] & 0xff); + pos = pos + 1; + } + return r; + } + + void skipInteger() throws IOException { + if (code[pos] != 2) + throw new IOException("encountered invalid integer tag " + ((int) code[pos]) + " at " + pos); + pos = pos + 1; + int len = rdLen(); + pos = pos + len; + } + + BigInteger rdInteger() throws IOException { + if (pos >= code.length) throw new EOFException("end of file at " + pos); + if (code[pos] != 2) + throw new IOException("encountered invalid integer tag " + ((int) code[pos]) + " at " + pos); + pos = pos + 1; + int len = rdLen(); + byte[] x = new byte[len]; + System.arraycopy(code, pos, x, 0, len); + pos = pos + len; + return new BigInteger(x); + } + + void rdKey(int nb) throws IOException { + ints = new BigInteger[8]; + skipInteger(); // version + for (int i = 0; i < 8; ++i) ints[i] = rdInteger(); + } + + public void extractIntegers(byte[] data) throws IOException { + pos = 0; + code = data; + if (code[pos] == 0x30) { + pos = 1; + int nb = rdLen(); + rdKey(nb); + } else throw new IOException("invalid private key leading tag " + (int) code[pos]); + } + + char[] readWrappedBody(String name) throws IOException { + FileReader file = new FileReader(name); + char[] ba = new char[20480]; + int i; + StringBuffer banner = null; + boolean bnl = false; + boolean knl = false; + try { + for (i = 0; i < 20480; ) { + int ic = file.read(); + char c = (char) ic; + if (ic < 0) break; + else if (c == '\n') { + if (bnl) { // processing a banner? + bnl = false; + if (banner.indexOf("PRIVATE KEY") > 0) knl = true; + } + } else if (bnl) { + banner.append(c); + } else if (c == '-') { + bnl = true; + if (knl) break; // done with key + banner = new StringBuffer(128); + } else if (knl) { + ba[i++] = c; + } + } + file.close(); + char[] contents = new char[i]; + System.arraycopy(ba, 0, contents, 0, i); + log.debug("readWrapped done, length = " + i); + return contents; + } catch (Exception e) { + log.debug("readWrapped error: " + e); + } + return null; + } + + byte[] readDecodedBytes(String name) throws IOException { + char[] ba = readWrappedBody(name); + int n = ba.length; + // return new BASE64Decoder().decodeBuffer(new String(ba, 0, n)); + return new Base64().decode(new String(ba, 0, n)); + } + + RSAPrivateCrtKeySpec readKeyFile(String name) throws IOException { + byte[] data = readDecodedBytes(name); + extractIntegers(data); + return keySpec(); + } + + public PrivateKey readKey(String name) throws IOException { + RSAPrivateCrtKeySpec sp = readKeyFile(name); + KeyFactory kf; + try { + kf = KeyFactory.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + throw new IOException("RSA: " + e.toString()); + } + PrivateKey pk; + try { + pk = kf.generatePrivate(sp); + } catch (InvalidKeySpecException e) { + throw new IOException(e.toString()); + } + return pk; + } } diff --git a/src/main/java/edu/washington/iam/tools/WebClient.java b/src/main/java/edu/washington/iam/tools/WebClient.java index 41607da..8bcf5ea 100644 --- a/src/main/java/edu/washington/iam/tools/WebClient.java +++ b/src/main/java/edu/washington/iam/tools/WebClient.java @@ -15,328 +15,326 @@ * ======================================================================== */ - package edu.washington.iam.tools; -import java.io.Serializable; -import java.io.InputStream; import java.io.IOException; import java.net.SocketTimeoutException; - import java.util.List; -import java.util.Vector; -import java.util.ArrayList; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.http.client.config.RequestConfig; -import org.apache.http.entity.StringEntity; -import org.apache.http.NameValuePair; - -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.entity.UrlEncodedFormEntity; - - -import org.apache.http.impl.client.DefaultHttpClient; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; - import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; -import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.util.EntityUtils; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ClientConnectionManager; - import org.apache.http.conn.HttpClientConnectionManager; - +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.HttpClients; - import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; - - +import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; - -import edu.washington.iam.tools.XMLHelper; public class WebClient { - private final Logger log = LoggerFactory.getLogger(getClass()); - private final ReentrantReadWriteLock locker = new ReentrantReadWriteLock(); - - // connection params - private String certFile = null; - private String keyFile = null; - private String caFile = null; - private int queryTimeLimit = 15000; // fifteen seconds default - - //private ClientConnectionManager connectionManager; - private HttpClientConnectionManager connectionManager; - private boolean initialized = false; - private DocumentBuilder documentBuilder; - - DefaultHttpClient soapclient = null; - CloseableHttpClient restclient = null; - - HttpParams httpParams = null; - - // - private String soapHeader = "" + - "" + - ""; - private String soapTrailer = ""; - - // "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + - // "xmlns:tns=\"http://ssl.ws.epki.comodo.com/\" " + - - public void closeIdleConnections() { - // log.debug("closing idle"); - connectionManager.closeExpiredConnections(); - connectionManager.closeIdleConnections(30, TimeUnit.SECONDS); - } - - public Element doSoapRequest(String url, String action, String body) { - - closeIdleConnections(); - - // log.debug("do soap: " + action); - Element ele = null; - // DefaultHttpClient soapclient = new DefaultHttpClient((ClientConnectionManager)connectionManager, new BasicHttpParams()); - if (soapclient==null) soapclient = new DefaultHttpClient((ClientConnectionManager)connectionManager, new BasicHttpParams()); - // soapclient.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false); - - try { - - // log.debug(" url: " + url); - // log.debug("content: [" + soapHeader + body + soapTrailer + "]"); - - HttpPost httppost = new HttpPost(url); - httppost.addHeader("SOAPAction", action); - - StringEntity strent= new StringEntity(soapHeader + body + soapTrailer); - strent.setContentType("text/xml; charset=utf-8"); - httppost.setEntity(strent); - - CloseableHttpResponse response = soapclient.execute(httppost); - - if (response.getStatusLine().getStatusCode()>=400) { - log.error("soap error: " + response.getStatusLine().getStatusCode() + " = " + response.getStatusLine().getReasonPhrase()); - throw new WebClientException("soap error"); - } - HttpEntity entity = response.getEntity(); - - // null is error - should get something - if (entity == null) { - throw new WebClientException("soapclient post exception"); - } - - // log.debug("got " + entity.getContentLength() + " bytes"); - // parse response text - Document doc = documentBuilder.parse(entity.getContent()); - - ele = XMLHelper.getElementByName(doc.getDocumentElement(), "Body"); - if (ele == null) { - log.error("no body element"); - throw new WebClientException("no body element?"); - } - } catch (Exception e) { - log.error("exception " + e); - } - return ele; + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ReentrantReadWriteLock locker = new ReentrantReadWriteLock(); + + // connection params + private String certFile = null; + private String keyFile = null; + private String caFile = null; + private int queryTimeLimit = 15000; // fifteen seconds default + + // private ClientConnectionManager connectionManager; + private HttpClientConnectionManager connectionManager; + private boolean initialized = false; + private DocumentBuilder documentBuilder; + + DefaultHttpClient soapclient = null; + CloseableHttpClient restclient = null; + + HttpParams httpParams = null; + + // + private String soapHeader = + "" + + "" + + ""; + private String soapTrailer = ""; + + // "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + + // "xmlns:tns=\"http://ssl.ws.epki.comodo.com/\" " + + + public void closeIdleConnections() { + // log.debug("closing idle"); + connectionManager.closeExpiredConnections(); + connectionManager.closeIdleConnections(30, TimeUnit.SECONDS); + } + + public Element doSoapRequest(String url, String action, String body) { + + closeIdleConnections(); + + // log.debug("do soap: " + action); + Element ele = null; + // DefaultHttpClient soapclient = new + // DefaultHttpClient((ClientConnectionManager)connectionManager, new BasicHttpParams()); + if (soapclient == null) + soapclient = + new DefaultHttpClient((ClientConnectionManager) connectionManager, new BasicHttpParams()); + // soapclient.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false); + + try { + + // log.debug(" url: " + url); + // log.debug("content: [" + soapHeader + body + soapTrailer + "]"); + + HttpPost httppost = new HttpPost(url); + httppost.addHeader("SOAPAction", action); + + StringEntity strent = new StringEntity(soapHeader + body + soapTrailer); + strent.setContentType("text/xml; charset=utf-8"); + httppost.setEntity(strent); + + CloseableHttpResponse response = soapclient.execute(httppost); + + if (response.getStatusLine().getStatusCode() >= 400) { + log.error( + "soap error: " + + response.getStatusLine().getStatusCode() + + " = " + + response.getStatusLine().getReasonPhrase()); + throw new WebClientException("soap error"); + } + HttpEntity entity = response.getEntity(); + + // null is error - should get something + if (entity == null) { + throw new WebClientException("soapclient post exception"); + } + + // log.debug("got " + entity.getContentLength() + " bytes"); + // parse response text + Document doc = documentBuilder.parse(entity.getContent()); + + ele = XMLHelper.getElementByName(doc.getDocumentElement(), "Body"); + if (ele == null) { + log.error("no body element"); + throw new WebClientException("no body element?"); + } + } catch (Exception e) { + log.error("exception " + e); } + return ele; + } - public Element doRestGet(String url, String auth) { - - closeIdleConnections(); - - // log.debug("do rest get"); - Element ele = null; - if (restclient==null) - { - restclient = HttpClients.custom() - .setConnectionManager(connectionManager).build(); - // restclient = new DefaultHttpClient((HttpClientConnectionManager)connectionManager, new BasicHttpParams()); - } - try { - - // log.debug(" rest get, url: " + url); - // log.debug(" auth: " + auth); - - HttpGet httpget = new HttpGet(url); - if (auth!=null) httpget.addHeader("Authorization", auth); - httpget.addHeader("Accept", "text/xml"); - - CloseableHttpResponse response = restclient.execute((HttpUriRequest)httpget); - log.debug(" rest get, rsp: " + response.getStatusLine().getStatusCode()); - // httpget.releaseConnection(); - if (response.getStatusLine().getStatusCode()==404) { - // log.error("rest, url not found"); - response.close(); - return null; - } - if (response.getStatusLine().getStatusCode()>=400) { - // log.error("rest error: " + response.getStatusLine().getStatusCode() + " = " + response.getStatusLine().getReasonPhrase()); - response.close(); - throw new WebClientException("rest error"); - } - HttpEntity entity = response.getEntity(); - - // null is error - should get something - if (entity == null) { - response.close(); - throw new WebClientException("restclient get exception"); - } - - // parse response text - Document doc = documentBuilder.parse(entity.getContent()); - ele = doc.getDocumentElement(); - response.close(); - } catch (Exception e) { - log.error("exception " + e); - } - return ele; - } + public Element doRestGet(String url, String auth) { - public Element doRestGet(String url) { - return doRestGet(url, null); - } + closeIdleConnections(); - // return status - public int simpleRestPut(String url, List data) { - - closeIdleConnections(); - log.debug("simple rest put"); - int status = 0; - Element ele = null; - if (restclient==null) restclient = new DefaultHttpClient((ClientConnectionManager)connectionManager, new BasicHttpParams()); - try { - - HttpPut httpput = new HttpPut(url); - httpput.setEntity(new UrlEncodedFormEntity(data)); - - CloseableHttpResponse response = restclient.execute(httpput); - - log.debug("resp: " + response.getStatusLine().getStatusCode() + " = " + response.getStatusLine().getReasonPhrase()); - status = response.getStatusLine().getStatusCode(); - response.close(); - } catch (Exception e) { - log.error("exception " + e); - } - return status; + // log.debug("do rest get"); + Element ele = null; + if (restclient == null) { + restclient = HttpClients.custom().setConnectionManager(connectionManager).build(); + // restclient = new DefaultHttpClient((HttpClientConnectionManager)connectionManager, new + // BasicHttpParams()); } - - // simple rest get - public String simpleRestGet(String url) - throws SocketTimeoutException, WebClientException { - - closeIdleConnections(); - - // log.debug("simple rest get"); - try { - - RequestConfig httpParams = RequestConfig.custom() - .setConnectTimeout(queryTimeLimit) - .setSocketTimeout(queryTimeLimit).build(); - CloseableHttpClient httpclient = HttpClients.custom() - .setDefaultRequestConfig(httpParams) - .setConnectionManager(connectionManager).build(); - - - // log.debug(" url: " + url); - HttpGet httpget = new HttpGet(url); - HttpResponse response = httpclient.execute(httpget); - log.debug("resp: " + response.getStatusLine().getStatusCode() + " = " + response.getStatusLine().getReasonPhrase()); - - HttpEntity entity = response.getEntity(); - - // null is error - should get something - if (entity == null) { - throw new WebClientException("httpclient post exception"); - } - String resp = EntityUtils.toString(entity); - // log.debug(" got: " + resp); - return (resp); - } catch (IOException e) { - log.error("io error " + e.getMessage()); - } - return null; + try { + + // log.debug(" rest get, url: " + url); + // log.debug(" auth: " + auth); + + HttpGet httpget = new HttpGet(url); + if (auth != null) httpget.addHeader("Authorization", auth); + httpget.addHeader("Accept", "text/xml"); + + CloseableHttpResponse response = restclient.execute((HttpUriRequest) httpget); + log.debug(" rest get, rsp: " + response.getStatusLine().getStatusCode()); + // httpget.releaseConnection(); + if (response.getStatusLine().getStatusCode() == 404) { + // log.error("rest, url not found"); + response.close(); + return null; + } + if (response.getStatusLine().getStatusCode() >= 400) { + // log.error("rest error: " + response.getStatusLine().getStatusCode() + " = " + + // response.getStatusLine().getReasonPhrase()); + response.close(); + throw new WebClientException("rest error"); + } + HttpEntity entity = response.getEntity(); + + // null is error - should get something + if (entity == null) { + response.close(); + throw new WebClientException("restclient get exception"); + } + + // parse response text + Document doc = documentBuilder.parse(entity.getContent()); + ele = doc.getDocumentElement(); + response.close(); + } catch (Exception e) { + log.error("exception " + e); + } + return ele; + } + + public Element doRestGet(String url) { + return doRestGet(url, null); + } + + // return status + public int simpleRestPut(String url, List data) { + + closeIdleConnections(); + log.debug("simple rest put"); + int status = 0; + Element ele = null; + if (restclient == null) + restclient = + new DefaultHttpClient((ClientConnectionManager) connectionManager, new BasicHttpParams()); + try { + + HttpPut httpput = new HttpPut(url); + httpput.setEntity(new UrlEncodedFormEntity(data)); + + CloseableHttpResponse response = restclient.execute(httpput); + + log.debug( + "resp: " + + response.getStatusLine().getStatusCode() + + " = " + + response.getStatusLine().getReasonPhrase()); + status = response.getStatusLine().getStatusCode(); + response.close(); + } catch (Exception e) { + log.error("exception " + e); } + return status; + } + + // simple rest get + public String simpleRestGet(String url) throws SocketTimeoutException, WebClientException { + + closeIdleConnections(); + + // log.debug("simple rest get"); + try { + + RequestConfig httpParams = + RequestConfig.custom() + .setConnectTimeout(queryTimeLimit) + .setSocketTimeout(queryTimeLimit) + .build(); + CloseableHttpClient httpclient = + HttpClients.custom() + .setDefaultRequestConfig(httpParams) + .setConnectionManager(connectionManager) + .build(); + + // log.debug(" url: " + url); + HttpGet httpget = new HttpGet(url); + HttpResponse response = httpclient.execute(httpget); + log.debug( + "resp: " + + response.getStatusLine().getStatusCode() + + " = " + + response.getStatusLine().getReasonPhrase()); + + HttpEntity entity = response.getEntity(); + + // null is error - should get something + if (entity == null) { + throw new WebClientException("httpclient post exception"); + } + String resp = EntityUtils.toString(entity); + // log.debug(" got: " + resp); + return (resp); + } catch (IOException e) { + log.error("io error " + e.getMessage()); + } + return null; + } + // initialize - // initialize - - public void init() { - log.debug("webclient init"); - - // init the doc system - try { - DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); - domFactory.setNamespaceAware(false); - domFactory.setValidating(false); - String feature = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; - domFactory.setFeature(feature, false); - documentBuilder = domFactory.newDocumentBuilder(); - - } catch (ParserConfigurationException e) { - log.error("javax.xml.parsers.ParserConfigurationException: " + e); - } - - // init SSL - // System.setProperty( "javax.net.debug", "ssl"); - - try { - if (caFile!=null && certFile!=null && keyFile!=null) { - log.info("using the socketfactory: ca=" + caFile + ", cert=" + certFile + ", key=" + keyFile); - IamConnectionManager icm = new IamConnectionManager(caFile, certFile, keyFile); - connectionManager = icm.getConnectionManager(); -/** - } else { - log.info("using default socketfactory"); - socketFactory = new SSLSocketFactory(); - **/ - } - - httpParams = new BasicHttpParams(); - HttpConnectionParams.setConnectionTimeout(httpParams, queryTimeLimit); - HttpConnectionParams.setSoTimeout(httpParams, queryTimeLimit); - - initialized = true; - - } catch (Exception e) { - log.error(" " + e); - } - log.debug("gws client initialize done"); - } + public void init() { + log.debug("webclient init"); - public void setCertFile(String v) { - certFile = v; - } - public void setKeyFile(String v) { - keyFile = v; - } - public void setCaFile(String v) { - caFile = v; + // init the doc system + try { + DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); + domFactory.setNamespaceAware(false); + domFactory.setValidating(false); + String feature = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; + domFactory.setFeature(feature, false); + documentBuilder = domFactory.newDocumentBuilder(); + + } catch (ParserConfigurationException e) { + log.error("javax.xml.parsers.ParserConfigurationException: " + e); } - public void setQueryTimeLimit(int t) { - queryTimeLimit = t; + + // init SSL + // System.setProperty( "javax.net.debug", "ssl"); + + try { + if (caFile != null && certFile != null && keyFile != null) { + log.info( + "using the socketfactory: ca=" + caFile + ", cert=" + certFile + ", key=" + keyFile); + IamConnectionManager icm = new IamConnectionManager(caFile, certFile, keyFile); + connectionManager = icm.getConnectionManager(); + /** + * } else { + * log.info("using default socketfactory"); + * socketFactory = new SSLSocketFactory(); + **/ + } + + httpParams = new BasicHttpParams(); + HttpConnectionParams.setConnectionTimeout(httpParams, queryTimeLimit); + HttpConnectionParams.setSoTimeout(httpParams, queryTimeLimit); + + initialized = true; + + } catch (Exception e) { + log.error(" " + e); } + log.debug("gws client initialize done"); + } + public void setCertFile(String v) { + certFile = v; + } -} + public void setKeyFile(String v) { + keyFile = v; + } + + public void setCaFile(String v) { + caFile = v; + } + public void setQueryTimeLimit(int t) { + queryTimeLimit = t; + } +} diff --git a/src/main/java/edu/washington/iam/tools/WebClientException.java b/src/main/java/edu/washington/iam/tools/WebClientException.java index 60281bd..6d37e58 100644 --- a/src/main/java/edu/washington/iam/tools/WebClientException.java +++ b/src/main/java/edu/washington/iam/tools/WebClientException.java @@ -21,12 +21,15 @@ public class WebClientException extends Exception { public WebClientException() { super(); } + public WebClientException(String msg) { super(msg); } + public WebClientException(String msg, Throwable cause) { super(msg, cause); } + public WebClientException(Throwable cause) { super(cause); } diff --git a/src/main/java/edu/washington/iam/tools/XMLHelper.java b/src/main/java/edu/washington/iam/tools/XMLHelper.java index 98e4926..9d2cddc 100644 --- a/src/main/java/edu/washington/iam/tools/XMLHelper.java +++ b/src/main/java/edu/washington/iam/tools/XMLHelper.java @@ -15,7 +15,6 @@ * ======================================================================== */ - package edu.washington.iam.tools; import java.io.BufferedWriter; @@ -24,133 +23,125 @@ import java.util.ArrayList; import java.util.List; import java.util.Vector; - -import org.w3c.dom.Document; +import org.apache.commons.lang.StringEscapeUtils; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; import org.w3c.dom.Node; - -import org.apache.commons.lang.StringEscapeUtils; +import org.w3c.dom.NodeList; public final class XMLHelper { - private XMLHelper() {} - - /** - * Get child element by name, ignoring namespace declarations - * - * @param ele parent element - * @param name name of element to find - */ - public static Element getElementByName(Element ele, String name) { - List list = getElementsByName(ele, name); - if (list.size()>0) return list.get(0); - return null; + private XMLHelper() {} + + /** + * Get child element by name, ignoring namespace declarations + * + * @param ele parent element + * @param name name of element to find + */ + public static Element getElementByName(Element ele, String name) { + List list = getElementsByName(ele, name); + if (list.size() > 0) return list.get(0); + return null; + } + + /** + * Get child elements by name, ignoring namespace declarations + * + * @param ele parent element + * @param name name of elements to find + */ + public static List getElementsByName(Element ele, String name) { + Vector list = new Vector(); + NodeList nl = ele.getChildNodes(); + for (int j = 0; j < nl.getLength(); j++) { + if (nl.item(j).getNodeType() != Node.ELEMENT_NODE) continue; + Element e = (Element) nl.item(j); + String n = e.getNodeName(); + if (matches(n, name)) list.add(e); } - - /** - * Get child elements by name, ignoring namespace declarations - * - * @param ele parent element - * @param name name of elements to find - */ - public static List getElementsByName(Element ele, String name) { - Vector list = new Vector(); - NodeList nl = ele.getChildNodes(); - for (int j=0; j getChildElements(Element ele){ - List list = new ArrayList<>(); - NodeList childNodes = ele.getChildNodes(); - for(int i = 0; i < childNodes.getLength(); i++){ - if (childNodes.item(i).getNodeType() == Node.ELEMENT_NODE) { - list.add((Element)childNodes.item(i)); - } - } - return list; + return (list); + } + + /** + * Get all child elements + * @param ele parent element + * @return list of child elements + */ + public static List getChildElements(Element ele) { + List list = new ArrayList<>(); + NodeList childNodes = ele.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + if (childNodes.item(i).getNodeType() == Node.ELEMENT_NODE) { + list.add((Element) childNodes.item(i)); + } } - - /** - * Get child element by classname - * - * @param ele parent element - * @param name of elements to find - */ - public static Element getElementByClass(Element ele, String name) { - List list = getElementsByClass(ele, name); - if (list.size()>0) return list.get(0); - return null; - } - - /** - * Get child elements by classname - * - * @param ele parent element - * @param cname of elements to find - */ - public static List getElementsByClass(Element ele, String cname) { - Vector list = new Vector(); - NodeList nl = ele.getChildNodes(); - for (int j=0; j0) nsname = nsname.substring(col+1); - return (nsname.matches(name)); - } - - /** - * make a string safe for xml - * - **/ - - public static String safeXml(String in) { - if (in==null) return null; - return StringEscapeUtils.escapeXml(in); - } - - - /** - * make a string safe for json - * - **/ - - public static String safeJson(String in) { - if (in==null) return null; - return in.replaceAll("'","").replaceAll("\n",""); - } - - public static String serializeXmlToString(XMLSerializable obj) throws IOException { - StringWriter sw = new StringWriter(); - BufferedWriter xout = new BufferedWriter(sw); - obj.writeXml(xout); - xout.close(); - return sw.toString(); + return list; + } + + /** + * Get child element by classname + * + * @param ele parent element + * @param name of elements to find + */ + public static Element getElementByClass(Element ele, String name) { + List list = getElementsByClass(ele, name); + if (list.size() > 0) return list.get(0); + return null; + } + + /** + * Get child elements by classname + * + * @param ele parent element + * @param cname of elements to find + */ + public static List getElementsByClass(Element ele, String cname) { + Vector list = new Vector(); + NodeList nl = ele.getChildNodes(); + for (int j = 0; j < nl.getLength(); j++) { + if (nl.item(j).getNodeType() != Node.ELEMENT_NODE) continue; + Element e = (Element) nl.item(j); + if (e.getAttribute("class").equals(cname)) list.add(e); } + return (list); + } + + /** + * Simple compare of strings without namespace preface + * + * @param nsname name with possible ns preface + * @param name name to compare + */ + public static boolean matches(String nsname, String name) { + int col = nsname.indexOf(":"); + if (col > 0) nsname = nsname.substring(col + 1); + return (nsname.matches(name)); + } + + /** + * make a string safe for xml + * + **/ + public static String safeXml(String in) { + if (in == null) return null; + return StringEscapeUtils.escapeXml(in); + } + + /** + * make a string safe for json + * + **/ + public static String safeJson(String in) { + if (in == null) return null; + return in.replaceAll("'", "").replaceAll("\n", ""); + } + + public static String serializeXmlToString(XMLSerializable obj) throws IOException { + StringWriter sw = new StringWriter(); + BufferedWriter xout = new BufferedWriter(sw); + obj.writeXml(xout); + xout.close(); + return sw.toString(); + } } - diff --git a/src/main/java/edu/washington/iam/tools/XMLSerializable.java b/src/main/java/edu/washington/iam/tools/XMLSerializable.java index 1bd84e2..66d2361 100644 --- a/src/main/java/edu/washington/iam/tools/XMLSerializable.java +++ b/src/main/java/edu/washington/iam/tools/XMLSerializable.java @@ -5,5 +5,5 @@ import java.io.Serializable; public interface XMLSerializable extends Serializable { - void writeXml(BufferedWriter xout) throws IOException; + void writeXml(BufferedWriter xout) throws IOException; } diff --git a/src/main/java/edu/washington/iam/tools/gws/GWSDNSVerifier.java b/src/main/java/edu/washington/iam/tools/gws/GWSDNSVerifier.java index 9f4ffe3..b08f0b5 100644 --- a/src/main/java/edu/washington/iam/tools/gws/GWSDNSVerifier.java +++ b/src/main/java/edu/washington/iam/tools/gws/GWSDNSVerifier.java @@ -15,96 +15,85 @@ * ======================================================================== */ - package edu.washington.iam.tools.gws; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; - import edu.washington.iam.tools.DNSVerifier; import edu.washington.iam.tools.DNSVerifyException; import edu.washington.iam.tools.WebClient; import edu.washington.iam.tools.XMLHelper; - +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; public class GWSDNSVerifier implements DNSVerifier { - private final Logger log = LoggerFactory.getLogger(getClass()); - - private WebClient webClient; - private String gwsOwnerBase = null; // base url for dns owner group lookup - - /** - * Test if a user has ownership of a domain - * - * @param id user's uwnetid - * @param domain to test - * @param return list of owners (can be null) - */ - - public boolean isOwner(String dns, String id, List owners) throws DNSVerifyException { - - boolean isOwner = false; - if (id==null) id = ""; - log.debug("looking for gws owner (" + id + ") in " + dns); - - try { - String url = gwsOwnerBase + dns + "/effective_member"; - Element resp = webClient.doRestGet(url); - if (resp!=null) { - Element grpE = XMLHelper.getElementByName(resp, "group"); - Element mbrsE = XMLHelper.getElementByName(grpE, "members"); - List mbrs = XMLHelper.getElementsByName(mbrsE, "member"); - log.debug("get " + mbrs.size() + " group members"); - for (int i=0; i owners) throws DNSVerifyException { + + boolean isOwner = false; + if (id == null) id = ""; + log.debug("looking for gws owner (" + id + ") in " + dns); + + try { + String url = gwsOwnerBase + dns + "/effective_member"; + Element resp = webClient.doRestGet(url); + if (resp != null) { + Element grpE = XMLHelper.getElementByName(resp, "group"); + Element mbrsE = XMLHelper.getElementByName(grpE, "members"); + List mbrs = XMLHelper.getElementsByName(mbrsE, "member"); + log.debug("get " + mbrs.size() + " group members"); + for (int i = 0; i < mbrs.size(); i++) { + String mbr = mbrs.get(i).getTextContent(); + log.debug("mbr: " + mbr); + if (owners != null && !owners.contains(mbr)) owners.add(mbr); + if (mbr.equals(id)) { + if (owners == null) return true; + isOwner = true; } + } + } - } catch (Exception e) { - log.debug("gws dns lookup error: " + e); - throw new DNSVerifyException(e.getMessage() + " : " + e.getCause()); - } - - // do substrings too - dns = dns.replaceFirst("[^\\.]+\\.", ""); - // log.debug("do substrings: " + dns); - int p = dns.indexOf("."); - if (p>0) { // only check to the 2nd level - if (isOwner(dns, id, owners)) { - if (owners==null) return true; // done - isOwner = true; - } - } - return isOwner; + } catch (Exception e) { + log.debug("gws dns lookup error: " + e); + throw new DNSVerifyException(e.getMessage() + " : " + e.getCause()); } - public boolean isOwner(String dns, String id) throws DNSVerifyException { - return isOwner(dns, id, null); - } - - public void setWebClient(WebClient v) { - webClient = v; + // do substrings too + dns = dns.replaceFirst("[^\\.]+\\.", ""); + // log.debug("do substrings: " + dns); + int p = dns.indexOf("."); + if (p > 0) { // only check to the 2nd level + if (isOwner(dns, id, owners)) { + if (owners == null) return true; // done + isOwner = true; + } } + return isOwner; + } - public void setGwsOwnerBase(String v) { - gwsOwnerBase = v; - } + public boolean isOwner(String dns, String id) throws DNSVerifyException { + return isOwner(dns, id, null); + } + public void setWebClient(WebClient v) { + webClient = v; + } - public void init() { - } + public void setGwsOwnerBase(String v) { + gwsOwnerBase = v; + } + + public void init() {} } - diff --git a/src/main/java/edu/washington/iam/tools/gws/GWSGroupManager.java b/src/main/java/edu/washington/iam/tools/gws/GWSGroupManager.java index fcef871..ba1a34d 100644 --- a/src/main/java/edu/washington/iam/tools/gws/GWSGroupManager.java +++ b/src/main/java/edu/washington/iam/tools/gws/GWSGroupManager.java @@ -15,73 +15,60 @@ * ======================================================================== */ - package edu.washington.iam.tools.gws; +import edu.washington.iam.tools.Group; +import edu.washington.iam.tools.GroupManager; +import edu.washington.iam.tools.WebClient; +import edu.washington.iam.tools.XMLHelper; import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; - -import edu.washington.iam.tools.DNSVerifier; -import edu.washington.iam.tools.DNSVerifyException; -import edu.washington.iam.tools.WebClient; -import edu.washington.iam.tools.XMLHelper; -import edu.washington.iam.tools.Group; -import edu.washington.iam.tools.GroupManager; - public class GWSGroupManager implements GroupManager { - private final Logger log = LoggerFactory.getLogger(getClass()); - - private WebClient webClient; - private String gwsBase = null; - - /** - * Get a group - * - */ - - public Group getGroup(String name) { - - Group group = new Group(name); - log.debug("looking for gws group: " + name); - - try { - String url = gwsBase + name + "/effective_member"; - Element resp = webClient.doRestGet(url); - Element grpE = XMLHelper.getElementByName(resp, "group"); - Element mbrsE = XMLHelper.getElementByName(grpE, "members"); - List mbrs = XMLHelper.getElementsByName(mbrsE, "member"); - log.debug("get " + mbrs.size() + " group members"); - for (int i=0; i mbrs = XMLHelper.getElementsByName(mbrsE, "member"); + log.debug("get " + mbrs.size() + " group members"); + for (int i = 0; i < mbrs.size(); i++) { + String mbr = mbrs.get(i).getTextContent(); + log.debug("mbr: " + mbr); + group.members.add(mbr); + } + + } catch (Exception e) { + log.debug("gws lookup error: " + e); + return null; } + return group; + } - public void setWebClient(WebClient v) { - webClient = v; - } + public void setWebClient(WebClient v) { + webClient = v; + } - public void setGwsBase(String v) { - gwsBase = v; - } + public void setGwsBase(String v) { + gwsBase = v; + } - - public void init() { - } + public void init() {} } - diff --git a/src/main/java/edu/washington/iam/tools/netact/NetactDNSVerifier.java b/src/main/java/edu/washington/iam/tools/netact/NetactDNSVerifier.java index b658071..b773092 100644 --- a/src/main/java/edu/washington/iam/tools/netact/NetactDNSVerifier.java +++ b/src/main/java/edu/washington/iam/tools/netact/NetactDNSVerifier.java @@ -15,172 +15,161 @@ * ======================================================================== */ - package edu.washington.iam.tools.netact; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import edu.washington.iam.tools.DNSVerifier; -import edu.washington.iam.tools.DNSVerifyException; -import edu.washington.iam.tools.WebClient; - -// google-gson +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.google.gson.JsonElement; -import com.google.gson.JsonArray; import com.google.gson.JsonPrimitive; - +import edu.washington.iam.tools.DNSVerifier; +import edu.washington.iam.tools.DNSVerifyException; +import edu.washington.iam.tools.WebClient; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class NetactDNSVerifier implements DNSVerifier { - private final Logger log = LoggerFactory.getLogger(getClass()); - - /* Netact rest service provides ownership list. - It is undocumented. Seems that we have to check for host and domain whether - or not the target is a host or a domain. - */ - - private static String hostUrl = null; - private static String domainUrl = null; - private static String certUrl = null; - private WebClient webClient; - - /** - * Test if a user (netid) has ownership of a domain - * - * @param id user's uwnetid - * @param dns domain to test - * @param owners list of owners (can be null) - */ - - public boolean isOwner(String dns, String id, List owners) throws DNSVerifyException { - - boolean isOwner = false; - if (id==null) id = ""; - log.debug("looking for owner (" + id + ") in " + dns); - - try { - String[] urls = { hostUrl, domainUrl }; - for ( String url : urls ) { - String respString = webClient.simpleRestGet(url + dns); - log.debug("got: " + respString); - - JsonParser parser = new JsonParser(); - JsonElement ele = parser.parse(respString); - if (ele.isJsonObject()) { - JsonObject resp = ele.getAsJsonObject(); - if (resp.get("netids").isJsonArray()) { - JsonArray ids = resp.getAsJsonArray("netids"); - for (int i = 0; i < ids.size(); i++) { - JsonPrimitive oidu = ids.get(i).getAsJsonPrimitive(); - if (oidu==null) continue; - String oid = oidu.getAsString(); - if (oid.equals(id)) { - if (owners==null) return true; // done - isOwner = true; - } - if (owners!=null && !owners.contains(oid)) owners.add(oid); - } - } - } - - } - - - } catch (Exception e) { - log.debug("netact dns lookup error: " + e); - throw new DNSVerifyException(e.getMessage() + " : " + e.getCause()); - } - - // do substrings too - dns = dns.replaceFirst("[^\\.]+\\.", ""); - // log.debug("do substrings: " + dns); - int p = dns.indexOf("."); - if (p>0) { - if (isOwner(dns, id, owners)) { - if (owners==null) return true; // done + private final Logger log = LoggerFactory.getLogger(getClass()); + + /* Netact rest service provides ownership list. + It is undocumented. Seems that we have to check for host and domain whether + or not the target is a host or a domain. + */ + + private static String hostUrl = null; + private static String domainUrl = null; + private static String certUrl = null; + private WebClient webClient; + + /** + * Test if a user (netid) has ownership of a domain + * + * @param id user's uwnetid + * @param dns domain to test + * @param owners list of owners (can be null) + */ + public boolean isOwner(String dns, String id, List owners) throws DNSVerifyException { + + boolean isOwner = false; + if (id == null) id = ""; + log.debug("looking for owner (" + id + ") in " + dns); + + try { + String[] urls = {hostUrl, domainUrl}; + for (String url : urls) { + String respString = webClient.simpleRestGet(url + dns); + log.debug("got: " + respString); + + JsonParser parser = new JsonParser(); + JsonElement ele = parser.parse(respString); + if (ele.isJsonObject()) { + JsonObject resp = ele.getAsJsonObject(); + if (resp.get("netids").isJsonArray()) { + JsonArray ids = resp.getAsJsonArray("netids"); + for (int i = 0; i < ids.size(); i++) { + JsonPrimitive oidu = ids.get(i).getAsJsonPrimitive(); + if (oidu == null) continue; + String oid = oidu.getAsString(); + if (oid.equals(id)) { + if (owners == null) return true; // done isOwner = true; + } + if (owners != null && !owners.contains(oid)) owners.add(oid); } + } } - return isOwner; + } + + } catch (Exception e) { + log.debug("netact dns lookup error: " + e); + throw new DNSVerifyException(e.getMessage() + " : " + e.getCause()); } - //check if a certificate is authorized to administer a domain - public boolean isCertOwner(String dns, String id, List owners) throws DNSVerifyException { - - boolean isOwner = false; - if (id==null) id = ""; - log.debug("looking for owner (" + id + ") in " + dns); - - try { - - - String respString = webClient.simpleRestGet(certUrl + dns); - log.debug("got: " + respString); - - JsonParser parser = new JsonParser(); - JsonElement ele = parser.parse(respString); - if (ele.isJsonObject()) { - JsonObject resp = ele.getAsJsonObject(); - if (resp.get("certificates").isJsonArray()) { - JsonArray certlist = resp.getAsJsonArray("certificates"); - for (int i = 0; i < certlist.size(); i++) { - JsonPrimitive certcn = certlist.get(i).getAsJsonPrimitive(); - if (certcn==null) continue; - String oid = certcn.getAsString(); - if (oid.equals(id)) { - if (owners==null) return true; // done - isOwner = true; - } - if (owners!=null && !owners.contains(oid)) owners.add(oid); - } - } else { - throw new DNSVerifyException("DNS contacts service did not return certificate array"); - } + // do substrings too + dns = dns.replaceFirst("[^\\.]+\\.", ""); + // log.debug("do substrings: " + dns); + int p = dns.indexOf("."); + if (p > 0) { + if (isOwner(dns, id, owners)) { + if (owners == null) return true; // done + isOwner = true; + } + } + return isOwner; + } + + // check if a certificate is authorized to administer a domain + public boolean isCertOwner(String dns, String id, List owners) throws DNSVerifyException { + + boolean isOwner = false; + if (id == null) id = ""; + log.debug("looking for owner (" + id + ") in " + dns); + + try { + + String respString = webClient.simpleRestGet(certUrl + dns); + log.debug("got: " + respString); + + JsonParser parser = new JsonParser(); + JsonElement ele = parser.parse(respString); + if (ele.isJsonObject()) { + JsonObject resp = ele.getAsJsonObject(); + if (resp.get("certificates").isJsonArray()) { + JsonArray certlist = resp.getAsJsonArray("certificates"); + for (int i = 0; i < certlist.size(); i++) { + JsonPrimitive certcn = certlist.get(i).getAsJsonPrimitive(); + if (certcn == null) continue; + String oid = certcn.getAsString(); + if (oid.equals(id)) { + if (owners == null) return true; // done + isOwner = true; } - + if (owners != null && !owners.contains(oid)) owners.add(oid); + } + } else { + throw new DNSVerifyException("DNS contacts service did not return certificate array"); } + } - catch (Exception e) { - log.debug("netact dns lookup error: " + e); - throw new DNSVerifyException(e.getMessage() + " : " + e.getCause()); - } - - // do substrings too - dns = dns.replaceFirst("[^\\.]+\\.", ""); - // log.debug("do substrings: " + dns); - int p = dns.indexOf("."); - if (p>0) { - if (isCertOwner(dns, id, owners)) { - if (owners==null) return true; // done - isOwner = true; - } - } - return isOwner; + } catch (Exception e) { + log.debug("netact dns lookup error: " + e); + throw new DNSVerifyException(e.getMessage() + " : " + e.getCause()); } - public boolean isOwner(String dns, String id) throws DNSVerifyException { - return isOwner(dns, id, null); + // do substrings too + dns = dns.replaceFirst("[^\\.]+\\.", ""); + // log.debug("do substrings: " + dns); + int p = dns.indexOf("."); + if (p > 0) { + if (isCertOwner(dns, id, owners)) { + if (owners == null) return true; // done + isOwner = true; + } } + return isOwner; + } - public void setWebClient(WebClient v) { - webClient = v; - } - public void setHostUrl(String v) { - hostUrl = v; - } - public void setDomainUrl(String v) { - domainUrl = v; - } - public void setCertUrl(String v) { - certUrl = v; - } + public boolean isOwner(String dns, String id) throws DNSVerifyException { + return isOwner(dns, id, null); + } - public void init() { - } + public void setWebClient(WebClient v) { + webClient = v; + } + + public void setHostUrl(String v) { + hostUrl = v; + } + + public void setDomainUrl(String v) { + domainUrl = v; + } + + public void setCertUrl(String v) { + certUrl = v; + } + + public void init() {} } - diff --git a/src/test/java/edu/washington/iam/registry/accessctrl/AccessCtrlManagerDBTest.java b/src/test/java/edu/washington/iam/registry/accessctrl/AccessCtrlManagerDBTest.java index 2c9705c..af0c588 100644 --- a/src/test/java/edu/washington/iam/registry/accessctrl/AccessCtrlManagerDBTest.java +++ b/src/test/java/edu/washington/iam/registry/accessctrl/AccessCtrlManagerDBTest.java @@ -1,275 +1,265 @@ package edu.washington.iam.registry.accessctrl; -import edu.washington.iam.registry.accessctrl.AccessCtrlManagerDB; -import edu.washington.iam.registry.accessctrl.AccessCtrl; import edu.washington.iam.registry.exception.AccessCtrlException; import edu.washington.iam.registry.rp.RelyingParty; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; +import java.io.ByteArrayInputStream; import java.util.Arrays; import java.util.List; -import edu.washington.iam.registry.exception.RelyingPartyException; +import java.util.UUID; +import javax.xml.parsers.DocumentBuilderFactory; import org.junit.*; import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.ByteArrayInputStream; -import java.sql.Timestamp; -import java.util.Date; -import java.util.UUID; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:test-db-context.xml") public class AccessCtrlManagerDBTest { - @Autowired - private AccessCtrlManagerDB dao; - @Autowired - private JdbcTemplate template; - - private String remoteUser = "mattjm"; - private final Logger log = LoggerFactory.getLogger(getClass()); - - private List fakeEntityIds = Arrays.asList( - "https://accessctrltest1.s.uw.edu/shibboleth", - "https://accessctrltest2.s.uw.edu/shibboleth", - "https://accessctrltest3.s.uw.edu/shibboleth", - "https://accessctrltest4.s.uw.edu/shibboleth"); - - @Before - public void setupInitialData() { - setupWithRPs(fakeEntityIds); + @Autowired private AccessCtrlManagerDB dao; + @Autowired private JdbcTemplate template; + + private String remoteUser = "mattjm"; + private final Logger log = LoggerFactory.getLogger(getClass()); + + private List fakeEntityIds = + Arrays.asList( + "https://accessctrltest1.s.uw.edu/shibboleth", + "https://accessctrltest2.s.uw.edu/shibboleth", + "https://accessctrltest3.s.uw.edu/shibboleth", + "https://accessctrltest4.s.uw.edu/shibboleth"); + + @Before + public void setupInitialData() { + setupWithRPs(fakeEntityIds); + } + + @After + public void teardown() { + teardownRPs(fakeEntityIds); + } + + // should be null if we've never set one before + @Test + public void testInitialAccessCtrl() { + + template.update("delete from access_control where entity_id = ?", fakeEntityIds.get(0)); + + AccessCtrl myCtrl = new AccessCtrl(); + myCtrl.setEntityId("phony"); + myCtrl = dao.getAccessCtrl(fakeEntityIds.get(0)); + // make sure phony access control object is overwritten with null one returned from get method + Assert.assertFalse(myCtrl.getAuto2FA()); + Assert.assertFalse(myCtrl.getCond2FA()); + Assert.assertFalse(myCtrl.getConditional()); + } + + @Test + public void testEnableStuff() { + String entityId = fakeEntityIds.get(0); + AccessCtrl myCtrl = new AccessCtrl(); + + // clear out any previous records + template.update("delete from filter where entity_id = ?", entityId); + + // get UUID from metadata table + List uuid = + template.queryForList( + "select uuid from metadata where entity_id = ? and end_time is null", + UUID.class, + entityId); + // set up test object + myCtrl.setUuid(uuid.get(0)); + try { + myCtrl.setAuto2FA(true); + myCtrl.setEntityId(entityId); + } catch (AccessCtrlException e) { } - - @After - public void teardown(){ - teardownRPs(fakeEntityIds); + // use test object to update access control for this entity id + try { + dao.updateAccessCtrl(myCtrl, remoteUser); + } catch (AccessCtrlException e) { + log.info("test enable 2fa threw exception"); } - - //should be null if we've never set one before - @Test - public void testInitialAccessCtrl(){ - - template.update("delete from access_control where entity_id = ?", - fakeEntityIds.get(0)); - - AccessCtrl myCtrl = new AccessCtrl(); - myCtrl.setEntityId("phony"); - myCtrl = dao.getAccessCtrl(fakeEntityIds.get(0)); - //make sure phony access control object is overwritten with null one returned from get method - Assert.assertFalse(myCtrl.getAuto2FA()); - Assert.assertFalse(myCtrl.getCond2FA()); - Assert.assertFalse(myCtrl.getConditional()); - + // new empty access control object + AccessCtrl myCtrlAfter = new AccessCtrl(); + // get access control data for this entity id + myCtrlAfter = dao.getAccessCtrl(entityId); + // verify expected state + Assert.assertTrue(myCtrlAfter.getAuto2FA()); + Assert.assertTrue(!myCtrlAfter.getConditional()); + Assert.assertTrue(myCtrlAfter.getConditionalGroup() == ""); + // get ALL DB entries (current and former) + List ids = + template.queryForList( + "select id from access_control where entity_id = ?", Integer.class, entityId); + // should just be 1 + Assert.assertTrue(ids.size() == 1); + + // now enable conditional access + // set group name and properties on object (changing access control object from above) + String myGroup = "uw_iam_my_group"; + myCtrl.setConditional(true); + myCtrl.setConditionalGroup(myGroup); + // do the update using appropriate method + try { + dao.updateAccessCtrl(myCtrl, remoteUser); + } catch (AccessCtrlException e) { + log.info("test enable conditional access threw exception"); } - - @Test - public void testEnableStuff(){ - String entityId = fakeEntityIds.get(0); - AccessCtrl myCtrl = new AccessCtrl(); - - //clear out any previous records - template.update("delete from filter where entity_id = ?", - entityId); - - //get UUID from metadata table - List uuid = template.queryForList("select uuid from metadata where entity_id = ? and end_time is null", - UUID.class, - entityId); - //set up test object - myCtrl.setUuid(uuid.get(0)); - try { - myCtrl.setAuto2FA(true); - myCtrl.setEntityId(entityId); - } catch (AccessCtrlException e) {} - //use test object to update access control for this entity id - try { - dao.updateAccessCtrl(myCtrl, remoteUser); - } catch (AccessCtrlException e) { - log.info("test enable 2fa threw exception"); - } - - //new empty access control object - AccessCtrl myCtrlAfter = new AccessCtrl(); - //get access control data for this entity id - myCtrlAfter = dao.getAccessCtrl(entityId); - //verify expected state - Assert.assertTrue(myCtrlAfter.getAuto2FA()); - Assert.assertTrue(!myCtrlAfter.getConditional()); - Assert.assertTrue(myCtrlAfter.getConditionalGroup() == ""); - //get ALL DB entries (current and former) - List ids = template.queryForList("select id from access_control where entity_id = ?", - Integer.class, - entityId); - //should just be 1 - Assert.assertTrue(ids.size() == 1); - - //now enable conditional access - //set group name and properties on object (changing access control object from above) - String myGroup = "uw_iam_my_group"; - myCtrl.setConditional(true); - myCtrl.setConditionalGroup(myGroup); - //do the update using appropriate method - try { - dao.updateAccessCtrl(myCtrl, remoteUser); - } catch (AccessCtrlException e) { - log.info("test enable conditional access threw exception"); - } - //reset retrieval object - myCtrlAfter = new AccessCtrl(); - myCtrlAfter = dao.getAccessCtrl(entityId); - //verify expected state - Assert.assertTrue(myCtrlAfter.getAuto2FA()); - Assert.assertTrue(myCtrlAfter.getConditional()); - Assert.assertTrue(myCtrlAfter.getConditionalGroup() == myGroup); - //get ALL DB entries (current and former) - ids = template.queryForList("select id from access_control where entity_id = ?", - Integer.class, - entityId); - //should be 2 - Assert.assertTrue(ids.size() == 2); - - + // reset retrieval object + myCtrlAfter = new AccessCtrl(); + myCtrlAfter = dao.getAccessCtrl(entityId); + // verify expected state + Assert.assertTrue(myCtrlAfter.getAuto2FA()); + Assert.assertTrue(myCtrlAfter.getConditional()); + Assert.assertTrue(myCtrlAfter.getConditionalGroup() == myGroup); + // get ALL DB entries (current and former) + ids = + template.queryForList( + "select id from access_control where entity_id = ?", Integer.class, entityId); + // should be 2 + Assert.assertTrue(ids.size() == 2); + } + + @Test + public void testDisableAllStuff() { + String entityId = fakeEntityIds.get(0); + AccessCtrl myCtrl = new AccessCtrl(); + + // start by creating a new DB entry (we don't care if there are others already) + // get UUID from metadata table + List uuid = + template.queryForList( + "select uuid from metadata where entity_id = ? and end_time is null", + UUID.class, + entityId); + // set up test object + myCtrl.setUuid(uuid.get(0)); + try { + myCtrl.setAuto2FA(true); + } catch (AccessCtrlException e) { } - - - @Test - public void testDisableAllStuff() { - String entityId = fakeEntityIds.get(0); - AccessCtrl myCtrl = new AccessCtrl(); - - //start by creating a new DB entry (we don't care if there are others already) - //get UUID from metadata table - List uuid = template.queryForList("select uuid from metadata where entity_id = ? and end_time is null", - UUID.class, - entityId); - //set up test object - myCtrl.setUuid(uuid.get(0)); - try { - myCtrl.setAuto2FA(true); - } catch (AccessCtrlException e) {} - myCtrl.setEntityId(entityId); - //use test object to update access control for this entity id - try { - dao.updateAccessCtrl(myCtrl, remoteUser); - } catch (AccessCtrlException e) { - log.info("test enable 2fa threw exception"); - } - //new empty access control object - AccessCtrl myCtrlAfter = new AccessCtrl(); - //get access control data for this entity id - myCtrlAfter = dao.getAccessCtrl(entityId); - //verify expected state - Assert.assertTrue(myCtrlAfter.getAuto2FA()); - Assert.assertTrue(!myCtrlAfter.getConditional()); - Assert.assertTrue(myCtrlAfter.getConditionalGroup() == ""); - - - //now call the remove method... - Integer returnCode = 0; - try { - returnCode = dao.removeAccessCtrl(entityId, remoteUser); - } catch (AccessCtrlException e) {log.info("test delete access control threw exception");} - Assert.assertTrue(returnCode == 200); - - List ids = template.queryForList("select id from access_control where entity_id = ? and end_time is null", - Integer.class, - entityId); - //should be none - Assert.assertTrue(ids.size() == 0); - + myCtrl.setEntityId(entityId); + // use test object to update access control for this entity id + try { + dao.updateAccessCtrl(myCtrl, remoteUser); + } catch (AccessCtrlException e) { + log.info("test enable 2fa threw exception"); } - - - - - - - - - - - - - - - - - - - - - -//TEST SETUP AND TEARDOWN METHODS - - private UUID genUUID() { return UUID.randomUUID(); } - - private void setupWithRPs(List entityIds){ - String groupId = "uwrp"; - for (String entityId : entityIds) { - - template.update("insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time) " + - "values (?, ?, ?, ?, ?, now())", - genUUID(), groupId, entityId, fakeRelyingPartyXml(entityId), null); - } - } - - private void teardownRPs(List entityIds){ - NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); - namedTemplate.update("delete from metadata where entity_id in (:ids)", - new MapSqlParameterSource().addValue("ids", entityIds)); + // new empty access control object + AccessCtrl myCtrlAfter = new AccessCtrl(); + // get access control data for this entity id + myCtrlAfter = dao.getAccessCtrl(entityId); + // verify expected state + Assert.assertTrue(myCtrlAfter.getAuto2FA()); + Assert.assertTrue(!myCtrlAfter.getConditional()); + Assert.assertTrue(myCtrlAfter.getConditionalGroup() == ""); + + // now call the remove method... + Integer returnCode = 0; + try { + returnCode = dao.removeAccessCtrl(entityId, remoteUser); + } catch (AccessCtrlException e) { + log.info("test delete access control threw exception"); } - - private RelyingParty fakeRelyingParty(String entityId) throws Exception { - RelyingParty relyingParty; - String relyingPartyXml = fakeRelyingPartyXml(entityId); - - relyingParty = new RelyingParty( - DocumentBuilderFactory - .newInstance() - .newDocumentBuilder() - .parse(new ByteArrayInputStream(relyingPartyXml.getBytes())) - .getDocumentElement(), - "uwrp", true, "mattjm", "2001-01-01", null, genUUID()); - - return relyingParty; + Assert.assertTrue(returnCode == 200); + + List ids = + template.queryForList( + "select id from access_control where entity_id = ? and end_time is null", + Integer.class, + entityId); + // should be none + Assert.assertTrue(ids.size() == 0); + } + + // TEST SETUP AND TEARDOWN METHODS + + private UUID genUUID() { + return UUID.randomUUID(); + } + + private void setupWithRPs(List entityIds) { + String groupId = "uwrp"; + for (String entityId : entityIds) { + + template.update( + "insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time) " + + "values (?, ?, ?, ?, ?, now())", + genUUID(), + groupId, + entityId, + fakeRelyingPartyXml(entityId), + null); } - - private String fakeRelyingPartyXml(String entityId){ - String xml = ("\n" + - " \n" + + } + + private void teardownRPs(List entityIds) { + NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); + namedTemplate.update( + "delete from metadata where entity_id in (:ids)", + new MapSqlParameterSource().addValue("ids", entityIds)); + } + + private RelyingParty fakeRelyingParty(String entityId) throws Exception { + RelyingParty relyingParty; + String relyingPartyXml = fakeRelyingPartyXml(entityId); + + relyingParty = + new RelyingParty( + DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new ByteArrayInputStream(relyingPartyXml.getBytes())) + .getDocumentElement(), + "uwrp", + true, + "mattjm", + "2001-01-01", + null, + genUUID()); + + return relyingParty; + } + + private String fakeRelyingPartyXml(String entityId) { + String xml = + ("\n" + + " \n" + + // no keydescriptor in the dao test, test elsewhere // " ...\n" +*/ - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " AIE-IAM urizen4 test and development\n" + - " Urizen4 est and dev system for AIE-IAM\n" + - " https://urizen4.cac.washington.edu/\n" + - " \n" + - " \n" + - " J F\n" + - " jf@example.com\n" + - " \n" + - " \n" + - " J F\n" + - " jf@example.com\n" + - " \n" + - " \n" + - " Super Bob\n" + - " bob@spud.edu\n" + - " \n" + - " ") - .replace("{entityId}", entityId); - return xml; - } + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " AIE-IAM urizen4 test and development\n" + + " Urizen4 est and dev system for AIE-IAM\n" + + " https://urizen4.cac.washington.edu/\n" + + " \n" + + " \n" + + " J F\n" + + " jf@example.com\n" + + " \n" + + " \n" + + " J F\n" + + " jf@example.com\n" + + " \n" + + " \n" + + " Super Bob\n" + + " bob@spud.edu\n" + + " \n" + + " ") + .replace("{entityId}", entityId); + return xml; + } } diff --git a/src/test/java/edu/washington/iam/registry/filter/AttributeDAOXMLTest.java b/src/test/java/edu/washington/iam/registry/filter/AttributeDAOXMLTest.java index 9e42bb9..a7888ee 100644 --- a/src/test/java/edu/washington/iam/registry/filter/AttributeDAOXMLTest.java +++ b/src/test/java/edu/washington/iam/registry/filter/AttributeDAOXMLTest.java @@ -1,6 +1,7 @@ package edu.washington.iam.registry.filter; import edu.washington.iam.registry.exception.AttributeNotFoundException; +import java.util.List; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -8,40 +9,35 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import java.util.List; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AttributeDAOXMLTest { - @Autowired - private AttributeDAOXML dao; + @Autowired private AttributeDAOXML dao; - @Test - public void testGetAttributes() throws Exception { - List attributeList = dao.getAttributes(); - Assert.assertEquals(28, attributeList.size()); + @Test + public void testGetAttributes() throws Exception { + List attributeList = dao.getAttributes(); + Assert.assertEquals(28, attributeList.size()); + } - } - - @Test - public void testGetAttribute() throws Exception { - Attribute attribute = dao.getAttribute("surname"); - Assert.assertNotNull(attribute); - Assert.assertEquals("surname", attribute.getId()); - Assert.assertEquals("u_weblogin_admins", attribute.getAuthorizingGroup()); - Assert.assertEquals("Last name (PDS: sn)", attribute.getDescription()); - Assert.assertNotNull(dao.getAttribute("uwNetID")); - } + @Test + public void testGetAttribute() throws Exception { + Attribute attribute = dao.getAttribute("surname"); + Assert.assertNotNull(attribute); + Assert.assertEquals("surname", attribute.getId()); + Assert.assertEquals("u_weblogin_admins", attribute.getAuthorizingGroup()); + Assert.assertEquals("Last name (PDS: sn)", attribute.getDescription()); + Assert.assertNotNull(dao.getAttribute("uwNetID")); + } - @Test - public void testGetAttributeNotFound() throws Exception { - boolean exceptionCaught = false; - try { - Attribute attribute = dao.getAttribute("foo"); - } - catch (AttributeNotFoundException e){ - exceptionCaught = true; - } - Assert.assertTrue(exceptionCaught); + @Test + public void testGetAttributeNotFound() throws Exception { + boolean exceptionCaught = false; + try { + Attribute attribute = dao.getAttribute("foo"); + } catch (AttributeNotFoundException e) { + exceptionCaught = true; } + Assert.assertTrue(exceptionCaught); + } } diff --git a/src/test/java/edu/washington/iam/registry/filter/DBFilterPolicyDAOTest.java b/src/test/java/edu/washington/iam/registry/filter/DBFilterPolicyDAOTest.java index ae91172..c25aeae 100644 --- a/src/test/java/edu/washington/iam/registry/filter/DBFilterPolicyDAOTest.java +++ b/src/test/java/edu/washington/iam/registry/filter/DBFilterPolicyDAOTest.java @@ -1,6 +1,12 @@ package edu.washington.iam.registry.filter; import edu.washington.iam.registry.rp.RelyingParty; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.StringWriter; +import java.sql.Timestamp; +import java.util.*; +import javax.xml.parsers.DocumentBuilderFactory; import org.junit.*; import org.junit.runner.RunWith; import org.slf4j.Logger; @@ -13,414 +19,458 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.w3c.dom.Element; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.BufferedWriter; -import java.io.ByteArrayInputStream; -import java.io.StringWriter; -import java.sql.Timestamp; -import java.util.*; - - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:test-db-context.xml") public class DBFilterPolicyDAOTest { - /** - * Amount of time for tests to sleep waiting for DB operations. - * - * Set as low as possible. - */ - private static int SLEEP_DELAY_MS = 10; - - private final Logger log = LoggerFactory.getLogger(getClass()); - - @Autowired - private DBFilterPolicyDAO dao; - - @Autowired - private JdbcTemplate template; - - private String remoteUser = "mattjm"; - - - private List fakeEntityIds = Arrays.asList( - "https://testupdate.s.uw.edu/shibboleth", - "https://testcreate.s.uw.edu/shibboleth", - "https://testnoupdate.s.uw.edu/shibboleth"); - - @Before - public void setupInitialData() { - setupWithRPs(fakeEntityIds); - } - - @After - public void teardown(){ - teardownRPs(fakeEntityIds); - } - - @Test - public void testGetFilterPolicyGroups() throws Exception { - List filterPolicyGroups = dao.getFilterPolicyGroups(); - Assert.assertTrue(filterPolicyGroups.size() > 0); + /** + * Amount of time for tests to sleep waiting for DB operations. + * + * Set as low as possible. + */ + private static int SLEEP_DELAY_MS = 10; + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Autowired private DBFilterPolicyDAO dao; + + @Autowired private JdbcTemplate template; + + private String remoteUser = "mattjm"; + + private List fakeEntityIds = + Arrays.asList( + "https://testupdate.s.uw.edu/shibboleth", + "https://testcreate.s.uw.edu/shibboleth", + "https://testnoupdate.s.uw.edu/shibboleth"); + + @Before + public void setupInitialData() { + setupWithRPs(fakeEntityIds); + } + + @After + public void teardown() { + teardownRPs(fakeEntityIds); + } + + @Test + public void testGetFilterPolicyGroups() throws Exception { + List filterPolicyGroups = dao.getFilterPolicyGroups(); + Assert.assertTrue(filterPolicyGroups.size() > 0); + } + + @Test + public void testGetFilterPolicyGroup() throws Exception { + FilterPolicyGroup filterPolicyGroup = dao.getFilterPolicyGroup("uwrp"); + Assert.assertNotNull(filterPolicyGroup); + } + + @Test + public void testGetFilterPolicies() throws Exception { + FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); + filterPolicyGroup.setId("uwrp"); + List fakeEntityIds = Arrays.asList("testsp1", "testsp2", "testsp3", "testsp4"); + for (String fakeId : fakeEntityIds) { + template.update( + "insert into filter (uuid, group_id, entity_id, xml, end_time, start_time) " + + "values (?, ?, ?, ?, null, now())", + genUUID(), + filterPolicyGroup.getId(), + fakeId, + fakeAttributeFilterPolicyXml(fakeId)); } - @Test - public void testGetFilterPolicyGroup() throws Exception { - FilterPolicyGroup filterPolicyGroup = dao.getFilterPolicyGroup("uwrp"); - Assert.assertNotNull(filterPolicyGroup); + List afps = dao.getFilterPolicies(filterPolicyGroup); + Assert.assertEquals(fakeEntityIds.size(), afps.size()); + NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); + namedTemplate.update( + "delete from filter where entity_id in (:entityIds)", + new MapSqlParameterSource().addValue("entityIds", fakeEntityIds)); + } + + @Test + public void testGetFilterPoliciesCaching() throws Exception { + FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); + filterPolicyGroup.setId("uwrp"); + List fakeEntityIds = Arrays.asList("testsp1", "testsp2", "testsp3", "testsp4"); + for (String fakeId : fakeEntityIds) { + template.update( + "insert into filter (uuid, group_id, entity_id, xml, end_time, start_time) " + + "values (?, ?, ?, ?, null, now())", + genUUID(), + filterPolicyGroup.getId(), + fakeId, + fakeAttributeFilterPolicyXml(fakeId)); } - @Test - public void testGetFilterPolicies() throws Exception { - FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); - filterPolicyGroup.setId("uwrp"); - List fakeEntityIds = Arrays.asList("testsp1", "testsp2", "testsp3", "testsp4"); - for(String fakeId : fakeEntityIds){ - template.update("insert into filter (uuid, group_id, entity_id, xml, end_time, start_time) " + - "values (?, ?, ?, ?, null, now())", - genUUID(), filterPolicyGroup.getId(), fakeId, fakeAttributeFilterPolicyXml(fakeId)); - } - - List afps = dao.getFilterPolicies(filterPolicyGroup); - Assert.assertEquals(fakeEntityIds.size(), afps.size()); - NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); - namedTemplate.update("delete from filter where entity_id in (:entityIds)", - new MapSqlParameterSource().addValue("entityIds", fakeEntityIds)); - } - - @Test - public void testGetFilterPoliciesCaching() throws Exception { - FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); - filterPolicyGroup.setId("uwrp"); - List fakeEntityIds = Arrays.asList("testsp1", "testsp2", "testsp3", "testsp4"); - for(String fakeId : fakeEntityIds){ - template.update("insert into filter (uuid, group_id, entity_id, xml, end_time, start_time) " + - "values (?, ?, ?, ?, null, now())", - genUUID(), filterPolicyGroup.getId(), fakeId, fakeAttributeFilterPolicyXml(fakeId)); - } - - List afps = dao.getFilterPolicies(filterPolicyGroup); - Assert.assertEquals(fakeEntityIds.size(), afps.size()); - // get it again to test that update check works - afps = dao.getFilterPolicies(filterPolicyGroup); - Assert.assertEquals(fakeEntityIds.size(), afps.size()); - - NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); - namedTemplate.update("delete from filter where entity_id in (:entityIds)", - new MapSqlParameterSource().addValue("entityIds", fakeEntityIds)); - } - - @Test - public void testAttributeFilterPolicyFromElement() throws Exception { - String inFilterPolicyXml = fakeAttributeFilterPolicyXml("https://example.com/shibboleth"); - FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); - filterPolicyGroup.setId("uwrp"); - AttributeFilterPolicy afp = dao.attributeFilterPolicyFromElement( - DocumentBuilderFactory - .newInstance() - .newDocumentBuilder() - .parse(new ByteArrayInputStream(inFilterPolicyXml.getBytes())) - .getDocumentElement(), - filterPolicyGroup); - - StringWriter sw = new StringWriter(); - BufferedWriter xout = new BufferedWriter(sw); - afp.writeXml(xout); - xout.close(); - - Assert.assertEquals(inFilterPolicyXml.replaceAll("\\s+", ""), - sw.toString().replaceAll("\\s+", "")); - - } - - @Test - public void testAttributeFilterPolicyParseComplexRegex() throws Exception { - String inFilterPolicyXml = " " + - " " + - " " + - " " + - " " + - " " + - ""; - FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); - filterPolicyGroup.setId("uwcore"); - Element afpElement = DocumentBuilderFactory - .newInstance() + List afps = dao.getFilterPolicies(filterPolicyGroup); + Assert.assertEquals(fakeEntityIds.size(), afps.size()); + // get it again to test that update check works + afps = dao.getFilterPolicies(filterPolicyGroup); + Assert.assertEquals(fakeEntityIds.size(), afps.size()); + + NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); + namedTemplate.update( + "delete from filter where entity_id in (:entityIds)", + new MapSqlParameterSource().addValue("entityIds", fakeEntityIds)); + } + + @Test + public void testAttributeFilterPolicyFromElement() throws Exception { + String inFilterPolicyXml = fakeAttributeFilterPolicyXml("https://example.com/shibboleth"); + FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); + filterPolicyGroup.setId("uwrp"); + AttributeFilterPolicy afp = + dao.attributeFilterPolicyFromElement( + DocumentBuilderFactory.newInstance() .newDocumentBuilder() .parse(new ByteArrayInputStream(inFilterPolicyXml.getBytes())) - .getDocumentElement(); - AttributeFilterPolicy afp = dao.attributeFilterPolicyFromElement( - afpElement, - filterPolicyGroup); - - Assert.assertNotNull(afp); - Assert.assertTrue(afp.matches("https://foo.washington.edu/shibboleth")); - Assert.assertTrue(afp.matches("https://foo.uw.edu/shibboleth")); - Assert.assertTrue(afp.matches("https://foo.washington.edu")); - Assert.assertTrue(afp.matches("https://foo.uw.edu")); - Assert.assertFalse(afp.matches("https://foo.uw.edu.haxxorz.ru/shibboleth")); - Assert.assertFalse(afp.matches("https://haxxorz.ru/foo.washington.edu/shibboleth")); - Assert.assertFalse(afp.matches("https://foo.notwashington.edu/shibboleth")); - - Assert.assertEquals(4, afp.getAttributeRules().size()); + .getDocumentElement(), + filterPolicyGroup); + + StringWriter sw = new StringWriter(); + BufferedWriter xout = new BufferedWriter(sw); + afp.writeXml(xout); + xout.close(); + + Assert.assertEquals( + inFilterPolicyXml.replaceAll("\\s+", ""), sw.toString().replaceAll("\\s+", "")); + } + + @Test + public void testAttributeFilterPolicyParseComplexRegex() throws Exception { + String inFilterPolicyXml = + " " + + " " + + " " + + " " + + " " + + " " + + ""; + FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); + filterPolicyGroup.setId("uwcore"); + Element afpElement = + DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new ByteArrayInputStream(inFilterPolicyXml.getBytes())) + .getDocumentElement(); + AttributeFilterPolicy afp = dao.attributeFilterPolicyFromElement(afpElement, filterPolicyGroup); + + Assert.assertNotNull(afp); + Assert.assertTrue(afp.matches("https://foo.washington.edu/shibboleth")); + Assert.assertTrue(afp.matches("https://foo.uw.edu/shibboleth")); + Assert.assertTrue(afp.matches("https://foo.washington.edu")); + Assert.assertTrue(afp.matches("https://foo.uw.edu")); + Assert.assertFalse(afp.matches("https://foo.uw.edu.haxxorz.ru/shibboleth")); + Assert.assertFalse(afp.matches("https://haxxorz.ru/foo.washington.edu/shibboleth")); + Assert.assertFalse(afp.matches("https://foo.notwashington.edu/shibboleth")); + + Assert.assertEquals(4, afp.getAttributeRules().size()); + } + + @Test + @Ignore( + "The possibility of a null AttributeFilterPolicy is understood, consider removing this test") + public void testAttributeFilterPolicyFromElementRuleAndNotParses() throws Exception { + String inFilterPolicyXml = + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""; + FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); + filterPolicyGroup.setId("uwcore"); + Element afpElement = + DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new ByteArrayInputStream(inFilterPolicyXml.getBytes())) + .getDocumentElement(); + AttributeFilterPolicy afp = dao.attributeFilterPolicyFromElement(afpElement, filterPolicyGroup); + Assert.assertNotNull(afp); + } + + @Test + public void testCreateFilterPolicy() throws Exception { + String entityId = "https://testcreate.s.uw.edu/shibboleth"; + FilterPolicyGroup filterPolicyGroup = fakeFilterPolicyGroup(); + AttributeFilterPolicy attributeFilterPolicy = + fakeAttributeFilterPolicy(filterPolicyGroup, entityId); + + template.update("delete from filter where entity_id = ?", entityId); + List qResults = + template.queryForList( + "select entity_id from filter where entity_id = ?", + new Object[] {entityId}, + Timestamp.class); + // check that there's nothing in there already + Assert.assertEquals(0, qResults.size()); + Timestamp preUpdateTime = new Timestamp(new Date().getTime()); + Thread.sleep(SLEEP_DELAY_MS); + attributeFilterPolicy.setUuid(genUUID()); + dao.createFilterPolicy(filterPolicyGroup, attributeFilterPolicy, remoteUser); + + qResults = + template.queryForList( + "select start_time from filter where entity_id = ?", + new Object[] {entityId}, + Timestamp.class); + Assert.assertEquals(1, qResults.size()); + Assert.assertTrue(qResults.get(0).after(preUpdateTime)); + + template.update("delete from filter where entity_id = ?", entityId); + } + + @Test + public void testCreateFilterPolicyPreviouslyDeleted() throws Exception { + // make sure an old end_time is null status doesn't break "updating" the status again + String entityId = "https://testcreate.s.uw.edu/shibboleth"; + FilterPolicyGroup filterPolicyGroup = fakeFilterPolicyGroup(); + AttributeFilterPolicy attributeFilterPolicy = + fakeAttributeFilterPolicy(filterPolicyGroup, entityId); + + template.update("delete from filter where entity_id = ?", entityId); + template.update( + "insert into filter (uuid, group_id, entity_id, xml, end_time, start_time) values (?, ?, ?, ?, now(), now())", + genUUID(), + filterPolicyGroup.getId(), + entityId, + fakeAttributeFilterPolicyXml(entityId)); + List qResults = + template.queryForList( + "select start_time from filter where entity_id = ? and end_time is null", + new Object[] {entityId}, + Timestamp.class); + Assert.assertEquals(0, qResults.size()); + Timestamp preUpdateTime = new Timestamp(new Date().getTime()); + Thread.sleep(SLEEP_DELAY_MS); + dao.updateFilterPolicies(filterPolicyGroup, Arrays.asList(attributeFilterPolicy), remoteUser); + + qResults = + template.queryForList( + "select start_time from filter where entity_id = ? and end_time is null", + new Object[] {entityId}, + Timestamp.class); + Assert.assertEquals(1, qResults.size()); + Assert.assertTrue(qResults.get(0).after(preUpdateTime)); + + template.update("delete from filter where entity_id = ?", entityId); + } + + @Test + public void testUpdateFilterPolicy() throws Exception { + String entityId = "https://testupdate.s.uw.edu/shibboleth"; + FilterPolicyGroup filterPolicyGroup = fakeFilterPolicyGroup(); + AttributeFilterPolicy attributeFilterPolicy = + fakeAttributeFilterPolicy(filterPolicyGroup, entityId); + + template.update("delete from filter where entity_id = ?", entityId); + template.update( + "insert into filter (group_id, entity_id, xml, start_time, end_time, uuid) values (?, ?, ?, now(), ?, ?)", + filterPolicyGroup.getId(), + entityId, + fakeAttributeFilterPolicyXml(entityId), + null, + genUUID()); + List qResults = + template.queryForList( + "select start_time from filter where entity_id = ? and end_time is null", + new Object[] {entityId}, + Timestamp.class); + Assert.assertEquals(1, qResults.size()); + Timestamp preUpdateTime = qResults.get(0); + // it's too fast! + Thread.sleep(SLEEP_DELAY_MS); + dao.updateFilterPolicy(filterPolicyGroup, attributeFilterPolicy, remoteUser); + + qResults = + template.queryForList( + "select start_time from filter where entity_id = ? and end_time is null", + new Object[] {entityId}, + Timestamp.class); + log.info("before: " + preUpdateTime.toString() + " after: " + qResults.get(0).toString()); + Assert.assertEquals(1, qResults.size()); + Assert.assertTrue(qResults.get(0).after(preUpdateTime)); + template.update("delete from filter where entity_id = ?", entityId); + } + + @Test + public void testUpdateFilterPolicies() throws Exception { + NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); + String updateEntityId = "https://testupdate.s.uw.edu/shibboleth"; + String createEntityId = "https://testcreate.s.uw.edu/shibboleth"; + String noUpdateEntityId = "https://testnoupdate.s.uw.edu/shibboleth"; + List entityIds = Arrays.asList(updateEntityId, createEntityId, noUpdateEntityId); + FilterPolicyGroup filterPolicyGroup = fakeFilterPolicyGroup(); + namedTemplate.update( + "delete from filter where entity_id in (:ids)", + new MapSqlParameterSource().addValue("ids", entityIds)); + insertFakeData(filterPolicyGroup, updateEntityId); + insertFakeData(filterPolicyGroup, noUpdateEntityId); + List qResults = + namedTemplate.queryForList( + "select start_time from filter where entity_id in (:ids)", + new MapSqlParameterSource().addValue("ids", entityIds), + Timestamp.class); + Assert.assertEquals(2, qResults.size()); + Thread.sleep(SLEEP_DELAY_MS); + + List updatePolicies = new ArrayList<>(); + updatePolicies.add(fakeAttributeFilterPolicy(filterPolicyGroup, updateEntityId)); + updatePolicies.add(fakeAttributeFilterPolicy(filterPolicyGroup, createEntityId)); + + dao.updateFilterPolicies(filterPolicyGroup, updatePolicies, remoteUser); + + // The two updated policies should have later start_times than other one + qResults = + namedTemplate.queryForList( + "select start_time from filter where end_time is null and entity_id in (:ids)" + + " and start_time > (select min(start_time) from filter where end_time is null)", + new MapSqlParameterSource().addValue("ids", entityIds), + Timestamp.class); + Assert.assertEquals(2, qResults.size()); + + // clean up + namedTemplate.update( + "delete from filter where entity_id in (:ids)", + new MapSqlParameterSource().addValue("ids", entityIds)); + } + + private void insertFakeData(FilterPolicyGroup filterPolicyGroup, String entityId) + throws Exception { + List uuid = + template.queryForList( + "select uuid from metadata where entity_id = ? and end_time is null", + UUID.class, + entityId); + template.update( + "insert into filter (uuid, group_id, entity_id, xml, end_time, start_time) values (?, ?, ?, ?, null, now())", + uuid.get(0), + filterPolicyGroup.getId(), + entityId, + fakeAttributeFilterPolicyXml(entityId)); + } + + private FilterPolicyGroup fakeFilterPolicyGroup() { + FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); + filterPolicyGroup.setId("uwrp"); + return filterPolicyGroup; + } + + private AttributeFilterPolicy fakeAttributeFilterPolicy( + FilterPolicyGroup filterPolicyGroup, String entityId) throws Exception { + String filterPolicyXml = fakeAttributeFilterPolicyXml(entityId); + return dao.attributeFilterPolicyFromElement( + DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new ByteArrayInputStream(filterPolicyXml.getBytes())) + .getDocumentElement(), + filterPolicyGroup); + } + + private String fakeAttributeFilterPolicyXml(String entityId) { + return String.format( + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ", + entityId.replaceAll("[:/.]", "_"), entityId); + } + + private UUID genUUID() { + return UUID.randomUUID(); + } + + private void setupWithRPs(List entityIds) { + String groupId = "uwrp"; + for (String entityId : entityIds) { + + template.update( + "insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time) " + + "values (?, ?, ?, ?, ?, now())", + genUUID(), + groupId, + entityId, + fakeRelyingPartyXml(entityId), + null); } - @Test - @Ignore("The possibility of a null AttributeFilterPolicy is understood, consider removing this test") - public void testAttributeFilterPolicyFromElementRuleAndNotParses() throws Exception { - String inFilterPolicyXml = " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - ""; - FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); - filterPolicyGroup.setId("uwcore"); - Element afpElement = DocumentBuilderFactory - .newInstance() - .newDocumentBuilder() - .parse(new ByteArrayInputStream(inFilterPolicyXml.getBytes())) - .getDocumentElement(); - AttributeFilterPolicy afp = dao.attributeFilterPolicyFromElement( - afpElement, - filterPolicyGroup); - Assert.assertNotNull(afp); - } - - @Test - public void testCreateFilterPolicy() throws Exception { - String entityId = "https://testcreate.s.uw.edu/shibboleth"; - FilterPolicyGroup filterPolicyGroup = fakeFilterPolicyGroup(); - AttributeFilterPolicy attributeFilterPolicy = fakeAttributeFilterPolicy(filterPolicyGroup, entityId); - - template.update("delete from filter where entity_id = ?", entityId); - List qResults = template.queryForList("select entity_id from filter where entity_id = ?" - , new Object[]{entityId} - , Timestamp.class); - // check that there's nothing in there already - Assert.assertEquals(0, qResults.size()); - Timestamp preUpdateTime = new Timestamp(new Date().getTime()); - Thread.sleep(SLEEP_DELAY_MS); - attributeFilterPolicy.setUuid(genUUID()); - dao.createFilterPolicy(filterPolicyGroup, attributeFilterPolicy, remoteUser); - - qResults = template.queryForList("select start_time from filter where entity_id = ?" - , new Object[] {entityId} - , Timestamp.class); - Assert.assertEquals(1, qResults.size()); - Assert.assertTrue(qResults.get(0).after(preUpdateTime)); - - template.update("delete from filter where entity_id = ?", entityId); - } - - @Test - public void testCreateFilterPolicyPreviouslyDeleted() throws Exception { - //make sure an old end_time is null status doesn't break "updating" the status again - String entityId = "https://testcreate.s.uw.edu/shibboleth"; - FilterPolicyGroup filterPolicyGroup = fakeFilterPolicyGroup(); - AttributeFilterPolicy attributeFilterPolicy = fakeAttributeFilterPolicy(filterPolicyGroup, entityId); - - template.update("delete from filter where entity_id = ?", entityId); - template.update("insert into filter (uuid, group_id, entity_id, xml, end_time, start_time) values (?, ?, ?, ?, now(), now())", - genUUID(), filterPolicyGroup.getId(), entityId, fakeAttributeFilterPolicyXml(entityId)); - List qResults = template.queryForList("select start_time from filter where entity_id = ? and end_time is null" - , new Object[]{entityId} - , Timestamp.class); - Assert.assertEquals(0, qResults.size()); - Timestamp preUpdateTime = new Timestamp(new Date().getTime()); - Thread.sleep(SLEEP_DELAY_MS); - dao.updateFilterPolicies(filterPolicyGroup, Arrays.asList(attributeFilterPolicy), remoteUser); - - qResults = template.queryForList("select start_time from filter where entity_id = ? and end_time is null" - , new Object[] {entityId} - , Timestamp.class); - Assert.assertEquals(1, qResults.size()); - Assert.assertTrue(qResults.get(0).after(preUpdateTime)); - - template.update("delete from filter where entity_id = ?", entityId); - } - - @Test - public void testUpdateFilterPolicy() throws Exception { - String entityId = "https://testupdate.s.uw.edu/shibboleth"; - FilterPolicyGroup filterPolicyGroup = fakeFilterPolicyGroup(); - AttributeFilterPolicy attributeFilterPolicy = fakeAttributeFilterPolicy(filterPolicyGroup, entityId); - - template.update("delete from filter where entity_id = ?", entityId); - template.update("insert into filter (group_id, entity_id, xml, start_time, end_time, uuid) values (?, ?, ?, now(), ?, ?)", - filterPolicyGroup.getId(), entityId, fakeAttributeFilterPolicyXml(entityId), null, genUUID()); - List qResults = template.queryForList("select start_time from filter where entity_id = ? and end_time is null" - , new Object[]{entityId} - , Timestamp.class); - Assert.assertEquals(1, qResults.size()); - Timestamp preUpdateTime = qResults.get(0); - //it's too fast! - Thread.sleep(SLEEP_DELAY_MS); - dao.updateFilterPolicy(filterPolicyGroup, attributeFilterPolicy, remoteUser); - - qResults = template.queryForList("select start_time from filter where entity_id = ? and end_time is null" - , new Object[] {entityId} - , Timestamp.class); - log.info("before: " + preUpdateTime.toString() + " after: " + qResults.get(0).toString()); - Assert.assertEquals(1, qResults.size()); - Assert.assertTrue(qResults.get(0).after(preUpdateTime)); - template.update("delete from filter where entity_id = ?", entityId); - } - - @Test - public void testUpdateFilterPolicies() throws Exception { - NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); - String updateEntityId = "https://testupdate.s.uw.edu/shibboleth"; - String createEntityId = "https://testcreate.s.uw.edu/shibboleth"; - String noUpdateEntityId = "https://testnoupdate.s.uw.edu/shibboleth"; - List entityIds = Arrays.asList(updateEntityId, createEntityId, noUpdateEntityId); - FilterPolicyGroup filterPolicyGroup = fakeFilterPolicyGroup(); - namedTemplate.update("delete from filter where entity_id in (:ids)", - new MapSqlParameterSource().addValue("ids", entityIds)); - insertFakeData(filterPolicyGroup, updateEntityId); - insertFakeData(filterPolicyGroup, noUpdateEntityId); - List qResults = namedTemplate.queryForList("select start_time from filter where entity_id in (:ids)" - , new MapSqlParameterSource().addValue("ids", entityIds) - , Timestamp.class); - Assert.assertEquals(2, qResults.size()); - Thread.sleep(SLEEP_DELAY_MS); - - List updatePolicies = new ArrayList<>(); - updatePolicies.add(fakeAttributeFilterPolicy(filterPolicyGroup, updateEntityId)); - updatePolicies.add(fakeAttributeFilterPolicy(filterPolicyGroup, createEntityId)); - - dao.updateFilterPolicies(filterPolicyGroup, updatePolicies, remoteUser); - - // The two updated policies should have later start_times than other one - qResults = namedTemplate.queryForList( - "select start_time from filter where end_time is null and entity_id in (:ids)" + - " and start_time > (select min(start_time) from filter where end_time is null)" - , new MapSqlParameterSource().addValue("ids", entityIds) - , Timestamp.class); - Assert.assertEquals(2, qResults.size()); - - //clean up - namedTemplate.update("delete from filter where entity_id in (:ids)", - new MapSqlParameterSource().addValue("ids", entityIds)); - } - - private void insertFakeData(FilterPolicyGroup filterPolicyGroup, String entityId) throws Exception { - List uuid = template.queryForList("select uuid from metadata where entity_id = ? and end_time is null", - UUID.class, - entityId); - template.update("insert into filter (uuid, group_id, entity_id, xml, end_time, start_time) values (?, ?, ?, ?, null, now())", - uuid.get(0), filterPolicyGroup.getId(), entityId, fakeAttributeFilterPolicyXml(entityId)); - } - private FilterPolicyGroup fakeFilterPolicyGroup() { - FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); - filterPolicyGroup.setId("uwrp"); - return filterPolicyGroup; - } - - private AttributeFilterPolicy fakeAttributeFilterPolicy (FilterPolicyGroup filterPolicyGroup, String entityId) - throws Exception { - String filterPolicyXml = fakeAttributeFilterPolicyXml(entityId); - return dao.attributeFilterPolicyFromElement( - DocumentBuilderFactory - .newInstance() - .newDocumentBuilder() - .parse(new ByteArrayInputStream(filterPolicyXml.getBytes())) - .getDocumentElement(), - filterPolicyGroup); - } - - private String fakeAttributeFilterPolicyXml(String entityId){ - return String.format( - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " ", - entityId.replaceAll("[:/.]", "_"), - entityId); - } - - private UUID genUUID() { return UUID.randomUUID(); } - - - private void setupWithRPs(List entityIds){ - String groupId = "uwrp"; - for (String entityId : entityIds) { - - template.update("insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time) " + - "values (?, ?, ?, ?, ?, now())", - genUUID(), groupId, entityId, fakeRelyingPartyXml(entityId), null); - } - - // All tests expect filter to be empty at start. - template.update("delete from filter"); - } - - private void teardownRPs(List entityIds){ - NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); - namedTemplate.update("delete from metadata where entity_id in (:ids)", - new MapSqlParameterSource().addValue("ids", entityIds)); - } - - private RelyingParty fakeRelyingParty(String entityId) throws Exception { - RelyingParty relyingParty; - String relyingPartyXml = fakeRelyingPartyXml(entityId); + // All tests expect filter to be empty at start. + template.update("delete from filter"); + } - relyingParty = new RelyingParty( - DocumentBuilderFactory - .newInstance() - .newDocumentBuilder() - .parse(new ByteArrayInputStream(relyingPartyXml.getBytes())) - .getDocumentElement(), - "uwrp", true, "mattjm", "2001-01-01", null, genUUID()); + private void teardownRPs(List entityIds) { + NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); + namedTemplate.update( + "delete from metadata where entity_id in (:ids)", + new MapSqlParameterSource().addValue("ids", entityIds)); + } - return relyingParty; - } + private RelyingParty fakeRelyingParty(String entityId) throws Exception { + RelyingParty relyingParty; + String relyingPartyXml = fakeRelyingPartyXml(entityId); - private String fakeRelyingPartyXml(String entityId){ - String xml = ("\n" + - " \n" + + relyingParty = + new RelyingParty( + DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new ByteArrayInputStream(relyingPartyXml.getBytes())) + .getDocumentElement(), + "uwrp", + true, + "mattjm", + "2001-01-01", + null, + genUUID()); + + return relyingParty; + } + + private String fakeRelyingPartyXml(String entityId) { + String xml = + ("\n" + + " \n" + + // no keydescriptor in the dao test, test elsewhere // " ...\n" +*/ - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " AIE-IAM urizen4 test and development\n" + - " Urizen4 est and dev system for AIE-IAM\n" + - " https://urizen4.cac.washington.edu/\n" + - " \n" + - " \n" + - " J F\n" + - " jf@example.com\n" + - " \n" + - " \n" + - " J F\n" + - " jf@example.com\n" + - " \n" + - " \n" + - " Super Bob\n" + - " bob@spud.edu\n" + - " \n" + - " ") - .replace("{entityId}", entityId); - return xml; - } - - - + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " AIE-IAM urizen4 test and development\n" + + " Urizen4 est and dev system for AIE-IAM\n" + + " https://urizen4.cac.washington.edu/\n" + + " \n" + + " \n" + + " J F\n" + + " jf@example.com\n" + + " \n" + + " \n" + + " J F\n" + + " jf@example.com\n" + + " \n" + + " \n" + + " Super Bob\n" + + " bob@spud.edu\n" + + " \n" + + " ") + .replace("{entityId}", entityId); + return xml; + } } diff --git a/src/test/java/edu/washington/iam/registry/filter/FilterPolicyManagerTest.java b/src/test/java/edu/washington/iam/registry/filter/FilterPolicyManagerTest.java index 86d89a8..bda4476 100644 --- a/src/test/java/edu/washington/iam/registry/filter/FilterPolicyManagerTest.java +++ b/src/test/java/edu/washington/iam/registry/filter/FilterPolicyManagerTest.java @@ -1,38 +1,37 @@ package edu.washington.iam.registry.filter; +import java.util.List; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.junit.Assert; - -import java.util.List; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class FilterPolicyManagerTest { - @Autowired - private FilterPolicyManager filterPolicyManager; - - @Test - public void testGetAttributes() throws Exception { - List attributes = filterPolicyManager.getAttributes(); - Assert.assertNotNull(attributes); - Assert.assertTrue(attributes.size() > 0); + @Autowired private FilterPolicyManager filterPolicyManager; - } + @Test + public void testGetAttributes() throws Exception { + List attributes = filterPolicyManager.getAttributes(); + Assert.assertNotNull(attributes); + Assert.assertTrue(attributes.size() > 0); + } - @Test - public void testGetFilterPolicy() throws Exception { - FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); - filterPolicyGroup.setId("UW"); - AttributeFilterPolicy attributeFilterPolicy = - filterPolicyManager.getFilterPolicy(filterPolicyGroup, "https://diafine3.cac.washington.edu/shibboleth"); - Assert.assertNotNull(attributeFilterPolicy); - Assert.assertEquals(8, attributeFilterPolicy.getAttributeRules().size()); - attributeFilterPolicy = filterPolicyManager.getFilterPolicy(filterPolicyGroup, - "https://jpf.cac.washington.edu/shibboleth"); - Assert.assertNull(attributeFilterPolicy); - } + @Test + public void testGetFilterPolicy() throws Exception { + FilterPolicyGroup filterPolicyGroup = new FilterPolicyGroup(); + filterPolicyGroup.setId("UW"); + AttributeFilterPolicy attributeFilterPolicy = + filterPolicyManager.getFilterPolicy( + filterPolicyGroup, "https://diafine3.cac.washington.edu/shibboleth"); + Assert.assertNotNull(attributeFilterPolicy); + Assert.assertEquals(8, attributeFilterPolicy.getAttributeRules().size()); + attributeFilterPolicy = + filterPolicyManager.getFilterPolicy( + filterPolicyGroup, "https://jpf.cac.washington.edu/shibboleth"); + Assert.assertNull(attributeFilterPolicy); + } } diff --git a/src/test/java/edu/washington/iam/registry/filter/XMLFilterPolicyDAOTest.java b/src/test/java/edu/washington/iam/registry/filter/XMLFilterPolicyDAOTest.java index c9cb071..43b1dbb 100644 --- a/src/test/java/edu/washington/iam/registry/filter/XMLFilterPolicyDAOTest.java +++ b/src/test/java/edu/washington/iam/registry/filter/XMLFilterPolicyDAOTest.java @@ -1,5 +1,6 @@ package edu.washington.iam.registry.filter; +import java.util.List; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -7,17 +8,14 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import java.util.List; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class XMLFilterPolicyDAOTest { - @Autowired - private XMLFilterPolicyDAO dao; + @Autowired private XMLFilterPolicyDAO dao; - @Test - public void testGetFilterPolicyGroups() throws Exception { - List filterPolicyGroups = dao.getFilterPolicyGroups(); - Assert.assertEquals(1, filterPolicyGroups.size()); - } + @Test + public void testGetFilterPolicyGroups() throws Exception { + List filterPolicyGroups = dao.getFilterPolicyGroups(); + Assert.assertEquals(1, filterPolicyGroups.size()); + } } diff --git a/src/test/java/edu/washington/iam/registry/proxy/ProxyManagerDBTest.java b/src/test/java/edu/washington/iam/registry/proxy/ProxyManagerDBTest.java index 77b1033..5953e75 100644 --- a/src/test/java/edu/washington/iam/registry/proxy/ProxyManagerDBTest.java +++ b/src/test/java/edu/washington/iam/registry/proxy/ProxyManagerDBTest.java @@ -8,50 +8,47 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:test-db-context.xml") public class ProxyManagerDBTest { - /* Integration tests commented out to placate CI */ - @Autowired - private ProxyManagerDB dao; - - @Autowired - private JdbcTemplate template; - - @Test - public void testGetProxy() throws Exception { - Proxy p = dao.getProxy("https://gettest.example.com"); - - Assert.assertNotNull(p); - Assert.assertEquals("https://gettest.example.com", p.getEntityId()); - Assert.assertEquals(true, p.getSocialActive()); - Assert.assertNotNull(p.getUuid()); - } - - /* - @Test - public void testUpdateProxy() throws Exception { - Proxy p = new Proxy(); - p.setEntityId("https://www.example.com"); - List proxyIdps = new ArrayList<>(); - ProxyIdp proxyIdp = new ProxyIdp(); - proxyIdp.setIdp("Facebook"); - proxyIdp.setClientSecret("letmein"); - proxyIdp.setClientId("facebookguy"); - proxyIdps.add(proxyIdp); - proxyIdp = new ProxyIdp(); - proxyIdp.setIdp("Twitter"); - proxyIdp.setClientSecret("shhhh"); - proxyIdp.setClientId("twitterguy"); - proxyIdps.add(proxyIdp); - p.setProxyIdps(proxyIdps); - dao.updateProxy(p); - } - - @Test - public void testRemoveRelyingParty() - { - dao.removeProxy("https://www.example.com"); - }*/ + /* Integration tests commented out to placate CI */ + @Autowired private ProxyManagerDB dao; + + @Autowired private JdbcTemplate template; + + @Test + public void testGetProxy() throws Exception { + Proxy p = dao.getProxy("https://gettest.example.com"); + + Assert.assertNotNull(p); + Assert.assertEquals("https://gettest.example.com", p.getEntityId()); + Assert.assertEquals(true, p.getSocialActive()); + Assert.assertNotNull(p.getUuid()); + } + + /* + @Test + public void testUpdateProxy() throws Exception { + Proxy p = new Proxy(); + p.setEntityId("https://www.example.com"); + List proxyIdps = new ArrayList<>(); + ProxyIdp proxyIdp = new ProxyIdp(); + proxyIdp.setIdp("Facebook"); + proxyIdp.setClientSecret("letmein"); + proxyIdp.setClientId("facebookguy"); + proxyIdps.add(proxyIdp); + proxyIdp = new ProxyIdp(); + proxyIdp.setIdp("Twitter"); + proxyIdp.setClientSecret("shhhh"); + proxyIdp.setClientId("twitterguy"); + proxyIdps.add(proxyIdp); + p.setProxyIdps(proxyIdps); + dao.updateProxy(p); + } + + @Test + public void testRemoveRelyingParty() + { + dao.removeProxy("https://www.example.com"); + }*/ } diff --git a/src/test/java/edu/washington/iam/registry/rp/DBMetadataTest.java b/src/test/java/edu/washington/iam/registry/rp/DBMetadataTest.java index f8ae091..c606456 100644 --- a/src/test/java/edu/washington/iam/registry/rp/DBMetadataTest.java +++ b/src/test/java/edu/washington/iam/registry/rp/DBMetadataTest.java @@ -1,6 +1,13 @@ package edu.washington.iam.registry.rp; import edu.washington.iam.registry.exception.RelyingPartyException; +import java.io.ByteArrayInputStream; +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import javax.xml.parsers.DocumentBuilderFactory; import org.junit.*; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -10,211 +17,227 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.ByteArrayInputStream; -import java.sql.Timestamp; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.UUID; - - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:test-db-context.xml") public class DBMetadataTest { - @Autowired - private DBMetadata dao; - @Autowired - private JdbcTemplate template; - - private List fakeEntityIds = Arrays.asList("testsp1", "testsp2", "testsp3", "testsp4", - "https://dbmetadatatest.s.uw.edu/shibboleth", - "https://searchdbmetadatatest.s.uw.edu", - "https://searchdbmetadatatest2.s.uw.edu", - "https://searchdbmetadatatest3.s.uw.edu"); - - @Before - public void setupInitialData() { - setupWithRPs(fakeEntityIds); - } - - @After - public void teardown(){ - teardownRPs(fakeEntityIds); - } - - @Test - public void testSearchRelyingPartyIdsNullSearch() throws Exception { - List ids = dao.searchRelyingPartyIds(null); - Assert.assertTrue(ids.size() > 5); - } - - @Test - public void testSearchRelyingPartyIds() throws Exception { - List ids = dao.searchRelyingPartyIds("searchdbmetadatatest"); - Assert.assertEquals(3, ids.size()); - } - - @Test - public void testSearchRelyingPartyIdsNoDeleted() throws Exception { - template.update("update metadata set end_time = '2001-01-01' where entity_id = ?", - "https://searchdbmetadatatest2.s.uw.edu"); - List relyingParties = dao.searchRelyingPartyIds("searchdbmetadatatest"); - Assert.assertEquals(2, relyingParties.size()); - } - - @Test - public void testGetRelyingPartyById() throws Exception { - RelyingParty relyingParty = dao.getRelyingPartyById("https://dbmetadatatest.s.uw.edu/shibboleth"); - Assert.assertNotNull(relyingParty); - } - - @Test - public void testGetRelyingPartyByIdNoParty() throws Exception { - boolean caughtException = false; - try { - dao.getRelyingPartyById("doublefoobar"); - } - catch (RelyingPartyException e){ - caughtException = true; - } - Assert.assertTrue(caughtException); - } - - @Test - public void testGetRelyingPartyByIdBigTest() throws Exception { - boolean atLeastOnce = false; - for(String rpId : dao.searchRelyingPartyIds(null)){ - atLeastOnce = true; - RelyingParty relyingParty = dao.getRelyingPartyById(rpId); - Assert.assertNotNull(relyingParty); - } - Assert.assertTrue(atLeastOnce); - } - - @Test - public void testRemoveRelyingParty(){ - dao.removeRelyingParty(fakeEntityIds.get(0), "testuser"); - List ids = dao.searchRelyingPartyIds(null); - Assert.assertEquals(fakeEntityIds.size() - 1, ids.size()); - } - - @Test - public void testUpdateRelyingPartyNewRP() throws Exception { - String entityId = "https://updaterelyingpartynewrp.s.uw.edu"; - RelyingParty relyingParty = fakeRelyingParty(entityId); - - dao.updateRelyingParty(relyingParty, "testuser"); - - //make sure uuids come along for the update - RelyingParty testUUID = dao.getRelyingPartyById(relyingParty.getEntityId()); - Assert.assertTrue(testUUID.getUuid().toString().length() > 30); - - List ids = dao.searchRelyingPartyIds(null); - Assert.assertEquals(fakeEntityIds.size() + 1, ids.size()); - Assert.assertTrue(String.format("list of entity ids contains %s", entityId), ids.contains(entityId)); - } - - @Test - public void testUpdateRelyingPartyExistingRP() throws Exception { - Thread.sleep(500); - Timestamp preUpdateTime = new Timestamp(new Date().getTime()); - Assert.assertTrue(getTimestampForRP(fakeEntityIds.get(0)).before(preUpdateTime)); - int preUpdateSize = dao.searchRelyingPartyIds(null).size(); - - dao.updateRelyingParty(fakeRelyingParty(fakeEntityIds.get(0)), "testuser"); - - Assert.assertTrue(String.format("update time for %s has changed", fakeEntityIds.get(0)), - getTimestampForRP(fakeEntityIds.get(0)).after(preUpdateTime)); - Assert.assertEquals(preUpdateSize, dao.searchRelyingPartyIds(null).size()); - } - - @Test - public void testUpdateRelyingPartyDeletedRP() throws Exception { - template.update("update metadata set end_time = '2001-01-01' where entity_id = ? ", fakeEntityIds.get(0)); - Timestamp preUpdateTime = new Timestamp(new Date().getTime()); - Thread.sleep(500); - int preUpdateSize = dao.searchRelyingPartyIds(null).size(); - - //TODO: to make this test work we need to get the UUID here and store it - - dao.updateRelyingParty(fakeRelyingParty(fakeEntityIds.get(0)), "testuser"); - - //TODO: Then get the UUID of the entity again here and compare it the previous one--it should be different - - Assert.assertTrue(String.format("update time for %s has changed", fakeEntityIds.get(0)), - getTimestampForRP(fakeEntityIds.get(0)).after(preUpdateTime)); - Assert.assertEquals(preUpdateSize + 1, dao.searchRelyingPartyIds(null).size()); - } - - private Timestamp getTimestampForRP(String entityId){ - return template.queryForObject("select start_time from metadata where entity_id = ? and end_time is null", - Timestamp.class, - entityId); - } - - private UUID genUUID() { return UUID.randomUUID(); } - - private void setupWithRPs(List entityIds){ - String groupId = "uwrp"; - for (String entityId : entityIds) { - - template.update("insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time) " + - "values (?, ?, ?, ?, ?, now())", - genUUID(), groupId, entityId, fakeRelyingPartyXml(entityId), null); - } - } - - private void teardownRPs(List entityIds){ - NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); - namedTemplate.update("delete from metadata where entity_id in (:ids)", - new MapSqlParameterSource().addValue("ids", entityIds)); - } - - private RelyingParty fakeRelyingParty(String entityId) throws Exception { - RelyingParty relyingParty; - String relyingPartyXml = fakeRelyingPartyXml(entityId); - - relyingParty = new RelyingParty( - DocumentBuilderFactory - .newInstance() - .newDocumentBuilder() - .parse(new ByteArrayInputStream(relyingPartyXml.getBytes())) - .getDocumentElement(), - "uwrp", true, "mattjm", "2001-01-01", null, genUUID()); - - return relyingParty; - } - - private String fakeRelyingPartyXml(String entityId){ - String xml = ("\n" + - " \n" + + @Autowired private DBMetadata dao; + @Autowired private JdbcTemplate template; + + private List fakeEntityIds = + Arrays.asList( + "testsp1", + "testsp2", + "testsp3", + "testsp4", + "https://dbmetadatatest.s.uw.edu/shibboleth", + "https://searchdbmetadatatest.s.uw.edu", + "https://searchdbmetadatatest2.s.uw.edu", + "https://searchdbmetadatatest3.s.uw.edu"); + + @Before + public void setupInitialData() { + setupWithRPs(fakeEntityIds); + } + + @After + public void teardown() { + teardownRPs(fakeEntityIds); + } + + @Test + public void testSearchRelyingPartyIdsNullSearch() throws Exception { + List ids = dao.searchRelyingPartyIds(null); + Assert.assertTrue(ids.size() > 5); + } + + @Test + public void testSearchRelyingPartyIds() throws Exception { + List ids = dao.searchRelyingPartyIds("searchdbmetadatatest"); + Assert.assertEquals(3, ids.size()); + } + + @Test + public void testSearchRelyingPartyIdsNoDeleted() throws Exception { + template.update( + "update metadata set end_time = '2001-01-01' where entity_id = ?", + "https://searchdbmetadatatest2.s.uw.edu"); + List relyingParties = dao.searchRelyingPartyIds("searchdbmetadatatest"); + Assert.assertEquals(2, relyingParties.size()); + } + + @Test + public void testGetRelyingPartyById() throws Exception { + RelyingParty relyingParty = + dao.getRelyingPartyById("https://dbmetadatatest.s.uw.edu/shibboleth"); + Assert.assertNotNull(relyingParty); + } + + @Test + public void testGetRelyingPartyByIdNoParty() throws Exception { + boolean caughtException = false; + try { + dao.getRelyingPartyById("doublefoobar"); + } catch (RelyingPartyException e) { + caughtException = true; + } + Assert.assertTrue(caughtException); + } + + @Test + public void testGetRelyingPartyByIdBigTest() throws Exception { + boolean atLeastOnce = false; + for (String rpId : dao.searchRelyingPartyIds(null)) { + atLeastOnce = true; + RelyingParty relyingParty = dao.getRelyingPartyById(rpId); + Assert.assertNotNull(relyingParty); + } + Assert.assertTrue(atLeastOnce); + } + + @Test + public void testRemoveRelyingParty() { + dao.removeRelyingParty(fakeEntityIds.get(0), "testuser"); + List ids = dao.searchRelyingPartyIds(null); + Assert.assertEquals(fakeEntityIds.size() - 1, ids.size()); + } + + @Test + public void testUpdateRelyingPartyNewRP() throws Exception { + String entityId = "https://updaterelyingpartynewrp.s.uw.edu"; + RelyingParty relyingParty = fakeRelyingParty(entityId); + + dao.updateRelyingParty(relyingParty, "testuser"); + + // make sure uuids come along for the update + RelyingParty testUUID = dao.getRelyingPartyById(relyingParty.getEntityId()); + Assert.assertTrue(testUUID.getUuid().toString().length() > 30); + + List ids = dao.searchRelyingPartyIds(null); + Assert.assertEquals(fakeEntityIds.size() + 1, ids.size()); + Assert.assertTrue( + String.format("list of entity ids contains %s", entityId), ids.contains(entityId)); + } + + @Test + public void testUpdateRelyingPartyExistingRP() throws Exception { + Thread.sleep(500); + Timestamp preUpdateTime = new Timestamp(new Date().getTime()); + Assert.assertTrue(getTimestampForRP(fakeEntityIds.get(0)).before(preUpdateTime)); + int preUpdateSize = dao.searchRelyingPartyIds(null).size(); + + dao.updateRelyingParty(fakeRelyingParty(fakeEntityIds.get(0)), "testuser"); + + Assert.assertTrue( + String.format("update time for %s has changed", fakeEntityIds.get(0)), + getTimestampForRP(fakeEntityIds.get(0)).after(preUpdateTime)); + Assert.assertEquals(preUpdateSize, dao.searchRelyingPartyIds(null).size()); + } + + @Test + public void testUpdateRelyingPartyDeletedRP() throws Exception { + template.update( + "update metadata set end_time = '2001-01-01' where entity_id = ? ", fakeEntityIds.get(0)); + Timestamp preUpdateTime = new Timestamp(new Date().getTime()); + Thread.sleep(500); + int preUpdateSize = dao.searchRelyingPartyIds(null).size(); + + // TODO: to make this test work we need to get the UUID here and store it + + dao.updateRelyingParty(fakeRelyingParty(fakeEntityIds.get(0)), "testuser"); + + // TODO: Then get the UUID of the entity again here and compare it the previous one--it should + // be different + + Assert.assertTrue( + String.format("update time for %s has changed", fakeEntityIds.get(0)), + getTimestampForRP(fakeEntityIds.get(0)).after(preUpdateTime)); + Assert.assertEquals(preUpdateSize + 1, dao.searchRelyingPartyIds(null).size()); + } + + private Timestamp getTimestampForRP(String entityId) { + return template.queryForObject( + "select start_time from metadata where entity_id = ? and end_time is null", + Timestamp.class, + entityId); + } + + private UUID genUUID() { + return UUID.randomUUID(); + } + + private void setupWithRPs(List entityIds) { + String groupId = "uwrp"; + for (String entityId : entityIds) { + + template.update( + "insert into metadata (uuid, group_id, entity_id, xml, end_time, start_time) " + + "values (?, ?, ?, ?, ?, now())", + genUUID(), + groupId, + entityId, + fakeRelyingPartyXml(entityId), + null); + } + } + + private void teardownRPs(List entityIds) { + NamedParameterJdbcTemplate namedTemplate = new NamedParameterJdbcTemplate(template); + namedTemplate.update( + "delete from metadata where entity_id in (:ids)", + new MapSqlParameterSource().addValue("ids", entityIds)); + } + + private RelyingParty fakeRelyingParty(String entityId) throws Exception { + RelyingParty relyingParty; + String relyingPartyXml = fakeRelyingPartyXml(entityId); + + relyingParty = + new RelyingParty( + DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(new ByteArrayInputStream(relyingPartyXml.getBytes())) + .getDocumentElement(), + "uwrp", + true, + "mattjm", + "2001-01-01", + null, + genUUID()); + + return relyingParty; + } + + private String fakeRelyingPartyXml(String entityId) { + String xml = + ("\n" + + " \n" + + // no keydescriptor in the dao test, test elsewhere // " ...\n" +*/ - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " AIE-IAM urizen4 test and development\n" + - " Urizen4 est and dev system for AIE-IAM\n" + - " https://urizen4.cac.washington.edu/\n" + - " \n" + - " \n" + - " J F\n" + - " jf@example.com\n" + - " \n" + - " \n" + - " J F\n" + - " jf@example.com\n" + - " \n" + - " \n" + - " Super Bob\n" + - " bob@spud.edu\n" + - " \n" + - " ") - .replace("{entityId}", entityId); - return xml; - } + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " AIE-IAM urizen4 test and development\n" + + " Urizen4 est and dev system for AIE-IAM\n" + + " https://urizen4.cac.washington.edu/\n" + + " \n" + + " \n" + + " J F\n" + + " jf@example.com\n" + + " \n" + + " \n" + + " J F\n" + + " jf@example.com\n" + + " \n" + + " \n" + + " Super Bob\n" + + " bob@spud.edu\n" + + " \n" + + " ") + .replace("{entityId}", entityId); + return xml; + } } diff --git a/src/test/java/edu/washington/iam/registry/rp/RelyingPartyManagerImplTest.java b/src/test/java/edu/washington/iam/registry/rp/RelyingPartyManagerImplTest.java index 200bd76..e1de7d7 100644 --- a/src/test/java/edu/washington/iam/registry/rp/RelyingPartyManagerImplTest.java +++ b/src/test/java/edu/washington/iam/registry/rp/RelyingPartyManagerImplTest.java @@ -1,7 +1,7 @@ package edu.washington.iam.registry.rp; -import org.junit.Test; import org.junit.Assert; +import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; @@ -10,27 +10,22 @@ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class RelyingPartyManagerImplTest { - @Autowired - private RelyingPartyManagerImpl rpManager; - - @org.junit.Before - public void setUp() throws Exception { - - } + @Autowired private RelyingPartyManagerImpl rpManager; - @org.junit.After - public void tearDown() throws Exception { + @org.junit.Before + public void setUp() throws Exception {} - } + @org.junit.After + public void tearDown() throws Exception {} - @Test - public void testGenRelyingPartyByName() throws Exception { - RelyingParty rp = rpManager.genRelyingPartyByName("https://www.example.com", "www.example.com"); - Assert.assertEquals("https://www.example.com", rp.getEntityId()); - } + @Test + public void testGenRelyingPartyByName() throws Exception { + RelyingParty rp = rpManager.genRelyingPartyByName("https://www.example.com", "www.example.com"); + Assert.assertEquals("https://www.example.com", rp.getEntityId()); + } - @Test - public void testGetMetadataIds() throws Exception { - Assert.assertTrue(rpManager.getMetadataIds().contains("UW")); - } + @Test + public void testGetMetadataIds() throws Exception { + Assert.assertTrue(rpManager.getMetadataIds().contains("UW")); + } }