Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import json | |
| 6 import logging | |
| 7 import os | |
| 8 import sys | |
| 9 import webapp2 | |
| 10 | |
| 11 from google.appengine.api import users | |
| 12 from webapp2_extras import jinja2 | |
| 13 | |
| 14 import common | |
| 15 | |
| 16 class AdminCommand(object): | |
| 17 """Base class for administrative commands. | |
| 18 | |
| 19 Implement get() and post() methods in the subclasses. | |
| 20 """ | |
| 21 | |
| 22 def __init__(self, handler): | |
| 23 self._handler = handler | |
| 24 | |
| 25 @property | |
| 26 def request(self): | |
| 27 return self._handler.request | |
| 28 | |
| 29 @property | |
| 30 def response(self): | |
| 31 return self._handler.response | |
| 32 | |
| 33 def render_response(self, _template, **context): | |
| 34 self._handler.render_response(_template, **context) | |
| 35 | |
| 36 | |
| 37 class AdminPage(AdminCommand): | |
| 38 """Display the admin page.""" | |
| 39 | |
| 40 def get(self): | |
| 41 context = {'title': 'Admin: Chrome Infra Monitoring Proxy'} | |
| 42 self.render_response('admin.html', **context) | |
| 43 | |
| 44 def post(self): | |
| 45 self.response.set_status(403) | |
| 46 return | |
| 47 | |
| 48 | |
| 49 class SetCredentials(AdminCommand): | |
| 50 """Save new credentials for the Monacq endpoint.""" | |
| 51 | |
| 52 @staticmethod | |
| 53 def setParams(params, data): | |
| 54 """Serialize data fields into template parameters.""" | |
| 55 params['url'] = data.url | |
| 56 params['credentials'] = json.dumps(data.credentials) | |
| 57 params['scopes'] = '\n'.join(data.scopes) | |
| 58 params['headers'] = json.dumps(data.headers) | |
| 59 | |
| 60 # Deserialize form fields. It is an inverse of setParams(). | |
| 61 _parsers = { | |
| 62 'url': lambda v: v, | |
| 63 'credentials': json.loads, | |
| 64 'scopes': lambda v: [l.strip() for l in v.splitlines() if l], | |
| 65 'headers': json.loads, | |
| 66 } | |
| 67 | |
| 68 def get(self): | |
| 69 params = { | |
| 70 'message': '', | |
| 71 'title': 'Config: Chrome Infra Monitoring Proxy', | |
| 72 } | |
| 73 data = common.MonAcqData.get_by_id(common.CONFIG_DATA_KEY) | |
| 74 if data: | |
| 75 self.setParams(params, data) | |
| 76 self.render_response('set_credentials.html', **params) | |
| 77 | |
| 78 def post(self): | |
| 79 params = { | |
| 80 'message': '', | |
| 81 'title': 'Config: Chrome Infra Monitoring Proxy', | |
| 82 } | |
| 83 data = common.MonAcqData.get_or_insert(common.CONFIG_DATA_KEY) | |
| 84 self.setParams(params, data) | |
| 85 | |
| 86 updated_fields = False | |
| 87 failed_fields = [] | |
| 88 for field, parser in self._parsers.iteritems(): | |
| 89 if not self.request.get(field): | |
| 90 continue | |
| 91 try: | |
| 92 setattr(data, field, parser(self.request.get(field))) | |
| 93 updated_fields = True | |
| 94 except ValueError: | |
| 95 failed_fields.append(field) | |
| 96 params[field] = self.request.get(field) | |
| 97 | |
| 98 if failed_fields: | |
| 99 params['message'] = 'Failed to update %s. Please try again.' % ( | |
| 100 ', '.join(failed_fields)) | |
| 101 elif updated_fields: | |
| 102 data.put() | |
| 103 self.setParams(params, data) | |
| 104 params['message'] = 'Updated configuration.' | |
| 105 logging.info('Updated configuration: %r', data) | |
| 106 self.render_response('set_credentials.html', **params) | |
| 107 | |
| 108 | |
| 109 commands = { | |
| 110 '': AdminPage, | |
| 111 'set-credentials': SetCredentials, | |
| 112 } | |
| 113 | |
| 114 | |
| 115 # TODO(sergeyberezin): reimplement this using auth groups. | |
| 116 class AdminDispatch(common.BaseHandler): | |
| 117 """Provide a cached Jinja environment to each request.""" | |
| 118 | |
| 119 def get(self, command): | |
| 120 if not users.get_current_user(): | |
| 121 self.redirect(users.create_login_url(self.request.url)) | |
| 122 return | |
| 123 if not users.is_current_user_admin(): | |
| 124 self.response.set_status(403) | |
| 125 return | |
| 126 commands[command](self).get() | |
| 127 | |
| 128 def post(self, command): | |
|
Vadim Sh.
2015/04/28 18:10:43
All POSTs here need XSRF protection, otherwise fol
Sergey Berezin
2015/04/28 19:35:27
Awesome! Thanks, Vadim, you just answered my not-y
| |
| 129 if not users.is_current_user_admin(): | |
| 130 self.response.set_status(403) | |
| 131 return | |
| 132 commands[command](self).post() | |
| 133 | |
| 134 | |
| 135 admin_handlers = [ | |
| 136 (r'/admin/(.*)', AdminDispatch), | |
| 137 ] | |
| 138 | |
| 139 admin = webapp2.WSGIApplication(admin_handlers, debug=True) | |
| OLD | NEW |