How to extract field value from REST response (json or xml) with Rest Assured? - rest-assured

I want to extract value from string typed REST response (json or xml). I tried the following code:
final Response response = new ResponseBuilder().setContentType("application/json").setStatusCode(200).setBody("{\"message\":\"hello\"}").build();
Object object = response.path("message");
System.out.println(object);
But it compains
Exception in thread "main" java.lang.NullPointerException: Cannot invoke method getObjectMapperConfig() on null object
at org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:91)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:48)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.NullCallSite.call(NullCallSite.java:35)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at io.restassured.internal.RestAssuredResponseOptionsGroovyImpl.jsonPath(RestAssuredResponseOptionsGroovyImpl.groovy:358)
The root cause is RestAssuredConfig object is null in RestAssuredResponseOptionsGroovyImpl
So, How can I construct Response object from raw string response correctly without get() or post() since I already have string response?

You can try following:
RestAssuredResponseOptionsImpl response = new RestAssuredResponseImpl();
response.setConfig(RestAssuredConfig.config());
response.setRpr(new ResponseParserRegistrar());
response.setContentType("application/json");
response.setStatusCode(200);
response.setContent("{\"message\":\"hello\"}");
Object message = response.path("message");
System.out.println(message);

Related

How to avoid Spring Data Rest throwing HTTP 400 when an AccessDeniedException occurs on a controller

