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"] && [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