How do I expose a PyAMF service? - python

I've created a service called 'timesTwo' and dropped the file in the correct directory. When I try and call it from my client-side code however, it tells me that the service doesn't exist. Once I've created my server side code, how do I expose the service? What step(s) am I missing?
Server-side code:
from pyamf.remoting.gateway.wsgi import WSGIGateway
def timesTwo(data):
return data * 2
services = {
'timesTwo': timesTwo,
# Add other exposed functions here
}
gateway = WSGIGateway(services)
I'm having a really hard time finding online documentation. Thanks for the help!
Sidenote: Is there some resource (website, book, ANYthing) that would be more thorough than what's on pyamf.org that you would recommend?!

Related

Calling Google App Engine (iAP Enabled) from Google Cloud Function within the same Project

Context:
Node Server in Google App Engine (GAE) that effectively houses a backend for a frontend that is also served by the same app engine instance
Hence why iAP is enabled (for selected web app users only)
Has various endpoints for the frontend to call via reverse-proxy (as I understand it's called)
Google Cloud Function(GCF) within the same project that (funny enough) is actually being called by the node server to initiate the cloud function that then needs to call an endpoint within the GAE node server.
....k wait I might've just found another way to solve the problem but I'll get to that at the end.
I created a VPC Connector for GCF to access a VM instance that I created to talk to external networks. GAE (Flex) is able to do so natively. Not sure if this is relevant but wanted to throw it in the mix.
Short term solution:
Since I need to call the GCF from the GAE node server first, I can just provide it with the relevant data as needed.
Long term solution:
Ideally, the GCF should be called by any other services that might or might not have the data, so it would be ideal to have the GCF call out the GAE endpoint to get the data.
So far:
import urllib
import google.auth.transport.requests
import google.oauth2.id_token
req = urllib.request.Request('https://the-gcp-project-id.appspot.com/api/theEndpoint')
auth_req = google.auth.transport.requests.Request()
id_token = google.oauth2.id_token.fetch_id_token(auth_req, 'https://appengine.googleapis.com')
log.info("Authorization: " + f"Bearer {id_token}")
# req.add_header("Authorization", f"Bearer {id_token}")
# response = urllib.request.urlopen(req)
# # return response.read()
# log.info(response.read())
import requests as reqs
response = reqs.post('https://the-gcp-project-id.appspot.com/theEndpoint', json={'test':'123'}, headers={"Authorization" : f"Bearer {id_token}"})
log.info(response)
This doesn't seem to actually trigger the endpoint though. As far as I know the service account for the cloud function should have the same permissions as the app engine service account.
Can anyone point me in the right direction on this?

How can i get request IP address from Google Cloud Logging using Python?

Using the google-cloud-logging module for Python, I can iterate through log messages for my GAE app, and I'd like to list the requesting IP address for each item in Request Log. The official docs don't mention how, and hack through the source code doesn't give me much hope since the log entries are mostly TextEntry with few object properties.
My code is like this:
logging_client = logging.Client()
logger = logging_client.logger('projects/MYPROJECT/logs/appengine.googleapis.com%2Frequest_log')
for entry in logging_client.list_entries():
timestamp = entry.timestamp.isoformat()
print("* {}, {}: {}".format(timestamp, type(entry), entry))
When looking at the same logs in the Google Cloud Console, I see a protoPayload.ip field for each log entry - that's exactly the field I hope to extract.
This is not currently possible since the Python client library for Stackdriver Logging doesn't support this feature yet. As you can check in the documentation for the Entry object and its code it is not possible to retrieve the section that contains the Ip of the caller.
However you can do a trick by logging this value yourself with in each call to your App Engine service and therefore you could be able to retrieve it. The value of the caller IP is in the 'X-Appengine-User-Ip' header. You can use this code as an example on how to get it:
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/')
def hello_world():
ip = request.headers['X-Appengine-User-Ip']

Is a python appengine app with no firestore security rules insecure?

I have a Google App Engine Standard Environment application written in Python 3, using Flask as the framework, and firestore in native mode as the database. All of the database calls are done in the App Engine code, hidden behind Flask end points/views/handlers. Client browsers do not execute any javascript that directly call the firestore database. Client side javascript is basically 'dumb' code used for cosmetics. The only time client side javascript does "anything" is when a user creates a new account or logs in using the firebase auth ui.
Having said so, I noticed that some online resources mention that it is absolutely necessary to secure the firestore database since anything that is not disallowed by security rules are basically allowed (i.e. the firestore database is insecure by default), however, I suspect that this is only the case for apps that have thick clients (i.e. the client side code or javascript is in charge of doing the heavy lifting of querying and writing to firestore).
So my question is, is writing these security rules necessary only for mobile/web clients and not for firestore databases accessed only by server side code? Or is it necessary for all firestore projects to define these security rules? If so, then I would appreciate any pointers as to where to find reasonable default security rules to start securing my firestore database.
I am including a caricature of my flask main.py file for reference.
# main.py
from google.cloud import firestore
from mylibrary import function_that_fetches_user_data
from mylibrary2 import function_that_writes_user_content
def validate_cookie(protected_function):
def wrapper(*args, **kwargs):
# handle cookie validation
# run protected function
return wrapper
# The dashboard is meant to display user data and user content to the user.
# It is not meant to be seen by other users.
#app.route("/user_dashboard")
#validate_cookie
def dashboard():
user_id = get_uid_from_cookie
firestore_client = firestore.Client()
user_data = function_that_fetches_user_data(user_id, firestore_client)
return render_template('dashboard.html', user_data)
# The write function creates user content that should only be accessible to the author
# and the system/app.
#app.route("/write_user_content")
#validate_cookie
def write_user_content():
user_id = get_uid_from_cookie
firestore_client = firestore.Client()
result = function_that_writes_user_content(user_id, firestore_client)
return render_template('success.html', result)
Security rules are only necessary to control access coming from web and mobile clients. Backend SDK accessing Firestore actually bypass security rules altogether, so writing any rules at all won't change the behavior of your backend code at all.
If you simply do not directly access the database from web or mobile, then you can set the security rules to reject all access, and that's fine.
match /{document=**} {
allow read, write: if false;
}

How can I access Google App Engine endpoints API from Python application with use OAuth?

How can I access Google App Engine endpoints API for Python (not web, android, ios)?
I read this tutorial but it not explains it enough to understand this.
As I found on serve side I can use such code to identify user:
#endpoints.method(message_types.VoidMessage, Greeting,
path='hellogreeting/authed', http_method='POST',
name='greetings.authed')
def greeting_authed(self, request):
current_user = endpoints.get_current_user()
email = (current_user.email() if current_user is not None
else 'Anonymous')
return Greeting(message='hello %s' % (email,))
Full code of API example
How can I connect from Python client to this API and call 'hellogreeting/authed' with authentication current_user != None.
Can you share some code how to do it?
app_id = 'xxx'
user = 'xxx'
password = 'xxx'
callAPI(app_id, user, password, 'hellogreeting/authed')
You need to configure your App Engine instance to be able to serve your API. I would recommend you create a separate module dedicated to your API, like explained in these docs: https://developers.google.com/appengine/docs/python/endpoints/api_server.
Once everything is correctly set up on the server side, you can call your API using something like: http://your-module.your-app.appspot.com/_ah/spi/hellogreeting/authed.
If you're using the development server, things are a little bit different for accessing modules, but once you know which port number the App Engine development server has assigned to your API module, you can reach it locally using: http://localost:<api_module_port_#>/_ah/spi/hellogreeting/authed.
Hope this helped.

