diff --git a/galicea_openid_connect/__manifest__.py b/galicea_openid_connect/__manifest__.py index 1508984..bc24662 100644 --- a/galicea_openid_connect/__manifest__.py +++ b/galicea_openid_connect/__manifest__.py @@ -9,7 +9,7 @@ 'website': "http://galicea.pl", 'category': 'Technical Settings', - 'version': '10.0.1.0', + 'version': '10.0.1.1', 'depends': ['web', 'galicea_environment_checkup'], diff --git a/galicea_openid_connect/controllers/main.py b/galicea_openid_connect/controllers/main.py index a7ec142..ed21422 100644 --- a/galicea_openid_connect/controllers/main.py +++ b/galicea_openid_connect/controllers/main.py @@ -114,7 +114,7 @@ class Main(http.Controller): 'jwks_uri': base_url + 'oauth/jwks', 'scopes_supported': ['openid'], 'response_types_supported': RESPONSE_TYPES_SUPPORTED, - 'grant_types_supported': ['authorization_code', 'implicit'], + 'grant_types_supported': ['authorization_code', 'implicit', 'password', 'client_credentials'], 'subject_types_supported': ['public'], 'id_token_signing_alg_values_supported': ['RS256'], 'token_endpoint_auth_methods_supported': ['client_secret_post'] @@ -258,6 +258,8 @@ class Main(http.Controller): return json.dumps(self.__handle_grant_type_authorization_code(req, **query)) elif query['grant_type'] == 'client_credentials': return json.dumps(self.__handle_grant_type_client_credentials(req, **query)) + elif query['grant_type'] == 'password': + return json.dumps(self.__handle_grant_type_password(req, **query)) else: raise OAuthException( 'Unsupported grant_type param: \'{}\''.format(query['grant_type']), @@ -314,6 +316,46 @@ class Main(http.Controller): response['id_token'] = self.__create_id_token(req, payload['user_id'], client, extra_claims) return response + def __handle_grant_type_password(self, req, **query): + client = self.__validate_client(req, **query) + if not client.allow_password_grant: + raise OAuthException( + 'This client is not allowed to perform password flow', + OAuthException.UNSUPPORTED_GRANT_TYPE + ) + + for param in ['username', 'password']: + if param not in query: + raise OAuthException( + '{} is required'.format(param), + OAuthException.INVALID_REQUEST + ) + user_id = req.env['res.users'].authenticate( + req.env.cr.dbname, + query['username'], + query['password'], + None + ) + if not user_id: + raise OAuthException( + 'Invalid username or password', + OAuthException.INVALID_REQUEST + ) + + scopes = query['scope'].split(' ') if query.get('scope') else [] + # Retrieve/generate access token. We currently only store one per user/client + token = req.env['galicea_openid_connect.access_token'].sudo().retrieve_or_create( + user_id, + client.id + ) + response = { + 'access_token': token.token, + 'token_type': 'bearer' + } + if 'openid' in scopes: + response['id_token'] = self.__create_id_token(req, user_id, client, {}) + return response + def __handle_grant_type_client_credentials(self, req, **query): client = self.__validate_client(req, **query) self.__validate_client_secret(client, req, **query) diff --git a/galicea_openid_connect/models/client.py b/galicea_openid_connect/models/client.py index 470c8db..0c00e20 100644 --- a/galicea_openid_connect/models/client.py +++ b/galicea_openid_connect/models/client.py @@ -30,6 +30,10 @@ class Client(models.Model): required=True, ondelete='restrict' ) + allow_password_grant = fields.Boolean( + string='Allow OAuth2 password grant', + default=False, + ) @api.model def __system_user_name(self, client_name): diff --git a/galicea_openid_connect/views/views.xml b/galicea_openid_connect/views/views.xml index cee47be..6e6cc66 100644 --- a/galicea_openid_connect/views/views.xml +++ b/galicea_openid_connect/views/views.xml @@ -27,6 +27,7 @@