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 |