You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2013/02/07 18:29:44 UTC

svn commit: r1443615 - in /subversion/trunk/subversion: include/svn_auth.h libsvn_subr/auth.c libsvn_subr/auth.h libsvn_subr/config_auth.c libsvn_subr/simple_providers.c tests/libsvn_subr/auth-test.c

Author: rhuijben
Date: Thu Feb  7 17:29:44 2013
New Revision: 1443615

URL: http://svn.apache.org/viewvc?rev=1443615&view=rev
Log:
Resolve issue #2775, by providing an api that allows removing cached
credentials for our api users.

As our credentials are keyed by 'realm' and the exact format
is provider specific I added a simple iterator over the cached
credentials, so a client can provide a UI on top, or simply guess
which ones to delete by checking if they contain a specific url.

* subversion/include/svn_auth.h
  (svn_auth_cleanup_callback): New typedef.
  (svn_auth_cleanup_walk): New function.

* subversion/libsvn_subr/auth.c
  (includes): Add auth.h
  (svn_auth_cleanup_walk): New function.

* subversion/libsvn_subr/auth.h
  (svn_auth__file_path): New function.
  (svn_auth__simple_cleanup_walk): New function.

* subversion/libsvn_subr/config_auth.c
  (auth_file_path): Rename to ...
  (svn_auth__file_path): ... this and make library public.
  (svn_config_read_auth_data): Update caller.
  (svn_config_write_auth_data): Update caller.

* subversion/libsvn_subr/simple_providers.c
  (includes): Add several.
  (svn_auth__simple_cleanup_walk): New function.

* subversion/tests/libsvn_subr/auth-test.c
  (includes): Add svn_auth_private.h.
  (cleanup_callback): New function.
  (test_auth_clear): Extend to verify the credential is really gone.

Added:
    subversion/trunk/subversion/libsvn_subr/auth.h   (with props)
Modified:
    subversion/trunk/subversion/include/svn_auth.h
    subversion/trunk/subversion/libsvn_subr/auth.c
    subversion/trunk/subversion/libsvn_subr/config_auth.c
    subversion/trunk/subversion/libsvn_subr/simple_providers.c
    subversion/trunk/subversion/tests/libsvn_subr/auth-test.c

Modified: subversion/trunk/subversion/include/svn_auth.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_auth.h?rev=1443615&r1=1443614&r2=1443615&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_auth.h (original)
+++ subversion/trunk/subversion/include/svn_auth.h Thu Feb  7 17:29:44 2013
@@ -775,6 +775,39 @@ svn_auth_get_simple_provider2(
   void *prompt_baton,
   apr_pool_t *pool);
 
+/** Callback for svn_auth_cleanup_walk.
+ *
+ * Called for each credential to allow selectively removing credentials.
+ *
+ * @a cred_kind and @realm specify the key of the credential (see
+ * svn_auth_first_credentials()).
+ *
+ * @a provider specifies which provider currently holds the credential.
+ *
+ * Before returning set @a *delete_cred to TRUE to remove the credential from
+ * the cache.
+ *
+ * @since New in 1.8.
+ */
+typedef svn_error_t * (*svn_auth_cleanup_callback)(svn_boolean_t *delete_cred,
+                                                   void *cleanup_baton,
+                                                   const char *cred_kind,
+                                                   const char *realmstring,
+                                                   const char *provider,
+                                                   apr_pool_t *scratch_pool);
+
+/** Call @a cleanup with information describing each currently cached
+ * credential (in providers that support iterating). If the callback
+ * confirms that the credential should be deleted, delete it.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_auth_cleanup_walk(svn_auth_baton_t *auth_baton,
+                      svn_auth_cleanup_callback cleanup,
+                      void *cleanup_baton,
+                      apr_pool_t *scratch_pool);
+
 /** Like svn_auth_get_simple_provider2, but without the ability to
  * call the svn_auth_plaintext_prompt_func_t callback, and the provider
  * always assumes that it is allowed to store the password in plaintext.

Modified: subversion/trunk/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/auth.c?rev=1443615&r1=1443614&r2=1443615&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/auth.c (original)
+++ subversion/trunk/subversion/libsvn_subr/auth.c Thu Feb  7 17:29:44 2013
@@ -35,6 +35,8 @@
 #include "svn_dso.h"
 #include "svn_version.h"
 
+#include "auth.h"
+
 /* AN OVERVIEW
    ===========
 
@@ -619,3 +621,20 @@ svn_auth_get_platform_specific_client_pr
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_auth_cleanup_walk(svn_auth_baton_t *baton,
+                      svn_auth_cleanup_callback cleanup,
+                      void *cleanup_baton,
+                      apr_pool_t *scratch_pool)
+{
+
+  if (apr_hash_get(baton->tables, SVN_AUTH_CRED_SIMPLE, APR_HASH_KEY_STRING))
+    {
+      SVN_ERR(svn_auth__simple_cleanup_walk(baton, cleanup, cleanup_baton,
+                                            baton->creds_cache, scratch_pool));
+    }
+  /* ### Maybe add support for other providers? */
+
+  return SVN_NO_ERROR;
+}

Added: subversion/trunk/subversion/libsvn_subr/auth.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/auth.h?rev=1443615&view=auto
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/auth.h (added)
+++ subversion/trunk/subversion/libsvn_subr/auth.h Thu Feb  7 17:29:44 2013
@@ -0,0 +1,47 @@
+/*
+ * auth.h :  shared stuff internal to the subr library.
+ *
+ * ====================================================================
+ *    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_SUBR_AUTH_H
+#define SVN_SUBR_AUTH_H
+
+/* Helper for svn_config_{read|write}_auth_data.  Return a path to a
+   file within ~/.subversion/auth/ that holds CRED_KIND credentials
+   within REALMSTRING.  If no path is available *PATH will be set to
+   NULL. */
+svn_error_t *
+svn_auth__file_path(const char **path,
+                    const char *cred_kind,
+                    const char *realmstring,
+                    const char *config_dir,
+                    apr_pool_t *pool);
+
+/* Implementation of svn_auth_cleanup_walk() for the "simple" provider */
+svn_error_t *
+svn_auth__simple_cleanup_walk(svn_auth_baton_t *baton,
+                              svn_auth_cleanup_callback cleanup,
+                              void *cleanup_baton,
+                              apr_hash_t *creds_cache,
+                              apr_pool_t *scratch_pool);
+
+
+#endif

Propchange: subversion/trunk/subversion/libsvn_subr/auth.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/trunk/subversion/libsvn_subr/config_auth.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/config_auth.c?rev=1443615&r1=1443614&r2=1443615&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/config_auth.c (original)
+++ subversion/trunk/subversion/libsvn_subr/config_auth.c Thu Feb  7 17:29:44 2013
@@ -35,12 +35,12 @@
    file within ~/.subversion/auth/ that holds CRED_KIND credentials
    within REALMSTRING.  If no path is available *PATH will be set to
    NULL. */
