Skip to content

Commit

Permalink
Merge branch 'master' into feature/shibui-1774
Browse files Browse the repository at this point in the history
  • Loading branch information
chasegawa committed Jun 25, 2021
2 parents c5da066 + 21e875f commit c24e581
Show file tree
Hide file tree
Showing 962 changed files with 38,742 additions and 52,484 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ rdurable
build-no-tests

beacon/spring/out
/.classpath

# Eclipse junk
*.classpath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class EntityAttributesFiltersUiDefinitionController {
ResponseEntity<?> getUiDefinitionJsonSchema() {
try {
def parsedJson = jacksonObjectMapper.readValue(this.jsonSchemaLocation.url, Map)
jsonSchemaBuilderService.addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['widget'])
jsonSchemaBuilderService.addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['items'])
jsonSchemaBuilderService.addRelyingPartyOverridesToJson(parsedJson['properties']['relyingPartyOverrides'])
jsonSchemaBuilderService.addRelyingPartyOverridesCollectionDefinitionsToJson(parsedJson["definitions"])
return ResponseEntity.ok(parsedJson)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class MetadataSourcesUiDefinitionController {
try {
def parsedJson = jacksonObjectMapper.readValue(this.jsonSchemaLocation.url, Map)
jsonSchemaBuilderService.hideServiceEnabledFromNonAdmins(parsedJson)
jsonSchemaBuilderService.addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['widget'])
jsonSchemaBuilderService.addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['items'])
jsonSchemaBuilderService.addRelyingPartyOverridesToJson(parsedJson['properties']['relyingPartyOverrides'])
jsonSchemaBuilderService.addRelyingPartyOverridesCollectionDefinitionsToJson(parsedJson["definitions"])
return ResponseEntity.ok(parsedJson)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService {

void constructXmlNodeForResolver(DynamicHttpMetadataResolver resolver, def markupBuilderDelegate, Closure childNodes) {
markupBuilderDelegate.MetadataProvider(id: resolver.xmlId,
'xsi:type': 'DynamicHttpMetadataProvider',
'xsi:type': 'DynamicHTTPMetadataProvider',
requireValidMetadata: !resolver.requireValidMetadata ?: null,
failFastInitialization: !resolver.failFastInitialization ?: null,
sortKey: resolver.sortKey,
Expand Down Expand Up @@ -559,4 +559,4 @@ class JPAMetadataResolverServiceImpl implements MetadataResolverService {

}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class JsonSchemaBuilderService {
}

void addReleaseAttributesToJson(Object json) {
json['data'] = customPropertiesConfiguration.getAttributes().collect {
[key: it['name'], label: it['displayName']]
json['enum'] = customPropertiesConfiguration.getAttributes().collect {
it['name']
}
}

Expand All @@ -36,12 +36,8 @@ class JsonSchemaBuilderService {
property =
[title : it['displayName'],
description: it['helpText'],
type : it['displayType']]
if (it['displayType'] == 'boolean') {
property['default'] = Boolean.valueOf(it['defaultValue'])
} else {
property['default'] = it['defaultValue']
}
type : it['displayType'],
examples : it['examples']]
}
properties[(String) it['name']] = property
}
Expand All @@ -64,7 +60,7 @@ class JsonSchemaBuilderService {
def items = [type : 'string',
minLength: 1, // TODO: should this be configurable?
maxLength: 255] //TODO: or this?
items.widget = [id: 'datalist', data: it['defaultValues']]
items.examples = it['examples']

definition['items'] = items
json[(String) it['name']] = definition
Expand All @@ -76,7 +72,7 @@ class JsonSchemaBuilderService {
if (currentUser != null && currentUser.role != 'ROLE_ADMIN') {
// user isn't an admin, so hide 'ServiceEnabled'
Map<String, String> serviceEnabled = (HashMap) json['properties']['serviceEnabled']
serviceEnabled['widget'] = 'hidden'
serviceEnabled['readOnly'] = true
serviceEnabled.remove('title')
serviceEnabled.remove('description')
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package edu.internet2.tier.shibboleth.admin.ui.configuration;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.ShallowEtagHeaderFilter;

@Configuration
public class ETagsConfiguration {
@Bean
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
FilterRegistrationBean<ShallowEtagHeaderFilter> filterRegistrationBean = new FilterRegistrationBean<>(new ShallowEtagHeaderFilter());
filterRegistrationBean.addUrlPatterns("/api/entities/*", "/entities/*");
filterRegistrationBean.setName("etagFilter");
return filterRegistrationBean;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ public class WebSecurityConfig {
@Autowired
private RoleRepository roleRepository;

@Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
private HttpFirewall allowUrlEncodedSlashHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
firewall.setAllowUrlEncodedDoubleSlash(true);
return firewall;
}

@Bean
public HttpFirewall defaultFirewall() {
private HttpFirewall defaultFirewall() {
return new DefaultHttpFirewall();
}

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

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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.servlet.support.ServletUriComponentsBuilder;

import edu.internet2.tier.shibboleth.admin.ui.domain.CustomEntityAttributeDefinition;
import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor;
import edu.internet2.tier.shibboleth.admin.ui.service.CustomEntityAttributesDefinitionService;

@Controller
@RequestMapping(value = "/api/custom/entity")
public class CustomEntityAttributesDefinitionsController {
@Autowired
private CustomEntityAttributesDefinitionService caService;

@PostMapping("/attribute")
@Transactional
public ResponseEntity<?> create(@RequestBody CustomEntityAttributeDefinition definition) {
// If already defined, we can't create a new one, nor will this call update the definition
CustomEntityAttributeDefinition cad = caService.find(definition.getName());

if (cad != null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/custom/entity/attribute").build().toUri());

return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.CONFLICT.value()),
String.format("The custom attribute definition with name: [%s] already exists.", definition.getName())));
}

CustomEntityAttributeDefinition result = caService.createOrUpdateDefinition(definition);
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

@PutMapping("/attribute")
@Transactional
public ResponseEntity<?> update(@RequestBody CustomEntityAttributeDefinition definition) {
CustomEntityAttributeDefinition cad = caService.find(definition.getName());
if (cad == null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/custom/entity/attribute").build().toUri());

return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.NOT_FOUND.value()),
String.format("The custom attribute definition with name: [%s] does not already exist.", definition.getName())));
}

CustomEntityAttributeDefinition result = caService.createOrUpdateDefinition(definition);
return ResponseEntity.ok(result);
}

@GetMapping("/attributes")
@Transactional(readOnly = true)
public ResponseEntity<?> getAll() {
return ResponseEntity.ok(caService.getAllDefinitions());
}

@GetMapping("/attribute/{name}")
@Transactional(readOnly = true)
public ResponseEntity<?> getOne(@PathVariable String name) {
CustomEntityAttributeDefinition cad = caService.find(name);
if (cad == null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(
ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/custom/entity/attribute/" + name).build().toUri());

return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.NOT_FOUND.value()),
String.format("The custom attribute definition with name: [%s] does not already exist.", name)));
}
return ResponseEntity.ok(cad);
}

@DeleteMapping("/attribute/{name}")
@Transactional
public ResponseEntity<?> delete(@PathVariable String name) {
CustomEntityAttributeDefinition cad = caService.find(name);
if (cad == null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(
ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/custom/entity/attribute/" + name).build().toUri());

return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.NOT_FOUND.value()),
String.format("The custom attribute definition with name: [%s] does not already exist.", name)));
}
caService.deleteDefinition(cad);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -1,64 +1,90 @@
package edu.internet2.tier.shibboleth.admin.ui.controller;

import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation;
import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects;
import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorService;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
import org.opensaml.core.criterion.EntityIdCriterion;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.http.client.utils.DateUtils;
import org.opensaml.core.xml.io.MarshallingException;
import org.opensaml.saml.metadata.resolver.MetadataResolver;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation;
import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects;
import edu.internet2.tier.shibboleth.admin.ui.repository.EntityDescriptorRepository;
import edu.internet2.tier.shibboleth.admin.ui.service.EntityDescriptorService;
import lombok.extern.slf4j.Slf4j;
import net.shibboleth.utilities.java.support.resolver.ResolverException;

@Controller
@RequestMapping(value = "/api/entities", method = RequestMethod.GET)
@RequestMapping(value = { "/entities", // per protocol - https://spaces.at.internet2.edu/display/MDQ/Metadata+Query+Protocol
"/api/entities" }, // existing - included to break no existing code
method = RequestMethod.GET)
@Slf4j
/**
* EntitiesController is here to meet the requirements for this project being an MDQ. Despite similar logic to the
* EntitiesDescriptorController, the required endpoints that make this project an MDQ server are served by this controller.
*/
public class EntitiesController {
private static final Logger logger = LoggerFactory.getLogger(EntitiesController.class);

@Autowired
private MetadataResolver metadataResolver;

@Autowired
private EntityDescriptorService entityDescriptorService;

@Autowired
private OpenSamlObjects openSamlObjects;

@Autowired
private EntityDescriptorRepository entityDescriptorRepository;

@RequestMapping(value = "{entityId:.*}")
@RequestMapping(value = "/{entityId:.*}")
@Transactional(readOnly = true)
public ResponseEntity<?> getOne(final @PathVariable String entityId, HttpServletRequest request) throws UnsupportedEncodingException, ResolverException {
EntityDescriptor entityDescriptor = this.getEntityDescriptor(entityId);
if (entityDescriptor == null) {
return ResponseEntity.notFound().build();
}
EntityDescriptorRepresentation entityDescriptorRepresentation = entityDescriptorService.createRepresentationFromDescriptor(entityDescriptor);
return ResponseEntity.ok(entityDescriptorRepresentation);
HttpHeaders headers = new HttpHeaders();
headers.set("Last-Modified", formatModifiedDate(entityDescriptorRepresentation));
return new ResponseEntity<>(entityDescriptorRepresentation, headers, HttpStatus.OK);
}

@RequestMapping(value = "{entityId:.*}", produces = "application/xml")
private String formatModifiedDate(EntityDescriptorRepresentation entityDescriptorRepresentation) {
Instant instant = entityDescriptorRepresentation.getModifiedDateAsDate().toInstant(ZoneOffset.UTC);
Date date = Date.from(instant);
return DateUtils.formatDate(date, DateUtils.PATTERN_RFC1123);
}

@RequestMapping(value = "/{entityId:.*}", produces = "application/xml")
@Transactional(readOnly = true)
public ResponseEntity<?> getOneXml(final @PathVariable String entityId) throws MarshallingException, ResolverException, UnsupportedEncodingException {
EntityDescriptor entityDescriptor = this.getEntityDescriptor(entityId);
if (entityDescriptor == null) {
return ResponseEntity.notFound().build();
}
final String xml = this.openSamlObjects.marshalToXmlString(entityDescriptor);
return ResponseEntity.ok(xml);
EntityDescriptorRepresentation entityDescriptorRepresentation = entityDescriptorService.createRepresentationFromDescriptor(entityDescriptor);
HttpHeaders headers = new HttpHeaders();
headers.set("Last-Modified", formatModifiedDate(entityDescriptorRepresentation));
return new ResponseEntity<>(xml, headers, HttpStatus.OK);
}

private EntityDescriptor getEntityDescriptor(final String entityId) throws ResolverException, UnsupportedEncodingException {
String decodedEntityId = URLDecoder.decode(entityId, "UTF-8");
EntityDescriptor entityDescriptor = this.metadataResolver.resolveSingle(new CriteriaSet(new EntityIdCriterion(decodedEntityId)));
EntityDescriptor entityDescriptor = entityDescriptorRepository.findByEntityID(decodedEntityId);
// TODO: we need to clean this up sometime
if (entityDescriptor instanceof edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor) {
((edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor) entityDescriptor).setResourceId(null);
Expand Down
Loading

0 comments on commit c24e581

Please sign in to comment.