diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2012-12-31 20:08:30 +0100 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2012-12-31 20:08:30 +0100 |
| commit | 95b85be502f639fb2080ae92d4d33c013b18aa94 (patch) | |
| tree | 7ca15af789198da9021937269eda023946b69221 | |
| parent | 571790ba31a48c108e42c4ae10f8e63ae734c376 (diff) | |
| download | cataract-95b85be502f639fb2080ae92d4d33c013b18aa94.tar.xz | |
Add support for password protected albums
This adds support for simple password protected areas (albums and
all subalbums) through webserver HTTP authentication. CGG simply
generates .htaccess and password files and it's up to the user to
set up the rest on server side.
No UI changes at this point. Limited to one user per album for
the moment.
| -rw-r--r-- | sample/src/index.xml | 6 | ||||
| -rw-r--r-- | sample/src/passwd_protect/index.xml | 27 | ||||
| -rw-r--r-- | src/generators.c | 76 | ||||
| -rw-r--r-- | src/generators.h | 12 | ||||
| -rw-r--r-- | src/items.c | 17 | ||||
| -rw-r--r-- | src/items.h | 9 | ||||
| -rw-r--r-- | src/job-manager.c | 26 |
7 files changed, 173 insertions, 0 deletions
diff --git a/sample/src/index.xml b/sample/src/index.xml index c5ec849..4363cb6 100644 --- a/sample/src/index.xml +++ b/sample/src/index.xml @@ -64,5 +64,11 @@ <title_description>Supplemental files distributed within the album</title_description> </item> + <item path="passwd_protect"> + <title>Restricted area</title> + <title_description><![CDATA[Password protected access<br/><br/>user/pass: test/test]]></title_description> + <thumbnail src="CIAF_1/img_6802.jpg" /> + </item> + </items> </gallery> diff --git a/sample/src/passwd_protect/index.xml b/sample/src/passwd_protect/index.xml new file mode 100644 index 0000000..10225fa --- /dev/null +++ b/sample/src/passwd_protect/index.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<gallery type="album"> + <general> + <ID>Restricted area</ID> + <title>Restricted area</title> + <description><![CDATA[Welcome to restricted area! You should have been presented a standard HTTP authentication dialog. If that didn't happen, your web server configuration is probably incorrect. Note that this natually doesn't work when opened locally (<code>file://</code> URL). + <br/><br/> + This feature requires web server user htaccess override enabled as well as the particular authentication modules loaded. All subdirectories (including the current album images) should be protected the same way through automatic parenting. It's usually sufficient to only set password for top-level path you want to protect. Please note this implementation is not bulletproof in any way, a simple configuration error or missing file will bypass any protection. See <a href="http://httpd.apache.org/docs/2.2/howto/auth.html">httpd.apache.org/docs/2.2/howto/auth.html</a> for more information. + <br/><br/> + CGG will automatically create new password file and will add necessary lines in <code>.htaccess</code> file (appending if it exists). By default, MD5 hash is used. The <code>htpasswd</code> tool needs to be installed as Apache uses it's own MD5 hash modification. Check e.g. <code>apache-tools</code> package. + <br/><br/> + All of this has a culprit however. For security reasons, the webserver (Apache) disallows relative pathnames to the password file and requires either absolute path or relative path to ServerRoot (basically document root for the domain). Also, storing the password file within the document tree is discouraged though it's fully satisfactory for our needs. A new <location> section in <code>setup.xml</code> file has been introduced. Having a correct path in the <local_path> tag is the key to success. + ]]></description> + + <auth> + <!-- ID of the area, the message will also be presented to user --> + <realm>Secret pictures</realm> + <username>test</username> + <!-- plain text password please, will be encrypted during processing --> + <password>test</password> + <!-- we only support mod_auth_basic, adding support for mod_auth_digest would be nice --> + <type>Basic</type> + </auth> + </general> + +</gallery> + diff --git a/src/generators.c b/src/generators.c index d5f1837..ac641d4 100644 --- a/src/generators.c +++ b/src/generators.c @@ -33,6 +33,7 @@ #include "replace-table.h" #include "block-parser.h" #include "stats.h" +#include "generators.h" #define IS_NOFULLSIZE(item,parent_items,setup) \ @@ -959,3 +960,78 @@ write_html_image (TGallerySetup *setup, return res; } + +/* + * write_auth_passwd_file, write_auth_htaccess_file: setup authentication files for the current album + * + */ +gboolean +write_auth_passwd_file (TGallerySetup *setup, + const gchar *dst, + TAlbum *items) +{ + GError *error = NULL; + const gchar *argv[8]; + + argv[0] = "htpasswd"; + argv[1] = "-b"; + argv[2] = "-c"; + argv[3] = "-m"; + argv[4] = dst; + argv[5] = items->auth_username; + argv[6] = items->auth_passwd; + argv[7] = NULL; + + if (! g_spawn_sync (NULL, + (gchar **) argv, + NULL, + G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, + NULL, NULL, + NULL, + &error)) + { + log_error ("Error writing password file: %s\n", error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +gboolean +write_auth_htaccess_file (TGallerySetup *setup, + const gchar *dst, + const gchar *passwd_file_name, + TAlbum *items) +{ + FILE* f; + + f = fopen (dst, "a"); + if (f == NULL) { + log_error ("Error writing htaccess file: %s\n", strerror (errno)); + return FALSE; + } + + fprintf (f, "\n"); + fprintf (f, "# CGG auth data\n"); + switch (items->auth_type) { + case AUTH_TYPE_NONE: + g_assert_not_reached(); + break; + case AUTH_TYPE_BASIC: + fprintf (f, "AuthType Basic\n"); + fprintf (f, "AuthName \"%s\"\n", items->auth_realm); + fprintf (f, "AuthBasicProvider file\n"); + fprintf (f, "AuthUserFile %s\n", passwd_file_name); + fprintf (f, "Require user %s\n", items->auth_username); + break; + } + + if (fclose (f) != 0) { + log_error ("Error writing htaccess file: %s\n", strerror (errno)); + return FALSE; + } + + return TRUE; +} diff --git a/src/generators.h b/src/generators.h index c284f37..bff6cde 100644 --- a/src/generators.h +++ b/src/generators.h @@ -70,6 +70,18 @@ gboolean write_html_image (TGallerySetup *setup, TIndexItem *item, TAlbum *parent_items); +/* + * write_auth_passwd_file, write_auth_htaccess_file: setup authentication files for the current album + * + */ +gboolean write_auth_passwd_file (TGallerySetup *setup, + const gchar *dst, + TAlbum *items); +gboolean write_auth_htaccess_file (TGallerySetup *setup, + const gchar *dst, + const gchar *passwd_file_name, + TAlbum *items); + G_END_DECLS diff --git a/src/items.c b/src/items.c index 68ae66d..8692b65 100644 --- a/src/items.c +++ b/src/items.c @@ -140,6 +140,20 @@ parse_album_xml (const gchar *filename, TPathInfo *path_info) } } + /* Authentication */ + index->auth_type = AUTH_TYPE_NONE; + s = xml_file_get_node_value (xml, "/gallery/general/auth/type/text()"); + if (g_strcmp0 (s, "Basic") == 0) + index->auth_type = AUTH_TYPE_BASIC; + g_free (s); + index->auth_realm = xml_file_get_node_value (xml, "/gallery/general/auth/realm/text()"); + index->auth_username = xml_file_get_node_value (xml, "/gallery/general/auth/username/text()"); + index->auth_passwd = xml_file_get_node_value (xml, "/gallery/general/auth/password/text()"); + if (index->auth_type != AUTH_TYPE_NONE && (index->auth_realm == NULL || index->auth_username == NULL || index->auth_passwd == NULL)) { + log_error ("Authentication requested but not all information provided. Ignoring.\n"); + index->auth_type = AUTH_TYPE_NONE; + } + /* Section Items */ count = xml_file_node_get_children_count (xml, "/gallery/items/*"); index->items = g_ptr_array_new (); @@ -276,6 +290,9 @@ free_album_data (TAlbum *album) g_free (album->meta_author); g_free (album->meta_description); g_free (album->meta_keywords); + g_free (album->auth_realm); + g_free (album->auth_username); + g_free (album->auth_passwd); g_strfreev (album->extra_files); if (album->items) { diff --git a/src/items.h b/src/items.h index 2a7179c..5b350b9 100644 --- a/src/items.h +++ b/src/items.h @@ -34,6 +34,11 @@ typedef enum { INDEX_ITEM_TYPE_INTERSPACE = 1 << 2 } TIndexItemType; +typedef enum { + AUTH_TYPE_NONE, + AUTH_TYPE_BASIC +} TAuthType; + typedef struct { TGalleryType type; gchar *ID; @@ -55,6 +60,10 @@ typedef struct { gboolean nofullsize; gboolean fullsize; gchar **extra_files; + gchar *auth_realm; + gchar *auth_username; + gchar *auth_passwd; + TAuthType auth_type; } TAlbum; typedef struct { diff --git a/src/job-manager.c b/src/job-manager.c index bf3b0df..8044b7f 100644 --- a/src/job-manager.c +++ b/src/job-manager.c @@ -35,6 +35,7 @@ #define DEFAULT_DATA_DIR_MODE S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH +#define AUTH_PASSWD_FILE ".htpasswd" typedef struct { @@ -268,9 +269,34 @@ build_tree (TGallerySetup *setup, } } + /* Cleanup for auth */ + if (items->auth_type != AUTH_TYPE_NONE) { + /* We're appending by default to preserve user .htaccess file supplied as an extra file. + * Let's remove the target file to prevent endless appending when overwriting the dst structure. */ + s1 = g_build_filename (path_info->dest_dir, ".htaccess", NULL); + unlink (s1); + g_free (s1); + } + /* Copy extra files */ mirror_files (setup, items->extra_files, path_info->src_dir, path_info->dest_dir, " Copying extra files: "); + /* Write auth files */ + if (items->auth_type != AUTH_TYPE_NONE) { + if (setup->verbose) printf (" Writing auth files: "); + s1 = g_build_filename (path_info->dest_dir, AUTH_PASSWD_FILE, NULL); + if (write_auth_passwd_file (setup, s1, items) && setup->verbose) + printf ("%s ", AUTH_PASSWD_FILE); + g_free (s1); + s1 = g_build_filename (path_info->dest_dir, ".htaccess", NULL); + s2 = g_build_filename (setup->location_local_path, path_info->album_path, AUTH_PASSWD_FILE, NULL); + if (write_auth_htaccess_file (setup, s1, s2, items) && setup->verbose) + printf ("%s ", ".htaccess"); + g_free (s2); + g_free (s1); + if (setup->verbose) printf ("\n"); + } + /* Prepare target image directories */ for (l = g_list_first (setup->design->image_sizes); l; l = g_list_next (l)) { image_size = l->data; |
