IAP Signed Headers & AppEngine Standard Python 3.7 Runtime - google-app-engine

Is it necessary to validate signed headers from IAP in the AppEngine Standard Python 3.7 runtime?
The IAP documentation is silent on specifics for the Python 3.7 runtime.
The IAP documentation says:
AppEngine Standard should use the Users API
validation is required to secure applications in AppEngine Flex
The Users API is not available for Standard 3.7. Signed headers are. Validating the headers is possible.
I can see that AppEngine environment adds some headers. I'm wondering if the X-Appengine- values can be implicitly trusted (ie, does AppEngine attach these after validating the headers from IAP)?
X-Appengine-User-Id: <user id>
X-Appengine-Auth-Domain: <domain>
X-Appengine-User-Email: <user email>
...
X-Goog-Iap-Jwt-Assertion: <assertion>
X-Goog-Authenticated-User-Email: accounts.google.com:<user email>
X-Goog-Authenticated-User-Id: accounts.google.com:<user id>

From App Engine-specific headers:
For login:admin or login:required handlers specified in
app.yaml, App Engine also provides the following set of headers:
X-AppEngine-User-Email, with example header: "ange#example.com"
X-AppEngine-Auth-Domain,with example header: "example.com"
X-AppEngine-User-ID, with example header: "100979712376541954724"
So they can be trusted not to come from outside GAE. But I'm unsure how they relate to the IAP infra.
Since the Users API isn't supported I'd follow the advice for the flexible environment which, from this perspective, seems closer to the Python3 runtime - I'd validate the signed headers.

Related

AADSTS9002326: Cross-origin token redemption is permitted only for the 'SPA'