I have a spring data rest application with a simple one-to-many relationship.
(1 organization contains zero or more employees).
In a scenario without any security, I can add employees to the organization like this :
curl -v -H "Content-Type:application/json" -d '{"name":"name1","organization":"http://localhost:8080/api/organizations/1"}' http://localhost:8080/api/employee
When the employee payload is pushed to the rest controller, Spring Data Rest will convert the organization uri to an organization entity, hook it up to the employee, and everything works fine.
However, suppose I start securing my organization API and I only want to allow authorized users to see an organization (based on some business logic).
#RepositoryRestResource
public interface OrganizationController extends CrudRepository<Organization, Long> {
#PreAuthorize("#securityService.isAllowedToSeeTheOrganization(#id)")
Organization findOne(#P("id") Long id);
}
The SecurityService implements some business logic to determine if the user is able to retrieve an organization based on his profile :
#Service
public class SecurityService {
public boolean isAllowedToSeeOrganization(Long organizationId) {
return isAdmin() || belongsToOrganization(organizationId);
}
private boolean isAdmin() {
return SecurityContextHolder.getContext().getAuthentication().getAuthorities().contains(new SimpleGrantedAuthority(ADMIN.getRoleName()));
}
private boolean belongsToOrganization(Long organizationId) {
return organizationId == Long.parseLong(getUserDetails().get(ORGANIZATION_ID_FIELD).toString());
}
protected Map<String,Object> getUserDetails() {
JwtAuthentication jwtAuthentication = (JwtAuthentication) SecurityContextHolder.getContext().getAuthentication();
return jwtAuthentication.getJwtClaimsSet().getClaims();
}
}
This off course will also have an effect on the call above, as it will no longer be able to convert the organization uri into an entity.
However, instead of throwing a 403 Forbidden, the API call fails with an HTTP 400 (Bad Request) and the following body:
{
"cause":{
"cause":{
"cause":null,
"message":"Access is denied"
},
"message":"Access is denied (through reference chain: com.example.Employee[\"organization\"])"
},
"message":"Could not read document: Access is denied (through reference chain: com.example.Employee[\"organization\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Access is denied (through reference chain: com.example.Employee[\"organization\"])"
}
In the logs :
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Access is denied (through reference chain: com.example.Employee["organization"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388) ~[jackson-databind-2.8.5.jar:2.8.5]
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:348) ~[jackson-databind-2.8.5.jar:2.8.5]
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1599) ~[jackson-databind-2.8.5.jar:2.8.5]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:359) ~[jackson-databind-2.8.5.jar:2.8.5]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:148) ~[jackson-databind-2.8.5.jar:2.8.5]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798) ~[jackson-databind-2.8.5.jar:2.8.5]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2922) ~[jackson-databind-2.8.5.jar:2.8.5]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:237) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
... 97 common frames omitted
Caused by: org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:65) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at com.sun.proxy.$Proxy156.findOne(Unknown Source) ~[na:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_40]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_40]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_40]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_40]
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:216) ~[spring-core-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.data.repository.support.ReflectionRepositoryInvoker.invoke(ReflectionRepositoryInvoker.java:265) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
at org.springframework.data.repository.support.ReflectionRepositoryInvoker.invokeFindOne(ReflectionRepositoryInvoker.java:140) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
at org.springframework.data.repository.support.CrudRepositoryInvoker.invokeFindOne(CrudRepositoryInvoker.java:91) ~[spring-data-commons-1.12.6.RELEASE.jar:na]
at org.springframework.data.rest.core.support.UnwrappingRepositoryInvokerFactory$UnwrappingRepositoryInvoker.invokeFindOne(UnwrappingRepositoryInvokerFactory.java:130) ~[spring-data-rest-core-2.5.6.RELEASE.jar:na]
at org.springframework.data.rest.core.UriToEntityConverter.convert(UriToEntityConverter.java:123) ~[spring-data-rest-core-2.5.6.RELEASE.jar:na]
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$UriStringDeserializer.deserialize(PersistentEntityJackson2Module.java:516) ~[spring-data-rest-webmvc-2.5.6.RELEASE.jar:na]
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499) ~[jackson-databind-2.8.5.jar:2.8.5]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101) ~[jackson-databind-2.8.5.jar:2.8.5]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:357) ~[jackson-databind-2.8.5.jar:2.8.5]
The fact that it leaks internal information back to the client makes me think there is something wrong.
I would simply like the api to return a 403 Forbidden in this case, or have some way of customising this error message.
How would I go about doing that?
Naturally you should use the standard Spring exception handling mechanisms but your problem is a bit more complicated than usually. I've tried my solution on a demo project and this should work.
In your case the AccessDeniedException is wrapped in a JsonMappingException, which itself is wrapped in a HttpMessageNotReadableException. This is what Spring exception handling gets:
HttpMessageNotReadableException
|---JsonMappingException
|---AccessDeniedException
According to this ticket in the Spring issue tracker #ExceptionHandler methods can match wrapped Exceptions since Spring 4.3, but only up to one level deep. Using an #ExceptionHandler for AccessDeniedException won't work because it's nested two levels below the exception Spring has received.
You could alter how deep in the exception chain Spring is looking for matching handlers, but if it's only for this problem i'd just define an exception handler that does that:
#ControllerAdvice
public class ExceptionAdvice {
#ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<String> accessDenied(Exception e) throws Exception {
Throwable cause = e.getCause();
if (cause != null) {
Throwable nestedCause = cause.getCause();
if (AccessDeniedException.class.isAssignableFrom(nestedCause.getClass())) {
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
}
throw e;
}
}
You could customise the matching (maybe search the complete exception chain for the wanted exception?) and add a return message.
Note that the handler is defined in its own class - since your EmployeeController presumably is an interface, like your OrganizationController, the #ExceptionHandler method can't be defined inside it (default method doesn't work either).

JClouds Logging Error

