Sencha Touch ajax prefilter, supply url root for all ajax requests - sencha-touch

In a Sencha touch aplication, can I use some sort of ajax prefilter and supply a URL root for all my requests (from stores and models)?
One more thing,
Is there a way to add a AUTH-TOKEN header, alto to every ajax request?
Thank you!

Ext.Ajax.request is a singleton instance. You can tap on beforerequest event and change/modify url, add/remove headers and do all other modification as needed. This way you can capture all your ajax request. You should be able to do this in your app.launch function.
Ext.Ajax.on('beforerequest', function(conn, request, eOpts){
// Your implementaion here. change request.url, request.headers etc
});

If you're setting the URL on your store proxies via Ext.data.proxy.Ajax.url, you could do this in one of two ways.
One: you can extend (or override) the class, adding the logic yourself.
Two: you could configure your URLs as such:
//someplace define this...
var urlPrefix = function() {
return '/path/to/API/';
};
//in your store/proxy
Ext.define('MyApp.store.Foo', {
config : {
proxy : {
type : 'ajax',
url : urlPrefix() + 'API_endpoint'
}
}
});
I've done that a bunch of times before.
As for your Auth headers, you can override Ext.data.Connection to include additional headers. The key here is that you would need to override it very early in the application lifetime, because other classes have unique instances of Ext.data.Connection (for example, Ext.Ajax).
But before giving a recommendation on how to apply the headers globally, I'd need to know more about what you needed to do. There's many things to consider before doing that.

Related

Can't perform HTTP Post Action from Logic App to Asp.net Core Web API

I've built many Logic Apps. I've also integrated with the Logic App API. For some reason, a Post request to an Asp.net Core Web API won't work. It works in Postman, but I can't get Logic Apps to complete the request.
The request arrives at my Web API. I can step through it during a remote debug session. I'm using the [FromBody] decorator on the API method. All the string values in the object are null.
Logic App Headers
Accept = "application/json"
ContentType = "application/json"
ContentLength = "35"
Host = "****.centralus.logic.azure.com"
API method
[HttpPost]
[Route("CreateSomething")]
public async Task<IActionResult> CreateSomething([FromBody] MyObject object)
{
//Create something great
}
I think it might have something to do with the Headers. I noticed that the Postman request won't succeed unless I check the Host and Content-Length box in the Headers section. According to this article, Logic Apps ignores those Headers.
https://learn.microsoft.com/en-us/azure/connectors/connectors-native-http
I've built the HTTP Post Action using the API as well as configured it manually using the Logic App UI in Azure.
By the way, does anyone know the Expression that will automatically calculate the ContentLength?
UPDATE:
I finally figured this out. I had to do some Ninja coding crap to make this work. I'll post my solution tomorrow.
Does anyone know how to make this work? Thanks in advance!
When you use the Logic App API to programmatically create Logic Apps, you have to specify the Body class for when you do something like an HTTP Post. When the Body JSON displayed in the designer, it contained a single object with the objects properties. My API method could not handle this. The key was to simply post the properties in the JSON Body. To make matters worse, I'm doing two HTTP Posts in this particular Logic App. When I tried to add my object properties to the existing Body class, it caused my other HTTP Post to stop working. To overcome this, I had to create a Body2 class with the objects properties. I then had to use the following line of code to replace body2 with body before adding the JSON to the Logic App API call.
This did not work.
body = new Body()
{
object = new Object()
{
//Properties
}
}
This worked.
body2 = new Body2()
{
Type = 0,
Description = "#{items('For_each_2')?['day']?['description']}",
Locations = item.Locations,
Cold = "#{items('For_each_2')?['temperature']?['cold']?['value']}",
Hot = "#{items('For_each_2')?['temperature']?['hot']?['value']}",
Hide = 0
}
Notice I used Replace on body2.
var options = new JsonSerializerOptions { WriteIndented = true, IgnoreNullValues = true};
string jsonString = ReplaceFirst(JsonSerializer.Serialize(myApp, options), "schema", "$schema").Replace("_else", "else").Replace("_foreach", "foreach").Replace("body2", "body");

ASP.NET Core : Return Json response on Unauthorized in a filter at the controller/action level

