I'm using ES 5.1.2 and I want to do some simple authentication key lookup for every /_search request.
I don't find a very detailed plugin development guide on elastic.co, so far the only document I found is this http://david.pilato.fr/blog/2016/10/19/adding-a-new-rest-endpoint-to-elasticsearch-updated-for-ga/, but it is about create another endpoint.
I found search-guard https://github.com/floragunncom/search-guard and from source code it feels like I can create my own plugin extends Plugin implements ActionPlugin, but then I'm stuck and don't know where to go.
From the source code I know I can add my own ActionFilter and add it into action chain in Plugin, such that all request go thru /_search endpoint will also go thru my ActionFilter. But I don't have a complete list of possible action, which might be indices:data/read/search (search) or indices:admin/delete (delete index). There are too many to use try and error.
Another thing is, in ActionFilter, how do I get POST request payload from a Request object? When in /_search request, I got SearchRequest, but it doesn't have http request headers from browser.
== update ==
Found I could use use stack trace to get the invoke history, so for ActionFilter the call stack is like
at org.elasticsearch.action.support.TransportAction$RequestFilterChain.proceed(TransportAction.java:171)
at org.elasticsearch.action.support.TransportAction.execute(TransportAction.java:145)
at org.elasticsearch.action.support.TransportAction.execute(TransportAction.java:87)
at org.elasticsearch.client.node.NodeClient.executeLocally(NodeClient.java:75)
at org.elasticsearch.client.node.NodeClient.doExecute(NodeClient.java:64)
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:403)
at org.elasticsearch.client.support.AbstractClient.search(AbstractClient.java:530)
at org.elasticsearch.rest.action.search.RestSearchAction.lambda$prepareRequest$0(RestSearchAction.java:83)
at org.elasticsearch.rest.action.search.RestSearchAction$$Lambda$1405/1241306571.accept(Unknown Source)
at org.elasticsearch.rest.BaseRestHandler.handleRequest(BaseRestHandler.java:82)
in RestSearchAction#prepareRequest, ES use parseSearchRequest and convert RestRequest data to SearchRequest, which means I can't get RestRequest in my ActionFitler. Should there be another way to pass this data? Because I want to extend an existed /_search not add another endpoint, so I think I should not create any more RestHandler
I found a temporary solution and source code is here.
Long thing short, when implement your plugin as RestHandler (usually with new endpoints), you can skip registerHandler and do registerFilter only. I implement my logic in RestFilter. This works because in ElasticSearch source code, when RestController gets a new request, it will check if you have any RestFilter, if you do then it will go through whole chain of filters, then dispatch to a particular handler based on request URI.
In search guard 5 there seems to be a way to directly register a RestFilter in RestController without creating a RestHandler, but I don't understand the whole flow so I didn't use it.
My main references:
http://david.pilato.fr/blog/2016/10/19/adding-a-new-rest-endpoint-to-elasticsearch-updated-for-ga/
https://github.com/floragunncom/search-guard/tree/es-5.1.2
Related
I'm new to backend programming. I chose the laravel framework. Already learned the basics. During the study, the question arose: is it necessary to use the form to transfer data to the server ?. For example: the deletion route looks like this to me
Delete.
If I leave it, will it be a mistake? Maybe advise an article or something. Thanks in advance
Short answer is no, it's not necessary, but you should (if you're bound to HTML only).
The HTTP standard has different methods for different purposes. Using an anchor tag will always make a HTTP GET request to the link/server, which is not ideal, GET request should never change the remote (server) state, that's a job other methods (POST, PUT, DELETE, PATCH), you should try to use the method that better describe what you're trying to do: in your case I suppose you're trying to delete a complaint, so a DELETE or POST is what you're looking for.
The only way to use make a non GET request in plain HTML* is to use <form>. Also if you're planning to use a method different from POST you should take a look at Laravel's #method here
Mind that if you can and want to use JavaScript to perform your request you totally can, dropping the requirement to have use form (docs and docs).
So I'm quite new to IIB and Extended SQL but what I want to do should be straight forward. I have a REST application which has a resource that is attached to a subflow. What I want to do is to get the input value passed to the service and use it to call a remote web service using the HTTP request node as shown below
SET OutputLocalEnvironment.Destination.HTTP.RequestLine.Method = 'POST';
SET OutputLocalEnvironment.Destination.HTTP.RequestURL = 'http://localhost:8002/MyService';
SET OutputLocalEnvironment.Destination.HTTP.QueryString.RemoteParam= InputLocalEnvironment.REST.Input.Parameters.myValue;
What is happening is, when I call the REST method and pass the value as a GET, I'm able to access the value. However, when I pass the parameter value using POST, I'm unable to access the value. My current flow is as follows:
Input > Compute > HTTPRequest > Compute > Output
I have searched on Google and applied all recommendations (e.g. setting compute node to LocalEnvironment) but nothing seems to work.
Well, we need more information in order to solve your problem but I guess you have problem in your HTTP request node
Go to HTTP request then in properties go to HTTP setting and change HTTP method to the method that you are using ( get or post )
and if you want to see if you are fetching data from right property just lunch debugger and put breakepoint in before and after of your nodes, then you can see what data you are receiving in each level and you can call the proper property.
ps. don't forget to deploy your project again in order to see new
changes
I hope that works for you
After further research, I found that IIB does not automatically parse content submitted as application/x-www-form-urlencoded. I inserted a trace node and realised that the parameters are instead submitted as a BLOB. All I had to do was read the blob, cast it to a string then use a Split function or a message model to get the individual parameters. Thanks for the pointers
Is there an easy way to ask the google api ruby client to just give you back the stock HTTP response, rather than to perform the lovely, but slightly limiting translation into one of their ruby representable objects?
e.g.
response = Gmail.client.get_user_message("me", id)
=> #<Google::Apis::GmailV1::Message
response = Gmail.client.list_user_messages("me")
=> #<Google::Apis::GmailV1::ListMessagesResponse
but
response = Gmail.client.delete_user_message("me", id)
=>nil #successfully deleted
Now that's all fine and dandy, except that sometimes I just want to know what sort of response is going to come back. i.e. an HTTP response with maybe some JSON in the body. And then I'll worry about what I do with it...
I can take the response and use the
response.to_json
to get the body of the json that would have come back (though I still won't have the response code, and I need to KNOW that it's one of those objects first).
The client library is definitely getting that, it's just converting it into these objects before it lets me see it. And if I don't know that it's a google object (and not nil) I can't run that to_json consistently....
Any ideas other than second guess what google is going to send me back?
(I should note that this has come about when trying to move a library from dealing with their 0.8 api to their 0.9 api, so call me a cynic if you must but my faith that google won't make breaking changes to those objects returned is at a low ebb...
As far as I know, it is possible to ask the server to send only the fields you really need and get a partial response instead of the default full response as mentioned in Performance Tips.
However, I suggest that you please check the documentation for the specific API you are using to see if the field you're looking for is currently supported. For the Gmail API, you may go through Working with partial resources.
Here are the two types of partial requests that you can use:
Partial response: A request where you specify which fields to include in the response (use the fields request parameter).
Patch: An update request where you send only the fields you want to change (use the PATCH HTTP verb).
Hope that helps!
I use ControllerLinkBuilder to create an index of links pointing to a list of Spring MVC controllers.
For example:
ResourceSupport resource = new ResourceSupport();
resource.add(linkTo(methodOn(ReactorController.class).sendmail(EventBody)).withRel(REACTOR_REL));
This generates:
"reactor": [
{
"href": "http://localhost:12345/main/reactor/sendmail"
}
]
In the example it is a POST to sendmail that is expected!
What is the way to document that a POST is expected ?
When you provide a link, you are pointing to a resource which can be manipulated by the users of your API, not a function they are expected to know how to use.
https://spring.io/understanding/HATEOAS
The last segment applies to your question.
According to the Richardson Maturity Model, HATEOAS is considered the final level of REST. This means that each link is presumed to implement the standard REST verbs of GET, POST, PUT, and DELETE (or a subset). Thus providing the links as shown above gives the client the information they need to navigate the service.
So in your case, if it does not make sense to implement any of the methods but post, you can just let them post to /mail and you may create a separate documentation (like Swagger, Spring REST Docs) to let them know your format of entity.
I am trying to make a RESTful api and have some function which needs credentials. For example say I'm writing a function which finds all nearby places within a certain radius, but only authorised users can use it.
One way to do it is to send it all using GET like so:
http://myapi.heroku.com/getNearbyPlaces?lon=12.343523&lat=56.123533&radius=30&username=john&password=blabla123
but obviously that's the worst possible way to do it.
Is it possible to instead move the username and password fields and embed them as POST variables over SSL, so the URL will only look like so:
https://myapi.heroku.com/getNearbyPlaces?lon=12.343523&lat=56.123533&radius=30
and the credentials will be sent encrypted.
How would I then in Sinatra and Ruby properly get at the GET and POST variables? Is this The Right Way To Do It? If not why not?
If you are really trying to create a restful API instead if some URL endpoints which happen to speak some HTTP dialect, you should stick to GET. It's even again in your path, so you seem to be pretty sure it's a get.
Instead of trying to hide the username and password in GET or POST parameters, you should instead use Basic authentication, which was invented especially for that purpose and is universally available in clients (and is available using convenience methods in Sinatra).
Also, if you are trying to use REST, you should embrace the concept of resources and resoiurce collections (which is implied by the R and E of REST). So you have a single URL like http://myapi.heroku.com/NearbyPlaces. If you GET there, you gather information about that resource, if you POST, you create a new resource, if you PUT yopu update n existing resource and if you DELETE, well, you delete it. What you should do before is th structure your object space into these resources and design your API around it.
Possibly, you could have a resource collection at http://myapi.heroku.com/places. Each place as a resource has a unique URL like http://myapi.heroku.com/places/123. New polaces can be created by POSTing to http://myapi.heroku.com/places. And nearby places could be gathered by GETing http://myapi.heroku.com/places/nearby?lon=12.343523&lat=56.123533&radius=30. hat call could return an Array or URLs to nearby places, e.g.
[
"http://myapi.heroku.com/places/123",
"http://myapi.heroku.com/places/17",
"http://myapi.heroku.com/places/42"
]
If you want to be truly discoverable, you might also embrace HATEOAS which constraints REST smentics in a way to allows API clients to "browse" through the API as a user with a browser would do. To allow this, you use Hyperlink inside your API which point to other resources, kind of like in the example above.
The params that are part of the url (namely lon, lat and radius) are known as query parameters, the user and password information that you want to send in your form are known as form parameters. In Sinatra both of these type of parameters are made available in the params hash of a controller.
So in Sinatra you would be able to access your lon parameter as params[:lon] and the user parameter as params[:user].
I suggest using basic or digest authentication and a plain GET request. In other words, your request should be "GET /places?lat=x&lon=x&radius=x" and you should let HTTP handle the authentication. If I understand your situation correctly, this is the ideal approach and will certainly be the most RESTful solution.
As an aside, your URI could be improved. Having verbs ("get") and query-like adjectives ("nearby") in your resource names is not really appropriate. In general, resources should be nouns (ie. "places", "person", "books"). See the example request I wrote above; "get" is redundant because you are using a GET request and "nearby" is redundant because you are already querying by location.