Get Google SpreadsheetService using OAuth - google-app-engine

I'm developing GWTP project, and below scenarios are tested successfully in my local development mode :
Get authenticated and authorized by OpenID and OAuth
Save GoogleOAuthParameters object into HttpSession.
Another action handler reuses the GoogleOAuthParameters stored in session to get SpreadsheetService object.
Use SpreadsheetService to manipulate spread sheets in GDoc.
However, when being deployed to App Engine, nothing can be read from GDoc, and no error/warning also, and returned list is always empty.
spreadsheetService = new SpreadsheetService("test");
GoogleOAuthParameters oauthParameters = (GoogleOAuthParameters)sessionProvider.get().getAttribute(HttpSessionProvider.PARAM_OAUTH_PARAMETERS);
spreadsheetService.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
oauthParameters.setScope(SCOPE_SPREADSHEET);
If I clearly use username/password as below when initializing SpreadsheetService, I can retrieve data from GDoc.
SpreadsheetService sService = new SpreadsheetService("test");
sService.setUserCredentials("username", "password");
I'm using App Engine SDK 1.6.6, and gdata-spreadsheet-3.0.
Please advise whether anything I did wrongly.
Thanks!

The documentation is for .Net, not Java. If you want to develop in Java, I found a solution here: Sharing authentication/token between Android Google Client API and SpreadSheet API 3.0
String token = GoogleAuthUtil.getToken(
this,
this.accountName,
this.scopes);
SpreadsheetService service = new SpreadsheetService("my-service-name");
service.setProtocolVersion(SpreadsheetService.Versions.V3);
service.setHeader("Authorization", "Bearer " + token);
Note that this does not work for setting the token and results in a 401 for me:
// BAD CODE
service.setUserToken(token);
// BAD CODE

The documentation has complete samples in Java showing how to perform authentication with all supported mechanisms. The recommendation is to use OAuth 2.0 which is explained at:
https://developers.google.com/google-apps/spreadsheets/#performing_oauth_20

Related

Is there a way to use the authentication retrieved from Microsoft Teams (via TeamsFX) and use it for an internal web API?

I am currently working on a Tab application for Microsoft Teams and have stumbled upon the extension called TeamsFx which enables easy retrieval of an authentication token from Teams without the need of prompting the user every time. Likewise, I used the Teams Toolkit extension for Visual Studio to get started. The project is implemented with .NET 5.0.
What I need, is to use the same authentication token retrieved from Teams inside the tab to then access a web API that is implemented in the same project. I have spent two full days trying to work this issue out with pretty much no result. I can retrieve an authentication token via TeamsFx, but simply using this as the bearer auth token in my web api did nothing but it telling me that the signature was wrong.
I have tried adding something like this to my Startup class:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration, "AzureAd");
,but then it threw an exception because the TeamsFx library has already done the same with this call:
services.AddTeamsFxSimpleAuth(Configuration);
In previous Web API projects I have been able to set up Azure AD authentication to the site, and pretty seemlessly add the [Authorize] tag to any WebAPI classes and it just worked.
I hope that someone can save me from my own insanity ;D
Best,
//F_
I think this is the same question which created in Github, it is already answered and got the solution.
https://github.com/OfficeDev/TeamsFx/issues/1363
Since we only got JavaScript version of microsoft/teamsfx sdk, so we including webpack to wrapper it and using JSRuntime to trigger it in Blazor.
The webpack source code is in JS/src/index.js, you could add these code to get SSO token
export async function getSsoToken() {
var credential = new TeamsUserCredential();
var token = await credential.getToken("");
return token;
}
Then under JS folder , run 'npm install' and 'npm run build' to webpack the code and refresh the webpack file (wwwroot/teamsfx.js).
Finally you could using JSRuntime trigger the new func you just added in TeamsFx.cs.
await jsRuntime.InvokeAsync<AccessToken>("TeamsFx.getSsoToken");

Scope for multiple web apis