-static svn_error_t *
-auth_file_path(const char **path,
-               const char *cred_kind,
-               const char *realmstring,
-               const char *config_dir,
-               apr_pool_t *pool)
+svn_error_t *
+svn_auth__file_path(const char **path,
+                    const char *cred_kind,
+                    const char *realmstring,
+                    const char *config_dir,
+                    apr_pool_t *pool)
 {
   const char *authdir_path, *hexname;
   svn_checksum_t *checksum;
@@ -81,8 +81,8 @@ svn_config_read_auth_data(apr_hash_t **h
 
   *hash = NULL;
 
-  SVN_ERR(auth_file_path(&auth_path, cred_kind, realmstring, config_dir,
-                         pool));
+  SVN_ERR(svn_auth__file_path(&auth_path, cred_kind, realmstring, config_dir,
+                              pool));
   if (! auth_path)
     return SVN_NO_ERROR;
 
@@ -118,8 +118,8 @@ svn_config_write_auth_data(apr_hash_t *h
   svn_stream_t *stream;
   const char *auth_path;
 
-  SVN_ERR(auth_file_path(&auth_path, cred_kind, realmstring, config_dir,
-                         pool));
+  SVN_ERR(svn_auth__file_path(&auth_path, cred_kind, realmstring, config_dir,
+                              pool));
   if (! auth_path)
     return svn_error_create(SVN_ERR_NO_AUTH_FILE_PATH, NULL,
                             _("Unable to locate auth file"));

Modified: subversion/trunk/subversion/libsvn_subr/simple_providers.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/simple_providers.c?rev=1443615&r1=1443614&r2=1443615&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/simple_providers.c (original)
+++ subversion/trunk/subversion/libsvn_subr/simple_providers.c Thu Feb  7 17:29:44 2013
@@ -29,6 +29,9 @@
 
 #include <apr_pools.h>
 #include "svn_auth.h"
+#include "svn_dirent_uri.h"
+#include "svn_hash.h"
+#include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_utf.h"
 #include "svn_config.h"
@@ -37,6 +40,8 @@
 #include "private/svn_auth_private.h"
 
 #include "svn_private_config.h"
+
+#include "auth.h"
 
 /*-----------------------------------------------------------------------*/
 /* File provider                                                         */
@@ -520,6 +525,135 @@ simple_save_creds(svn_boolean_t *saved,
                                           pool);
 }
 
+svn_error_t *
+svn_auth__simple_cleanup_walk(svn_auth_baton_t *baton,
+                              svn_auth_cleanup_callback cleanup,
+                              void *cleanup_baton,
+                              apr_hash_t *creds_cache,
+                              apr_pool_t *scratch_pool)
+{
+  const char *config_dir;
+  svn_boolean_t no_auth_cache;
+  int i;
+  apr_pool_t *iterpool;
+
+  const char *cred_kinds[] =
+  {
+      SVN_AUTH_CRED_SIMPLE,
+      SVN_AUTH_CRED_USERNAME,
+      SVN_AUTH_CRED_SSL_CLIENT_CERT,
+      SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
+      SVN_AUTH_CRED_SSL_SERVER_TRUST,
+      NULL
+  };
+
+  config_dir = svn_auth_get_parameter(baton, SVN_AUTH_PARAM_CONFIG_DIR);
+  no_auth_cache = (svn_auth_get_parameter(baton, SVN_AUTH_PARAM_NO_AUTH_CACHE)
+                                != NULL);
+
+  if ((! config_dir) || no_auth_cache)
+    {
+      /* Can't locate the cache to clear */
+      return SVN_NO_ERROR;
+    }
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; cred_kinds[i]; i++)
+    {
+      const char *item_path;
+      const char *dir_path;
+      apr_hash_t *nodes;
+      svn_error_t *err;
+      apr_pool_t *itempool;
+      apr_hash_index_t *hi;
+
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(svn_auth__file_path(&item_path, cred_kinds[i], "!", config_dir,
+                                  iterpool));
+
+      dir_path = svn_dirent_dirname(item_path, iterpool);
+
+      err = svn_io_get_dirents3(&nodes, dir_path, TRUE, iterpool, iterpool);
+
+      if (err)
+        {
+          if (!APR_STATUS_IS_ENOENT(err->apr_err)
+              && !SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
+            return svn_error_trace(err);
+
+          svn_error_clear(err);
+          continue;
+        }
+
+      itempool = svn_pool_create(iterpool);
+      for (hi = apr_hash_first(iterpool, nodes); hi; hi = apr_hash_next(hi))
+        {
+          svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi);
+          const char *item_path;
+          svn_error_t *err;
+          svn_stream_t *stream;
+          apr_hash_t *file_data;
+
+          if (dirent->kind != svn_node_file)
+            continue;
+
+          svn_pool_clear(itempool);
+
+          item_path = svn_dirent_join(dir_path, svn__apr_hash_index_key(hi),
+                                      itempool);
+
+          err = svn_stream_open_readonly(&stream, item_path, itempool, itempool);
+          if (err)
+            {
+              /* Ignore this file. There are no credentials in it anyway */
+              svn_error_clear(err);
+              continue;
+            }
+
+          file_data = apr_hash_make(itempool);
+          err = svn_hash_read2(file_data, stream, SVN_HASH_TERMINATOR, itempool);
+          err = svn_error_compose_create(err, svn_stream_close(stream));
+          if (err)
+            {
+              /* Ignore this file. There are no credentials in it anyway */
+              svn_error_clear(err);
+              continue;
+            }
+
+          {
+            const svn_string_t *realm = svn_hash_gets(file_data, SVN_CONFIG_REALMSTRING_KEY);
+            svn_boolean_t delete_file = FALSE;
+
+            if (! realm)
+              continue; /* Not an auth file */
+
+            SVN_ERR(cleanup(&delete_file, cleanup_baton, cred_kinds[i], realm->data,
+                            SVN_AUTH_CRED_SIMPLE, itempool));
+
+            if (delete_file)
+              {
+                /* Delete from the credential hash */
+                const char *cache_key = apr_pstrcat(itempool,
+                                                    cred_kinds[0],
+                                                    ":",
+                                                    realm->data,
+                                                    (char *)NULL);
+
+                svn_hash_sets(creds_cache, cache_key, NULL);
+
+                /* And the file on disk */
+                SVN_ERR(svn_io_remove_file2(item_path, TRUE, itempool));
+              }
+          }
+        }
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
+
 static const svn_auth_provider_t simple_provider = {
   SVN_AUTH_CRED_SIMPLE,
   simple_first_creds,
@@ -721,7 +855,6 @@ simple_prompt_next_creds(void **credenti
                                  ! no_auth_cache, pool);
 }
 
-
 static const svn_auth_provider_t simple_prompt_provider = {
   SVN_AUTH_CRED_SIMPLE,
   simple_prompt_first_creds,

Modified: subversion/trunk/subversion/tests/libsvn_subr/auth-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/auth-test.c?rev=1443615&r1=1443614&r2=1443615&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/auth-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/auth-test.c Thu Feb  7 17:29:44 2013
@@ -26,6 +26,7 @@
 #include "svn_private_config.h"
 
 #include "../svn_test.h"
+#include "private/svn_auth_private.h"
 
 static svn_error_t *
 test_platform_specific_auth_providers(apr_pool_t *pool)
@@ -207,6 +208,26 @@ test_platform_specific_auth_providers(ap
   return SVN_NO_ERROR;
 }
 
+/* Helper for test_auth_clear(). Implements svn_auth_cleanup_callback */
+static svn_error_t *
+cleanup_callback(svn_boolean_t *delete_cred,
+                 void *cleanup_baton,
+                 const char *cred_kind,
+                 const char *realmstring,
+                 const char *provider,
+                 apr_pool_t *scratch_pool)
+{
+  if (!strcmp(provider, SVN_AUTH__SIMPLE_PASSWORD_TYPE))
+    return SVN_NO_ERROR;
+
+  SVN_TEST_ASSERT(! strcmp(cred_kind, SVN_AUTH_CRED_SIMPLE));
+  SVN_TEST_ASSERT(! strcmp(realmstring, "<http://my.host> My realm"));
+
+  *delete_cred = TRUE;
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 test_auth_clear(apr_pool_t *pool)
 {
@@ -255,9 +276,35 @@ test_auth_clear(apr_pool_t *pool)
   SVN_ERR(svn_auth_save_credentials(state, pool));
 
   /* Ok, and now we try to remove the credentials */
+  svn_auth_set_parameter(baton, SVN_AUTH_PARAM_DEFAULT_USERNAME, NULL);
+  svn_auth_set_parameter(baton, SVN_AUTH_PARAM_DEFAULT_PASSWORD, NULL);
+
+  /* Are they still in the baton? */
+  SVN_ERR(svn_auth_first_credentials(&credentials,
+                                     &state,
+                                     SVN_AUTH_CRED_SIMPLE,
+                                     "<http://my.host> My realm",
+                                     baton,
+                                     pool));
+
+  SVN_TEST_ASSERT(credentials);
+  creds = credentials;
+  SVN_TEST_ASSERT(! strcmp(creds->username, "jrandom"));
+  SVN_TEST_ASSERT(creds->may_save);
+
+
+  SVN_ERR(svn_auth_cleanup_walk(baton,
+                                cleanup_callback, NULL,
+                                pool));
 
-  /* ### TODO: Implement to resolve issue #2775 */
+  SVN_ERR(svn_auth_first_credentials(&credentials,
+                                     &state,
+                                     SVN_AUTH_CRED_SIMPLE,
+                                     "<http://my.host> My realm",
+                                     baton,
+                                     pool));
 
+  SVN_TEST_ASSERT(! credentials);
 
   return SVN_NO_ERROR;
 }
@@ -270,7 +317,13 @@ struct svn_test_descriptor_t test_funcs[
     SVN_TEST_NULL,
     SVN_TEST_PASS2(test_platform_specific_auth_providers,
                    "test retrieving platform-specific auth providers"),
+#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
     SVN_TEST_PASS2(test_auth_clear,
                    "test svn_auth_clear()"),
+#else
+    SVN_TEST_WIMP(test_auth_clear,
+                  "test svn_auth_clear()",
+                  "Needs testing with SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE"),
+#endif
     SVN_TEST_NULL
   };