Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1277)

Unified Diff: appengine/chromium_build_logs/third_party/oauth2client/crypt.py

Issue 1260293009: make version of ts_mon compatible with appengine (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: clean up code Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/chromium_build_logs/third_party/oauth2client/crypt.py
diff --git a/appengine/chromium_build_logs/third_party/oauth2client/crypt.py b/appengine/chromium_build_logs/third_party/oauth2client/crypt.py
index 3df861d29b98368239727c75b7f1d3e2a9f9b456..cc7a6cd3a46b85d6df62eb0db27c03814bb89282 100644
--- a/appengine/chromium_build_logs/third_party/oauth2client/crypt.py
+++ b/appengine/chromium_build_logs/third_party/oauth2client/crypt.py
@@ -1,7 +1,6 @@
-#!/usr/bin/python2.4
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2011 Google Inc.
+# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,14 +13,17 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+"""Crypto-related routines for oauth2client."""
-import base64
-import hashlib
+import imp
+import json
import logging
+import os
import time
-from OpenSSL import crypto
-from anyjson import simplejson
+from oauth2client._helpers import _json_encode
+from oauth2client._helpers import _urlsafe_b64decode
+from oauth2client._helpers import _urlsafe_b64encode
CLOCK_SKEW_SECS = 300 # 5 minutes in seconds
@@ -29,113 +31,71 @@ AUTH_TOKEN_LIFETIME_SECS = 300 # 5 minutes in seconds
MAX_TOKEN_LIFETIME_SECS = 86400 # 1 day in seconds
-class AppIdentityError(Exception):
- pass
-
-
-class Verifier(object):
- """Verifies the signature on a message."""
-
- def __init__(self, pubkey):
- """Constructor.
-
- Args:
- pubkey, OpenSSL.crypto.PKey, The public key to verify with.
- """
- self._pubkey = pubkey
-
- def verify(self, message, signature):
- """Verifies a message against a signature.
-
- Args:
- message: string, The message to verify.
- signature: string, The signature on the message.
-
- Returns:
- True if message was singed by the private key associated with the public
- key that this object was constructed with.
- """
- try:
- crypto.verify(self._pubkey, signature, message, 'sha256')
- return True
- except:
- return False
-
- @staticmethod
- def from_string(key_pem, is_x509_cert):
- """Construct a Verified instance from a string.
-
- Args:
- key_pem: string, public key in PEM format.
- is_x509_cert: bool, True if key_pem is an X509 cert, otherwise it is
- expected to be an RSA key in PEM format.
-
- Returns:
- Verifier instance.
-
- Raises:
- OpenSSL.crypto.Error if the key_pem can't be parsed.
- """
- if is_x509_cert:
- pubkey = crypto.load_certificate(crypto.FILETYPE_PEM, key_pem)
- else:
- pubkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key_pem)
- return Verifier(pubkey)
-
-
-class Signer(object):
- """Signs messages with a private key."""
+logger = logging.getLogger(__name__)
- def __init__(self, pkey):
- """Constructor.
-
- Args:
- pkey, OpenSSL.crypto.PKey, The private key to sign with.
- """
- self._key = pkey
-
- def sign(self, message):
- """Signs a message.
-
- Args:
- message: string, Message to be signed.
-
- Returns:
- string, The signature of the message for the given key.
- """
- return crypto.sign(self._key, message, 'sha256')
-
- @staticmethod
- def from_string(key, password='notasecret'):
- """Construct a Signer instance from a string.
-
- Args:
- key: string, private key in P12 format.
- password: string, password for the private key file.
-
- Returns:
- Signer instance.
-
- Raises:
- OpenSSL.crypto.Error if the key can't be parsed.
- """
- pkey = crypto.load_pkcs12(key, password).get_privatekey()
- return Signer(pkey)
+class AppIdentityError(Exception):
+ pass
-def _urlsafe_b64encode(raw_bytes):
- return base64.urlsafe_b64encode(raw_bytes).rstrip('=')
+def _TryOpenSslImport():
+ """Import OpenSSL, avoiding the explicit import where possible.
-def _urlsafe_b64decode(b64string):
- # Guard against unicode strings, which base64 can't handle.
- b64string = b64string.encode('ascii')
- padded = b64string + '=' * (4 - len(b64string) % 4)
- return base64.urlsafe_b64decode(padded)
+ Importing OpenSSL 0.14 can take up to 0.5s, which is a large price
+ to pay at module import time. However, it's also possible for
+ ``imp.find_module`` to fail to find the module, even when it's
+ installed. (This is the case in various exotic environments,
+ including some relevant for Google.) So we first try a fast-path,
+ and fall back to the slow import as needed.
+ Args:
+ None
+ Returns:
+ None
+ Raises:
+ ImportError if OpenSSL is unavailable.
-def _json_encode(data):
- return simplejson.dumps(data, separators = (',', ':'))
+ """
+ try:
+ _, _package_dir, _ = imp.find_module('OpenSSL')
+ if not (os.path.isfile(os.path.join(_package_dir, 'crypto.py')) or
+ os.path.isfile(os.path.join(_package_dir, 'crypto.so')) or
+ os.path.isdir(os.path.join(_package_dir, 'crypto'))):
+ raise ImportError('No module named OpenSSL.crypto')
+ return
+ except ImportError:
+ import OpenSSL.crypto
+
+
+try:
+ _TryOpenSslImport()
+ from oauth2client._openssl_crypt import OpenSSLVerifier
+ from oauth2client._openssl_crypt import OpenSSLSigner
+ from oauth2client._openssl_crypt import pkcs12_key_as_pem
+except ImportError:
+ OpenSSLVerifier = None
+ OpenSSLSigner = None
+ def pkcs12_key_as_pem(*args, **kwargs):
+ raise NotImplementedError('pkcs12_key_as_pem requires OpenSSL.')
+
+
+try:
+ from oauth2client._pycrypto_crypt import PyCryptoVerifier
+ from oauth2client._pycrypto_crypt import PyCryptoSigner
+except ImportError:
+ PyCryptoVerifier = None
+ PyCryptoSigner = None
+
+
+if OpenSSLSigner:
+ Signer = OpenSSLSigner
+ Verifier = OpenSSLVerifier
+elif PyCryptoSigner:
+ Signer = PyCryptoSigner
+ Verifier = PyCryptoVerifier
+else:
+ raise ImportError('No encryption library found. Please install either '
+ 'PyOpenSSL, or PyCrypto 2.6 or later')
def make_signed_jwt(signer, payload):
@@ -153,15 +113,15 @@ def make_signed_jwt(signer, payload):
header = {'typ': 'JWT', 'alg': 'RS256'}
segments = [
- _urlsafe_b64encode(_json_encode(header)),
- _urlsafe_b64encode(_json_encode(payload)),
+ _urlsafe_b64encode(_json_encode(header)),
+ _urlsafe_b64encode(_json_encode(payload)),
]
signing_input = '.'.join(segments)
signature = signer.sign(signing_input)
segments.append(_urlsafe_b64encode(signature))
- logging.debug(str(segments))
+ logger.debug(str(segments))
return '.'.join(segments)
@@ -185,9 +145,8 @@ def verify_signed_jwt_with_certs(jwt, certs, audience):
"""
segments = jwt.split('.')
- if (len(segments) != 3):
- raise AppIdentityError(
- 'Wrong number of segments in token: %s' % jwt)
+ if len(segments) != 3:
+ raise AppIdentityError('Wrong number of segments in token: %s' % jwt)
signed = '%s.%s' % (segments[0], segments[1])
signature = _urlsafe_b64decode(segments[2])
@@ -195,15 +154,15 @@ def verify_signed_jwt_with_certs(jwt, certs, audience):
# Parse token.
json_body = _urlsafe_b64decode(segments[1])
try:
- parsed = simplejson.loads(json_body)
+ parsed = json.loads(json_body.decode('utf-8'))
except:
raise AppIdentityError('Can\'t parse token: %s' % json_body)
# Check signature.
verified = False
- for (keyname, pem) in certs.items():
+ for pem in certs.values():
verifier = Verifier.from_string(pem, True)
- if (verifier.verify(signed, signature)):
+ if verifier.verify(signed, signature):
verified = True
break
if not verified:
@@ -216,21 +175,20 @@ def verify_signed_jwt_with_certs(jwt, certs, audience):
earliest = iat - CLOCK_SKEW_SECS
# Check expiration timestamp.
- now = long(time.time())
+ now = int(time.time())
exp = parsed.get('exp')
if exp is None:
raise AppIdentityError('No exp field in token: %s' % json_body)
if exp >= now + MAX_TOKEN_LIFETIME_SECS:
- raise AppIdentityError(
- 'exp field too far in future: %s' % json_body)
+ raise AppIdentityError('exp field too far in future: %s' % json_body)
latest = exp + CLOCK_SKEW_SECS
if now < earliest:
raise AppIdentityError('Token used too early, %d < %d: %s' %
- (now, earliest, json_body))
+ (now, earliest, json_body))
if now > latest:
raise AppIdentityError('Token used too late, %d > %d: %s' %
- (now, latest, json_body))
+ (now, latest, json_body))
# Check audience.
if audience is not None:
@@ -239,6 +197,6 @@ def verify_signed_jwt_with_certs(jwt, certs, audience):
raise AppIdentityError('No aud field in token: %s' % json_body)
if aud != audience:
raise AppIdentityError('Wrong recipient, %s != %s: %s' %
- (aud, audience, json_body))
+ (aud, audience, json_body))
return parsed

Powered by Google App Engine
This is Rietveld 408576698