Sails JS: How to pass value from policy to controller - sails.js

I have a policy which checks whether a request has complete and valid body. I want to send a value to the controller to determine whether the result is passed or failed. Is there anyway to achieve that?

Why pass control to the controller at all if the policy fails? Usually the point of a policy like the one you described is to divert program flow if the policy fails, perhaps to an error page. In any case, what you're looking for is best done using req.options:
req.options allows altering of (or providing defaults for) request parameters without modifying the original object.
You can set a value in req.options in your policy, then read it back in your controller without having to modify the actual request.

Policy gets the request object as input and you can modify that object before sending it to the controller, ie piggyback your data over the request object.
You can do something like this in the policy :
req.body.paramname = 'newval';
And in the controller, you can get the value
var paramFromPoliy = req.body.paramname;

Related

Using OAuth2 how do I pull the access token into a variable?

I am trying to make a call to an authorization endpoint using OAuth2 with grant type Client Credentials - my call is successful - that is not an issue. However, I, now, want to take the access token that is returned and put it in a variable so I may use it in subsequent calls without having to manually cut-and-paste to my other calls.
When the call returns I see the token I desire to copy in the Access Token field at the bottom of the OAuth2 window (the one shown below that says expires in 42 minutes) AND I see it in the Authorization field on the Timeline tab of the results. I just can't figure out how to get access to it so I may dump it into variable.
The gif on the FAQ goes really fast, and does not provide step by step. Also, I didnt find any answer on YouTube or other websites, so I thought to share step by step for chaining requests on Insomnia.
Create a POST query to obtain your access token. Notice that my access token is returned in the field called "access_token", we will use this in step 3. Your return field may be different.
Create a second GET request for the API that would return the data for you. In my case, I wanted to get all users from a SCIM interface. In the Bearer tab, type in Response => Body Attribute (Insomnia will autofill).
Mouse click on the Request => Body Attribute (the one you just typed in), and select the authentication post in the dropdown "Request" (this is the one you created in step 1), and in the "Filter (JSONPath)" field, type in the $.[attribute name] - where attribute name is the response that returns from authentication call. In my case, it was access_token, see step 1 for yours.
Enjoy!!
Click No Environment > Manage Environments and you will see a base environment in JSON.
Since this is in JSON, create a { "jwt_token": "Response => Body Attribute" }" pair for your token variable. Please note that "Response => Body Attribute" needs to be configured. When you type response, hit space and this option should be available.
Once done choosing "Response => Body Attribute", it will show with some gibberish content and with red background, no worries... just click it to configure. Make sure you have the same setup.
However... you need to change your request to the route where you get the token from the server and another thing is the Filter (JSONPath or XPath) change it depending on your setup.
You should have the token, stored in jwt_token variable and can use the variable on a route that you like.
Example:
If you want to save a token that is returned in a response into an environment variable, you can use request chaining in your environment variable. Take a look at this url for more details on that https://support.insomnia.rest/article/43-chaining-requests...
Here is what you could do (what I did)
Create an environment variable
For the value of the variable, use the Response => Body Attribute and under Filter (JSONPath or XPath), choose the attribute of the token in your response body (if it is "token" then put $.token).
After that just put the token environment variable wherever you need it in the following requests.
I was not able to resolve this question but was able to get around it by defining the fields in the body of the request and bypassing the OAuth2 tab completely.
You can add it as a header, by referencing the outputs of the OAuth2 request:

Request in IAuthorizationPolicy

I'm trying to implement a custom IAuthorizationPolicy in Kinto. The documentation points to https://docs.pylonsproject.org/projects/pyramid/en/latest/quick_tutorial/authorization.html, which does not make me entirely understand how to add my IAuthorizationPolicy to the Kinto app.
My solution is to make it into a plugin, and implement the includeme function like this:
def includeme(config):
custom_authorization_policy = CustomAuthorizationPolicy()
config.set_authorization_policy(custom_authorization_policy)
But later, in IAuthorizationPolicy#permits, I would like to access the request that is currently being processed. This is because I want to cache the authentication tokens, and, as I understand it, the cache can be accessed from the request.
However, the IAuthorizationPolicy#permits takes the context parameter, and on it I can't find any request or cache.
The cache, if supported, can be accessed on config.registry.cache aswell, so I'm injecting it into my Auth policy:
def includeme(config):
custom_authorization_policy = CustomAuthorizationPolicy(config.registry.cache)
config.set_authorization_policy(custom_authorization_policy)

How to perform slot validation in webhook in Dialogflow?

How to perform slot validation in an intent using backend code (webhook).
I have seen how to perform slot filling using the webhooks but I want to know how to validate the slot data and re-prompt the user if validation fails.
Example:
User: I want to know the your services in London.
Bot: We do not provide service in London, please enter some other city name.
In short: If validation fails, reset the dialog contexts, trigger your intent again, and optionally use default values to keep other parameters that were actually valid (so you don't need to re-prompt the user for those again).
You don't need to declare an incoming context on that intent to achieve this. Note that you can use contexts in intents, even though they are not declared as incoming/outgoing contexts on that intent.
In this example, I'm requesting 2 parameters from the user (car make and model). Of course, Enable webhook call for slot filling needs to be set in your intent.
Steps:
On Dialogflow, in the intent, declare an Event. This can be used to trigger this intent from your fulfillment code:
In your parameters, declare a Default Value for each parameter you want to be able to keep after resetting the intent:
Set the Default Value to a parameter in a helper context. If this helper context does exist, the default value will be set, otherwise, it'll be kept empty. This will allow you to reset the intent and keep other parameters you already had. In this example, I'm using the context show-car-details-data, and setting the default value of parameter model to _model in that incoming context:
In your slot-filling fulfillment method, you can validate your parameter and re-prompt the user by reseting the intent. To do that, you need to 1) clear the current dialog contexts, 2) call setFollowupEvent to trigger your intent again, and 3) optionally set up some helper context you can use to assign default values (so you don't need to re-prompt user for those that were valid).
I'm using Dialogflow Fulfillment Node.js Library:
// clear dialog contexts:
agent.contexts.forEach( e => {
if ( e.name.endsWith('_id_dialog_context') ) agent.context.delete(e.name);
});
// workaround bug: https://github.com/dialogflow/dialogflow-fulfillment-nodejs/issues/160
agent.add('');
// set follow up event: this triggers your intent again
agent.setFollowupEvent('show-car-details');
// optionally set helper context to set default values and avoid re-prompt of already valid values
// in this example, keep make since it was a valid parameter
// clear model because it was invalid. User will be prompted again on model, but not on make
agent.context.set('show-car-details-data', 1, { '_make': make, '_model': '' });
Steps
Enable webhook for slot filing in Dialog flow with Entity set as "Required".
Get entity from arguments.
Programmatically check if it is not null and as per your requirement.
If it is correct, proceed further.
Else, RESET THE CONTEXT and ask the question as per the wrong slot input. Programmatically, set the output context same as input so that user can again respond back slot/entity. If the correct context is not present, the slot will not get captured. When a slot is captured as per set Entity, the context for that slot captured is finished and to recapture it you need to increase the lifespan or create it again.

How to represent a read-only property in a REST Api

if you have a REST API that is hypermedia-driven (HATEOAS) you can easily change a client's behavior by including or omitting links in the response (_links). That enables a client to completely forget about testing permissions for the operations that are possible in the current state of a resource (the link to the operation is present or not).
Additionally you can leave out properties in the response if the current user doesn't have permission to see it.
That way authorization is done entirely on the server (and controls actions and properties that are eligible to execute/view).
But what if I want to a have a read-only property? It is no problem for the REST API to ignore the property if it is present in the request (_POST_ OR _PUT_). it just won't get saved. But how can a client distinguish between write and read-only properties to present the user appropriate controls (like a disabled input field in HTML)?
The goal is to never ever have the client request a user's permissions, but to have a completely resource driven client/frontend.
Any help is greatly appreciated :-)
If I misunderstood your question, I apologize upfront. With that being said...
But how can a client distinguish between write and read-only
properties to present the user appropriate controls (like a disabled
input field in HTML)
Well, there are multiple solutions to this. The simplest one I can personally think of is to make each property an object having a simple structure of something like:
...
someProperty: {
value: 'some value',
access: 'read-only'
},
someOtherProperty: {
value: 'some value',
access: 'write'
}
...
You can obviously get as creative as you want with how you represent the "access" level of the property (using enums, booleans, changing access to be isReadOnly or whatever).
After that, the person using the API now knows they are read-only or not. If they submit a "write" value for a "read-only" property as part of the POST payload, then they should expect nothing less than a 403 response.
Edit:
In case you can't alter the properties in this manner, there are a number of other ways you can still achieve this:
write documentation that explains what access each property has
create a route that the user can submit 1 or more properties to in order to receive a response that indicates the access level of each property (response: { propName: 'read-only', propName2: 'write', etc.)
Return a propertyAccess map as part of the response (mapping properties to access levels).
end of the day, you just need a way to map a property with an access level. however that's done depends on what your restrictions and requirements are for the api, what changes you can make, and what is acceptable to both your client(s) and the business requirements.

Tastypie build_filters access tp request.user

Is there any way to access the user that initiated the request in build_filters override in tastypie.
I want to use the logged in user to give context to one of the filters for example filter contains the word Home and i want to use this as a lookup to the requesting users locations to find their home address.
If build filters took the request as an argument this would be easy as i could simply call
request.user.get_profile().userlocation_set.get(name_iexact=filters['location'])
Is there anyway to force the user into the list of filters or alternatively enrich get parameters before they are passed to build_filters.
There still isn't a great method for this. I'm currently overriding obj_get_list like so, so that I can manually pass the bundle object to build_filters:
def obj_get_list(self, bundle, **kwargs):
filters = {}
if hasattr(bundle.request, 'GET'):
filters = bundle.request.GET.copy()
filters.update(kwargs)
applicable_filters = self.build_filters(filters=filters, bundle=bundle)
try:
objects = self.apply_filters(bundle.request, applicable_filters)
return self.authorized_read_list(objects, bundle)
except ValueError:
raise BadRequest("Invalid resource lookup data provided (mismatched type).")
There is currently an open pull request for this change:
https://github.com/toastdriven/django-tastypie/pull/901
I haven't found a way to do that. I generally 'cheat' by adding the code into apply_authorization_limits where the session is available.