I'm finding a way to programatically list Google Cloud projects inside an organization. I'm trying to use a service account exported json credential to achieve such purpose in this way:
// More info on the endpoint here:
// https://cloud.google.com/resource-manager/reference/rest/v1/projects/list
final CloudResourceManager cloudResourceManagerService = createCloudResourceManagerService();
final CloudResourceManager.Projects.List listRequest = cloudResourceManagerService
.projects()
.list()
.setFilter("labels.it-restoring:false name:IT-TEST-*");
final ListProjectsResponse listResponse = listRequest.execute();
if (listResponse.isEmpty()) {
throw new RuntimeException("The API did not get any response"); // I never get past here
}
log.info("Listing projects returned: {}", listResponse);
The problem I find is that I always get an empty response. Even though I assigned the service account the role of owner. According to docs, I could use roles/
resourcemanager.organizationAdmin which I also set but with no luck. I create the CloudResourceManagement api object using getApplicationDefault.
However if I do gcloud beta auth application-default login which triggers an auth flow in the browser and authenticate with the user which is the owner of the organization this works and lists all the projects that I have.
Can anybody explain to me what I should do to store a proper credential which would emulate he user owner? I already set the service account with the Owner role which in theory gives virtually access to all resources and still no luck.
In order to list the projects on your organization, you need the permission resourcemanager.projects.get. Please find more information in this link The service account might have the owner role of 1 project, and not enought to list them all.
An alternative solution is to grant the account the cloudasset.assets.searchAllResources permission at org level by using one of the following roles:
roles/cloudasset.viewer
roles/cloudasset.owner
roles/viewer
roles/editor
roles/owner
With this permission, you can list all the projects within an organization 456:
gcloud asset search-all-resources \
--asset-types="cloudresourcemanager.googleapis.com/Project"
--scope=organizations/456
Documentation: https://cloud.google.com/asset-inventory/docs/searching-resources
Related post: How to find, list, or search resources across services (APIs) and projects in Google Cloud Platform?
Related
I am writing application that need to read mailbox using IMAP, but as daemon, without user interaction. I need to use OAuth2 to get access.
Because I need it without user interaction, I need to use client credentials flow. This was added this June.
I have done everything from official documentation. Registered application, added permissions, added mailbox permission using PowerShell.
When I get request access token with scope https://outlook.office365.com/.default, the one that I receive has role IMAP.AccessAsApp, so I believe that is correct. I used https://jwt.ms/ to parse JWT.
The problem is when I try to authenticate using this access token in Java, for example
Properties props = new Properties();
props.put("mail.imap.ssl.enable", "true");
props.put("mail.imap.auth.mechanisms", "XOAUTH2");
props.put("mail.debug", "true");
Session session = Session.getInstance(props);
Store store = session.getStore("imap");
store.connect("outlook.office365.com", 993, "testing#mydomain.com", "accessToken");
I receive AUTHENTICATE failed. I tried same code with access token received using authorization code flow, which requires user interaction. Using that access code I was able to connect to mailbox. So the code is correct.
I even tried using client id and service id instead of email address as username, but without success.
I am not sure where I made the mistake and if I am using correct username. Any help is appreciated.
I wrote same answer here, so I am coping it here.
I think I made some progress.
I read documentation few times, tried few times from the start with same error. I even have tried using client and object ids instead of email as username, in lack of better ideas.
So this is where I think I have made mistake previous times.
On the part where it is needed to register service principal, I needed to execute
New-ServicePrincipal -AppId <APPLICATION_ID> -ServiceId <OBJECT_ID> [-Organization <ORGANIZATION_ID>]
Here I have put enterprise application object id as ServiceId argument. And that is ok.
But on
Add-MailboxPermission -Identity "email address removed for privacy reasons" -User
<SERVICE_PRINCIPAL_ID> -AccessRights FullAccess
I have put my registered application object id as User argument. I also tried setting object id of enterprise application, but it did not have success.
When I executed
Get-ServicePrincipal -Organization <ORGANIZATION_ID> | fl
I did not pay attention to ServiceId property, even with documentation specifying it and saying it will be different.
Now I cleared everything and started fresh.
I have executed all the steps again, but on the step for creating new service principal I used data from enterprise application view. When I need to add mail permission, I list service principals, and then use ServiceId value from the output, as argument for user.
With that, I was able to authorise.
Thanks everyone for sharing your experience. This has proved to be a little confusing. :)
To sum everything up, to access a mailbox with IMAPS and OAuth2 (as opposed to using Graph API which is another method Microsoft recommends):
Create an Azure App Registration
Add API permission Office 365 Exchange Online - IMAP.AccessAsApp and grant admin consent
Create a service principal, which will be used to grant mailbox permissions to in Exchange Online
Connect-AzureAD
Connect-ExchangeOnline
$azapp = Get-AzureADApplication -SearchString 'App Registration Name'
$azsp = Get-AzureADServicePrincipal -SearchString $azapp.DisplayName
# GOTCHA: You need the ObjectId from 'Enterprise applications' (Get-AzureADServicePrincipal), not 'Application registrations' (Get-AzureADApplication) for ServiceId (thanks #[jamie][1])
$sp = New-ServicePrincipal -AppId $azapp.AppId -ServiceId $azsp.ObjectId -DisplayName "EXO Service Principal for $($azapp.DisplayName)"
Grant access rights to mailboxes for the service principal
$mbxs = 'mymbx1#yourdomain.tld',`
'mymbx2#yourdomain.tld',`
'mymbx3#yourdomain.tld'
$mbxs | %{ Add-MailboxPermission -Identity $_ -User $sp.ServiceId -AccessRights FullAccess } | fl *
Get-MailboxPermission $mbxs[-1] | ft -a
You can use Get-IMAPAccessToken.ps1 to test your setup
.\Get-IMAPAccessToken.ps1 -TenantID $TenantId -ClientId $ClientId -ClientSecret $ClientSecret -TargetMailbox $TargetMailbox
Other parameters you may need:
Authority: https://login.microsoftonline.com/<YourTenantId>/
Scope: https://outlook.office365.com/.default
I have a java application running in ECS in which I want to read data from table in account 1 (source_table) and write it to a table in account 2 (destination_table). I created two dynamodb clients with different credential providers - for source_table client I'm using an STSAssumeRoleSessionCredentialsProvider with the arn of a role in account 1; for destination client I'm using DefaultAWSCredentialsProviderChain.
The assume role bit works and I'm able to read using the source client but using the destination client does not work - it still tries to use the assumed role credentials when trying to write to destination_table and fails with unauthorized error (assumed-role is not authorized to perform Put Item).
I tried using EC2ContainerCredentialsProviderWrapper on the destination client but same error.
Should this work? Or are the credentials shared under the hood which makes it impossible to have two different AWSCredentialProviders running simultaneously like this?
I noticed this answer which uses static credentials and apparently works, so I'm at a loss why this doesn't work.
I figured it out with some help from AWS support. It was a problem with my IAM configuration on the role in account 2. I was misled by the error message which said 'assumed-role is not authorized to perform Put Item' when in fact my original account 2 role itself was unable to do so.
I was overwhelmed by the amount of information on https://dev.twitter.com/docs and then I went to twitter4j and downloaded the library. I got a consumer key and secret by registering on their website. What are these for?
What I am trying to is get tweet text from certain twitter account( not my personal one but public one) and other information( account user, time and other stuff).
I couldn't find useful tutorial online. So please help me. Thank you very much!
The keys are so that your application can authenticate to the Twitter API. I put them in a properties file and made them available on the classpath. Once your application has authenticated, you will be able to use the API to get the account information you need. I don't know any good tutorials, but you could use an open source project I wrote as a reference if you like: https://github.com/rossh/gift-findr.
This is an example of how to get hold of a org.twitter4j.Twitter object. Once you have that, you can do a great many operations - just inspect the interface for org.twitter4j.Twitter.
Twitter twitter = new TwitterFactory().getInstance(twitter4JConfiguration);
twitter.setOAuthConsumer(consumerKey, consumerSecret);
twitter.setOAuthAccessToken(new AccessToken(oauthToken, oauthTokenSecret));
String screenName = twitter.getScreenName(); // Returns authenticating user's screen name.
User stephenfry = twitter.showUser("stephenfry"); // Returns extended information of a given user ...
List<User> friends = twitter.getFriendsList("stephenfry", -1L); // Returns a cursored collection of user objects ...
This is a link to the javadoc for the org.twitter4j.Twitter interface
I am currently working on a Grails application (using Groovy which is similar to Java), where a user can view the profile of other users. On user's profile page, I need to show the LinkedIn connections shared between that user and the viewer's LinkedIn profiles.
For LinkedIn integration, I am currently using linkedin-j.jar
Using all that I could guess from the API documentation and Google search, I wrote the following code, which was unsuccessful to fetch shared connections.
Any help will be appreciated.
LinkedInAccessToken targetUserLiAccessToken = new LinkedInAccessToken(targetUserOauthToken, targetUserOauthSecret)
LinkedInApiClient targetUserLiApiClient= linkedInApiClientFactory.createLinkedInApiClient(targetUserLiAccessToken)
Person targetUserLiProrfile=targetUserLiApiClient.getProfileForCurrentUser([ProfileField.ID] as Set)
LinkedInAccessToken currentUserLiAccessToken = new LinkedInAccessToken(currUserOauthToken, currUserOauthSecret)
LinkedInApiClient currentUserLiApiClient= linkedInApiClientFactory.createLinkedInApiClient(currentUserLiAccessToken)
Person resultProfile = currentUserLiApiClient.getProfileById(targetUserProfile.id, [ProfileField.ID, ProfileField.RELATION_TO_VIEWER] as Set)
List<Person> commonConnections= resultProfile.relationToViewer.relatedConnections.personList
(Here the current User is viewer and target User is the one whose profile is being viewed.)
Upon running this code, I am getting the following results:
resultProfile.relationToViewer.relatedConnections: NULL
resultProfile.relationToViewer.distance: 2
But this is not as expected, the LinkedIn Profiles of both the users have one shared Connection
I was able to fix the issue.
The points where I was missing are:
The LinkedIn Application whose API Key and Secret I was using to retrieve data was configured to ask only BASIC_PROFILE permission (This was because LinkedIN recently introduced some changes in their API Permissions). NETWORK permissions were also required to access connections info.
In code, I should have used
ProfileField.RELATION_TO_VIEWER_RELATED_CONNECTIONS
instead of
ProfileField.RELATION_TO_VIEWER
Following is the final piece of code that worked for me:
LinkedInAccessToken targetUserLiAccessToken = new LinkedInAccessToken(targetUserOauthToken, targetUserOauthSecret)
LinkedInApiClient targetUserLiApiClient= linkedInApiClientFactory.createLinkedInApiClient(targetUserLiAccessToken)
Person targetUserLiProrfile=targetUserLiApiClient.getProfileForCurrentUser([ProfileField.ID] as Set)
LinkedInAccessToken currentUserLiAccessToken = new LinkedInAccessToken(currUserOauthToken, currUserOauthSecret)
LinkedInApiClient currentUserLiApiClient= linkedInApiClientFactory.createLinkedInApiClient(currentUserLiAccessToken)
Person resultProfile = currentUserLiApiClient.getProfileById(targetUserProfile.id, [ProfileField.ID, ProfileField.RELATION_TO_VIEWER_RELATED_CONNECTIONS] as Set)
List<Person> commonConnections= resultProfile.relationToViewer.relatedConnections.personList
I am building a client application for Intra Office Messaging System using Openfire as server. Using Roster class I can find the list of buddies (friends/contacts) using:
Roster rs= con.getRoster();
Collection<RosterEntry> list=rs.getEntries();
System.out.println("\n\n" + list.size() + " buddy(ies):");
for (RosterEntry r : list) {
System.out.println(r.getName());
}
But since this is an IOMS (Intra Office Messaging System), the requirement is diferent. There is no need to add contact. All users should see every other user and his status. Is there a way to achieve this?
One way to do this would be to integrating your openfire with AD. Add all users in a single common group and then import that group in the client. That way a user will automatically appear as a member of that group, and his/her online status will be available to all members of that group. And make sure whenever a new user is added, it becomes member of this group. This way everybody is imported at once in user's list.
Here is a reference link regarding same: Openfire Automatic Roster Population via Shared Groups and here is the guide to integrate Openfire with LDAP
Another way would be to update Openfire code and change registration process to add code for automatically adding all users to buddy list of the newly registered user. You can also do the same code on client side. But this is not a good path to walk on, as it will cause problem as the number of users in system grows.