Browse Source

Allow restricting clients to groups, APIs to clients, custom API exceptions

10.0
Maciej Wawro 5 years ago
parent
commit
ad1e00ab5d
  1. 2
      galicea_openid_connect/__manifest__.py
  2. 33
      galicea_openid_connect/api.py
  3. 13
      galicea_openid_connect/controllers/main.py
  4. 4
      galicea_openid_connect/models/client.py
  5. 1
      galicea_openid_connect/views/views.xml

2
galicea_openid_connect/__manifest__.py

@ -9,7 +9,7 @@
'website': "http://galicea.pl", 'website': "http://galicea.pl",
'category': 'Technical Settings', 'category': 'Technical Settings',
'version': '10.0.1.1',
'version': '10.0.1.2',
'depends': ['web', 'galicea_environment_checkup'], 'depends': ['web', 'galicea_environment_checkup'],

33
galicea_openid_connect/api.py

@ -16,7 +16,13 @@ class ApiException(Exception):
super(Exception, self).__init__(message) super(Exception, self).__init__(message)
self.code = code if code else self.INVALID_REQUEST self.code = code if code else self.INVALID_REQUEST
def resource(path, method, auth='user'):
def to_json(self):
return {
'error': self.code,
'error_message': self.message
}
def resource(path, method, auth='user', clients=None):
assert auth in ['user', 'client'] assert auth in ['user', 'client']
def endpoint_decorator(func): def endpoint_decorator(func):
@ -68,6 +74,10 @@ def resource(path, method, auth='user'):
) )
req.uid = token.client_id.system_user_id.id req.uid = token.client_id.system_user_id.id
if clients:
if token.client_id.id not in map(lambda c: req.env.ref(c).id, clients):
raise ApiException('Access denied', 'restricted_app')
ctx = req.context.copy() ctx = req.context.copy()
ctx.update({'client_id': token.client_id.id}) ctx.update({'client_id': token.client_id.id})
req.context = ctx req.context = ctx
@ -78,22 +88,17 @@ def resource(path, method, auth='user'):
headers=cors_headers, headers=cors_headers,
status=200 status=200
) )
except ApiException as e:
except Exception as e:
status = 400
if not isinstance(e, ApiException):
_logger.exception('Unexpected exception while processing API request')
e = ApiException('Unexpected server error', 'server_error')
status = 500
return werkzeug.Response( return werkzeug.Response(
response=json.dumps({'error': e.code, 'error_message': e.message}),
status=400,
response=json.dumps(e.to_json()),
status=status,
headers=cors_headers headers=cors_headers
) )
except:
_logger.exception('Unexpected exception while processing API request')
return werkzeug.Response(
response=json.dumps({
'error': 'server_error',
'error_message': 'Unexpected server error',
}),
headers=cors_headers,
status=500
)
return func_wrapper return func_wrapper
return endpoint_decorator return endpoint_decorator

13
galicea_openid_connect/controllers/main.py

@ -47,6 +47,7 @@ class OAuthException(Exception):
UNSUPPORTED_RESPONSE_TYPE = 'unsupported_response_type' UNSUPPORTED_RESPONSE_TYPE = 'unsupported_response_type'
INVALID_GRANT = 'invalid_grant' INVALID_GRANT = 'invalid_grant'
UNSUPPORTED_GRANT_TYPE = 'unsupported_grant_type' UNSUPPORTED_GRANT_TYPE = 'unsupported_grant_type'
RESTRICTED_APP = 'restricted_app'
def __init__(self, message, type): def __init__(self, message, type):
super(Exception, self).__init__(message) super(Exception, self).__init__(message)
@ -103,6 +104,15 @@ class Main(http.Controller):
OAuthException.INVALID_CLIENT, OAuthException.INVALID_CLIENT,
) )
def __validate_user(self, client, user):
if not client.user_group_id:
return
if client.user_group_id not in user.groups_id:
raise OAuthException(
'User is not allowed to use this client',
OAuthException.RESTRICTED_APP
)
@http.route('/.well-known/openid-configuration', auth='public', type='http') @http.route('/.well-known/openid-configuration', auth='public', type='http')
def metadata(self, req, **query): def metadata(self, req, **query):
base_url = http.request.httprequest.host_url base_url = http.request.httprequest.host_url
@ -206,6 +216,7 @@ class Main(http.Controller):
} }
return self.__redirect('/web/login', params, 'query') return self.__redirect('/web/login', params, 'query')
self.__validate_user(client, user)
response_types = response_type.split() response_types = response_type.split()
extra_claims = { extra_claims = {
@ -355,7 +366,7 @@ class Main(http.Controller):
'Invalid username or password', 'Invalid username or password',
OAuthException.INVALID_REQUEST OAuthException.INVALID_REQUEST
) )
self.__validate_user(client, req.env['res.users'].sudo().browse(user_id))
scopes = query['scope'].split(' ') if query.get('scope') else [] scopes = query['scope'].split(' ') if query.get('scope') else []
# Retrieve/generate access token. We currently only store one per user/client # Retrieve/generate access token. We currently only store one per user/client
token = req.env['galicea_openid_connect.access_token'].sudo().retrieve_or_create( token = req.env['galicea_openid_connect.access_token'].sudo().retrieve_or_create(

4
galicea_openid_connect/models/client.py

@ -34,6 +34,10 @@ class Client(models.Model):
string='Allow OAuth2 password grant', string='Allow OAuth2 password grant',
default=False, default=False,
) )
user_group_id = fields.Many2one(
'res.groups',
'Restrict the client to a group'
)
@api.model @api.model
def __system_user_name(self, client_name): def __system_user_name(self, client_name):

1
galicea_openid_connect/views/views.xml

@ -28,6 +28,7 @@
<button class="oe_read_only" string="Show" type="action" name="%(client_action_secret)d" /> <button class="oe_read_only" string="Show" type="action" name="%(client_action_secret)d" />
<field name="auth_redirect_uri" /> <field name="auth_redirect_uri" />
<field name="allow_password_grant" /> <field name="allow_password_grant" />
<field name="user_group_id" />
</group> </group>
</form> </form>
</field> </field>

Loading…
Cancel
Save