Re: Using credentials with ZEO 5 -- possible bug in ZEOStorage

Jim Fulton <[email protected]>
Newsgroups gmane.comp.web.zope.zodb
Message-ID <CAPDm-FgGj+h2V9J+f9U6hq=ubGWFVvY8Vh4VguxbmB3G4eNsdQ@mail.gmail.com>
On Tue, Mar 28, 2017 at 1:06 PM, Bill Janssen <[email protected]>
wrote:

> I've been tracing calls through ZEO 5 again.  My setup is that I'm running
> a big ZEO server, which services multiple users, each of which may have
> access to multiple storages.
>

That's interesting.  For a long time I've viewed serving multiple storages
to be an unnecessary complication, and possibly an attractive nuisance,
given the GIL.  But I've found a few people, including yourself making use
of the feature.



> When a user creates a ClientStorage, they specify which storage they want
> to access, presumably via the "storage" parameter to
> ClientStorage.__init__()
>

Yup.


> , and pass some credentials which are used to authenticate their identity
> (which in turn is used to authorize their access to the specified
> storage).  I see that the credentials passed to ClientStorage are then
> passed through to the server as part of the "register" call:
>
>         credentials = (self.credentials,) if self.credentials else ()
>
>         try:
>             try:
>                 server_tid = yield self.fut(
>                     'register', self.storage_key,
>                     self.read_only if self.read_only is not Fallback else
> False,
>                     *credentials)
>             except ZODB.POSException.ReadOnlyError:
>                 if self.read_only is Fallback:
>                     self.read_only = True
>                     server_tid = yield self.fut(
>                         'register', self.storage_key, True, *credentials)
>                 else:
>                     raise
>             else:
>                 if self.read_only is Fallback:
>                     self.read_only = False
>         except Exception as exc:
>             self.client.register_failed(self, exc)
>         else:
>             self.client.registered(self, server_tid)
>
> On the server side, the "register" method in ZEOStorage looks like this:
>
>     def register(self, storage_id, read_only):
>         """Select the storage that this client will use
>
>         This method must be the first one called by the client.
>         For authenticated storages this method will be called by the client
>         immediately after authentication is finished.
>         """
>
> If credentials are passed, won't this error out because of too many
> parameters?
>

Yup. The credentials addition to the protocol is a hook for
*experimentation*.  Note for example that it isn't mentioned in the docs:
https://github.com/zopefoundation/ZEO#python-api-for-creating-a-zeo-client-storage

I added it when adding the feature *experimentally* for ZeroDB.

I emphasize the experimental nature of this not to make you go away, but to
set your expectations. :)


> So presumably I need to write a subtype of ZEOStorage with a version of
> "register" which will accept the credentials and validate them -- a
> before-method.
>

I don't understand what you mean by a "before-method".



>   But then I need to arrange for that subtype to be the class that's
> instantiated.  To do that, I need to subclass StorageServer and override
> create_client_handle.
>

Yup.



>   Or, subclass Acceptor (from asyncio/server.py), and override the
> "factory()" method -- but then I'd have to arrange for my subclass to be
> used, and I don't see a clean way of doing that except to replace
> "create_server" in runzeo.py.  Which I'd have to do anyway if I subclass
> StorageServer.
>

Yes.


> Some questions:
>
> 1.  StorageServer takes a dict of storages, which are FileStorage
> instances.
>

No, they're ZODB.interfaces.IStorage instances. FileStorage is the most
common implementation though.

  How many is too many in this case?  What if I have thousands of them?
>

I have no idea.  I never use more than one.  You can try and let us know.
 :) Some folks in the Plone community have an extension that adds storages
dynamically. Perhaps they can shed light.

I'm not sure what your use cases are, but for ZeroDB, we went a different
route, creating virtual storages within a single physical storage.  This
feels cleaner to me.  I've pointed you at that code before.  That approach
too is experimental and has some issues.


>
> 2.  Is it OK for my storage names to be UUIDs?  Or is there some
> dependency on the small integer naming that I haven't seen?
>

Nope. The storage names are strings.


>
> 3.  My "register" method will have to call out to another service to get
> authorization for access to the named storage.  Presumably I can just do
> this synchronously?
>

Yes, but you may be better off implementing this asynchronously.

The default ZEO 5 implementation shares a single thread for all clients.
(ZEO 4 used a separate thread per client and ZEO 5 has an option, for
that.)  ZEO has a mechanism for delayed responses, so making register
asynchronous should be pretty straightforward.

Jim

-- 
Jim Fulton
http://jimfulton.info

-- 
You received this message because you are subscribed to the Google Groups "zodb" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
For more options, visit https://groups.google.com/d/optout.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.