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
Related
I am currently trying out Ruby and the Google API for Ruby and I am having difficulties accessing my Gmail account and creating drafts with it (via create_user_draft) using a Service Account. I have successfully authenticated my Service Account with the API (Access Tokens are being generated).
I can use it with the Google::Apis::DriveV2::DriveService::list_files but not on GmailV1 methods.
I use this code to authorise the service account and the scope https://www.googleapis.com/auth/gmail.compose
Authorisation
def authorise
#jsonKeyIo = self.loadCredentialsFile
gAuthDefaultCreds = ##gAuthDefaultCreds
serviceAccountCredentials = gAuthDefaultCreds.make_creds(
{json_key_io: #jsonKeyIo, scope: #scope})
#service.authorization = serviceAccountCredentials
#service.authorization.fetch_access_token!
end
It generates an access token with this format:
{"access_token"=>"ya29.access_token_codes_here", "token_type"=>"Bearer", "expires_in"=>3600}
Draft creator snippet
##gmail = Google::Apis::GmailV1
##service = ##gmail::GmailService.new
def createDraft(draftTitle, draftMessage)
draft = ##gmail::Draft.new
draft.message = draftMessage
#service.create_user_draft('my.email#gmail.com', draft)
end
It throws a failedPrecondition: Bad Request (Google::Apis::ClientError) with the above code but when I added options: {authorization: #accessToken } as a third parameter of create_user_draft, the exception becomes Unauthorized (Google::Apis::AuthorizationError).
Can you help me go to the right path? I find the API documentation, on the Google API sites and on the source code itself, lackluster.
UPDATE
I have read here that in order for Service Accounts to work on the Gmail API, a paid Google Apps account is required (normal #gmail.com accounts won't work) since on the Admin Console is where we should have to enable the scopes for our Service Accounts.
Currently trying out JWT Credentials login.
I have a web application running on Azure. The web application authenticates the users via OpenID Connect from a Azure Active Directory tenant.
Azure Sample on GitHub.
On the Azure Active Directory tenant I have integrated Google Apps and configured single sing-on to Google Apps and automated user provisioning. Tutorial: How to integrate Google Apps with Azure Active Directory.
In my web application I would like to access user content from Google Apps (e.g. files on Google Drive) of the signed in user via Google API.
Is it possible to do this with the help of the setup single sign-on federation, so that the user only needs to sign in to the web application/Azure AD and for the Web API call there is no need for a further sign in, e.g. by using a token optained by Azure AD for accessing the Google Web API?
Tokens obtained from Azure AD cannot be used directly against Google API. However if you integrated Azure AD and Google Apps you should be able to go through the google token acquisition process without gathering user credentials again. You might want to go through an authorization code flow for getting tokens from google, and inject in the request information that would help to leverage your existing session. Typical examples are passing your user's UPN (via login_hint query parameter) and tenant (domain_hint). However I don't know if the google authorization endpoint will pass those along, you'll need to consult the google api documentation.
I ended up with two solutions:
a) Service Account:
Accessing the users data with a service account on behalf of a user.
For this you have to setup a service account: Using OAuth 2.0 for Server to Server Applications
private static ServiceAccountCredential GetServiceAccountCredential(string user)
{
const string privateKey = "<PRIVATEKEY>";
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer("<SERVICEACOUNTEMAIL>")
{
Scopes = new[] {DriveService.Scope.Drive},
User = user
}.FromPrivateKey(privateKey));
return credential;
}
b) User:
Accessing the users data with the user. For this you have to register your app to get the client ID and secret: Using OAuth 2.0 for Web Server Applications
private static UserCredential GetUserCredential(string user)
{
ClientSecrets secrets = new ClientSecrets
{
ClientId = "<CLIENTID>",
ClientSecret = "<CLIENTSECRET>"
};
IDataStore credentialPersistanceStore = new FileDataStore("Drive.Sample.Credentials");
Task<UserCredential> result = GoogleWebAuthorizationBroker.AuthorizeAsync(
secrets,
new[] {DriveService.Scope.Drive},
user,
CancellationToken.None,
credentialPersistanceStore);
result.Wait();
UserCredential credential = result.Result;
return credential;
}
With the credentials I can request the files from Drive:
Claim emailClaim = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email);
IConfigurableHttpClientInitializer credential = GetServiceAccountCredential(emailClaim.Value);
//IConfigurableHttpClientInitializer credential = GetUserCredential(emailClaim.Value);
var service = new DriveService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "My App"
});
FileList list = service.Files.List().Execute();
I am not yet sure which option I will use. Maybe you have some advices or suggestions.
I am trying to get an access token for Google Service Account. Following is my code -
String SERVICE_ACCOUNT_EMAIL = "edited#developer.gserviceaccount.com";
List scope = new ArrayList();
scope.add("https://www.googleapis.com/auth/admin.directory.user");
String keyFile = "C:\\edited-privatekey.p12";
HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
JsonFactory JSON_FACTORY = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(scope)
.setServiceAccountPrivateKeyFromP12File(new java.io.File(keyFile))
.build();
credential.refreshToken();
String accessTokens = credential.getAccessToken();
Although the code works fine and I do get an access token, when I try to use it to 'GET' a Google Apps User using the Google Directory APIs, I get a 403 - Forbidden response code. Could someone please help?
I know the code for GET user is correct because it works fine with the access token generated by Google Apps Admin.
You need to set an admin account with:
.setServiceAccountUser(some_admin_email)
And make sure your App (with the correct scopes) is granted access in the cpanel.
Proceed to https://admin.google.com . Login and add Security control if not exists from More Controls.
Click on Security->Advance Settings->Manage ThirdParty OAuth Client Access and check that those scopes are added(comma separated) for your xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com service account id/client id.
You have to enable the specific api before using it inside https://console.developers.google.com/ library, to make it work with your api key.
watch the video https://www.youtube.com/watch?v=s_G5CnAu69M.
I'm using Google APIs Client Library for JavaScript (Beta) to authorize user google account on web application (for youtube manipulations). Everything works fine, but i have no idea how to "logout" user from my application, i.e. reset access tokens.
For example, following code checks user authorization and if not, shows popup window for user to log into account and permit web-application access to user data:
gapi.auth.authorize({client_id: CLIENT_ID, scope: SCOPES, immediate: false}, handleAuth);
But client library doesn't have methods to reset authorization.
There is workaround to redirect user to "accounts.google.com/logout", but this
approach is not that i need: thus we logging user off from google account not only from my application, but also anywhere.
Google faq and client library description neither helpful.
Try revoking an access token, that should revoke the actual grant so auto-approvals will stop working. I assume this will solve your issue.
https://developers.google.com/accounts/docs/OAuth2WebServer#tokenrevoke
Its very simple. Just revoke the access.
void RevokeAcess()
{
try{
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/revoke?token="+ACCESS_TOKEN);
org.apache.http.HttpResponse response = client.execute(post);
}
catch(IOException e)
{
}
}
But it should be in asyncTask
It depends what you mean by resetting authorization. I could think of a three ways of doing this:
Remove authorization on the server
Go to myaccount.google.com/permissions, find your app and remove it. The next time you try to sign in you have to complete full authorization flow with account chooser and consent screen.
Sign out on the client
gapi.auth2.getAuthInstance().signOut();
In this way Google authorization server still remembers your app and the authorization token remains in browser storage.
Sign out and disconnect
gapi.auth2.getAuthInstance().signOut();
gapi.auth2.getAuthInstance().disconnect();
This is equivalent to (1) but on the client.
Simply use: gapi.auth.setToken(null);
Solution for dotnet, call below API and pass the access token, doc - https://developers.google.com/identity/protocols/oauth2/web-server#tokenrevoke
string url = "https://accounts.google.com/o/oauth2/revoke?token=" + profileToken.ProfileAccessToken;
RestClient client = new RestClient(url);
var req = new RestRequest(Method.POST);
IRestResponse resp = client.Execute(req);
Most of the Google Management APIs seem to have been enabled for Service Accounts. For example, I can retrieve calendars like so:
string scope = Google.Apis.Calendar.v3.CalendarService.Scopes.Calendar.ToString().ToLower();
string scope_url = "https://www.googleapis.com/auth/" + scope;
string client_id = "999...#developer.gserviceaccount.com";
string key_file = #"\path\to\my-privatekey.p12";
string key_pass = "notasecret";
AuthorizationServerDescription desc = GoogleAuthenticationServer.Description;
X509Certificate2 key = new X509Certificate2(key_file, key_pass, X509KeyStorageFlags.Exportable);
AssertionFlowClient client = new AssertionFlowClient(desc, key) { ServiceAccountId = client_id, Scope = scope_url };
OAuth2Authenticator<AssertionFlowClient> auth = new OAuth2Authenticator<AssertionFlowClient>(client, AssertionFlowClient.GetState);
CalendarService service = new CalendarService(auth);
var x = service.Calendars.Get("calendarID#mydomain.com").Fetch();
However, identical code on the GroupssettingsService returns a 503 - Server Not Available. Does that mean service accounts can't be used with that API?
In a possibly related issue, the scope of the Groups Settings Service seems to be apps.groups.settings but if you call
GroupssettingsService.Scopes.AppsGroupsSettings.ToString().ToLower();
...you get appsgroupssettings instead, without the embedded periods.
Is there another method to use service accounts for the GroupssettingsService? Or any information on the correct scope string?
Many thanks.
I found this thread, and the most important part of the docs after some time. Posting so others don't waste their time in the future.
Your application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported. If your application uses Google Sign-In, some aspects of authorization are handled for you.
See the "About authorization protocols" section of the docs
Why do you need to use a service account for this? You can use regular OAuth 2.0 authorization flows to get an authorization token from a Google Apps super admin user and use that:
https://developers.google.com/accounts/docs/OAuth2InstalledApp