Skip to content

Commit

Permalink
Merge branch 'SHIBUI-906' of bitbucket.org:unicon/shib-idp-ui into SH…
Browse files Browse the repository at this point in the history
…IBUI-906
  • Loading branch information
rmathis committed Nov 8, 2018
2 parents 89e1977 + 2a4dc66 commit b031fe2
Show file tree
Hide file tree
Showing 22 changed files with 230 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package edu.internet2.tier.shibboleth.admin.ui.controller

import com.fasterxml.jackson.databind.ObjectMapper
import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation
import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocationRegistry
import edu.internet2.tier.shibboleth.admin.ui.service.JsonSchemaBuilderService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

import javax.annotation.PostConstruct

import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.entityAttributesFiltersSchema
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR

/**
* Controller implementing REST resource responsible for exposing structure definition for metadata sources user
* interface in terms of JSON schema.
*
* @author Dmitriy Kopylenko
* @author Bill Smith (wsmith@unicon.net)
*/
@RestController
@RequestMapping('/api/ui/EntityAttributesFilters')
class EntityAttributesFiltersUiDefinitionController {

@Autowired
JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry

JsonSchemaResourceLocation jsonSchemaLocation

@Autowired
ObjectMapper jacksonObjectMapper

@Autowired
JsonSchemaBuilderService jsonSchemaBuilderService

@GetMapping
ResponseEntity<?> getUiDefinitionJsonSchema() {
try {
def parsedJson = jacksonObjectMapper.readValue(this.jsonSchemaLocation.url, Map)
jsonSchemaBuilderService.addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['widget'])
jsonSchemaBuilderService.addRelyingPartyOverridesToJson(parsedJson['properties']['relyingPartyOverrides'])
jsonSchemaBuilderService.addRelyingPartyOverridesCollectionDefinitionsToJson(parsedJson["definitions"])
return ResponseEntity.ok(parsedJson)
}
catch (Exception e) {
e.printStackTrace()
return ResponseEntity.status(INTERNAL_SERVER_ERROR)
.body([jsonParseError : e.getMessage(),
sourceUiSchemaDefinitionFile: this.jsonSchemaLocation.url])
}
}