I have 2 web apis (A and B) on my b2c. Each one of them publishes their own permissions respectively (scopeA1, scopeA2) and (scopeB1, scopeB2).
On my web application (which already configured and have granted access permission on both apis and the 4 scopes), in order to get authorization code for both apis during authentication, I tried to set my OpenIdConnectAuthenticationOptionsin scope property to include the 4 scopes.
I got an error AADB2C90146: The scope 'scopeA1 scopeA2 scopeB1 scopeB2 openid offline_access' provided in request specifies more than one resource for an access token, which is not supported.
While if I specify only scopes for web api A or B, then it works as per this link
How can I get my web app to use both web apis even with granted permissions for both
Thanks for help
If the two web APIs are separate applications in Azure AD, then you need to request access tokens separately for them.
I'm not familiar with the sample you used as a starting point, but it looks like these lines are where you need to make your change:
// Retrieve the token using the provided scopes
ConfidentialClientApplication app = new ConfidentialClientApplication(authority, Startup.ClientId,
Startup.RedirectUri, credential,
new NaiveSessionCache(userObjectID, this.HttpContext));
AuthenticationResult result = await app.AcquireTokenSilentAsync(scope);
accessToken = result.Token;
You should create an app instance for each of your APIs, and acquire a token for each of them. Then, when you call the APIs somewhere else, use the correct access token in the Bearer authentication header.
I had the same issue and asked a similar question Extend MSAL to support multiple Web APIs
but i have not had an answer, basically to get around it in the short term i have made both my API's use the same authorization client ID + secret and therefore I can reuse the same scopes accross my APIS
its not what i want but if you want to use Azure AD B2C you need to get used to compromising for a while until the support is there
-- I would also say you are using an older version of MSAL which i am also using, im waiting until the version 1 release before upgrading again.
The github talks about using this format
https://github.com/AzureAD/microsoft-authentication-library-for-dotnet
Step 1: Add MSAL to your Solution/Project
Right click on your project > Manage packages.
Select include prerelease > search msal.
Select the Microsoft.Identity.Client package > install.
Step 2: Instantiate MSAL and Acquire a Token
Create a new PublicClientApplication instance. Make sure to fill in your
app/client id
PublicClientApplication myApp = new PublicClientApplication(CLIENT_ID);
Acquire a token
AuthenticationResult authenticationResult = await
myApp.AcquireTokenAsync(SCOPES).ConfigureAwait(false);
Step 3: Use the token!
The access token can now be used in an HTTP Bearer request.

How do I protect my API that was built using Google Cloud Endpoints?

