def logout(): """ - Revoke the tokens with Globus Auth. - Destroy the session state. - Redirect the user to the Globus Auth logout page. """ client = load_portal_client() # Revoke the tokens with Globus Auth for token, token_type in ( (token_info[ty], ty) # get all of the token info dicts for token_info in session['tokens'].values() # cross product with the set of token types for ty in ('access_token', 'refresh_token') # only where the relevant token is actually present if token_info[ty] is not None): client.oauth2_revoke_token( token, additional_params={'token_type_hint': token_type}) # Destroy the session state session.clear() redirect_uri = url_for('home', _external=True) ga_logout_url = [] ga_logout_url.append(app.config['GLOBUS_AUTH_LOGOUT_URI']) ga_logout_url.append('?client={}'.format(app.config['PORTAL_CLIENT_ID'])) ga_logout_url.append('&redirect_uri={}'.format(redirect_uri)) ga_logout_url.append('&redirect_name=Globus Sample Data Portal') # Redirect the user to the Globus Auth logout page return redirect(''.join(ga_logout_url))
def browse(dataset_id=None, endpoint_id=None, endpoint_path=None): """ - Get list of files for the selected dataset or endpoint ID/path - Return a list of files to a browse view The target template (browse.jinja2) expects an `endpoint_uri` (if available for the endpoint), `target` (either `"dataset"` or `"endpoint"`), and 'file_list' (list of dictionaries) containing the following information about each file in the result: {'name': 'file name', 'size': 'file size', 'id': 'file uri/path'} If you want to display additional information about each file, you must add those keys to the dictionary and modify the browse.jinja2 template accordingly. """ assert bool(dataset_id) != bool(endpoint_id and endpoint_path) if dataset_id: try: dataset = next(ds for ds in datasets if ds['id'] == dataset_id) except StopIteration: abort(404) endpoint_id = app.config['DATASET_ENDPOINT_ID'] endpoint_path = app.config['DATASET_ENDPOINT_BASE'] + dataset['path'] else: endpoint_path = '/' + endpoint_path transfer = TransferClient(authorizer=RefreshTokenAuthorizer( session['tokens']['transfer.api.globus.org']['refresh_token'], load_portal_client())) try: transfer.endpoint_autoactivate(endpoint_id) listing = transfer.operation_ls(endpoint_id, path=endpoint_path) except TransferAPIError as err: flash('Error [{}]: {}'.format(err.code, err.message)) return redirect(url_for('transfer')) file_list = [e for e in listing if e['type'] == 'file'] ep = transfer.get_endpoint(endpoint_id) https_server = ep['https_server'] endpoint_uri = https_server + endpoint_path if https_server else None webapp_xfer = 'https://www.globus.org/app/transfer?' + \ urlencode(dict(origin_id=endpoint_id, origin_path=endpoint_path)) return render_template( 'browse.jinja2', endpoint_uri=endpoint_uri, target="dataset" if dataset_id else "endpoint", description=(dataset['name'] if dataset_id else ep['display_name']), file_list=file_list, webapp_xfer=webapp_xfer)
def authcallback(): """Handles the interaction with Globus Auth.""" # If we're coming back from Globus Auth in an error state, the error # will be in the "error" query string parameter. if 'error' in request.args: flash("You could not be logged into the portal: " + request.args.get('error_description', request.args['error'])) return redirect(url_for('home')) # Set up our Globus Auth/OAuth2 state redirect_uri = url_for('authcallback', _external=True) client = load_portal_client() client.oauth2_start_flow(redirect_uri, refresh_tokens=True, requested_scopes=app.config['USER_SCOPES']) # If there's no "code" query string parameter, we're in this route # starting a Globus Auth login flow. if 'code' not in request.args: additional_authorize_params = ({ 'signup': 1 } if request.args.get('signup') else {}) auth_uri = client.oauth2_get_authorize_url( additional_params=additional_authorize_params) return redirect(auth_uri) else: # If we do have a "code" param, we're coming back from Globus Auth # and can start the process of exchanging an auth code for a token. code = request.args.get('code') tokens = client.oauth2_exchange_code_for_tokens(code) id_token = tokens.decode_id_token(client) session.update( tokens=tokens.by_resource_server, is_authenticated=True, name=id_token.get('name', ''), email=id_token.get('email', ''), institution=id_token.get('organization', ''), primary_username=id_token.get('preferred_username'), primary_identity=id_token.get('sub'), ) profile = database.load_profile(session['primary_identity']) if profile: name, email, institution = profile session['name'] = name session['email'] = email session['institution'] = institution else: return redirect(url_for('profile', next=url_for('transfer'))) return redirect(url_for('transfer'))
def submit_transfer(): """ - Take the data returned by the Browse Endpoint helper page and make a Globus transfer request. - Send the user to the transfer status page with the task id from the transfer. """ browse_endpoint_form = request.form selected = session['form']['datasets'] filtered_datasets = [ds for ds in datasets if ds['id'] in selected] transfer_tokens = session['tokens']['transfer.api.globus.org'] authorizer = RefreshTokenAuthorizer( transfer_tokens['refresh_token'], load_portal_client(), access_token=transfer_tokens['access_token'], expires_at=transfer_tokens['expires_at_seconds']) transfer = TransferClient(authorizer=authorizer) source_endpoint_id = app.config['DATASET_ENDPOINT_ID'] source_endpoint_base = app.config['DATASET_ENDPOINT_BASE'] destination_endpoint_id = browse_endpoint_form['endpoint_id'] destination_folder = browse_endpoint_form.get('folder[0]') transfer_data = TransferData(transfer_client=transfer, source_endpoint=source_endpoint_id, destination_endpoint=destination_endpoint_id, label=browse_endpoint_form.get('label')) for ds in filtered_datasets: source_path = source_endpoint_base + ds['path'] dest_path = browse_endpoint_form['path'] if destination_folder: dest_path += destination_folder + '/' dest_path += ds['name'] + '/' transfer_data.add_item(source_path=source_path, destination_path=dest_path, recursive=True) transfer.endpoint_autoactivate(source_endpoint_id) transfer.endpoint_autoactivate(destination_endpoint_id) task_id = transfer.submit_transfer(transfer_data)['task_id'] flash('Transfer request submitted successfully. Task ID: ' + task_id) return (redirect(url_for('transfer_status', task_id=task_id)))
def transfer_status(task_id): """ Call Globus to get status/details of transfer with task_id. The target template (tranfer_status.jinja2) expects a Transfer API 'task' object. 'task_id' is passed to the route in the URL as 'task_id'. """ transfer = TransferClient(authorizer=RefreshTokenAuthorizer( session['tokens']['transfer.api.globus.org']['refresh_token'], load_portal_client())) task = transfer.get_task(task_id) return render_template('transfer_status.jinja2', task=task)
def authcallback(): """Handles the interaction with Globus Auth.""" # If we're coming back from Globus Auth in an error state, the error # will be in the "error" query string parameter. if 'error' in request.args: flash("You could not be logged into the portal: " + request.args.get('error_description', request.args['error']), 'warning') return redirect(url_for('home')) # Set up our Globus Auth/OAuth2 state redirect_uri = url_for('authcallback', _external=True) client = load_portal_client() client.oauth2_start_flow(redirect_uri, refresh_tokens=True) # If there's no "code" query string parameter, we're in this route # starting a Globus Auth login flow. if 'code' not in request.args: # print("SIGNUP: {} ".format(request.args)) next_url = get_safe_redirect() additional_authorize_params = ( {'signup': 1} if request.args.get('signup') else {'next': next_url}) auth_uri = client.oauth2_get_authorize_url( additional_params=additional_authorize_params) print("ADDITIONAL AUTHORIZED PARAMS: {}".format(additional_authorize_params)) print("NEXT URL: {}".format(next_url)) return redirect(auth_uri) else: # If we do have a "code" param, we're coming back from Globus Auth # and can start the process of exchanging an auth code for a token. print("GOT OUT OF AUTH URI LOOP") next_url = get_safe_redirect() print("NEXT URL: {}".format(next_url)) code = request.args.get('code') tokens = client.oauth2_exchange_code_for_tokens(code) id_token = tokens.decode_id_token(client) session.update( tokens=tokens.by_resource_server, is_authenticated=True, name=id_token.get('name', ''), email=id_token.get('email', ''), institution=id_token.get('organization', ''), primary_username=id_token.get('preferred_username'), primary_identity=id_token.get('sub'), ) access_token = session['tokens']['auth.globus.org']['access_token'] token_introspect = client.oauth2_token_introspect( token=access_token, include='identity_set') identity_set = token_introspect.data['identity_set'] profile = None for identity in identity_set: query = {'token': ciconnect_api_token, 'globus_id': identity} try: r = requests.get( ciconnect_api_endpoint + '/v1alpha1/find_user', params=query) # r = get_user_info(session) if r.status_code == requests.codes.ok: user_info = r.json() # user_access_token = user_info['metadata']['access_token'] unix_name = user_info['metadata']['unix_name'] profile = requests.get( ciconnect_api_endpoint + '/v1alpha1/users/' + unix_name, params=query) profile = profile.json() session['primary_identity'] = identity except: print("NO PROFILE FOUND WITH IDENTITY: {}".format(identity)) connect_keynames = {'atlas': {'name': 'atlas-connect', 'display_name': 'Atlas Connect', 'unix_name': 'root.atlas'}, 'cms': {'name': 'cms-connect', 'display_name': 'CMS Connect', 'unix_name': 'root.cms'}, 'duke': {'name': 'duke-connect', 'display_name': 'Duke Connect', 'unix_name': 'root.duke'}, 'uchicago': {'name': 'uchicago-connect', 'display_name': 'UChicago Connect', 'unix_name': 'root.uchicago'}, 'spt': {'name': 'spt-connect', 'display_name': 'SPT Connect', 'unix_name': 'root.spt'}, 'psdconnect': {'name': 'psd-connect', 'display_name': 'PSD Connect', 'unix_name': 'root.uchicago'}, 'snowmass21': {'name': 'snowmass21-connect', 'display_name': 'Snowmass21 Connect', 'unix_name': 'root.snowmass21'}, 'localhost': {'name': 'snowmass21-connect', 'display_name': 'Snowmass21 Connect', 'unix_name': 'root.snowmass21'}} url_host = request.host try: referrer = urlparse(request.referrer) # print("REFERRER: {}".format(referrer)) queries = parse_qs(referrer.query) # print("QUERIES: {}".format(queries)) redirect_uri = queries['redirect_uri'][0] # print("REDIRECT URI: {}".format(redirect_uri)) next_url = queries['next'][0] # print("AFTER QUERIES NEXT URL: {}".format(next_url)) except: next_url = '/' if 'ci-connect' in url_host: session['url_host'] = {'name': 'ci-connect', 'display_name': 'CI Connect', 'unix_name': 'root'} for key, value in list(connect_keynames.items()): if key in url_host: session['url_host'] = value if profile: profile = profile['metadata'] session['name'] = profile['name'] session['email'] = profile['email'] session['phone'] = profile['phone'] session['institution'] = profile['institution'] session['unix_name'] = profile['unix_name'] session['url_root'] = request.url_root # session['url_host'] = (request.host).split(':')[0] session['admin'] = admin_check(profile['unix_name']) else: session['url_root'] = request.url_root return redirect(url_for('create_profile', next=url_for('profile'))) # print("FINAL NEXT URL: {}".format(next_url)) if next_url == '/': return redirect(url_for('profile')) else: return redirect(next_url)
def browse(dataset_id=None, endpoint_id=None, endpoint_path=None): """ - Get list of files for the selected dataset or endpoint ID/path - Return a list of files to a browse view The target template (browse.jinja2) expects an `endpoint_uri` (if available for the endpoint), `target` (either `"dataset"` or `"endpoint"`), and 'file_list' (list of dictionaries) containing the following information about each file in the result: {'name': 'file name', 'size': 'file size', 'id': 'file uri/path'} If you want to display additional information about each file, you must add those keys to the dictionary and modify the browse.jinja2 template accordingly. """ if request.method == 'GET': assert bool(dataset_id) != bool(endpoint_id and endpoint_path) if dataset_id: try: dataset = next(ds for ds in datasets if ds['id'] == dataset_id) except StopIteration: abort(404) endpoint_id = app.config['DATASET_ENDPOINT_ID'] endpoint_path = app.config['DATASET_ENDPOINT_BASE'] + dataset['path'] else: endpoint_path = '/' + endpoint_path transfer_tokens = session['tokens']['transfer.api.globus.org'] authorizer = RefreshTokenAuthorizer( transfer_tokens['refresh_token'], load_portal_client(), access_token=transfer_tokens['access_token'], expires_at=transfer_tokens['expires_at_seconds']) transfer = TransferClient(authorizer=authorizer) try: transfer.endpoint_autoactivate(endpoint_id) listing = transfer.operation_ls(endpoint_id, path=endpoint_path) except TransferAPIError as err: flash('Error [{}]: {}'.format(err.code, err.message)) return redirect(url_for('browse')) file_list = [e for e in listing if e['type'] == 'file'] ep = transfer.get_endpoint(endpoint_id) https_server = ep['https_server'] endpoint_uri = https_server + endpoint_path if https_server else None webapp_xfer = 'https://app.globus.org/file-manager?' + \ urlencode(dict(origin_id=endpoint_id, origin_path=endpoint_path)) #print("endpintURL == " + endpoint_uri) return render_template('browse.jinja2', endpoint_uri=endpoint_uri, target="dataset" if dataset_id else "endpoint", description=(dataset['name'] if dataset_id else ep['display_name']), mypath=(dataset['path'] if dataset_id else None), myid=(dataset['id'] if dataset_id else None), file_list=file_list, webapp_xfer=webapp_xfer) if request.method == 'POST': if not request.form.get('file'): flash('Please select at least one file.') return redirect(url_for('browse')) params = { 'method': 'POST', 'action': url_for('submit_transfer', _external=True, _scheme='https'), 'filelimit': 0, 'folderlimit': 1 } browse_endpoint = 'https://app.globus.org/file-manager?{}' \ .format(urlencode(params)) session['form'] = { 'dirselect': False, 'datasets': request.form.getlist('file'), 'path': request.form.getlist('path'), 'id': request.form.getlist('id') } return redirect(browse_endpoint)
def authcallback(): """Handles the interaction with Agave Auth.""" # If we're coming back from Agave Auth in an error state, the error # will be in the "error" query string parameter. if 'error' in request.args: flash("You could not be logged into the portal: " + request.args.get('error_description', request.args['error'])) return redirect(url_for('home')) redirect_uri = url_for('authcallback', _external=True) client = load_portal_client(redirect_uri) auth_uri = client.step1_get_authorize_url() print 'auth uri', auth_uri # If there's no "code" query string parameter, we're in this route # starting a Agave Auth login flow. if 'code' not in request.args: auth_uri = client.step1_get_authorize_url() return redirect(auth_uri) else: # If we do have a "code" param, we're coming back from Agave Auth # and can start the process of exchanging an auth code for a token. code = request.args.get('code') print 'code', code tokens = client.step2_exchange(code) tokens.revoke_uri = app.config['REVOKE_URL'] token_json = tokens.to_json() print 'token json', token_json # user_profile = get_profile(tokens.access_token) user_profile = get_result(app.config['PROFILE_URL_BASE'], 'me', tokens.access_token) if user_profile[0]: print 'username', user_profile[1]['username'] else: flash("User profile was not retrieved. Error:" + user_profile[1]) session.update(tokens=tokens.to_json(), is_authenticated=True, name=user_profile[1]['full_name'], email=user_profile[1]['email'], institution='', primary_identity=user_profile[1]['username']) profile = database.load_profile(session['primary_identity']) if profile: name, email, institution = profile session['name'] = name session['email'] = email session['institution'] = institution # handle_permission(session['primary_identity']) else: # take the user profile and save it into the database database.save_profile(identity_id=session['primary_identity'], name=session['name'], email=session['email'], institution=session['institution']) # set up the permission for new user handle_permission(session['primary_identity']) return redirect(url_for('profile', next=url_for('submit_job'))) return redirect(url_for('submit_job'))