我试图使用此RPC处理程序从Google AppEngine应用程序实例中显示iOS推送通知的概念证明...
PAYLOAD = {'aps': {'alert':'Push!','sound':'default'}}
TOKEN = '[...]'
class APNsTest(BaseRPCHandler):
def get(self, context, name):
self._call_method(context, name)
def send_push(self):
# certificate files
filename = 'VisitorGuidePush'
abs_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../archive/certificate'))
ca_certs = os.path.abspath(os.path.join(abs_path, '%s.ca'%filename))
certfile = os.path.abspath(os.path.join(abs_path, '%s.crt'%filename))
keyfile = os.path.abspath(os.path.join(abs_path, '%s.key'%filename))
# serialize payload
payload = json.dumps(PAYLOAD)
# APNS server address...
# apns_address = ('api.development.push.apple.com', 443) # Development server
# apns_address = ('api.development.push.apple.com', 2197) # Development server
# apns_address = ('api.push.apple.com', 443) # Production server
apns_address = ('api.push.apple.com', 2197) # Production server
# a socket to connect to APNS over SSL
_sock = socket.socket()
_ssl = ssl.wrap_socket(_sock, keyfile=keyfile,
certfile=certfile,
server_side=False,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
ca_certs=ca_certs)
_ssl.connect(apns_address)
# Generate a notification packet
token = binascii.unhexlify(TOKEN)
fmt = '!cH32sH{0:d}s'.format(len(payload))
cmd = '\x00'
message = struct.pack(fmt, cmd, len(token), token, len(payload), payload)
_ssl.write(message)
_ssl.close()
return self.response_result(PAYLOAD)
执行“_ssl.connect(apns_address)”时需要帮助解决此错误
SSLError: [Errno 1] _ssl.c:507: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
我的PEM文件(源自.p12)和设备令牌是我们团队的移动开发人员一周前生成的,有关验证这些内容的建议会有所帮助。现在我相信目前有效。
在指定TLSv1协议时,我注意到握手失败标识了sslv3。
我尝试过wrap_socket和apns_address的许多变体和组合,并且由于握手失败而一直停止。这导致我怀疑我使用pem证书的方式有问题。
我一直用于wrap_socket的主要引用是Using OpenSSL和TLS/SSL wrapper for socket objects,更不用说几个StackOverflow帖子了。
请提供有关适当的密钥文件,certfile和ca_certs值以及可用于基于GAE的APN通信的任何其他建议或资源的建议。谢谢〜
原始.p12已使用Pusher验证,并通过openssl ...
进行划分openssl pkcs12 -in vgp.p12 -out VisitorGuidePush.key -nodes -nocerts
openssl pkcs12 -in vgp.p12 -out VisitorGuidePush.crt -nodes -nokeys
openssl pkcs12 -in vgp.p12 -out VisitorGuidePush.ca -nodes -cacerts
我收到一个与ca_certs相关的新错误...
SSLError: [Errno 0] _ssl.c:343: error:00000000:lib(0):func(0):reason(0)
删除ca_certs要求或传入.p12或.crt等其他文件会导致返回原始握手失败。
答案 0 :(得分:1)
考虑使用像pyapns这样的库,这是我用来获取推送通知以便在GAE上工作的。要测试您是否使用了正确的密钥/证书文件,可以使用Pusher之类的应用。另外,我知道要在GAE上获得SSL功能,你必须启用计费,所以这可能是问题所在。祝你好运!
答案 1 :(得分:1)
相应的支持文件以Creating a Universal Push Notification Client SSL Certificate作为 p12 文件开头。
接下来,利用命令行openssl将 p12 解析为所需的证书和密钥文件......
openssl pkcs12 -in VisitorGuide.p12 -out VisitorGuide.key -nodes -nocerts
openssl pkcs12 -in VisitorGuide.p12 -out VisitorGuide.crt -nodes -nokeys
openssl pkcs12 -in VisitorGuide.p12 -out VisitorGuide.pem -nodes
最后获取合格的证书颁发机构文件(来自Troubleshooting Push Notifications)
除了SSL身份(证书和相关的私人身份证明) 密钥)由会员中心创建,您还应该安装Entrust CA. (2048)您的提供商的根证书。
Entrust.net Certificate Authority (2048) download ~encoust_2048_ca.cer
请注意,每个GAE实例都在/etc/ca-certificates.crt上托管自己的证书颁发机构,如此处所述Using OpenSSL。
将这些文件添加到您的项目中,您可以制作两个同样有效的ssl套接字对象中的一个......
_ssl = ssl.wrap_socket(_sock, keyfile=VisitorGuide.key,
certfile=VisitorGuide.crt,
server_side=False,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
ca_certs=entrust_2048_ca.cer)
...或...
_ssl = ssl.wrap_socket(_sock, certfile=VisitorGuide.pem,
server_side=False,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
ca_certs=entrust_2048_ca.cer)
TLS/SSL wrapper for socket objects 17.3.4.3. Combined key and certificate解释了为什么两者都是有效的参数选项。
在我提供最终代码块之前,我必须指出有关APNs地址的事情(这被证明是关键点,允许我解决握手失败并获得GAE和APN之间的SSL连接)
根据iOS开发人员库APNs Provider API
发送远程通知的第一步是与相应的APN服务器建立连接:
开发服务器:api.development.push.apple.com:443
生产服务器:api.push.apple.com:443
注意:您也可以在与APN通信时使用端口2197。例如,您可以执行此操作,以允许APN通过防火墙,但阻止其他HTTPS流量。
但直到我挖掘Pusher来源,才发现我可以连接的APNs地址...
gateway.sandbox.push.apple.com:2195
gateway.push.apple.com:2195
没有进一步的... ...
class APNsTest(BaseRPCHandler):
def get(self, context, name):
self._call_method(context, name)
def send_push(self):
# certificate files
abs_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../cert'))
pem_file = os.path.abspath(os.path.join(abs_path, 'VisitorGuide.pem'))
ca_certs = '/etc/ca-certificates.crt'
# APNS server address...
apns_address = ('gateway.sandbox.push.apple.com', 2195)
# apns_address = ('gateway.push.apple.com', 2195)
# a socket to connect to APNS over SSL
_sock = socket.socket()
_ssl = ssl.wrap_socket(_sock, certfile=pem_file,
server_side=False,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
ca_certs=ca_certs)
_ssl.connect(apns_address)
# a notification packet
payload = json.dumps(PAYLOAD)
token = binascii.unhexlify(TOKEN)
fmt = '!cH32sH{0:d}s'.format(len(payload))
cmd = '\x00'
message = struct.pack(fmt, cmd, len(token), token, len(payload), payload)
_ssl.write(message)
_ssl.close()
return self.response_result(PAYLOAD)
...执行没有错误。
答案 2 :(得分:0)
此外,通过实验,我发现当我应用内置的第三方ssl lib时,App Engine上的SSL相关错误通常会消失:
libraries:
- name: ssl
version: latest
或:
libraries:
- name: ssl
version: "2.7"