Клиент Python для доступа к CalDAV через OAuth2 в Nextcloud

Канонические примеры использования CalDAV всегда используют аутентификацию по имени пользователя и паролю. Однако Nextcloud поддерживает OAuth2, поэтому я бы хотел использовать CalDAV через oauth.

Я уже сделал то же самое с API календаря Google, но просто адаптировал oauth2client образец предоставлен Google:

client_secrets = 'client_secrets.json'
flow = client.flow_from_clientsecrets(client_secrets, scope="",
                                      message=tools.message_if_missing(client_secrets))
storage = file.Storage('calendar_credentials.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
    credentials = tools.run_flow(flow, storage)

http = credentials.authorize(http=build_http())

заменив build_http() по примеру caldav.DAVClient не работает. внутренний request() API-интерфейсы совершенно разные, и вызов любого метода клиента caldav будет с треском провален, когда обернут authorize(), Итак, вопрос: как интегрировать caldav.DAVClient с oauth2client?

Также нет документации по использованию OAuth с nextCloud. Я нашел это сообщение, но до сих пор не очевидно, что и где.

1 ответ

Решение

Давайте начнем с конфигурации. В Nextcloud перейдите в настройки безопасности ( https://mycloud.example.com/settings/admin/security). Есть раздел OAuth 2.0 clients, Добавьте клиента. Вы можете использовать любое имя, например calendar, но важно, чтобы URI перенаправления был http://localhost:8080, Зачем? tools.run_flow() создаст экземпляр http-сервера для получения вызова аутентификации по этому адресу по умолчанию. Нажмите "Добавить". Теперь вы должны увидеть новый идентификатор клиента. Скопируйте идентификатор клиента и секрет (нажмите значок глаза, чтобы открыть его) в client_secrets.json, который должен выглядеть следующим образом:

{
  "web": {
    "client_id": "stuff copied from Client Identifier",
    "client_secret": "stuff copied from secret",
    "auth_uri": "https://mycloud.example.com/index.php/apps/oauth2/authorize",
    "token_uri": "https://mycloud.example.com/index.php/apps/oauth2/api/v1/token",
    "redirect_uris": []
  }
}

Теперь, когда вы запускаете пример из раздела вопросов, ваш браузер должен автоматически перейти к экземпляру mycloud.example.com, и должно появиться сообщение "Вы собираетесь предоставить доступ к календарю своей учетной записи mycloud.example.com". Нажмите "Предоставить доступ". После ввода вашего имени пользователя и пароля браузер должен быть перенаправлен на http://localhost:8080/, и вы должны увидеть сообщение "Процесс аутентификации завершен".

Заметки:

  • Я не нашел разницы client_secrets.json начинается с webили с installed, Это должен быть один из этих двух, как бы то ни было.
  • по-видимому, redirect_uris может оставаться пустым.

Теперь вопрос программирования (это ведь форум программиста...)

Конструктор caldav.DAVClient позволяет auth параметр, который должен быть экземпляром requests.auth.AuthBase, Итак, давайте создадим один:

from requests.auth import AuthBase


class OAuth(AuthBase):
    def __init__(self, credentials):
        self.credentials = credentials

    def __call__(self, r):
        self.credentials.apply(r.headers)
        return r

Сейчас вместо звонка credentials.authorize(http=build_http()) как в оригинальном примере от Google, мы пишем

caldav_client = caldav.DAVClient(
    "https://mycloud.example.com/remote.php/dav/",
    auth=OAuth(credentials))

Это оно! Теперь мы можем написать

principal = caldav_client.principal()
calendars = principal.calendars()

как в оригинальном примере.

Другие вопросы по тегам