Authorizing Application Access to BigQuery without User Interaction, via PHP - google-api

I have a website, that does the simple work of fetching an USN from Google BigQuery on the cloud. Now, while accessing each time, I need to have a Google Account and also that particular email-id, should have the "permission" assigned in the "Team tab". I basically want the website to be available to everyone. And i am using PHP, so I need help about the functions that will be useful here.

The best way to build an application that is authorized to access the BigQuery API (as opposed to requiring a user authorization step) is to use OAuth2 service accounts. Essentially, a service account authorization provides certificate-based authorization for "server to server" interactions (such as your server side PHP script interacting with the BigQuery API).
There is documentation for using the Google PHP Client library with service account authorization here.

You have to create a 'service account' through google console and download the private key file (.p12) on your server. And use following code
/**
* setup service client using key file
* #param String $keyFileLoc location of .p12 file provided in google console
* #param String $clientEmail client location provided in google console
*/
function setupServiceClient($keyFileLoc,$clientEmail){
$client = new Google_Client();
$service = new Google_Service_Bigquery($client);
$client->setApplicationName("My Application Name");
$key = file_get_contents($keyFileLoc);
$cred = new Google_Auth_AssertionCredentials(
$clientEmail,
array('https://www.googleapis.com/auth/bigquery'),
$key
);
$this->client->setAssertionCredentials($cred);
return $service;
}

Related

Google calendar API - How to make a request without having to prompt a login?

I have a simple question:
I am developing a website that needs full authorisation to make requests to a Google calendar. I manage to do all the requests I need with javascript from a web server and it works, but I need to be logged into my google account for it to work. This caused a problem for other users that use my website because the request doesn't work if they are not logged into MY google account.
I understand why it doesn't work, my question is How can I do for my website to get full access granted for use the google calendar without having to log into my google account, even better if nobody had to log into a Google account to perform the task??
The form of login you are currently using is called Oauth2. It requires that a user authenticate access.
What you should be using is a service account. Service accounts are pre authorized. You will need to share your personal calendar with the service account then it will be able to access it.
The only drawback is that service account authentication is not supported by JavaScript you will need to switch to a server sided language like node.js for example.
'use strict';
const {google} = require('googleapis');
const path = require('path');
/**
* The JWT authorization is ideal for performing server-to-server
* communication without asking for user consent.
*
* Suggested reading for Admin SDK users using service accounts:
* https://developers.google.com/admin-sdk/directory/v1/guides/delegation
*
* See the defaultauth.js sample for an alternate way of fetching compute credentials.
*/
async function runSample () {
// Create a new JWT client using the key file downloaded from the Google Developer Console
const client = await google.auth.getClient({
keyFile: path.join(__dirname, 'jwt.keys.json'),
scopes: 'https://www.googleapis.com/auth/drive.readonly'
});
// Obtain a new drive client, making sure you pass along the auth client
const drive = google.drive({
version: 'v2',
auth: client
});
// Make an authorized request to list Drive files.
const res = await drive.files.list();
console.log(res.data);
return res.data;
}
if (module === require.main) {
runSample().catch(console.error);
}
// Exports for unit testing purposes
module.exports = { runSample };
Code ripped from smaples jwt

Integration tests for web api with Azure AD

I am working on a webapi webservice that is proteted by Azure Active Directory. The webservice cumminucates heavily with Office 365 (SharePoint / Yammer) based on the user that is signed in.
To test the web api endpoints I am writing an Console App that let me sign in with my AAD credentials and then calls the endpoints. It works, but looking for something to replace this way of testing the web api. Would be great if it’s more repeatable and that I don’t have to fill in my credentials each time. I was looking for a unit test project but can’t get the Azure AD sign in to work.
Any tips how to make this easier?
The easiest way would be to define the test runner as an application in Azure AD and have it call the API with its own client id and secret.
To do that there are a few things you would need to do:
Add appRoles to your API in its manifest in Azure AD. These are application permissions.
Define your test runner, and have it require the necessary application permissions for your API.
In your test runner you should now be able to get an access token with the client id and secret of the test runner, no user authentication required.
Some setup is needed for app permissions on the API side as well, authorization must also look at the role claims.
You can find an example for defining app permissions and also handling them here: http://www.dushyantgill.com/blog/2014/12/10/roles-based-access-control-in-cloud-applications-using-azure-ad/.
More on defining app permissions: https://stackoverflow.com/a/27852592/1658906.
More info on the application manifest in AAD: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-application-manifest.
EDIT: If you must make calls on behalf of the user in the API, then this of course won't work.
In that case, I would suggest creating a user account with the necessary access for the purpose of running the tests. It would be best not to hard-code its credentials, but store them elsewhere.
If you don't want to "fill in my credentials each time", one workaround is using the Resource Owner Password Credentials Grant flow. This flow is flexible to gain a token easily. In the Console App, you could directly use user account and password to get the access token for your protected web API . The code below is for your reference :
static void Main(string[] args)
{
test().Wait();
}
public static async Task test()
{
using (HttpClient client = new HttpClient())
{
var tokenEndpoint = #"https://login.windows.net/a703965c-e057-4bf6-bf74-1d7d82964996/oauth2/token";
var accept = "application/json";
client.DefaultRequestHeaders.Add("Accept", accept);
string postBody = #"resource=https%3A%2F%2Fgraph.microsoft.com%2F //here could be your own web api
&client_id=<client id>
&grant_type=password
&username=nanyu#xxxxxxx.onmicrosoft.com
&password=<password>
&scope=openid";
using (var response = await client.PostAsync(tokenEndpoint, new StringContent(postBody, Encoding.UTF8, "application/x-www-form-urlencoded")))
{
if (response.IsSuccessStatusCode)
{
var jsonresult = JObject.Parse(await response.Content.ReadAsStringAsync());
var token = (string)jsonresult["access_token"];
}
}
}
}
But the problem is that flow will expose the username and password directly in the code, it brings potential attack risk as well and we will always avoid handling the user credential directly. So make sure you just use this flow for testing in a secure environment. You could refer to this article for more details.