The API is a backend to a mobile app. I don't need user authentication. I simply need a way to secure access to this API. Currently, my backend is exposed.
The documentation seems to only talk about user authentication and authorization, which is not what I need here. I just need to ensure only my mobile app can talk to this backend and no one else.
Yes, you can do that: use authentication to secure your endpoints without doing user authentication.
I have found that this way of doing it is not well documented, and I haven't actually done it myself, but I intend to so I paid attention when I saw it being discussed on some of the IO13 videos (I think that's where I saw it):
Here's my understanding of what's involved:
Create a Google API project (though this doesn't really involve their API's, other than authentication itself).
Create OATH client ID's that are tied to your app via its package name and the SHA1 fingerprint of the certificate that you will sign the app with.
You will add these client ID's to the list of acceptable ID's for your endpoints. You will add the User parameter to your endpoints, but it will be null since no user is specified.
#ApiMethod(
name = "sendInfo",
clientIds = { Config.WEB_CLIENT_ID, Config.MY_APP_CLIENT_ID, Config.MY_DEBUG_CLIENT_ID },
audiences = { Config.WEB_CLIENT_ID }
// Yes, you specify a 'web' ID even if this isn't a Web client.
)
public void sendInfo(User user, Info greeting) {
There is some decent documentation about the above, here:
https://developers.google.com/appengine/docs/java/endpoints/auth
Your client app will specify these client ID's when formulating the endpoint service call. All the OATH details will get taken care of behind the scenes on your client device such that your client ID's are translated into authentication tokens.
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience( ctx, Config.WEB_CLIENT_ID );
//credential.setSelectedAccountName( user ); // not specify a user
Myendpoint.Builder builder = new Myendpoint.Builder( transport, jsonFactory, credential );
This client code is just my best guess - sorry. If anyone else has a reference for exactly what the client code should look like then I too would be interested.
I'm sorry to say that Google doesn't provide a solution for your problem (which is my problem too).
You can use their API key mechanism (see https://developers.google.com/console/help/new/#usingkeys), but there is a huge hole in this strategy courtesy of Google's own API explorer (see https://developers.google.com/apis-explorer/#p/), which is a great development tool to test API's, but exposes all Cloud Endpoint API's, not just Google's services API's. This means anyone with the name of your project can browse and call your API at their leisure since the API explorer circumvents the API key security.
I found a workaround (based on bossylobster's great response to this post: Simple Access API (Developer Key) with Google Cloud Endpoint (Python) ), which is to pass a request field that is not part of the message request definition in your client API, and then read it in your API server. If you don't find the undocumented field, you raise an unauthorized exception. This will plug the hole created by the API explorer.
In iOS (which I'm using for my app), you add a property to each request class (the ones created by Google's API generator tool) like so:
#property (copy) NSString *hiddenProperty;
and set its value to a key that you choose. In your server code (python in my case) you check for its existence and barf if you don't see it or its not set to the value that your server and client will agree on:
mykey,keytype = request.get_unrecognized_field_info('hiddenProperty')
if mykey != 'my_supersecret_key':
raise endpoints.UnauthorizedException('No, you dont!')
Hope this puts you on the right track
The documentation is only for the client. What I need is documentation
on how to provide Service Account functionality on the server side.
This could mean a couple of different things, but I'd like to address what I think the question is asking. If you only want your service account to access your service, then you can just add the service account's clientId to your #Api/#ApiMethod annotations, build a GoogleCredential, and invoke your service as you normally would. Specifically...
In the google developer's console, create a new service account. This will create a .p12 file which is automatically downloaded. This is used by the client in the documentation you linked to. If you can't keep the .p12 secure, then this isn't much more secure than a password. I'm guessing that's why this isn't explicitly laid out in the Cloud Endpoints documentation.
You add the CLIENT ID displayed in the google developer's console to the clientIds in your #Api or #ApiMethod annotation
import com.google.appengine.api.users.User
#ApiMethod(name = "doIt", scopes = { Constants.EMAIL_SCOPE },
clientIds = { "12345678901-12acg1ez8lf51spfl06lznd1dsasdfj.apps.googleusercontent.com" })
public void doIt(User user){ //by convention, add User parameter to existing params
// if no client id is passed or the oauth2 token doesn't
// match your clientId then user will be null and the dev server
// will print a warning message like this:
// WARNING: getCurrentUser: clientId 1234654321.apps.googleusercontent.com not allowed
//..
}
You build a client the same way you would with the unsecured version, the only difference being you create a GoogleCredential object to pass to your service's MyService.Builder.
HttpTransport httpTransport = new NetHttpTransport(); // or build AndroidHttpClient on Android however you wish
JsonFactory jsonFactory = new JacksonFactory();
// assuming you put the .p12 for your service acccount
// (from the developer's console) on the classpath;
// when you deploy you'll have to figure out where you are really
// going to put this and load it in the appropriate manner
URL url = getClass().class.getResource("/YOURAPP-b12345677654.p12");
File p12file = new File(url.toURI());
GoogleCredential.Builder credentialBuilder = new GoogleCredential.Builder();
credentialBuilder.setTransport(httpTransport);
credentialBuilder.setJsonFactory(jsonFactory);
//NOTE: use service account EMAIL (not client id)
credentialBuilder.setServiceAccountId("12345678901-12acg1ez8lf51spfl06lznd1dsasdfj#developer.gserviceaccount.com"); credentialBuilder.setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/userinfo.email"));
credentialBuilder.setServiceAccountPrivateKeyFromP12File(p12file);
GoogleCredential credential = credentialBuilder.build();
Now invoke your generated client the same way
you would the unsecured version, except the builder takes
our google credential from above as the last argument
MyService.Builder builder = new MyService.Builder(httpTransport, jsonFactory, credential);
builder.setApplicationName("APP NAME");
builder.setRootUrl("http://localhost:8080/_ah/api");
final MyService service = builder.build();
// invoke service same as unsecured version

Custom SignIn & SignUp on RESTlet + GAE/J?

I am currently working on a small project using RESTlet on Google App Engine/Java.
I was searching.. searching.. and couldn't find the exact or understandable solutions for my doubts.
My question is that How am I suppose to implement my own SignIn & SignUp module without using google's UserService or Spring Security??
Is there any actual sample code available??
I mean SignUp part is just a simple JDO insert & select module. let's just say I've done it.
How am I supposed to handle each user's request session and authentication??
I am thinking about using HTTPS on every request.
Any suggestions or help would be really appreciated!
Thanks in advance.
In Restlet, you have security support on both client and server sides. On client side, you can specify security hints using the ChallengeResponse entity. This feature is open and you can specify the authentication type you want. In the following code, I use an http basic authentication based on username / password:
ClientResource cr = new ClientResource(uri);
ChallengeScheme scheme = ChallengeScheme.HTTP_BASIC;
ChallengeResponse authentication = new ChallengeResponse(
scheme, "username", "password");
cr.setChallengeResponse(authentication);
Restlet will automatically build necessary headers in the corresponding request. You can note that Restlet supports a wide range of authentication types through its extensions. I know that some work is done at the moment to support OAuth v2 (see http://wiki.restlet.org/developers/172-restlet/257-restlet/310-restlet.html).
On the server side, you need to secure accesses at routing level using the ChallengeAuthenticator entity, as described below. This can be done within your Restlet application:
public Restlet createInboundRoot() {
Router router = new Router(getContext());
ChallengeAuthenticator guard = new ChallengeAuthenticator(getContext(),
ChallengeScheme.HTTP_BASIC, "realm");
guard.setVerifier(verifier);
guard.setEnroler(enroler);
guard.setNext(router);
return guard;
}
Like for client side, this support is generic and is based on two interfaces that need to be specified on the guard:
The verifier one to check if authentication is successful
The enroler one to fill roles for the authenticated user
You can notice that same security technologies need to be use on both sides...
If you want to manage authentication session for user, you need to implement it by yourself using cookies.
When authentication successes on server side, you can return a cookie containing a security token that allows you checking the user from your database (for example). Some code like below can implement that:
CookieSetting cookie = new CookieSetting(0,
SECURITY_COOKIE_NAME, securityToken);
Series<CookieSetting> cookieSettings = response.getCookieSettings();
cookieSettings.clear();
cookieSettings.add(cookie);
You can extend for example the SecretVerifier class of Restlet to add a test on security data received and add this code when receiving the security cookie.
On client side, you need to add hints for authentication the first time and then re send the security cookie following times, as described below:
ClientResource clientResource = (...)
(...)
Cookie securityCookie = new Cookie(0,
SECURITY_COOKIE_NAME, securityToken);
clientResource.getRequest().getCookies().clear();
clientResource.getRequest().getCookies().add(securityCookie);
Hope it will help you!
Thierry
If you are interested in re-using social accounts, you need to integrate with each one like facebook oauth
And/Or use the app engine authentication via OpenID
Both ways define an API to authenticate a client, you can use the UserService or manage your own state via cookies.

How does one avoid a cyclic redirect when writing a facebook application using pyfacebook and google app engine?

I'm trying to write my first application for Facebook using
python and pyfacebook hosted on Google App Engine. The problem I'm facing is
that of cyclic redirects. Firefox dies complaining "This page isn't
redirecting properly" when I visit http://apps.facebook.com/appname.
Here's the code:
class CanvasHandler(webapp.RequestHandler):
def get(self):
## instantiate the Facebook API wrapper with your FB App's keys
fb = facebook.Facebook(config.FACEBOOK_API_KEY, config.FACEBOOK_API_SECRET)
## check that the user is logged into FB and has added the app
## otherwise redirect to where the user can login and install
if fb.check_session(self.request) and fb.added:
pass
else:
url = fb.get_add_url()
self.response.out.write('<script language="javascript">top.location.href="' + url + '";</script>')
return
rendered_template = render_template('facebook/app.html')
self.response.out.write(rendered_template)
I see this problem when I'm logged out of Facebook. Any help is appreciated.
If you're just starting out with your Facebook app, consider using the Official Python SDK which accesses the Graph API. The REST API is being phased out.
To do authentication, use the JS SDK which will set a cookie you can read on the server side.
I agree with cope360. I've been playing around with facebook app development for a little while now. They seem to be changing their API frequently, so you'd be better off using the official libraries.
That said, to answer your question, pyfacebbok tries to get authenticaion information from information in django's HttpRequest.GET. This is out-dated, because facebook provides authenticaion info in POST data.
The source code that's responsible is in pyfacebook/facebook/__init__.py. The method name seems to be validate_request.

Resources