1 [[!template id=plugin name=signinview core=0 author="[[jcflack]]"]]
2 [[!tag type/special-purpose]]
4 This plugin is one implementation approach to a [[todo/zoned ikiwiki]]. It is named
5 like [[plugins/signinedit]], which requires users to sign in before editing pages.
6 Similarly, this plugin requires users to sign in before _viewing_ certain pages.
7 Unlike [[plugins/signinedit]], which _only_ checks that any user is signed in,
8 this plugin is also similar to [[plugins/lockedit]] in that it checks the user's
9 identity and a [[ikiwiki/PageSpec]] to determine _which_ pages may be viewed.
10 It works with any auth methods ikiwiki supports, not only those the `http` server
15 This plugin adds a new function, `do=view`, to ikiwiki's CGI wrapper. It is intended
16 to be called by the `http` server as an `ErrorDocument` for the `403` (forbidden) error response.
18 In order to be usable even in shared-hosting situations without full access to
19 the `http` server configuration files, this plugin requires nothing more than
20 `.htaccess` files, as long as the server is configured to honor `ErrorDocument` and
21 `Deny` or `Require` directives in them.
23 To divide the wiki into a public zone and one or more private zone(s), simply place
24 `Require all denied` (Apache 2.4), `Deny from All` (Apache 2.2), or the equivalent
25 directive for the server and version in use, on the topmost directory of any private
26 zone, either in an `.htaccess` file, or in the server configuration file if possible.
27 Any location outside of these will continue to be served as normal public static
30 Then, if the `{$cgiurl}` is, for example, `/cgi-bin/ikiwiki.cgi`, add the directive
32 ErrorDocument 403 /cgi-bin/ikiwiki.cgi?do=view
34 at the private locations or any ancestor up to the documentroot itself, again either
35 in a `.htaccess` file or in the server configuration file.
37 That's it for the server configuration. The server will now punt every request for
38 private content to the ikiwiki wrapper. Everything else about the authorization
39 decision--what auth method to use, whether there is just one private zone or different
40 zones for different users--is handled by ikiwiki using a [[ikiwiki/PageSpec]].
42 ### viewable_pages config option
44 This option in `ikiwiki.setup` is a [[ikiwiki/PageSpec]] defining which pages can be viewed.
45 Because one predicate that can be used in a [[ikiwiki/PageSpec]] is `user`, this is enough
46 to define interesting access rules. For example:
49 ((user(astolfo) or user(basilio)) and team1/*)
51 ((user(clotaldo) or user(estrella)) and team2/*)
53 Note that this defines the conditions to _allow_ viewing, which is opposite the
54 sense of the [[plugins/lockedit]] plugin, where you define the conditions
57 If there are more than a few users in a group, or the specification for accessible
58 pages is more complex, the [[plugins/contrib/pagespec_alias]] plugin
59 can be useful to factor things out. Note it currently must [[be patched|plugins/contrib/pagespec_alias/discussion]]
69 team1stuff: team1/* or common/*
70 team2stuff: team2/* or common/*
72 (team1() and team1stuff())
73 or (team2() and team2stuff())
75 ### mime_types config option
77 Normally, when serving the static pages of an ordinary public site,
78 the `http` server itself is responsible for identifying the `Content-Type`
79 of each file. However, for any page that is served by this plugin instead
80 of directly, the CGI specification makes it [plugin's job](http://tools.ietf.org/html/rfc3875#section-6.3.1),
81 not the server's, to identify the `Content-Type`.
83 In the current version, this plugin does that in a dead-simple way. For any page that ikiwiki htmlized
84 (that is, for which the `pagetype` [[plugin API function|plugins/write]] returns a value),
85 the type `text/html` is assigned. For anything else, a simple collection of content types and `PageSpec`s
86 must be configured in the `ikiwiki.setup` file:
90 application/pdf: '*.pdf'
93 Anything without a matching rule gets served as `application/octet-stream`, which is
94 probably not what you want, but a clear sign of what rule needs to be added.
96 ## Other considerations
98 ### Leakage of non-content files
100 Any CGI code that does what this plugin does, and can serve requested files under the
101 document root, needs to be careful not to allow viewing of certain sensitive files
102 that may also be found there, such as `.htaccess`, `.htpasswd`, etc. Instead of trying
103 to think of all the possible files that should not be served, this plugin takes an
104 absolutely strict approach: every requested file is looked up in the `%destsources` hash,
105 containing all the files ikiwiki has generated or placed in the web root.
106 Any file that _ikiwiki didn't put there_, this plugin _won't touch_. Otherwise, its page
107 name is now known, and must satisfy the `viewable_pages` `PageSpec`.
109 This policy is also what allows this plugin to work back through `%pagesources` to
110 the original source name, needed for the content-type rules described above.
114 The purpose of a non-public zone can be defeated if there are caching proxies or
115 other non-private caches that might retain the content this plugin returns.
117 Caching of the response is automatically forbidden by the HTTP specification
118 [if there was an `Authorization` header in the request](http://tools.ietf.org/html/rfc7234#section-3.2).
119 However, this plugin works with any auth method ikiwiki supports, not all of which require
120 that header, so this plugin always emits response headers to explicitly forbid caching.
122 Note that nothing precludes an evil caching agent that ignores the rules.
124 ### Other ways to handle `Content-Type`
126 While it is simple enough to supply a `mime_types` map in `ikiwiki.setup`, it also
127 duplicates logic that has already been done to death in other places. Another approach
128 would be to use `File::MimeInfo::Magic`, which is already present if the `filecheck`
131 In a wiki _compiler_, it would be natural to do that content-type determination
132 at compile time and save it in page state, so this plugin would simply output
133 the stored type. On the other hand, saving the type for every (non-htmlized?) page
134 would enlarge the state `Storable` that has to be loaded, and so might not be
135 faster than typing the file on the fly.
137 ## Obtaining and installing
139 The `signinview` plugin is [not in github yet](https://github.com/jcflack/ikiwiki/tree/plug-signinview)
140 (horroars! vaporware!). What _is_ in github at the moment is a preliminary patch I have
141 [proposed](https://github.com/joeyh/ikiwiki/pull/14),
142 giving plugins some control over the environment variables that a generated wrapper will preserve.
144 Depending on the ultimate fate of that patch, I will adjust/rebase and then push the `signinview`