Skip to content
Snippets Groups Projects
Commit bf5ac485 authored by Viktor Vorobev's avatar Viktor Vorobev Committed by Ugo Albanese
Browse files

Merged in NRRPLT-8379-ebrains-auth (pull request #35)

[NRRPLT-8379] Authentication via Collab v2 .

* [NRRPLT-8379] replace to collab 2 auth and remove token check
* [NRRPLT-8379] fix browser communication at login
* [NRRPLT-8379] fix oidc scopes
* [NRRPLT-8379] add docs note about login


Approved-by: Ugo Albanese
Approved-by: Eloy Retamino
parent 4b0eb6b4
No related branches found
No related tags found
No related merge requests found
......@@ -41,7 +41,9 @@ Here we chose the local machine as the NRP server. The Virtual Coach can connect
vc = VirtualCoach('http://148.187.97.37', oidc_username='<your-hbp-username>', oidc_password='<your-hbp-password>')
Notice that parameters *storage_username* and *storage_password* are replaced with *oidc_username* and *oidc_password*. The latter must be used when :term:`OIDC` authentication is required, the former are used otherwise.
Notice that parameters *storage_username* and *storage_password* are replaced with *oidc_username* and *oidc_password*. The latter must be used when EBRAINS :term:`OIDC` authentication is required, the former are used otherwise.
.. note:: Prior using Virtual Coach with the online NRP servers, you should login at least once to that online server with your EBRAINS account in order to give the user consent.
Once we created a VirtualCoach instance, we can use it to check out the current state of our environment. We can see a list of the available experiments to run, a list of the available servers to run experiments on, and a list of the currently running experiments.
......
......@@ -129,9 +129,6 @@ class TestVirtualCoach(unittest.TestCase):
def test_init_asserts_no_password(self):
# invalid oidc token
self.assertRaises(AssertionError, VirtualCoach, oidc_token=123)
# invalid environment
self.assertRaises(AssertionError, VirtualCoach, environment=True)
......
......@@ -43,6 +43,8 @@ import tempfile
import requests
from urllib import parse as urlparse
import secrets
from copy import copy
from datetime import datetime, timedelta
......@@ -72,7 +74,7 @@ class VirtualCoach(object):
"""
def __init__(self, environment='http://localhost:9000', oidc_username=None, oidc_password=None,
oidc_token=None, storage_username=None, storage_password=None):
storage_username=None, storage_password=None):
"""
Instantiates the Virtual Coach by loading the configuration file and logging into OIDC for
the given user. This will only fail if the config file is invalid or if the user
......@@ -86,9 +88,6 @@ class VirtualCoach(object):
authentication and no token is provided.
:param oidc_password: (optional) A string representing the OIDC Server password. If
not supplied, the user will be prompted to enter a password.
:param oidc_token: (optional) A string representing the OIDC token for the current
user, required if the selected environment requires OIDC
and the username is not provided.
:param storage_username: (optional) A string representing the Storage Server username. It is
required if the user wants to have access to the storage server to
clone experiments and launch cloned experiments.
......@@ -97,7 +96,6 @@ class VirtualCoach(object):
"""
assert isinstance(environment, (string_types, type(None)))
assert isinstance(oidc_username, (string_types, type(None)))
assert isinstance(oidc_token, (string_types, type(None)))
assert isinstance(storage_username, (string_types, type(None)))
# parse and load the config file before any OIDC actions
......@@ -107,19 +105,12 @@ class VirtualCoach(object):
# authorize client into oidc or storage server
token = ''
if oidc_username or oidc_token:
if oidc_username:
logger.info('Logging into OIDC as: %s', oidc_username)
if not oidc_password:
oidc_password = getpass.getpass(prompt='input your OIDC password: ')
token = self.__get_oidc_token(oidc_username, oidc_password)
else:
if self.__oidc_token_is_valid(token):
logger.info('Using provided token for OIDC server authorization')
token = oidc_token
else:
raise Exception('Provided OIDC token is invalid, VirtualCoach cannot be '
'instantiated.')
if oidc_username:
logger.info('Logging into OIDC as: %s', oidc_username)
if not oidc_password:
oidc_password = getpass.getpass(prompt='input your OIDC password: ')
token = self.__get_oidc_token(oidc_username, oidc_password)
elif storage_username:
logger.warning('No OIDC username supplied, simulation services will fail if OIDC is '
'enabled in this environment (%s).', environment)
......@@ -141,31 +132,6 @@ class VirtualCoach(object):
# if the config is valid and the login doesn't fail, we're ready
logger.info('Ready.')
def __oidc_token_is_valid(self, token):
'''
check if a given oidc token is valid
:param token: token to validate as a string
'''
response = requests.post('https://services.humanbrainproject.eu/oidc/tokeninfo',
data=urlparse.urlencode({'access_token': token}),
headers={'Content-Type': 'application/x-www-form-urlencoded'})
if response.status_code != 200:
raise Exception('OIDC token validation failed, Status Code: %d'
% response.status_code)
d = json.loads(response.content)
if 'valid' in d and not d['valid']:
logger.info('OIDC token not valid')
return False
elif 'expires_in' in d and int(d['expires_in']) < 1:
logger.info('OIDC token expired')
return False
logger.info('OIDC token valid')
return True
def __get_oidc_token(self, user_name, password):
"""
......@@ -176,18 +142,19 @@ class VirtualCoach(object):
"""
# hbp oidc request
client_id = 'kamaji-python-client'
oauth_url = 'https://services.humanbrainproject.eu/oidc/'
client_id = 'nrp-frontend'
oauth_url = 'https://iam.ebrains.eu/auth/realms/hbp/protocol/openid-connect/'
# construct request
query = {
'response_type': 'token',
'client_id': client_id,
'redirect_uri': oauth_url + 'resources/oauth_code.html',
'prompt': 'consent',
'redirect_uri': 'https://neurorobotics.net',
'nonce': secrets.token_urlsafe(),
'scope': 'openid profile email group'
}
parts = list(urlparse.urlparse(oauth_url + 'authorize'))
parts = list(urlparse.urlparse(oauth_url + 'auth'))
query.update(dict(urlparse.parse_qsl(parts[4]))) # 4 is the index of the query part
parts[4] = urlparse.urlencode(query)
authorize_url = urlparse.urlunparse(parts)
......@@ -198,12 +165,12 @@ class VirtualCoach(object):
br.set_handle_robots(False)
for _ in range(3):
br.open(authorize_url)
br.select_form(name='j_spring_security_check')
br.select_form(nr=0)
# fill form
# pylint: disable=unsupported-assignment-operation
br['j_username'] = user_name
br['j_password'] = password
br['username'] = user_name
br['password'] = password
# pylint: disable=assignment-from-none
res = br.submit()
......@@ -215,9 +182,7 @@ class VirtualCoach(object):
# the user is forwarded to the approve page if not approved yet
if 'access_token' not in urlparse.urlparse(res.geturl()).fragment.lower():
br.select_form(name='confirmationForm')
# pylint: disable=assignment-from-none
res = br.submit()
raise Exception('Login to NRP online and give your consent. Then return to VC.')
url_with_fragment = res.geturl()
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment