You are viewing a plain text version of this content. The canonical link for it is here.
Posted to websh-cvs@tcl.apache.org by ro...@apache.org on 2009/04/10 22:42:23 UTC

svn commit: r764044 - in /tcl/websh/trunk: CHANGES doc/quickref.xml src/ChangeLog src/apachetests/docs/headers.ws3 src/apachetests/test/headers.test src/generic/request_ap.c src/generic/script.ws3 src/tests/request.test

Author: ronnie
Date: Fri Apr 10 20:42:22 2009
New Revision: 764044

URL: http://svn.apache.org/viewvc?rev=764044&view=rev
Log:
- added AUTH_USER and AUTH_PW to web::request to allow Basic Auth handling

Modified:
    tcl/websh/trunk/CHANGES
    tcl/websh/trunk/doc/quickref.xml
    tcl/websh/trunk/src/ChangeLog
    tcl/websh/trunk/src/apachetests/docs/headers.ws3
    tcl/websh/trunk/src/apachetests/test/headers.test
    tcl/websh/trunk/src/generic/request_ap.c
    tcl/websh/trunk/src/generic/script.ws3
    tcl/websh/trunk/src/tests/request.test

Modified: tcl/websh/trunk/CHANGES
URL: http://svn.apache.org/viewvc/tcl/websh/trunk/CHANGES?rev=764044&r1=764043&r2=764044&view=diff
==============================================================================
--- tcl/websh/trunk/CHANGES (original)
+++ tcl/websh/trunk/CHANGES Fri Apr 10 20:42:22 2009
@@ -9,6 +9,11 @@
 Trunk
 -----
 
+- web::request now provides AUTH_USER and AUTH_PW if Authorization 
+  header is sent, and Apache does not handle it (i.e. does not provide 
+  the REMOTE_USER variable). Refer to the quick reference for an 
+  explanation about how to make it work in CGI.
+
 - Revamped mod_websh tests: better directory structure and integrated
   into src/unix/Makefile: 'make apachetest' now runs the test suite
 

Modified: tcl/websh/trunk/doc/quickref.xml
URL: http://svn.apache.org/viewvc/tcl/websh/trunk/doc/quickref.xml?rev=764044&r1=764043&r2=764044&view=diff
==============================================================================
--- tcl/websh/trunk/doc/quickref.xml (original)
+++ tcl/websh/trunk/doc/quickref.xml Fri Apr 10 20:42:22 2009
@@ -998,6 +998,81 @@
 	  </varlistentry>
 	</variablelist>
 
+	Special case for handling Basic Auth:
+
+	<variablelist>
+	  <varlistentry>
+	    <term><command>web::request</command> <option>AUTH_USER</option></term>
+	    <listitem>
+	      <para>
+		returns the username provided by the user when Basic Auth is requested and Apache 
+		does not handle it (i.e. if Apache does not provide REMOTE_USER).
+	      </para>
+	    </listitem>
+	  </varlistentry>
+	  <varlistentry>
+	    <term><command>web::request</command> <option>AUTH_PW</option></term>
+	    <listitem>
+	      <para>
+		returns the password provided by the user when Basic Auth is requested and Apache 
+		does not handle it (i.e. if Apache does not provide REMOTE_USER).
+	      </para>
+	    </listitem>
+	  </varlistentry>
+	</variablelist>
+	
+        The following example provides a basic app that requires Basic Auth and
+        completely bypasses Apache's auth mechanisms.
+
+        <example>
+	  <title>web::request AUTH_USER and web::request AUTH_PW</title>
+      	  <programlisting>
+# returns 1 if user/pass provided is websh/websh
+proc isAuthenticated {} {
+    if {[web::request -count AUTH_USER]} {
+	set user [web::request AUTH_USER]
+	set pass [web::request AUTH_PW]
+	if {[string eq $user "websh"] &amp;&amp; [string eq $pass "websh"]} {
+	    return 1
+	}
+    }
+    return 0
+}
+
+# the default command requests Basic Auth unless provided correctly
+web::command default {
+    if {![isAuthenticated]} {
+	web::response -set Status {401 Authorization Required}
+	web::response -set WWW-Authenticate {Basic realm="Websh auth"}
+	web::put "Sorry, you're out"
+    } else {
+	web::put "You're in"
+    }
+}
+
+# command dispath
+web::dispatch
+	  </programlisting>
+        </example>
+
+        <emphasis>Note:</emphasis> CGI usually does not expose the Basic Auth
+        Authorization header for security reasons. The following configuration
+        for Apache (as of version 2.0.51) will allow Websh to also provide the
+        same functionality when running in CGI (requires mod_setenvif):
+
+        <example>
+	  <title>Apache configuration for AUTH_USER and AUTH_PW to work under CGI</title>
+      	  <programlisting>
+SetEnvIf Authorization "^(Basic .+)$" AUTH_BASIC=$1
+	  </programlisting>
+        </example>
+
+        <emphasis>Important security consideration:</emphasis> This configuration 
+        will also expose the authentication information to Websh when Apache does
+        handle the authentication. Although Websh hides the information in that 
+        case, it is always available in the CGI environment. Use this configuration
+        carefully!
+
       </para>
     </section>
     <section id="web::param">

