Quoth o...@eigenstate.org:
> Quoth Demetrius Iatrakis <demetrius.iatra...@gmail.com>:
> > This is a preview of OAuth2 support in factotum, as part of this year's 
> > GSoC:
> > https://github.com/Mitsos101/plan9front/pull/1
> > 
> > Installation, on 9front:
> > 
> > git/clone https://github.com/Mitsos101/plan9front plan9front-oauth
> > cd plan9front-oauth
> > git/branch oauth
> > bind sys/include /sys/include
> > @{cd sys/src/libauth && mk install}
> > @{cd sys/src/cmd/auth && mk install}
> > @{cd sys/src/cmd/webfs && mk install}
> > 
> > This will replace your factotum.
> > 
> > Usage:
> > 
> > You need to obtain OAuth credentials from your issuer first. See, for
> > example, Google's guide:
> > https://developers.google.com/identity/protocols/oauth2.
> > 
> > % echo 'key proto=oauth issuer=https://accounts.google.com scope=email
> > client_id=1234 !client_secret=5678' > /mnt/factotum/ctl
> > % auth/oauth 'client_id=1234'
> > go to https://google.com/device
> > your code is ABCD-EFGH
> > <after user consent is provided, the access token is printed>
> > 
> > auth_oauth is also available in libauth. Webfs uses it to implement
> > the preoauth command.
> > 
> > Bugs:
> > 
> > This code is specific to 9front, as libjson is required and Plan 9's
> > webfs doesn't support preoauth.
> > 
> > factotum uses the needkey RPC to display the verification URL and code
> > to the user. This means that, for now, the needkey file must not be
> > open so that fgui doesn't intercept it.
> > 
> > The module imports lots of code to support HTTP/1.0 so that the
> > refresh token doesn't leave factotum's address space.
> > 
> > Only the device and refresh flows are supported. There is an
> > implementation of the authorization code flow (tested on macOS) here:
> > https://github.com/Mitsos101/plan9port/pull/1. However, it is not
> > included in the module as there is no good browser to plumb the URL
> > to.
> > 
> > Refresh tokens are not saved to persistent storage when factotum
> > exits. The user must provide consent every time factotum is restarted.
> > 
> 
> And, now that we have something working, I wrote
> some code to use it. I wrote a patch to add oauth
> support to upas/fs -- see attached:
> 
> To use the patch, I followed this kind of clunky
> process:
> 
>       https://developers.google.com/identity/protocols/oauth2
> 
> I went to the 'credentials' section on the sidebar
> and I created a key for a 'desktop application'; Then
> I went to the 'oauth consent screen' and added my work
> email account as a 'test user'.
> 
> I grabbed the keys, and on my unix box, went to
> the patched oauth:
> 
>       % cd $HOME/src/plan9port/src/cmd/oauth
> 
> and generated a key using the full, browser based
> auth flow:
> 
>       % python httpd.py
>       % ./oauth https://accounts.google.com https://mail.google.com/ 
> $clientkey $clientsecret
>       key proto=oauth issuer=https://accounts.google.com client_id=72...
> 
> then edited the resulting output to include the appropriate
> attributes, adding the attributes in >>...<< for upas/fs:
> 
>       key proto=oauth
>               >>service=imap server=imap.gmail.com user=o...@pingthings.io<<
>               issuer=https://accounts.google.com client_id=<id> 
>               token_type=Bearer exptime=1629662303 scope=...
> 
> and then added that to factotum:
> 
>       echo key=... >/mnt/factotum/ctl
> 
> With that, upas/fs just worked with my work email:
> 
>       upas/fs -f /imaps/imap.gmail.com/o...@pingthings.io
> 
> 
> Bugs: there are way too many steps. Unfortunately, the most
> annoying one is generating and adding an oauth client key/secret,
> and short of shipping a pregenerated one (is that a good idea?),
> I don't think there's a solution.
> 
> Beyond that, 2 small bits of polish which I think we
> can do:
> 
>       - Adding a '-t' flag to oauth (the way auth/rsa does)
>         to add type information to auth/oauth login would
>         make it more convenient to use: the output could
>         be stored directly rather than needing editing.
>       - Adding a script that allows spawning a browser and
>         http listener on unix (or redirecting thigns through
>         to plan 9) would make it easier to drive the auth
>         process from plan 9.
> 
> Thanks for doing this work, Demetrius!

Oops, realized that I'd left this line in the patch:

+       imap->flags |= Fdebug;

you'll really want to delete that, or you end up with
a *TON* of debug spew.

Updated patch attached.
diff bcfee7b54757eb64cade34e476cf0dba672832f6 uncommitted
--- a/sys/src/cmd/upas/fs/imap.c
+++ b/sys/src/cmd/upas/fs/imap.c
@@ -24,6 +24,7 @@
        Cnolog  = 1<<0,
        Ccram   = 1<<1,
        Cntlm   = 1<<2,
+       Coauth  = 1<<3,
 
        /* flags */
        Fssl    = 1<<0,
@@ -151,7 +152,7 @@
 static void
 imap4cmd(Imap *imap, char *fmt, ...)
 {
-       char buf[256], *p;
+       char buf[1024], *p;
        va_list va;
 
        va_start(va, fmt);
@@ -430,6 +431,8 @@
                                imap->cap |= Ccram;
                        if(strcmp(p, "ntlm") == 0)
                                imap->cap |= Cntlm;
+                       if(strcmp(p, "xoauth2") == 0)
+                               imap->cap |= Coauth;
                }else if(strcmp(t[i], "logindisabled") == 0)
                        imap->cap |= Cnolog;
        }
@@ -733,6 +736,38 @@
 }
 
 static char*
+imap4oauth(Imap *imap)
+{
+       char *s, *auth, *enc;
+       int n;
+       OAuth *oa;
+
+       if(imap->user == nil)
+               return "user required for oauth";
+       oa = auth_getoauth(auth_getkey, "proto=oauth service=imap server=%q 
user=%q", imap->host, imap->user);
+       if(oa == nil)
+               return "cannot find IMAP oauth token";
+
+       imap->tag = 1;
+       if((auth = smprint("user=%s\x01auth=Bearer %s\x01\x01", imap->user, 
oa->access_token)) == nil)
+               sysfatal("smprint: %r");
+       if((enc = smprint("%[", auth) == nil)
+               sysfatal("smprint: %r");
+       imap4cmd(imap, "authenticate xoauth2 %s", enc);
+       free(auth);
+       free(enc);
+       free(oa);
+       s = imap4resp(imap);
+       if(isokay(s))
+               return nil;
+       imap4cmd(imap, "");
+       s = imap4resp(imap);
+       if(isokay(s))
+               return nil;
+       return s;
+}
+
+static char*
 imap4passwd(Imap *imap)
 {
        char *s;
@@ -762,6 +797,8 @@
                e = imap4cram(imap);
        else if(imap->cap & Cntlm)
                e = imap4ntlm(imap);
+       else if(imap->cap & Coauth)
+               e = imap4oauth(imap);
        else
                e = imap4passwd(imap);
        if(e)
------------------------------------------
9fans: 9fans
Permalink: 
https://9fans.topicbox.com/groups/9fans/T6899bf3f0654295d-Mbcaea13458be56f2909ea6c3
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

Reply via email to