@PostConstruct
void init() {
this.jsonSchemaLocation = entityAttributesFiltersSchema(this.jsonSchemaResourceLocationRegistry);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package edu.internet2.tier.shibboleth.admin.ui.controller

import com.fasterxml.jackson.databind.ObjectMapper
import edu.internet2.tier.shibboleth.admin.ui.configuration.CustomPropertiesConfiguration
import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup
import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation
import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocationRegistry
import org.springframework.beans.factory.BeanInitializationException
import edu.internet2.tier.shibboleth.admin.ui.service.JsonSchemaBuilderService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
Expand All @@ -15,7 +13,6 @@ import org.springframework.web.bind.annotation.RestController
import javax.annotation.PostConstruct

import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.metadataSourcesSchema
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR

/**
Expand All @@ -38,15 +35,15 @@ class MetadataSourcesUiDefinitionController {
ObjectMapper jacksonObjectMapper

@Autowired
CustomPropertiesConfiguration customPropertiesConfiguration
JsonSchemaBuilderService jsonSchemaBuilderService

@GetMapping
ResponseEntity<?> getUiDefinitionJsonSchema() {
try {
def parsedJson = jacksonObjectMapper.readValue(this.jsonSchemaLocation.url, Map)
addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['widget'])
addRelyingPartyOverridesToJson(parsedJson['properties']['relyingPartyOverrides'])
addRelyingPartyOverridesCollectionDefinitions(parsedJson["definitions"])
jsonSchemaBuilderService.addReleaseAttributesToJson(parsedJson['properties']['attributeRelease']['widget'])
jsonSchemaBuilderService.addRelyingPartyOverridesToJson(parsedJson['properties']['relyingPartyOverrides'])
jsonSchemaBuilderService.addRelyingPartyOverridesCollectionDefinitionsToJson(parsedJson["definitions"])
return ResponseEntity.ok(parsedJson)
}
catch (Exception e) {
Expand All @@ -61,52 +58,4 @@ class MetadataSourcesUiDefinitionController {
void init() {
this.jsonSchemaLocation = metadataSourcesSchema(this.jsonSchemaResourceLocationRegistry);
}

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

private void addRelyingPartyOverridesToJson(Object json) {
def properties = [:]
customPropertiesConfiguration.getOverrides().each {
def property
if (it['displayType'] == 'list'
|| it['displayType'] == 'set') {
property = [$ref: '#/definitions/' + it['name']]
} else {
property =
[title : it['displayName'],
description: it['helpText'],
type : it['displayType'],
default : it['defaultValue']]
}
properties[(String) it['name']] = property
}
json['properties'] = properties
}

private void addRelyingPartyOverridesCollectionDefinitions(Object json) {
customPropertiesConfiguration.getOverrides().stream().filter {
it -> it['displayType'] && (it['displayType'] == 'list' || it['displayType'] == 'set')
}.each {
def definition = [title : it['displayName'],
description: it['helpText'],
type : 'array',
default : null]
if (it['displayType'] == 'set') {
definition['uniqueItems'] = true
} else if (it['displayType'] == 'list') {
definition['uniqueItems'] = false
}
def items = [type : 'string',
minLength: '1', // TODO: should this be configurable?
maxLength: '255'] //TODO: or this?
items.widget = [id: 'datalist', data: it['defaultValues']]

definition['items'] = items
json[(String) it['name']] = definition
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package edu.internet2.tier.shibboleth.admin.ui.jsonschema

import edu.internet2.tier.shibboleth.admin.ui.domain.frontend.EntityDescriptorRepresentation
import mjson.Json
import org.springframework.beans.factory.BeanInitializationException
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.core.MethodParameter
import org.springframework.http.HttpInputMessage
Expand All @@ -18,7 +17,6 @@ import javax.annotation.PostConstruct
import java.lang.reflect.Type

import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.metadataSourcesSchema
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES

/**
* Controller advice implementation for validating relying party overrides payload coming from UI layer
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package edu.internet2.tier.shibboleth.admin.ui.service

import edu.internet2.tier.shibboleth.admin.ui.configuration.CustomPropertiesConfiguration
import org.springframework.beans.factory.annotation.Autowired

/**
* @author Bill Smith (wsmith@unicon.net)
*/
class JsonSchemaBuilderService {

@Autowired
CustomPropertiesConfiguration customPropertiesConfiguration

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

void addRelyingPartyOverridesToJson(Object json) {
def properties = [:]
customPropertiesConfiguration.getOverrides().each {
def property
if (it['displayType'] == 'list'
|| it['displayType'] == 'set') {
property = [$ref: '#/definitions/' + it['name']]
} else {
property =
[title : it['displayName'],
description: it['helpText'],
type : it['displayType'],
default : it['defaultValue']]
}
properties[(String) it['name']] = property
}
json['properties'] = properties
}

void addRelyingPartyOverridesCollectionDefinitionsToJson(Object json) {
customPropertiesConfiguration.getOverrides().stream().filter {
it -> it['displayType'] && (it['displayType'] == 'list' || it['displayType'] == 'set')
}.each {
def definition = [title : it['displayName'],
description: it['helpText'],
type : 'array',
default : null]
if (it['displayType'] == 'set') {
definition['uniqueItems'] = true
} else if (it['displayType'] == 'list') {
definition['uniqueItems'] = false
}
def items = [type : 'string',
minLength: '1', // TODO: should this be configurable?
maxLength: '255'] //TODO: or this?
items.widget = [id: 'datalist', data: it['defaultValues']]

definition['items'] = items
json[(String) it['name']] = definition
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package edu.internet2.tier.shibboleth.admin.ui.configuration;

import com.fasterxml.jackson.databind.ObjectMapper;
import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation;
import edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocationRegistry;
import edu.internet2.tier.shibboleth.admin.ui.service.JsonSchemaBuilderService;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;

import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.*;
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.ENTITY_ATTRIBUTES_FILTERS;
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES;
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ENTITY_ATTRIBUTES_FILTERS;
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES;

/**
* @author Dmitriy Kopylenko
Expand Down Expand Up @@ -47,4 +47,9 @@ public JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry(Res
.build());

}

@Bean
public JsonSchemaBuilderService jsonSchemaBuilderService() {
return new JsonSchemaBuilderService();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@
*/
class InMemoryJsonSchemaResourceLocationRegistry implements JsonSchemaResourceLocationRegistry {

private Map<JsonSchemaResourceLocation.ShemaType, JsonSchemaResourceLocation> schemaLocations =
new EnumMap<>(JsonSchemaResourceLocation.ShemaType.class);
private Map<JsonSchemaResourceLocation.SchemaType, JsonSchemaResourceLocation> schemaLocations =
new EnumMap<>(JsonSchemaResourceLocation.SchemaType.class);


@Override
public JsonSchemaResourceLocationRegistry register(JsonSchemaResourceLocation.ShemaType type, JsonSchemaResourceLocation location) {
public JsonSchemaResourceLocationRegistry register(JsonSchemaResourceLocation.SchemaType type, JsonSchemaResourceLocation location) {
this.schemaLocations.put(type, location);
return this;
}

@Override
public Optional<JsonSchemaResourceLocation> lookup(JsonSchemaResourceLocation.ShemaType type) {
public Optional<JsonSchemaResourceLocation> lookup(JsonSchemaResourceLocation.SchemaType type) {
return Optional.ofNullable(this.schemaLocations.get(type));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edu.internet2.tier.shibboleth.admin.ui.jsonschema;

import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES;
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ENTITY_ATTRIBUTES_FILTERS;
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES;

/**
* Utility methods for common JSON schema types lookups.
Expand All @@ -21,4 +22,17 @@ public static JsonSchemaResourceLocation metadataSourcesSchema(JsonSchemaResourc
.lookup(METADATA_SOURCES)
.orElseThrow(() -> new IllegalStateException("JSON schema resource location for metadata sources is not registered."));
}

/**
* Searches entity attributes filters JSON schema resource location object in the given location registry.
*
* @param resourceLocationRegistry
* @returnentity attributes filters JSON schema resource location object
* @throws IllegalStateException if schema is not found in the given registry
*/
public static JsonSchemaResourceLocation entityAttributesFiltersSchema(JsonSchemaResourceLocationRegistry resourceLocationRegistry) {
return resourceLocationRegistry
.lookup(ENTITY_ATTRIBUTES_FILTERS)
.orElseThrow(() -> new IllegalStateException("JSON schema resource location for entity attributes filters is not registered."));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static JsonSchemaResourceLocation newSchemaLocation(String jsonSchemaLoca
}
}

public enum ShemaType {
public enum SchemaType {
METADATA_SOURCES, ENTITY_ATTRIBUTES_FILTERS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ public interface JsonSchemaResourceLocationRegistry {
* @param type of JSON schema
* @param location of JSON schema resource
*/
JsonSchemaResourceLocationRegistry register(JsonSchemaResourceLocation.ShemaType type, JsonSchemaResourceLocation location);
JsonSchemaResourceLocationRegistry register(JsonSchemaResourceLocation.SchemaType type, JsonSchemaResourceLocation location);

/**
* Look up json schema resource location by given schema type.
*
* @param type type of JSON schema
* @return optional location of JSON schema resource
*/
Optional<JsonSchemaResourceLocation> lookup(JsonSchemaResourceLocation.ShemaType type);
Optional<JsonSchemaResourceLocation> lookup(JsonSchemaResourceLocation.SchemaType type);

/**
* Factory method.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,5 +222,7 @@
"attributeRelease"
]
}
]
],
"definitions": {
}
}
2 changes: 1 addition & 1 deletion backend/src/main/resources/i18n/messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ tooltip.backing-file=Specifies where the backing file is located. If the remote
tooltip.backup-file-init-refresh-delay=Delay duration after which to schedule next HTTP refresh when initialized from the backing file.
tooltip.require-valid-metadata=Whether candidate metadata found by the resolver must be valid in order to be returned (where validity is implementation specific, but in SAML cases generally depends on a validUntil attribute.) If this flag is true, then invalid candidate metadata will not be returned.
tooltip.fail-fast-init=Whether to fail initialization of the underlying MetadataResolverService (and possibly the IdP as a whole) if the initialization of a metadata provider fails. When false, the IdP may start, and will continue to attempt to reload valid metadata if configured to do so, but operations that require valid metadata will fail until it does.
tooltip.use-default-predicate-reg=Whether to fail initialization of the underlying MetadataResolverService (and possibly the IdP as a whole) if the initialization of a metadata provider fails. When false, the IdP may start, and will continue to attempt to reload valid metadata if configured to do so, but operations that require valid metadata will fail until it does.
tooltip.use-default-predicate-reg=Flag which determines whether the default CriterionPredicateRegistry will be used if a custom one is not supplied explicitly.
tooltip.satisfy-any-predicates=Flag which determines whether predicates used in filtering are connected by a logical 'OR' (true) or by logical 'AND' (false).
tooltip.enable-provider-upon-saving=Enable Metadata Provider upon saving?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import org.springframework.test.context.ActiveProfiles
import spock.lang.Specification

import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.*
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.ShemaType.METADATA_SOURCES
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.ENTITY_ATTRIBUTES_FILTERS
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaResourceLocation.SchemaType.METADATA_SOURCES

/**
* @author Dmitriy Kopylenko
Expand Down Expand Up @@ -49,6 +50,12 @@ class BadJSONMetadataSourcesUiDefinitionControllerIntegrationTests extends Speci
.jacksonMapper(jacksonMapper)
.detectMalformedJson(false)
.build())
.register(ENTITY_ATTRIBUTES_FILTERS, JsonSchemaLocationBuilder.with()
.jsonSchemaLocation('classpath:entity-attributes-filters-ui-schema.json')
.resourceLoader(resourceLoader)
.jacksonMapper(jacksonMapper)
.detectMalformedJson(false)
.build())
}
}
}
Loading

0 comments on commit b031fe2

Please sign in to comment.