Modified: tcl/websh/trunk/src/ChangeLog
URL: http://svn.apache.org/viewvc/tcl/websh/trunk/src/ChangeLog?rev=764044&r1=764043&r2=764044&view=diff
==============================================================================
--- tcl/websh/trunk/src/ChangeLog (original)
+++ tcl/websh/trunk/src/ChangeLog Fri Apr 10 20:42:22 2009
@@ -1,3 +1,13 @@
+2009-04-10 Brunner Ronnie <ro...@netcetera.ch>
+	* src/generic/script.ws3, src/generic/request_ap.c:
+	- web::request provides AUTH_USER and AUTH_PW if browser provides
+	  an Authorization header and Apache does not handle it.
+	* src/tests/request.test, src/apachetests/test/headers.test,
+	  src/apachetests/docs/headers.ws3:
+	- test [web::request AUTH_USER] and [web::request AUTH_PW]
+	* doc/quickref.xml
+	- documentation for AUTH_USER and AUTH_PW
+	
 2009-02-17 Brunner Ronnie <ro...@netcetera.ch>
 	* src/apachetests:
 	- Better directory structure

Modified: tcl/websh/trunk/src/apachetests/docs/headers.ws3
URL: http://svn.apache.org/viewvc/tcl/websh/trunk/src/apachetests/docs/headers.ws3?rev=764044&r1=764043&r2=764044&view=diff
==============================================================================
--- tcl/websh/trunk/src/apachetests/docs/headers.ws3 (original)
+++ tcl/websh/trunk/src/apachetests/docs/headers.ws3 Fri Apr 10 20:42:22 2009
@@ -10,5 +10,11 @@
     web::put "hi world"
 }
 
+web::command auth {
+    set user [web::request AUTH_USER]
+    set pass [web::request AUTH_PW]
+    web::put "$user*$pass"
+}
+
 web::dispatch
 

Modified: tcl/websh/trunk/src/apachetests/test/headers.test
URL: http://svn.apache.org/viewvc/tcl/websh/trunk/src/apachetests/test/headers.test?rev=764044&r1=764043&r2=764044&view=diff
==============================================================================
--- tcl/websh/trunk/src/apachetests/test/headers.test (original)
+++ tcl/websh/trunk/src/apachetests/test/headers.test Fri Apr 10 20:42:22 2009
@@ -4,8 +4,9 @@
 
 set testfilename1 "headers.ws3"
 
-::tcltest::test header-1.1 {websh header test} {
-    apachetest::start {} {
+apachetest::start {} {
+
+    ::tcltest::test header-1.1 {websh header test} {
 	### fixme: this can't work, because state doesn't handle
 	### multiple headers correctly anyway ...
 	#set page [ ::http::geturl "${urlbase}$testfilename1" ]
@@ -24,14 +25,8 @@
 	    }
 	}
 	close $s
-    }
-    ### fixme: this can't work, because state doesn't handle
-    ### multiple headers correctly anyway ...
-    # upvar 0 $page state
-    #array set meta $state(meta)
-    #array get meta
-    set page
-} {HTTP/1.1 200 OK
+	set page
+    } {HTTP/1.1 200 OK
 Foo: bar
 Foo: bla
 Foo: que
@@ -43,3 +38,14 @@
 
 hi world
 }