I am not using Identity.
I have this ASP.NET Core configuration enabling two authentication schemes, cookies and basic auth:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.Name = "_auth";
options.Cookie.HttpOnly = true;
options.LoginPath = new PathString("/Account/Login");
options.LogoutPath = new PathString("/Account/LogOff");
options.AccessDeniedPath = new PathString("/Account/Login");
options.ExpireTimeSpan = TimeSpan.FromHours(4);
options.SlidingExpiration = true;
})
.AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);
BasicAuthenticationHandler is a custom class inheriting from AuthenticationHandler and overriding HandleAuthenticateAsync to check the request headers for basic authentication challenge, and returns either AuthenticateResult.Fail() or AuthenticateResult.Success() with a ticket and the user claims.
It works fine as is:
Controllers/Actions with the [Authorize] tag will check the cookies and redirect to the login page is not present.
Controllers/Actions with the [Authorize(AuthenticationSchemes = "BasicAuthentication")] tag will check the header and reply a 401 Unauthorized HTTP code if not present.
Controllers/Actions with the [Authorize(AuthenticationSchemes = "BasicAuthentication,Cookies")] tag will allow both methods to access the page, but somehow use the Cookies redirection mechanism when failing both checks.
My goal is to have most of my project to use Cookies (hence why it is set as default), but have some API type of controllers to accept both methods. It should also be possible to tag the Controllers/Actions to return a specific Json body when desired (as opposed to the login redirect or base 401 response), but only for certain controllers.
I've spent the last 2 days reading different similar questions and answers here on StackOverflow, nothing seems to accommodate my need.
Here's a few methods I found:
The options under AddCookie allow you to set certain events, like OnRedirectToAccessDenied and change the response from there. This does not work because it applies to the whole project.
Under my BasicAuthenticationHandler class, the AuthenticationHandler class allow to override HandleChallengeAsync to change the response from there instead of replying 401. Unfortunately, again it applies globally to everywhere you use the scheme, not on a controller/action level. Not sure if it's applied when mixing multiple schemes either.
Many answers point to adding a Middleware to the solution, again, it impacts the whole project.
Many answers point to Policies, but it seems to be to control whether or not an user have access to the resource based on claims, not controlling the response when he do not.
Many answers suggest creating a class inheriting from AuthorizeAttribute, IAuthorizationFilter. Again, this allow to override the OnAuthorization method to decide if the user have the right or not to access the resource, but not to control the response AFTER the normal authentication scheme failed.
I'm thinking either there's a filter type I'm missing, or maybe I need to create a third authentication type that will mix the previous two and control the response from there. Finding a way to add a custom error message in the options would also be nice.
I managed to do it via a IAuthorizationMiddlewareResultHandler. Not my favorite approach because there can be only one per project and it intercepts all calls, but by checking if a specific (empty) attribute is set, I can control the flow:
public class JsonAuthorizationAttribute : Attribute
{
public string Message { get; set; }
}
public class MyAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
private readonly AuthorizationMiddlewareResultHandler DefaultHandler = new AuthorizationMiddlewareResultHandler();
public async Task HandleAsync(RequestDelegate requestDelegate, HttpContext httpContext, AuthorizationPolicy authorizationPolicy, PolicyAuthorizationResult policyAuthorizationResult)
{
// if the authorization was forbidden and the resource had specific attribute, respond as json
if (policyAuthorizationResult.Forbidden)
{
var endpoint = httpContext.GetEndpoint();
var jsonHeader = endpoint?.Metadata?.GetMetadata<JsonAuthorizationAttribute>();
if (jsonHeader != null)
{
var message = "Invalid User Credentials";
if (!string.IsNullOrEmpty(jsonHeader.Message))
message = jsonHeader.Message;
httpContext.Response.StatusCode = 401;
httpContext.Response.ContentType = "application/json";
var jsonResponse = JsonSerializer.Serialize(new
{
error = message
});
await httpContext.Response.WriteAsync(jsonResponse);
return;
}
}
// Fallback to the default implementation.
await DefaultHandler.HandleAsync(requestDelegate, httpContext, authorizationPolicy, policyAuthorizationResult);
}
}
I was typing this on comment... but it's doesn't fit... so here is something we probably need to make clear before choosing a solution:
Authorization process happen at the upper middleware above controller
Yes, AuthorizationMiddleware was registered when we use app.UseAuthorization();, that quite far above controller layer, so it was returned long before the request can reach controller, so, any type of filter cannot be applied here.
Not specify an authentication scheme or policy would easily lead to un-stable behavior.
Imagine, Authentication process return an instance of User that stick with the request, but what would happen if the permission on cookie and basicAuth was difference, like cookie have myclaim, while basicAuth doens't ? Related process on both type of scheme was difference (like challenge on cookie would lead to /Account/Login and basicAuth to /Login ?). And various logic case that we could implement on each page.
I Know, this is not possible, but it would become a mess, not for the author of these code, but for those maintainers to come.
Json response for some specific process on client ?
This might sound detailed at first glance, but it would rather become burden soon, if some more authentication requirement raise after that (like Jwt). Covering each of these case on client would make user experience quite awkward (like, half-authentication and authorization).
And if It's un-avoidable in the project. Might I suggest create a default authentication scheme with ForwardDefaultSelector that would elected which authentication scheme to use for each request. And maintain a stable routing HashSet that would use to detect on which endpoint to set Json Response as wished on some upper level than AuthorizationMiddleware, by using middleware, ofcourse. Then, we narrow down to 2 centralize places to checkout the authorization.
Chaos came when we tried to make one thing to do somethings. At least in this case, I think we would breath easier when coming to debug phase.

