78 lines
3.6 KiB
Python
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)
|