diff --git a/lib/Bio/KBase/KIDL/client_stub.tt b/lib/Bio/KBase/KIDL/client_stub.tt index 6c6fb62..a91098c 100644 --- a/lib/Bio/KBase/KIDL/client_stub.tt +++ b/lib/Bio/KBase/KIDL/client_stub.tt @@ -35,6 +35,11 @@ our $VERSION = "0.1.0"; sub new { + # 'args' argument is a pointer to a hash with authentication parameters. + # In case there is 'auth_service_url' key in this map defining end-point + # of auth_service then '/Sessions/Login' function of KBase auth_service + # will be used for authentication rather than direct communication with + # GlobusOnline. my($class, $url, @args) = @_; [% IF default_service_url -%] diff --git a/lib/Bio/KBase/KIDL/python_client.tt b/lib/Bio/KBase/KIDL/python_client.tt index 796b3b6..3187e36 100644 --- a/lib/Bio/KBase/KIDL/python_client.tt +++ b/lib/Bio/KBase/KIDL/python_client.tt @@ -26,9 +26,32 @@ _URL_SCHEME = frozenset(['http', 'https']) def _get_token(user_id, password, auth_svc='https://nexus.api.globusonline.org/goauth/token?' + - 'grant_type=client_credentials'): + 'grant_type=client_credentials', + auth_service_url = None): # This is bandaid helper function until we get a full # KBase python auth client released + # In case auth_service_url input argument is passed defining end-point + # of auth_service then '/Sessions/Login' function of KBase auth_service + # will be used for authentication rather than direct communication with + # GlobusOnline. + if auth_service_url: + headers = {'Content-type': 'application/x-www-form-urlencoded'} + url = auth_service_url + '/Sessions/Login' + data = 'user_id=' + user_id + '&password=' + password + '&fields=token' + # Here we use '/Sessions/Login' function of KBase auth_service sending + # user_id and password there and getting valid token back. + ret = _requests.post(url, headers = headers, data = data) + status = ret.status_code + if status >= 200 and status <= 299: + # Parse response in JSON format, it's a map containing requested + # user properties (only token in our case). + user_map = _json.loads(ret.text) + elif status == 403: + raise Exception('Authentication failed: Bad user_id/password ' + + 'combination for user %s' % (user_id)) + else: + raise Exception(ret.text) + return user_map['token'] auth = _base64.encodestring(user_id + ':' + password) headers = {'Authorization': 'Basic ' + auth} ret = _requests.get(auth_svc, headers=headers, allow_redirects=True) @@ -107,7 +130,8 @@ class [% module.module_name %](object): def __init__(self, url=None, timeout=30 * 60, user_id=None, password=None, token=None, ignore_authrc=False, - trust_all_ssl_certificates=False): + trust_all_ssl_certificates=False, + auth_service_url = None): if url is None: [% IF default_service_url -%] url = '[% default_service_url %]' @@ -125,7 +149,10 @@ class [% module.module_name %](object): if token is not None: self._headers['AUTHORIZATION'] = token elif user_id is not None and password is not None: - self._headers['AUTHORIZATION'] = _get_token(user_id, password) + # We propagate auth_service_url to _get_token method in case + # it was passed into constructor of client. + self._headers['AUTHORIZATION'] = _get_token(user_id, password, + auth_service_url = auth_service_url) elif 'KB_AUTH_TOKEN' in _os.environ: self._headers['AUTHORIZATION'] = _os.environ.get('KB_AUTH_TOKEN') elif not ignore_authrc: @@ -137,8 +164,11 @@ class [% module.module_name %](object): self._headers['AUTHORIZATION'] = authdata['token'] elif(authdata.get('user_id') is not None and authdata.get('password') is not None): + # We propagate auth_service_url to _get_token method in case + # it was passed into constructor of client. self._headers['AUTHORIZATION'] = _get_token( - authdata['user_id'], authdata['password']) + authdata['user_id'], authdata['password'], + auth_service_url = auth_service_url) if self.timeout < 1: raise ValueError('Timeout value must be at least 1 second') diff --git a/lib/Bio/KBase/KIDL/python_server.tt b/lib/Bio/KBase/KIDL/python_server.tt index 0df7bc9..18abbc3 100644 --- a/lib/Bio/KBase/KIDL/python_server.tt +++ b/lib/Bio/KBase/KIDL/python_server.tt @@ -349,8 +349,13 @@ class Application(object): pass else: try: + auth_service_url = None + if config is not None: + auth_service_url = config.get('auth-service-url') + # We propagate auth_service end-point to validate_token method in case there is + # 'auth-service-url' property defined in deployment configuration of server. user, _, _ = \ - self.auth_client.validate_token(token) + self.auth_client.validate_token(token, auth_service_url) ctx['user_id'] = user ctx['authenticated'] = 1 ctx['token'] = token diff --git a/lib/Bio/KBase/KIDL/server_stub.tt b/lib/Bio/KBase/KIDL/server_stub.tt index 3d821de..348cab3 100644 --- a/lib/Bio/KBase/KIDL/server_stub.tt +++ b/lib/Bio/KBase/KIDL/server_stub.tt @@ -246,7 +246,10 @@ sub call_method { $self->exception('PerlError', "Authentication required for [% module.module_name %] but no authentication header was passed"); } - my $auth_token = Bio::KBase::AuthToken->new(token => $token, ignore_authrc => 1); + # We propagate auth_service end-point to AuthToken constructor in case there is + # 'auth-service-url' property defined in deployment configuration of server. + my $auth_token = Bio::KBase::AuthToken->new(token => $token, ignore_authrc => 1, + auth_service_url => $self->config->{'auth-service-url'}); my $valid = $auth_token->validate(); # Only throw an exception if authentication was required and it fails if ($method_auth eq 'required' && !$valid)