Skip to content

Commit

Permalink
SHIBUI-1478
Browse files Browse the repository at this point in the history
  • Loading branch information
dima767 committed Sep 11, 2019
1 parent ce8b279 commit e4fdcc3
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import mjson.Json
import org.springframework.http.HttpInputMessage

import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.dynamicHttpMetadataProviderSchema
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.entityAttributesFiltersSchema
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.filesystemMetadataProviderSchema
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.JsonSchemaLocationLookup.localDynamicMetadataProviderSchema

/**
* Currently uses mjson library.
*
* @author Dmitriy Kopylenko
*/
class LowLevelJsonSchemaValidator {

Expand Down Expand Up @@ -44,6 +47,24 @@ class LowLevelJsonSchemaValidator {
doValidate(origInput, Json.schema(schemaUri), json)
}

static HttpInputMessage validateMetadataFilterTypePayloadAgainstSchema(HttpInputMessage inputMessage,
JsonSchemaResourceLocationRegistry schemaRegistry) {
def origInput = [inputMessage.body.bytes, inputMessage.headers]
def json = extractJsonPayload(origInput)
def schemaUri = null
switch (json.asMap()['@type']) {
case 'EntityAttributes':
schemaUri = entityAttributesFiltersSchema(schemaRegistry).uri
break
default:
break
}
if (!schemaUri) {
return newInputMessage(origInput)
}
doValidate(origInput, Json.schema(schemaUri), json)
}

private static Json extractJsonPayload(List origInput) {
Json.read(new ByteArrayInputStream(origInput[0]).getText())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package edu.internet2.tier.shibboleth.admin.ui.jsonschema

import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter
import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.MetadataResolver
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.core.MethodParameter
import org.springframework.http.HttpInputMessage
import org.springframework.http.converter.HttpMessageConverter
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter

import java.lang.reflect.Type

import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.LowLevelJsonSchemaValidator.validateMetadataFilterTypePayloadAgainstSchema
import static edu.internet2.tier.shibboleth.admin.ui.jsonschema.LowLevelJsonSchemaValidator.validateMetadataResolverTypePayloadAgainstSchema

/**
* Controller advice implementation for validating metadata filters payload coming from UI layer
* against pre-defined JSON schema for their respected types. Choosing of the appropriate schema based on incoming
* resolver types is delegated to @{LowLevelJsonSchemaValidator}.
*
* @author Dmitriy Kopylenko
*/
@ControllerAdvice
class MetadataFiltersSchemaValidatingControllerAdvice extends RequestBodyAdviceAdapter {

@Autowired
JsonSchemaResourceLocationRegistry jsonSchemaResourceLocationRegistry

@Override
boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
targetType.typeName == MetadataFilter.typeName
}

@Override
HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType)
throws IOException {

validateMetadataFilterTypePayloadAgainstSchema(inputMessage, jsonSchemaResourceLocationRegistry)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package edu.internet2.tier.shibboleth.admin.ui.controller

import edu.internet2.tier.shibboleth.admin.ui.domain.resolvers.FileBackedHttpMetadataResolver
import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.test.context.ActiveProfiles
import spock.lang.Specification

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles(["no-auth", "dev"])
class MetadataFiltersControllerSchemaValidationIntegrationTests extends Specification {

@Autowired
private TestRestTemplate restTemplate

@Autowired
MetadataResolverRepository metadataResolverRepository

static RESOURCE_URI = '/api/MetadataResolvers/%s/Filters'

private HTTP_POST = { body, resourceId ->
this.restTemplate.postForEntity(resourceUriFor(RESOURCE_URI, resourceId), createRequestHttpEntityFor(body), Map)
}

private static checkJsonValidationIsPerformed = {
assert it.statusCodeValue == 400
assert it.body.errorMessage.count('Type mistmatch for null') > 0
assert it.body.errorMessage.count('Type mistmatch for "not-a-boolean"') > 0
true
}

def 'POST for EntityAttributesFilter with invalid payload according to schema validation'() {
given:
def resolver = metadataResolverRepository.save(new FileBackedHttpMetadataResolver(name: 'fbmr', backingFile: '/tmp/metadata.xml'))
def postedJsonBody = """
{
"name" : "EntityAttributes",
"filterEnabled" : "not-a-boolean",
"entityAttributesFilterTarget" : {
"entityAttributesFilterTargetType" : "ENTITY",
"value" : [ "CedewbJJET" ]
},
"attributeRelease" : [ "9ktPyjjiCn" ],
"relyingPartyOverrides" : {
"signAssertion" : false,
"dontSignResponse" : true,
"turnOffEncryption" : true,
"useSha" : false,
"ignoreAuthenticationMethod" : false,
"omitNotBefore" : true,
"responderId" : null,
"nameIdFormats" : [ ],
"authenticationMethods" : [ ]
},
"@type" : "EntityAttributes"
}
"""

when:
def result = HTTP_POST(postedJsonBody, resolver.resourceId)

then:
checkJsonValidationIsPerformed(result)

}

private static HttpEntity<String> createRequestHttpEntityFor(String jsonBody) {
new HttpEntity<String>(jsonBody, ['Content-Type': 'application/json'] as HttpHeaders)
}

private static resourceUriFor(String uriTemplate, String resourceId) {
String.format(uriTemplate, resourceId)
}
}

0 comments on commit e4fdcc3

Please sign in to comment.