Skip to content

Commit

Permalink
Removed white spaces between parenthesis and arguments.
Browse files Browse the repository at this point in the history
  • Loading branch information
VJalili committed Aug 18, 2017
1 parent 7ae287d commit f622206
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 92 deletions.
54 changes: 27 additions & 27 deletions lib/galaxy/authnz/__init__.py
Expand Up @@ -13,15 +13,15 @@
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import ParseError

log = logging.getLogger( __name__ )
log = logging.getLogger(__name__)


class IdentityProvider( object ):
class IdentityProvider(object):
"""
OpenID Connect Identity Provider abstract interface.
"""

def __init__( self, config ):
def __init__(self, config):
"""
Initialize the identity provider using the provided configuration,
and raise a ParseError (or any more related specific exception) in
Expand All @@ -35,7 +35,7 @@ def __init__( self, config ):
"""
raise NotImplementedError()

def authenticate( self, trans ):
def authenticate(self, trans):
"""Runs for authentication process. Checks the database if a
valid identity exists in the database; if yes, then the user
is authenticated, if not, it generates a provider-specific
Expand All @@ -49,7 +49,7 @@ def authenticate( self, trans ):
"""
raise NotImplementedError()

def callback( self, state_token, authz_code, trans ):
def callback(self, state_token, authz_code, trans):
"""
Handles authentication call-backs from identity providers.
This process maps `state-token` to a user
Expand All @@ -68,50 +68,50 @@ def callback( self, state_token, authz_code, trans ):
raise NotImplementedError()


class AuthnzManager( object ):
class AuthnzManager(object):

def __init__( self, config ):
def __init__(self, config):
"""
:type config: string
:param config: sets the path for OAuth2.0 configuration
file (e.g., OAuth2_config.xml).
"""
self._parse_config( config )
self._parse_config(config)

def _parse_config( self, config ):
def _parse_config(self, config):
self.providers = {}
try:
tree = ET.parse( config )
tree = ET.parse(config)
root = tree.getroot()
if root.tag != 'OAuth2.0':
raise ParseError( "The root element in OAuth2.0 config xml file is expected to be `OAuth2.0`, "
"found `{}` instead -- unable to continue.".format( root.tag ) )
raise ParseError("The root element in OAuth2.0 config xml file is expected to be `OAuth2.0`, "
"found `{}` instead -- unable to continue.".format(root.tag))
for child in root:
if child.tag != 'provider':
log.error( "Expect a node with `provider` tag, found a node with `{}` tag instead; "
"skipping the node.".format( child.tag ) )
log.error("Expect a node with `provider` tag, found a node with `{}` tag instead; "
"skipping the node.".format(child.tag))
continue
if 'name' not in child.attrib:
log.error( "Could not find a node attribute 'name'; skipping the node '{}'.".format( child.tag ) )
log.error("Could not find a node attribute 'name'; skipping the node '{}'.".format(child.tag))
continue
provider = child.get( 'name' )
provider = child.get('name')
try:
if provider == 'Google':
from .oidc_idp_google import OIDCIdPGoogle
self.providers[ provider ] = OIDCIdPGoogle( child )
self.providers[provider] = OIDCIdPGoogle(child)
except ParseError:
log.error( "Could not initialize `{}` identity provider; skipping this node.".format( provider ) )
log.error("Could not initialize `{}` identity provider; skipping this node.".format(provider))
continue
if len( self.providers ) == 0:
raise ParseError( "No valid provider configuration parsed." )
if len(self.providers) == 0:
raise ParseError("No valid provider configuration parsed.")
except ImportError:
raise
except ParseError as e:
raise ParseError( "Invalid configuration at `{}`: {} -- unable to continue.".format( config, e.message ) )
raise ParseError("Invalid configuration at `{}`: {} -- unable to continue.".format(config, e.message))
except Exception:
raise ParseError( "Malformed OAuth2.0 Configuration XML -- unable to continue." )
raise ParseError("Malformed OAuth2.0 Configuration XML -- unable to continue.")

def authenticate( self, provider, trans ):
def authenticate(self, provider, trans):
"""
:type provider: string
:param provider: set the name of the identity provider to be
Expand All @@ -126,13 +126,13 @@ def authenticate( self, provider, trans ):
except:
raise
else:
log.error( "The provider '{}' is not a recognized and expected provider.".format( provider ) )
log.error("The provider '{}' is not a recognized and expected provider.".format(provider))

