SignedJwtAssertionCredential refresh - google-oauth

Each thread in my client initializes with
self.credentials = oauth2client.client.SignedJwtAssertionCredentials(...)
http = httplib2.Http()
http = self.credentials.authorize(http)
self.http = http
This works fine initially and each client is able do appropriate work.
As the hour approaches and the token nears expiration what is the best way to refresh the credential so that each thread can continue to make progress? I tried
self.credentials.refresh(self.http)
just before the hour but am seeing
File "/usr/lib64/python2.6/httplib.py", line 355, in _read_status
raise BadStatusLine(line)
BadStatusLine

OAuth 2.0 Service Account Access Tokens cannot be refreshed in the same way that regular OAuth 2.0 access tokens are. Instead, you need to rebuild the credentials from scratch and request another access token.
So effectively, you would just reuse your initialization code.

Regarding threads, please read this: https://developers.google.com/api-client-library/python/guide/thread_safety
There is no need for manual refresh since it's automagically done in the apiclient library (here).
The code should be as follows:
{Shared code}
self.credentials = oauth2client.client.SignedJwtAssertionCredentials(...)
.
{Thread code}
service = self.credentials.authorize(httplib2.Http())
Hope it helps.

Related

Create a space with Google Chat REST API

We have a program that uses a service account to manage various thing inside Google Chat.
Now, we have the need to create a new space using the Google Chat REST API (spaces.create).
We already joined the developer preview program, as this endpoint is not yet generally available.
From what we understand, this endpoint is not possible to invoke via service account and so we wanted to ask you… can we invoke this endpoint automatically using “domain delegation”? If yes, how?
We always want to use the service account as it is not possible to show a login prompt to the user.
We enabled the domain delegation but that endpoint returns always status 403. (We are using Google.Apis library for .NET Core
using Google.Apis.Auth.OAuth2;
var credential = GoogleCredential.FromFile("key.json")
.CreateScoped("https://www.googleapis.com/auth/chat.spaces.create")
.CreateWithUser("service-account-email#project.iam.gserviceaccount.com");
var token = await credential.UnderlyingCredential.GetAccessTokenForRequestAsync();
HttpRequestMessage request = new(HttpMethod.Post, "https://chat.googleapis.com/v1/spaces");
request.Headers.Authorization = new("Bearer", token);
var payload = #"
{
""name"": ""testspace-1"",
""spaceType"": ""SPACE"",
""singleUserBotDm"": true,
""displayName"": ""Test Space""
}
";
request.Content = new StringContent(payload, System.Text.Encoding.UTF8, "application/json");
HttpClient client = new();
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
If you check the documentation Auth
You will notice it stats that service account authorization is supported. If you are part of thedeveloper preview program
The reason I asked about your code is that the last time i tried this which notably was a while ago. The google .net client library was not generated the methods that were under preview.
So while it may work yes. The issue your may have is that the client library when loaded will not have the method you need meaning you will have to code the call to the endpoint yourself.
If this is in fact the case let me know if you have any issues peceing it together I may be able to help.
update your code
There is an error in your code
.CreateWithUser("service-account-email#project.iam.gserviceaccount.com");
The email in CreateWithUser should be the user on your domain who you wish to delicate the service account as. Not the service account email address.

Token management in Karate parallel execution

Scenario : All the endpoints in my API test need authentication and hence authorization header needs to be passed. I have Authentication.feature file where I read refresh token from a file, generate new access token, write the new refresh token back to the file. After running each scenario, I need to update the refresh token back to the file and it will be consumed by next feature. Authentication.feature file is called from karate-config.js file and authentication header is set as shown below
var response = karate.call('classpath:Test/features/Authentication.feature',config).response;
var token = response.access_token
karate.configure('headers',{Authorization: 'Bearer '+token});
Everything till now is working fine, but when I use junit5 parallel runner, it causes issues with the authentication token. Not the latest refresh token is written to the file. I tried by making the file read/write part synchronized, but it does not solve the problem. Also I tried #parallel=false annotation in Authentication.feature, still no luck. How can I make my test run parallel at the same time it correctly update the file with latest refresh token
The recommended way to do this is to use karate.callSingle() - please read about it if you haven't already: https://github.com/karatelabs/karate#hooks
Note that this code example below is JS in karate-config.js:
var result = karate.callSingle('classpath:some/package/my.feature');
Also see this answer for some other ideas: https://stackoverflow.com/a/53516885/143475

How do I make authenticated Rest call to google machine learning predict endpoint?

I want to make a simple http rest call to a google machine learning predict endpoint, but I can't find any information on how to do that. As far as I can tell from the limited documentation, you have to use either the Java or Python library (or figure out how to properly encrypt everything when using the REST auth endpoints) and get a credentials object. Then the instructions end and I have no idea how to actually use my credentials object. This is my code so far:
import urllib2
from google.oauth2 import service_account
# Constants
ENDPOINT_URL = 'ml.googleapis.com/v1/projects/{project}/models/{model}:predict?access_token='
SCOPES = ['https://www.googleapis.com/auth/cloud-platform']
SERVICE_ACCOUNT_FILE = 'service.json'
credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
access_token=credentials.token
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request(ENDPOINT_URL + access_token)
request.get_method = lambda: 'POST'
result = opener.open(request).read()
print(str(result))
If I print credentials.valid it returns False, so I think there is an issue with the credentials object init but I don't know what since no errors are reported, the fields are all correct inside the credentials object, and I did everything according to the instructions. Also my service.json is the same one our mobile team is successfully using to get an access token so I know the json file has the correct data.
How do I get an access token for the machine learning service that I can use to call the predict endpoint?
It turns out the best way to do a simple query is to use the gcloud console. I ended up following the instructions here to setup my environment: https://cloud.google.com/sdk/docs/quickstart-debian-ubuntu
Then the instructions here to actually hit the endpoint (with some help from the person that originally setup the model):
https://cloud.google.com/sdk/gcloud/reference/ml-engine/predict
It was way easier than trying to use the python library and I highly recommend it to anyone trying to just hit the predict endpoint.

Ember.js Authentication Token for Ember-Data + AMS => JSON or HTTP Header?

CONTEXT:
I have an Ember.js 1.1.0-beta.1 application that exchanges JSON data with a Rails-API server (Rails 4). JSON data exchange is accomplished with Ember-Data 1.0.0-beta.2 and Active Model Serializers 0.8.1 (AMS). I'm using the default recommended configurations for both Ember-Data and AMS, and am compliant with the JSON-API spec.
On any given RESTful call, the client passes the current authentication token to the server. The authentication token is verified and retired, and a new authentication token is generated and sent back to the client. Thus, every RESTful call accepts an authentication token in the request, and provides a new authentication token in the response that the client can cache and use for the next RESTful call.
QUESTION:
Where do I put the authentication token in each request and response?
Should it be part of each object's JSON in request and response? If so, where is the token placed in the existing object's JSON structure (which has nothing to do with authentication)?
Or should they be placed in the HTTP header for each request and response object?
What is "The Ember Way" that one might eventually expect to find in the new Ember Guides Cookbook?
MORE CONTEXT:
I'm already familiar with the following links:
#machty 2 Embercasts: http://www.embercasts.com/episodes/client-side-authentication-part-2
#wycats tweet: https://twitter.com/wycats/status/376495062709854209
#cavneb 3 blog posts: http://coderberry.me/blog/2013/07/08/authentication-with-emberjs-part-1
#simplabs blog post: http://log.simplabs.com/post/53016599611/authentication-in-ember-js
...and am looking for answers that go beyond these, and are specific to Ember-Data + AMS.
With the exception of the need to pass a new token back to the client in the response via Ember-Data, assume my client code is otherwise similar to the #machty Embercast example on GitHub: https://github.com/embercasts/authentication-part-2/blob/master/public/js/app.js
Thank you very much!
I've got a similar stack - ember, ember-data and rails-api with AMS. Right now, I'm just passing the authentication token (which I store in localStorage) in a header (though you could pass it on the query string) by modifying the RESTAdapter's ajax method.
My initial thought would be to avoid resetting the token on every request. If you're particularly concerned about the token being sniffed, it might be easier to just reset the token on the server at a regular interval (say, 10 minutes). Then, if any request from the client fails due to an old token, just fetch the new token (by passing a'reset token' that your server gives you at login) and replay the initial request.
As for where to put the token, there isn't really an "Ember Way" - I prefer passing it in a header since passing it in the query string can mess with caching and is also more likely to be logged somewhere along the way. I'd definitely avoid passing it in the request body - that would go against what ember-data expects, I'd imagine.
I have built something similar, although I do not reset the token unless the user signs out.
I would not put it in the request body itself - you are just going to pollute your models. There probably is no Ember way since this is more of a transport issue. I pass the token using a custom HTTP header and/or a cookie. The cookie is needed to authorize file downloads, which can not be done through ajax, although the cookie works for ajax calls too. In your case I would use a cookie and have the server set it to the new value each time. However, your scheme of resetting the token on each JSON request is not going to work on simultaneous requests. Is this really necessary? If you use TLS you probably don't need to worry so much. You could also timeout the token so that if there are no requests for 10 minutes a new token is generated.

Rest and ZF session management

I'm trying to create a web service which utilizes Zend framework. The API is REST based and uses Zend_Rest_Controller as base class. I wish to have user management and session, and for that I'm using the following code:
Login (POST)
// user id and password fetched first
$users = new Application_Model_DbTable_UserInfo();
$auth = Zend_Auth::getInstance();
$authAdapter = new Zend_Auth_Adapter_DbTable($users->getAdapter(),'users');
$authAdapter->setIdentityColumn('userid')
->setCredentialColumn('password');
$authAdapter->setIdentity($userid)
->setCredential($pwd);
$result = $auth->authenticate($authAdapter);
if($result->isValid()){
Zend_Session::rememberMe(604800);
$storage = new Zend_Auth_Storage_Session();
$usa = $authAdapter->getResultRowObject();
$auth->getStorage()->write($usa);
$authSession = new Zend_Session_Namespace('Zend_Auth');
$authSession->setExpirationSeconds(60*60);
}
and when accessing the service with e.g. some GET method I wish to check that there is a valid session with the following code:
$auth = Zend_Auth::getInstance();
if(!$auth->hasIdentity())
{
// error handling etc.
}
I never get an identity, hence the service doesn't work.
I have followed the guidance for ZF authentication quite strictly, but does the REST stuff need additional items to be taken into account?
I know I'm not answering your question, but if you are REALLY planning to implement a true REST interface (which implies it's going to enable you to scale well), you'd probably better forget about sessions and using Zend_Auth in the way you've depicted above.
Take a look here, where something about REST interfaces and authentication has been discussed already:
Can you help me understand this? "Common REST Mistakes: Sessions are irrelevant"
In short, quoting from the Q/A thread above, "To be RESTful, each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP". I really feel like seconding that.