Skip to content

Commit

Permalink
Resolved merge conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
rmathis committed Aug 29, 2022
2 parents 2813d25 + 86e0b01 commit b26d925
Show file tree
Hide file tree
Showing 13 changed files with 741 additions and 392 deletions.
Original file line number Diff line number Diff line change
@@ -1,70 +0,0 @@
package edu.internet2.tier.shibboleth.admin.ui.service

import com.opencsv.CSVReader
import edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties.ShibConfigurationProperty
import groovy.util.logging.Slf4j
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.context.event.ApplicationStartedEvent
import org.springframework.context.event.EventListener
import org.springframework.core.io.ClassPathResource
import org.springframework.core.io.Resource
import org.springframework.stereotype.Component

import javax.transaction.Transactional

@Component
@Slf4j
class ShibPropertiesBootstrap {
@Autowired
private ShibConfigurationService service

ShibPropertiesBootstrap(ShibConfigurationService service) {
this.service = service
}

@Transactional
@EventListener
void bootstrapUsersAndRoles(ApplicationStartedEvent e) {
log.info("Ensuring base Shibboleth properties configuration has loaded")

Resource resource = new ClassPathResource('shib_configuration_prop.csv')
final HashMap<String, ShibConfigurationProperty> propertiesMap = new HashMap<>()

// Read in the defaults in the configuration file
new CSVReader(new InputStreamReader(resource.inputStream)).each { fields ->
def (resource_id,category,config_file,description,idp_version,module,module_version,note,default_value,property_name,property_type,selection_items,property_value) = fields
ShibConfigurationProperty prop = new ShibConfigurationProperty().with {
it.resourceId = resource_id
it.category = category
it.configFile = config_file
it.description = description
it.idpVersion = idp_version
it.module = module
it.moduleVersion = module_version
it.note = note
it.defaultValue = default_value
it.description = description
it.propertyName = property_name
def pt = property_type
it.setPropertyType(pt)
it.selectionItems = selection_items
// we shouldn't have property values coming in from the config...
it
}
propertiesMap.put(prop.getPropertyName(), prop)
}

// If we already have the property in the db, ignore the configuration setup for that property
service.getExistingPropertyNames().each {
propertiesMap.remove(it)
}

// Save anything that's left
if (propertiesMap.size() > 0) {
log.info("Saving/loading [" + propertiesMap.size() + "] properties to the database")
service.addAllConfigurationProperties(propertiesMap.values())
}

log.info("COMPLETED: ensuring base Shibboleth properties configuration has loaded")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import edu.internet2.tier.shibboleth.admin.ui.domain.IRelyingPartyOverrideProperty;
import edu.internet2.tier.shibboleth.admin.ui.domain.RelyingPartyOverrideProperty;
import edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties.ShibConfigurationProperty;
import edu.internet2.tier.shibboleth.admin.ui.service.CustomEntityAttributesDefinitionService;
import edu.internet2.tier.shibboleth.admin.ui.service.ShibConfigurationService;
import edu.internet2.tier.shibboleth.admin.ui.service.events.CustomEntityAttributeDefinitionChangeEvent;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,139 +0,0 @@
package edu.internet2.tier.shibboleth.admin.ui.controller;

import edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties.ShibPropertySet;
import edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties.ShibPropertySetting;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.service.ShibConfigurationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.tags.Tags;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping(value = "/api/shib")
@Tags(value = {@Tag(name = "Shibboleth Properties")})
public class ShibPropertiesController {
@Autowired
private ShibConfigurationService service;

@GetMapping("/properties")
@Transactional(readOnly = true)
@Operation(description = "Return all the configuration properties - used to populate the UI with the know configuration properties",
summary = "Return all the configuration properties - used to populate the UI with the know configuration properties", method = "GET")
public ResponseEntity<?> getAllConfigurationProperties() {
return ResponseEntity.ok(service.getAllConfigurationProperties());
}

/**
* @return a List of the set names and their ids
*/
@GetMapping("/property/set")
@Transactional(readOnly = true)
@Operation(description = "Return a list of all the set names and their resourceId",
summary = "Return a list of all the set names and their resourceId", method = "GET")
public ResponseEntity<?> getAllPropertySets() {
return ResponseEntity.ok(service.getAllPropertySets());
}

@GetMapping(value="/property/set/{resourceId}", produces="applcation/json")
@Transactional(readOnly = true)
@Operation(description = "Return the property set with the given resourceId",
summary = "Return the property set with the given resourceId", method = "GET")
public ResponseEntity<?> getPropertySet(@PathVariable Integer resourceId) throws EntityNotFoundException {
return ResponseEntity.ok(service.getSet(resourceId));
}

@GetMapping(value="/property/set/{resourceId}", produces="application/zip")
@Transactional(readOnly = true)
@Operation(description = "Return the property set with the given resourceId as a zip file of the properties files",
summary = "Return the property set with the given resourceId as a zip file of the properties files", method = "GET")
public ResponseEntity<?> getPropertySetAsZip(@PathVariable Integer resourceId) throws EntityNotFoundException, IOException {
ShibPropertySet set = service.getSet(resourceId);
StringBuilder sb = new StringBuilder("attachment; filename=\"").append(set.getName()).append(".zip\"");
return ResponseEntity.ok().header("Content-Disposition", sb.toString()).body(prepDownloadAsZip(convertPropertiesToMaps(set.getProperties())));
}

private Map<String, Map<String,String>> convertPropertiesToMaps(List<ShibPropertySetting> properties) {
HashMap<String, Map<String,String>> result = new HashMap<>();
for (ShibPropertySetting setting:properties){
String confFile = setting.getConfigFile();
if (!result.containsKey(confFile)) {
Map<String,String> props = new HashMap<>();
result.put(confFile,props);
}
Map<String,String> props = result.get(confFile);
props.put(setting.getPropertyName(), setting.getPropertyValue());
}
return result;
}

private byte[] prepDownloadAsZip(Map<String, Map<String,String>> propertiesFiles) throws IOException {
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
ZipOutputStream zipOutputStream = new ZipOutputStream(byteOutputStream);

for (String filename : propertiesFiles.keySet()) {
zipOutputStream.putNextEntry(new ZipEntry(filename));
Map<String, String> properties = propertiesFiles.get(filename);
StringBuilder props = new StringBuilder();
for (String key : properties.keySet()) {
props.append(key).append("=").append(properties.get(key)).append("\n");
}
ByteArrayInputStream inputStream = new ByteArrayInputStream(props.toString().getBytes());
IOUtils.copy(inputStream, zipOutputStream);
zipOutputStream.closeEntry();
}
zipOutputStream.close();
return byteOutputStream.toByteArray();
}

@DeleteMapping("/property/set/{resourceId}")
@Secured("ROLE_ADMIN")
@Transactional
public ResponseEntity<?> deletePropertySet(@PathVariable Integer resourceId) throws EntityNotFoundException {
service.delete(resourceId);
return ResponseEntity.noContent().build();
}

@PostMapping("/property/set")
@Secured("ROLE_ADMIN")
@Transactional
@Operation(description = "Create a property set with all new information - must not be an existing set",
summary = "Create a property set with all new information - must not be an existing set", method = "POST")
public ResponseEntity<?> createPropertySet(@RequestBody ShibPropertySet newSet) throws ObjectIdExistsException {
ShibPropertySet result = service.create(newSet);
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

@PutMapping("/property/set/{resourceId}")
@Secured("ROLE_ADMIN")
@Transactional
@Operation(description = "Update a property set with with the matching resourceId - must exist",
summary = "Update an existing property set with the matching resourceId - must exist", method = "PUT")
public ResponseEntity<?> updatePropertySet(@RequestBody ShibPropertySet setToUpdate, @PathVariable int resourceId) throws EntityNotFoundException {
ShibPropertySet result = service.update(setToUpdate);
return ResponseEntity.status(HttpStatus.OK).body(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package edu.internet2.tier.shibboleth.admin.ui.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import edu.internet2.tier.shibboleth.admin.util.EmptyStringToNullConverter;
import lombok.Data;
import org.hibernate.envers.Audited;

import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.UUID;

@Entity(name = "shib_configuration_prop")
@Audited
@Data
public class ShibConfigurationProperty {
@Id
@Column(name = "resource_id", nullable = false)
String resourceId = UUID.randomUUID().toString();

@Column(name = "category", nullable = false)
String category;

@Column(name = "config_file", nullable = false)
String configFile;

@Column(name = "default_value")
@Convert(converter = EmptyStringToNullConverter.class)
String defaultValue;

@Column(name = "description")
@Convert(converter = EmptyStringToNullConverter.class)
String description;

@Column(name = "idp_version", nullable = false)
String idpVersion;

@Column(name = "module")
@Convert(converter = EmptyStringToNullConverter.class)
String module;

@Column(name = "module_version")
@Convert(converter = EmptyStringToNullConverter.class)
String moduleVersion;

@Column(name = "note")
@Convert(converter = EmptyStringToNullConverter.class)
String note;

@Column(name = "property_name", nullable = false)
String propertyName;

@Column(name = "property_type", nullable = false)
@JsonIgnore // display type is sent to the ui instead
PropertyType propertyType;

@Column(name = "selection_items")
@Convert(converter = EmptyStringToNullConverter.class)
String selectionItems;

public String getDisplayType() {
switch (propertyType) {
case BOOLEAN:
return propertyType.name().toLowerCase();
case INTEGER:
return "number";
case SELECTION_LIST:
return "list";
default: // DURATION, SPRING_BEAN_ID, STRING
return "string";
}
}

public void setPropertyType(String val) {
this.propertyType = PropertyType.valueOf(val);
}

}

enum PropertyType {
BOOLEAN, DURATION, INTEGER, SELECTION_LIST, SPRING_BEAN_ID, STRING
}
Original file line number Diff line number Diff line change
@@ -1,15 +0,0 @@
package edu.internet2.tier.shibboleth.admin.ui.repository;

import edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties.ShibConfigurationProperty;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

/**
* Repository to manage {@link ShibConfigurationProperty} instances.
*/
public interface ShibConfigurationRepository extends JpaRepository<ShibConfigurationProperty, String> {
@Query(value = "select property_name from shib_configuration_prop", nativeQuery = true)
List<String> getPropertyNames();
}
Original file line number Diff line number Diff line change
@@ -1,30 +0,0 @@
package edu.internet2.tier.shibboleth.admin.ui.service;

import edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties.ShibConfigurationProperty;
import edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties.ShibPropertySet;
import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import edu.internet2.tier.shibboleth.admin.ui.repository.ProjectionIdAndName;

import java.util.Collection;
import java.util.List;

public interface ShibConfigurationService {
void addAllConfigurationProperties(Collection<ShibConfigurationProperty> newProperties);

ShibPropertySet create(ShibPropertySet set) throws ObjectIdExistsException;

void delete(int resourceId) throws EntityNotFoundException;

List<ShibConfigurationProperty> getAllConfigurationProperties();

List<ProjectionIdAndName> getAllPropertySets();

List<String> getExistingPropertyNames();

ShibPropertySet getSet(int resourceId) throws EntityNotFoundException;

ShibConfigurationProperty save(ShibConfigurationProperty prop);

ShibPropertySet update(ShibPropertySet setToUpdate) throws EntityNotFoundException;
}
Loading

0 comments on commit b26d925

Please sign in to comment.