subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cmpil...@apache.org
Subject svn commit: r1325956 - in /subversion/branches/master-passphrase/subversion: include/svn_error_codes.h libsvn_subr/auth_store.h libsvn_subr/pathetic_auth_store.c tests/libsvn_subr/crypto-test.c
Date Fri, 13 Apr 2012 21:16:30 GMT
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
   };



Mime
View raw message