Author: cmpilato
Date: Fri Apr 13 21:16:29 2012
New Revision: 1325956
URL: http://svn.apache.org/viewvc?rev=1325956&view=rev
Log:
On the 'master-passphrase' branch, actually start playing with encrypted
storage.
### No, this is *absolutely not* a serious storage proposal! ###
* subversion/include/svn_error_codes.h
(SVN_ERR_NODE_NOT_FOUND): New error code.
* subversion/libsvn_subr/auth_store.h,
* subversion/libsvn_subr/pathetic_auth_store.c
Brand new files and content, implementing a rather pathetic
encrypted auth store for the sake of validating the general
approach.
* subversion/tests/libsvn_subr/crypto-test.c
(create_ephemeral_auth_store): New helper function.
(test_auth_store_basic, test_auth_store_get_set): New tests.
(test_funcs): Add references to new tests.
Added:
subversion/branches/master-passphrase/subversion/libsvn_subr/auth_store.h
(with props)
subversion/branches/master-passphrase/subversion/libsvn_subr/pathetic_auth_store.c
(with props)
Modified:
subversion/branches/master-passphrase/subversion/include/svn_error_codes.h
subversion/branches/master-passphrase/subversion/tests/libsvn_subr/crypto-test.c
Modified:
subversion/branches/master-passphrase/subversion/include/svn_error_codes.h
URL:
http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/include/svn_error_codes.h?rev=1325956&r1=1325955&r2=1325956&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/include/svn_error_codes.h
(original)
+++ subversion/branches/master-passphrase/subversion/include/svn_error_codes.h
Fri Apr 13 21:16:29 2012
@@ -313,6 +313,11 @@ SVN_ERROR_START
SVN_ERR_NODE_CATEGORY_START + 1,
"Unexpected node kind found")
+ /* @since New in 1.8 */
+ SVN_ERRDEF(SVN_ERR_NODE_NOT_FOUND,
+ SVN_ERR_NODE_CATEGORY_START + 2,
+ "Node not found")
+
/* entry errors */
SVN_ERRDEF(SVN_ERR_ENTRY_NOT_FOUND,
Added: subversion/branches/master-passphrase/subversion/libsvn_subr/auth_store.h
URL:
http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/auth_store.h?rev=1325956&view=auto
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/auth_store.h
(added)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/auth_store.h
Fri Apr 13 21:16:29 2012
@@ -0,0 +1,133 @@
+/*
+ * auth_store.h: Storage routines for authentication credentials
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#ifndef SVN_LIBSVN_SUBR_AUTH_STORE_H
+#define SVN_LIBSVN_SUBR_AUTH_STORE_H
+
+#include "svn_types.h"
+#include "svn_string.h"
+#include "svn_auth.h"
+#include "crypto.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Opaque encrypted authentication credential store object. */
+typedef struct svn_auth__store_t svn_auth__store_t;
+
+
+/* Open (creating if necessary and if CREATE is set) an encrypted
+ authentication credential store at AUTH_STORE_PATH, and set
+ *AUTH_STORE_P to the object which describes it.
+
+ CRYPTO_CTX is the cryptographic context which the store will use
+ for related functionality.
+
+ SECRET is the master passphrase used to encrypt the sensitive
+ contents of the store. When creating the store it is registered
+ with the store as-is, but when opening a previously existing store,
+ it is validated against the passphrase self-checking information in
+ the store itself. SVN_ERR_AUTHN_FAILED will be returned if SECRET
+ does not validate against an existing store's checktext.
+*/
+svn_error_t *
+svn_auth__store_open(svn_auth__store_t **auth_store_p,
+ const char *auth_store_path,
+ svn_crypto__ctx_t *crypto_ctx,
+ const svn_string_t *secret,
+ svn_boolean_t create,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+
+/* Close the auth store represented by AUTH_STORE. */
+svn_error_t *
+svn_auth__store_close(svn_auth__store_t *auth_store,
+ apr_pool_t *scratch_pool);
+
+
+/* Close the on-disk auth store represented by AUTH_STORE. */
+svn_error_t *
+svn_auth__store_delete(const char *auth_store_path,
+ apr_pool_t *scratch_pool);
+
+
+/* Set *CREDS_P to the "username" credentials from AUTH_STORE which
+ match REALMSTRING, if any.
+
+ NOTE: Only the 'username' member of *CREDS_P will be populated.
+*/
+svn_error_t *
+svn_auth__store_get_username_creds(svn_auth_cred_username_t **creds_p,
+ svn_auth__store_t *auth_store,
+ const char *realmstring,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+
+/* Store CREDS as "username" credentials in AUTH_STORE, associated
+ with REALMSTRING.
+
+ NOTE: Only the 'username' member of CREDS will be stored.
+*/
+svn_error_t *
+svn_auth__store_set_username_creds(svn_auth__store_t *auth_store,
+ const char *realmstring,
+ svn_auth_cred_username_t *creds,
+ apr_pool_t *scratch_pool);
+
+
+/* Set *CREDS_P to the "simple" credentials from AUTH_STORE which
+ match REALMSTRING, if any.
+
+ NOTE: Only the 'username' and 'password' members of *CREDS_P will
+ be populated.
+*/
+svn_error_t *
+svn_auth__store_get_simple_creds(svn_auth_cred_simple_t **creds_p,
+ svn_auth__store_t *auth_store,
+ const char *realmstring,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+
+/* Store CREDS as "simple" credentials in AUTH_STORE, associated with
+ REALMSTRING.
+
+ NOTE: Only the 'username' and 'password' members of CREDS will be
+ stored.
+*/
+svn_error_t *
+svn_auth__store_set_simple_creds(svn_auth__store_t *auth_store,
+ const char *realmstring,
+ svn_auth_cred_simple_t *creds,
+ apr_pool_t *scratch_pool);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SVN_LIBSVN_SUBR_AUTH_STORE_H */
Propchange:
subversion/branches/master-passphrase/subversion/libsvn_subr/auth_store.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
subversion/branches/master-passphrase/subversion/libsvn_subr/auth_store.h
------------------------------------------------------------------------------
svn:mime-type = text/x-chdr
Added:
subversion/branches/master-passphrase/subversion/libsvn_subr/pathetic_auth_store.c
URL:
http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/pathetic_auth_store.c?rev=1325956&view=auto
==============================================================================
---
subversion/branches/master-passphrase/subversion/libsvn_subr/pathetic_auth_store.c
(added)
+++
subversion/branches/master-passphrase/subversion/libsvn_subr/pathetic_auth_store.c
Fri Apr 13 21:16:29 2012
@@ -0,0 +1,542 @@
+/*
+ * pathetic_auth_store.c: A pathetic implementation of an encrypted
+ * auth store.
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#include "svn_dirent_uri.h"
+#include "svn_hash.h"
+#include "svn_io.h"
+#include "svn_auth.h"
+#include "svn_base64.h"
+#include "private/svn_skel.h"
+
+#include "crypto.h"
+#include "auth_store.h"
+#include "config_impl.h"
+
+#include "svn_private_config.h"
+
+/* This module implements an encrypted auth store using the popular
+ * serialized hash format, whose contents look like so:
+ *
+ * hash = {
+ * "checktext" ==> base64(skel(CIPHERTEXT, IV, SALT, CHECKTEXT)),
+ * KIND ":" REALMSTRING ==> base64(skel(CREDCIPHERTEXT, IV, SALT)),
+ * ...
+ * }
+ *
+ * The decrypted CREDCIPHERTEXT is a base64-encoded skel string
+ * containing authn-provider-specific data.
+ *
+ * KIND is a provider type string ("svn.simple", "svn.username", ...).
+ *
+ * Oh, it ain't pretty. It ain't supposed to be.
+ */
+
+
+
+
+struct svn_auth__store_t
+{
+ /* On-disk path of this store. */
+ const char *path;
+
+ /* Cryptographic context. */
+ svn_crypto__ctx_t *crypto_ctx;
+
+ /* Crypto secret (may be NULL if not yet provided, which will also
+ serve as our indication that the store hasn't yet been read). */
+ const svn_string_t *secret;
+
+ /* Skel containing checktext bits: (CIPHERTEXT, IV, SALT,
+ CHECKTEXT). This needs to be unparsed (stringified) and
+ base64-encoded before storage. */
+ svn_skel_t *checktext_skel;
+
+ /* Hash, mapping kind/realmstring keys to skels with credential
+ details: (CIPHERTEXT, IV, SALT). The skels need to be unparsed
+ and base64-encoded before storage. */
+ apr_hash_t *realmstring_skels;
+
+ /* Pool for holding all this fun stuff. */
+ apr_pool_t *pool;
+
+};
+
+
+/* Parse the contents of the auth store file represented by
+ AUTH_STORE. */
+static svn_error_t *
+read_auth_store(svn_auth__store_t *auth_store,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err;
+ svn_stream_t *stream;
+ apr_hash_t *hash, *realmstring_skels;
+ const svn_string_t *str;
+ svn_skel_t *checktext_skel = NULL;
+ apr_hash_index_t *hi;
+ svn_node_kind_t kind;
+
+ SVN_ERR(svn_io_check_path(auth_store->path, &kind, scratch_pool));
+ if (kind == svn_node_none)
+ return svn_error_create(SVN_ERR_NODE_NOT_FOUND, NULL,
+ _("Pathetic auth store not found"));
+ else if (kind != svn_node_file)
+ return svn_error_create(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+ _("Unexpected node kind for pathetic auth store"));
+
+ SVN_ERR_W(svn_stream_open_readonly(&stream, auth_store->path,
+ scratch_pool, scratch_pool),
+ _("Unable to open pathetic auth store for reading"));
+
+ hash = apr_hash_make(scratch_pool);
+ err = svn_hash_read2(hash, stream, SVN_HASH_TERMINATOR, scratch_pool);
+ if (err)
+ return svn_error_createf(err->apr_err, err,
+ _("Error parsing '%s'"),
+ svn_dirent_local_style(auth_store->path,
+ scratch_pool));
+ SVN_ERR(svn_stream_close(stream));
+
+ str = apr_hash_get(hash, "checktext", APR_HASH_KEY_STRING);
+ if (str)
+ {
+ str = svn_base64_decode_string(str, scratch_pool);
+ checktext_skel = svn_skel__parse(str->data, str->len, auth_store->pool);
+ apr_hash_set(hash, "checktext", APR_HASH_KEY_STRING, NULL);
+ }
+
+ realmstring_skels = apr_hash_make(auth_store->pool);
+ for (hi = apr_hash_first(scratch_pool, hash); hi; hi = apr_hash_next(hi))
+ {
+ const void *key;
+ apr_ssize_t klen;
+ void *val;
+
+ apr_hash_this(hi, &key, &klen, &val);
+ str = svn_base64_decode_string(val, scratch_pool);
+ apr_hash_set(realmstring_skels, apr_pstrdup(auth_store->pool, key), klen,
+ svn_skel__parse(str->data, str->len, auth_store->pool));
+ }
+
+ auth_store->checktext_skel = checktext_skel;
+ auth_store->realmstring_skels = realmstring_skels;
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Unparse the contents of AUTH_STORE to the appropriate on-disk
+ location. If there's no appropriate on-disk location to flush to
+ (because there's no configuration directory provided), do nothing. */
+static svn_error_t *
+write_auth_store(svn_auth__store_t *auth_store,
+ apr_pool_t *scratch_pool)
+{
+ apr_file_t *authfile = NULL;
+ svn_stream_t *stream;
+ apr_hash_t *hash = apr_hash_make(scratch_pool);
+ apr_hash_index_t *hi;
+ const svn_string_t *str;
+
+ SVN_ERR_ASSERT(auth_store->checktext_skel);
+
+ SVN_ERR_W(svn_io_file_open(&authfile, auth_store->path,
+ (APR_WRITE | APR_CREATE | APR_TRUNCATE
+ | APR_BUFFERED),
+ APR_OS_DEFAULT, scratch_pool),
+ _("Unable to open auth file for writing"));
+
+ str = svn_base64_encode_string2(
+ svn_string_create_from_buf(
+ svn_skel__unparse(auth_store->checktext_skel, scratch_pool),
+ scratch_pool),
+ FALSE, scratch_pool);
+ apr_hash_set(hash, "checktext", APR_HASH_KEY_STRING, str);
+ for (hi = apr_hash_first(scratch_pool, auth_store->realmstring_skels);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const void *key;
+ apr_ssize_t klen;
+ void *val;
+
+ apr_hash_this(hi, &key, &klen, &val);
+ str = svn_base64_encode_string2(
+ svn_string_create_from_buf(svn_skel__unparse(val,
+ scratch_pool),
+ scratch_pool),
+ FALSE, scratch_pool);
+ apr_hash_set(hash, key, klen, str);
+ }
+
+ stream = svn_stream_from_aprfile2(authfile, FALSE, scratch_pool);
+ SVN_ERR_W(svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR, scratch_pool),
+ apr_psprintf(scratch_pool, _("Error writing hash to '%s'"),
+ svn_dirent_local_style(auth_store->path,
+ scratch_pool)));
+
+ SVN_ERR(svn_stream_close(stream));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Create a pathetic auth store file at the path registered with
+ the AUTH_STORE object. */
+static svn_error_t *
+create_auth_store(svn_auth__store_t *auth_store,
+ apr_pool_t *scratch_pool)
+{
+ const svn_string_t *ciphertext, *iv, *salt;
+ const char *checktext;
+
+ SVN_ERR(svn_crypto__generate_secret_checktext(&ciphertext, &iv,
+ &salt, &checktext,
+ auth_store->crypto_ctx,
+ auth_store->secret,
+ scratch_pool, scratch_pool));
+
+ auth_store->checktext_skel = svn_skel__make_empty_list(auth_store->pool);
+ svn_skel__prepend(svn_skel__str_atom(checktext,
+ auth_store->pool),
+ auth_store->checktext_skel);
+ svn_skel__prepend(svn_skel__mem_atom(salt->data, salt->len,
+ auth_store->pool),
+ auth_store->checktext_skel);
+ svn_skel__prepend(svn_skel__mem_atom(iv->data, iv->len,
+ auth_store->pool),
+ auth_store->checktext_skel);
+ svn_skel__prepend(svn_skel__mem_atom(ciphertext->data, ciphertext->len,
+ auth_store->pool),
+ auth_store->checktext_skel);
+
+ auth_store->realmstring_skels = apr_hash_make(auth_store->pool);
+ SVN_ERR(write_auth_store(auth_store, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* ### TODO: document */
+static svn_error_t *
+get_cred_hash(apr_hash_t **cred_hash,
+ svn_auth__store_t *auth_store,
+ const char *cred_kind_string,
+ const char *realmstring,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *key, *plaintext;
+ svn_skel_t *realmstring_skel, *proplist_skel;
+ svn_skel_t *cipher_skel, *iv_skel, *salt_skel;
+ const svn_string_t *skel_str;
+
+ *cred_hash = NULL;
+
+ SVN_ERR_ASSERT(realmstring);
+ SVN_ERR_ASSERT(cred_kind_string);
+
+ key = apr_pstrcat(scratch_pool, cred_kind_string, ":", realmstring, NULL);
+ realmstring_skel = apr_hash_get(auth_store->realmstring_skels,
+ key, APR_HASH_KEY_STRING);
+ if (! realmstring_skel)
+ return SVN_NO_ERROR;
+
+ cipher_skel = realmstring_skel->children;
+ iv_skel = realmstring_skel->children->next;
+ salt_skel = realmstring_skel->children->next->next;
+
+ SVN_ERR(svn_crypto__decrypt_password(&plaintext,
+ auth_store->crypto_ctx,
+ svn_string_ncreate(cipher_skel->data,
+ cipher_skel->len,
+ scratch_pool),
+ svn_string_ncreate(iv_skel->data,
+ iv_skel->len,
+ scratch_pool),
+ svn_string_ncreate(salt_skel->data,
+ salt_skel->len,
+ scratch_pool),
+ auth_store->secret,
+ scratch_pool, scratch_pool));
+
+ skel_str = svn_base64_decode_string(svn_string_create(plaintext,
+ scratch_pool),
+ scratch_pool);
+ proplist_skel = svn_skel__parse(skel_str->data, skel_str->len, scratch_pool);
+ SVN_ERR(svn_skel__parse_proplist(cred_hash, proplist_skel, result_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* ### TODO: document */
+static svn_error_t *
+set_cred_hash(svn_auth__store_t *auth_store,
+ const char *cred_kind_string,
+ const char *realmstring,
+ apr_hash_t *cred_hash,
+ apr_pool_t *scratch_pool)
+{
+ const char *key;
+ svn_skel_t *proplist_skel, *realmstring_skel;
+ svn_stringbuf_t *skel_buf;
+ const svn_string_t *skel_str;
+ const svn_string_t *ciphertext, *iv, *salt;
+
+ SVN_ERR(svn_skel__unparse_proplist(&proplist_skel, cred_hash, scratch_pool));
+ skel_buf = svn_skel__unparse(proplist_skel, scratch_pool);
+ skel_str = svn_base64_encode_string2(svn_string_ncreate(skel_buf->data,
+ skel_buf->len,
+ scratch_pool),
+ FALSE, scratch_pool);
+
+ SVN_ERR(svn_crypto__encrypt_password(&ciphertext, &iv, &salt,
+ auth_store->crypto_ctx, skel_str->data,
+ auth_store->secret, auth_store->pool,
+ scratch_pool));
+
+ realmstring_skel = svn_skel__make_empty_list(auth_store->pool);
+ svn_skel__prepend(svn_skel__mem_atom(salt->data, salt->len,
+ auth_store->pool),
+ realmstring_skel);
+ svn_skel__prepend(svn_skel__mem_atom(iv->data, iv->len,
+ auth_store->pool),
+ realmstring_skel);
+ svn_skel__prepend(svn_skel__mem_atom(ciphertext->data, ciphertext->len,
+ auth_store->pool),
+ realmstring_skel);
+
+ key = apr_pstrcat(auth_store->pool, cred_kind_string, ":",
+ realmstring, NULL);
+ apr_hash_set(auth_store->realmstring_skels, key,
+ APR_HASH_KEY_STRING, realmstring_skel);
+
+ SVN_ERR(write_auth_store(auth_store, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/*** Semi-public APIs ***/
+
+svn_error_t *
+svn_auth__store_open(svn_auth__store_t **auth_store_p,
+ const char *auth_store_path,
+ svn_crypto__ctx_t *crypto_ctx,
+ const svn_string_t *secret,
+ svn_boolean_t create,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_auth__store_t *auth_store;
+ svn_error_t *err;
+ svn_skel_t *cipher_skel, *iv_skel, *salt_skel, *check_skel;
+ svn_boolean_t valid_secret;
+
+ if (! svn_crypto__is_available())
+ return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ _("Encrypted auth store feature not available"));
+
+ auth_store = apr_pcalloc(result_pool, sizeof(*auth_store));
+ auth_store->pool = result_pool;
+ auth_store->path = apr_pstrdup(result_pool, auth_store_path);
+ auth_store->crypto_ctx = crypto_ctx;
+ auth_store->secret = svn_string_dup(secret, result_pool);
+
+ err = read_auth_store(auth_store, scratch_pool);
+ if (err)
+ {
+ if (err->apr_err == SVN_ERR_NODE_NOT_FOUND)
+ {
+ if (create)
+ {
+ svn_error_clear(err);
+ *auth_store_p = auth_store;
+ return svn_error_trace(create_auth_store(auth_store,
+ scratch_pool));
+ }
+ else
+ {
+ return err;
+ }
+ }
+ else
+ {
+ return err;
+ }
+ }
+
+ cipher_skel = auth_store->checktext_skel->children;
+ iv_skel = auth_store->checktext_skel->children->next;
+ salt_skel = auth_store->checktext_skel->children->next->next;
+ check_skel = auth_store->checktext_skel->children->next->next->next;
+
+ SVN_ERR(svn_crypto__verify_secret(&valid_secret,
+ auth_store->crypto_ctx,
+ auth_store->secret,
+ svn_string_ncreate(cipher_skel->data,
+ cipher_skel->len,
+ scratch_pool),
+ svn_string_ncreate(iv_skel->data,
+ iv_skel->len,
+ scratch_pool),
+ svn_string_ncreate(salt_skel->data,
+ salt_skel->len,
+ scratch_pool),
+ apr_pstrmemdup(scratch_pool,
+ check_skel->data,
+ check_skel->len),
+ scratch_pool));
+ if (! valid_secret)
+ return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL, _("Invalid secret"));
+
+ *auth_store_p = auth_store;
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_auth__store_close(svn_auth__store_t *auth_store,
+ apr_pool_t *scratch_pool)
+{
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_auth__store_delete(const char *auth_store_path,
+ apr_pool_t *scratch_pool)
+{
+ svn_node_kind_t kind;
+
+ SVN_ERR(svn_io_check_path(auth_store_path, &kind, scratch_pool));
+ if (kind == svn_node_none)
+ return svn_error_create(SVN_ERR_NODE_NOT_FOUND, NULL,
+ _("Pathetic auth store not found"));
+ else if (kind != svn_node_file)
+ return svn_error_create(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+ _("Unexpected node kind for pathetic auth store"));
+
+ SVN_ERR(svn_io_remove_file2(auth_store_path, FALSE, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_auth__store_get_username_creds(svn_auth_cred_username_t **creds_p,
+ svn_auth__store_t *auth_store,
+ const char *realmstring,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_auth_cred_username_t *creds;
+ apr_hash_t *cred_hash;
+ const svn_string_t *prop;
+
+ *creds_p = NULL;
+
+ SVN_ERR(get_cred_hash(&cred_hash, auth_store, SVN_AUTH_CRED_USERNAME,
+ realmstring, result_pool, scratch_pool));
+
+ creds = apr_pcalloc(result_pool, sizeof(*creds));
+ prop = apr_hash_get(cred_hash, "username", APR_HASH_KEY_STRING);
+ if (prop)
+ creds->username = prop->data;
+
+ *creds_p = creds;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_auth__store_set_username_creds(svn_auth__store_t *auth_store,
+ const char *realmstring,
+ svn_auth_cred_username_t *creds,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *cred_hash = apr_hash_make(scratch_pool);
+
+ if (creds->username)
+ apr_hash_set(cred_hash, "username", APR_HASH_KEY_STRING,
+ svn_string_create(creds->username, scratch_pool));
+
+ SVN_ERR(set_cred_hash(auth_store, SVN_AUTH_CRED_USERNAME, realmstring,
+ cred_hash, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_auth__store_get_simple_creds(svn_auth_cred_simple_t **creds_p,
+ svn_auth__store_t *auth_store,
+ const char *realmstring,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_auth_cred_simple_t *creds;
+ apr_hash_t *cred_hash;
+ const svn_string_t *prop;
+
+ *creds_p = NULL;
+
+ SVN_ERR(get_cred_hash(&cred_hash, auth_store, SVN_AUTH_CRED_SIMPLE,
+ realmstring, result_pool, scratch_pool));
+
+ creds = apr_pcalloc(result_pool, sizeof(*creds));
+ prop = apr_hash_get(cred_hash, "username", APR_HASH_KEY_STRING);
+ if (prop)
+ creds->username = prop->data;
+ prop = apr_hash_get(cred_hash, "password", APR_HASH_KEY_STRING);
+ if (prop)
+ creds->username = prop->data;
+
+ *creds_p = creds;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_auth__store_set_simple_creds(svn_auth__store_t *auth_store,
+ const char *realmstring,
+ svn_auth_cred_simple_t *creds,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *cred_hash = apr_hash_make(scratch_pool);
+
+ if (creds->username)
+ apr_hash_set(cred_hash, "username", APR_HASH_KEY_STRING,
+ svn_string_create(creds->username, scratch_pool));
+ if (creds->password)
+ apr_hash_set(cred_hash, "password", APR_HASH_KEY_STRING,
+ svn_string_create(creds->password, scratch_pool));
+
+ SVN_ERR(set_cred_hash(auth_store, SVN_AUTH_CRED_SIMPLE, realmstring,
+ cred_hash, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+
Propchange:
subversion/branches/master-passphrase/subversion/libsvn_subr/pathetic_auth_store.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
subversion/branches/master-passphrase/subversion/libsvn_subr/pathetic_auth_store.c
------------------------------------------------------------------------------
svn:mime-type = text/x-csrc
Modified:
subversion/branches/master-passphrase/subversion/tests/libsvn_subr/crypto-test.c
URL:
http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/tests/libsvn_subr/crypto-test.c?rev=1325956&r1=1325955&r2=1325956&view=diff
==============================================================================
---
subversion/branches/master-passphrase/subversion/tests/libsvn_subr/crypto-test.c
(original)
+++
subversion/branches/master-passphrase/subversion/tests/libsvn_subr/crypto-test.c
Fri Apr 13 21:16:29 2012
@@ -25,11 +25,16 @@
#include <string.h>
#include "svn_pools.h"
+#include "svn_io.h"
#include "../svn_test.h"
#include "../../libsvn_subr/crypto.h"
+#include "../../libsvn_subr/auth_store.h"
-/* Helper function: encrypt PASSWORD within CTX using MASTER, then
+
+/*** Helper functions ***/
+
+/* Encrypt PASSWORD within CTX using MASTER, then
decrypt those results and ensure the original PASSWORD comes out
the other end. */
static svn_error_t *
@@ -73,6 +78,31 @@ encrypt_decrypt(svn_crypto__ctx_t *ctx,
}
+/* Create an auth store within CONFIG_DIR, deleting any previous auth
+ store at that location, and using CRYPTO_CTX and the master
+ passphrase SECRET. Set *AUTH_STORE_P to the resulting store
+ object. */
+static svn_error_t *
+create_ephemeral_auth_store(svn_auth__store_t **auth_store_p,
+ const char **auth_store_path,
+ svn_crypto__ctx_t *crypto_ctx,
+ const svn_string_t *secret,
+ apr_pool_t *pool)
+{
+ SVN_ERR(svn_io_open_uniquely_named(NULL, auth_store_path, NULL,
+ "auth_store", NULL,
+ svn_io_file_del_on_pool_cleanup,
+ pool, pool));
+ SVN_ERR(svn_io_remove_file2(*auth_store_path, TRUE, pool));
+ SVN_ERR(svn_auth__store_open(auth_store_p, *auth_store_path, crypto_ctx,
+ secret, TRUE, pool, pool));
+ return SVN_NO_ERROR;
+}
+
+
+
+/*** Test functions ***/
+
static svn_error_t *
test_encrypt_decrypt_password(apr_pool_t *pool)
{
@@ -141,6 +171,9 @@ test_passphrase_check(apr_pool_t *pool)
"Error validating secret against checktext");
}
+ /* Now check that a bogus secret causes the validation to fail. We
+ try to verify each secret against the checktext generated by the
+ previous one. */
for (i = 0; i < num_passwords; i++)
{
int test_secret_index = (i + 1) % num_passwords;
@@ -159,13 +192,115 @@ test_passphrase_check(apr_pool_t *pool)
"got success");
}
- /* Now check that a bogus secret causes the validation to fail. */
-
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
+static svn_error_t *
+test_auth_store_basic(apr_pool_t *pool)
+{
+ svn_error_t *err;
+ svn_crypto__ctx_t *ctx;
+ svn_auth__store_t *auth_store;
+ const char *auth_store_path;
+ const svn_string_t *secret = svn_string_create("My Secret", pool);
+ const svn_string_t *bad_secret = svn_string_create("Not My Secret", pool);
+
+ /* Skip this test if the crypto subsystem is unavailable. */
+ if (! svn_crypto__is_available())
+ return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, NULL);
+
+ SVN_ERR(svn_crypto__context_create(&ctx, pool));
+ SVN_ERR(create_ephemeral_auth_store(&auth_store, &auth_store_path,
+ ctx, secret, pool));
+
+ /* Close and reopen the auth store. */
+ SVN_ERR(svn_auth__store_close(auth_store, pool));
+ SVN_ERR(svn_auth__store_open(&auth_store, auth_store_path, ctx,
+ secret, FALSE, pool, pool));
+
+ /* Close and reopen the auth store with a bogus secret. */
+ SVN_ERR(svn_auth__store_close(auth_store, pool));
+ err = svn_auth__store_open(&auth_store, auth_store_path, ctx,
+ bad_secret, FALSE, pool, pool);
+ if (! err)
+ return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
+ "Successfully opened auth store with the wrong "
+ "secret");
+ if (err && (err->apr_err == SVN_ERR_AUTHN_FAILED))
+ {
+ svn_error_clear(err);
+ err = SVN_NO_ERROR;
+ }
+ SVN_ERR(err);
+
+ return SVN_NO_ERROR;
+}
+
+
+
+static svn_error_t *
+test_auth_store_get_set(apr_pool_t *pool)
+{
+ svn_crypto__ctx_t *ctx;
+ apr_pool_t *iterpool;
+ svn_auth__store_t *auth_store;
+ const char *auth_store_path;
+ const svn_string_t *secret = svn_string_create("My Secret", pool);
+ const char *usernames[] = {
+ "jrandom",
+ "root",
+ "John Boy"
+ };
+ const char *passwords[] = { /* sync with USERNAMES array length */
+ "rayjandom",
+ "l33th4x0r",
+ "Billy"
+ };
+ int i;
+ svn_auth_cred_username_t *username_creds;
+ svn_auth_cred_simple_t *simple_creds;
+ const char *realmstring;
+
+ /* Skip this test if the crypto subsystem is unavailable. */
+ if (! svn_crypto__is_available())
+ return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, NULL);
+
+ SVN_ERR(svn_crypto__context_create(&ctx, pool));
+ SVN_ERR(create_ephemeral_auth_store(&auth_store, &auth_store_path,
+ ctx, secret, pool));
+
+ iterpool = svn_pool_create(pool);
+
+ /* Store some simple and username creds. */
+ for (i = 0; i < (sizeof(usernames) / sizeof(const char *)); i++)
+ {
+ svn_pool_clear(iterpool);
+
+ realmstring = usernames[i]; /* not schema-jiving */
+ username_creds = apr_pcalloc(iterpool, sizeof(*username_creds));
+ username_creds->username = usernames[i];
+ SVN_ERR(svn_auth__store_set_username_creds(auth_store, realmstring,
+ username_creds, iterpool));
+ }
+ for (i = 0; i < (sizeof(usernames) / sizeof(const char *)); i++)
+ {
+ svn_pool_clear(iterpool);
+
+ realmstring = usernames[i]; /* not schema-jiving */
+ simple_creds = apr_pcalloc(iterpool, sizeof(*simple_creds));
+ simple_creds->username = usernames[i];
+ simple_creds->password = passwords[i];
+ SVN_ERR(svn_auth__store_set_simple_creds(auth_store, realmstring,
+ simple_creds, iterpool));
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
/* The test table. */
@@ -177,5 +312,9 @@ struct svn_test_descriptor_t test_funcs[
"basic password encryption/decryption test"),
SVN_TEST_PASS2(test_passphrase_check,
"password checktext generation/validation"),
+ SVN_TEST_PASS2(test_auth_store_basic,
+ "basic auth store create/open test"),
+ SVN_TEST_PASS2(test_auth_store_get_set,
+ "basic auth store get/set creds test"),
SVN_TEST_NULL
};