I have the code below - can someone tell me the cause of the error?
`String provider = "openstack-nova";
String username = "admin:admin";
String credential = "luel2005";
String endpoint = "httpenter code here://192.168.2.100:5000/v2.0/";
ContextBuilder contextBuilder = ContextBuilder.newBuilder(provider).credentials(username, credential).endpoint(endpoint);`
Error:
Exception in thread "main" java.util.ServiceConfigurationError: org.jclouds.providers.ProviderMetadata: Provider org.jclouds.aws.route53.AWSRoute53ProviderMetadata could not be instantiated: java.lang.reflect.MalformedParameterizedTypeException
at java.util.ServiceLoader.fail(Unknown Source)
at java.util.ServiceLoader.access$100(Unknown Source)
at java.util.ServiceLoader$LazyIterator.next(Unknown Source)
at java.util.ServiceLoader$1.next(Unknown Source)
at com.google.common.collect.ImmutableCollection$Builder.addAll(ImmutableCollection.java:342)
From first glance, the endpoint that you are using to create the Context appears to be malformed:
String endpoint = "httpenter code here://192.168.2.100:5000/v2.0/";
Try removing the "enter code here" from that String and give it another try. For further reference, check out the jclouds OpenStack QuickStart, Compute Basics example, and the Rackspace Cloud Servers examples.

Error when serializing byte[]

In our backing database, we have a Data field that is of type varbinary(max). Using Breeze we are able to save data in this field, however, when we want to call it back down we are getting errors. In our generated models, the field gets mapped to a byte[]. But when Breeze tries to serialize that into a string it throws up errors.
$id: "1",
$type: "System.Web.Http.HttpError, System.Web.Http",
Message: "An error has occurred.",
ExceptionMessage: "The specified cast from a materialized 'System.String' type to the 'System.Byte[]' type is not valid.",
ExceptionType: "System.InvalidOperationException",
StackTrace: " at System.Data.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetValue(DbDataReader reader, Int32 ordinal) at System.Data.Common.Internal.Materialization.Shaper.GetColumnValueWithErrorHandling[TColumn](Int32 ordinal) at lambda_method(Closure , Shaper ) at System.Data.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper) at System.Data.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext() at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at Breeze.WebApi.ODataActionFilter.OnActionExecuted(HttpActionExecutedContext actionExecutedContext) at System.Web.Http.Filters.ActionFilterAttribute.CallOnActionExecuted(HttpActionContext actionContext, HttpResponseMessage response, Exception exception) at System.Web.Http.Filters.ActionFilterAttribute.<>c__DisplayClass2.<System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync>b__0(HttpResponseMessage response) at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass41`2.<Then>b__40(Task`1 t) at System.Threading.Tasks.TaskHelpersExtensions.ThenImpl[TTask,TOuterResult](TTask task, Func`2 continuation, CancellationToken cancellationToken, Boolean runSynchronously)"
Any help would be great!
I have been unable to reproduce this.
Breeze is able to take a server side byte[] and convert it to a string on the client. You can see an example of this in the breeze 'DocCode' samples whenever an Employee entity is returned. The Employee type has a Photo property that has a server side datatype of 'byte[]' which is returned to the breeze client as a 'string'.
What I think you are running into is a server side materialization issue where you are trying to materialize a binary blob on the database into a string property. This would occur if your model property was typed as a 'String' instead of as a 'byte[]'.
Hope this helps.

RestSharp Serializer Setter has no effect

