summaryrefslogtreecommitdiffstats
path: root/google_appengine/google/appengine/tools/dev_appserver_login.py
diff options
context:
space:
mode:
Diffstat (limited to 'google_appengine/google/appengine/tools/dev_appserver_login.py')
-rwxr-xr-xgoogle_appengine/google/appengine/tools/dev_appserver_login.py297
1 files changed, 297 insertions, 0 deletions
diff --git a/google_appengine/google/appengine/tools/dev_appserver_login.py b/google_appengine/google/appengine/tools/dev_appserver_login.py
new file mode 100755
index 0000000..e03e9a3
--- /dev/null
+++ b/google_appengine/google/appengine/tools/dev_appserver_login.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed 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.
+#
+"""Helper CGI for logins/logout in the development application server.
+
+This CGI has these parameters:
+
+ continue: URL to redirect to after a login or logout has completed.
+ email: Email address to set for the client.
+ admin: If 'True', the client should be logged in as an admin.
+ action: What action to take ('Login' or 'Logout').
+
+To view the current user information and a form for logging in and out,
+supply no parameters.
+"""
+
+
+import cgi
+import Cookie
+import md5
+import os
+import sys
+import urllib
+
+
+CONTINUE_PARAM = 'continue'
+EMAIL_PARAM = 'email'
+ADMIN_PARAM = 'admin'
+ACTION_PARAM = 'action'
+
+LOGOUT_ACTION = 'Logout'
+LOGIN_ACTION = 'Login'
+
+LOGOUT_PARAM = 'action=%s' % LOGOUT_ACTION
+
+COOKIE_NAME = 'dev_appserver_login'
+
+
+def GetUserInfo(http_cookie, cookie_name=COOKIE_NAME):
+ """Get the requestor's user info from the HTTP cookie in the CGI environment.
+
+ Args:
+ http_cookie: Value of the HTTP_COOKIE environment variable.
+ cookie_name: Name of the cookie that stores the user info.
+
+ Returns:
+ Tuple (email, admin) where:
+ email: The user's email address, if any.
+ admin: True if the user is an admin; False otherwise.
+ """
+ cookie = Cookie.SimpleCookie(http_cookie)
+
+ cookie_value = ''
+ if cookie_name in cookie:
+ cookie_value = cookie[cookie_name].value
+
+ email, admin, user_id = (cookie_value.split(':') + ['', '', ''])[:3]
+ return email, (admin == 'True'), user_id
+
+
+def CreateCookieData(email, admin):
+ """Creates cookie payload data.
+
+ Args:
+ email, admin: Parameters to incorporate into the cookie.
+
+ Returns:
+ String containing the cookie payload.
+ """
+ admin_string = 'False'
+ if admin:
+ admin_string = 'True'
+ if email:
+ user_id_digest = md5.new(email.lower()).digest()
+ user_id = '1' + ''.join(['%02d' % ord(x) for x in user_id_digest])[:20]
+ else:
+ user_id = ''
+ return '%s:%s:%s' % (email, admin_string, user_id)
+
+
+def SetUserInfoCookie(email, admin, cookie_name=COOKIE_NAME):
+ """Creates a cookie to set the user information for the requestor.
+
+ Args:
+ email: Email to set for the user.
+ admin: True if the user should be admin; False otherwise.
+ cookie_name: Name of the cookie that stores the user info.
+
+ Returns:
+ 'Set-Cookie' header for setting the user info of the requestor.
+ """
+ cookie_value = CreateCookieData(email, admin)
+ set_cookie = Cookie.SimpleCookie()
+ set_cookie[cookie_name] = cookie_value
+ set_cookie[cookie_name]['path'] = '/'
+ return '%s\r\n' % set_cookie
+
+
+def ClearUserInfoCookie(cookie_name=COOKIE_NAME):
+ """Clears the user info cookie from the requestor, logging them out.
+
+ Args:
+ cookie_name: Name of the cookie that stores the user info.
+
+ Returns:
+ 'Set-Cookie' header for clearing the user info of the requestor.
+ """
+ set_cookie = Cookie.SimpleCookie()
+ set_cookie[cookie_name] = ''
+ set_cookie[cookie_name]['path'] = '/'
+ set_cookie[cookie_name]['max-age'] = '0'
+ return '%s\r\n' % set_cookie
+
+
+LOGIN_TEMPLATE = """<html>
+<head>
+ <title>Login</title>
+</head>
+<body>
+
+<form method='get' action='%(login_url)s'
+ style='text-align:center; font: 13px sans-serif'>
+ <div style='width: 20em; margin: 1em auto;
+ text-align:left;
+ padding: 0 2em 1.25em 2em;
+ background-color: #d6e9f8;
+ border: 2px solid #67a7e3'>
+ <h3>%(login_message)s</h3>
+ <p style='padding: 0; margin: 0'>
+ <label for='email' style="width: 3em">Email:</label>
+ <input name='email' type='text' value='%(email)s' id='email'/>
+ </p>
+ <p style='margin: .5em 0 0 3em; font-size:12px'>
+ <input name='admin' type='checkbox' value='True'
+ %(admin_checked)s id='admin'/>
+ <label for='admin'>Sign in as Administrator</label>
+ </p>
+ <p style='margin-left: 3em'>
+ <input name='action' value='Login' type='submit'
+ id='submit-login' />
+ <input name='action' value='Logout' type='submit'
+ id='submit-logout' />
+ </p>
+ </div>
+ <input name='continue' type='hidden' value='%(continue_url)s'/>
+</form>
+
+</body>
+</html>
+"""
+
+
+def RenderLoginTemplate(login_url, continue_url, email, admin):
+ """Renders the login page.
+
+ Args:
+ login_url, continue_url, email, admin: Parameters passed to
+ LoginCGI.
+
+ Returns:
+ String containing the contents of the login page.
+ """
+ login_message = 'Not logged in'
+ if email:
+ login_message = 'Logged in'
+ admin_checked = ''
+ if admin:
+ admin_checked = 'checked'
+
+ template_dict = {
+
+
+ 'email': email or 'test\x40example.com',
+ 'admin_checked': admin_checked,
+ 'login_message': login_message,
+ 'login_url': login_url,
+ 'continue_url': continue_url
+ }
+
+ return LOGIN_TEMPLATE % template_dict
+
+
+def LoginRedirect(login_url,
+ hostname,
+ port,
+ relative_url,
+ outfile):
+ """Writes a login redirection URL to a user.
+
+ Args:
+ login_url: Relative URL which should be used for handling user logins.
+ hostname: Name of the host on which the webserver is running.
+ port: Port on which the webserver is running.
+ relative_url: String containing the URL accessed.
+ outfile: File-like object to which the response should be written.
+ """
+ dest_url = "http://%s:%s%s" % (hostname, port, relative_url)
+ redirect_url = 'http://%s:%s%s?%s=%s' % (hostname,
+ port,
+ login_url,
+ CONTINUE_PARAM,
+ urllib.quote(dest_url))
+ outfile.write('Status: 302 Requires login\r\n')
+ outfile.write('Location: %s\r\n\r\n' % redirect_url)
+
+
+def LoginCGI(login_url,
+ email,
+ admin,
+ action,
+ set_email,
+ set_admin,
+ continue_url,
+ outfile):
+ """Runs the login CGI.
+
+ This CGI does not care about the method at all. For both POST and GET the
+ client will be redirected to the continue URL.
+
+ Args:
+ login_url: URL used to run the CGI.
+ email: Current email address of the requesting user.
+ admin: True if the requesting user is an admin; False otherwise.
+ action: The action used to run the CGI; 'Login' for a login action, 'Logout'
+ for when a logout should occur.
+ set_email: Email to set for the user; Empty if no email should be set.
+ set_admin: True if the user should be an admin; False otherwise.
+ continue_url: URL to which the user should be redirected when the CGI
+ finishes loading; defaults to the login_url with no parameters (showing
+ current status) if not supplied.
+ outfile: File-like object to which all output data should be written.
+ """
+ redirect_url = ''
+ output_headers = []
+
+ if action:
+ if action.lower() == LOGOUT_ACTION.lower():
+ output_headers.append(ClearUserInfoCookie())
+ elif set_email:
+ output_headers.append(SetUserInfoCookie(set_email, set_admin))
+
+ redirect_url = continue_url or login_url
+
+ if redirect_url:
+ outfile.write('Status: 302 Redirecting to continue URL\r\n')
+ for header in output_headers:
+ outfile.write(header)
+ outfile.write('Location: %s\r\n' % redirect_url)
+ outfile.write('\r\n')
+ else:
+ outfile.write('Status: 200\r\n')
+ outfile.write('Content-Type: text/html\r\n')
+ outfile.write('\r\n')
+ outfile.write(RenderLoginTemplate(login_url,
+ continue_url,
+ email,
+ admin))
+
+
+def main():
+ """Runs the login and logout CGI script."""
+ form = cgi.FieldStorage()
+ login_url = os.environ['PATH_INFO']
+ email = os.environ.get('USER_EMAIL', '')
+ admin = os.environ.get('USER_IS_ADMIN', '0') == '1'
+
+ action = form.getfirst(ACTION_PARAM)
+ set_email = form.getfirst(EMAIL_PARAM, '')
+ set_admin = form.getfirst(ADMIN_PARAM, '') == 'True'
+ continue_url = form.getfirst(CONTINUE_PARAM, '')
+
+ LoginCGI(login_url,
+ email,
+ admin,
+ action,
+ set_email,
+ set_admin,
+ continue_url,
+ sys.stdout)
+ return 0
+
+
+if __name__ == '__main__':
+ main()