Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extension points #29

Open
fxnn opened this issue Mar 25, 2016 · 1 comment
Open

Add extension points #29

fxnn opened this issue Mar 25, 2016 · 1 comment
Milestone

Comments

@fxnn
Copy link
Owner

fxnn commented Mar 25, 2016

I want to make gone an application that fits many purposes, yet as simple as possible. Therefore, we need extension points (Open Closed Principle). This could include the possibility to call completely new functionality from the UI. Such a concept would greatly complement with the customizeable UI templates.

Stories

  1. An administrator wants to incorporate version control into his gone installation. Now, without modifying the gone sourcecode, he makes gone execute git commit -a everytime a file is saved.
  2. An administrator wants to offer every user of his gone installation the function of publishing all files inside the content root onto a public web server. Therefore, he modifies the UI templates, adding a special link. That link points to a URL which makes gone call a script that publishes the files. The gone sourcecode wasn't changed for this.
  3. An administrator wants to offer a function where each user can see the VCS history of the current resource. Therefore, he modifies the UI templates, adding a special link. That link adds something to the resources URL, which makes gone call a script. That script writes the VCS history to stdout, being displayed by gone. The gone sourcecode wasn't changed for this.
@fxnn
Copy link
Owner Author

fxnn commented Mar 25, 2016

Implementation via hook directories

Adding functionality to existing workflows calls for hooks. A hook is an executable, e.g. a shell script, placed inside a special directory structure inside the .gone directory (cf. #27). It is executed instead of gones regular request processing, receiving some information about the HTTP request via commandline / environment variables, and having it's output sent back as HTTP response.

Hook types

gone will provide different types of hooks, which differ in the kind of activation criteria.

  • by action: every request in gone contains an explicit or implicit action to perform. Regular GET requests without any further parameters imply the read action. Creating or updating files is done using create or edit actions and POST requests, while the respective UI is displayed using GET requests. With hooks, the admin can have executables invoked only for specific actions, and thus overwrite predefined actions or create new ones.
  • by extension: it is possible to create hooks responsible for all files with a given extension.
  • by MIME type: likewise, hooks can be created by the files MIME type, as far as gone can tell.

Depending on the hook's type, you would define them in different directories: .gone/hook-by-action, .gone/hook-by-extension or .gone/hook-by-mime. Below, you can place the executables (or symlinks to executables), possibly in subdirectories. However, naming and exact placement of the executable has an impact of when it gets called.

  • The filename of the executable decides on the trigger, which contains of two parts: on the one hand the HTTP method (esp. GET, POST, PUT), and on the other hand the action/extension/MIME type (depending on the trigger type). An action trigger post-create.sh is invoked on POST requests for the create action, the extension trigger get-md.sh could specify another Markdown renderer, and get-application-xml.sh might implement some XSL transformation.
    • Additionally, the filename may contain flags, separated by dots from other parts of the filename.
    • The listener flag makes the HTTP response completely independent of the hook output. gone will apply its regular request processing, and might invoke the hook synchronously or asynchronously to request processing. There may be multiple listener hooks per request.
    • The precondition flag makes gone apply its regular request processing, but only after the hook was invoked and returned exit code 0. Otherwise, gone will not process the request furtherly and respond with an HTTP error code. Especially, gone will not write any files due to create or edit request. It's unclear, whether gone should respond with a 400 or 500 status code in case of failure.
    • The postcondition flag makes gone apply its regular request processing in any case. Additionally, before sending a response, it invokes the hook. If that returns a non-zero exit code, gone will send an HTTP error response.
    • The virtual flag tells gone not to check whether the HTTP request path matches a file, i.e. the hook is also executed for non-existant files or directories. gone will never respond with 404 in that case.
  • The directory placement of the executable might give additional filters.
    • There may only be one hook per trigger. If mulitple hooks match, the one the least deeply nested in the directory structure will be chosen. If two equally deep hooks match, the one whose path comes first according to alphabetic order will be chosen.
    • Any directory containing hooks might contain a special .request-path-glob.allow.filter file. Every line may contain a glob pattern matched against the HTTP request path, e.g. /path/to/file.ext. If the file exists, hooks from that directory or any directory below will only be applied to a given request, if at least one glob in the file matches. Consequently, an empty file of that name completely disables the directory.
    • The same holds for a special .request-path-glob.deny.filter file, with the opposite semantics: no hook from that directory or any directory below will be applied to a given request as soon as at least one glob in the file matches.
    • The special files .user.allow.filter and .user.deny.filter contain a login username per line, enabling or disabling hooks for the given users as described above. The special line * matches any user being logged in.
    • The special files .group.allow.filter and .group.deny.filter contain a group name per line, enabling or disabling hooks for users of the given groups as described above. You will be able to assign users to groups using a .htgroup file.

Hooks vs. CGI

CGI scripts are invoked directly by giving their path and name as HTTP request URL, e.g. http://example.com/cgi-bin/some-cgi-script.pl. This makes file system internas publicy available and has a high risk of misconfiguration. For example, a common problem with CGI scripts is that attackers manage to download the script's sourcecode, thus being able to find security holes.

gones hooks are strictly separated from the content root. The contents of the hook directory will never be modified by gone, nor will they be displayed to a client. gone will only execute hooks that were explicitly defined to be executed in a special situation, they can not be executed by file name.

Potential attack vectors

The following new attack vectors arise. Besides, I sketch potential risk mitigation strategies.

  • Denial of service using computation-intensive hooks.
    • This might be circumvented using a rate limiter.
  • Modifying input data for a hook, thus attacking the hooks internal algorithms. For example, XML parsers in general are known to be vulnerable to many different kinds of attacks. If a hook takes a file inside the content root as input and processes it, and if the attacker can use gones wiki features to modify that data, attacks can easily be performed.
    • As it's the purpose of gone to provide easy editing capability, this one is hard to tackle.
    • To provide security by default, it might make sense to disable any editing capabilities as soon as a hook might get triggered for a given file -- at least, for anonymous users.
    • The opposite direction would be a configuration option to disable editing capabilites for any given hook.
  • Insecure hook scripts. Hook scripts will contain security holes.
    • It's unclear to me whether we are able to mitigate this kind of attack vector a priori.

Overwriting the login hook

It's unclear to me whether we should allow overwriting the login hook. The only possible scenario I can imagine is deactivating gones user and permission management, and possibly redirecting login requests to a different application instead.

I can't see, why we should forbid this kind of action.

Access control

  • A hook script is invoked only if it's executable by the gone process.
  • A hook script is invoked in course of the action of a user being not logged in only if that script is world executable.
  • A hook script is never invoked if it's world-writeable.

In other words, a script that's executable by the gone process, but not world executable will only get invoked in course of the action of a user being logged in.

Output filtering

At the beginning, it will not be possible for a hook to tell gone to render it's output using a template, or using the Markdown parser. A hook's output will directly be used as HTTP body.

Exit codes

If a hook returns a non-zero exit code, by default, gone will deliver a HTTP 500 without any further information about the hook or it's output. However, relevant information will be logged.

@fxnn fxnn added this to the 1.1.0 milestone Mar 25, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant