[libvirt] Authentication with virConnectAuthPtr

Eduardo Otubo otubo at linux.vnet.ibm.com
Thu May 7 05:30:54 UTC 2009


This sample of code helped me a lot!

Here is the phypOpen function I rewrited based on your code:
http://pastebin.com/f65912242 - I did a lot of tests with my HMC here
and everything seemed to be working fine. The prompt for the password
and the use of the public key.

I also did use the virRaiseError() to adjust all the error messages into
libvirt pattern. the modified function I made based on your sample code.

Thanks for the help.
[]'s

Em Ter, 2009-05-05 às 21:50 +0100, Daniel P. Berrange escreveu:
> On Tue, May 05, 2009 at 04:06:12PM -0300, Eduardo Otubo wrote:
> > Hello all,
> > 
> > I'll start using virConnectAuthPtr to handle the authentication proccess
> > at the phyp driver I'm wrinting
> > <https://www.redhat.com/archives/libvir-list/2009-April/msg00493.html>
> > and I have some doubts in my mind:
> > 
> > 1) What are the types of authentication that 'int *credtype' can hold?
> > And who fills it with the information I'll need?
> 
> These are all defined in libvirt.h - we basically copied the SASL
> credential types
> 
>     VIR_CRED_USERNAME = 1,     /* Identity to act as */
>     VIR_CRED_AUTHNAME = 2,     /* Identify to authorize as */
>     VIR_CRED_LANGUAGE = 3,     /* RFC 1766 languages, comma separated */
>     VIR_CRED_CNONCE = 4,       /* client supplies a nonce */
>     VIR_CRED_PASSPHRASE = 5,   /* Passphrase secret */
>     VIR_CRED_ECHOPROMPT = 6,   /* Challenge response */
>     VIR_CRED_NOECHOPROMPT = 7, /* Challenge response */
>     VIR_CRED_REALM = 8,        /* Authentication realm */
>     VIR_CRED_EXTERNAL = 9,     /* Externally managed credential */
> 
> The client application filles in the data in virConnectAuth struct,
> providing the function callback pointer, an opaque data blob (cddata)
> and the list of credential types it knows how to handle.
> 
> > 2) Once known the credential type, I need to use the function pointer
> > 'virConnectAuthCallbackPtr cb' to get the information whatever it is,
> > right? I mean, it can be a password, a pubkey or anything else, right?
> > Is there a callback able to handle password or pubkeys?
> 
> Yep, once your driver knows what credentials it needs to collect, it
> should check to see if the client has declared it supports the required
> credentials. If it does, then the driver should populate  an array of
> virConnectCredential objects detailing what credentials needs to be
> collected. The callback is then invoked, and the client app will collect
> the credentials, putting the results in the 'result' / resultlen fields.
> 
> When the callback returns, the driver can get the credentials fro mthe
> result/resultlen field - though it should check the callback return
> status to see if the client app had any errors.
> 
> > 3) And finally I'll be able to use the 'void *cbdata' to manage the
> > authentication in my way. In my case, using libssh. In fact, in the end
> > of the process, I'll just need a password or a key to get things
> > working.
> 
> The 'cbdata' field is something used by the client app. Both a password
> or private key passphrase would map to VIR_CRED_PASSPHRASE credential
> type. You'd just have a different prompt / challenge 
> 
> > There is no driver authenticatin agaist ssh channel, that's why I got so
> > confused with this topic.
> > 
> > I don't know if my thoughts are pretty clear here. But I would like to
> > confirm the information 2 and 3, and check how 1 works. Could anyone
> > help me?
> 
> Let me give you a close-to-working example that tries to illustrate 
> the general idea from the driver point of view.
> 
> First off, libvirt.so provides a generic callback that works for command
> line based apps, and knows how to collect credentials of type
> 
>   static int virConnectCredTypeDefault[] = {
>     VIR_CRED_AUTHNAME,
>     VIR_CRED_ECHOPROMPT,
>     VIR_CRED_REALM,
>     VIR_CRED_PASSPHRASE,
>     VIR_CRED_NOECHOPROMPT,
>     VIR_CRED_EXTERNAL,
>   };
> 
>   static virConnectAuth virConnectAuthDefault = {
>     virConnectCredTypeDefault,
>     sizeof(virConnectCredTypeDefault)/sizeof(int),
>     virConnectAuthCallbackDefault,
>     NULL,
>   };
> 
> 
> This is what virsh uses when connecting to libvirt
> 
>     ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault, 0)
> 
> 
> 
> Now, in your Phyp  driver, lets assume at some point in time libssh tells
> it wants a username+password. 
> 
> These will map to VIR_CRED_AUTHNAME and VIR_CRED_PASSPHRASE, so first
> step is to ensure the callback passed in by the client app supports
> these
> 
>   static virDrvOpenStatus phypOpen(virConnectPtr conn,
>                                    virConnectAuthPtr auth,
>                                    int flags) {
> 
>    .... start ssh conection ...
> 
>    if (need password) {
>      int i;
>      int hasPassphrase = 0
>      int hasAuthname = 0;
>      /* The creds we're about to ask the application for... */
>      virConnectCredentials creds[] = {
>         { VIR_CRED_AUTHNAME, "Enter username:", "Username", NULL, NULL, 0 },
>         { VIR_CRED_PASSPHRASE, "Enter password:", "Password", NULL, NULL, 0 },
>      };
> 
>      /* If no auth callback info was provided, must fail now */
>      if (!auth || !auth->cb) {
>        virPhypRaiseError(conn, VIR_ERR_AUTH_FAILED, "%s",
>                          _("no authentication callback provided"));
>        return VIR_OPEN_FAILED;
>      }
> 
>      /* Check if desired credentials are supported */
>      for  (i = 0 ; i < auth.ncredtype ; i++) {
>        if (auth.credtype[i] == VIR_CRED_AUTHNAME)
>             hasAuthName = 1;
>        if (auth.credtype[i] == VIR_CRED_PASSPHRASE)
>             hasPassphrase = 1;
>      }
>      if (!hasPassphrase || !hasAuthname) {
>          virPhypRaiseError(conn, VIR_ERR_AUTH_FAILED, "%s",
>                            _("required credentials are not supported"));
>          return VIR_OPEN_FAILED;
>      }
> 
> 
>      /* Credential supported, to try to get them from user */
>      int res = (auth->cb)(creds, ARRAY_CARDINALITY(creds), auth->cbdata);
> 
>      if (res < 0) {
>          virPhypRaiseError(conn, VIR_ERR_AUTH_FAILED, "%s",
>                            _("unable to fetch credentials"));
>          return VIR_OPEN_FAILED;
>      }
> 
>      char *username = creds[0]->result;
>      char *password = creds[1]->result;
>        .... give these back to libssh now ....
>     }
> 
> 
> This example code is quite inflexible & hardcoded to the specifics of
> getting a username + password. Depending on libssh's API you may want
> or need todo things slightly differently.  For example, you probably
> won't need to actually prompt for username, since I imagine you're
> getting that from the connection URI directly. 
> 
> You may have to try several credentials in turn, requiring multiple
> invocations of the callback. For example, first time you may prompt
> for a passphrase for a SSH private key. If private key auth fails,
> you may then continue onto password based auth, and need to prompt
> for login password. So in that cae you'd be invoking the callback
> twice asking for different types of data each time.
> 
> Also, don't assume that the 'result' field is NULL terminated, or
> that 'result' is even non-NULL - sanity check  this data you get
> back from the client app before using it. 
> 
> Regards,
> Daniel
-- 
Eduardo Otubo
Software Engineer
Linux Technology Center
IBM Systems & Technology Group
Mobile: +55 19 8135 0885 
otubo at linux.vnet.ibm.com




More information about the libvir-list mailing list