Merge lp://staging/~hazmat/pyjuju/rapi-login into lp://staging/~hazmat/pyjuju/rapi-rollup

Proposed by Kapil Thangavelu
Status: Merged
Merged at revision: 624
Proposed branch: lp://staging/~hazmat/pyjuju/rapi-login
Merge into: lp://staging/~hazmat/pyjuju/rapi-rollup
Diff against target: 256 lines (+84/-12)
6 files modified
juju/errors.py (+4/-0)
juju/rapi/context.py (+9/-2)
juju/rapi/tests/common.py (+1/-0)
juju/rapi/tests/test_context.py (+3/-1)
juju/rapi/transport/tests/test_ws.py (+47/-2)
juju/rapi/transport/ws.py (+20/-7)
To merge this branch: bzr merge lp://staging/~hazmat/pyjuju/rapi-login
Reviewer Review Type Date Requested Status
Kapil Thangavelu Pending
Review via email: mp+140268@code.staging.launchpad.net

Description of the change

Require login before api usage.

This update requires login before using the ws api and before the delta stream is active.

https://codereview.appspot.com/6935068/

To post a comment you must log in.
Revision history for this message
Kapil Thangavelu (hazmat) wrote :
Download full text (8.5 KiB)

Reviewers: mp+140268_code.launchpad.net,

Message:
Please take a look.

Description:
Add a login api

Login support using admin credentials/secret

https://code.launchpad.net/~hazmat/juju/rapi-login/+merge/140268

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/6935068/

Affected files:
   A [revision details]
   M juju/agents/api.py
   M juju/rapi/context.py
   M juju/rapi/tests/test_context.py
   M juju/state/initialize.py
   M juju/state/tests/test_initialize.py

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>

Index: juju/agents/api.py
=== modified file 'juju/agents/api.py'
--- juju/agents/api.py 2012-09-10 03:43:29 +0000
+++ juju/agents/api.py 2012-12-12 19:30:20 +0000
@@ -11,6 +11,7 @@
  from juju.errors import JujuError
  from juju.lib.websockets import WebSocketsResource
  from juju.rapi.transport.ws import WebSocketAPIFactory
+from juju.state.auth import make_ace

  from twisted.web.static import Data
  from twisted.web.server import Site
@@ -32,7 +33,7 @@
          log.debug("Received environment data.")
          root = Data("Juju API Server\n", "text/plain")
          self.ws_factory = WebSocketAPIFactory(
- self.config['zookeeper_servers'], self.provider)
+ self.config['zookeeper_servers'], self.provider)
          yield self.ws_factory.startFactory()

          root.putChild('ws', WebSocketsResource(self.ws_factory))
@@ -79,10 +80,30 @@
                  environment = yield watch_d
              returnValue(environment)

+ # Lazy initialize login nodes if not present.
+ yield self._initialize_login()
+
          config = EnvironmentsConfig()
          config.parse(environment_data)
          returnValue(config.get_default())

+ @inlineCallbacks
+ def _initialize_login(self):
+ children = yield self.client.get_children("/")
+ if "login" in children:
+ return
+
+ acls, stat = yield self.client.get_acl("/initialized")
+ admin_acl = None
+
+ for a in acls:
+ if a['id'].startswith('admin'):
+ admin_acl = a
+ break
+
+ yield self.client.create(
+ "/login", acls=[make_ace(admin_acl['id'], all=True)])
+
      def configure(self, options):
          super(APIEndpointAgent, self).configure(options)
          if not options.get("port"):

Index: juju/rapi/context.py
=== modified file 'juju/rapi/context.py'
--- juju/rapi/context.py 2012-10-12 20:49:45 +0000
+++ juju/rapi/context.py 2012-12-12 19:30:20 +0000
@@ -1,5 +1,6 @@
  from StringIO import StringIO
-from twisted.internet.defer import maybeDeferred, succeed
+from twisted.internet.defer import (
+ maybeDeferred, succeed, returnValue, inlineCallbacks)

  from juju.rapi.cmd import add_relation
  from juju.rapi.cmd import add_unit
