0
votes

I have created a custom model binder for my webhook. When I subscribe to the webhook the validation works correctly, but when it receives a ResourceWriteSuccessEvent or a ResourceDeleteSuccessEvent type I get the following error when passing the json string into the eventGridSubscriber.DeserializeEventGridEvents method,

Newtonsoft.Json.JsonReaderException HResult=0x80131500 Message=Error reading string. Unexpected token: StartObject. Path 'authorization'. Source=Newtonsoft.Json StackTrace: at Newtonsoft.Json.JsonReader.ReadAsString() at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer) at Microsoft.Azure.EventGrid.EventGridSubscriber.DeserializeEventGridEventData(EventGridEvent[] eventGridEvents, JsonSerializer jsonSerializer) at Microsoft.Azure.EventGrid.EventGridSubscriber.DeserializeEventGridEvents(String requestContent, JsonSerializer jsonSerializer) at Microsoft.Azure.EventGrid.EventGridSubscriber.DeserializeEventGridEvents(String requestContent)

I have tried to implement a custom model instead of using ResourceWriteSuccessData but get the same result.

My model binder looks like this,

public class EventGridEventModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            controllerContext.HttpContext.Request.InputStream.Position = 0;
            using (var sr = new StreamReader(controllerContext.HttpContext.Request.InputStream))
            {
                var json = sr.ReadToEnd();
                EventGridSubscriber eventGridSubscriber = new EventGridSubscriber();
                eventGridSubscriber.AddOrUpdateCustomEventMapping(EventTypes.EventGridSubscriptionValidationEvent, typeof(SubscriptionValidationEventData));
                eventGridSubscriber.AddOrUpdateCustomEventMapping(EventTypes.ResourceWriteSuccessEvent, typeof(ResourceWriteSuccessData));
                eventGridSubscriber.AddOrUpdateCustomEventMapping(EventTypes.ResourceDeleteSuccessEvent, typeof(ResourceDeleteSuccessData));
                return eventGridSubscriber.DeserializeEventGridEvents(json);
            }
        }
    }

The test json im sending through is,

[
   {
      "subject":"/subscriptions/{subscription-id}/resourcegroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-name}",
      "eventType":"Microsoft.Resources.ResourceWriteSuccess",
      "eventTime":"2018-07-19T18:38:04.6117357Z",
      "id":"4db48cba-50a2-455a-93b4-de41a3b5b7f6",
      "data":{
         "authorization":{
            "scope":"/subscriptions/{subscription-id}/resourcegroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-name}",
            "action":"Microsoft.Storage/storageAccounts/write",
            "evidence":{
               "role":"Subscription Admin"
            }
         },
         "claims":{
            "aud":"{audience-claim}",
            "iss":"{issuer-claim}",
            "iat":"{issued-at-claim}",
            "nbf":"{not-before-claim}",
            "exp":"{expiration-claim}",
            "_claim_names":"{\"groups\":\"src1\"}",
            "_claim_sources":"{\"src1\":{\"endpoint\":\"{URI}\"}}",
            "http://schemas.microsoft.com/claims/authnclassreference":"1",
            "aio":"{token}",
            "http://schemas.microsoft.com/claims/authnmethodsreferences":"rsa,mfa",
            "appid":"{ID}",
            "appidacr":"2",
            "http://schemas.microsoft.com/2012/01/devicecontext/claims/identifier":"{ID}",
            "e_exp":"{expiration}",
            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname":"{last-name}",
            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname":"{first-name}",
            "ipaddr":"{IP-address}",
            "name":"{full-name}",
            "http://schemas.microsoft.com/identity/claims/objectidentifier":"{ID}",
            "onprem_sid":"{ID}",
            "puid":"{ID}",
            "http://schemas.microsoft.com/identity/claims/scope":"user_impersonation",
            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier":"{ID}",
            "http://schemas.microsoft.com/identity/claims/tenantid":"{ID}",
            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name":"{user-name}",
            "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn":"{user-name}",
            "uti":"{ID}",
            "ver":"1.0"
         },
         "correlationId":"{ID}",
         "resourceProvider":"Microsoft.Storage",
         "resourceUri":"/subscriptions/{subscription-id}/resourcegroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-name}",
         "operationName":"Microsoft.Storage/storageAccounts/write",
         "status":"Succeeded",
         "subscriptionId":"{subscription-id}",
         "tenantId":"{tenant-id}"
      },
      "dataVersion":"2",
      "metadataVersion":"1",
      "topic":"/subscriptions/{subscription-id}/resourceGroups/{resource-group}"
   }
]

This is the custom model I have tried

`public class ResourceWriteSuccessDataCustom
{
[JsonProperty("authorization")]
public Authorization Authorization { get; set; }

 [JsonProperty("subscriptionId")]
public string SubscriptionId { get; set; }

 [JsonProperty("tenantId")]
public string TenantId { get; set; }
}

public class Authorization
{
[JsonProperty("scope")]
public string Scope { get; set; }

 [JsonProperty("action")]
public string Action { get; set; }

 [JsonProperty("evidence")]
public Evidence Evidence { get; set; }
}

public class Evidence
{
[JsonProperty("role")]
public string Role { get; set; }
}

Update The original issue has already been raised as a bug for the nuget package https://github.com/Azure/azure-sdk-for-net/issues/5189

I still doesn't explain why my custom model isn't working.

1

1 Answers

0
votes

I ended up removing all of the EventGridSubscriber as there was too many bugs and used the standard JSON deserialize object method instead.

JsonConvert.DeserializeObject<EventGridEvent[]>(json);