How to pass request headers set using headers option for ServerSideEvent (If Platform is browser) in React js

I have got to know that, the new npm package #microsoft/signalR provided options to pass custom header to httpClient used to make SSE calls in javascript (using headers option in withUrl).
But found a difference in the code (git code) where I see, the same custom header isn't forwarded if the request is from Browser or WebWorker. If otherwise, it is forwareded (git code)
I would like to understand, is there a security reason for not forwarding the header? If yes, is there a way to get it working? i.e, set custom header when making HTTP requests if the transport type is SSE (ServerSentEvent).
The reason is because browsers do not support sending headers with EventSource
https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource
Answering my question for future readers.
I have got it working for my requirement, Where I need to pass custom headers to all the signalR calls irrespective of transport type, starting from the negotiate call.
I could be able to send the custom header using the headers option while creating hubConnectionBuilder.withUrl(url, options) (have given detailed answer here)
To the point:
For SSE, as mentioned by Brennan, we cant set the custom header with the Native EventSource constructor. But I have achieved it using the EventSource polyfill using this package (npm package)
Two points to note down, if you are using signalR and try to achieve the same as mine.
By default signalR uses native EventSource, but there is a property we can set in the same options parameter in withUrl.
Extend the polyfill constructor and add the custom headers.
import { EventSourcePolyfill } from 'event-source-polyfill';
function EventSourceWithCustomHeader(url, options) {
return new EventSourcePolyfill(url, {
...options,
headers: {
...options.headers,
"custom-header-name": "value"
}
});
}
const conn = new signalR.HubConnectionBuilder()
.withUrl("/chat", {
headers: {
"custom-header-name": "value"
},
EventSource: EventSourceWithCustomHeader,
})
.build();

Enabling binary media types breaks Option POST call (CORS) in AWS Lambda