I'm trying to make a request for a token request to an API service running on the Azure platform. I solved the cross origin problem with proxy pass setting via Plesk, but when the request is forwarded, I get the following error and there is no solution.
{"error":"invalid_request","error_description":"AADSTS9002326:
Cross-origin token redemption is permitted only for the 'Single-Page
Application' client-type.\r\nTrace ID:
578a738f-3b77-4a4b-a425-160f38da2d00\r\nCorrelation ID:
cabc0d01-da8d-4b44-90b8-b182c1f21e1b\r\nTimestamp: 2022-07-03
18:51:58Z","error_codes":[9002326],"timestamp":"2022-07-03
18:51:58Z","trace_id":"578a738f-3b77-4a4b-a425-160f38da2d00","correlation_id":"cabc0d01-da8d-4b44-90b8-b182c1f21e1b","error_uri":"https://login.windows.net/error?code=9002326"}
My Nginx Proxy pass Settings
location /vipps/ {
proxy_pass https://apitest.vipps.no/;
}
underscores_in_headers on;
Request needs that headers
client_id
client_secret
Vipps-Subscription-Key
Merchant-Serial-Number
When I forward this problem to the vipps authority, it says you have the problem, but as far as I researched, it is related to the Azure platform.
As per this Microsoft Documentation,
Select Single-page application platform if you're building a client-side web app by using JavaScript or a framework like Angular, Vue.js, React.js, or Blazor WebAssembly.
Redirect URI for SPA:
As per Microsoft Documentation ,
The authorization code flow for single page applications requires additional setup. Follow the instructions for creating your single-page application to correctly mark your redirect URI as enabled for Cross-Origin Resource Sharing (CORS).
Please refer MS Q&A for more information.

Trouble authorizing access to App Engine via IAP

I currently have App Engine up and running, protected by IAP, and my eventual aim is to have this be triggered by an Apps Script project. I've tested the code without IAP and it works fine. However, I'm running into difficulties successfully authorizing access to it when IAP is enabled.
I've added myself as an IAP-secured Web App User (as well as Policy Admin) to the App Engine, but whenever I try triggering it from a GSheets Apps Script where I'm the owner and it's associated with the correct GCP project (using this great explanation as a guide) I get the following:
"Invalid IAP credentials: JWT audience doesn't match this application ('aud' claim (1084708005908-bk66leo0dnkrjsh276f0rgeoq8ns87qu.apps.googleusercontent.com) doesn't match expected value (1084708005908-oqkn6pcj03c2pmdufkh0l7mh37f79po2.apps.googleusercontent.com))"
I've tried adding/removing various permissions to my account, as well creating a new Apps Script and re-adding to the project, but to no avail. I run into the same issue when triggering from CLI, so I'm fairly sure it's an issue with authentication, however this is my Apps Script code in case it helps:
function test() {
const options = {
headers: {'Authorization': 'Bearer ' + ScriptApp.getIdentityToken()},
muteHttpExceptions: true
}
var result = UrlFetchApp.fetch('https://APP-ENGINE-URL.appspot.com', options);
Logger.log(result);
}
And the manifest file:
{
"timeZone": "Europe/London",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": ["openid", "https://www.googleapis.com/auth/script.external_request"]
}
Any help on this is super appreciated! Never posted here before, but pretty desperate and couldn't find anyone with this exact problem on SO.
Consideration
The problem with your solution is that you are using the identity of an auto-generated OAuth Client for Apps Script. This clients are not suitable for this kind of authentication, here a complete list of supported OAuth clients.
Solution
In order to complete your authentication you will need an extra step. You will have to create another OAuth Client and build an identity token with its credentials.
To make things easier I would recommend to use this Apps Script library: https://github.com/gsuitedevs/apps-script-oauth2
The inital Set-up is covered in the linked documentation.
Important: When creating the OAuth Client take note of the ClientID and the Client-secret. Plus, you will need to add an Authorized Redirect URI. This is standard when using the OAuth2 GAS library and it has this form: https://script.google.com/macros/d/{Your Apps Script ID}/usercallback
Now you have all the necessary information to build your identity token. In the Github repository there is a boilerplate sample that will cover the first coding steps with the OAuth2 GAS library.
Here is the link.
Copy this code to your Apps Script project and follow the instructions in the comments. You will need to add an extra OAuth scope: "https://www.googleapis.com/auth/userinfo.email".
Once you set all the constants with your OAuth clients information you should run the run() function from your Apps Script editor. This will log a URL you have to open in your browser to authorize your App. Once you authorized the App run again the run() function and you will successfully access your IAP protected application.
References
OAuth2 GAS library
IAP programmatic authentication

How to properly enable HTTPS on App Engine flex environment and Go?

I am trying to enable HTTPS on my Go App deployed to GAE flex environment. I have my custom domain successfully mapped, and am using Google-managed SSL certificates. I have app.yaml configured to redirect HTTP to HTTPS as follows:
handlers:
- url: /.*
script: _go_app
secure: always
Now there are two problems that I haven't been able to resolve so far.
First, the above configuration is supposed to redirect HTTP traffic to HTTPS, but apparently it is not happening.
Second, when I add https:// in the url box, I see three different behavior on Firefox, Chrome, and Edge. Edge identifies the website as secure, Firefox marks the website as secure connection, but says that it "has blocked parts of this page that are not secure", and surprisingly Chrome marks the website as Not secure (though it says certificate is valid!).
With these symptoms I was wondering if I should take additional steps to make redirecting and SSL work for my website? Specifically, I would like to know with App Engine, and managed SSL enabled:
Should I continue serving pages on HTTP using http.ListenAndServe(..), or need to switch to http.ListenAndServeTLS(..)?
In my Go app should I redirect HTTP to HTTPS? or the above setting is expected to work just fine?
Thanks in advance for your help and advice.
PS:
Trying out with different suggestions, I added Strict-Transport-Security: max-age=31536000; includeSubDomains to handlers' response. Does not seem if this helped with redirection either.
EDIT/PARTIAL ANSWER:
According to this documentation, under Authentication changes, the secure and login handlers are deprecated. The documentation suggests using Strict-Transport-Security or X-Forwarded-Proto instead.
I am using Strict-Transport-Security on the server side to enrich my response header:
func (h *STLHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
h.nextHandler.ServeHTTP(w, req)
}
I was wondering if I am using this header in the right place?
For the second set of my problems I realized I have mixed content on my page. My mixed content was a http link to a set of fonts. When I fixed the mixed content, i.e. changed http to https, both Chrome and Firefox security warnings disappeared. You may also find this page Avoiding the Not Secure Warning in Chrome useful on this matter.
You need to check your app using:
http://[YOUR_PROJECT_ID].appspot.com
Or if you nedd HTTPS:
https://[YOUR_PROJECT_ID].appspot.com
If you want your own certificate you will need to upload it and then be available to use: https://your-domain.tld
From the docs:
For APIs that will be hosted on App Engine flexible environment, you must use the appspot.com domain, and the service name must be in the following format:
YOUR_PROJECT_ID.appspot.com
When you deploy your API to App Engine, a DNS entry with a name in the format YOUR_PROJECT_ID.appspot.com is created automatically.
For APIs that will be hosted on Compute Engine, Kubernetes Engine, or Kubernetes, you must use the cloud.goog domain, and the service name must be in the following format:
YOUR_API_NAME.endpoints.YOUR_PROJECT_ID.cloud.goog
Or you could just put a CDN in front like Cloudflare which will do all the SSL termination for you and if required redirect all HTTP to HTTPS

Specify Google App Engine health check endpoint

How do I specify a health check endpoint in my GAE health_check entry in app.yaml? I see options for various thresholds but I have no indication of how to set a custom endpoint or even if my options are being respected.
The app engine documentation states that /_ah/health is used for health checks but I would like to provide my own health checks.
You can still write your own custom health-checking code. It just needs to reply to /_ah/health request with HTTP 200.

Cloud Endpoints HTTP Cookies

I am implementing Cloud Endpoints with a Python app that uses custom authentication (GAE Sessions) instead of Google Accounts. I need to authenticate the requests coming from the Javascript client, so I would like to have access to the cookie information.
Reading this other question leads me to believe that it is possible, but perhaps not documented. I'm not familiar with the Java side of App Engine, so I'm not quite sure how to translate that snippet into Python. Here is an example of one of my methods:
class EndpointsAPI(remote.Service):
#endpoints.method(Query_In, Donations_Out, path='get/donations',
http_method='GET', name='get.donations')
def get_donations(self, req):
#Authenticate request via cookie
where Query_In and Donations_Out are both ProtoRPC messages (messages.Message). The parameter req in the function is just an instance of Query_In and I didn't find any properties related to HTTP data, however I could be wrong.
First, I would encourage you to try to use OAuth 2.0 from your client as is done in the Tic Tac Toe sample.
Cookies are sent to the server in the Cookie Header and these values are typically set in the WSGI environment with the keys 'HTTP_...' where ... corresponds to the header name:
http = {key: value for key, value in os.environ.iteritems()
if key.lower().startswith('http')}
For cookies, os.getenv('HTTP_COOKIE') will give you the header value you seek. Unfortunately, this doesn't get passed along through Google's API Infrastructure by default.
UPDATE: This has been enabled for Python applications as of version 1.8.0. To send cookies through, specify the following:
from google.appengine.ext.endpoints import api_config
AUTH_CONFIG = api_config.ApiAuth(allow_cookie_auth=True)
#endpoints.api(name='myapi', version='v1', auth=AUTH_CONFIG, ...)
class MyApi(remote.service):
...
This is a (not necessarily comprehensive list) of headers that make it through:
HTTP_AUTHORIZATION
HTTP_REFERER
HTTP_X_APPENGINE_COUNTRY
HTTP_X_APPENGINE_CITYLATLONG
HTTP_ORIGIN
HTTP_ACCEPT_CHARSET
HTTP_ORIGINALMETHOD
HTTP_X_APPENGINE_REGION
HTTP_X_ORIGIN
HTTP_X_REFERER
HTTP_X_JAVASCRIPT_USER_AGENT
HTTP_METHOD
HTTP_HOST
HTTP_CONTENT_TYPE
HTTP_CONTENT_LENGTH
HTTP_X_APPENGINE_PEER
HTTP_ACCEPT
HTTP_USER_AGENT
HTTP_X_APPENGINE_CITY
HTTP_X_CLIENTDETAILS
HTTP_ACCEPT_LANGUAGE
For the Java people who land here. You need to add the following annotation in order to use cookies in endpoints:
#Api(auth = #ApiAuth(allowCookieAuth = AnnotationBoolean.TRUE))
source
(Without that it will work on the local dev server but not on the real GAE instance.)

Resources