+
+    ::tcltest::test header-1.1 {websh Basic auth header test (pass through Authorization)} {
+	set auth [list Authorization {Basic d2Vic2g6cGFzcw==}]
+	set page [::http::geturl "${urlbase}/$testfilename1?cmd=auth" -headers $auth]
+	set match [::http::data $page]
+	set auth [list Authorization {Basic d2Vic2g6cGFzczp3b3Jk}]
+	set page [::http::geturl "${urlbase}/$testfilename1?cmd=auth" -headers $auth]
+	append match ! [::http::data $page]
+    } {websh*pass!websh*pass:word}
+
+}

Modified: tcl/websh/trunk/src/generic/request_ap.c
URL: http://svn.apache.org/viewvc/tcl/websh/trunk/src/generic/request_ap.c?rev=764044&r1=764043&r2=764044&view=diff
==============================================================================
--- tcl/websh/trunk/src/generic/request_ap.c (original)
+++ tcl/websh/trunk/src/generic/request_ap.c Fri Apr 10 20:42:22 2009
@@ -39,7 +39,6 @@
 int requestFillRequestValues(Tcl_Interp * interp, RequestData * requestData)
 {
 
-    /*Tcl_Obj *reso = NULL;*/
     request_rec *r = NULL;
 #ifndef APACHE2
     array_header *hdrs_arr = NULL;
@@ -49,6 +48,9 @@
     apr_table_entry_t *hdrs = NULL;
 #endif /* APACHE2 */
     int i = 0;
+    int remote_user = 0;
+
+    Tcl_Obj *valo = NULL;
 
     if (requestData->requestIsInitialized)
 	return TCL_OK;
@@ -64,8 +66,6 @@
 	return TCL_ERROR;
     }
 
-    /*reso = Tcl_NewObj();*/
-
 #ifndef APACHE2
     hdrs_arr = ap_table_elts(r->subprocess_env);
     hdrs = (table_entry *) hdrs_arr->elts;
@@ -75,7 +75,6 @@
 #endif /* APACHE2 */
     for (i = 0; i < hdrs_arr->nelts; ++i) {
 
-	Tcl_Obj *valo = NULL;
 	if (!hdrs[i].key)
 	    continue;
 
@@ -87,9 +86,68 @@
 	if (paramListAdd(requestData->request, hdrs[i].key, valo) != TCL_OK)
 	    /* fatal case */
 	    return TCL_ERROR;
+
+	if (!remote_user && !strcmp(hdrs[i].key, "REMOTE_USER")) {
+	  remote_user = 1;
+	}
     }
 
     paramListSetAsWhole(requestData->request, "GATEWAY_INTERFACE",
 			Tcl_NewStringObj("CGI-websh/1.1", -1));
+
+    /* create AUTH_USER and AUTH_PW if not set (i.e. if not handeled by Apache),
+       otherwise don't set them for security reasons */
+    if (!remote_user) {
+
+      int ret = 0;
+      const char *pw = NULL;
+      const char *user = NULL;
+      const char *auth_line;
+
+      /* Check to see if a Authorization header is there */
+#ifndef APACHE2
+      auth_line = (char *)ap_table_get(r->headers_in, "Authorization");
+#else /* APACHE2 */
+      auth_line = (char *)apr_table_get(r->headers_in, "Authorization");
+#endif
+      if (auth_line) {
+
+	char *decoded_line;
+	int length;
+
+	/* check if we know how to handle the Auth string */
+	if (!strcasecmp((char *)ap_getword(r->pool, &auth_line, ' '), "Basic")) {
+
+	  /* Skip leading spaces. */
+	  while (isspace((int)*auth_line)) {
+	    auth_line++;
+	  }
+#ifndef APACHE2
+	  decoded_line = (char *) ap_palloc(r->pool, ap_base64decode_len(auth_line) + 1);
+	  length = ap_base64decode(decoded_line, auth_line);
+#else /* APACHE2 */
+	  decoded_line = (char *) apr_palloc(r->pool, apr_base64_decode_len(auth_line) + 1);
+	  length = apr_base64_decode(decoded_line, auth_line);
+#endif
+	  /* Null-terminate the string. */
+	  decoded_line[length] = '\0';
+
+	  user = ap_getword_nulls(r->pool, (const char**)&decoded_line, ':');
+	  pw = decoded_line;
+
+	  if (paramListAdd(requestData->request, "AUTH_USER", Tcl_NewStringObj(user, -1)) != TCL_OK)
+	    /* fatal case */
+	    return TCL_ERROR;
+
+	  if (paramListAdd(requestData->request, "AUTH_PW", Tcl_NewStringObj(pw, -1)) != TCL_OK)
+	    /* fatal case */
+	    return TCL_ERROR;
+
+	}
+
+      }
+
+    }
+
     return TCL_OK;
 }

