I have run through the google example of using Authsub to retrieve Google feed data (http://code.google.com/appengine/articles/python/retrieving_gdata_feeds.html)
If I understand correctly, it is possible for a malicious hacker to call the 'next_url' (which google auth service calls with your token) and inject their own token?
Meaning that they could cause the Web apps to write to the Hackers google doc account instead of the authenticated user!
Does anyone know how to secure this url so that only google auth service can call it?
Below is the code I am referring to:
def get(self):
next_url = atom.url.Url('http', settings.HOST_NAME, path='/step1')
# Initialize a client to talk to Google Data API services.
client = gdata.service.GDataService()
gdata.alt.appengine.run_on_appengine(client)
# Generate the AuthSub URL and write a page that includes the link
self.response.out.write("""<html><body>
Request token for the Google Documents Scope
</body></html>""" % client.GenerateAuthSubURL(next_url,
('http://docs.google.com/feeds/',), secure=False, session=True))
Related
Below are my requirements.
Develop a flask app.
Use collections in the firebase in the app.
Deploy this app on Google App Engine using a standard service account
What I have done.
Created a service account
Downloaded the corresponding credentials json; I am calling it as key.json
written a main.py
cred = credentials.Certificate('key.json')
default_app = initialize_app(cred)
db = firestore.client()
user_ref = db.collection_group('Users')
#app.route('/', methods=['GET'])
def home():
return "<h1>Welcome to my first app</h1>"
#app.route('/users', methods=['GET'])
def getUsers():
try:
result = [user.to_dict() for user in user_ref .stream()]
return jsonify(result), 200
except Exception as e:
result = { "message:"failed"}
return jsonify(result), 500
I have tested this locally and also on deployed on Google App Engine.
In both the cases, key.json was in the same directory as the code.
I have verified that if this key.json is modified to store wrong data, then /users endpoint won't work and gives me a 500 error.
So far so good. I want to know if this is even the right approach.
I want the key.json authentication to applied even for the root / endpoint.
i.e., if the user supplies a valid key.json, only then the Welcome to my first app should be displayed.
Else, Unauthorized user message needs to be displayed.
As mentioned by #Gaefan and #DishantMakwana, as well as in this documentation:
An API key only identifies the application and doesn't require user authentication. It is sufficient for accessing public data.
So in order to authenticate/authorize your users you should reconsider your strategy. I would recommend you to follow the instructions in the Authenticating as an end user Documentation.
I have found that we can use Google Cloud Endpoints for API management. Works as a charm.
I have a private HTTP Google Cloud Function which I'd like to call from an AppEngine app in another project.
Ideally, the AppEngine Service Account would have roles/cloudfunctions.invoker on my Cloud Function, I'd turn off all other invokers, and I wouldn't have to worry about auth at all inside of the CF. I'm struggling to get the AppEngine identity passed along.
Google's docs show how to do this from one Cloud Function to another, but AppEngine instead uses its own identity library to simplify getting access tokens. AppEngine docs outline:
Identity for other AppEngine apps in the same project
Identity for Google APIs
Something seemingly unrelated: verifying a payload's signature
Any way to include the AppEngine identity such that Google's native Cloud Function invoker role will the request through?
For this situation you will need to do the authentication programmatically by yourself.
First you need to add the app engine service account to the Cloud Functions permission.
After that, you need to follow the steps for this situation. Basically you will need to create a JWT, to authorize it and then to include the JWT in your request.
Here you can find a code example for creating and authorising a JWT.
I have reproduced your situation in python. I used the code from the link I have sent to you, and then after I had my JWT alright, I made a request like this :
#app.route('/')
def index():
data = {'headers': request.headers,
'service_name': os.environ.get('GAE_SERVICE', '(running locally)'),
'environment': os.environ}
return render_template('index.html', data=data)
#app.route('/request')
def send_request():
import requests
receiving_function_url = 'YOUR-CLOUD-FUNCT-URL'
r=requests.get("http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token?audience="+receiving_function_url,
headers={'Metadata-Flavor': 'Google'})
response = make_iap_request('YOUR-CLOUD-FUNCTION-URL', 'YOUR-CLOUD-FUNCTION-URL')
print(response)
return response
if __name__ == '__main__':
app.run('127.0.0.1', port=8080, debug=True)
The dependencies you need, in requirements.txt:
flask
PyJWT==1.7.1
cryptography==2.7
google-auth==1.6.3
gunicorn==19.9.0
requests==2.22.0
requests_toolbelt==0.9.1
In this repository you can find more code examples on how to do IAP(Identity Aware Proxy) requests.
I'm building a multi tenant app using Angular and Node.js, is it wise to have the same API for both Front End users (Public) and Admin Area users (Tenants)?
The Admin Area will require authentication for viewing and modifying sensitive data but I don't see why the rest of the API can't be left open for the front end which is only querying data?
Is this a good idea? Will it cause problems further down the line?
I'm looking to go for the following application structure:
Front end: tenant-name.domain.com (Open to public)
Admin area: domain.com/admin (with login and token auth)
API: api.domain.com
Would it be a good idea to have the client's front end authenticate with the API?
I would suggest that the admin area API calls require an auth token to be passed on all API calls. You can inject the token into the headers with http request interceptors in Angular. A user who does not already have an auth token should have to log in to get one. The injected auth token should be all the security you need.
I'll suggest you to create a token when an anonymous user requests your API. Reason for that is that you can always identify who requested what.
My Setup
Backend: Google App Engine (Java) w/ Google Cloud Endpoints using Endpoint's built in authentication
Frontend: AngularJS web app
Problem
I need to get the Google+ profile for my users. The keyword "me" can generally be used to get the current user's Google+ profile, however since all the authentication, in Google Cloud Endpoints, is done under the hood, I don't see anyway to get credentials, nor a token, for the current user. All you get it the com.google.appengine.api.users.User object.
Is there any way to get user credentials, or the access token, when using Google Cloud Endpoint's built in authentication?
Note: Google+ profile ID is different form Google account ID.
Possible Solution
I could just use the Google+ JS client with the keyword "me" and have the user send their Google+ ID and then subsequently store it and tie it to their Google Account ID, but this would be incredible insecure as the user could hack their way to sending the ID of any Google+ account.
It is possible to get the user access token when using Google Cloud Endpoint's built in authentication.
Add the parameter HttpServletRequest request to your Google Cloud endpoint as shown below. This will allow you to get the raw request.
You will then need to retreive the header called Authentication. This will get a Bearer access token that will allow you to build credentials to impersonate the authenticated user.
Next you will use that Bearer access token to build a com.google.api.client.googleapis.auth.oauth2.GoogleCredential object. You will need this to build the Plus service.
Use the Plus builder to build a Plus service object with the credential you just created.
Sample Code
#ApiMethod(path = "myPath")
public void myEndpoint(HttpServletRequest request, ParmOne paramOne, ...) throws OAuthRequestException {
if (user == null) {
throw new OAuthRequestException("Authentication error!");
}
GoogleCredential credentialAsUser = new GoogleCredential().setAccessToken(request.getHeader("Authorization").substring(7)); // Start string at index position 7 to remove prefix "Bearer" from token.
Plus plus = new Plus.Builder(new UrlFetchTransport(), new JacksonFactory(), credentialAsUser).setApplicationName("my-app").build();
Person profile = plus.people().get("me").execute();
}
Documentation
The Java docs for the Google Plus client can be found here.
The Java docs for instructions on creating Google credentials can be found here.
Additional Answer for Android Clients
Problem
In addition to the Marc's answer it is important that the GoogleCredentials-Object needs an access_token in the request-header.
If you call the endpoint with your apiExplorer or a javascript endpoint, this token is already served in the Authorization-header. But if you follow the docs for an android client your requests header contains an id_token, so GoogleCredentials.setAccessToken does not work.
Solution
To change the type of authorization to an access_token simply create your GoogleAccountCredential-Object in Android with usingOAuth2 instead of usingAudience.
Example
Replace this code in your Android App
credential = GoogleAccountCredential.usingAudience(this,
"server:client_id:1-web-app.apps.googleusercontent.com");
with this
credential = GoogleAccountCredential.usingOAuth2(this,
Collections.singleton(Scopes.PLUS_LOGIN));
and send it to your Api, as it is explained by the documentation
Helloworld.Builder helloWorld = new Helloworld.Builder(AppConstants.HTTP_TRANSPORT,
AppConstants.JSON_FACTORY,credential);
Hi so I have been trying to make an app that uses a Biq Query API.
All the authentication and client secrets for OAuth2 work fine when I load the app locally, however after deploying the code I get the following error:
Error: redirect_uri_mismatch
Request Details
scope=https://www.googleapis.com/auth/bigquery
response_type=code
redirect_uri=https://terradata-test.appspot.com/oauth2callback
access_type=offline
state=https://terradata-test.appspot.com/
display=page
client_id=660103924069.apps.googleusercontent.com
But looking at my API Console, I find that the redirect uri https://terradata-test.appspot.com/oauth2callback is in my list or redirect uri's:
Redirect URIs:
1.https://terradata-test.appspot.com/oauth2callback
2.http://terradata-test.appspot.com/oauth2callback
3.http://1.terradata-test.appspot.com/oauth2callback
4.https://code.google.com/oauthplayground
I'm not sure what I'm missing to fix this problem? Why is there a redirect error with a uri that is listed in the API console?
The app builds the OAuth2 decorator to pass through to the Biq Query API like this:
CLIENT_SECRETS = os.path.join(os.path.dirname(__file__),
'client_secrets.json')
decorator = oauth2decorator_from_clientsecrets(
CLIENT_SECRETS,
'https://www.googleapis.com/auth/bigquery')
http = httplib2.Http(memcache)
bq = bqclient.BigQueryClient(http, decorator)
Is there any more code I should put to clarify the situation? Any input would be greatly appreciated. Thanks so much!
Shan
In standard web server OAuth 2.0 flows (authorization code), there are 3 places the redirect_uri is used. It must be identical in all three places:
In the URL you redirect the user to for them to approve access and
get an authorization code.
In the APIs console
In the
server-to-server HTTPS post when exchanging an authorization code
for an access token (+ maybe a refresh token)
You haver to create an API credentials with next steps on
https://console.cloud.google.com/apis/credentials
Client Oauth Id
Web Type
JavaScript authorized -> https://yourapp.appspot.com
URIs authorized -> https://yourapp.appspot.com/oauth2callback
This is the credentials you have to use in local app before deploy