|
| 1 | +# This file is part of Radicale Server - Calendar Server |
| 2 | +# |
| 3 | +# Original from https://gitlab.mim-libre.fr/alphabet/radicale_oauth/ |
| 4 | +# Copyright © 2021-2022 Bruno Boiget |
| 5 | +# Copyright © 2022-2022 Daniel Dehennin |
| 6 | +# |
| 7 | +# Since migration into upstream |
| 8 | +# Copyright © 2025-2025 Peter Bieringer <pb@bieringer.de> |
| 9 | +# |
| 10 | +# This library is free software: you can redistribute it and/or modify |
| 11 | +# it under the terms of the GNU General Public License as published by |
| 12 | +# the Free Software Foundation, either version 3 of the License, or |
| 13 | +# (at your option) any later version. |
| 14 | +# |
| 15 | +# This library is distributed in the hope that it will be useful, |
| 16 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | +# GNU General Public License for more details. |
| 19 | +# |
| 20 | +# You should have received a copy of the GNU General Public License |
| 21 | +# along with Radicale. If not, see <http://www.gnu.org/licenses/>. |
| 22 | + |
| 23 | +""" |
| 24 | +Authentication backend that checks credentials against an oauth2 server auth endpoint |
| 25 | +""" |
| 26 | + |
| 27 | +import requests |
| 28 | + |
| 29 | +from radicale import auth |
| 30 | +from radicale.log import logger |
| 31 | + |
| 32 | + |
| 33 | +class Auth(auth.BaseAuth): |
| 34 | + def __init__(self, configuration): |
| 35 | + super().__init__(configuration) |
| 36 | + self._endpoint = configuration.get("auth", "oauth2_token_endpoint") |
| 37 | + if not self._endpoint: |
| 38 | + logger.error("auth.oauth2_token_endpoint URL missing") |
| 39 | + raise RuntimeError("OAuth2 token endpoint URL is required") |
| 40 | + logger.info("auth OAuth2 token endpoint: %s" % (self._endpoint)) |
| 41 | + |
| 42 | + def _login(self, login, password): |
| 43 | + """Validate credentials. |
| 44 | + Sends login credentials to oauth token endpoint and checks that a token is returned |
| 45 | + """ |
| 46 | + try: |
| 47 | + # authenticate to authentication endpoint and return login if ok, else "" |
| 48 | + req_params = { |
| 49 | + "username": login, |
| 50 | + "password": password, |
| 51 | + "grant_type": "password", |
| 52 | + "client_id": "radicale", |
| 53 | + } |
| 54 | + req_headers = {"Content-Type": "application/x-www-form-urlencoded"} |
| 55 | + response = requests.post( |
| 56 | + self._endpoint, data=req_params, headers=req_headers |
| 57 | + ) |
| 58 | + if ( |
| 59 | + response.status_code == requests.codes.ok |
| 60 | + and "access_token" in response.json() |
| 61 | + ): |
| 62 | + return login |
| 63 | + except OSError as e: |
| 64 | + logger.critical("Failed to authenticate against OAuth2 server %s: %s" % (self._endpoint, e)) |
| 65 | + logger.warning("User failed to authenticate using OAuth2: %r" % login) |
| 66 | + return "" |
0 commit comments