@@ -22,7 +23,10 @@

  from juju.rapi import rest

+from juju.state.security import Principal
+
  ...

Read more...

Revision history for this message
Nicola Larosa (teknico) wrote :

Code looks good, on the face of it (I'm not familiar with this
codebase).

I dislike one- or two-letter names, even in tests, but that's just
personal preference.

https://codereview.appspot.com/6935068/

Revision history for this message
Benjamin Saller (bcsaller) wrote :

I think I'm a little shy on context here given the comments below. If
the goals are in keeping with the comments then this seems ok, if we are
looking for real ACL access over the tree, it wasn't clear to make that
worked as expected.

https://codereview.appspot.com/6935068/diff/1/juju/agents/api.py
File juju/agents/api.py (right):

https://codereview.appspot.com/6935068/diff/1/juju/agents/api.py#newcode102
juju/agents/api.py:102: break
Its not possible for someone to register another 'admin' like name here
or will the first added always appear first? This seems an odd way of
tracking this. Since this codebase only supports admin anyway wouldn't
this be acls[0] anyway or are there others?

https://codereview.appspot.com/6935068/diff/1/juju/agents/api.py#newcode105
juju/agents/api.py:105: "/login", acls=[make_ace(admin_acl['id'],
all=True)])
I don't recall the details of the security branch, but this copies it
from /initialized to /login basically? I only have vague guesses as to
why this is the process, you need to create it during init to set up the
agents and then add it to the login tree which will in the future
support additional logins?

https://codereview.appspot.com/6935068/diff/1/juju/rapi/context.py
File juju/rapi/context.py (right):

https://codereview.appspot.com/6935068/diff/1/juju/rapi/context.py#newcode222
juju/rapi/context.py:222: yield self.client.get("/login")
This does the ACL check on the login node and and uses that as the
success boolean. Are the other nodes protected with the same ACL? Its
not clear where that's being managed here.

https://codereview.appspot.com/6935068/diff/1/juju/rapi/tests/test_context.py
File juju/rapi/tests/test_context.py (right):

https://codereview.appspot.com/6935068/diff/1/juju/rapi/tests/test_context.py#newcode177
juju/rapi/tests/test_context.py:177:
Again it looks like the ACL check works here, but I'm not sure if the
way this is wired in provides any actual access control outside of that
node. Is that a non-goal with this iteration?

https://codereview.appspot.com/6935068/

Revision history for this message
Kapil Thangavelu (hazmat) wrote :
Download full text (3.5 KiB)

replies to ben's comments.

https://codereview.appspot.com/6935068/diff/1/juju/agents/api.py
File juju/agents/api.py (right):

https://codereview.appspot.com/6935068/diff/1/juju/agents/api.py#newcode102
juju/agents/api.py:102: break
On 2012/12/17 18:36:59, benjamin.saller wrote:
> Its not possible for someone to register another 'admin' like name
here or will
> the first added always appear first? This seems an odd way of tracking
this.
> Since this codebase only supports admin anyway wouldn't this be
acls[0] anyway
> or are there others?

at the moment the only time this node is created is if it doesn't exist,
at the client side. there is no other client that will modify it once
its in place. the initialized node is the marker node for the rest of
the system to go forward once the environment details have been loaded.

ie. while its true that multiple 'admin' users could potentially be
created with different passwords, this node is WORM and thus suitable
for this use.

https://codereview.appspot.com/6935068/diff/1/juju/agents/api.py#newcode105
juju/agents/api.py:105: "/login", acls=[make_ace(admin_acl['id'],
all=True)])
On 2012/12/17 18:36:59, benjamin.saller wrote:
> I don't recall the details of the security branch, but this copies it
from
> /initialized to /login basically?

This copies the admin identity (which is a hash of the secret of the
user id) with a more restrictive acl grant to a newly created login
node. Effectively to read this node you must have authenticated with the
admin credentials.

This code also exists in initialized, but our current usage/deployment
mode is via charm so the initialize code from this branch will never be
called, hence this lazy init technique for the api agent startup.

> I only have vague guesses as to why this is
> the process, you need to create it during init to set up the agents
and then add
> it to the login tree which will in the future support additional
logins?

hopefully the previous comments make it clear.

https://codereview.appspot.com/6935068/diff/1/juju/rapi/context.py
File juju/rapi/context.py (right):

https://codereview.appspot.com/6935068/diff/1/juju/rapi/context.py#newcode222
juju/rapi/context.py:222: yield self.client.get("/login")
On 2012/12/17 18:36:59, benjamin.saller wrote:
> This does the ACL check on the login node and and uses that as the
success
> boolean. Are the other nodes protected with the same ACL? Its not
clear where
> that's being managed here.

access to the node is only possible if the username and password are
correct, ie. match the admin identity used for the node acl.

https://codereview.appspot.com/6935068/diff/1/juju/rapi/tests/test_context.py
File juju/rapi/tests/test_context.py (right):

https://codereview.appspot.com/6935068/diff/1/juju/rapi/tests/test_context.py#newcode177
juju/rapi/tests/test_context.py:177:
On 2012/12/17 18:36:59, benjamin.saller wrote:
> Again it looks like the ACL check works here, but I'm not sure if the
way this
> is wired in provides any actual access control outside of that node.
Is that non-goal with this iteration?

this isn't about access control at the node tree level, that's the
security branch work which is *much* larger ...

Read more...

Revision history for this message
Kapil Thangavelu (hazmat) wrote :
Revision history for this message
Kapil Thangavelu (hazmat) wrote :
Revision history for this message
Benjamin Saller (bcsaller) wrote :

LGTM

I didn't see a test around the login call returning the added
unauthorized error though.

https://codereview.appspot.com/6935068/diff/12001/juju/rapi/context.py
File juju/rapi/context.py (right):

https://codereview.appspot.com/6935068/diff/12001/juju/rapi/context.py#newcode85
juju/rapi/context.py:85: if not self.authenticated and not func.__name__
== "_login":
func.__name__ has a bad smell to it but fair enough

https://codereview.appspot.com/6935068/diff/12001/juju/rapi/transport/ws.py
File juju/rapi/transport/ws.py (right):

https://codereview.appspot.com/6935068/diff/12001/juju/rapi/transport/ws.py#newcode68
juju/rapi/transport/ws.py:68:
Is there an use case for a logout/inverse to this stopping the delta? I
suspect not at this time.

https://codereview.appspot.com/6935068/

Revision history for this message
Kapil Thangavelu (hazmat) wrote :

thanks for the review

https://codereview.appspot.com/6935068/diff/12001/juju/rapi/context.py
File juju/rapi/context.py (right):

https://codereview.appspot.com/6935068/diff/12001/juju/rapi/context.py#newcode85
juju/rapi/context.py:85: if not self.authenticated and not func.__name__
== "_login":
On 2013/01/18 14:04:23, bcsaller wrote:
> func.__name__ has a bad smell to it but fair enough

its already playing with func.. not many other options outside of
decorating every other function with another attribute for perm, which
still amounts to the same, ie func inspection.

https://codereview.appspot.com/6935068/diff/12001/juju/rapi/transport/ws.py
File juju/rapi/transport/ws.py (right):

https://codereview.appspot.com/6935068/diff/12001/juju/rapi/transport/ws.py#newcode68
juju/rapi/transport/ws.py:68:
On 2013/01/18 14:04:23, bcsaller wrote:
> Is there an use case for a logout/inverse to this stopping the delta?
I suspect
> not at this time.

logout not possible with the underlying zk auth mechanism, wrt to use
not at the moment outside of disconnect.

ideally stream sub/unsub would be explicit api methods, but doing so
without gui support first would break the gui.

https://codereview.appspot.com/6935068/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
The diff is not available at this time. You can reload the page or download it.

Subscribers

People subscribed via source and target branches

to all changes: