[Freeipa-devel] OTP Sync Client Design

Nathaniel McCallum npmccallum at redhat.com
Fri May 23 21:19:50 UTC 2014


On Wed, 2014-05-14 at 14:08 -0400, Nathaniel McCallum wrote:
> Occasionally OTP tokens get out of sync with the server. When this
> happens, the user or an admin need to synchronize the token. To this
> end, we landed server-side synchronization support, which is a simple
> bind with a custom control. This all works with my sample test script.
> 
> Client support is proving a bit more difficult. In the ideal world, the
> client would contact LDAP directly and perform the operation. This would
> make a man in the middle attack difficult and we can ensure encryption
> over the entire operation.
> 
> However, browsers, without server-side assistance, cannot perform this
> operation from javascript. This means that, in this case, the first
> factor and two second factors must be transmitted to the FreeIPA server
> and then proxied to 389. Is this an acceptable compromise?
> 
> This command also needs to be accessible *without* an existing user
> login since, if a user's token is out of sync, the user can't login. Is
> it possible to expose such an API? If so, how? Both "ipa env" and "ipa
> ping" seem to require kinit, so I don't see any obvious examples.

Thanks everyone for your feedback. This particular feature is proving
difficult to implement, even with our agreed upon design. To reiterate
this design: there will be an HTTP method by which to synchronize
tokens.

There are two assumptions in the code which are making this difficult:
1. All cli commands are Command subclasses.
2. All Command subclasses create authenticated server methods.

There are thus two ways to tackle this problem.

First, I can create a standard POST method in rpcserver.py. This is not
very modular. But the biggest problem is that there is no way to create
the cli-side command to call it (assumption #1).

Second, I can create a Command subclass, similar to the passwd plugin.
This will create both the client- and server-side components. However,
there is no way to disable the server-side authentication.

I think that solving the second of these problems is the most reusable.
Just as an example, the ping command currently requires authentication
but does not need to do so. The passwd Command too shouldn't need to
authenticate before executing the command because the command
authenticates itself.

I think it very likely that we are going to have need for other Command
subclasses in the future which do not require authentication.

However, implementing this approach is rather difficult as it will
require a refactoring of rpcserver.py. The code in rpcserver.py contains
many layering violations and the class structure is rather unclear
(look, for instance, at the different orders in which xmlrpc and jsonrpc
classes inherit from their parent classes).

The current problem forcing this refactoring is that authentication
appears to happen across several different layers, but always before the
command to be executed is unmarshalled. We need to invert this order:
the command needs to be unmarshalled first in order to determine whether
or not authentication is necessary. I don't think that switching this
order is practical without constraining authentication to a single layer
(or two: session and krb5) late in the request process.

Git tells me that lots of people have touched this code, so I'm hoping
for good feedback! ;)

Alternatively, we could create a way to inject cli commands without
having Command subclasses. Isolating these concerns is itself probably a
good design choice. Ideally we'd have a structure where the Command
class itself inherits from a CLICommand class and a ServerMethod class.
But this too will be a massive refactoring, perhaps even bigger than the
rpcserver.py refactoring.

So, which assumption should we break: #1 or #2? And who wants to help me
do it? Also, I am all ears for easier solutions for this feature.

Nathaniel




More information about the Freeipa-devel mailing list