← Back to team overview

cf-charmers team mailing list archive

[Merge] lp:~johnsca/charms/trusty/cloudfoundry/reconciler-auth into lp:~cf-charmers/charms/trusty/cloudfoundry/trunk

 

Cory Johns has proposed merging lp:~johnsca/charms/trusty/cloudfoundry/reconciler-auth into lp:~cf-charmers/charms/trusty/cloudfoundry/trunk.

Requested reviews:
  Cloud Foundry Charmers (cf-charmers)

For more details, see:
https://code.launchpad.net/~johnsca/charms/trusty/cloudfoundry/reconciler-auth/+merge/243340

Uses the CF admin user username and password (admin / whatever-was-passed-into-cfdeploy).
-- 
Your team Cloud Foundry Charmers is requested to review the proposed merge of lp:~johnsca/charms/trusty/cloudfoundry/reconciler-auth into lp:~cf-charmers/charms/trusty/cloudfoundry/trunk.
=== modified file 'charmhelpers/core/services/base.py'
--- charmhelpers/core/services/base.py	2014-11-20 17:40:26 +0000
+++ charmhelpers/core/services/base.py	2014-12-01 22:39:38 +0000
@@ -2,7 +2,7 @@
 import json
 import hashlib
 import inspect
-from collections import Iterable
+from collections import Iterable, OrderedDict
 
 from charmhelpers.core import host
 from charmhelpers.core import hookenv
@@ -108,7 +108,7 @@
         self._ready_file = os.path.join(hookenv.charm_dir(), 'READY-SERVICES.json')
         self._data_hash_file = os.path.join(hookenv.charm_dir(), 'DATA-HASHES.json')
         self._ready = None
-        self.services = {}
+        self.services = OrderedDict()
         for service in services or []:
             service_name = service['service']
             self.services[service_name] = service

=== modified file 'hooks/common.py'
--- hooks/common.py	2014-11-07 21:18:42 +0000
+++ hooks/common.py	2014-12-01 22:39:38 +0000
@@ -7,6 +7,7 @@
 import yaml
 from urlparse import urlparse
 
+from charmhelpers.core import host
 from charmhelpers.core import hookenv
 from charmhelpers.core import services
 
@@ -17,6 +18,7 @@
 from cloudfoundry.contexts import OrchestratorRelation
 from cloudfoundry.contexts import CloudFoundryCredentials
 from cloudfoundry.contexts import RequiredConfig
+from cloudfoundry.contexts import StoredContext
 from cloudfoundry.path import path
 from cloudfoundry.utils import wait_for
 from cloudfoundry.utils import socket_open
@@ -66,7 +68,11 @@
     bundle = generator.build_deployment(placement)['cloudfoundry']
     wait_for(300, 5, socket_open)
     hookenv.log(json.dumps(bundle))
-    requests.post('http://localhost:8888/api/v1/', data=json.dumps(bundle))
+    creds = CloudFoundryCredentials().provide_data()
+    username = creds['admin-user']
+    password = creds['admin-password']
+    requests.post('http://localhost:8888/api/v1/', data=json.dumps(bundle),
+                  auth=(username, password))
 
 
 def cache_unit_addresses(s):