def callback( self, provider, state_token, authz_code, trans ):
def callback(self, provider, state_token, authz_code, trans):
if provider in self.providers:
try:
return self.providers[ provider ].callback( state_token, authz_code, trans )
return self.providers[provider].callback(state_token, authz_code, trans)
except:
raise
else:
raise NameError( "The provider '{}' is not a recognized and expected provider.".format( provider ) )
raise NameError("The provider '{}' is not a recognized and expected provider.".format(provider))
92 changes: 46 additions & 46 deletions lib/galaxy/authnz/oidc_idp_google.py
Expand Up @@ -17,97 +17,97 @@
from oauth2client import client, GOOGLE_TOKEN_URI, GOOGLE_REVOKE_URI


log = logging.getLogger( __name__ )
log = logging.getLogger(__name__)


class OIDCIdPGoogle( IdentityProvider ):
def __init__( self, config ):
client_secret_file = config.find( 'client_secret_file' )
class OIDCIdPGoogle(IdentityProvider):
def __init__(self, config):
client_secret_file = config.find('client_secret_file')
if client_secret_file is None:
log.error( "Did not find `client_secret_file` key in the configuration; skipping the node '{}'."
.format(config.get( 'name' ) ) )
log.error("Did not find `client_secret_file` key in the configuration; skipping the node '{}'."
.format(config.get('name')))
raise ParseError
redirect_uri = config.find( 'redirect_uri' )
redirect_uri = config.find('redirect_uri')
if redirect_uri is None:
log.error( "Did not find `redirect_uri` key in the configuration; skipping the node '{}'."
.format(config.get( 'name' ) ) )
log.error("Did not find `redirect_uri` key in the configuration; skipping the node '{}'."
.format(config.get('name')))
raise ParseError
self.provider = 'Google'
self.client_secret_file = client_secret_file.text
self.redirect_uri = redirect_uri.text

def _redirect_uri( self, trans ):
def _redirect_uri(self, trans):
# Prepare authentication flow.
flow = client.flow_from_clientsecrets(
self.client_secret_file,
scope=[ 'openid', 'email', 'profile' ],
redirect_uri=self.redirect_uri )
flow.params[ 'access_type' ] = 'offline' # This asks google to send back a `refresh token`.
flow.params[ 'prompt' ] = 'consent'
scope=['openid', 'email', 'profile'],
redirect_uri=self.redirect_uri)
flow.params['access_type'] = 'offline' # This asks google to send back a `refresh token`.
flow.params['prompt'] = 'consent'

# Include the following parameter only if we need 'incremental authorization',
# however, current application scenario does not seem to require it.
# flow.params[ 'include_granted_scopes' ] = "true"

# A anti-forgery state token. This token will be sent back from Google upon user authentication.
state_token = hashlib.sha256( str( trans.user.username ) ).hexdigest()
flow.params[ 'state' ] = state_token
user_oauth2 = trans.app.model.UserOAuth2( trans.user.id, self.provider, state_token )
trans.sa_session.add( user_oauth2 )
state_token = hashlib.sha256(str(trans.user.username)).hexdigest()
flow.params['state'] = state_token
user_oauth2 = trans.app.model.UserOAuth2(trans.user.id, self.provider, state_token)
trans.sa_session.add(user_oauth2)
trans.sa_session.flush()
return flow.step1_get_authorize_url()

