9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
From: ori@eigenstate.org
To: 9fans@9fans.net, 9front@9front.org
Subject: Re: [9fans] OAuth2 in factotum
Date: Sun, 22 Aug 2021 16:16:58 -0400	[thread overview]
Message-ID: <FEF7A1A8AA43660462E5C685BBCF3230@eigenstate.org> (raw)
In-Reply-To: <CALo7eEuXOfgr=2nj7A-rKNDejHdyBHWg98eJhvmLTneNaM5=Gw@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3933 bytes --]

Quoth Demetrius Iatrakis <demetrius.iatrakis@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=ori@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/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!

[-- Attachment #2: Type: text/plain, Size: 2726 bytes --]

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)
@@ -1165,6 +1202,7 @@
        imap->host = f[2];
        if(strstr(imap->host, "gmail.com"))
                imap->flags |= Fgmail;
+       imap->flags |= Fdebug;
        imap->refreshtime = 60;
        if(nf < 4)
                imap->user = nil;
------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/T6899bf3f0654295d-M539f47f30599e6cfecb3adb9
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

  parent reply	other threads:[~2021-08-22 20:17 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-16 11:15 Demetrius Iatrakis
2021-08-17  3:48 ` Lucio De Re
2021-08-17  7:47   ` Keith Gibbs
2021-08-18  3:55     ` Lucio De Re
2021-08-18  7:02       ` [9fans] Software philosophy Skip Tavakkolian
2021-08-18  7:19         ` hiro
2021-08-18 10:15           ` Lucio De Re
2021-08-18  9:46         ` Keith Gibbs
2021-08-18 10:13         ` vic.thacker
2021-08-18 11:34           ` Keith Gibbs
2021-08-18 11:47             ` Lucio De Re
2021-08-18 23:44             ` hiro
2021-08-19  4:34               ` Lucio De Re
2021-08-19 10:44                 ` Keith Gibbs
2021-08-19 18:53                 ` Git & Conventional Browsers (Was Re: [9fans] Software philosophy) unobe
2021-08-19 19:00                   ` ori
2021-08-18 11:34           ` [9fans] Software philosophy Lucio De Re
2021-08-18 11:28         ` Lucio De Re
2021-08-18 12:02           ` Keith Gibbs
2021-08-18 19:33             ` leimy2k via 9fans
2021-08-18 20:09               ` David du Colombier
2021-08-18 22:00                 ` Eli Cohen
2021-08-19  7:08                   ` Keith Gibbs
2021-08-19  7:59                     ` sirjofri
2021-08-19  9:27                       ` Lucio De Re
2021-08-19  9:45                         ` hiro
2021-08-19  9:51                         ` hiro
2021-08-19 10:10                           ` sirjofri
2021-08-19 10:38                         ` Keith Gibbs
2021-08-19 11:45                           ` hiro
2021-08-19 12:43                             ` Eli Cohen
2021-08-19 19:58                               ` Aram Hăvărneanu
2021-08-19 10:56                         ` kvik
2021-08-19 11:33                           ` sirjofri
2021-08-19 20:44                           ` ori
2021-08-19  9:29                       ` hiro
2021-08-19  9:44                         ` sirjofri
2021-08-19  9:19                     ` hiro
2021-08-22  2:46                   ` kokamoto
2021-08-22  3:16                     ` Eli Cohen
2021-08-22  7:07                       ` [9fans] Drawterm GPU (was: Software philosophy) sirjofri
2021-08-22 10:04                         ` Frank D. Engel, Jr.
2021-08-22 11:49                           ` sirjofri
2021-08-22 12:24                             ` Chris McGee
2021-08-18  9:18       ` [9fans] OAuth2 in factotum Keith Gibbs
2021-08-18 12:10         ` Ethan Gardener
2021-08-18 15:23         ` Stuart Morrow
2021-08-18 16:58           ` Stuart Morrow
2021-08-18 17:06             ` Sigrid Solveig Haflínudóttir
2021-08-17 15:25   ` ori
2021-08-18  3:59     ` Lucio De Re
2021-08-18  4:20       ` ori
2021-08-18  4:42         ` Eli Cohen
2021-08-18  5:06         ` Lucio De Re
2021-08-17  4:13 ` ori
2021-08-17  5:43   ` Lucio De Re
2021-08-19  3:52 ` Kurt H Maier
2021-08-19  5:38 ` ori
2021-08-22 20:16 ` ori [this message]
2021-08-22 20:32   ` Demetrius Iatrakis
2021-08-22 20:38     ` ori
2021-08-22 20:36   ` ori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=FEF7A1A8AA43660462E5C685BBCF3230@eigenstate.org \
    --to=ori@eigenstate.org \
    --cc=9fans@9fans.net \
    --cc=9front@9front.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).