From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 5812 invoked from network); 22 Aug 2021 20:46:47 -0000 Received: from 1ess.inri.net (216.126.196.35) by inbox.vuxu.org with ESMTPUTF8; 22 Aug 2021 20:46:47 -0000 Received: from mimir.eigenstate.org ([206.124.132.107]) by 1ess; Sun Aug 22 16:43:07 -0400 2021 Received: from abbatoir.myfiosgateway.com (pool-74-108-56-225.nycmny.fios.verizon.net [74.108.56.225]) by mimir.eigenstate.org (OpenSMTPD) with ESMTPSA id 2782455b (TLSv1.2:ECDHE-RSA-AES256-SHA:256:NO); Sun, 22 Aug 2021 13:36:18 -0700 (PDT) Message-ID: <7BD08FA33BDEF31677ABBA911CD6A3FE@eigenstate.org> To: 9fans@9fans.net, 9front@9front.org Date: Sun, 22 Aug 2021 16:36:17 -0400 From: ori@eigenstate.org In-Reply-To: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="upas-ifmpfcjiockyosceugiyqlgyjc" List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: virtualized hosting property controller Subject: [9front] Re: [9fans] OAuth2 in factotum Reply-To: 9front@9front.org Precedence: bulk This is a multi-part message in MIME format. --upas-ifmpfcjiockyosceugiyqlgyjc Content-Disposition: inline Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit Quoth ori@eigenstate.org: > Quoth Demetrius Iatrakis : > > 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 > > > > > > 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=ori@pingthings.io<< > issuer=https://accounts.google.com client_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/ori@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. --upas-ifmpfcjiockyosceugiyqlgyjc Content-Disposition: inline Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit 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) --upas-ifmpfcjiockyosceugiyqlgyjc--