def _refresh_access_token( self, trans, authn_record ): # TODO: handle `Bad Request` error
with open( self.client_secret_file ) as file:
client_secret = json.load( file )[ 'web' ]
def _refresh_access_token(self, trans, authn_record): # TODO: handle `Bad Request` error
with open(self.client_secret_file) as file:
client_secret = json.load(file)['web']
credentials = client.OAuth2Credentials(
None, client_secret[ 'client_id' ], client_secret[ 'client_secret' ],
authn_record.refresh_token, None, GOOGLE_TOKEN_URI, None, revoke_uri = GOOGLE_REVOKE_URI )
credentials.refresh( httplib2.Http() )
None, client_secret['client_id'], client_secret['client_secret'],
authn_record.refresh_token, None, GOOGLE_TOKEN_URI, None, revoke_uri=GOOGLE_REVOKE_URI)
credentials.refresh(httplib2.Http())
access_token = credentials.get_access_token()
authn_record.id_token = credentials.id_token_jwt
authn_record.access_token = access_token[ 'access_token' ]
authn_record.expiration_date = datetime.now() + timedelta( seconds = access_token[ 'expires_in' ] )
authn_record.access_token = access_token['access_token']
authn_record.expiration_date = datetime.now() + timedelta(seconds=access_token['expires_in'])
trans.sa_session.commit()
trans.sa_session.flush()

def authenticate( self, trans ):
def authenticate(self, trans):
query_result = trans.sa_session.query(
trans.app.model.UserOAuth2).filter(
trans.app.model.UserOAuth2.table.c.user_id == trans.user.id).filter(
trans.app.model.UserOAuth2.table.c.provider == self.provider )
trans.app.model.UserOAuth2.table.c.provider == self.provider)
if query_result.count() == 1:
authn_record = query_result.first()
if authn_record.expiration_date is not None \
and authn_record.expiration_date < datetime.now() + timedelta( minutes = 15 ):
self._refresh_access_token( trans, authn_record )
and authn_record.expiration_date < datetime.now() + timedelta(minutes=15):
self._refresh_access_token(trans, authn_record)
elif query_result.count() > 1:
log.critical(
"Found `{}` records for user `{}` authentication against `{}` identity provider; at most one "
"record should exist. Now deleting all the `{}` records and prompt re-authentication.".format(
query_result.count(), trans.user.username, self.provider, query_result.count() ) )
query_result.count(), trans.user.username, self.provider, query_result.count()))
for record in query_result:
trans.sa_session.delete( record )
trans.sa_session.delete(record)
trans.sa_session.flush()
return self._redirect_uri( trans )
return self._redirect_uri(trans)

def callback( self, state_token, authz_code, trans ):
query_result = trans.sa_session.query(trans.app.model.UserOAuth2 ).filter(
trans.app.model.UserOAuth2.table.c.provider == self.provider ).filter(
trans.app.model.UserOAuth2.table.c.state_token == state_token )
def callback(self, state_token, authz_code, trans):
query_result = trans.sa_session.query(trans.app.model.UserOAuth2).filter(
trans.app.model.UserOAuth2.table.c.provider == self.provider).filter(
trans.app.model.UserOAuth2.table.c.state_token == state_token)
if query_result.count() > 1:
log.critical(
"Found `{}` records for user `{}` authentication against `{}` identity provider; at most one "
"record should exist. Now deleting all the `{}` records and prompt re-authentication.".format(
query_result.count(), trans.user.username, self.provider, query_result.count() ) )
query_result.count(), trans.user.username, self.provider, query_result.count()))
for record in query_result:
trans.sa_session.delete( record )
trans.sa_session.delete(record)
trans.sa_session.flush()
return False # results in re-authentication.
if query_result.count() == 0:
log.critical( "Found `0` records for user `{}` authentication against `{}` identity provider;"
" an improperly initiated authentication flow. Now prompting re-authentication.".format(
trans.user.username, self.provider ) )
trans.user.username, self.provider))
return False # results in re-authentication.
# A callback should follow a request from Galaxy; and if a request was (successfully) made by Galaxy,
# the a record in the `galaxy_user_oauth2` table with valid `user_id`, `provider`, and `state_token`
Expand All @@ -118,19 +118,19 @@ def callback( self, state_token, authz_code, trans ):
# Prepare authentication flow.
flow = client.flow_from_clientsecrets(
self.client_secret_file,
scope=[ 'openid', 'email', 'profile' ],
redirect_uri = self.redirect_uri )
scope=['openid', 'email', 'profile'],
redirect_uri = self.redirect_uri)
# Exchanges an authorization code for OAuth2Credentials.
# The credentials object holds refresh and access tokens
# that authorize access to a single user's data.
credentials = flow.step2_exchange( authz_code )
credentials = flow.step2_exchange(authz_code)
access_token_info = credentials.get_access_token()
user_oauth_record = query_result.first()
user_oauth_record.id_token = credentials.id_token_jwt
user_oauth_record.refresh_token = credentials.refresh_token
user_oauth_record.expiration_date = datetime.now() + timedelta( seconds = access_token_info.expires_in )
user_oauth_record.expiration_date = datetime.now() + timedelta(seconds=access_token_info.expires_in)
user_oauth_record.access_token = access_token_info.access_token
trans.sa_session.flush()
log.debug( "User `{}` authentication against `Google` identity provider is successfully saved."
.format( trans.user.username ) )
log.debug("User `{}` authentication against `Google` identity provider is successfully saved."
.format(trans.user.username))
return True
4 changes: 2 additions & 2 deletions lib/galaxy/model/__init__.py
Expand Up @@ -4936,8 +4936,8 @@ def __init__( self, user=None, session=None, openid=None ):
self.openid = openid


