You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Victor Sudakov <su...@sibptus.tomsk.ru> on 2013/02/07 09:31:54 UTC

Kerberos foreign principals

Colleagues,

I use subversion-1.7.2 with cyrus-sasl-2.1.25 for Kerberos (GSSAPI)
authentication. I have the following in svnserve.conf: 

[general]
auth-access = write
[general]
realm = SIBPTUS.TOMSK.RU
[sasl]
use-sasl = true

Everything works smoothly for the users (Kerberos principals) in the
SIBPTUS.TOMSK.RU realm.

How can I give repository access (authorization) to users in other
realms which are trusted by the SIBPTUS.TOMSK.RU realm? It seems that
"auth-access = write" is not sufficient to give them access.

I would not mind if all the foreign principals were granted write
access to the repository with their subversion ids (e.g. in logs) being
'user@FOREIGN.REALM'. Is this possible?

TIA for any input.

-- 
Victor Sudakov,  VAS4-RIPE, VAS47-RIPN
sip:sudakov@sibptus.tomsk.ru

Re: Kerberos foreign principals

Posted by Stefan Sperling <st...@elego.de>.
On Thu, Feb 07, 2013 at 03:31:54PM +0700, Victor Sudakov wrote:
> Colleagues,
> 
> I use subversion-1.7.2 with cyrus-sasl-2.1.25 for Kerberos (GSSAPI)
> authentication. I have the following in svnserve.conf: 
> 
> [general]
> auth-access = write
> [general]
> realm = SIBPTUS.TOMSK.RU
> [sasl]
> use-sasl = true
> 
> Everything works smoothly for the users (Kerberos principals) in the
> SIBPTUS.TOMSK.RU realm.
> 
> How can I give repository access (authorization) to users in other
> realms which are trusted by the SIBPTUS.TOMSK.RU realm? It seems that
> "auth-access = write" is not sufficient to give them access.
> 
> I would not mind if all the foreign principals were granted write
> access to the repository with their subversion ids (e.g. in logs) being
> 'user@FOREIGN.REALM'. Is this possible?
> 
> TIA for any input.

Cross-realm auth isn't supported at present, as reported by Alec Kloss
here: http://svn.haxx.se/users/archive-2008-08/0472.shtml

And Alec also submitted a patch:
http://svn.haxx.se/dev/archive-2009-03/0650.shtml

But we never applied it due to lack of time and ability to test it:
http://svn.haxx.se/dev/archive-2010-05/0098.shtml

Would you be willing to help test this patch against 1.7 sources?

[[[

Add option cross-realm support to cyrus_auth.c.  Adds three
boolean configuration entries in the [sasl] section:

enable-cross-realm:  set to enable cross-realm support
remove-local-realm:  set to true to remove the local realm
	from a user name, false to keep the realm on a local user.
	Defaults to !enable-cross-realm
remove-remote-realm: set to true to remove the realm of a remote
	user.  This is a potential security hazard and should not 
	be enabled unless you're confident all realms are trustworthy.

]]]

Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h	(revision 1439424)
+++ subversion/include/svn_config.h	(working copy)
@@ -135,6 +135,9 @@ typedef struct svn_config_t svn_config_t;
 #define SVN_CONFIG_OPTION_USE_SASL                  "use-sasl"
 #define SVN_CONFIG_OPTION_MIN_SSF                   "min-encryption"
 #define SVN_CONFIG_OPTION_MAX_SSF                   "max-encryption"
+#define SVN_CONFIG_OPTION_ENABLE_CROSS_REALM        "enable-cross-realm"
+#define SVN_CONFIG_OPTION_REMOVE_LOCAL_REALM        "remove-local-realm"
+#define SVN_CONFIG_OPTION_REMOVE_REMOTE_REALM       "remove-remote-realm"
 
 /* For repository password database */
 #define SVN_CONFIG_SECTION_USERS                "users"
Index: subversion/svnserve/cyrus_auth.c
===================================================================
--- subversion/svnserve/cyrus_auth.c	(revision 1439424)
+++ subversion/svnserve/cyrus_auth.c	(working copy)
@@ -53,7 +53,7 @@
    '\0'-terminated; we just need to set *OUT_LEN correctly.
 */
 static int canonicalize_username(sasl_conn_t *conn,
-                                 void *context, /* not used */
+                                 server_baton_t *b, /* set by cyrus_auth_request */
                                  const char *in, /* the username */
                                  unsigned inlen, /* its length */
                                  unsigned flags, /* not used */
@@ -61,11 +61,15 @@ static int canonicalize_username(sasl_conn_t *conn
                                  char *out, /* the output buffer */
                                  unsigned out_max, unsigned *out_len)
 {
+  svn_boolean_t crossrealm_enabled;
   int realm_len = strlen(user_realm);
   char *pos;
 
   *out_len = inlen;
 
+  svn_config_get_server_setting_bool(b->cfg, &crossrealm_enabled,
+    SVN_CONFIG_SECTION_SASL, SVN_CONFIG_OPTION_ENABLE_CROSS_REALM, FALSE);
+
   /* If the username contains an '@', the part after the '@' is the realm
      that the user wants to authenticate in. */
   pos = memchr(in, '@', inlen);
@@ -73,7 +77,7 @@ static int canonicalize_username(sasl_conn_t *conn
     {
       /* The only valid realm is user_realm (i.e. the repository's realm).
          If the user gave us another realm, complain. */
-      if (strncmp(pos+1, user_realm, inlen-(pos-in+1)) != 0)
+      if (!crossrealm_enabled && strncmp(pos+1, user_realm, inlen-(pos-in+1)) != 0)
         return SASL_BADPROT;
     }
   else
@@ -96,6 +100,7 @@ static int canonicalize_username(sasl_conn_t *conn
   return SASL_OK;
 }
 
+static int callbackslen = 2;
 static sasl_callback_t callbacks[] =
 {
   { SASL_CB_CANON_USER, canonicalize_username, NULL },
@@ -255,6 +260,7 @@ svn_error_t *cyrus_auth_request(svn_ra_svn_conn_t
   sasl_security_properties_t secprops;
   svn_boolean_t success, no_anonymous;
   int mech_count, result = SASL_OK;
+  sasl_callback_t *my_callbacks;
 
   SVN_ERR(svn_ra_svn__get_addresses(&localaddrport, &remoteaddrport,
                                         conn, pool));
@@ -266,12 +272,23 @@ svn_error_t *cyrus_auth_request(svn_ra_svn_conn_t
       return svn_ra_svn_flush(conn, pool);
     }
 
+  /* Initialize my own callbacks with my context */
+  my_callbacks = apr_palloc(pool, callbackslen*sizeof(sasl_callback_t));
+  if (!my_callbacks)
+  {
+      svn_error_t *err = svn_error_wrap_apr(apr_err, _("Can't allocate memory"));
+      SVN_ERR(write_failure(conn, pool, &err));
+      return svn_ra_svn_flush(conn, pool);
+  }
+  memcpy(my_callbacks, callbacks, callbackslen*sizeof(sasl_callback_t));
+  my_callbacks[0].context = b;
+
   /* Create a SASL context. SASL_SUCCESS_DATA tells SASL that the protocol
      supports sending data along with the final "success" message. */
   result = sasl_server_new(SVN_RA_SVN_SASL_NAME,
                            hostname, b->realm,
                            localaddrport, remoteaddrport,
-                           NULL, SASL_SUCCESS_DATA,
+                           my_callbacks, SASL_SUCCESS_DATA,
                            &sasl_ctx);
   if (result != SASL_OK)
     {
@@ -350,6 +367,9 @@ svn_error_t *cyrus_auth_request(svn_ra_svn_conn_t
 
   if (no_anonymous)
     {
+      svn_boolean_t crossrealm_enabled;
+      svn_boolean_t remove_local_realm;
+      svn_boolean_t remove_remote_realm;
       char *p;
       const void *user;
 
@@ -359,10 +379,27 @@ svn_error_t *cyrus_auth_request(svn_ra_svn_conn_t
       if (result != SASL_OK)
         return fail_cmd(conn, pool, sasl_ctx);
 
+      svn_config_get_server_setting_bool(b->cfg, &crossrealm_enabled,
+        SVN_CONFIG_SECTION_SASL, SVN_CONFIG_OPTION_ENABLE_CROSS_REALM, FALSE);
+
+      svn_config_get_server_setting_bool(b->cfg, &remove_local_realm,
+        SVN_CONFIG_SECTION_SASL, SVN_CONFIG_OPTION_REMOVE_LOCAL_REALM, !crossrealm_enabled);
+
+      svn_config_get_server_setting_bool(b->cfg, &remove_remote_realm,
+        SVN_CONFIG_SECTION_SASL, SVN_CONFIG_OPTION_REMOVE_REMOTE_REALM, FALSE);
+
       if ((p = strchr(user, '@')) != NULL)
         {
-          /* Drop the realm part. */
-          b->user = apr_pstrndup(b->pool, user, p - (const char *)user);
+          svn_boolean_t is_local_realm = !strcmp(p+1, b->realm);
+          svn_boolean_t remove_realm  = 
+            remove_local_realm && is_local_realm ||
+            remove_remote_realm && !is_local_realm;
+
+          if (remove_realm)
+            /* Drop the realm part. */
+            b->user = apr_pstrndup(b->pool, user, p - (char *)user);
+          else
+            b->user = apr_pstrdup(b->pool, user);
         }
       else
         {