NAME

Catalyst::Controller::ElasticSearch - Thin proxy for ElasticSearch with some protection

VERSION

version 0.1.0

DESCRIPTION

This controller base class provides some basic protection for your ElasticSearch server. This will allow you to publish individual indices and types through your Catalyst application. The controller will prevent malicious requests such as huge size parameters or scripts.

ElasticSearch's _search endpoint is very powerful. And with power comes great responsibility. Instead of providing the vanilla search endpoint, it is recommeded that you predefine searches that process only certain parameters. See "DISABLING FEATURES".

Exposing ElasticSearch to the Internet is dangerous. MetaCPAN is doing it, and this module is the result of what we've learned so far.

SYNOPSIS

 package MyApp::Model::ElasticSearch;
 use Moose;
 use ElasticSearch
 extends 'Catalyst::Model';

 has es => (
    is => "ro",
    default => sub { ElasticSearch->new },
 );

 package MyApp::Controller::Twitter;
 use Moose;
 extends "Catalyst::Controller::ElasticSearch";

 __PACKAGE__->config(
    model_class => "ElasticSearch",
    index => "twitter",
 );


 package MyApp::Controller::Twitter::Tweet;
 use Moose;
 extends "MyApp::Controller::Twitter";

 __PACKAGE__->config(
    type  => "tweet",

    # defaults
    max_size      => 5000,
    allow_scripts => 0,
    get_raw       => 1,
 );

CONFIGURATION

model_class

The name of your model class that connects to ElasticSearch. Basically the name you would use to access it via "model" in Catalyst.

This controller is very flexible and accepts any model class that provides a _es or es method that returns a ElasticSearch instance.

If you want to use ElasticSearchX::Model classes in the controller, provide a esxmodel method in your model that will return an instance of ElasticSearchX::Model.

index

The ElasticSearch index this controller will handle. "index" and "type" can also be ArrayRefs or _all. See ElasticSearch for more information.

type

The ElasticSearch type this controller will handle. The type is optional.

max_size

Defaults to 5000. A http status 416 is returned in case the user exceed the size limit. The size parameter is evaluated both from the query parameter as well as in the request body.

Setting max_size to 0 will disabled the check.

raw_get

Disable to only retrieve the _source or fields key if requesting a resource by its ID (i.e. no searching). This might be more convenient because the client doesn't has to traverse to the actual data but it also breaks clients that expect the ElasticSearch format that includes type and index information.

allow_scripts

Malicious scripts for scoring can cause the ElasticSearch server to spin or even execute commands on the server. By default, scripts are not enabled.

DISABLING FEATURES

If you want to disable certain features such as search, get or mapping, feel free to override the corresponding methods.

 sub search {
    my ($self, $c) = @_;
    $c->detach("error", [403, "Disabled _search"]);
 }

 sub by_color : Path  : Args(1) {
    my ($self, $c, $color) = @_;
    my $model = $self->model($c); # does security checks
    eval { $c->stash(
        $model->es->search(
            index => $self->index,
            type => $self->type,
            size => $model->size,
        ) );
    } or do { $c->detach("error", [500, $@]) };
 }

ENDPOINTS

By default, this controller will create the following endpoints for a controller named MyApp::Controller::Tweet.

mapping

  /twitter/tweet/_mapping

This will return the ElasticSearch mapping.

get

  /twitter/tweet/$id

Will return the document $id. If "raw_get" is set to false, the returned JSON will not include the ElasticSearch metadata. Instead the _source or fields property is returned.

all

 /twitter/tweet

This endpoint is equivalent to /tweet/_search?q=*.

 /twitter/tweet/_search

This endpoint proxies to the search endpoint of ElasticSearch. However, it will sanitize the query first.

ACCESS CONTROL

As with other controllers, you would do the access control in the auto action.

 sub auto : Private {
    my ($self, $c) = @_;
    return $c->detach("error", [403, "Unauthorized"])
        unless $c->user->is_admin;
    return 1; # return 1 to proceed
 }

PRIVATE ACTIONS

error

 $c->detach("error", [404, "Not found"]);
 $c->detach("error", [$code, $message]);

This helper action can be used to return a error message to the client. The client will receive a JSON response that includes the message and the error code. If the message is a ElasticSearch::Error, the corresponding error message will be retrieved from the object.

AUTHOR

Moritz Onken <onken@netcubed.de>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2013 by Moritz Onken.

This is free software, licensed under:

  The MIT (X11) License