Files
enterprise-addons/databases_auth/controllers/databases.py
T

78 lines
3.6 KiB
Python

import json
import logging
import requests
import werkzeug.exceptions
from odoo import http, tools
from odoo.exceptions import ValidationError
from odoo.http import fragment_to_query_string, request
_logger = logging.getLogger(__name__)
ACCOUNTS_URL = 'https://accounts.odoo.com'
class DatabasesController(http.Controller):
@http.route('/databases/auth', type='http', auth='user', readonly=False)
@fragment_to_query_string
def databases_set_direct_connect(self, **kw):
user = self.env.user
if not user.has_group('databases.group_databases_user'):
_logger.warning("'/databases/auth' access forbidden to %s", user)
raise werkzeug.exceptions.Forbidden()
if not kw.get('state'):
raise werkzeug.exceptions.BadRequest()
# 1) db token: Was it made by this db and for this user?
state = json.loads(kw['state'])
token = state['t']
payload = tools.verify_hash_signed(self.env(su=True), 'signup', token)
if not payload:
raise werkzeug.exceptions.Forbidden()
_, user_ids, _, _ = payload
if user != self.env['res.users'].browse(user_ids):
# This is not the same account: don't link them
_logger.warning("'/databases/auth' %s attempt to use a token for %s", user, user_ids)
raise werkzeug.exceptions.Forbidden()
# 2) access token: does the provider validate it?
access_token = kw.get('access_token')
try:
response = requests.get(f'{ACCOUNTS_URL}/oauth2/tokeninfo', params={'access_token': access_token}, timeout=10)
response.raise_for_status()
validation = response.json()
except requests.RequestException as e:
_logger.warning("'/databases/auth' request error: %s", e)
raise ValidationError(self.env._("An error occured during the validation request to the OAuth provider."))
if validation.get("error"):
_logger.warning("'/databases/auth' access_token could't be validated for %s, error provided: %s", user, validation['error'])
raise ValidationError(self.env._("The OAuth provider couldn't verify your identity."))
# 3) access token: was it generated for us? (avoid Confused Deputy Problem)
if validation['audience'] != self.env['ir.config_parameter'].sudo().get_param('database.uuid'):
# That token wasn't made for us
_logger.warning("'/databases/auth' %s use token with wrong audience: %s", user, validation['audience'])
raise werkzeug.exceptions.Forbidden()
# 4) access_token: was it generated for this user?
if user.email != validation['email']:
# This is not the same account: don't link them
_logger.warning("'/databases/auth' %s validation email don't match", user)
raise werkzeug.exceptions.Forbidden()
# everything alright: write oauth and continue the flow
user.databases_sso_uid = validation['user_id']
db_id = int(state['r'])
database = self.env['project.project'].browse(db_id).exists()
if not database or not (user.database_user_ids & database.database_user_ids):
# This user shouldn't get access to this db: don't let it even see the url
_logger.warning("'/databases/auth' %s attempt to connect to %s", user, database)
raise werkzeug.exceptions.Forbidden()
if database.database_hosting == "saas":
database._set_oauth_to_remote_db(user) # allow smooth connection
return request.redirect(database._get_connect_url(), local=False)