New to AWS..
We have a .NET Core Microservice running on a serverless aws instance as lambda functions.
Our Controller looks like this
[Route("api/[controller]")]
[ApiController]
public class SomeController : ControllerBase
{
[HttpGet()]
[Route("getsomedoc")]
public async Task<IActionResult> GetSomeDoc()
{
byte[] content;
//UI needs this to process the document
var contentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
contentDisposition.FileName = "File Name";
Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
return File(content, "application/octet-stream");
}
[HttpPost()]
[Route("somepost")]
public async Task<IActionResult> SomePost()
{
return null;
}
}
URL's
{{URL}}/getsomedoc
{{URL}}/somepost
We have enabled 'Binary Media Types' in AWS package settings to / for the getsomedoc to work otherwise it was returning the byte array back instead of the file.
But this is breaking our 'somepost' call when UI is accessing the API using
Method: OPTIONS & Access-Control-Request-Method as POST
When we remove the binary media type the 'somepost' starts working.
Looking for suggestions as why this might be happening? and what can we add/remove from gateway to get this fixed.
Well we ended up resolving this in a strange way.
Added two gateways for the lambda
- on one of them have binary enabled
- Disabled on the other one.
For
getsomedoc - Using the one where binary media types are enabled
postsomedoc - Using the other one
Wish there was a better way!!
I have found this same behavior with my API. While looking everywhere for some help, I found a few things that address the issue:
Basically, this bug report says the problem is having CORS enabled while also using the generic Binary Media Type "*/*". Apparently the OPTIONS method gets confused by this. They discuss this in terms of using Serverless, but it should apply to using the console or other ways of interacting with AWS.
They link to a possible solution: you can modify the Integration Response of the OPTIONS method - change the Mapping Template's Content-Type to an actual binary media type, like image/jpeg. They say this allows you to leave the binary media type in Settings as "*/*". This is a little hacky, but at least it is something.
There also was this alternate suggestion in the issues section of this GitHub repo that is a little less hacky. You can set the content handling parameter of the OPTIONS Integration Request to "CONVERT_TO_TEXT"... but you can only do this via CloudFormation or the CLI (not via the console). This is also the recommended solution by some AWS Technicians.
Another possible workaround is to setup a custom Lambda function to handle the OPTIONS request, this way the API gateway may have the "*/*" Binary Media Type.
Create a new lambda function for handling OPTIONS requests:
exports.handler = async (event) => {
const response = {
statusCode: 200,
headers:{
'access-control-allow-origin':'*',
'Access-Control-Allow-Headers': 'access-control-allow-origin, content-type, access-control-allow-methods',
'Access-Control-Allow-Methods':"GET,POST,PUT,DELETE,OPTIONS"
},
body: JSON.stringify("OK")
};
return response;
};
In your API Gateway OPTION method, change the integration type from Mock to Lambda Function.
Make sure to check 'Use Lambda proxy integration'
Select the correct region and point to the created Lambda Function
This way any OPTIONS request made from the browser will trigger the Lambda function and return the custom response.
Be aware this solution might involve costs.

changing meteor restivus PUT to implement upsert

i'm using restivus with meteor and would like to change the PUT schemantic to an upsert.
// config rest endpoints
Restivus.configure({
useAuth: false,
prettyJson: false
});
Restivus.addCollection("sensor", {
excludedEndpoints: ['getAll','deleteAll','delete'],
defaultOptions: {},
});
how does one do this?
Right now, the only way to do this would be to provide a custom PUT endpoint on each collection route:
Restivus.addCollection(Sensors, {
excludedEndpoints: ['getAll','deleteAll','delete'],
endpoints: {
put: function () {
var entityIsUpdated = Sensors.upsert(this.urlParams.id, this.bodyParams);
if (entityIsUpdated) {
var entity = Sensors.findOne(this.urlParams.id);
return {status: "success", data: entity};
}
else {
return {
statusCode: 404,
body: {status: "fail", message: "Sensor not found"}
}
}
}
}
});
The goal with Restivus is to provide the best REST practices by default, and enough flexibility to allow the user to override it with custom behavior where they desire. The proper RESTful behavior of PUT is to completely replace the entity with a given ID. It should never generate a new entity (that's what POST is for). For collections, Restivus will only allow you to define a PUT on a specific entity. In your example, an endpoint is generated for PUT /api/sensors/:id. If you aren't doing the PUT by :id, then you should probably be using POST instead (there's no "right way" to do this in REST, but at least you can POST without requiring an :id).
It sounds like what you want is a way to override the default behavior of the collections endpoints. That is extremely doable, but it would help me if you would make a feature request via the Restivus GitHub Issues so I can better track it. You can literally copy and paste your question from here. I'll make sure I add a way for you to access the collection in the context of any collection endpoints you define.
Last, but certainly not least, I noticed you are using v0.6.0, which needs to be updated to 0.6.1 immediately to fix an existing bug which prevents you from adding existing collections or using any collections created in Restivus anywhere else. That wasn't the intended behavior, and an update has been released. Check out the docs for more on that.