Google Admin SDK API : Not Authorized to access this resource/api - java

I want to delete user from google Directory API. I received error while deleting
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden "Not Authorized to access this resource/api".
However my code works fine while insert user. I have super admin accounts and I'm using same directory instance for inserting and deleting user. It does work when I'm trying to delete the user.
Please help me out. Thanks in advance.
public class UserDisable {
private static final Logger LOGGER = Logger.getLogger(EmployeeAPI.class);
/** Application name. */
private static final String APPLICATION_NAME = "User Account Creation";
/** Directory to store user credentials for this application. */
private static final java.io.File DATA_STORE_DIR = new java.io.File(
System.getProperty("user.home"),
".credentials/admin-directory_v1-java-quickstart");
/** Global instance of the {#link FileDataStoreFactory}. */
private static FileDataStoreFactory DATA_STORE_FACTORY;
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = JacksonFactory
.getDefaultInstance();
/** Global instance of the HTTP transport. */
private static HttpTransport HTTP_TRANSPORT;
private static final Random randomGenerator = new Random();
static Directory directoryClient = null;
private static final List<String> SCOPES = Arrays.asList(
DirectoryScopes.ADMIN_DIRECTORY_USER, DirectoryScopes.ADMIN_DIRECTORY_GROUP);
static {
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
} catch (Throwable t) {
System.exit(1);
}
}
/**
* Creates an authorized Credential object.
*
* #return an authorized Credential object.
* #throws IOException
*/
public static Credential authorize() throws IOException {
// Load client secrets.
InputStream in = UserDisable.class
.getResourceAsStream("/client_secret.json");
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(DATA_STORE_FACTORY)
.setAccessType("offline").build();
Credential credential = new AuthorizationCodeInstalledApp(flow,
new LocalServerReceiver()).authorize("user");
LOGGER.info("Credentials saved to "
+ DATA_STORE_DIR.getAbsolutePath());
return credential;
}
/**
* Build and return an authorized Admin SDK Directory client service.
*
* #return an authorized Directory client service
* #throws IOException
*/
public static Directory getDirectoryService() throws IOException {
Credential credential = authorize();
return new Directory.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME).build();
}
public static void demo(){
try {
directoryClient = getDirectoryService();
removeUser(directoryClient, "Anderson.Paul2#abc.com");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* removeGroup removes a group from Google.
* #param directoryClient a Directory (service) object
* #param userKey an identifier for a user (e-mail address is the most popular)
* #throws IOException
*/
public static void removeUser(Directory directoryClient, String userKey) throws IOException {
LOGGER.info("removeUser() - {}"+ userKey);
try {
directoryClient.users().delete(userKey).execute();
} catch (IOException e) {
LOGGER.info("An unknown error occurred: " + e);
}
}
}
Here is error that i have received:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Not Authorized to access this resource/api",
"reason" : "forbidden"
}
],
"message" : "Not Authorized to access this resource/api"
}

Related

Use Service Account with GoogleAdsClient to make AdWordsSession