I am struggling to make RestSharp talk with MVC API with EF4 and I'm very close to making it work. In order to overcome the interface limitation of the stock serializer I am using the Json.NET serializer. For the deserialization it worked out of the box but I can't make RestSharp use my custom serializer. The method Serializeis not getting called. Everything compiled great but doesn't work. Here is the code:
var client = CreateClient();
// client.Authenticator = new HttpBasicAuthenticator(username, password);
var request = new RestRequest("api/{type}s", Method.GET);
request.AddUrlSegment("type", typeof(T).Name);
request.RequestFormat = DataFormat.Json;
request.AddParameter("criteria", criteria);
IRestResponse<List<T>> response = client.Execute<List<T>>(request);
HandleResponse(response);
return response.Data;
Any ideas?
Edit
I tried to follow an example and change the post method to accept JObject and it worked!. But trying to call jitem.ToObject<Item>() caused the following exception:
Error converting value "System.Collections.Generic.List`1[DataAbstractionLayer.Poco.ItemCheckpoint]" to type 'System.Collections.Generic.ICollection`1[DataAbstractionLayer.Poco.ItemCheckpoint]'.
But more interesting is the inner exception:
Could not cast or convert from System.String to System.Collections.Generic.ICollection`1[DataAbstractionLayer.Poco.ItemCheckpoint].
Could it be that Json.NET converts collection items automatically to string?

Using Amazon's WSDL web service from F# 3.0 with type providers

I wrote the following F# 3.0 program using the built-in WSDL type provider to autogenerate an F# version of the Amazon WSDL:
open Microsoft.FSharp.Data.TypeProviders
type azn = WsdlService<"http://soap.amazon.com/schemas2/AmazonWebServices.wsdl">
let authorRequest author =
azn.ServiceTypes.AuthorRequest(author=author)
do
let client = azn.GetAmazonSearchPort()
let response = client.AuthorSearchRequest(authorRequest "Harrop")
printfn "%s" response.TotalResults
When I run this I get a exciting internal exception from the Microsoft toolstack at run time:
Unhandled Exception: System.ServiceModel.ProtocolException: The remote server returned an unexpected response: (410) Gone. ---> System.Net.WebException: The remote server returned an error: (410) Gone.
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
--- End of inner exception stack trace ---
Server stack trace:
at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory`1 factory, WebException responseException, ChannelBinding channelBinding)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at Program.azn.ServiceTypes.AmazonSearchPort.AuthorSearchRequest(AuthorRequest AuthorSearchRequest1)
at Program.azn.ServiceTypes.AmazonSearchPortClient.AuthorSearchRequest(AuthorRequest AuthorSearchRequest1)
at Program.azn.ServiceTypes.SimpleDataContextTypes.AmazonSearchPortClient.AuthorSearchRequest(AuthorRequest )
at <StartupCode$ConsoleApplication2>.$Program.main#() in c:\users\jon\documents\visual studio 11\Projects\ConsoleApplication2\ConsoleApplication2\Program.fs:line 5
I've since found out that there is a more recent schema here:
type azn = WsdlService<"http://soap.amazon.com/schemas2/AmazonWebServices.wsdl">
But this doesn't fix my exciting error message. What is the problem and how can I fix it?
I don't know the end-to-end solution but can probably help you to move a bit further
Url that you are using right now corresponds to the stale version of API, I believe more recent one is http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl
If you just pass this url to WsdlService type provider, everything will be fine in in design time, but in runtime with weird error like "There was an error in serializing body of message ItemSearchRequest1: 'Unable to generate a temporary class (result=1). error CS0030: Cannot convert type 'Program.Amazon.ServiceTypes.ImageSet[]' to 'Program.Amazon.ServiceTypes.ImageSet'; error CS0029: Cannot implicitly convert type 'Program.Amazon.ServiceTypes.ImageSet' to 'Program.Amazon.ServiceTypes.ImageSet[]'".
It seems to be the known error (here), to fix it you should set ForceUpdate=false, and LocalSchemaFile='your local schema file' and then fix the definition of ImagesSet in your local schema file from
<xs:element minOccurs="0" maxOccurs="unbounded" name="ImageSets">
to
<xs:element minOccurs="0" maxOccurs="1" name="ImageSets">
type Amazon = Microsoft.FSharp.Data.TypeProviders.WsdlService<
#"http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl",
ForceUpdate=false,
LocalSchemaFile="amazon.wsdlschema"
>
let searchAuthor author =
Amazon.ServiceTypes.ItemSearch(Request = [| Amazon.ServiceTypes.ItemSearchRequest(Author = author) |])
[<EntryPoint>]
let main argv =
let amazon = Amazon.GetAWSECommerceServicePort()
let result = amazon.ItemSearch (searchAuthor "Harrop")
0
However this is still not the end of the story - this code throws MessageSecurityException: "The HTTP request was forbidden with client authentication scheme 'Anonymous'". It looks like the known issue as well (i.e. here), but to check the solution you'll need Amazon user id and secret key (I don't have ones).

Resources