I've worked through the examples for performing OOB OAuth2 connections and it works fine from my laptop.
The challenge I'm having is that it fires up a browser, asking me to verify if I want to grant access for my app to the documents in question. From then on it stores my credential set in a local file and continues to work just fine.
The use case I have is that I have a number of departments in my company that want to leverage Google Docs spreadsheets for reporting. I then want to be able to run a program on a server (from a cron job) that can scrape this data and build an aggregated report for all departments.
I had intended on creating a "reporting user" that is granted read access to all of the documents in question, then run the report process using that identity.
I tried running it on my laptop, then copying the stored credentials to my server for it to use. But it seems those credentials are tied to the machine and so it forces a new verification flow via browser.
Any suggestions on how to work with the auth flow for Google Drive to allow me to do what I need?
TIA
Rather than needing to grant some user read-only access to all docs, I'd suggest using a service account which has been granted read-only access to all of your Google Apps domain user's docs:
https://developers.google.com/drive/delegation
use:
https://www.googleapis.com/auth/drive.readonly
as the OAuth scope that you grant the service account access to in the Control Panel. That way if the server is compromised you've limited access to read-only.
Create GoogleCredential with p12 file from API console (API Access > Create Another Client ID > Service Account etc):
GoogleCredential.Builder#setServiceAccountPrivateKeyFromP12File(File)
more info on Service Accounts
The other answers are better than this, but you can always get a set of credentials and save them in a file for reuse. Getting the credentials could be done with a web browser, but only once, and then your server could use them forever (as long as you request offline access and get a refresh token).
Related
Let's say we have a very simple Java application, that edits resources on remote servers, that it authenticates with using Access Tokens. Application always uses the same identity, so it is always using the same client id, secret and refresh token to obtain access token.
The whole authentication process is supposed to go through without user intervention and app should perform actions automatically triggered by the user from another application. The other app is sending HTTP requests, but the whole thing would only be accessed in internal network and there would be no "legal" way to access it outside of it.
Is there a way to keep this data (refresh token, client id, secret...) securely within my application?
I have seen similar questions, but they all talked about websites and cookies, but this is supposed to happen under the hood, without any frontend etc. so I don't think those apply to my issue.
Edit: the application will be deployed on an internal server so it's not a Desktop solution. Basically there is an internal app that will send HTTP request to mine, triggering edit on a remote server that is outside of the internal network.
It is not a good idea to store client secrets, access tokens, refresh tokens etc in persistence storage unless it is stored in a secret store (like Vault). But there are other options.
If you are using Spring then you can use Spring OAuth2RestTemplate or else you can write something similar by looking at the code.
It acquires or renews an access token transparently and caches to avoid round trips to Authorization server.
The simplest option is to use memory storage, but if that diesn't work because you need to deal with restarts etc, operating systems provide per-user secure storage. This is a model sometimes used by OAuth desktop or console clients:
Credential Manager on Windows
Keychain on macOS
Passwords and Keys on Linux
It would require some native interop to interact with these credential stores, via use of a library such as java-keytar.
DESKTOP EXAMPLE
For something to compare against see these resources of mine:
Node.js desktop keytar code
This blog post has some related screenshots towards the end
I would like to have access to my OneDrive files using Microsoft Graph API in Java. I've tested this sample : https://learn.microsoft.com/en-us/graph/tutorials/java, and added a "getFiles" part to it which displays informations about my files. For the moment, this works perfectly.
But I would like to avoid user sign-in each time I run the sample. Indeed, in the authentication part of the code, a DeviceCode is used to acquire the token, and I'm redirected to a Microsoft web page where I sign-in and authorize the application to have access to my account.
I tried to replace the DeviceCode with IntegratedWindowsAuthenticationParameters (I got this from here : https://github.com/Azure-Samples/ms-identity-java-desktop/blob/master/Integrated-Windows-Auth-Flow/src/main/java/IntegratedWindowsAuthFlow.java (line 73)) using my scopes and email address as parameters, but I got the error below :
"com.microsoft.aad.msal4j.MsalServiceException: WsTrust endpoint not found in metadata document"
Edit : IntegratedWindowsAuthenticationParameters isn't suitable for personal accounts like mine (xxxxx#hotmail.com), is there another way to acquire token with this type of account ?
Is it the right solution to access personal accounts ? Or did I miss something in the App configuration in AAD ? Are there any other solutions ?
Thank you for your help :)
Using a global tenant administrator account, which is your .onmicrosoft.com account.
Please verify and make sure you have logged in with the proper account for the App you registered.
username = xxxx#xxxx.onmicrosoft.com
Update
Integrated Windows Authentication (IWA) supports federated users only - users created in Active Directory and backed by Azure AD. Users created directly in Azure AD without Active Directory backing (managed users) can't use this authentication flow.
Please refer to this doc.
We want to download files from Google Storage in our application server. It is important to have read-only restricted access to a single bucket and nothing else.
At first I used a regular user account (not a service account) which have permissions to access all buckets in our Google Cloud project, and everything worked fine - my Java code opened buckets and downloaded files without problems.
Storage storage = StorageOptions.getDefaultInstance().getService();
Bucket b = storage.get( "mybucketname" );
Then I wanted to switch to use a specially created service account which has access to a single bucket only. So I created a service account, gave permissions to read a single bucket, and downloaded its key file. The permissions in Google Cloud Console are named as:
Storage Object Viewer (3 members) Read access to GCS objects.
gsutil command line utility works fine with this account - from the command line it allows accessing this bucket but not the others.
The initialization from the command line is done using the following command:
gcloud --project myprojectname auth activate-service-account files-viewer2#myprojectname.iam.gserviceaccount.com --key-file=/.../keyfilename.json
I even tried two different service accounts which have access to different buckets, and from the command line I can switch between them and gsutil gives access to a relevant bucket only, and for any other it returns the error:
"AccessDeniedException: 403 Caller does not have storage.objects.list access to bucket xxxxxxxxxx."
So, from the command line everything worked fine.
But in Java there is some problem with the authentication.
The default authentication I previously used with a regular user account stopped working - it reports the error:
com.google.cloud.storage.StorageException: Anonymous users does not have storage.buckets.get access to bucket xxxxxxxxxx.
Then I've tried the following code (this is the simplest variant because it relies on the key json file, but I've already tried a number of other variants found in various forums, with no success):
FileInputStream fis = new FileInputStream( "/path/to/the/key-file.json" );
ServiceAccountCredentials credentials = ServiceAccountCredentials.fromStream( fis );
Storage storage = StorageOptions.newBuilder().setCredentials( credentials )
.setProjectId( "myprojectid" ).build().getService();
Bucket b = storage.get( "mybucketname" );
And all I receive is this error:
com.google.cloud.storage.StorageException: Caller does not have storage.buckets.get access to bucket mybucketname.
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
The same error is returned no matter to what buckets I'm trying to access (even non-existing).
What confuses me is that the same service account, initialized with the same JSON key file, works fine from the command line.
So I think something is missing in Java code that ensures correct authentication.
TL;DR - If you're using Application Default Credentials (which BTW you are when you do StorageOptions.getDefaultInstance().getService();), and if you need to use the credentials from a service account, you can do so without changing your code. All you need to do is set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the full path of your service account json file and you are all set.
Longer version of the solution using Application Default Credentials
Use your original code as-is
Storage storage = StorageOptions.getDefaultInstance().getService();
Bucket b = storage.get( "mybucketname" );
Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the full path of your json file containing the service account credentials.
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service_account_credentials.json
Run your java application once again to verify that it is working as expected.
Alternate solution using hard-coded Service Account Credentials
The code example you posted for initializing ServiceAccountCredentials looks valid to me on a quick glance. I tried the following code snippet and it is working for me as expected.
String SERVICE_ACCOUNT_JSON_PATH = "/path/to/service_account_credentials.json";
Storage storage =
StorageOptions.newBuilder()
.setCredentials(
ServiceAccountCredentials.fromStream(
new FileInputStream(SERVICE_ACCOUNT_JSON_PATH)))
.build()
.getService();
Bucket b = storage.get("mybucketname");
When specifying a service account credential, the project ID is automatically picked up from the information present in the json file. So you do not have to specify it once again. I'm not entirely sure though if this is related to the issue you're observing.
Application Default Credentials
Here is the full documentation regarding Application Default Credentials explaining which credentials are picked up based on your environment.
How the Application Default Credentials work
You can get Application Default Credentials by making a single client
library call. The credentials returned are determined by the
environment the code is running in. Conditions are checked in the
following order:
The environment variable GOOGLE_APPLICATION_CREDENTIALS is checked. If this variable is specified it should point to a file that
defines the credentials. The simplest way to get a credential for this
purpose is to create a Service account key in the Google API Console:
a. Go to the API Console Credentials page.
b. From the project drop-down, select your project.
c. On the Credentials page, select the Create credentials drop-down,
then select Service account key.
d.From the Service account drop-down, select an existing service
account or create a new one.
e. For Key type, select the JSON key option, then select Create. The
file automatically downloads to your computer.
f. Put the *.json file you just downloaded in a directory of your
choosing. This directory must be private (you can't let anyone get
access to this), but accessible to your web server code.
g. Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to
the path of the JSON file downloaded.
If you have installed the Google Cloud SDK on your machine and have run the command gcloud auth application-default login, your
identity can be used as a proxy to test code calling APIs from that
machine.
If you are running in Google App Engine production, the built-in service account associated with the application will be used.
If you are running in Google Compute Engine production, the built-in service account associated with the virtual machine instance
will be used.
If none of these conditions is true, an error will occur.
IAM roles
I would recommend going over the IAM permissions and the IAM roles available for Cloud Storage. These provide control at project and bucket level. In addition, you can use ACLs to control permissions at the object level within the bucket.
If your use case involves just invoking storage.get(bucketName). This operation will require just storage.buckets.get permission and the best IAM role for just this permission is roles/storage.legacyObjectReader.
If you also want to grant the service account permissions to get (storage.objects.get) and list (storage.objects.list) individual objects, then also add the role roles/storage.objectViewer to the service account.
Thanks to #Taxdude's long explanation, I understood that my Java code should be all right, and started looking at other possible reasons for the problem.
One of additional things I've tried were the permissions set to the service account, and there I've found the solution – it was unexpected, actually.
When a service account is created, it must not be given permissions to read from Google Storage, because then it will have read permissions to ALL buckets, and it is impossible to change that (not sure why), because the system marks these permissions as "inherited".
Therefore, you have to:
Create a "blank" service account with no permissions, and
Configure permissions from the bucket configuration
To do so:
Open Google Cloud Web console
Open Storage Browser
Select your bucket
Open the INFO PANEL with Permissions
Add the service account with the Storage Object Viewer permission, but there are also permissions named Storage Legacy Object Reader and Storage Legacy Bucket Reader
Because of the word "Legacy" I thought those should not be used – they look like something kept for backward compatibility. And after experimenting and adding these "legacy" permissions, all of a sudden the same code I was trying all the time started working properly.
I'm still not entirely sure what is the minimal set of permissions I should assign to a service account, but at least now it works with all three "read" permissions on the bucket – two "legacy" and one "normal".
I know there are other questions regarding this issue, but even after reading those, looking at the associated links and checking the QuickBooks docs, I'm struggling to understand it all and I feel like I'm going around in circles.
I need to create a load of invoices in my QuickBooks Online account based on data in Excel/CSV files. I will take a long time to do it manually (as well as being really tedious work) and I'll have to do it again in the future. I'm just trying to write a Java desktop application that will parse the file data and create the invoices in QuickBooks Online.
This is only for me and only for my companies QuickBooks account. I don't need my application to access other QuickBooks accounts, but I understand that I still need to go through the oAuth process (or do I?) to get the credentials that will allow me to make requests.
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(
accessToken, accessTokenSecret, consumerKey, consumerSecret);
ServiceContext context = new ServiceContext(
realmID, IntuitServicesType.QBD, oauthValidator);
I keep hearing that I have to register my app with Intuit to get the consumerKey and consumerSecret, but when I try to do that through developer.intuit.com, it's requiring an app URL and host name domain. This is a desktop app, I don't have those.
Is there seriously no way to simply access my QuickBooks Online account using the SDK by just supplying my userID and password?
I understand that I still need to go through the oAuth process (or do I?)
Yes, you do.
but when I try to do that through developer.intuit.com, it's requiring an app URL and host name domain.
Just enter in localhost to get through the registration process.
Then, you can use Intuit's OAuth Playground tool to get the access tokens you need, without having to actually implement any website-based stuff.
https://appcenter.intuit.com/Playground/OAuth
Is there seriously no way to simply access my QuickBooks Online
account using the SDK by just supplying my userID and password?
There is no way to access your QuickBooks Online account programatically with just a username and password. You need to use OAuth.
It's really not that difficult if you just enter localhost in and use the Playground tool. Should take all of 30 minutes tops to get going.
i want my company website to access from my android phone but that website can only be accessed by registered member
i have login page in that i have to enter registered email and passwrd than directly from the login page only i have to redirect to my company web url ???
Please give suggestion
Thanks in advance
Edited, to be more explicit :
How to secure and restrict access to a website ?
Restrict network access
Maybe the simpliest solution. A web site is not always available on the internet or for everybody. In fact if your website sit in some machine in your company office, make it available on the net require more effort than just let local computers access to it.
What does that mean ? You configure your firewall and your network to allow access of your server for only some IP address/port. To continue on this network only solution, you can create a VPN that include your mobile phone devices.
Include authentification and authorization management directly in the application
The first solution is a first pass. It allow you to forbidd access to most people out of your organisation. But maybe you want more, you want for exemple that only people from marketing do have access to the web site. Or maybe you want depending of the user (or user group), allow them to do differents things.
The best way to do that is to directly manage uses rights into your website. You authenticate users, and when a specific functionnality is requested your firt verify is user has credential.
If you already have an IT department, it is likely that a directory is available with all users, their password and their groups. You can base your check on the directory, avoiding the harsle to create/delete users in your application directly.
Using a proxy to secure or authenticate access
This solution is like a melt of the other ones. First you make sure sure using network restriction that your web site is only accessible using the proxy machine (so only one IP basically). Then you use a web server (like Apache HTTPD server) as a proxy, or a gateway to access the website.
Basically, when a user want to request your website, it doesn't directly ask the application that manage it, but the proxy. Because the application server is isolated in the network, it doesn't have to be secured.
The proxy allow you to fine tune the behaviour of your web site :
you can add encryption using SSL to
all data that transit from the client
to server, so no senssible data is
sent unprotected
you can compress all data that
transit to optimize the bandwidth
usage (really important for mobile
device and their not so good
internet connexion).
you can use HTTP authentification to
check user has the right to access
to the page. This can be just a
login/password check, or a client
certificate to fully secure the
connexion, allowing only device
with the certificate to be granted
access.
You can tune access per group to certain part of the site, but this is not as flexible as retrictions done directly by the web site application.
Didn't catch you very well. Do you mean that you want your company website can just be accessed by android phone for registered member? If so, I think you can check what browser type can be used in android phone, and in your website check it from http request, like "String browserType=(String)request.getHeader("User-Agent");" .