def key(key): # get the key from URL if not re.match("[0-9a-fA-F]+", key): raise Exception("Key id {0} is not a valid key".format(key)) # check for the key file in the credmon directory cred_dir = get_cred_dir() key_path = os.path.join(cred_dir, key) if not os.path.exists(key_path): raise Exception("Key file {0} doesn't exist".format(key_path)) # read in the key file, which is a list of classads providers = {} session['logged_in'] = False print('Creating new session from {0}'.format(key_path)) with open(key_path, 'r') as key_file: # store the path to the key file since it will be accessed later in the session session['key_path'] = key_path # initialize data for each token provider for provider_ad in classad.parseAds(key_file): provider = get_provider_str(provider_ad['Provider'], provider_ad.get('Handle', '')) providers[provider] = {} providers[provider]['logged_in'] = False if 'Scopes' in provider_ad: providers[provider]['requested_scopes'] = [ s.rstrip().lstrip() for s in provider_ad['Scopes'].split(',') ] if 'Audience' in provider_ad: providers[provider]['requested_resource'] = provider_ad[ 'Audience'] # the local username is global to the session, just grab it from the last classad session['local_username'] = provider_ad['LocalUser'] session['providers'] = providers print('New session started for user {0}'.format(session['local_username'])) return render_template('index.html')
def __init__(self, cred_dir = None): self.cred_dir = get_cred_dir(cred_dir) self.log = self.get_logger()
def oauth_return(provider): """ Returning from OAuth provider """ # get the provider name from the outgoing_provider set in oauth_login() provider = session.pop('outgoing_provider', get_provider_str(provider, '')) if not (provider in session['providers']): raise Exception( "Provider {0} not in list of providers".format(provider)) provider_ad = get_provider_ad(provider, session['key_path']) # gather information from the key file classad client_id = provider_ad['ClientId'] redirect_uri = provider_ad['ReturnUrl'] state = session['providers'][provider]['state'] oauth = OAuth2Session(client_id, state=state, redirect_uri=redirect_uri) # convert http url to https if needed if request.url.startswith("http://"): updated_url = request.url.replace('http://', 'https://', 1) else: updated_url = request.url # fetch token client_secret = provider_ad['ClientSecret'] token_url = provider_ad['TokenUrl'] token = oauth.fetch_token(token_url, authorization_response=updated_url, client_secret=client_secret, method='POST') print('Got {0} token for user {1}'.format(provider, session['local_username'])) # get user info if available # todo: make this more generic try: get_user_info = oauth.get(provider_ad['UserUrl']) user_info = get_user_info.json() if 'login' in user_info: # box session['providers'][provider]['username'] = user_info['login'] elif 'sub' in user_info: # scitokens/jwt session['providers'][provider]['username'] = user_info['sub'] else: session['providers'][provider]['username'] = '******' except ValueError: session['providers'][provider]['username'] = '******' # split off the refresh token from the access token if it exists try: refresh_token_string = token.pop('refresh_token') except KeyError: # no refresh token use_refresh_token = False refresh_token_string = '' else: use_refresh_token = True refresh_token = {'refresh_token': refresh_token_string} # create a metadata file for refreshing the token metadata = { 'client_id': client_id, 'client_secret': client_secret, 'token_url': token_url, 'use_refresh_token': use_refresh_token } # atomically write the tokens to the cred dir cred_dir = get_cred_dir() user_cred_dir = os.path.join(cred_dir, session['local_username']) if not os.path.isdir(user_cred_dir): os.makedirs(user_cred_dir) refresh_token_path = os.path.join(user_cred_dir, provider.replace(' ', '_') + '.top') access_token_path = os.path.join(user_cred_dir, provider.replace(' ', '_') + '.use') metadata_path = os.path.join(user_cred_dir, provider.replace(' ', '_') + '.meta') # write tokens to tmp files (tmp_fd, tmp_access_token_path) = tempfile.mkstemp(dir=user_cred_dir) with os.fdopen(tmp_fd, 'w') as f: json.dump(token, f) (tmp_fd, tmp_refresh_token_path) = tempfile.mkstemp(dir=user_cred_dir) with os.fdopen(tmp_fd, 'w') as f: json.dump(refresh_token, f) (tmp_fd, tmp_metadata_path) = tempfile.mkstemp(dir=user_cred_dir) with os.fdopen(tmp_fd, 'w') as f: json.dump(metadata, f) # (over)write token files try: atomic_rename(tmp_access_token_path, access_token_path) atomic_rename(tmp_refresh_token_path, refresh_token_path) atomic_rename(tmp_metadata_path, metadata_path) except OSError as e: sys.stderr.write(e) # mark provider as logged in session['providers'][provider]['logged_in'] = True # check if other providers are logged in session['logged_in'] = True for provider in session['providers']: if session['providers'][provider]['logged_in'] == False: session['logged_in'] = False return redirect("/")
def oauth_return(provider): """ Returning from OAuth provider """ # get the provider name from the outgoing_provider set in oauth_login() provider = session.pop('outgoing_provider', get_provider_str(provider, '')) if not ('providers' in session): sys.stderr.write( '"providers" key was not found in session object: {0}\n'.format( session)) raise KeyError( 'Key "providers" was not found in session object. This session is invalid.' ) if not (provider in session['providers']): sys.stderr.write( 'key {0} was not found in session["providers"] dict: {1}\n'.format( provider, session)) raise KeyError( "Provider {0} was not found in list of providers. This session is invalid." .format(provider)) provider_ad = get_provider_ad(provider, session['key_path']) # gather information from the key file classad client_id = provider_ad['ClientId'] redirect_uri = provider_ad['ReturnUrl'] state = session['providers'][provider]['state'] oauth = OAuth2Session(client_id, state=state, redirect_uri=redirect_uri) # convert http url to https if needed if request.url.startswith("http://"): updated_url = request.url.replace('http://', 'https://', 1) else: updated_url = request.url # fetch token client_secret = provider_ad['ClientSecret'] token_url = provider_ad['TokenUrl'] token = oauth.fetch_token(token_url, authorization_response=updated_url, client_secret=client_secret, method='POST', **fetch_token_kwargs) print('Got {0} token for user {1}'.format(provider, session['local_username'])) # get user info if available try: (user_url, user_field_keys) = api_endpoints.user(provider_ad['TokenUrl']) if user_url is not None: get_user_info = oauth.get(user_url) user_info = get_user_info.json() for user_field in user_field_keys: username = user_info[user_field] username = str(username) session['providers'][provider]['username'] = username elif 'sub' in token: # scitokens/jwt session['providers'][provider]['username'] = token['sub'] elif 'name' in token: # scitokens/jwt session['providers'][provider]['username'] = token['name'] else: session['providers'][provider]['username'] = '******' except ValueError: session['providers'][provider]['username'] = '******' # split off the refresh token from the access token if it exists try: refresh_token_string = token.pop('refresh_token') except KeyError: # no refresh token use_refresh_token = False refresh_token_string = '' else: use_refresh_token = True refresh_token = {'refresh_token': refresh_token_string} # create a metadata file for refreshing the token metadata = { 'client_id': client_id, 'client_secret': client_secret, 'token_url': token_url, 'use_refresh_token': use_refresh_token } # atomically write the tokens to the cred dir cred_dir = get_cred_dir() user_cred_dir = os.path.join(cred_dir, session['local_username']) if not os.path.isdir(user_cred_dir): os.makedirs(user_cred_dir) refresh_token_path = os.path.join(user_cred_dir, provider.replace(' ', '_') + '.top') access_token_path = os.path.join(user_cred_dir, provider.replace(' ', '_') + '.use') metadata_path = os.path.join(user_cred_dir, provider.replace(' ', '_') + '.meta') # write tokens to tmp files try: (tmp_fd, tmp_access_token_path) = tempfile.mkstemp(dir=user_cred_dir) except OSError as oe: print( "Failed to create temporary file in the user credential directory: {0}" .format(str(oe))) raise with os.fdopen(tmp_fd, 'w') as f: json.dump(token, f) (tmp_fd, tmp_refresh_token_path) = tempfile.mkstemp(dir=user_cred_dir) with os.fdopen(tmp_fd, 'w') as f: json.dump(refresh_token, f) (tmp_fd, tmp_metadata_path) = tempfile.mkstemp(dir=user_cred_dir) with os.fdopen(tmp_fd, 'w') as f: json.dump(metadata, f) # (over)write token files try: atomic_rename(tmp_access_token_path, access_token_path) atomic_rename(tmp_refresh_token_path, refresh_token_path) atomic_rename(tmp_metadata_path, metadata_path) except OSError as e: sys.stderr.write('{0}\n'.format(str(e))) # mark provider as logged in session['providers'][provider]['logged_in'] = True # check if other providers are logged in session['logged_in'] = True for provider in session['providers']: if session['providers'][provider]['logged_in'] == False: session['logged_in'] = False # cleanup key file if logged in if session['logged_in']: print('Attempting to remove session file {0}'.format( session['key_path'])) try: os.unlink(session['key_path']) except OSError as e: sys.stderr.write('Could not remove session file {0}: {1}\n'.format( session['key_path'], str(e))) return redirect("/")