OAuth-авторизація в Mozilla Thunderbird: від зародження до релізу



Якийсь час назад ми розповідали про те, як Mail.Ru реалізований збір пошти з використанням протоколу OAuth 2.0. Ми продовжуємо підвищувати безпеку пошти і просувати стандарт OAuth 2.0 в маси. І сьогодні розповімо про те, як ми додали OAuth-авторизацію в поштовий клієнт Mozilla Thunderbird. На цьому прикладі ми розберемо процес внесення нової фічі в продукт з відкритим вихідним кодом, від створення тікета до релізу. Якщо ви давно хотіли зробити свій перший pull request, але не знали як, — читайте нашу історію.

1. Загальна схема роботи
На дії користувача Thunderbird відкриває веб-в'ю з адресою для OAuth-авторизації. Якщо користувач успішно пройшов процедуру авторизації і погодився надати додатком доступ до своїх даних, то ми перенаправляємо користувача на адресу, зазначений у параметрі
redirect_uri
. Так додаток отримає авторизаційний токен і зможе використовувати його для роботи з нашої поштовою службою. Адреса для запиту сертифіката:
https://o2.test.mail.ru/login
?response_type=code
&client_id=<ідентифікатор програми>
&redirect_uri=http%3A%2F%2Flocalhost

Варто зауважити, що значення
localhost
,
redirect_uri
додаток задає самостійно, а параметр state (використовується клієнтом для підтримки зв'язку між запитом і колбэком) не передає зовсім. Нижче представлена схема взаємодії програми з сервісом:


2. Як влаштований процес інтеграції, основні етапи
Хоча сам процес інтеграції досить простий і не займає багато часу, все ж варто розповісти про окремі моменти, які варто планувати заздалегідь.
Оскільки Thunderbird — це продукт компанії Mozilla, ми одразу вирушили на MDN. Ми Так швидко отримали загальне уявлення про основних етапах інтеграції:
  1. Тікет на додавання поштового клієнта.
  2. Тікет на додавання конфігурації в ISP-бази.
  3. Патч в репозиторій comm-central.
  4. Патч в ISP-бази.
  5. Тестова зборка.
  6. Збереження зворотної сумісності.
  7. Тестування функціональності в попередніх релізах.
  8. Тестування релізу.
Далі розглянемо кожен етап окремо.
2.1. Тікет на додавання поштового клієнта
Перед тим як ставити тікет, переконайтеся, що до вас цього ніхто не зробив. Постановка тікета є ключовим етапом у вирішенні будь схожою завдання, тому дуже важливо правильно заповнити всі обов'язкові поля:
  • Продукт: Структура репозиторію
    comm-central
    розділена на незалежні продукти. З цим у нас проблем не виникло, оскільки назва продукту
    MailNews
    відразу згадується на домашня сторінка.
  • Компонент: Напроти цього пункту є підказка, однак тут і так інтуїтивно зрозуміло, що робота пов'язана з мережею, тому вибираємо Networking.
  • Версія: Щоб зрозуміти, яку версію релізу вибрати, слід звернутися до сторінки списком релізів. Однак цієї інформації буде явно недостатньо, оскільки нам важливо розуміти, на якому етапі знаходиться ще не вийшов реліз. З цим нам допоможе календар релізів. Більш детальну інформацію про реліз-циклі можна отримати на відповідній сторінки. Але якщо ви все-таки сумніваєтеся, яку версію релізу, то не соромтеся задати своє питання в списку розсилки або IRC-каналі. При крайньої необхідності вам допоможуть ревьюверы тікета.
  • Платформа: У нашому випадку продукт платформонезависимый (
    all
    ).
  • Важливість: Оскільки ми розширюємо функціональність, тип
    enhancement
    .
  • Ключові слова: Список ключових слів обмежений. Побіжний пошук за схожим тикетам підказав вибрати
    feature
    ,
    user-doc-needed
    .
Порада: щоб випадково не пропустити якийсь етап, додайте до себе календарь.
2.2. Тікет на додавання конфігурації в ISP-бази
Нам попався хороший ревьювер, який допоміг із заповненням більшості полів і релізом. Дивіться приклад нашого тікета.
2.3. Патч в репозиторій
comm-central

Якщо ви звернули увагу, співтовариство Mozilla дуже трепетно ставиться до документування своїх продуктів. Керівництво по сборке продукту, стилистике написання програмного коду та ін. Всі посилання на це розташовуються в одному місці і не вимагають, як це часто буває з іншими продуктами, проходження якогось квесту. Відразу скажу, що ніякого "rocket science" у додаванні нового OAuth-провайдера в Thunderbird немає, — це стає зрозуміло після грепа репозиторія і побіжного ознайомлення з вихідним кодом. Незважаючи на те що файлів з ключовим словом OAuth було досить багато:
➜ clone hg http://hg.mozilla.org/comm-central
...
➜ hg grep --ignore-case --files-with-matches oauth | wc -l
91

Інтуїція підказувала, що все має бути простіше. І ми не помилилися, коли відкрили перший із списку файл:
mailnews/base/util/OAuth2Providers.jsm 

Не буду томити, просто дивіться діфф:
➜ hg log -p -l 1

changeset: [draft] 18512:a2f404184ac0 support_oauth_mail_ru_1231642 tip
author: Alexander Abashkin <monolithed@gmail.com>
date: Mon, 14 Dec 2015 15:17:09 +0300 (4 months ago)
summary: Bug 1231642 - Log in to Mail.Ru (IMAP/SMTP) using OAuth

M mailnews/base/util/OAuth2Providers.jsm

diff --git a/mailnews/base/util/OAuth2Providers.jsm b/mailnews/base/util/OAuth2Providers.jsm
--- a/mailnews/base/util/OAuth2Providers.jsm
+++ b/mailnews/base/util/OAuth2Providers.jsm
@@ -10,32 +10,41 @@ var EXPORTED_SYMBOLS = ["OAuth2Providers
var {classes: Cc, interfaces: Ci results: Cr, utils: Cu} = Components;

// map of hostnames to [issuer, scope]
var kHostnames = new Map([
["imap.googlemail.com", ["accounts.google.com", "https://mail.google.com/"]],
["smtp.googlemail.com", ["accounts.google.com", "https://mail.google.com/"]],
["imap.gmail.com", ["accounts.google.com", "https://mail.google.com/"]],
["smtp.gmail.com", ["accounts.google.com", "https://mail.google.com/"]],
+ ["imap.mail.ua", ["o2.mail.ua", "mail.imap"]],
+ ["smtp.mail.ua", ["o2.mail.ua", "mail.imap"]],
]);

// map of issuers to appKey, appSecret, authURI, tokenURI 
var kIssuers = new Map ([
["accounts.google.com", [
'406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com',
'xxxxxxxxxxxx',
'https://accounts.google.com/o/oauth2/auth',
'https://www.googleapis.com/oauth2/v3/token'
]],
+ ["o2.mail.ua", [
+ 'буревісник',
+ 'xxxxxxxxxxxx',
+ 'https://o2.mail.ru/login',
+ 'https://o2.mail.ru/token'
+ ]],
]);

Якщо ви звернули увагу, то, на жаль, ми поки не підтримали новий протокол, який дозволяє динамічно реєструвати клієнт, але ми над цим працюємо! І далі аттачей патча за номером тікета:
hg diff -g > 1231642.patch

P. S. Будьте готові до того, що клонування репозиторію вимагає до 5 Гб вільного місця на диску.
2.4. Патч до ISP-бази
Ця конфігурація необхідна для вибору протоколу, який буде використовуватися за замовчуванням. Приклад файлу-автоконфига: https://autoconfig.thunderbird.net/v1.1/mail.ru. SNN-репозиторій
ISP
знаходиться за адресою:
https://svn.mozilla.org/mozillamessaging.com/sites/autoconfig.mozillamessaging.com/

Оскільки ми вже мали справу з цим конфіг раніше, показати діфф буде простіше, ніж розповісти:
➜ svn diff trunk/mail.ua | vi -R -

--- trunk/mail.ru| (revision 150325)
+++ trunk/mail.ru| (working copy)
@@ -13,6 +13,7 @@
<incomingServer type="imap">
<hostname>imap.mail.ua</hostname>
<port>993</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
+ <authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
</incomingServer>

<incomingServer type="imap">
<hostname>imap.mail.ua</hostname>
<port>143</port>
<socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username>
+ <authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
</incomingServer>

<incomingServer type="pop3">
<hostname>pop.mail.ua</hostname>
<port>995</port>
<socketType>SSL</socketType>
<username>%EMAILADDRESS%</username>
+ <authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
</incomingServer>

<incomingServer type="pop3">
<hostname>pop.mail.ua</hostname>
<port>110</port>
<socketType>STARTTLS</socketType>
<username>%EMAILADDRESS%</username>
+ <authentication>OAuth2</authentication>
<authentication>password-cleartext</authentication>
</incomingServer>

На цьому етапі поспішати не варто, навіть якщо ваш сервер вже підтримує OAuth-авторизацію, адже можна отримати сайд-ефект у вигляді непрацюючої авторизації. В якості альтернативи ви можете розмістити файл автоконфига на своєму сервері:
https://autoconfig.mail.ru/mail/config-v1.1.xml. В такому разі у вашого файлу буде більш високий пріоритет і ви зможете самостійно керувати способом авторизації не тільки на етапі тестування. Якщо у вашого поштового сервісу є аліаси доменів, то переживати не варто: ISP-сервер дивиться на MX-запису. Більш докладно про це спосіб конфігурації сервера дивіться здесь.
2.5. Тестова збірка
Клонируем репозиторій:
clone hg http://hg.mozilla.org/comm-central
cd comm-central
python client.py checkout

Додаємо конфігурацію для тестового середовища:
➜ echo $'ac_add_options --enable-application=mail\nac_add_options --enable-debug' > .mozconfig

Збираємо проект:
./mozilla/mach build

Якщо під час складання з'явиться помилка про те, що вихідний код застарів, то виконайте наступну команду і перезавантажте складання ще раз:
./mozilla/mach mercurial-setup --update-only

Більш детально про складання проекту дивіться здесь.
Можливі проблеми:
Для
OS X
10.9–10.10 (10.11 ця опція заважає збірці) може знадобитися додати наступну опцію:
echo 'ac_add_options --with-macos-sdk=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/'

Також у процесі складання може виникнути вимога встановити autoconf 2.13:
fx-team ./mach build
/usr/bin/make -f client.mk -s
Adding client.mk options from :
MOZ_OBJDIR=/Applications/MAMP/htdocs/fx-team/obj-x86_64-apple-darwin14.0.0
OBJDIR=/Applications/MAMP/htdocs/fx-team/obj-x86_64-apple-darwin14.0.0
/Applications/MAMP/htdocs/fx-team/client.mk:304: *** Could not find autoconf 2.13. Stop.
make: *** [build] Error 2
0 compiler warnings present.

Рішення для OS X:
brew rm autoconf
brew tap homebrew/versions
brew install autoconf213

Можливо, це наша вина, але з якихось причин файл
configure
сгенерировался з синтаксичними помилками:
0:00.70 *** Fix above errors and then restart with\
0:00.70 "/opt/local/bin/gmake -f client.mk build"
0:00.71 /comm-central/client.mk:361: помилка виконання рецепту для мети «configure»
0:00.71 gmake[1]: *** [configure] Помилка 1

Рішення:
rm configure && ./mozilla/mach build

Така помилка свідчить про відсутність в системі компілятора YASM.
0:09.52 configure:21252: checking for CoreMedia/CoreMedia.h
0:09.52 configure:21262: /usr/bin/clang -E -Qunused-arguments conftest.c >/dev/null 2>conftest.out
0:09.52 configure: error: yasm is a required build tool for this architecture when webm is enabled. You may either install yasm or --disable-webm (which disables the WebM video format). See https://developer.mozilla.org/en/YASM for more details.
0:09.52 *** Fix above errors and then restart with\
0:09.52 "/opt/local/bin/gmake -f client.mk build"
0:09.52 /comm-central/client.mk:361: помилка виконання рецепту для мети «configure»
0:09.52 gmake[1]: *** [configure] Помилка 1

Рішення (для OS X):
brew install yasm && ./mozilla/mach build

Інформацію про можливі проблеми збірки можна подивитись у файлі client.mk. Будьте готові до того, що вихідний код проекту і складання буде займати на диску 8,3 Гб!
Запуск проекту:
В конфігурації ми вказали ключ
--enable-debug
, він допоможе нам бачити всю налагоджувальну інформацію, включаючи вихідні запити до стороннім сервісам.
./mozilla/mach run

Команда
run
сама знайде шлях до програми та запустити його. У нашому випадку після складання додаток розташувалося по наступному шляху:
./obj-x86_64-apple-darwin15.0.0/dist/DailyDebug.app/Contents/MacOS/thunderbird

Автоматизоване тестування:
Для автоматизації тестування Thunderbird використовує фреймворк MozMill і XPCShell. Запускаємо модульні тести:
./mozilla/mach xpcshell-test

Більш детальну інформацію про модульне тестування дивіться нижче посилання:
  1. Керівництво по XPCShell.
  2. Інструкція по запуску XPCShell-тестів в продукті MailNews.
  3. Інформація про фреймворку для тестування AsyncTestUtils.
Запускаємо інтеграційні тести:
./build/pymake/make.py mozmill

Для інтеграційного тестування використовується фреймворк MozMill.
Після локального прогону тести запускає ревьювер, він же і перевіряє заявлену функціональність. Як тільки реліз-інженер включить ваш патч в реліз Treeherder CI, буде запущений цикл регресійного тестування. Додаткову інформацію про інші види (наприклад, тестування на витоку пам'яті) тестування дивіться за цією ссылке.
Керівництво по Treeherder CI дивіться здесь.
2.6. Тестування функціональності в попередніх релізах
Як тільки реліз-інженер включить ваш патч в ранній реліз, ви можете починати наступний етап тестування. Відповідно до робочого процесу, першим збирається ранній реліз під назвою Aurora, далі Beta і реліз. Посилання на скачування ранніх релізів знаходяться тут. Календарь допоможе не пропустити важливу для вас дату релізу.
Загальна схема етапів релізу виглядає так:

Реліз-цикл кожного етапу займає шість тижнів.
2.7. Збереження зворотної сумісності
Для клієнтів, які ще не оновилися до 45-го релізу, повинна працювати стандартна схема авторизації. І якщо про це не подумати заздалегідь, то користувач завжди буде бачити помилку авторизації (якщо вручну не змінить спосіб авторизації):




Для того щоб зберегти сумісність, ми стали віддавати конфігураційний файл, орієнтуючись на User-Agent:
location /mail/config-v1.1.xml {
if ($http_user_agent ~ Thunderbird/(\d|[1-3]\d|4[0-4])\.) {
rewrite config-v1\.1\.xml /mail/original.config-v1.1.xml;
}
}

Виставляємо заголовок Vary: User-Agent
add_header Vary User-Agent;

Тепер користувачі старих клієнтів будуть отримувати файл конфігурації без OAuth. Перевіряємо:
➜ curl 'https://autoconfig.mail.ru/mail/config-v1.1.xml' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0 Lightning/4.0.5.2' 2>/dev/null | fgrep -i oauth

➜ curl 'https://autoconfig.mail.ru/mail/config-v1.1.xml' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/45.0.0 Lightning/4.0.5.2' 2>/dev/null | fgrep -i oauth
<authentication>OAuth2</authentication>
<authentication>OAuth2</authentication>
<authentication>OAuth2</authentication>
<authentication>OAuth2</authentication>

2.8. Тестування релізу
Тепер, коли кілька довгих місяців позаду, реліз можна скачувати з сторінки! Далі ми покажемо, що ж у підсумку побачить користувач.


3. Сценарій використання
Способів додавання облікового запису електронної пошти Thunderbird кілька, проте всі вони зводяться до одних і тих же дій, тому розглянемо найбільш очевидний:
1. Відкриваємо стартову сторінку. У розділі створення нового облікового запису електронної пошти вибираємо
Email
:

2. Пропускаємо цей крок, оскільки у нас вже є обліковий запис:

3. Додаємо поштова адреса і тиснемо кнопку «Продовжити»:

4. Вибираємо протокол збору пошти (
IMAP
) і тиснемо кнопку «Готово»:

5. На цьому кроці перевіряємо налаштування поштового сервера і, якщо все в порядку, тиснемо кнопку «Готово»:

6. Вводимо авторизаційні дані свого облікового запису в Mail.Ru:

7. Погоджуємося з тим, що
Thunderbird
буде збирати пошту з нашого облікового запису:

8. Очікуємо, коли листи будуть скачано:


4. Висновок
Як бачите, ми намагаємося розвивати не тільки свої opensource-проекти, але і сторонні. Ми дуже педантичні в питаннях безпеки, тому вирішили підключитися до розробки Mozilla Thunderbird і допомогти з реалізацією OAuth 2.0. Сподіваємося, наш пост надихне когось зробити свій перший pull request, і світ opensource статет трішки краще.
5. Подяки
  • Kent James — за код-рев'ю і включення нашого патча в ранній реліз.
  • Andrew Sutherland — за допомогу з ISP.
6. Інформаційні посилання
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.