def test_recover_root_identity(self): """ MULTI VO (CORE): Test adding a new identity for root using super_root """ identity_key = ''.join(choice(ascii_lowercase) for x in range(10)) with assert_raises(AccessDenied): vo_api.recover_vo_root_identity(root_vo=self.new_vo['vo'], identity_key=identity_key, id_type='userpass', email='*****@*****.**', issuer='root', password='******', **self.vo) vo_api.recover_vo_root_identity(root_vo=self.new_vo['vo'], identity_key=identity_key, id_type='userpass', email='*****@*****.**', issuer='super_root', password='******', vo='def') assert_in('root', list_accounts_for_identity(identity_key=identity_key, id_type='userpass'))
def select_account_name(identitystr, identity_type): """ Looks for account corresponding to the provided identity. :param identitystr: identity string :param identity_type: identity_type e.g. x509, saml, oidc, userpass :returns: None or account string """ accounts = identity.list_accounts_for_identity(identitystr, identity_type) ui_account = None if len(accounts) == 0: return None # check if ui_account param is set if 'ui_account' in input(): ui_account = input()['ui_account'] # if yes check if the accounts provided for users identity include this account if not ui_account and 'account' in input(): ui_account = input()['account'] if ui_account: if ui_account not in accounts: return None else: return ui_account else: # try to set the default account to the user account, if not available take the first account. def_account = accounts[0] for account in accounts: account_info = get_account_info(account) if account_info.account_type == AccountType.USER: def_account = account break selected_account = cookies().get('rucio-selected-account') if (selected_account): def_account = selected_account ui_account = def_account return ui_account
def finalize_auth(token, identity_type, cookie_dict_extra=None): """ Finalises login. Validates provided token, sets cookies and redirects to the final page. :param token: token string :param identity_type: identity_type e.g. x509, userpass, oidc, saml :param cookie_dict_extra: extra cookies to set, dictionary expected :returns: redirects to the final page or renders a page with an error message. """ valid_token_dict = validate_webui_token(from_cookie=False, session_token=token) if not valid_token_dict: return RENDERER.problem("It was not possible to validate and finalize your login with the provided token.") try: attribs = list_account_attributes(valid_token_dict['account'], valid_token_dict['vo']) accounts = identity.list_accounts_for_identity(valid_token_dict['identity'], identity_type) accvalues = "" for acc in accounts: accvalues += acc + " " accounts = accvalues[:-1] cookie_dict = {'x-rucio-auth-token': token, 'x-rucio-auth-type': identity_type, 'rucio-auth-token-created-at': long(time()), 'rucio-available-accounts': accounts, 'rucio-account-attr': dumps(attribs), 'rucio-selected-account': valid_token_dict['account'], 'rucio-selected-vo': valid_token_dict['vo']} if cookie_dict_extra and isinstance(cookie_dict_extra, dict): cookie_dict.update(cookie_dict_extra) set_cookies(cookie_dict) return redirect_to_last_known_url() except: return RENDERER.problem("It was not possible to validate and finalize your login with the provided token.")
def test_api_identity(self): """ IDENTITY (API): Test external representation of identity accounts """ id_key = ''.join(random.choice(string.ascii_lowercase) for x in range(10)) add_account_identity(id_key, 'userpass', self.account_name, '*****@*****.**', 'root', default=True, password='******', **self.vo) out = list_accounts_for_identity(id_key, 'userpass') assert_in(self.account_name, out) if self.multi_vo: assert_not_in(self.account.internal, out)
def check_token(rendered_tpl): token = None js_token = "" js_account = "" def_account = None accounts = None cookie_accounts = None rucio_ui_version = version.version_string() render = template.render(join(dirname(__file__), '../templates')) if ctx.env.get('SSL_CLIENT_VERIFY') != 'SUCCESS': return render.problem("No certificate provided. Please authenticate with a cerficate registered in Rucio.") dn = ctx.env.get('SSL_CLIENT_S_DN') # try to get and check the rucio session token from cookie session_token = cookies().get('x-rucio-auth-token') validate_token = authentication.validate_auth_token(session_token) # if there is no session token or if invalid: get a new one. if validate_token is None: # get all accounts for an identity. Needed for account switcher in UI. accounts = identity.list_accounts_for_identity(dn, 'x509') cookie_accounts = accounts try: try: # try to get the default account for the identity. def_account = identity.get_default_account(dn, 'x509') except IdentityError: # if there is no default account used the first from the list off accounts. def_account = accounts[0] token = authentication.get_auth_token_x509(def_account, dn, 'webui', ctx.env.get('REMOTE_ADDR')) except: return render.problem("Your certificate (%s) is not registered in Rucio. Please contact <a href=\"mailto:[email protected]\">Rucio Support</a>" % dn) # write the token and account to javascript variables, that will be used in the HTML templates. js_token = __to_js('token', token) js_account = __to_js('account', def_account) # if there was no valid session token write the new token to a cookie. if token: setcookie('x-rucio-auth-token', value=token, expires=3600, path='/') if cookie_accounts: values = "" for acc in cookie_accounts: values += acc + " " setcookie('rucio-available-accounts', value=values[:-1], path='/') return render.base(js_token, js_account, rucio_ui_version, rendered_tpl)
def select_account_name(identitystr, identity_type, vo=None): """ Looks for account (and VO if not known) corresponding to the provided identity. :param identitystr: identity string :param identity_type: identity_type e.g. x509, saml, oidc, userpass :returns: Tuple of None or account string, None or VO string or list of VO strings """ ui_account = None if not MULTI_VO: vo = 'def' if vo is not None: accounts = identity.list_accounts_for_identity(identitystr, identity_type) else: internal_accounts = identity_core.list_accounts_for_identity( identitystr, IdentityType.from_sym(identity_type)) accounts = [account.external for account in internal_accounts] vos = [account.vo for account in internal_accounts] if vos: vos = list(set(vos)) # If we only have 1 VO that matches the identity use that, otherwise return all possible VOs so the user can choose if len(vos) == 1: vo = vos[0] else: return None, vos if len(accounts) == 0: return None, vo # check if ui_account param is set if 'ui_account' in input(): ui_account = input()['ui_account'] # if yes check if the accounts provided for users identity include this account if not ui_account and 'account' in input(): ui_account = input()['account'] if ui_account: if ui_account not in accounts: return None, vo else: return ui_account, vo else: # try to set the default account to the user account, if not available take the first account. def_account = accounts[0] for account in accounts: account_info = get_account_info(account, vo=vo) if account_info.account_type == AccountType.USER: def_account = account break selected_account = cookies().get('rucio-selected-account') if (selected_account): def_account = selected_account ui_account = def_account return ui_account, vo
def get(self, identity_key, type): """ Return all identities mapped to an account. .. :quickref: Accounts; list account identities. :param identity_key: Identity string. :param type: Identity type. :resheader Content-Type: application/json :status 200: OK. :status 401: Invalid Auth Token. :status 406: Not Acceptable. :returns: List of identities. """ accounts = list_accounts_for_identity(identity_key, type) return jsonify(accounts)
def test_recover_vo_success(self): """ MULTI VO (REST): Test recovering VO through REST layer succeeds """ mw = [] headers1 = {'X-Rucio-Account': 'super_root', 'X-Rucio-Username': '******', 'X-Rucio-Password': '******'} headers1.update(self.def_header) res1 = TestApp(auth_app.wsgifunc(*mw)).get('/userpass', headers=headers1, expect_errors=True) assert_equal(res1.status, 200) token = str(res1.header('X-Rucio-Auth-Token')) identity_key = ''.join(choice(ascii_lowercase) for x in range(10)) params = {'identity': identity_key, 'authtype': 'userpass', 'email': '*****@*****.**', 'password': '******'} headers2 = {'X-Rucio-Auth-Token': str(token)} res2 = TestApp(vo_app.wsgifunc(*mw)).post('/' + self.vo['vo'] + '/recover', headers=headers2, expect_errors=True, params=dumps(params)) assert_equal(res2.status, 201) assert_in('root', list_accounts_for_identity(identity_key=identity_key, id_type='userpass'))
def GET(self, identity_key, type): """ Return all identities mAPPed to an account. HTTP Success: 200 OK HTTP Error: 400 Bad Reqeust 401 Unauthorized 500 Internal Error :param account: Identity string. """ try: return json.dumps(list_accounts_for_identity(identity_key, type)) except Exception as error: print(str(format_exc())) raise InternalError(error)
def get(self, identity_key, type): """ Return all identities mapped to an account. .. :quickref: Accounts; list account identities. :param identify_key: Identity string. :param type: Identity type. :resheader Content-Type: application/json :status 200: OK. :status 401: Invalid Auth Token. :status 500: Internal Error. :returns: List of identities. """ try: return Response(json.dumps(list_accounts_for_identity(identity_key, type)), content_type="application/json") except Exception, error: print error print str(format_exc()) return error, 500
def get(self, identity_key, type): """ Return all identities mapped to an account. .. :quickref: Accounts; list account identities. :param identity_key: Identity string. :param type: Identity type. :resheader Content-Type: application/json :status 200: OK. :status 401: Invalid Auth Token. :status 406: Not Acceptable. :status 500: Internal Error. :returns: List of identities. """ try: accounts = list_accounts_for_identity(identity_key, type) return jsonify(accounts) except Exception as error: print(format_exc()) return str(error), 500
def get(self, identity_key, type): """ --- summary: List description: List all identities mapped to an account. tags: - Identity parameters: - name: identity_key in: path description: Identity string. schema: type: string style: simple - name: type in: path description: Identity type. schema: type: string style: simple required: false responses: 200: description: OK content: application/json: schema: type: array items: type: object description: Account for the identity. 401: description: Invalid Auth Token 401: description: Not acceptable """ accounts = list_accounts_for_identity(identity_key, type) return jsonify(accounts)
def check_token(rendered_tpl): attribs = None token = None js_token = "" js_account = "" def_account = None accounts = None cookie_accounts = None rucio_ui_version = version.version_string() ui_account = None if 'ui_account' in input(): ui_account = input()['ui_account'] render = template.render(join(dirname(__file__), '../templates')) if ctx.env.get('SSL_CLIENT_VERIFY') != 'SUCCESS': return render.problem( "No certificate provided. Please authenticate with a certificate registered in Rucio." ) dn = ctx.env.get('SSL_CLIENT_S_DN') msg = "Your certificate (%s) is not mapped to any rucio account." % dn msg += "<br><br><font color=\"red\">First, please make sure it is correctly registered in <a href=\"https://voms2.cern.ch:8443/voms/atlas\">VOMS</a> and be patient until it has been fully propagated through the system.</font>" msg += "<br><br>Then, if it is still not working please contact <a href=\"mailto:[email protected]\">DDM Support</a>." # try to get and check the rucio session token from cookie session_token = cookies().get('x-rucio-auth-token') validate_token = authentication.validate_auth_token(session_token) # check if ui_account param is set and if yes, force new token if ui_account: accounts = identity.list_accounts_for_identity(dn, 'x509') if len(accounts) == 0: return render.problem(msg) if ui_account not in accounts: return render.problem( "The rucio account (%s) you selected is not mapped to your certificate (%s). Please select another account or none at all to automatically use your default account." % (ui_account, dn)) cookie_accounts = accounts if (validate_token is None) or (validate_token['account'] != ui_account): try: token = authentication.get_auth_token_x509( ui_account, dn, 'webui', ctx.env.get('REMOTE_ADDR')) except: return render.problem(msg) attribs = list_account_attributes(ui_account) js_token = __to_js('token', token) js_account = __to_js('account', def_account) else: # if there is no session token or if invalid: get a new one. if validate_token is None: # get all accounts for an identity. Needed for account switcher in UI. accounts = identity.list_accounts_for_identity(dn, 'x509') if len(accounts) == 0: return render.problem(msg) cookie_accounts = accounts # try to set the default account to the user account, if not available take the first account. def_account = accounts[0] for account in accounts: account_info = get_account_info(account) if account_info.account_type == AccountType.USER: def_account = account break selected_account = cookies().get('rucio-selected-account') if (selected_account): def_account = selected_account try: token = authentication.get_auth_token_x509( def_account, dn, 'webui', ctx.env.get('REMOTE_ADDR')) except: return render.problem(msg) attribs = list_account_attributes(def_account) # write the token and account to javascript variables, that will be used in the HTML templates. js_token = __to_js('token', token) js_account = __to_js('account', def_account) # if there was no valid session token write the new token to a cookie. if token: setcookie('x-rucio-auth-token', value=token, path='/') setcookie('rucio-auth-token-created-at', value=int(time()), path='/') if cookie_accounts: values = "" for acc in cookie_accounts: values += acc + " " setcookie('rucio-available-accounts', value=values[:-1], path='/') if attribs: setcookie('rucio-account-attr', value=dumps(attribs), path='/') if ui_account: setcookie('rucio-selected-account', value=ui_account, path='/') return render.base(js_token, js_account, rucio_ui_version, rendered_tpl)
def finalize_auth(token, identity_type, cookie_dict_extra=None): """ Finalises login. Validates provided token, sets cookies and redirects to the final page. :param token: token string :param identity_type: identity_type e.g. x509, userpass, oidc, saml :param cookie_dict_extra: extra cookies to set, dictionary expected :returns: redirects to the final page or renders a page with an error message. """ global COOKIES valid_token_dict = validate_webui_token(from_cookie=False, session_token=token) if not valid_token_dict: return render_template( "problem.html", msg= "It was not possible to validate and finalize your login with the provided token." ) try: attribs = list_account_attributes(valid_token_dict['account'], valid_token_dict['vo']) accounts = identity.list_accounts_for_identity( valid_token_dict['identity'], identity_type) accvalues = "" for acc in accounts: accvalues += acc + " " accounts = accvalues[:-1] COOKIES.extend([{ 'key': 'x-rucio-auth-token', 'value': quote(token) }, { 'key': 'x-rucio-auth-type', 'value': quote(identity_type) }, { 'key': 'rucio-auth-token-created-at', 'value': str(long(time())) }, { 'key': 'rucio-available-accounts', 'value': quote(accounts) }, { 'key': 'rucio-account-attr', 'value': quote(dumps(attribs)) }, { 'key': 'rucio-selected-account', 'value': quote(valid_token_dict['account']) }, { 'key': 'rucio-selected-vo', 'value': quote(valid_token_dict['vo']) }]) if cookie_dict_extra: for key, value in cookie_dict_extra.items(): COOKIES.append({'key': key, 'value': value}) return redirect_to_last_known_url() except Exception: return render_template( "problem.html", msg= "It was not possible to validate and finalize your login with the provided token." )
def saml_authentication(method, rendered_tpl): """ Login with SAML :param method: method type, GET or POST :param rendered_tpl: page to be rendered """ attribs = None token = None js_token = "" js_account = "" def_account = None accounts = None cookie_accounts = None rucio_ui_version = version.version_string() policy = config_get('policy', 'permission') # Initialize variables for sending SAML request SAML_PATH = join(dirname(__file__), 'saml/') request = ctx.env data = dict(input()) req = prepare_webpy_request(request, data) auth = OneLogin_Saml2_Auth(req, custom_base_path=SAML_PATH) saml_user_data = cookies().get('saml-user-data') render = template.render(join(dirname(__file__), '../templates')) session_token = cookies().get('x-rucio-auth-token') validate_token = authentication.validate_auth_token(session_token) if method == "GET": # If user data is not present, redirect to IdP for authentication if not saml_user_data: return seeother(auth.login()) # If user data is present and token is valid, render the required page elif validate_token: js_token = __to_js('token', session_token) js_account = __to_js('account', def_account) return render.base(js_token, js_account, rucio_ui_version, policy, rendered_tpl) # If user data is present but token is not valid, create a new one saml_nameid = cookies().get('saml-nameid') accounts = identity.list_accounts_for_identity(saml_nameid, 'saml') cookie_accounts = accounts try: token = authentication.get_auth_token_saml( def_account, saml_nameid, 'webui', ctx.env.get('REMOTE_ADDR')).token except: return render.problem('Cannot get auth token') attribs = list_account_attributes(def_account) # write the token and account to javascript variables, that will be used in the HTML templates. js_token = __to_js('token', token) js_account = __to_js('account', def_account) set_cookies(token, cookie_accounts, attribs) return render.base(js_token, js_account, rucio_ui_version, policy, rendered_tpl) # If method is POST, check the received SAML response and redirect to home if valid auth.process_response() errors = auth.get_errors() if not errors: if auth.is_authenticated(): setcookie('saml-user-data', value=auth.get_attributes(), path='/') setcookie('saml-session-index', value=auth.get_session_index(), path='/') setcookie('saml-nameid', value=auth.get_nameid(), path='/') saml_nameid = auth.get_nameid() accounts = identity.list_accounts_for_identity(saml_nameid, 'saml') cookie_accounts = accounts # try to set the default account to the user account, if not available take the first account. def_account = accounts[0] for account in accounts: account_info = get_account_info(account) if account_info.account_type == AccountType.USER: def_account = account break selected_account = cookies().get('rucio-selected-account') if (selected_account): def_account = selected_account try: token = authentication.get_auth_token_saml( def_account, saml_nameid, 'webui', ctx.env.get('REMOTE_ADDR')).token except: return render.problem('Cannot get auth token') attribs = list_account_attributes(def_account) # write the token and account to javascript variables, that will be used in the HTML templates. js_token = __to_js('token', token) js_account = __to_js('account', def_account) set_cookies(token, cookie_accounts, attribs) return seeother("/") return render.problem("Not authenticated") return render.problem("Error while processing SAML")
def log_in(data, rendered_tpl): attribs = None token = None js_token = "" js_account = "" def_account = None accounts = None cookie_accounts = None rucio_ui_version = version.version_string() policy = config_get('policy', 'permission') render = template.render(join(dirname(__file__), '../templates')) # # try to get and check the rucio session token from cookie session_token = cookies().get('x-rucio-auth-token') validate_token = authentication.validate_auth_token(session_token) # if token is valid, render the requested page. if validate_token and not data: token = session_token js_token = __to_js('token', token) js_account = __to_js('account', def_account) return render.base(js_token, js_account, rucio_ui_version, policy, rendered_tpl) else: # if there is no session token or if invalid: get a new one. # if user tries to access a page through URL without logging in, then redirect to login page. if rendered_tpl: return render.login() # get all accounts for an identity. Needed for account switcher in UI. accounts = identity.list_accounts_for_identity(data.username, 'userpass') if len(accounts) == 0: return render.problem('No accounts for the given identity.') cookie_accounts = accounts # try to set the default account to the user account, if not available take the first account. def_account = accounts[0] for account in accounts: account_info = get_account_info(account) if account_info.account_type == AccountType.USER: def_account = account break selected_account = cookies().get('rucio-selected-account') if (selected_account): def_account = selected_account try: token = authentication.get_auth_token_user_pass( def_account, data.username, data.password.encode("ascii"), 'webui', ctx.env.get('REMOTE_ADDR')).token except: return render.problem('Cannot get auth token') attribs = list_account_attributes(def_account) # write the token and account to javascript variables, that will be used in the HTML templates. js_token = __to_js('token', token) js_account = __to_js('account', def_account) set_cookies(token, cookie_accounts, attribs) return seeother('/')