Modified: tcl/websh/trunk/src/generic/script.ws3
URL: http://svn.apache.org/viewvc/tcl/websh/trunk/src/generic/script.ws3?rev=764044&r1=764043&r2=764044&view=diff
==============================================================================
--- tcl/websh/trunk/src/generic/script.ws3 (original)
+++ tcl/websh/trunk/src/generic/script.ws3 Fri Apr 10 20:42:22 2009
@@ -170,10 +170,60 @@
 	HTTPS
     }
 
+    # set request headers from environment
     foreach e [array names ::env] {
 	if {![string match HTTP_* $e]} {
 	    if {[lsearch -exact $cgienv $e] == -1} continue
 	}
 	web::request -set $e $::env($e)
     }
-}
+    
+    # check for Authorization
+    if {![info exists ::env(REMOTE_USER)] && [info exists ::env(AUTH_BASIC)]} {
+	# AUTH_BASIC contains the Authorization header
+	# sent by the browser (e.g. created using Apache >= 2.0.51: 
+	#   SetEnvIf Authorization "^(Basic .+)$" AUTH_BASIC=$1
+	# check the quick reference for security considerations
+	if {[regexp "^Basic (.*)" $::env(AUTH_BASIC) dummy authstring]} {
+	    # base64 decode it
+	    set i 0
+	    foreach char {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
+		    a b c d e f g h i j k l m n o p q r s t u v w x y z \
+		    0 1 2 3 4 5 6 7 8 9 + / =} {
+		set b64($char) $i
+		incr i
+	    }
+	    set decoded {}
+	    set group 0; set j 18; set eq 0
+	    foreach char [split $authstring {}] {
+
+		# ignore all characters not in base64 character set
+		# should be only newlines, but who knows ;-)
+		if {![info exists b64($char)]} {continue}
+
+		if {[string compare $char "="]} {
+		    set bits $b64($char)
+		    set group [expr {$group | ($bits << $j)}]
+		} else {
+		    incr eq
+		}
+		
+		if {[incr j -6] < 0} {
+		    scan [format %06x $group] %2x%2x%2x a b c
+		    switch $eq {
+			0 {append decoded [format %c%c%c $a $b $c]}
+			1 {append decoded [format %c%c $a $b]}
+			2 {append decoded [format %c $a]}
+		    }
+		    set group 0; set j 18; set eq 0
+		}
+	    }
+	    # set request params
+	    web::request -set AUTH_USER [lindex [split $decoded :] 0]
+	    web::request -set AUTH_PW [join [lrange [split $decoded :] 1 end] :]
+	}
+    }
+    if {[info exists ::env(AUTH_BASIC)]} {
+	unset ::env(AUTH_BASIC)
+    }
+ }

Modified: tcl/websh/trunk/src/tests/request.test
URL: http://svn.apache.org/viewvc/tcl/websh/trunk/src/tests/request.test?rev=764044&r1=764043&r2=764044&view=diff
==============================================================================
--- tcl/websh/trunk/src/tests/request.test (original)
+++ tcl/websh/trunk/src/tests/request.test Fri Apr 10 20:42:22 2009
@@ -88,5 +88,19 @@
 } {stdin}
 
 
+test request-3.0 {check Basic Auth translation of Apache hack} {
+    set ::env(AUTH_BASIC) {Basic d2Vic2g6cGFzcw==}
+    ::web::request -reset
+    ::web::cgi::copyenv
+    set match "[web::request AUTH_USER]*[web::request AUTH_PW]"
+    set ::env(AUTH_BASIC) {Basic d2Vic2g6cGFzczp3b3Jk}
+    ::web::request -reset
+    ::web::cgi::copyenv
+    append match "![web::request AUTH_USER]*[web::request AUTH_PW]"
+    set match
+
+    } {websh*pass!websh*pass:word}
+}
+
 # cleanup
 ::tcltest::cleanupTests



---------------------------------------------------------------------
To unsubscribe, e-mail: websh-cvs-unsubscribe@tcl.apache.org
For additional commands, e-mail: websh-cvs-help@tcl.apache.org