thirdparty/google_appengine/google/appengine/tools/dev_appserver_login.py
changeset 109 620f9b141567
child 686 df109be0567c
equal deleted inserted replaced
108:261778de26ff 109:620f9b141567
       
     1 #!/usr/bin/env python
       
     2 #
       
     3 # Copyright 2007 Google Inc.
       
     4 #
       
     5 # Licensed under the Apache License, Version 2.0 (the "License");
       
     6 # you may not use this file except in compliance with the License.
       
     7 # You may obtain a copy of the License at
       
     8 #
       
     9 #     http://www.apache.org/licenses/LICENSE-2.0
       
    10 #
       
    11 # Unless required by applicable law or agreed to in writing, software
       
    12 # distributed under the License is distributed on an "AS IS" BASIS,
       
    13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    14 # See the License for the specific language governing permissions and
       
    15 # limitations under the License.
       
    16 #
       
    17 """Helper CGI for logins/logout in the development application server.
       
    18 
       
    19 This CGI has these parameters:
       
    20 
       
    21   continue: URL to redirect to after a login or logout has completed.
       
    22   email: Email address to set for the client.
       
    23   admin: If 'True', the client should be logged in as an admin.
       
    24   action: What action to take ('Login' or 'Logout').
       
    25 
       
    26 To view the current user information and a form for logging in and out,
       
    27 supply no parameters.
       
    28 """
       
    29 
       
    30 
       
    31 import Cookie
       
    32 import cgi
       
    33 import os
       
    34 import sys
       
    35 import urllib
       
    36 
       
    37 
       
    38 CONTINUE_PARAM = 'continue'
       
    39 EMAIL_PARAM = 'email'
       
    40 ADMIN_PARAM = 'admin'
       
    41 ACTION_PARAM = 'action'
       
    42 
       
    43 LOGOUT_ACTION = 'Logout'
       
    44 LOGIN_ACTION = 'Login'
       
    45 
       
    46 LOGOUT_PARAM = 'action=%s' % LOGOUT_ACTION
       
    47 
       
    48 COOKIE_NAME = 'dev_appserver_login'
       
    49 
       
    50 
       
    51 def GetUserInfo(http_cookie, cookie_name=COOKIE_NAME):
       
    52   """Get the requestor's user info from the HTTP cookie in the CGI environment.
       
    53 
       
    54   Args:
       
    55     http_cookie: Value of the HTTP_COOKIE environment variable.
       
    56     cookie_name: Name of the cookie that stores the user info.
       
    57 
       
    58   Returns:
       
    59     Tuple (email, admin) where:
       
    60       email: The user's email address, if any.
       
    61       admin: True if the user is an admin; False otherwise.
       
    62   """
       
    63   cookie = Cookie.SimpleCookie(http_cookie)
       
    64 
       
    65   cookie_value = ''
       
    66   if cookie_name in cookie:
       
    67     cookie_value = cookie[cookie_name].value
       
    68 
       
    69   email, admin = (cookie_value.split(':') + ['', ''])[:2]
       
    70   return email, (admin == 'True')
       
    71 
       
    72 
       
    73 def CreateCookieData(email, admin):
       
    74   """Creates cookie payload data.
       
    75 
       
    76   Args:
       
    77     email, admin: Parameters to incorporate into the cookie.
       
    78 
       
    79   Returns:
       
    80     String containing the cookie payload.
       
    81   """
       
    82   admin_string = 'False'
       
    83   if admin:
       
    84     admin_string = 'True'
       
    85   return '%s:%s' % (email, admin_string)
       
    86 
       
    87 
       
    88 def SetUserInfoCookie(email, admin, cookie_name=COOKIE_NAME):
       
    89   """Creates a cookie to set the user information for the requestor.
       
    90 
       
    91   Args:
       
    92     email: Email to set for the user.
       
    93     admin: True if the user should be admin; False otherwise.
       
    94     cookie_name: Name of the cookie that stores the user info.
       
    95 
       
    96   Returns:
       
    97     'Set-Cookie' header for setting the user info of the requestor.
       
    98   """
       
    99   cookie_value = CreateCookieData(email, admin)
       
   100   set_cookie = Cookie.SimpleCookie()
       
   101   set_cookie[cookie_name] = cookie_value
       
   102   set_cookie[cookie_name]['path'] = '/'
       
   103   return '%s\r\n' % set_cookie
       
   104 
       
   105 
       
   106 def ClearUserInfoCookie(cookie_name=COOKIE_NAME):
       
   107   """Clears the user info cookie from the requestor, logging them out.
       
   108 
       
   109   Args:
       
   110     cookie_name: Name of the cookie that stores the user info.
       
   111 
       
   112   Returns:
       
   113     'Set-Cookie' header for clearing the user info of the requestor.
       
   114   """
       
   115   set_cookie = Cookie.SimpleCookie()
       
   116   set_cookie[cookie_name] = ''
       
   117   set_cookie[cookie_name]['path'] = '/'
       
   118   set_cookie[cookie_name]['max-age'] = '0'
       
   119   return '%s\r\n' % set_cookie
       
   120 
       
   121 
       
   122 LOGIN_TEMPLATE = """<html>
       
   123 <head>
       
   124   <title>Login</title>
       
   125 </head>
       
   126 <body>
       
   127 
       
   128 <form method='get' action='%(login_url)s'
       
   129       style='text-align:center; font: 13px sans-serif'>
       
   130   <div style='width: 20em; margin: 1em auto;
       
   131               text-align:left;
       
   132               padding: 0 2em 1.25em 2em;
       
   133               background-color: #d6e9f8;
       
   134               border: 2px solid #67a7e3'>
       
   135     <h3>%(login_message)s</h3>
       
   136     <p style='padding: 0; margin: 0'>
       
   137       <label for='email' style="width: 3em">Email:</label>
       
   138       <input name='email' type='text' value='%(email)s' id='email'/>
       
   139     </p>
       
   140     <p style='margin: .5em 0 0 3em; font-size:12px'>
       
   141       <input name='admin' type='checkbox' value='True'
       
   142        %(admin_checked)s id='admin'/>
       
   143         <label for='admin'>Sign in as Administrator</label>
       
   144     </p>
       
   145     <p style='margin-left: 3em'>
       
   146       <input name='action' value='Login' type='submit'
       
   147              id='submit-login' />
       
   148       <input name='action' value='Logout' type='submit'
       
   149              id='submit-logout' />
       
   150     </p>
       
   151   </div>
       
   152   <input name='continue' type='hidden' value='%(continue_url)s'/>
       
   153 </form>
       
   154 
       
   155 </body>
       
   156 </html>
       
   157 """
       
   158 
       
   159 
       
   160 def RenderLoginTemplate(login_url, continue_url, email, admin):
       
   161   """Renders the login page.
       
   162 
       
   163   Args:
       
   164     login_url, continue_url, email, admin: Parameters passed to
       
   165       LoginCGI.
       
   166 
       
   167   Returns:
       
   168     String containing the contents of the login page.
       
   169   """
       
   170   login_message = 'Not logged in'
       
   171   if email:
       
   172     login_message = 'Logged in'
       
   173   admin_checked = ''
       
   174   if admin:
       
   175     admin_checked = 'checked'
       
   176 
       
   177   template_dict = {
       
   178 
       
   179 
       
   180     'email': email or 'test\x40example.com',
       
   181     'admin_checked': admin_checked,
       
   182     'login_message': login_message,
       
   183     'login_url': login_url,
       
   184     'continue_url': continue_url
       
   185   }
       
   186 
       
   187   return LOGIN_TEMPLATE % template_dict
       
   188 
       
   189 
       
   190 def LoginRedirect(login_url,
       
   191                   hostname,
       
   192                   port,
       
   193                   relative_url,
       
   194                   outfile):
       
   195   """Writes a login redirection URL to a user.
       
   196 
       
   197   Args:
       
   198     login_url: Relative URL which should be used for handling user logins.
       
   199     hostname: Name of the host on which the webserver is running.
       
   200     port: Port on which the webserver is running.
       
   201     relative_url: String containing the URL accessed.
       
   202     outfile: File-like object to which the response should be written.
       
   203   """
       
   204   dest_url = "http://%s:%s%s" % (hostname, port, relative_url)
       
   205   redirect_url = 'http://%s:%s%s?%s=%s' % (hostname,
       
   206                                            port,
       
   207                                            login_url,
       
   208                                            CONTINUE_PARAM,
       
   209                                            urllib.quote(dest_url))
       
   210   outfile.write('Status: 302 Requires login\r\n')
       
   211   outfile.write('Location: %s\r\n\r\n' % redirect_url)
       
   212 
       
   213 
       
   214 def LoginCGI(login_url,
       
   215              email,
       
   216              admin,
       
   217              action,
       
   218              set_email,
       
   219              set_admin,
       
   220              continue_url,
       
   221              outfile):
       
   222   """Runs the login CGI.
       
   223 
       
   224   This CGI does not care about the method at all. For both POST and GET the
       
   225   client will be redirected to the continue URL.
       
   226 
       
   227   Args:
       
   228     login_url: URL used to run the CGI.
       
   229     email: Current email address of the requesting user.
       
   230     admin: True if the requesting user is an admin; False otherwise.
       
   231     action: The action used to run the CGI; 'Login' for a login action, 'Logout'
       
   232       for when a logout should occur.
       
   233     set_email: Email to set for the user; Empty if no email should be set.
       
   234     set_admin: True if the user should be an admin; False otherwise.
       
   235     continue_url: URL to which the user should be redirected when the CGI
       
   236       finishes loading; defaults to the login_url with no parameters (showing
       
   237       current status) if not supplied.
       
   238     outfile: File-like object to which all output data should be written.
       
   239   """
       
   240   redirect_url = ''
       
   241   output_headers = []
       
   242 
       
   243   if action:
       
   244     if action.lower() == LOGOUT_ACTION.lower():
       
   245       output_headers.append(ClearUserInfoCookie())
       
   246     elif set_email:
       
   247       output_headers.append(SetUserInfoCookie(set_email, set_admin))
       
   248 
       
   249     redirect_url = continue_url or login_url
       
   250   elif email and continue_url:
       
   251     redirect_url = continue_url
       
   252 
       
   253   if redirect_url:
       
   254     outfile.write('Status: 302 Redirecting to continue URL\r\n')
       
   255     for header in output_headers:
       
   256       outfile.write(header)
       
   257     outfile.write('Location: %s\r\n' % redirect_url)
       
   258     outfile.write('\r\n')
       
   259   else:
       
   260     outfile.write('Status: 200\r\n')
       
   261     outfile.write('Content-Type: text/html\r\n')
       
   262     outfile.write('\r\n')
       
   263     outfile.write(RenderLoginTemplate(login_url,
       
   264                                       continue_url,
       
   265                                       email,
       
   266                                       admin))
       
   267 
       
   268 
       
   269 def main():
       
   270   """Runs the login and logout CGI script."""
       
   271   form = cgi.FieldStorage()
       
   272   login_url = os.environ['PATH_INFO']
       
   273   email = os.environ.get('USER_EMAIL', '')
       
   274   admin = os.environ.get('USER_IS_ADMIN', '0') == '1'
       
   275 
       
   276   action = form.getfirst(ACTION_PARAM)
       
   277   set_email = form.getfirst(EMAIL_PARAM, '')
       
   278   set_admin = form.getfirst(ADMIN_PARAM, '') == 'True'
       
   279   continue_url = form.getfirst(CONTINUE_PARAM, '')
       
   280 
       
   281   LoginCGI(login_url,
       
   282            email,
       
   283            admin,
       
   284            action,
       
   285            set_email,
       
   286            set_admin,
       
   287            continue_url,
       
   288            sys.stdout)
       
   289   return 0
       
   290 
       
   291 
       
   292 if __name__ == '__main__':
       
   293   main()