I want to use Google Ads API with service account I managed to create a session using this Java code configuration:
ClassLoader classLoader = this.getClass().getClassLoader();
File configFile = new File(classLoader.getResource("ads.properties").getFile());
GoogleAdsClient googleAdsClient = GoogleAdsClient.newBuilder()
.fromEnvironment()
.fromPropertiesFile(configFile)
.build();
GoogleAdsServiceClient googleAdsServiceClient = googleAdsClient.getLatestVersion().createGoogleAdsServiceClient();
I want to use this connection to make a request using this code:
AdWordsSession session = null;
try {
// Generate a refreshable OAuth2 credential.
Credential oAuth2Credential = new OfflineCredentials.Builder()
.forApi(Api.ADWORDS)
.fromFile()
.build()
.generateCredential();
// Construct an AdWordsSession.
session =
new AdWordsSession.Builder().fromFile().build();
} catch (ConfigurationLoadException cle) {
System.err.printf(
"Failed to load configuration from the %s file. Exception: %s%n",
DEFAULT_CONFIGURATION_FILENAME, cle);
return;
} catch (ValidationException ve) {
System.err.printf(
"Invalid configuration in the %s file. Exception: %s%n",
DEFAULT_CONFIGURATION_FILENAME, ve);
return;
} catch (OAuthException oe) {
System.err.printf(
"Failed to create OAuth credentials. Check OAuth settings in the %s file. "
+ "Exception: %s%n",
DEFAULT_CONFIGURATION_FILENAME, oe);
return;
}
AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();
try {
runExample(adWordsServices, session);
} catch (ApiException apiException) {
System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
if (apiException.getErrors() != null) {
int i = 0;
for (ApiError apiError : apiException.getErrors()) {
System.err.printf(" Error %d: %s%n", i++, apiError);
}
}
} catch (RemoteException re) {
System.err.printf(
"Request failed unexpectedly due to RemoteException: %s%n", re);
}
AdWordsServicesInterface adWordsServices, AdWordsSession session) throws RemoteException {
// Get the TrafficEstimatorService.
TrafficEstimatorServiceInterface trafficEstimatorService =
adWordsServices.get(session, TrafficEstimatorServiceInterface.class);
Full source: https://developers.google.com/adwords/api/docs/samples/java/basic-operations
Do you know how I can use service account into the above code?
It looks like Adwords does support service account Authentication
OAuth2 service accounts
The AdWords API allows service account access through G Suite domains.
Which means you need to have your Gsuite domain admin authorize your service account to access it.
The Code should look something like this to authorize a service account
/**
* Initializes an adwords service object.
*
* #return An authorized adwords service object.
* #throws IOException
* #throws GeneralSecurityException
*/
private static AdWordsServices initializeAdWords() throws GeneralSecurityException, IOException {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
GoogleCredential credential = GoogleCredential
.fromStream(new FileInputStream(KEY_FILE_LOCATION))
.createScoped(AdwordsScopes.all());
// Construct the Analytics Reporting service object.
return new AdWordsServices.Builder(httpTransport, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME).build();
}

Google Calendar get all events from every calendar

I would like to retrieve all the events within a calendar, then categorize them by calendar.
Here is what I have so far.
public class Quickstart {
/** Application name. */
private static final String APPLICATION_NAME =
"Google Calendar API Java Quickstart";
/** Directory to store user credentials for this application. */
private static final java.io.File DATA_STORE_DIR = new java.io.File(
System.getProperty("user.home"), ".credentials/calendar-java-quickstart");
/** Global instance of the {#link FileDataStoreFactory}. */
private static FileDataStoreFactory DATA_STORE_FACTORY;
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY =
JacksonFactory.getDefaultInstance();
/** Global instance of the HTTP transport. */
private static HttpTransport HTTP_TRANSPORT;
/** Global instance of the scopes required by this quickstart.
*
* If modifying these scopes, delete your previously saved credentials
* at ~/.credentials/calendar-java-quickstart
*/
private static final List<String> SCOPES =
Arrays.asList(CalendarScopes.CALENDAR_READONLY);
static {
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}
/**
* Creates an authorized Credential object.
* #return an authorized Credential object.
* #throws IOException
*/
public static Credential authorize() throws IOException {
// Load client secrets.
BufferedReader br = new BufferedReader( new FileReader("C:\\Users\\User\\.credentials\\calendar-java-quickstart\\client_secret.json"));
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, br);
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(DATA_STORE_FACTORY)
.setAccessType("offline")
.build();
Credential credential = new AuthorizationCodeInstalledApp(
flow, new LocalServerReceiver()).authorize("user");
System.out.println(
"Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
return credential;
}
/**
* Build and return an authorized Calendar client service.
* #return an authorized Calendar client service
* #throws IOException
*/
public static com.google.api.services.calendar.Calendar
getCalendarService() throws IOException {
Credential credential = authorize();
return new com.google.api.services.calendar.Calendar.Builder(
HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
}
public static void main(String[] args) throws IOException {
// Build a new authorized API client service.
// Note: Do not confuse this class with the
// com.google.api.services.calendar.model.Calendar class.
com.google.api.services.calendar.Calendar service =
getCalendarService();
String pageToken = null;
// List the next 10 events from the primary calendar.
DateTime now = new DateTime(System.currentTimeMillis());
Events events = service.events().list("primary")
.setPageToken(pageToken)
.setMaxResults(10)
.setTimeMin(now)
.setOrderBy("startTime")
.setSingleEvents(true)
.execute();
List<Event> items = events.getItems();
do
{
CalendarList calendarList = service.calendarList().list().setPageToken(pageToken).execute();
List<CalendarListEntry> items2 = calendarList.getItems();
for (CalendarListEntry calendarListEntry : items2)
{
System.out.println(calendarListEntry.getSummary());
}//for
while(pageToken != null)
pageToken = calendarList.getNextPageToken();
}//do
while (pageToken != null);
System.out.println("------------------------------");
if (items.size() == 0)
{
System.out.println("No upcoming events found.");
}//if
else
{
for (Event event : items)
{
DateTime start = event.getStart().getDateTime();
if (start == null)
{
start = event.getStart().getDate();
}//if
System.out.println(event.getSummary());
}//for
}//else
}//main
As you can see, I can get all the events (from the primary calendar) and all the names of the available calendars.
How can I fetch the calendarId so I can sort the events by Calendar?
Calendar list returns a clandarListResponse
{
"kind": "calendar#calendarList",
"etag": etag,
"nextPageToken": string,
"nextSyncToken": string,
"items": [
calendarList Resource
]
}
You are already looping tough each calendarListEntry but instead of doing your summary you should just request the fields you want in this case id.
Each calendar#calendarListEntry has an id value which is the calendar id you are looking for.
I am not a java developer but I would guess something ike
for (CalendarListEntry calendarListEntry : items) {
System.out.println(calendarListEntry.getId());
}

Google Reseller API getting GoogleJsonResponseException: 403 Forbidden

I'm working on a project that uses the Google Apps Reseller API (Found here).
I'm running into a 403 Forbidden Exception.
Code (most of it origins from the Google Codelab Example Here:
try {
try {
Reseller service = GoogleResellerApiUtil.getResellerService();
Customer customerRecord = service.customers().get("acme.com").execute(); //crashes here
// "acme.com" is also used in the example from Google
System.out.println(customerRecord.toString());
} catch (GoogleJsonResponseException e) {
e.printStackTrace();
}
And this is the class I use to connect to the API.
I've provided a p12 file and it uses the service account, when calling the API it is impersonating one of the super admins, so it should be allowed to make all the calls.
At the moment I'm only using the read-only scope.
public class GoogleResellerApiUtil {
/** HTTP_TRANSPORT */
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
/** JSON Factory*/
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
/** Service Account Email */
public static final String SERVICE_ACCOUNT_EMAIL = "****#appspot.gserviceaccount.com";
/** P12 File Location */
public static final String PRIVATE_KEY_FILE = "WEB-INF/key.p12";
/** Reseller Admin Account to impersonate */
public static final String RESELLER_ADMIN = "**.**#**.com";
/** Scopes */
public static final List<String> SCOPES = Arrays.asList(ResellerScopes.APPS_ORDER_READONLY);
/** Application name. */
private static final String APPLICATION_NAME = "**-subscription-portal";
/** Logger */
private final static Logger LOGGER =
Logger.getLogger(GoogleResellerApiUtil.class.getName());
public static GoogleCredential getCredentials() throws IOException {
GoogleCredential credentials = null;
try {
credentials = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(SCOPES)
.setServiceAccountUser(RESELLER_ADMIN)
.setServiceAccountPrivateKeyFromP12File(new File(PRIVATE_KEY_FILE))
.build();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
System.out.println("credential has been build, returning credential "); //this gets printed, so I think the credentials are valid?
return credentials;
}
/**
* Build and return an authorized Reseller client service.
* #return an authorized Reseller client service
* #throws IOException
*/
public static Reseller getResellerService() throws Exception {
Credential credential = getCredentials();
return new Reseller.Builder(
HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
}
}
But I get the following error message when making the call:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 OK
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Forbidden",
"reason" : "forbidden"
} ],
"message" : "Forbidden"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
etc. etc. etc.
It is noted in Reseller API: Manage Subscriptions that
Note: If the customerAuthToken is not valid or has expired, the API response returns a 403 "Forbidden" error.
To solve the issue, please make sure that requests must be authorized by an authenticated user who has access to the data. As also noted in Reseller API: Authorizing
Note: The user granting permission for the Reseller API must be a domain super administrator.
In addition to that, it was suggested in Token expiration that you write your code to anticipate the possibility that a granted token might no longer work. A token might stop working for one of these reasons:
The user has revoked access.
The token has not been used for six months.
The user changed passwords and the token contains Gmail scopes.
The user account has exceeded a certain number of token requests.
Hope that helps!

Invalid channel Id return by youtube service api

I am trying to get a list of my youtube channels from a java app using the com.google.api.services.youtube.YouTube class. .
First of all I have enabled the Service Account credentials (https://console.developers.google.com > Credentials ) and I have enabled the following apis :
-YouTube Analytics API
-YouTube Data API
-Analytics API
To make a call to the Youtube service I create a Credential object using the following code.
/** Global instance of the HTTP transport. */
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static Credential authorize() throws Exception
{
List<String> scopes = new ArrayList<String>();
scopes.add("https://www.googleapis.com/auth/youtube");
scopes.add("https://www.googleapis.com/auth/yt-analytics.readonly");
scopes.add("https://www.googleapis.com/auth/youtube.readonly");
scopes.add("https://www.googleapis.com/auth/youtubepartner-channel-audit");
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountPrivateKeyFromP12File(new File("C://file.privatekey.p12"))
.setServiceAccountId("xxxx-yyyyyyyyyyyyyy#developer.gserviceaccount.com")
.setServiceAccountScopes(scopes)
.build();
return credential;
}
After that I call the Youtube service to get my channels
/** Global instance of the HTTP transport. */
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
/** Global instance of Youtube object to make general YouTube API requests. */
private static YouTube youtube;
/** Global instance of YoutubeAnalytics object to make analytic API requests. */
private static YouTubeAnalytics analytics;
public String getDefaultChannelId(){
try{
Credential credential = authorize();
// YouTube object used to make all non-analytic API requests.
youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName("API Project")
.build();
YouTube.Channels.List channelRequest = youtube.channels().list("id,snippet");
channelRequest.setMine(true);
channelRequest.setMaxResults(50L);
channelRequest.setFields("items(id,snippet/title,contentDetails,status,kind,etag,auditDetails)");
ChannelListResponse channels = channelRequest.execute();
System.out.println(channels.getItems());
// List of channels associated with user.
List<Channel> listOfChannels = channels.getItems();
// Grab default channel which is always the first item in the list.
Channel defaultChannel = listOfChannels.get(0);
String channelId = defaultChannel.getId();
return channelId;
}catch(Exception ex){
ex.printStacktrace();
}
}
The authorization code seems to work without any problem. The problem is with the getDefaultChannelId() method which returns a channel with id UC9i22sTxrX0IQk4AkT_Og3w .
I tried to navigate using the browser to my youtube channel using tha url : http://www.youtube.com/channel/UC9i22sTxrX0IQk4AkT_Og3w but the channel does not exist..
The line I used to print the channels results "System.out.println(channels.getItems());" displays the following json string.
[{"etag":"\"BDC7VThyM9nfoSQm1_kOyhtJTEw/yJvLzly7DMctrvFV5drOtgksadM\"","id":"UC9i22sTxrX0IQk4AkT_Og3w","kind":"youtube#channel","snippet":{"title":""}}
For some reason the youtube service does not return the right list of channels for the specific credential object.
But why????
You can not use Service Account with Youtube API : https://developers.google.com/youtube/v3/guides/moving_to_oauth#service_accounts. Youtube API is supposed to raise an error with service account but apparently it doesn't.
You should instead create a client ID of type Installed Application then retrieve a refresh token for your user (https://developers.google.com/accounts/docs/OAuth2InstalledApp) and use this token to create credentials.
Here is an example (store clientId, clientSecret, refreshToken and accessToken wherever you like, as soon as you keep it secret, token response should be cached) :
private String clientId;
private String clientSecret;
private String refreshToken;
private String accessToken;
private TokenResponse tokenResponse;
private Credential createCredential() {
final GoogleCredential.Builder builder = new GoogleCredential.Builder();
builder.setTransport(HTTP_TRANSPORT);
builder.setJsonFactory(JSON_FACTORY);
builder.setClientSecrets(clientId, clientSecret);
builder.addRefreshListener(new CredentialRefreshListener() {
#Override
public void onTokenResponse(final Credential credential,
final TokenResponse tokenResponse) throws IOException {
this.tokenResponse = tokenResponse;
}
#Override
public void onTokenErrorResponse(final Credential credential,
final TokenErrorResponse tokenErrorResponse)
throws IOException {
this.tokenResponse = null;
// trace error
}
});
return builder.build();
}
private YouTube getYoutube() {
final Credential credential = createCredential();
if (this.tokenResponse == null) {
credential.setAccessToken(this.accessToken);
credential.setRefreshToken(this.refreshToken);
} else {
credential.setFromTokenResponse(this.tokenResponse);
}
final YouTube youtube = new YouTube.Builder(HTTP_TRANSPORT,
JSON_FACTORY, credential).setApplicationName("*****").build();
return youtube;
}

How to get userinfo with google-api after succesfully been authenticated?

I try to get the userinfo after successfully authenticate with a gmail account (tok is a valid token):
GoogleCredential credential2 = new GoogleCredential.Builder()
.setTransport(TRANSPORT).setJsonFactory(JSON_FACTORY)
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.setRequestInitializer((new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request)
throws IOException {
request.getHeaders().setAuthorization("Bearer ".concat(tok));
}
}))
.build();
Oauth2 userInfoService = new Oauth2.Builder(TRANSPORT,
JSON_FACTORY, credential2.getRequestInitializer())
.setApplicationName(APPLICATION_NAME).build();
Userinfo userInfo = userInfoService.userinfo().get().execute();
logger.warn("User email: {}", userInfo.getEmail());
logger.warn("User gender: {}", userInfo.getGender());
logger.warn("User complet name: {} - {}", userInfo.getFamilyName(), userInfo.getName());
But logs display 'null' for all fields, the json data returned contains only the id:
{
"id": "113695880661351193041"
}
What i'm supposed to do ? Add a special scope to do this? I tried it several times without success, just by adding scope=https://www.googleapis.com/auth/userinfo.profile as url parameter, maybe that's wrong ?
Hope someone can help or know how to add scopes to my request and get the correct response from this service.
This works for me :
Credential credential = OAuth2Utils.newFlow().loadCredential(userId);
Oauth2 service = new Oauth2.Builder(OAuth2Utils.HTTP_TRANSPORT, OAuth2Utils.JSON_FACTORY, credential).setApplicationName("appname").build();
UserInfo userInfo = service.userinfo().get().execute();
These are some of the properties that are returned :
userInfo.getBirthday()
userInfo.getFamilyName()
userInfo.getGender()
userInfo.getGivenName()
userInfo.getHd()
userInfo.getLink()
The utility class OAuth2Utils referred in the code :
/** Global instance of the HTTP transport. */
public final static HttpTransport HTTP_TRANSPORT = new UrlFetchTransport();
/** Global instance of the JSON factory. */
public final static com.google.api.client.json.JsonFactory JSON_FACTORY = new com.google.api.client.json.jackson2.JacksonFactory();
public static GoogleAuthorizationCodeFlow newFlow() throws IOException {
return new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, getClientCredential(),
Arrays.asList(SCOPES)).setCredentialStore(new OAuth2CredentialStore()).setAccessType("offline")
.setApprovalPrompt("force").build();
}

Categories