class UserOAuth2( object ):
def __init__( self, user_id, provider, state_token, id_token=None, refresh_token=None, expiration_date=None, access_token=None ):
class UserOAuth2(object):
def __init__(self, user_id, provider, state_token, id_token=None, refresh_token=None, expiration_date=None, access_token=None):
self.user_id = user_id
self.provider = provider
self.state_token = state_token
Expand Down
24 changes: 12 additions & 12 deletions lib/galaxy/model/mapping.py
Expand Up @@ -92,14 +92,14 @@

model.UserOAuth2.table = Table(
"galaxy_user_oauth2", metadata,
Column( "id", Integer, primary_key=True ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), nullable=False, index=True ),
Column( "provider", String, nullable=False ),
Column( "state_token", String, nullable=False, index=True ),
Column( "id_token", String ),
Column( "refresh_token", String ),
Column( "expiration_date", DateTime ),
Column( "access_token", String ) )
Column("id", Integer, primary_key=True),
Column("user_id", Integer, ForeignKey("galaxy_user.id"), nullable=False, index=True),
Column("provider", String, nullable=False),
Column("state_token", String, nullable=False, index=True),
Column("id_token", String),
Column("refresh_token", String),
Column("expiration_date", DateTime),
Column("access_token", String))

model.PasswordResetToken.table = Table(
"password_reset_token", metadata,
Expand Down Expand Up @@ -1578,10 +1578,10 @@ def simple_mapping( model, **kwds ):
order_by=desc( model.UserOpenID.table.c.update_time ) )
) )

mapper( model.UserOAuth2, model.UserOAuth2.table, properties=dict(
user=relation( model.User,
primaryjoin=( model.UserOAuth2.table.c.user_id == model.User.table.c.id ) )
) )
mapper(model.UserOAuth2, model.UserOAuth2.table, properties=dict(
user=relation(model.User,
primaryjoin=(model.UserOAuth2.table.c.user_id == model.User.table.c.id))
))

mapper( model.ValidationError, model.ValidationError.table )

Expand Down
10 changes: 5 additions & 5 deletions lib/galaxy/webapps/galaxy/controllers/oauth2.py
Expand Up @@ -8,18 +8,18 @@
from galaxy import web
from galaxy.web.base.controller import BaseUIController

class OAuth2( BaseUIController ):
class OAuth2(BaseUIController):

@web.expose
@web.require_login( "authenticate against Google identity provider" )
@web.require_login("authenticate against Google identity provider")
def google_authn(self, trans, **kwargs):
if trans.user is None:
# Only logged in users are allowed here.
return
return trans.response.send_redirect( web.url_for( trans.app.authnz_manager.authenticate( "Google", trans ) ) )
return trans.response.send_redirect(web.url_for(trans.app.authnz_manager.authenticate("Google", trans)))

@web.expose
def google_callback(self, trans, **kwargs):
if trans.app.authnz_manager.callback( "Google", kwargs[ 'state' ], kwargs[ 'code' ], trans ) is False:
if trans.app.authnz_manager.callback( "Google", kwargs['state'], kwargs['code'], trans) is False:
# TODO: inform the user why he/she is being re-authenticated.
self.google_authn( trans )
self.google_authn(trans)

0 comments on commit f622206

Please sign in to comment.