@@ -116,28 +122,29 @@
         return
     manager = services.ServiceManager([
         {
-            'service': 'bundle',
+            'service': 'nfs-kernel-server',
             'required_data': [
-                JujuAPICredentials(),
+                RequiredConfig('mirror_artifacts') == True,  # noqa
                 RequiredConfig('artifacts_url') != '',
+                {'nfs_units': OrchestratorRelation.remote_units()},
             ],
-            'provided_data': [OrchestratorRelation(),
-                              CloudFoundryCredentials()],
             'data_ready': [
-                cache_unit_addresses,
-                deploy,
+                precache_job_artifacts,
+                services.render_template('nfs-exports',
+                                         target='/etc/exports'),
             ],
-            'start': [],
-            'stop': [],
         },
         {
             'service': 'reconciler',
             'ports': [8888],
             'required_data': [
                 JujuAPICredentials(),
+                CloudFoundryCredentials.remote_view(),
                 RequiredConfig('artifacts_url') != '',
                 {'charm_dir': hookenv.charm_dir(),
                  'environment_uuid': os.environ.get('JUJU_ENV_UUID')},
+                StoredContext('.reconciler_cookie_secret.yaml',
+                              {'cookie_secret': host.pwgen(20)}),
             ],
             'data_ready': [
                 services.render_template('reconciler-upstart.conf',
@@ -147,17 +154,18 @@
             ],
         },
         {
-            'service': 'nfs-kernel-server',
+            'service': 'bundle',
             'required_data': [
-                RequiredConfig('mirror_artifacts') == True,  # noqa
+                JujuAPICredentials(),
                 RequiredConfig('artifacts_url') != '',
-                {'nfs_units': OrchestratorRelation.remote_units()},
             ],
+            'provided_data': [OrchestratorRelation(), CloudFoundryCredentials()],
             'data_ready': [
-                precache_job_artifacts,
-                services.render_template('nfs-exports',
-                                         target='/etc/exports'),
+                cache_unit_addresses,
+                deploy,
             ],
+            'start': [],
+            'stop': [],
         },
     ])
     manager.manage()

=== modified file 'reconciler/app.py'
--- reconciler/app.py	2014-11-20 16:09:27 +0000
+++ reconciler/app.py	2014-12-01 22:39:38 +0000
@@ -40,6 +40,7 @@
 import time
 import subprocess
 import hashlib
+import base64
 
 import tornado.autoreload
 import tornado.httpserver
@@ -233,6 +234,30 @@
         return self.settings['config']
 
 
+def require_basic_auth(handler_class):
+    def wrap_execute(handler_execute):
+        def _check_auth(header):
+            global application
+            username = application.config['credentials']['app']['user']
+            password = application.config['credentials']['app']['password']
+            if not header.startswith('Basic '):
+                return False
+            auth = base64.decodestring(header[6:]).split(':')
+            return auth == [username, password]
+
+        def _execute(handler, *args, **kwargs):
+            if not _check_auth(handler.request.headers.get('Authorization', '')):
+                handler.set_status(401)
+                handler.set_header('WWW-Authenticate', 'Basic realm=Restricted')
+                handler._transforms = []
+                handler.finish()
+                return False
+            return handler_execute(handler, *args, **kwargs)
+        return _execute
+    handler_class._execute = wrap_execute(handler_class._execute)
+    return handler_class
+
+
 def main():
     define('config', default='/etc/juju-deployer/server.conf', type=path)
 
@@ -240,7 +265,7 @@
     default_config = {
         'server.address': '127.0.0.1',
         'server.port': 8888,
-        'credentials.user': 'user-admin',
+        'credentials.juju.user': 'user-admin',
         'server.repository': 'build',
         'runtime.observe': True,
         'runtime.modify': True,
@@ -255,14 +280,14 @@
     application = ReconcilerWebApp([
         (r'/static/(.*)', tornado.web.StaticFileHandler,
          {'path': static_resources}),
-        (r"/dashboard.ws", DashboardIO),
-        (r"/api/v1/", StateHandler),
-        (r"/api/v1/status", StatusHandler),
-        (r"/api/v1/history", HistoryHandler),
-        (r"/api/v1/strategy", StrategyHandler),
-        (r"/debug/api/v1/reset", ResetHandler),
-        (r"/debug/api/v1/prev", PrevHandler),
-        (r"/", MainHandler)
+        (r"/dashboard.ws", require_basic_auth(DashboardIO)),
+        (r"/api/v1/", require_basic_auth(StateHandler)),
+        (r"/api/v1/status", require_basic_auth(StatusHandler)),
+        (r"/api/v1/history", require_basic_auth(HistoryHandler)),
+        (r"/api/v1/strategy", require_basic_auth(StrategyHandler)),
+        (r"/debug/api/v1/reset", require_basic_auth(ResetHandler)),
+        (r"/debug/api/v1/prev", require_basic_auth(PrevHandler)),
+        (r"/", require_basic_auth(MainHandler))
         ],
         autoreload=True,
         config=config,

=== modified file 'reconciler/strategy.py'
--- reconciler/strategy.py	2014-11-11 18:22:53 +0000
+++ reconciler/strategy.py	2014-12-01 22:39:38 +0000
@@ -49,8 +49,8 @@
         self._env = self.get_env(
             env_name=c.get('juju.environment'),
             api_address=api_address,
-            user=c['credentials.user'],
-            password=c['credentials.password'])
+            user=c['credentials.juju.user'],
+            password=c['credentials.juju.password'])
         return self._env
 
     @property

=== modified file 'templates/reconciler-config.conf'
--- templates/reconciler-config.conf	2014-11-06 23:37:55 +0000
+++ templates/reconciler-config.conf	2014-12-01 22:39:38 +0000
@@ -7,13 +7,20 @@
         {% endif %}
     },
     "credentials": {
-        "user": "user-admin",
-        "password": "{{api_password}}"
+        "juju": {
+            "user": "user-admin",
+            "password": "{{api_password}}"
+        },
+        "app": {
+            "user": "{{credentials[0]['admin-user']}}",
+            "password": "{{credentials[0]['admin-password']}}"
+        }
     },
     "server": {
         "address": "0.0.0.0",
         "port": 8888,
-        "repository": "build"
+        "repository": "build",
+        "cookie_secret": "{{cookie_secret}}"
     },
     "runtime": {
         "observe": true,