Gmail API with service account

Under mygmailaccount#gmail.com in the API console I created a project and I am successfully using a service account for the Analytics API and Search Console API services. I've now enabled the Gmail V1 API and ran this code:
gmail_scopes = [
"https://mail.google.com/",
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/gmail.readonly"
]
gmail = Google::Apis::GmailV1::GmailService.new
gmail.authorization = Google::Auth.get_application_default(gmail_scopes)
This is the same code (with different scopes of course) that I use to authorize the Analytics and Search Console API.
However I get BAD REQUEST Failed Precondition errors when I run this:
gmail.get_user_profile("mygmailaccount#gmail.com")
Some googling tells me that is because the API is trying to access the non-existent inbox for the serviceaccount email address and that in the initiatlization process I need to include mygmailaccount#gmail.com so that the API service will use that inbox.
How do I do that?
I've tried the following '...' always being the email address
gmail.authorization = Google::Auth.get_application_default(gmail_scopes, username: '...')
gmail.authorization = Google::Auth.get_application_default(gmail_scopes, {username: '...'})
gmail.authorization.username = '...'
Service accounts cannot access #gmail.com mailboxes. You need to use an OAuth2 UserAuthorizer. See the Gmail API Ruby Quickstart guide for an example.

Possible to use Google service account with Sites APIs

I am using a service account to impersonate an admin user successfully with the Admin Directory and Google+ Domain APIs, but I am unable to figure out if Sites can make use of service accounts. Is it even possible? I am referring to the API that allows you to create and delete sites, not the Webmaster Tools API for managing the content and so on.
You can use Service Accounts with Sites API. All you need to do is use SignedJwtAssertionCredentials, impersonate the user from background and access the GData APIs.
Here is the code snippet:
credentials = SignedJwtAssertionCredentials(
SERVICE_ACCOUNT_EMAIL,
file(SERVICE_ACCOUNT_PEM_FILE_PATH, "rb").read(),
scope=["https://sites.google.com/feeds/"],
prn=userEmailYouWantToImpersonate
)
http = httplib2.Http()
http = credentials.authorize(http)
sitesClient = gdata.sites.client.SitesClient(source='mycompany', site='mySite', domain='mydomain')
sitesClient.auth_token = TokenFromOAuth2Creds(credentials)
feed = sitesClient.GetContentFeed()
class TokenFromOAuth2Creds:
def __init__(self, creds):
self.creds = creds
def modify_request(self, req):
if self.creds.access_token_expired or not self.creds.access_token:
self.creds.refresh(httplib2.Http())
self.creds.apply(req.headers)
Yes it is possible. Here's a code example :
SitesService sitesService = new SitesService("MyApplication");
final GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(new NetHttpTransport()).setJsonFactory(new JacksonFactory())
.setServiceAccountId("XXXX.apps.googleusercontent.com")
.setServiceAccountScopes(Collections.singleton(SERVICE_SCOPES))
.setServiceAccountPrivateKeyFromP12File(new File("key.p12"))
.setServiceAccountUser("mysiteowner#domain.com").build();
sitesService.setOAuth2Credentials(credential);
The only thing you have to be cautious with, is that some SitesService methods might not be able to refresh the token properly, in which case you will have to catch the SessionExpiredException and refresh the Credential yourself.
Google Sites API pages says [1] that you can "Create new Sites or copy existing Sites" with it.
[1] https://developers.google.com/google-apps/sites

Retrieve blog feeds using google oauth 2.0 and scribe

I used scribe to connect to google using oAuth 2.0 and successfully got the access token. When i am trying to get the blogs i always get the below error
Unauthorized
Must authenticate to use 'default' user
Below is the code snippet
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET_KEY);
oauthParameters.setScope("http://www.blogger.com/feeds");
oauthParameters.setOAuthToken(ACCESS_TOKEN);
oauthParameters.setOAuthTokenSecret(ACCESS_TOKEN_SECRET); // this is null
BloggerService myService = new BloggerService("blogger");
try {
myService.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
} catch (OAuthException e) {
e.printStackTrace();
}
final URL feedUrl = new URL("http://www.blogger.com/feeds/default/blogs");
Query query = new Query(feedUrl);
Feed resultFeed = myService.getFeed(query, Feed.class);
Not able to get the feeds here and displays the Unauthorized error as mentioned above.
Jason has answered your question, I believe.
You do not want to use the library code above to access blogger. Use the new API, and use OAuth2 https://developers.google.com/blogger/docs/3.0/using#auth
I'm not sure what scribe is, but with OAuth2, you need to indicate what type of application you're building, It might be one that runs from a web server, or an installed application. What's you've determined that, you can follow the appropriate documentation for the java client library linked to above to get the access token and retrieve the data.

Resources