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 @@
+