WCF and Python

Is there any example code of a cpython (not IronPython) client which can call Windows Communication Foundation (WCF) service?
I used suds.
from suds.client import Client
print "Connecting to Service..."
wsdl = "http://serviceurl.com/service.svc?WSDL"
client = Client(wsdl)
result = client.service.Method(variable1, variable2)
print result
That should get you started. I'm able to connect to exposed services from WCF and a RESTful layer. There needs to be some data massaging to help do what you need, especially if you need to bind to several namespaces.
TL;DR: For wsHttpBinding (SOAP 1.2) use zeep
In case someone is having trouble using suds (or suds-jurko for that matter) with WCF and wsHttpBinding (which is SOAP 1.2):
suds is pretty much dead (can't even pip install it on python 3)
suds-jurko seems kind-of dead. The 0.6 release has a very annoying infinite recursion bug (at least on the WSDL exposed by our service) which is fixed in the tip but that's not released and it's been 1.5years (at time of this writing in Feb'17) since the last commit.
It works on python 3 but doesn't support SOAP 1.2. Sovetnikov's answer is an attempt to get it working with 1.2 but I haven't managed to make it work for me.
zeep seems to be the current way to go and worked out of the box (I'm not affiliated with zeep, it just works for me and I spent several hours banging my head against a brick wall trying to make suds work). For zeep to work, the WCF service host configuration must include <security mode="None"/> under the wsHttpBinding node Actually zeep seems to support username and signature (x509) based WS-SE but I haven't tried that so can't speak to any problems around it.
WCF needs to expose functionality through a communication protocol. I think the most commonly used protocol is probably SOAP over HTTP. Let's assume that's
what you're using then.
Take a look at this chapter in Dive Into Python. It will show you how to
make SOAP calls.
I know of no unified way of calling a WCF service in Python, regardless of communication
protocol.
Just to help someone to access WCF SOAP 1.2 service with WS-Addressing using suds.
Main problem is to inject action name in every message.
This example for python 3 and suds port https://bitbucket.org/jurko/suds.
Example uses custom authentification based on HTTP headers, i leave it as is.
TODO: Automatically get api_direct_url from WSDL (at now it is hard coded).
from suds.plugin import MessagePlugin
from suds.sax.text import Text
from suds.wsse import Security, UsernameToken
from suds.sax.element import Element
from suds.sax.attribute import Attribute
from suds.xsd.sxbasic import Import
api_username = 'some'
api_password = 'none'
class api(object):
api_direct_url = 'some/mex'
api_url = 'some.svc?singleWsdl|Wsdl'
NS_WSA = ('wsa', 'http://www.w3.org/2005/08/addressing')
_client_instance = None
#property
def client(self):
if self._client_instance:
return self._client_instance
from suds.bindings import binding
binding.envns = ('SOAP-ENV', 'http://www.w3.org/2003/05/soap-envelope')
api_inst = self
class _WSAPlugin(MessagePlugin):
def marshalled(self, context):
api_inst._marshalled_message(context)
self._client_instance = Client(self.api_url,
plugins=[_WSAPlugin()],
headers={'Content-Type': 'application/soap+xml',
'login':api_username,
'password': api_password}
)
headers = []
headers.append(Element('To', ns=self.NS_WSA).setText(self.api_direct_url))
headers.append(Element('Action', ns=self.NS_WSA).setText('Blank'))
self._client_instance.set_options(soapheaders=headers)
cache = self._client_instance.options.cache
cache.setduration(days=10)
return self._client_instance
def _marshalled_message(self, context):
def _children(r):
if hasattr(r, 'children'):
for c in r.children:
yield from _children(c)
yield c
for el in _children(context.envelope):
if el.name == 'Action':
el.text = Text(self._current_action)
return
_current_action = None
def _invoke(self, method, *args):
try:
self._current_action = method.method.soap.action.strip('"')
return method(*args)
finally:
self._current_action = None
def GetRequestTypes(self):
return self._invoke(self.client.service.GetRequestTypes)[0]
def GetTemplateByRequestType(self, request_type_id):
js = self._invoke(self.client.service.GetTemplateByRequestType, request_type_id)
return json.loads(js)
def GetRequestStatus(self, request_guid):
return self._invoke(self.client.service.GetRequestStatus, request_guid)
def SendRequest(self, request_type_id, request_json):
r = json.dumps(request_json, ensure_ascii=False)
return self._invoke(self.client.service.SendRequest, request_type_id, r)
I do not know of any direct examples, but if the WCF service is REST enabled you could access it through POX (Plain Old XML) via the REST methods/etc (if the service has any). If you are in control of the service you could expose endpoints via REST as well.
if you need binary serialized communication over tcp then consider implementing solution like Thrift.
Even if there is not a specific example of calling WCF from Python, you should be able to make a fully SOAP compliant service with WCF. Then all you have to do is find some examples of how to call a normal SOAP service from Python.
The simplest thing will be to use the BasicHttpBinding in WCF and then you can support your own sessions by passing a session token with each request and response.

Categories