Skip to content

Commit

Permalink
Merge branch 'feature/shibui-2270' of bitbucket.org:unicon/shib-idp-u…
Browse files Browse the repository at this point in the history
…i into feature/SHIBUI-2270-property-list
  • Loading branch information
rmathis committed Aug 26, 2022
2 parents 4afa8fd + 705bc57 commit 63fde81
Show file tree
Hide file tree
Showing 18 changed files with 833 additions and 676 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package edu.internet2.tier.shibboleth.admin.ui.service

import com.opencsv.CSVReader
import edu.internet2.tier.shibboleth.admin.ui.domain.ShibConfigurationProperty
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
Expand Down Expand Up @@ -62,7 +62,7 @@ class ShibPropertiesBootstrap {
// Save anything that's left
if (propertiesMap.size() > 0) {
log.info("Saving/loading [" + propertiesMap.size() + "] properties to the database")
service.addAll(propertiesMap.values())
service.addAllConfigurationProperties(propertiesMap.values())
}

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

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.ShibConfigurationProperty;
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,15 +1,37 @@
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")})
Expand All @@ -19,7 +41,99 @@ public class ShibPropertiesController {

@GetMapping("/properties")
@Transactional(readOnly = true)
public ResponseEntity<?> getAll() {
return ResponseEntity.ok(service.getAll());
@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,35 @@
package edu.internet2.tier.shibboleth.admin.ui.controller;

import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.exception.ObjectIdExistsException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import java.io.IOException;

@ControllerAdvice(assignableTypes = {ShibPropertiesController.class})
public class ShibPropertiesControllerExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({ EntityNotFoundException.class })
public ResponseEntity<?> handleEntityNotFoundException(EntityNotFoundException e, WebRequest request) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse(HttpStatus.NOT_FOUND, e.getMessage()));
}

@ExceptionHandler({ IOException.class })
public ResponseEntity<?> handleIOException(EntityNotFoundException e, WebRequest request) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error creating file");
}

@ExceptionHandler({ ObjectIdExistsException.class })
public ResponseEntity<?> handleObjectIdExistsException(ObjectIdExistsException e, WebRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(EntityDescriptorController.getResourceUriFor(e.getMessage()));
return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(new ErrorResponse(
String.valueOf(HttpStatus.CONFLICT.value()),
String.format("The property set with id [%s] already exists.", e.getMessage())));
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package edu.internet2.tier.shibboleth.admin.ui.domain;
package edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties;

import com.fasterxml.jackson.annotation.JsonIgnore;
import edu.internet2.tier.shibboleth.admin.util.EmptyStringToNullConverter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties;

import edu.internet2.tier.shibboleth.admin.util.EmptyStringToNullConverter;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.envers.Audited;

import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;

@Entity(name = "shib_property_set")
@Audited
@Getter
@Setter
@ToString
@RequiredArgsConstructor
public class ShibPropertySet {
@Id
@GeneratedValue
private int resourceId;

@Column(unique = true, nullable = false)
@Convert(converter = EmptyStringToNullConverter.class)
private String name;

@OneToMany
private List<ShibPropertySetting> properties = new ArrayList<>();

@Override
public boolean equals(Object o) {
if (o instanceof ShibPropertySet) {
ShibPropertySet that = (ShibPropertySet) o;
boolean result = this.name.equals(that.name) && this.resourceId == that.resourceId && this.properties.size() == that.properties.size();
if (result == true) {
for (ShibPropertySetting thisSetting : this.properties) {
if ( !that.properties.contains(thisSetting) ) {
return false;
}
}
}
return result;
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package edu.internet2.tier.shibboleth.admin.ui.domain.shib.properties;

import lombok.Data;
import org.hibernate.envers.Audited;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity(name = "shib_property_setting")
@Audited
@Data
public class ShibPropertySetting {
@Id
@GeneratedValue
private int resourceId;

@Column
private String configFile;

@Column
private String propertyName;

@Column
private String propertyValue;

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package edu.internet2.tier.shibboleth.admin.ui.exception;

/**
* Generically meaning - hibernate entity, not SAML entity
*/
public class EntityNotFoundException extends Exception {
public EntityNotFoundException(String message) {
super(message);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package edu.internet2.tier.shibboleth.admin.ui.repository;

public interface ProjectionIdAndName{
String getResourceId();
String getName();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package edu.internet2.tier.shibboleth.admin.ui.repository;

import edu.internet2.tier.shibboleth.admin.ui.domain.ShibConfigurationProperty;
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;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package edu.internet2.tier.shibboleth.admin.ui.repository;

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

import java.util.List;

/**
* Repository to manage {@link ShibPropertySet} instances.
*/
public interface ShibPropertySetRepository extends JpaRepository<ShibPropertySet, String> {
ShibPropertySet findByName(String name);

ShibPropertySet findByResourceId(Integer id);

List<ProjectionIdAndName> findAllBy();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package edu.internet2.tier.shibboleth.admin.ui.repository;

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

/**
* Repository to manage {@link ShibPropertySetting} instances.
*/
public interface ShibPropertySettingRepository extends JpaRepository<ShibPropertySetting, String> {
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
package edu.internet2.tier.shibboleth.admin.ui.service;

import edu.internet2.tier.shibboleth.admin.ui.domain.ShibConfigurationProperty;
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 addAll(Collection<ShibConfigurationProperty> newProperties);
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();

void save(ShibConfigurationProperty prop);
ShibPropertySet getSet(int resourceId) throws EntityNotFoundException;

ShibConfigurationProperty save(ShibConfigurationProperty prop);

List<ShibConfigurationProperty> getAll();
ShibPropertySet update(ShibPropertySet setToUpdate) throws EntityNotFoundException;
}
Loading

0 comments on commit 63fde81

Please sign in to comment.